;LBSPOOLB/ASM - Actual spool driver
;
;
;	This is the spool/despool driver - bank 0
;
FIX1	CALL	SPLR2		;Code mods to module-A
RX16	EQU	$-2		;  if strictly bank-0
	XOR	A
	RET
	CALL	DSPLR1
RX17	EQU	$-2
	XOR	A
	RET
	CALL	GETBLK2
RX18	EQU	$-2
	XOR	A
	RET
;
DVRABGN	EQU	$
	JR	DVREPT		;Branch around linkage
	DW	$-$		;Last byte used
	DB	5
SPOOL$	DB	'SPOOL'
S0DCB	DW	0,0		;Space for DCB pointers
PRMSAV	DW	0		;HIGH$ before space alloc
	DW	DVRABGN-1	;HIGH$ after space alloc
	DW	0		;Previous MPARM
	DW	0		;Previous DPARM
MODDVR	DW	0		;DCB address of device
SPLBNK	DB	0		;Bank of RAM
	DW	SPLFCB		;FCB pointer
RX8	EQU	$-2
;
DVREPT	JR	Z,PUTCHAR	;Go on @PUT
	JR	NC,CKCTL	;Go on @CTL
	LD	A,0		;Show nothing on @GET
	RET
CKCTL	XOR	A
	RET			;Show available on CTL-0
;
;	Move stack low if needed
;
STKCTL	PUSH	HL
	LD	HL,8005H
	ADD	HL,SP		;Stack in what bank?
	POP	HL
	RET	NC		;Ok if stack low
	DI
	LD	(SVHL),HL
RX19	EQU	$-2
	POP	HL		;Return address
	LD	(SAVSTK),SP	;Save the current stack
RX20	EQU	$-2
	LD	SP,STACK$-20H	;Force it low
	PUSH	HL		;User ret back on
	LD	HL,SPOLRET
RX21	EQU	$-2
	EX	(SP),HL		;Now, ultimate ret 1st,
	PUSH	HL		;  and local ret 2nd
	LD	HL,(SVHL)	;Restore HL
RX23	EQU	$-2
	EI
	RET
;
SPOLRET
	DI			;Just in case
	LD	SP,(SAVSTK)	;Get the old stack
RX22	EQU	$-2
	EI
	RET
SAVSTK	DW	0
SVHL	DW	0
;
;	Character to PUT - Get bank activated
;
PUTCHAR	LD	HL,SPLR1A	;Point to transfer addr
RX01	EQU	$-2
	LD	E,C		;Xfer char to PUT
	LD	BC,0<8!0!80H	;P/u function & bank req
BANKX1	EQU	$-2
	CALL	STKCTL		;Move stack low?
RX24	EQU	$-2
	@@BANK			;  & invoke bank transfer
	RET
;
;	Task processor despooling routine
;
DSPLTCB	DW	DSPLR		;Despool task control blk
RX02	EQU	$-2
DSPLR	LD	A,($-$)		;P/u PFLAG$ & ck if
DFLAG	EQU	$-2		;  despooling is active
	RLCA
	RET	NC		;Back if not
	LD	HL,(S0DCB)	;If spooler is inactive
RX08	EQU	$-2		;  then don't try to
	INC	L		;  do any despooling
	LD	C,(HL)		;Get DCB vector
	INC	L
	LD	B,(HL)		;  into BC
	LD	HL,DVRABGN	;P/u spooler start
RX09	EQU	$-2
	XOR	A
	SBC	HL,BC		;If the same, then
	RET	Z		;  module is not active
FIX2UP	LD	HL,DSPLR0	;Point to transfer addr
RX03	EQU	$-2
	LD	BC,0<8!0!80H	;P/u function & bank req
BANKX2	EQU	$-2
	CALL	STKCTL		;Move stack low?
RX25	EQU	$-2
	@@BANK			;  & invoke bank transfer
	RET
;
;	KI task routine to get a disk block
;
GETBLK	LD	HL,GETBLK1	;Point to transfer addr
RX04	EQU	$-2
	LD	BC,0<8!0!80H	;P/u function & bank req
BANKX3	EQU	$-2
	CALL	STKCTL		;Move stack low?
RX26	EQU	$-2
	@@BANK			;  & invoke bank transfer
GETBLK0	DB	0,0,0		;Orig @KITSK
DVRAEND	EQU	$-1
RELTABA	DB	TABALEN
	DW	RX02,RX05,RX06,RX08,RX09
	DW	RX19,RX20,RX21,RX22,RX23
	DW	RX24,RX25,RX26
TABALEN	EQU	$-RELTABA/2
;
;
DVRBBGN	EQU	$
;
;	Spool/despool module in bank x
;
S0DCB1	DW	0
;
;	Spool a character
;
SPLR1A	PUSH	HL		;Save new transfer addr
	PUSH	BC		;Save invocation
	LD	C,E		;Get char to PUT
	CALL	SPLR2		;Spool a char
RX1	EQU	$-2
	POP	BC
	POP	HL
	@@BANK			;Transfer back
SPLR2	LD	IX,SPLFCB
RX2	EQU	$-2
	LD	L,(IX+20H)	;P/u next buffer position
	LD	H,(IX+21H)
	LD	(HL),C		;Stuff char received
	DI
SPLR3	INC	(IX+20H)	;Inc lo order
	JR	Z,SPLR5		;Jump if block full
	CALL	DSPLR1X		;Output to *PR if avail
RX3	EQU	$-2
	EI
	JP	GETBLK2
RX4	EQU	$-2
SPLR5	LD	L,(IX+24H)	;P/u pointer to table
	LD	H,(IX+25H)
SPLR6	LD	A,(HL)		;Find spare pointer field
	INC	HL
	OR	(HL)
	JR	Z,SPLR7		;Jump if spare
	INC	HL		;  else index to next
	INC	HL
	INC	HL
	JR	SPLR6
SPLR7	DEC	HL
	PUSH	HL		;Save pointer
	INC	HL
	INC	HL
	LD	B,(HL)		;P/u memory segment byte
	INC	HL		;  or lo-order recno
	LD	A,(HL)		;End of table?
	CP	0FFH
	JR	NZ,SPLR10	;Jump if still space
	POP	HL
SPLR8	CALL	DSPLR1X		;Output to *PR if avail
RX5	EQU	$-2
	EI
SPLR9	CALL	GETBLK2		;Disk rec to bring back?
RX6	EQU	$-2
	DI
	JR	SPLR5
SPLR10	BIT	7,A		;Test mem or disk block
	JR	NZ,SPLR12	;Jump if disk pointer
;
;	Found a spare memory pointer
;
	POP	HL		;Rcvr ptr to start
	PUSH	HL		;  of spare table field
	LD	(HL),L		;Place address of table
	LD	A,H		;  position into table
	INC	HL
	LD	(HL),A
	LD	(IX+21H),B	;Stuff hi-order free mem
	LD	L,(IX+26H)	;P/u current table ptr
	LD	H,(IX+27H)
	LD	(IX+2AH),L	;Stuff last block pointer
	LD	(IX+2BH),H
	POP	BC		;Rcvr ptr to field start
	LD	(HL),C		;Set up a link to this
	INC	HL		;  block in last block
	LD	(HL),B
	LD	(IX+26H),C	;Reset current block ptr
	LD	(IX+27H),B
	EI
	RET
;
SPLR12	EQU	$
	EI
	LD	C,B		;Lo order recno
	AND	0FH		;Hi-order recno
	LD	B,A
	PUSH	IX		;Position file to recno
	POP	DE		;FCB to DE
	@@POSN			;Posn to desired record
	DB	0,0,0		;Reserved
	LD	C,(IX+26H)	;P/u current table ptr
	LD	B,(IX+27H)
	POP	HL		;P/u ptr to this disk
	PUSH	HL		;Block table field
	LD	(HL),C		;Tell this disk block
	INC	HL		;  field which memory
	LD	(HL),B		;  block it is storing
	POP	BC		;Exchange link in last
	LD	L,(IX+2AH)	;  block pointer with new
	LD	H,(IX+2BH)	;  link since this memory
	LD	(HL),C		;  block is now on disk
	INC	HL
	LD	(HL),B
	LD	(IX+2AH),C
	LD	(IX+2BH),B
	LD	BC,256		;Block move the page
	LD	L,C		;  into the low memory
	LD	H,(IX+21H)	;  buuffer fo disk I/O
	PUSH	DE		;Save fcb pointer
	LD	DE,LOWBUF$
	LDIR
	POP	DE
	@@WRITE			;Write out the block
	DB	0,0,0		;Reserved
	RET
;
DSPLR0	PUSH	HL		;Save new transfer addr
	PUSH	BC		;Save invocation
	CALL	DSPLR1		;Send device a char
RX7	EQU	$-2
	POP	BC
	POP	HL
	@@BANK			;Transfer back
;
;	Routine will output a char to PR if available
;
DSPLR1X	LD	A,($-$)		;P/u PFLAG$ & ck if
DFLAG1	EQU	$-2		;  despooling is active
	RLCA
	RET	NC		;Back if not active
DSPLR1	LD	BC,4<8!0	;Init to CTL-0
	PUSH	IX		;Save current DCB vector
PUDCB	LD	IX,(S0DCB1)	;Point to printer
RX9	EQU	$-2
	@@CHNIO			;Ck *PR status
	POP	IX
	RET	NZ		;Ret if not avail
PUFCB	LD	IX,SPLFCB
RX10	EQU	$-2
	LD	A,(IX+23H)	;See if char in buffer
	OR	A		;  to send to the printer
	RET	Z		;Ret if none
	LD	H,A		;None also if GET pointer
	CP	(IX+21H)	;  is same as PUT pointer
	LD	A,(IX+22H)
	JR	NZ,DSPLR2
	CP	(IX+20H)
	RET	Z		;In & out the same
DSPLR2	LD	L,A		;P/u the character
	LD	C,(HL)		;Xfer to output reg
	PUSH	IX		;Save this dcb vector
	LD	B,2		;Set chain for PUT
PUDCB1	LD	IX,(S0DCB1)	;Pt to spooled DCB
RX11	EQU	$-2
	@@CHNIO			;Output the char
	POP	IX		;Rcvr dcb
	INC	(IX+22H)	;Bump PUT (out) ptr
	RET	NZ		;Ret if still more in buf
	LD	(IX+23H),0	;Block empty, turn off
	RET			;  hi-order & exit
;
;	Routine to see if we can grab a block back from
;	the disk file & insert into a spare memory block
;
GETBLK1	PUSH	HL		;Save new transfer addr
	PUSH	BC		;Save invocation
	CALL	GETBLK2		;Spool a char
RX12	EQU	$-2
	POP	BC
	POP	HL
	@@BANK			;Transfer back
GETBLK2	PUSH	AF
	PUSH	IX		;Save in case DSPLR1
GETBLK3	LD	A,(SPLFCB+23H)	;Jump if block being
RX13	EQU	$-2
	OR	A		;  printed is not empty
	JR	NZ,GETBLK6
;
;	The block's been despooled. Get 1 from D,M?
;
	PUSH	HL
	PUSH	DE
	PUSH	BC
GETBLK4	LD	IX,SPLFCB
RX14	EQU	$-2
	LD	L,(IX+28H)	;P/u pointer of block
	LD	H,(IX+29H)	;  being printed
	PUSH	HL
	LD	C,(HL)		;Point to POSN or hi-mem
	INC	HL		;  byte of field this
	LD	B,(HL)		;  field points to
	LD	HL,2		;P/u the POSN or hi-order
	ADD	HL,BC
	LD	A,(HL)
	INC	HL
	BIT	7,(HL)		;Jump if it is pointing
	JR	NZ,GETBLK7	;  to a disk block
	LD	(IX+23H),A	;Reset hi order of where
	POP	HL		;  next block coming from
	LD	(HL),0		;Show that this block
	INC	HL		;  is spare
	LD	(HL),0
	LD	(IX+28H),C	;Set the next block
	LD	(IX+29H),B	;  to be printed
GETBLK5	POP	BC
	POP	DE
	POP	HL
GETBLK6	EQU	$
	DI
	CALL	DSPLR1X		;Check if we can despool
RX15	EQU	$-2		;  a character while
	EI			;  we are in here
	POP	IX
	POP	AF
	RET
;
;	Next block to print is on disk, get it
;
GETBLK7	LD	C,A		;Set up position
	LD	A,(HL)
	AND	0FH
	LD	B,A
	PUSH	IX		;Set FCB & position
	POP	DE		;  the spool file
	@@POSN
	DB	0,0,0		;Reserved
	POP	HL		;Rcvr table ptr of
	PUSH	HL		;  block just finished
	INC	HL
	INC	HL		;P/u its buffer location
	@@READ			;Read block from file
	DB	0,0,0		;Reserved
	LD	BC,256		;Block move from the
	LD	D,(HL)		;  low memory buffer
	LD	E,C		;  to RAM page
	LD	HL,LOWBUF$
	LDIR
	POP	HL		;Tbl ptr of block fin'd
	PUSH	HL
	LD	A,(HL)		;P/u field addrress of
	INC	HL		;  the next table field
	LD	H,(HL)		;  that gets printed
	LD	L,A
	LD	C,(HL)		;P/u field address of the
	LD	(HL),0		;  block after that to 
	INC	HL		;  print & show this one
	LD	B,(HL)		;  as empty (this was the
	LD	(HL),0		;  disk one just vacated)
	POP	HL
	LD	(HL),C		;Reset current printing
	INC	HL		;  block & point to
	LD	(HL),B		;  new next block
	INC	HL
	LD	B,(HL)
	LD	(IX+23H),B	;Show where new printing
	JR	GETBLK5		;  block is & exit
;
;	File control block area for spool file
;
SPLFCB	DS	32
;
;	Pointer to the memory location where the next
;	character received from *XX can be put
;
PUTNXT$	DS	2
;
;	Pointer to where the next character to print
;	is going to come from
;
GETNXT$	DS	2
;
;	Pointer to start of block map table
;	table configuration is:
;	 TAB+0/1 -> store the TAB address if the field
;	 is currently in use for receiving. If a
;	 block is not current, it stores the
;	 address of the next TAB to print. If
;	 a disk field, then stores the TAB address
;	 of the previous block (link back)
;
;	 TAB+2 -> for a memory block, stores the hi-order
;	 byte of where the memory block starts. If
;	 a disk byte, stores the lo-order POSN #.
;
;	 TAB+3 -> s/b 0 for a memory block or if a disk
;	 block, it contains the hi-order POSN
;	 vector with bit 7 set.
;
MAPPTR$	DS	2
;
;	Pointer to the beginning of the memory table
;	block pointer for the block that is receiving
;	characters from *PR calls (the current block)
;
PUTBLK$	DS	2
;
;	Pointer to the memory table field for the block
;	that is printing characters
;
GETBLK$	DS	2
;
;	Points to the table position of the previous
;	block. This is used to reset the previous link
;
	DW	0
DVRBEND	EQU	$-1
RELTABB	DB	TABBLEN
	DW	RX01,RX03,RX04
	DW	RX1,RX2,RX3,RX4,RX5,RX6,RX7,RX8
	DW	RX9,RX10,RX11,RX12,RX13,RX14,RX15
	DW	RX16,RX17,RX18
TABBLEN	EQU	$-RELTABB/2
