	.TITLE	SPOL11.145
	.SBTTL	COPYRIGHT
;
;COPYRIGHT (C) 1975
;DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
;
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE FOR USE ONLY
;ON A SINGLE COMPUTER SYSTEM AND MAY BE COPIED ONLY WITH
;THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS
;SOFTWARE, OR ANY OTHER COPIES THEREOF, MAY NOT BE PRO-
;VIDED OR OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON
;EXCEPT FOR USE ON SUCH SYSTEM AND TO ONE WHO AGREES TO
;THESE LICENSE TERMS.  TITLE TO AND OWNERSHIP OF THE
;SOFTWARE SHALL AT ALL TIMES REMAIN IN DEC.
;
;THE INFORMATION IN THIS DOCUMENT IS SUBJECT TO CHANGE
;WITHOUT NOTICE AND SHOULD NOT BE CONSTRUED AS A COM-
;MITMENT BY DIGITAL EQUIPMENT CORPORATION.
;
;DEC ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY
;OF ITS SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DEC.
; 
; 
; 
	.SBTTL	LEGEND
;
EDIT=145.
;	#085	SK	UPDATE TO PERMIT RESTART AFTER "RESTORE#
;	086	SR		TAKE OUT CD CONDITIONAL
;	087	SR		EQUATE FOR ACCURATE SPOOLER SIZE
;	088	SK	16-OCT-73	FLUSH BUG FIX-WAIT FOR OUTPUT
;					TASK TO BE IDLE BEFORE SETTING SWITCHES
;					POINTERS
;	089	SR		CLEANUP
;	090	SK	17-OCT-73	BUG FIX IN END-GET FA FROM TCB
;					RATHER THAN COMPUTE IT TO PREVENT
;					ODD/EVEN BYTE PROBLEM
;	092	SK	3-DEC-73	GENERAL FIX UP
;	093	SK	10-DEC-73	CHANGE @SEND11 TCB FORMAT. SEND TASK CODEE
;					# OF THE TASK TO RETURN CONTROL TO IN WORD0
;	094	SK	17-DEC-73	B-E-B-E-B-E BUG FIX. STORE FA SENT IN BEGIN
;					TCB IN TCBDIS
;	095	SK	10-JAN-74	REMOVE HALT FROM GETBUF/GETRKT/XXCALL &
;					XXINT ROUTINES. FOR GETBUF & GETRKT REPLACE
;					BY WAIT.
;	096	SK	11-JAN-74	CDINT: EOD CARD/BUFFER FULL CONFLICT BUG FIX
;					PROTECT FINDBK,GETBUF,GETRKT ROUTINES
;	097	SCR	1-FEB-74	REDUCE TO LP,PL, 8 BUFF'S FOR FIELD
;	098	SK	14-FEB-74	CD MULTIPLE DECK BUG FIX
;	099	SK	18-FEB-74	CD EMPTY BUG FIX
;	100	SK	21-FEB-74	E. 099 CLEANUP
;	101	SK	25-FEB-74	E. 101 CLEANUP
;	102	SK	26-FEB-74	E. 101	CLEANUP
;	103	SK	28-FEB-74	SPOOLER FULL PROBLEM FIX ATTEMPT
;					+ DISK FAILURE HANDLING (IOPS 20)
;	104	SK	1-MAR-74	REFINE DISK FAILURE ERROR REPORT
;	115		26-JUN-74	DE-IMPLEMENT ALL EXCEPT  BEGIN AND END
;					PRINT BLOCK NUMBER + ADD ERROR REPORT
;					FOR REV SETTING OF NOT EQUAL TO "1"
;	116-119...........
;		BR,SK,SR.........
;			8-JUL-74	FIXED 2 END-OF-SPOOLER BUGS
;					FIXED ERROR 400 TO OCCUR ONLY ON
;					  REAL ERROR
;					FIXED EXTRA RKTCDS TO BE CREATED
;					  WITH EXTRA BUFFERS FOR THREE DEVICES
;	120	BR	9-JUL-74	CHANGED CDCALL LOCKOUT PRIORITY
;					  FROM 6 TO 5
;					FIXED BAD FIX ON ERROR 400 BUG
;	121	SK	10-JUL-74	FIX PDP-15 CTL 'C'/IOPSUC 15 PROBLEM
;	122	SK	14-JUL-74	CLEANUP+FIX 2 CONSECUTIVE .CLOSE PROBLEM
;	123	SK	31-JUL-74	FIX .CLOSE PL PROBLEM.
;	124	SK	1-AUG-74	FIX MULTIPLE SEQUENTIAL EOF PROBLEM
;	125	SK	2-AUG-74	EDIT #124 CLEANUP
;					IN LP & PL
;	126	BR	11-DEC-74	REMOVE MAP/TABLE SAVE JUNK
;	127	BR	12-DEC-74	ADD SPOOLER SIZE TO FRONT
;	128	BR	16-DEC-74	ADD STARTING OFFSET TO WORD 1
;	129	BR	22-DEC-74	FIX COND. ASM PARAM TO DELETE LISTING
;					ADD UNIT SELECTION FEATURE
;	130	BR/SK	23-31 DEC	FIX CTL'C'.IOPSUC15 LP PROBLEMS
;	131	"	"		"
;	132	SK	2-JAN-75	EDIT 129,130,131 CLEANUP
;	133	SCR	2-JAN-75	SPEED FINDDISKBLOCK ROUTINE
;	135	SCR	2-JAN-75	MAKE FROM 133, CLEANUP
;	136,7	SCR	2-JAN-75	DEBUG FINDBK ROUTINE
;	138	BLR	6-JAN-75	DELAY END/FIXUP IOPSUC 20
;	139	SCR	6-JAN-75	FIX:>1SPOOLER WAITING ON FULLDSK
;	140	BR	10-JAN-75	CLEAN UP OUT OF BLOCKS CONDITION.
;	141	GAR	20-JUN-75	FIX SO THAT THE SPOLLER DOESN'T
;					CAUSE THE PDP-11 TO TRAP AT LOC. 10
;					WHEN THE SPOOLER IS TURNED OFF
;					AND IS IMPROPERLY CONFIGURED.
;					(CODE DONE BY BR.)
;	142	MJH	20-AUG-75	DISCLAIMER
; 143	03-OCT-75 (RCHM-SCR)		FIX LP EOF.
; 144	08-OCT-75 (SCR)		1 DEV. BUFFERS TO 6; FIX 577 ERROR BYTE
;	145	BR	9-NOV-75	FIX EOF BUG
;
;		SPOL11
;
;THIS IS THE SPOOLER FOR THE UC15 SYSTEM.  IT RUNS UNDER
;PIREX ON THE PDP-11.  IT IS ALMOST ENTIRELY INDEPENDENT OF THE
;SOFTWARE ENVIORNMENT ON THE MASTER PROCESSOR(PDP-15).
;SPOL11 IS CURRENTLY CONTROLLED BY SPOL15 RUNNING UNDER
;DOS-15.  THE FOLLOWING DIRECTIVES, WHICH CAN BE ISSUED TO
;SPOL11 PERFORM THE INDICATED FUNCTIONS:
;
;	DIR.		CODE.			FUN.
;
;	B:BEGIN		0		START SPOOLING OF I/O
;	E:END		4		END SPOOLING
;
;
; A MAXIMUM OF 32(5BITS) DIRECTIVES & 8(3BITS) SUB_DIRECTIVES UNDER
; EACH DIRECTIVE IS POSSIBLE
;
;THE SPOOLER SUPPORTS THE FOLLOWING DEVICES:
;		LP:  LINE PRINTER
;		CD:  CARD READER
;		LT:  XY PLOTTER
;
;
	.SBTTL	ASSEMBLY PARAMETERS
;
;  CONDITIONAL ASSEMBLY, $LP, $CD, $PL, FOR LINEPRINTER
; FOR LP USE 40000
; FOR PL USE 10000
; FOR CD USE 20000
;
;     CARD READER, AND XY PLOTTER, RESPECTIVELY
DEVSPP=0
DEVCNT=0
	.IFDF	$LP
DEVCNT=DEVCNT+1
DEVSPP=DEVSPP!$LP
.ENDC
.IFDF	$CD
DEVCNT=DEVCNT+1
DEVSPP=DEVSPP!$CD
.ENDC
.IFDF	$PL
DEVCNT=DEVCNT+1
DEVSPP=DEVSPP!$PL
.ENDC
;
;
;
;
	.SBTTL	SYMBOLIC EQUATES
	.ENABL	ABS
	.LIST	ME
;
;GENERAL PURPOSE REGISTERS
;
R0=%0
R1=%1
R2=%2
R3=%3
R4=%4
R5=%5
R6=%6
R7=%7
PC=R7
SP=R6
PS=177776
SW=177570
AC=177302
MQ=177304
SC=177310
CKCREG=177546
;
;INSTRUCTION MNEMONICS
;
RETURN=207			;RTS PC
;
;INDEX CONSTANTS
;
;  ERROR BYTES FOR SPOOLER FOR SPECIFIC DEVICES
;
LPSPER=4*6+5		;4 IS LP DEV CODE
CDSPER=5*6+5
PLSPER=6*6+5
;
SPOLSZ=SPEND-SPBEG/2	;SPOOLER SIZE IN WORDS (EDIT #087)
;
;
;  EQUATE FOR DIFFERENCE IN ADDR. IN TABLE FOR PL-LP
PLTEOF=30			;PL ENTRY IN TABLE
CDTEOF=14			;CD	-
TCODE=2				;INDEX TO TASK CODE
FCODE=6				;      -  FUNCTION CODE
SBN  =10			;      -  START BLOCK NUMBER
NBK  =12			;      -  NUMBER OF SPOOL BLOCKS
UNIT=16				;UNIT TO SPOOL ON (BR-126)
TCBDSA=12			;	- START ADDRESS
DTCODE=26			;      -  CALLING DEVICE TASK CODE
TWD0=774			;	- TRAILER WORD 0 (WORD 376) IN BUFER
TWD1=776			;	-		1	 7
CBN=2				;TABLE OFFSET FOR A TASK ENTRY
CRP=4
NBN=6
LSB=10
LFB=12
;
;POINTERS TO LOCATIONS IN PIREX
;
MEMSIZ=40			;11'S LOCAL MEMORY SIZE
SEND11=1002			;LOC. CONTAINING RETURN ADDRESS ON
				;COMPLETION OF A REQUEST
CURTSK=1004			;CURRENT TASKS ATL POINTER
POL.LH=1006			;POOL LISTHEAD
LISTHD=1010			;BYSTEM LIST HEAD
R.SAVE=1012			;SAVE REG ROUTINE
R.REST=1014			;RESTORE REG ROUTINE
DEQU=1022				;DEQUE NEXT REQUEST ROUTINE
MOVEN=1020			;MOVE NODE ROUTINE
SEND15=1024			;SEND INT. TO 15
EMPTY=1026			;EMPTY TASKS DEQUE
ATLNP=1030			;ATL NODE POINTER TABLE
SPOLSW=1046			;SPOOLER SWITCHES
				;BIT 0-7 DEVICE BUSY IDLE SWITCH
				;'0' IF IDLE & '1' IF BUSY
				;	BIT	0	LP
				;		1	CD
				;		2	PL
				;	BITS	3-7	UNUSED
				;BITS 8-15 SPOOLER STATE/FUNCTION SWITCHES
				;	BIT	12=1	DESPOOLER ENABLED
				;		13=1	SPOOLING ENABLED
				;		14=1	SPOOLING+DESPOOLING
				;			ENABLED
				;		15=1	SPOOLER CONNECTED TO PIREX
RTURN=1036			;RETURN INST ADRESS
DEVST=1050			;DEVICE ERROR STATUS TABLE
DEVSPL=1064
CLTABL=1052			;CLOCK TABLE SPOOLER ENTRY
DEQU1=1054			;SET TASK IN WAIT STATE ROUTINE
TEVADD=1060			;TABLE OF TASK START ADDRESSES
CTLCT=1066			;PDP-15 CTL 'C' RUNNING COUNTER
SPUNIT=1070			;PIREX COPY OF UNIT TO SPOOL ON (BR-126)
;
;LITERALS
;
WRITEF=2				;RK FUNCTION CODE
READF=4				;	-
RKCOD=2				;RK TASK CODE UNDER PIREX
SDCOD=1				;SD	-
LPCOD=4				;LP	-
CDCOD=5				;CD	-
PLCOD=6				;PL	-
SPCOD=7				;SP	-
FLTCOD=7			;FLUSH DIR. TASK CODE(FOR SPOOLER)
;
IOPS15=15			;SPOOLER FULL ERROR CODE
IOPS20=20			;DISK HARDWARE FAILURE ERROR CODE
IOPS55=55			;NO BUFFERS AVAILABLE
IOPS77=77			;TASK NOT SUPPORTED ERROR CODE
;
CDSIZE=124			;CARD SIZE(80 COLOUMS=120+HEADER=4)
;
LVL5=240			;LEVEL 5 PS SETTING
LVL6=300			;	6
LVL7=340			;	7
;
LP1=142061			;LINE PRINTER UNIT #1
CD1=030461			;CARD READER UNIT #1
LT1=142461			;XY PLOTTER UNIT #1
;
CDEOD=104611			;END OF DECK CARD CODE
;
TABLBN=1773			;DISK HOME BLOCK NUMBER FOR TABLE
BTMPBN=1774			;	-		BITMAP
;
;	*******
BEGSW=170000			;PIREX SPOLSW SETTING FOR 'B'
CONTSW=40005			;	-	-	'C'
HALTSW=40000			;	-	-	'H'
CDTIME=200			;CARD READER EMPTY TIMER REQUEST
;
	.IFDF	EAE
EAESTK=6
	.ENDC
	.IFNDF	EAE
EAESTK=0
	.ENDC
;
	.SBTTL	MACROS
;
;GET ADDRESS OF REG.  'A' IN REG. 'B'
	.MACRO	ADR A,B
	MOV	PC,B
	ADD	#A-.,B
	.ENDM
;
;
;RESERVE A BLOCK OF ZEROED CORE
	.MACRO	.BLOCK N
	.NLIST
	.REPT	N
	.WORD	0
	.ENDR
	.LIST
	.ENDM
;
;CALL SUBROUTINE
	.MACRO	CALL ROUTIN
	JSR	PC,ROUTIN
	.ENDM
;
;PUSH ARGUMENT IN STACK
	.MACRO	PUSH ARG
	MOV	ARG,-(SP)
	.ENDM
;
;POP ARGUMENT OF STACK
	.MACRO	POP ARG
	MOV	(SP)+,ARG
	.ENDM
;
;INHIBIT INTERRUPTS
	.MACRO	.INH
	PUSH	@#PS
	BIS	#LVL7,@#PS
	.ENDM
;
;ENABLE INTERRUPTS
	.MACRO	.ENA
	POP	@#PS
	.ENDM
;
;EXIT FROM TASK IN STATE 'S'
	.MACRO	SEXIT S
	IOT
	.BYTE	0,S
	.ENDM
;
;ISSUE A TASK REQUEST
	.MACRO	IREQ
	MOV	#100000,R4
	IOT
	.BYTE	1,0
	.ENDM
;
;RK TCB TEMPLATES
	.MACRO	TCBRK
	SPCOD		;0.	API LVL & TRAP ADD.
	1600+RKCOD	;2.	NO. INT. + RK TASK + RETURN @SEND11
	0		;4.	REV
	0		;6.	BLOCK	#
	100000		;10.	DONT RELOCATE ADD.
	0		;12.	FA
	0		;14.	WC
	0		;16.	UNIT # (13-15) + FUN. (1-3)
	.BLOCK	3	;20.,22.,24.	DISK STATUR
	0		;26.	REQ. DEV. CODE
	.ENDM
;
	.MACRO	TCBDK	A
A:	0		;0.	API LVL & TRAP ADD.
	600+RKCOD	;2.	NO INT. + RK TASK
	0		;4.	REV
	0		;6.	BLOCK #
	100000		;10.	DONT RELOC. ADD.
	0		;12.	FA
	0		;14.	WC
	0		;16.	UNIT + FUN.
	.BLOCK	3	;20,22,24.	DISK STATUS
	.ENDM
;
;
	.SBTTL	SPOOLER DISPATCHER
SPBEG=.
	.WORD	SPEND-SPBEG/2		;SIZE OF SPOOLER (BR-127)
	.WORD	SPST			;STARTING BYTE OFFSET (BR-128)
	.BLOCK	8.+EAESTK*6-2	;(BR-128)
	.WORD	DUM
DUM:	.WORD	0
	.WORD	0
SPST:	MOV	SPST-2,R0	;GET TCP ADDRESS IN R0
	MOV	#100000,SPST-4	;FAKE 11'S REQ. TO PREVENT GETTING KILLED
				;THIS IS TO PREVENT STACK BLOW UP THRO'
				;CTL 'C'S FROM PDP-15
	MOV	@#CTLCT,SDCTSV	;SAVE CURRENT CTL 'C' COUNT FOR LATER CLEANUP
	TST	ONCEFL		;HAS THIS CODE ALREADY BEEN DONE?
	BNE	20$		;YES -- DON'T DO IT AGAIN
	MOV	#DEVSPP,@#DEVSPL	;SET UP DEVICE SPOOLED WORD
	ADR	SPBEG,R1	;INITALIZE ADDRESSES (PIC CODE)
	ADR	ADRTBL,R2
	MOV	#-ADTCNT,R3
10$:	ADD	R1,(R2)+		;CALCULATE ADDRESSES
	DEC	R3
	BNE	10$		;LOOP UNTIL ALL FINISHED
	MOV	BUFLAD,R2		;SET UP BUFFERS 
15$:	ADD	R1,(R2)+	;SET UP POINTERS GOING BACKWARDS THRU Q
	ADD	R1,@R2
	MOV	-(R2),R2
	CMP	R2,BUFLAD	;HEAD OF BUFFER?
	BNE	15$		;NO -- TRY AGAIN
20$:
	CMPB	#SPCOD+200,TCODE(R0)	;SPOOLER REQUEST?
	BEQ	Z1$
	MOV	PC,R1
	ADD	#DISP1-.,R1	; GET DEVICE DISPATCH TABLE IN R1
	CLR	R2
;
	CMPB	#LPCOD,TCODE(R0)	;LP REQUEST?
	BEQ	Z2$
;
	TST	(R2)+
	CMPB	#CDCOD,TCODE(R0)	;NO. CD REQUEST?
	BEQ	Z2$
;
	TST	(R2)+
	CMPB	#PLCOD,TCODE(R0)	;NO. PL REQUEST?
	BEQ	Z2$
;
;UNRECOGNISED TASK REQUEST REPORT.
;
ERROR:
	MOV	@#DEVST,R1
	ADD	#SPCOD*3*2+4,R1
	MOVB	#IOPS77,(R1)
	CALL	DEQREQ
;
Z1$:	MOV	PC,R1		;SPOOLER REQUEST ;GET SPOOLER DISPTACH
	ADD	#DISP0-.,R1	;TABLE IN #3
	MOVB	FCODE(R0),R2	;GET FUN. CODE
	BIC	#177740,R2
Z2$:	ADD	R1,R2		;ADD FUN. CODE TO R1
	ADD	(R2),R1		;BUILD DISPATCH JUMP X
	JMP	(R1)		;BRANCH TO APPROPRIATE ROUTINE
;
;SPOOLER DIRECTIVE DISPATCH TABLE
DISP0:	BEGIN	-DISP0		;BEGIN: CODE=0
	ERROR	-DISP0		;ERROR: CODE=2
	END	-DISP0		;END: CODE=4
	ERROR	-DISP0		;ERROR: CODE=6
	ERROR	-DISP0		;ERROR: CODE=10
	ERROR	-DISP0		;ERROR: CODE=12
	ERROR	-DISP0		;ERROR: CODE=14
;
;DEVICE REQUEST -DISPATCH TABLE
DISP1:	LPCALL	-DISP1		;LP: LINE PRINTER
	CDCALL	-DISP1		;CD: CARD READER
	PLCALL	-DISP1		;PL: XY PLOTTER
;
	.SBTTL	BEGIN DIRECTIVE
;
;THIS ROUTINE STARTS ALL SPOOLING OPERATIONS. SWITCHES, CONTROL REGISTERS
;ETC. ARE SET . THE BUFFER POOL, TCB POINTERS, BITMAP, TABLE ETC. ARE
;SET UP;BITMAP & TABLE ARE SAVED ON DISK(FOR BACKUP OPERATIONS). EACH
;INDIVIDUAL SPOOLED TASK IS THEN INITIALIZED & STARTED UP IF NECESSARY
;
;
BEGIN:	MOV	PC,R1		;GET ADDRESS OF DEVINT IN R1
	ADD	#DEVINT-.,R1
	MOV	@#SEND11,R2
	MOV	R1,SPCOD*2(R2)		;SET SEND11 ADDRESS IN PIREX
	MOV	14(R0),TCBDSA+TCBDIS
; INITIALIZE ALL SWITCHES
	MOV	#1,CBTPTR	;START BIT MAP SEARCH
	MOV	ASPLFU,R1	;##139##SETUP TASK CODE STACK FOR FINDBK
	MOV	R1,TCDINI	;##139##WHEN MORE THAN ONE GUY FINDS OUT
	MOV	R1,TCDPNT	;##139##THERE ARE NO BLOCKS
;SET  CONTROL REGS.
	MOV	PC,R1		;GET ADD. OF DUM IN R1
	ADD	#DUM-.,R1
	PUSH	R1		;SAVE ON STACK
	POP	-(R1)		; SET SPOOLER CONTROL REG.!!
;SETUP BUFFER POOL
;INITIALIZE RK TCB POINTERS
	MOV	RKCAD,R1		;GET RKTCBP ADD. IN R1
	MOV	PC,R2		;GET TCBR01 ADD. IN R2
	ADD	#TCBST-.,R2
	MOV	#TCBCT,R3	;SETUP TCBCT TCB'S
2$:	MOV	R2,(R1)+	;SET TCBRK1 POINTER
	ADD	#30,R2		;BUMP R2 TO TCBRK2
	DEC	R3
	BNE	2$
;INITIALIZE BITMAP
	PUSH	NBK(R0)		;GET SIZE OF SPOOLER AREA NUMBER
	ASR	(SP)		;COMPUTE SIZE OF BIT MAP
	ASR	(SP)		;SIZE=NUMBK/8+2
	ASR	(SP)
	BIC	#1,(SP)		;GET EVEN NUMBER
	MOV	BTMPAD,CWDPTR	;RESET CWDPTR
	MOV	BTMPAD,R1	;(BR_112. TEMP FIX)
	ADD	(SP)+,R1	;ADD OFFSET TO END
	MOV	R1,BTMPED	;SET UP BTMPED
	MOV	STBKNA,R1		;GET ADDRESS OF STBKNM-4 IS R1
	MOV	SBN(R0),(R1)+	;SET STARTING LOCK #
	MOV	NBK(R0),(R1)+	;SET NUMBER OF BLOCKS
	MOV	UNIT(R0),@#SPUNIT	;TELL PIREX SPOOLING UNIT (BR-126)
	MOV	UNIT(R0),UNITSP		;COPY INTO LOCAL MEM. (BR-126)
	SWAB	UNITSP			;SET UP FOR TCB USE (BR-126)
	MOV	#BTMPSZ,R2	;GET BIT MAP SIZE IN R2
	MOV	R1,R3
4$:	CLR	(R3)+
	DEC	R2
	BNE	4$
;INITIALIZE TABLE
	MOV	TABLAD,R1		;GET ADDRESS OF TABLE IN R1,R3,R1
	MOV	R1,R3
	MOV	#TABLSZ,R2	;GET TABLE SIZE IN R2
3$:	MOV	#-1,(R3)+
	DEC	R2
	BNE	3$
	MOV	#LP1,(R1)	;SET LP1(DED) IN TABLE
	MOV	#CD1,CDTEOF(R1)	;SET CD1 (DED) IN TABLE
	MOV	#LT1,PLTEOF(R1)	;SET PL1 (DED) IN TABLE
;SET SPOOLER SWITCHES
1$:	CLR	@#SPOLSW	;RESET SPOOLER SWITCHES
	BIS	#BEGSW,@#SPOLSW ;SET SPOOLER ENABLED AND RUNNING
;
;ALL SPOOLED TASKS HAVE TO BE INITIALISED. OPERATIONS LIKE SETTING
;& RESETTING SWITCHES, SETTING UP POINTERS, BUFFERS, STARTING UP
;TASK ETC. HAVE TO BE DONE AS INDICATED FOR EACH TASK
;
	.IFDF $CD
	BIS	#2,@#SPOLSW	;SET CD ON ONLY IF PRESENT
;INITIALIZE CD SPOOLER/DESPOOLER TASK
	CLRB	CDONCE
	MOV	#1000,CDONCE+1
	MOV	@#LISTHD,R2	;GET ADDRESS OF LISTHD IN R2
	ADD	#CDCOD*4,R2		;CLEAR CD DEQUE TASK CODE=5
	CALL	EMPTD
	MOV	@R1,NBN+TABLE+CDTEOF
	MOVB	#1,CDCNTI	;INITIALIZE CDCNTI
	CLRB	CDBMS		;RESET CDBMS
	CLRB	CDBFS
	MOV	R1,CDCBIP
	CMP	(R1)+,(R1)+
	MOV	R1,CDWDIP
	ADD	#CDSIZE,CDWDIP	;BUMP TO NEXT CARD
	MOV	R1,R5		;SAVE BUFFER ADDRESS ON DTA H
	CALL	STUPCT		;SET UP TCB TO READ A CARD
	.ENDC
	.IFDF $LP
;INITIALIZE LP SPOOLER/DESPOOLER TASK
	CLRB	LPONCE
	MOV	#1000,LPONCE+1
	MOV	@#LISTHD,R2	;GET ADDRESS OF LISTHD IN R2
	ADD	#LPCOD*4,R2	;CLEAR LP DEQUE: TASK CODE=4
	CALL	EMPTD
				;SET NBN=CBN FOR START UP
	MOV	@R1,NBN+TABLE
	MOV	R1,LPCBCP
	CMP	(R1)+,(R1)+
	MOV	R1,LPWDCP
	CLRB	LPBMS
	.ENDC
	.IFDF $PL
;INITIALIZE PL SPOOLER/DESPOOLER TASK
	CLRB	PLONCE
	MOV	#1000,PLONCE+1
	MOV	@#LISTHD,R2	;GET ADDRESS OF LISTHD IN R2
	ADD	#PLCOD*4,R2	;CLEAR PL DEQUE: TASK CODE=6
	CALL	EMPTD
	MOV	@R1,NBN+TABLE+PLTEOF
	MOV	R1,PLCBCP		;SET PLCBCP
	CMP	(R1)+,(R1)+
	MOV	R1,PLWDCP	;SET PLWDCP
	CLRB	PLBMS		;RESET PLBMS
	.ENDC
;ALL DONE DEQUE NEXT REQUEST
	CALL	DEQREQ
;
;EMPTY TASK DEQUE
EMPTD:
	.INH			;INHIBIT INTERRUPTS
	MOV	#EMPTY,R1	;EMPTY TASKS DEQUE
	JSR	PC,@(R1)+
	.ENA			;ENABLE INTERRUPTS
	CALL	FINDBK
	MOV	R1,-(SP)
	CALL	GETBUF
	POP	(R1)
	RETURN
	.SBTTL	END
;
;THIS ROUTINE SHUTS DOWN ALL SPOOLING OPERATIONS. THE TIMER REQUEST
;IS CANCELLED, SOFTWARE INTERRUPTS ARE IGNORED AND THE SPOL11 TASK
;IS DISCONNECTED FROM PIREX
;
;
END:	BIS	#LVL7,@#PS	;PROTECT ROUTINE (BR-138)
	MOV	@#CLTABL,R1	;NULL SPOOLER TIMER REQUEST
	CLR	SPST-4		;ENABLE STOP ALL I/O
	CLR	@#DEVSPL		;CLEAR DEVICED SPOOLED SWITCH
	CLR	SPCOD*4(R1)
	CLR	@#SPOLSW	;RESET SPOOLER SWITCH
	BIC	#LVL7,@#PS	;UNPROTECT TO ALLOW INTS. TO RUN DOWN (BR-138)
	MOV	#20,R5		;ALLOW 20 INTERRUPTS (CLOCK OR DEVICE) (BR-138)
1$:	WAIT			;WAIT FOR THEM (BR-138)
	DEC	R5		;COUNT 20 INTS. (BR-138)
	BNE	1$		;BRANCH IF NOT 20 (BR-138)
	BIS	#LVL7,@#PS	;INHIBIT INT.
	MOV	@#TEVADD,R1	;FIND THE ENTRY ADDRESS
	.IFDF	$LP	
	MOV	LPCOD*2(R1),R2	;FIND TASK ADDRESS
	CALL	STPTSK		;STOP THE TASK
	.ENDC
	.IFDF	$CD
	MOV	CDCOD*2(R1),R2	;STOP THE CARD READER TASK
	CALL	STPTSK		;STOP  THE TASK
	.ENDC
	.IFDF	$PL
	MOV	PLCOD*2(R1),R2	;STOP THE PLOTTER TASK
	CALL	STPTSK
	.ENDC
	MOV	#RTURN,R1	;GET RETURN INST. ADD IN R1
	MOV	@#SEND11,R2
	MOV	(R1),SPCOD*2(R2) ;SHUT OFF SEND11
	CMP	FCODE(R0),#4	;SEE IF THIS WAS  "END" OR IOPSUC 20 (BR-138)
	BNE	2$		;BRANCH IF IOPSUC 20 (BR-138)
	MOV	#1,R1		;TELL SPOL15 DONE
	MOV	#SEND15,R2
	JSR	PC,@(R2)+
2$:	ADR	TCBDIS,R5	;SET FA
	IREQ			;SEND REQUEST
;
STPTSK:	TST	R2		;(GAR-141) IS TASK IN EXISTENCE?
	BEQ	1$		;(GAR-141) BRANCH IF NOT.
	TST	-4(R2)	;PDP-11 REQUEST?
	BPL	1$		;NO -- IGNORE
	MOV	-(R2),R3	;YES -- TEST FOR SPOLLER REQUEST?
	CMPB	#SPCOD,@R3
	BNE	1$
	CLR	@R2
	CLR	-(R2)	;STOP TASK (CLEAR TCB ADR
	CLR	@-2(R2)		;STOP DEVICE FROM INTERRUPTING
1$:	RETURN
;
;
	.SBTTL	DEQUE NEXT REQUEST
;
;THIS ROUTINE CHECKS TO SEE IF THERE ARE ANY MORE REQUESTS IN THE
;'TRL'.  IT HAS 3 ENTRY POINTS:
;	DEQRQO		PROCESS NEXT REQUEST IF ANY
;	DEQRQ		ABOVE+TELL CALLER DONE
;	DEQREQ		ABOVE+INDICATE GOOD COMPLETION
;
DEQREQ:	BIS	#LVL7,@#PS	;INHIBIT INT.
	MOV	#1,R1		;TELL CALLER ALL DONE
DEQRQ:	MOV	#SEND15,R2
	CMP	@#CTLCT,SDCTSV	;ANY CTL 'C'S FROM PDP-15??
	BNE	DEQRQ0
	JSR	PC,@(R2)+	;NO.
DEQRQ0:	TST	(SP)+		;THROW AWAY PC!!!!
	BIS	#LVL7,@#PS
	MOV	SPSTAD,R1
	MOV	R1,R3
	CLR	-(R1)		;CLEAR BUSY FLAG
	CLR	-(R1)
	MOV	@#LISTHD,R1	;GET ADDRESS OF SYSTEM LISTAD IN R1
	ADD	#SPCOD*4,R1	;ADD OFFSET TO TASK LISTHEAD
	MOV	@#DEQU,R2	;DEQUE REQUEST
	JMP	(R2)
;
	.SBTTL	UTILITY ROUTINES
	.IFDF $CD
;
;SET UP TCB TO READ A CARD FROM CD
;CALLING SEQUENCE:	MOV	BUFAD,R5
;			CALL	STUPCT
;
STUPCT:	MOV	PC,R1		;GET ADDRESS OF TCBCD IN R1
	ADD	#TCBCD-.,R1
	BR	STUCOM		;ENTER COMMON ROUTNINE
	.ENDC
	.IFDF $LP
;
;SET UP TCB TO WRITE A LINE ON LP
;CALLING SEQUENCE:	MOV	BUFAD,R5
;			CALL	STUPLT
;
STUPLT:	MOV	PC,R1		;GET ADDRESS OF TCBLP IN R1 & R5
	ADD	#TCBLP-.,R1
	BR	STUCOM
	.ENDC
	.IFDF $PL
;
;SET UP TCB TO WRITE A LINE ON PL
;CALLING SEQUENCE:	MOV	BUFAD,R5
;			CALL	STUPPT
;
STUPPT:	MOV	PC,R1		;GET ADDRESS OF TCBPL IN R1 & R5
	ADD	#TCBPL-.,R1
	.ENDC
STUCOM:	MOV	R5,10(R1)
	MOV	R1,R5
	CLR	4(R1)		;RESET REV
	IREQ			;SEND
	RETURN
;
;SET UP DISK TCB TO READ A BLOCK WITH NO INTERRUPTS & RETURN ADDRESS
;	CALLING SEQUENCE:	ADR	BUFF,R4
;				ADR	-.CBN,R3
;				ADR	TCBDK-,R2
;				CALL	STUPDT
;
STUPDT:	MOV	R2,R5		;SAVE TCBP IN R5
	CMP	(R2)+,(R2)+	;BUMP TO REV
	CLR	(R2)+		;RESET REV
	MOV	(R3),(R2)+	;SET BLOCK #
	TST	(R2)+
	MOV	R4,(R2)+	;SET BUFAD
	MOV	#-400,(R2)+	;SET WC
	MOV	#READF,(R2)+
	ADD	UNITSP,-2(R2)	;ADD UNIT NUMBER (BR-126)
	IREQ
	RETURN
;
WAITBK:	PUSH	@#PS
	CLRB	@#PS
	WAIT
	POP	@#PS
	RETURN
;
;
	.SBTTL	FIND A FREE BLOCK ON DISK
;
;FIND A FREE BLOCK ON DISK
;CALLING SEQUENCE:	CALL FINDBK
;			FREE BLOCK # IF ANY RETURNED ON STACK 
;			IF NOT SET UP TO HALT CURRENT OPERATION & RETURN
;			REGS USED R1, R2, R3
FINDBK:	.INH
;
; < > < > < > < > < > < > < > < > < > < > START OF EDIT #133
;
	MOV	CWDPTR,R1	;ADDR OF BIT MAP WORD LAST USED
	MOV	CBTPTR,R2	;LAST BIT USED
	BMI	1$		;MINUS, NO BITS LEFT IN WORD
	ASL	R2		;START SEARCH WITH NEXT BIT UP
	ADD	(R1),R2		;THIS SETS NEXT ZERO BIT IN WORD!
	BCC	6$		;IF NO CARRY, A BIT WAS FOUND AND SET
1$:	TST	(R1)+		;BUMP R1 TO POINT TO NEXT WORD
	CLR	R3		;##135##FLAG FOR PASS 1;CWDPTR TO END
	MOV	#-1,R2		;COMPARE TO SEE IF WORD OF BITS ALL USED
2$:	CMP	(R1)+,R2	;DOES WORD HAVE ANY FREE BITS
	BNE	3$		;EITHER IT DOES, OR WE RAN OFF END
	CMP	(R1)+,R2
	BNE	3$
	CMP	(R1)+,R2	;LEAVE THESE SPREAD OUT TO SPEED LOOP
	BNE	3$		;SINCE WE ARE LEVEL 7, AND BR'S THAT BR
	CMP	(R1)+,R2	;ARE SLOWER!!!
	BNE	3$
	CMP	(R1)+,R2
	BEQ	2$		;WORD ALL FULL, KEEP LOOPING
; < > < > < > < > < > < > < > < > < > < > START OF EDIT #135
3$:	TST	R3		;SEE IF PASS 1 OR PASS 2
	BNE	4$		;NON0, GO FIELD PASS 2
	CMP	BTMPED,R1	;SEE IF RAN OFF END OF MAP
	BHIS	7$		;NO, SO WE'VE FOUND A FREE BIT
	MOV	CWDPTR,R3	;OFF END, INIT PASS 2, HERE'S FLAG
	CLR	(R3)		;CLEAR BEGINNING WORD TO STOP PASS 2
	MOV	BTMPAD,R1	;START PASS 2 AT TOP OF MAP
	BR	2$		;GO TO SCAN LOOP
;
4$:	COM	(R3)		;PASS 2, TURN BEGINNING WORD BACK TO -1
	CMP	R1,R3		;DID WE GET TO BEGINNING WORD
	BHI	55$		;YES, NO BITS, SET UP FOR 'ERROR'
;
7$:	MOV	-(R1),R2	;BACK UP TO GET COPY OF MAP WORD
; < > < > < > < > < > < > < > < > < > < > END OF EDIT #135
	MOV	R1,CWDPTR	;SAVE FIND POSITION FOR NEXT TIME CALLED
	INC	R2		;SETS FIRST ZERO BIT IN WORD!!
6$:	BIC	(R1),R2		;CLEAR ALL REST,LEAVING BIT FOR OUR BLOK
	BIS	R2,(R1)		;SET BIT IN MAP
	MOV	R2,CBTPTR	;REMEMBER BIT FOR NEXT TIME
	SUB	BTMPAD,R1	;BYTE INDEX FOR FOUND BLOCK #
	TSTB	R2		;IS BIT IN LOW HALF OF WORD
	BNE	8$		;YUP, NO CHANGE
	INC	R1		;IN HIGH HALF, INC BYTE COUNT
8$:	ASL	R1		;NIBBLE (4 BIT) INDEX FOR FIND
	BIT	#170360,R2	;IS BIT IN HIGH NIBBLE OF BYTE
	BEQ	9$		;NO, NOCHANGE
	INC	R1		;YES, SO INCR NIBBLE COUNT
9$:	ASL	R1		;CRUMB (2 BIT) INDEX FOR FOUND BLOCK
	BIT	#146314,R2	; IS BIT IN HIGH CRUMB OF MIBBLE
	BEQ	10$		;NO, NO CHANGE
	INC	R1		;YES, SO INCR CRUMB COUNT
10$:	ASL	R1		;NOW HAVE BIT COUNT FOR BLOCK
	BIT	#125252,R2	;IS BIT IN HIGH BIT OF CRUMP
	BEQ	11$		;NO, NO CHANGE
	INC	R1		;YES, SO ADD ONE
11$:	ADD	STBKNM,R1	;AND FINALLY ADD #OF FIRST MAPPED BLOCK
;
; < > < > < > < > < > < > < > < > < > < > END OF EDIT #133
;
;THE FOLLOWING PIECE OF CODE CHECKS TO SEE IF THE CURRENT BLOCK TO BE
;ALLOCATED TO THE CURRENT SPOOLING TASK EQUALS THE CBN OF THIS
;DESPOOLING TASK;IF THIS IS TRUE, THEN THE 'SPOOLER IS DECLARED FLOODED'
;THIS HAPPENS ONLY ON A WRAP AROUND(ENTIRE SPOOLER AREA IS TREATED AS A
;RING BUFFER)WHEN SPOOLING OPERATIONS ARE WAY AHEAD OF DESPOOLING OPERATIONS
;
;
;*****NOTE: AS NEW TASKS ARE ADDED NEW CODE HAS TO BE ADDED*****
;********** SIMILAR TO THE CODE FOR EXISTING TASKS**************
;
	MOVB	2(R0),R2	;GET CURRENT TASK CODE
	CMPB	#LPCOD,R2	;LP?
	BEQ	21$
	CMPB	#CDCOD+200,R2	;NO. CD?
	BEQ	22$
	CMPB	#PLCOD,R2	;NO. PL?
	BNE	26$
	MOV	TABPLC,R2	;YES
	BR	30$
21$:	MOV	TABPCB,R2
	BR	30$
;
22$:	MOV	TABCDC,R2
30$:
	CMP	R1,(R2)
	BEQ	5$
26$:
	POP	@#PS		;DEBUG;UNPROTECT
				;RETURN WITH BLOCK # ON STACK
	RETURN
;
;SORRY NO BLOCK FREE?? SETUP TO HALT CURRENT OPERATION
; < > < > < > < > < > < > < > < > < > < > START OF EDIT #135
55$:	MOV	AFNDBK,R3	;ADDR  'FINDBK' ; ENTER WHEN NO BLOCK
	POP	R2		;STACK NOW   /ENTER PS/CALL PC/
	PUSH	R3		;MAKE IT  /ENTER PS/ADDR FINDBK/CALL PC
	PUSH	R2		;AND HOPE IT FALLS THRU 5 OK
; < > < > < > < > < > < > < > < > < > < > END OF EDIT #135
5$:	MOV	(SP),R2		;DEBUG;GET OLD PS;BR HERE 1 BLK LEFT
	MOV	2(SP),(SP)	;DEBUG;SET UP PC
	MOV	R2,2(SP)	;DEBUG;SET PS
	PUSH	R0
	PUSH	R1
	PUSH	R2
	PUSH	R3
	PUSH	R4
	PUSH	R5
	MOV	@#CTLCT,SDCTSV	;SAVE CURRENT COUNT OF PDP-11 CTL 'C'S
	MOV	@#CURTSK,R2
	MOVB	6(R2),R1	;##139##GET TASK CODE
	MOVB	R1,SPLFUL	;##139##USE AS FULL FLAG
	BIC	#177417,R1	;##139##KEEP ONLY TASK CODE
	ASR	R1		;##139##MAKE CODE INTO WORD INDEX
	ASR	R1		;##139##
	MOV	#4,R3		;START TO COMPUTE TASKS DEVST LOCATION (BR-140)
	ADD	R1,R3		;CONTINUE DEVST STUFF (BR-140)
	ASR	R1		;##139## CONTINUE TASK CODE INDEX COMPUTATION
	ADD	R1,R3		;BACK TO DEVST COMPUT. R3=6*TASK CODE (BR-140)
	ADD	@#DEVST,R3	;FINISH DEVST COMPUT. (BR-140)
	MOVB	#IOPS15,(R3)	;MOVE IOPS 15 INTO DEVST TABLE (BR-140)
	DEC	TCDPNT		;##139##PUSH TASK CODE*2 ONTO BYTE STACK
	MOVB	R1,@TCDPNT	;##139##
	ADD	@#TEVADD,R1	;##139##KEEP BECAUSE IT WAS THERE
	MOV	(R1),R1		;##139##DON'T THINK NECESSARY
	TST	-(R1)		;##139##MAKES IT A PDP-11 REQ.
	MOV	#100000,-(R1)	;##139##WITH HIGH BIT OF HIGH ADDR WORD
	MOV	@#DEQU1,R1	;SET TASK IN WAIT STATE & EXIT
	JMP	(R1)
;
;
CWDPTR:	0			;CURRENT WORD POINTER
CBTPTR:	1			;CURRENT BIT POINTER
;				;##139##KEEP EDIT 139 IN THIS ORDER
TCDINI:	0			;##139##INIT'ED TO POINT TO SPLFUL!
TCDPNT:	0			;##139##ALSO INIT'ED TO POINT AT SPLFUL
	.WORD	0,0,0,0		;##139##STACK TASK CODES THRU TCDPNT
SPLFUL:	.BYTE	0		;##139##SPOOLER FULL FLAG
FRBKCT:	.BYTE	0		;##139##FREE BLOCK COUNT
SDCTSV:	0		;PDP-15 CTL 'C'S COUNT SAVE
;
;
	.SBTTL	FREE BLOCK ON DISK
;
;CALLING SEQUENCE:	CALL	FREEBK
;			BLOCK # IN R4
;			REGS USED R1,R2,R3
;
FREEBK:
	SUB	STBKNM,R4		;DEDUCT STARTING BLOCK #
	CLR	R2		;RESET WORD OFFSET COUNTES
	BR	1$
2$:	TST	(R2)+		;COMPUT WORD OFFSET IN BITMAP
1$:	SUB	#16.,R4
	BGE	2$		;DONE?
	ADD	#16.,R4		;RESTORE BIT OFFSET
	MOV	#1,R3		;RESET BIT POINTERS
4$:	TST	R4		;SET BIT POINTER CORRESPONDING TO OFFSET
	BEQ	3$
	DEC	R4
	ASL	R3
	BR	4$
3$:	MOV	BTMPAD,R1		;GET ADDR OF START OF BITMAP
	ADD	R2,R1		;ADD WORD OFFSET
	BIC	R3,(R1)		;CLEAR BIT FREE BLOCK!!
				;SPOOL FLOODED?
	TSTB	SPLFUL
	BEQ	8$
;
5$:
	INCB	FRBKCT
	CMPB	#5,FRBKCT		;5 FREE BLOCKS?
	BNE	8$
;
6$:	.INH			;##139##EXPAND RANGE OF .INH SLIGHTLY
	CLR	SPLFUL		;##139##CLEAR FRBKCT AND SPLFUL
	BIS	#20000,@#SPOLSW	;##139##ENABLE SPOOLING
	MOV	TCDPNT,R2	;##139##FETCH TASKS WHO ARE WAITING
9$:	MOVB	(R2)+,R3	;##139##WORD INDEX OF WAITING TASK
	ADD	@#ATLNP,R3	;##139##ADDED TO ADDR OF LIST OF ATL NOD
	MOV	(R3),R3		;##139##ADDR OF A WAITING NODE
	BIC	#17,6(R3)	;##139##SET TASK TO RUNNABLE
	CMP	TCDINI,R2	;##139##CHECK FOR MORE TO DO
	BNE	9$		;##139##MORE
	MOV	R2,TCDPNT	;##139##RESET POINTER FOR NEXT TIME
	.ENA		;DEBUG
8$:
	RETURN
;
	.SBTTL	GETPUT/CHNBUF/STUPRT
;
;THIS ROUTINE SETS UP FOR DISK BLOCK TRANSFERS(IN/OUT)
;
;CALLING SEQUENCE	(SP-10)	DEVICE CODE
;			(SP-6)	DISK FUNCT WRITE (2)/READ (4)
;			(SP-4)	BUFFER ADDRESS
;			(SP-2)	BLOCK #
;			(SP)	RETURN ADDRESS
;			CALL	GETPUT
;			REGS USED R4
GETPUT:	MOV	2(SP),(R4)+	;SET BLOCK # IS TCB
	TST	(R4)+		;STEP PAST MSB-FA
	MOV	4(SP),(R4)+	;SET BUFFER ADDRESS IN TCB
	MOV	#-400,(R4)+	;SET WC IN TCB
	MOV	6(SP),(R4)+		;SET DISK FUNCT IN TCB
	ADD	UNITSP,-(R4)		;ADD IN UNIT NUMBER
	ADD	#10,R4		;BUMP TO END OF R3
	MOV	10(SP),(R4)	;SET DEVICE CODE
	IREQ			;SEND DISK REQUEST
	RETURN
UNITSP:	.WORD	3400		;UNIT TO SPOOL ON - INITIALIZED TO 7 -
				;TO PREVENT ACCIDENTIAL USE - SINCE THERE
				;IS A LOW PROBABILITY OF A 8 DRIVE UC15
				;IN ANY CASE SPOL15 SETS THIS TO A VAILD
				;NUMBER UPON STARTUP (BEGIN) (BR-126)
	.SBTTL	GETBUF/GIVBUF
;
;CALLING SEQUENCE:	CALL	GETBUF
;			BUFFER ADDRESS RETURNED IN R1
;				REGS USED R1, R2, R3
GETBUF:	PUSH	@#PS
2$:	BIS	#LVL7,@#PS
	MOV	BUFLAD,R1
	CMP	R1,(R1)		;BUFFER: LEFT?
	BEQ	1$
	MOV	R1,R3		;YES ???
	MOV	(R1),R1		;GET FOR PTR OF BAFLHD IN R1
	PUSH	R1		;SAVE ON 1 TACK
	MOV	(R1),R2		;GET TO PTR OF BUF IN R2
	CMP	(R1)+,(R2)+	;BUMP TO BACK USED PTR.
	MOV	(R1),(R2)	;SET BACK UP TO OF NEXT BUT TO BUFLHD
	MOV	-(R1),(R3)	;SET TO PTR OF BUFLHD
	POP	R1		;GET BUFAD IN R1 & POP STACK
	CLR	(R1)		;RESET HEADER WORDS FOR DEBUGGING
	CLR	2(R1)
	.ENA
	RETURN
;
;	******TEMPORARY FIX FOR RUNNING OUT OF BUFFERS*******
;		EDIT #092
;
1$:	MOV	@#DEVST,R1	;SET ERROR CODE IN PIREX TABLE
	ADD	#SPCOD*3*2+4,R1
	MOVB	#IOPS55,(R1)
	CLRB	@#PS
	WAIT			;TIME OUT
	BR	2$
;
;CALLING SEQUENCE:	R3	BUFAD
;			CALL GIVBUF
;			REGS USE R1, R2, R3
GIVBUF:
	.INH
	MOV	BUFLAD,R1
	CMP	R1,(R1)		;BUFFER POOL EMPTY?
	BEQ	1$
	MOV	R1,R2		;COPY R1 INTO R2
	TST	(R2)+		;BUMP R2 TO BACK. PTR. OF BUFLHD
	MOV	@(R2),(R3)+	;SET FOR. PTR. OF N.BUF=FOR. PTR. OF
				;LAST BUF. IN CHAIN & BUMP TO BACK. PTR.
				;OF N.BUFF
	MOV	(R2),(R3)	;SET BACK. PTR. OF N.BUFF=BACK. PTR. OF
				;BUFLHD
	TST	-(R3)		;POINT R3 BACK TO FOR. PTR. OF N.BUFF
	MOV	R3,@(R2)	;SET FOR. PTR. OF LAST BUF. IN CHAIN
	MOV	R3,(R2)		;SET BACK. PTR. OF BUFLHD
	BR	2$
1$:	MOV	R1,(R3)+	;SET FOR. PTR. IN BUFF.
	MOV	R1,(R3)		;SET BACK. PTR. IN BUF
	TST	-(R3)		;POINT TO WD0 IN BUF.
	MOV	R3,(R1)+	;SET FOR. PTR. OF BUFLHD
	MOV	R3,(R1)		;SET BACK. PTR. IN BUFLHD
2$:	.ENA
	RETURN
	.SBTTL	RK TCB SETUP ROUTINES
;
;	***NOTE***
;
;A POOL OF DISK TCB'S(ONE FOR EACH BUFFER) IS KEPT TO ENABLE CONTINUOUS
;DISK BLOCK TRANSFERS. EACH TCB HAS A CORRESPONDING BIT WHICH IS SET IF
;BUSY, RESET IF IDLE. A POINTER TO EACH TCB IS KEPT IN A TABLE BELOW.
;
RKTCBS:	0			;TCB BUSY/IDLE SWITCH. MAXM. OF 16 TCB
RKTCBP=.			;POINTERS TO TCB
	.IFEQ	DEVCNT-1
	.REPT	DEVCNT*4+2		;(SCR-144)1 DEV. EXTRA BUFFER
	.WORD	0
	.ENDR
	.ENDC
	.IFNE	DEVCNT-1
	.REPT	DEVCNT*4
	.WORD	0
	.ENDR
	.ENDC
;
;GET A DISK TCB FROM POOL
;CALLING SEQUENCE:	CALL	GETRKT
;			ADD. OF TCB RET. IN R4
;			REGS. USED R1,R4,R5
GETRKT:	PUSH	@#PS
6$:	BIS	#LVL7,@#PS
	MOV	#1,R5		;START OF SEARCH
1$:	BIT	R5,RKTCBS		;FREE TCB?
	BEQ	2$
	ASL	R5		;TRY NEXT TCB
	CMP	#TCBLIM,R5	;TCB'S LEFT?
	BEQ	3$
	BR	1$		;YES.
2$:	BIS	R5,RKTCBS		;FREE TCB. SET BUSY SW
	CLR	-(SP)		;COMPUTE TCB ADD.
4$:	ROR	R5
	BEQ	5$
	ADD	#2,(SP)		;BUMP OFFSET
	BR	4$
5$:	MOV	RKCAD,R4		;GET ADD. OF TCB IN R4
	ADD	(SP)+,R4
	MOV	(R4),R4
	MOV	R4,R5		;SAVE IN R5 FOR IREQ
	CMP	(R4)+,(R4)+	;BUMP R4 TO REV
	CLR	(R4)+		;RESET REV & BUMP TO BLOCK #
	.ENA
	RETURN
;
;	******TEMPORARY FIX FOR RUNNING OUT OF TCB'S*******
;		EDIT #092
;
3$:	MOV	@#DEVST,R1	;SET ERROR CODE
	ADD	#SPCOD*3*2+4,R1
	MOV	#IOPS55,(R1)
	CLRB	@#PS
	WAIT
	BR	6$
;
;
;GIVE BACK TCB
;CALLING SEQUENCE:	TCB ADD. IN R4
;			CALL	GIVRKT
;			REGS. USED R1,R4,R5
GIVRKT:	.INH
	MOV	#1,-(SP)
	MOV	RKCAD,R1
2$:
	MOV	(R1)+,R5		;GET ADD. OF NEXT TCB
	CMP	R5,R4		;ADD. MATCH?
	BEQ	1$
	ASL	(SP)
	BR	2$		;YES.
;
1$:
	BIC	(SP)+,RKTCBS	;SET TCB IDLE SW
	.ENA
	RETURN
;
;
	.SBTTL	TASK SOFTWARE INTERRUPT DISPATCHER
;
;SEND15 IN PIREX TRANSFERS CONTROL TO DEVINT BY A "CALL @SEND11(-COD*2)"
;IF REQUESTED IN TCB.  THIS IS DONE BY A CODE OF '3' IN BYTE-3
;OF TCB. SPOOLER SETS THE ADDRESS OF DEVINT IN SEND11 WHEN STARTED
;
;
;
DEVINT:	CMP	#1,4(R0)	;GOOD COMPLETION??
	BNE	5$		;BRANCH IF NO
	CMPB	#RKCOD+200,TCODE(R0)	;RK REQ.?
	BEQ	RKINT
	CMPB	#LPCOD+200,TCODE(R0)	;LP REQ?
	BEQ	2$
	CMPB	#CDCOD+200,TCODE(R0)	;CD REQ?
	BEQ	3$
	JMP	PLINT
;
;
2$:	JMP	LPINT
;
3$:	JMP	CDINT
;
;
;
5$:
	RETURN
;
	.SBTTL	RK INTERRUPT SERVICE
;
;DISK REQUEST WAS MADE ON BEHALF OF A SPOOLED DEVICE: ??? FIND OUT
;WHAT HAS TO BE DONE NEXT
;
RKINT:	TST	20(R0)	;DISK HARDWARE FAILURE?
	BMI	3$
	CMPB	#WRITEF,16(R0)	;WRITE FUNCT?
	BEQ	1$
	MOV	6(R0),R4	;NO. READ GET BLOCK # IN R4
	CALL	FREEBK		;FREE BLOCK
	CMPB	#LPCOD,DTCODE(R0)	;FOR LP DEV?
	BEQ	10$
	CMPB	#CDCOD,DTCODE(R0)	;NO. CD DEV.?
	BEQ	20$
	CMPB	#PLCOD,DTCODE(R0)	;NO. PL DEV.?
	BEQ	30$
;ASSUME SPOOLER REQUEST
	JMP	DONE
;
1$:	JMP	WRITE
;
;
;
;THIS IMPLEMENTATION DOES NOT RECOVER FROM DISK FAILURE.
;USER IS INTIMATED OF THIS CONDITION -IOPS 20- AND THE SPOOLER GOES INTO A HALT
;STATE. THIS IS TO PERMIT USER TO RECOVER,IF POSSIBLE FROM THIS CONDITION.
;
3$:	BIS	#LVL7,@#PS	;SHUT OFF THE WORLD
	MOV	@#DEVST,R1	;SET ERROR IN PIREX TABLE
	ADD	#SPCOD*3*2+4,R1
	MOVB	#IOPS20,(R1)
	MOV	6(R0),-(R1)	;SET BLOCK NUMBER IN TABLE
	CLR	R0		;SETUP CALL FOR "END" (BR-138)
	JMP	END		;CALL END ROUTINE (BR-138)
	.IFNDF $LP
10$:	MOV	@#DEVST,R1	;SET ERROR CODE
	MOVB	#IOPS77,LPSPER(R1)
	RETURN
	.ENDC
	.IFDF $LP
;
;READ REQUEST WAS MADE FOR LP.
10$:	MOV	TABLAD,R3	;CBN=LFB?
	CMP	6(R0),LFB(R3)
	BNE	13$
	MOV	#-1,LFB(R3)	;YES. SET LFB=-1
13$:
	CLRB	LPBMD
	DECB	LPBUFS		;DECREMENT LPBUFS
	CMPB	#1,LPONCE	;LPONCE=1?
	BNE	DONE		;BRANCH IF NO
	MOV	LPCZAD,R2	;YES. START UP LP
11$:	CALL	12$
	INCB	LPONCE		;SET ONCE ONLY COMPLETE SW.
	BIT	#40000,@#SPOLSW	;SHUT DOWN?
	BEQ	DONE
	MOV	@R2,R5		;SAVE BUFAD ON STACK
	CALL	STUPLT		;NO SET LP TCB
	BIS	#1,@#SPOLSW	;SET LP BUSY SW
	BR	DONE		;EXIT
	.ENDC
;
;SECTIONS 12 USED FOR LP AND PL
;
;
12$:	MOV	6(R0),CBN(R3)	;SET CBN IN TABLE
	PUSH	12(R0)		;SAVE FA ON STACK
	MOV	@SP,(R2)+	;SET LPCBIP
	MOV	#4,(R2)		;SET LPWDIP
	ADD	@SP,(R2)	;COMPUTE LPWDIP
	ADD	#TWD1,(SP)	;BUMP TO LINK A NBN
	MOV	@(SP)+,NBN(R3)	;SET NBN IN TABLE
	MOV	#4,CRP(R3)	;SET CRP IN TABLE
	RETURN
	.IFNDF $CD
20$:	MOV	@#DEVST,R1
	MOVB	#IOPS77,CDSPER(R1)	;REPORT TASK NOT SUPPORTED
	RETURN
	.ENDC
	.IFDF $CD
;READ REQUEST WAS MADE FOR CD
20$:	MOV	TABCDT,R3	;CBN=LFB?
	CMP	6(R0),LFB(R3)
	BNE	21$
	MOV	#-1,LFB(R3)	;YES. SET LFB=-1
21$:
	CLRB	CDBMD
	DECB	CDBUFS
	CMPB	#1,CDONCE		;CDONCE=1?
	BNE	DONE
	MOV	CDCBAD,R2
	CALL	12$
	INCB	CDONCE		;YES. SET ONCE ONLY PROCESS COMPLETE SW.
	BR	DONE		;EXIT
	.ENDC
;READ REQUEST WAS MADE FOR A PLOTTER
	.IFNDF $PL
30$:	MOV	@#DEVST,R1
	MOVB	#IOPS77,PLSPER(R1)	;REPORT TASK NOT SUPPORTED
	RETURN
	.ENDC
	.IFDF $PL
;READ REQUEST WAS MADE FOR PL.
30$:	MOV	TABPLA,R3		;CBN=LFB?
	CMP	6(R0),LFB(R3)
	BNE	33$
	MOV	#-1,LFB(R3)	;YES. SET LFB=-1
33$:
	CLRB	PLBMD
	DECB	PLBUFS		;DECREMENT PLBUFS
	CMPB	#1,PLONCE	;PLONCE=1?
	BNE	DONE		;BRANCH IF NO
	MOV	PLCIAD,R2	;YES. START UP PL
31$:	CALL	12$
	INCB	PLONCE
	BIT	#40000,@#SPOLSW	;SHUT DOWN?
	BEQ	DONE
	MOV	@R2,R5		;SAVE BUFAD ON STACK
	CALL	STUPPT		;NO SET PL TCB
	BIS	#4,@#SPOLSW	;SET PL BUSY SW
;
	.ENDC
;ALL DONE; CHECK REV, RESOTRE REGS & EXIT
DONE:	MOV	R0,R4		;RETURN TCB
	CALL	GIVRKT
	RETURN
;
;
;DISK WRITE REQUEST WAS MADE FOR A SPOOLED DEVICE
;
WRITE:	MOV	12(R0),R1	;GET BUFFER ADDRESS IN R1
	MOV	R1,R3
	CLR	(R1)+		;RESET HWDS
	CLR	(R1)
	CALL	GIVBUF
	CMPB	#PLCOD,DTCODE(R0)	;REQ MADE FOR PL DEV?
	BEQ	43$
	CMPB	#CDCOD,DTCODE(R0)	;REQ MADE FOR CD DEV?
	BEQ	42$
	.IFNDF $LP
41$:	MOV	@#DEVST,R1
	MOVB	#IOPS77,LPSPER(R1)	;REPORT TASK NOT SUPPORTED
	RETURN
	.ENDC
	.IFDF $LP
;WRITE REQUEST MADE FOR LP
41$:	MOV	LPBMSA,R1	;RESET LPBMSA
	CLRB	(R1)
	MOV	TABLAD,R5
	MOV	6(R0),LSB(R5)	;SET LSB IN TABLE
	MOV	LPONAD,R3		;GET ADD OF LPBMS IN R3
	TSTB	(R3)		;FIRST TIME THROUGH??
	BNE	DONE
	INCB	(R3)+		;YES. SET SW.
	INCB	(R3)		;SET LPBMD
	CALL	GETBUF		;GET A BUFFER
	PUSH	#LPCOD		;SETUP FOR GETPUT SAVE DEV CODE
	.ENDC
44$:	PUSH	#READF		;SAVE DISK FUN.
	PUSH	R1		;SAVE BUFFER ADD
	PUSH	NBN(R5)		;SAVE BLOCK #
	CALL	GETRKT		;GET A RK TCB
	CALL	GETPUT		;GET BLOCK
	ADD	#10,SP		;CLEAN STACK
	BR	DONE		;CHECK REV & EXIT
	.IFNDF $CD
42$:	MOV	@#DEVST,R1
	MOVB	#IOPS77,CDSPER(R1)	;REPORT TASK NOT SUPPORTED
	RETURN
	.ENDC
	.IFDF $CD
;WRITE REQUEST MADE FOR CD
42$:	MOV	CDBMSA,R1	;SET CDBMD
	CLRB	(R1)
	MOV	TABCDT,R5
	MOV	6(R0),LSB(R5)	;SET LSB IN TABLE
	MOV	CDONAD,R4	;YES. CDONCE=0?
	TSTB	(R4)
	BNE	DONE
	INCB	(R4)		;SET CDONCE
	INCB	1(R4)		;SET CDBMS
	CALL	GETBUF		;GET A BUFFER
	MOV	R1,7(R4)	;SET CDOBCP
	CALL	GETBUF
	PUSH	#CDCOD		;SAVE DEV.CODE FOR GETPUT
	BR	44$		;ISSUE READ REQUEST
	.ENDC
	.IFNDF $PL
43$:	MOV	@#DEVST,R1
	MOVB	#IOPS77,PLSPER(R1)	;REPORT TASK NOT SUPPORTED
	RETURN
	.ENDC
	.IFDF $PL
;WRITE REQUEST MADE FOR PL
43$:	MOV	PLBMSA,R1	;RESET PLBMSA
	CLRB	(R1)
	MOV	TABPLA,R5
	MOV	6(R0),LSB(R5)	;SET LSB IN TABLE
	MOV	PLONAD,R3		;GET ADD OF PLBMS IN R3
	TSTB	(R3)		;FIRST TIME THROUGH??
	BNE	DONE
	INCB	(R3)+		;YES. SET SW.
	INCB	(R3)		;SET PLBMD
	CALL	GETBUF		;GET A BUFFER
	PUSH	#PLCOD		;SETUP FOR GETPUT SAVE DEV CODE
	BR	44$
	.ENDC
;
;
	.SBTTL 	SPOOLED TASKS
;
;UNDER THE CURRENT IMPLEMENTATION, SPOOLED TASKS BASICALLY CONSIST OF A
;"CALL SERVICE ROUTINE" & A "INTERRUPT SERVICE ROUTINE" BESIDES THE
;OTHER SUPPORTING ROUTINES. THE 'CALL SEVICE ROUTINE' IS THE SPOOLER FOR
;OUTPUT TASKS(LP) AND DESPOOLER FOR INPUT TASKS(CD). CONVERSELY THE 'INTERRUPT
;SERVICE ROUTINE' IS THE DESPOOLER FOR OUTPUT TASKS(LP) & THE SPOOLER FOR
;INPUT TASKS(CD).
;IN GENERAL THE SPOOLER ROUTINE COPIES THE RECORD OF DATA RECEIVED, INTO
;THE CURRENT BUFFER & INDICSTES COMPLETION OF REQUEST TO CALLER. WHEN
;THE BUFFER IS FULL IT WRITES IT OUT ON THE NEXT AVAILABLE FREE BLOCK
;ON THE DISK. IT ALSO GETS A NEW BUFFER TO COPY THE NEXT RECORD. THE ONLY
;RECORD OF SPOOLED DATA MAINTAINED ARE THE LFB & LSB ENTRIES IN THE TABLE
;OTHER THAN THE FORWARD LINK IN EACH SPOOLED DATA BLOCK, CURRENT WORD
;POINTER, CURRENT BUFFER POINTER & NEXT BUFFER POINTER. THE LAST BLOCK IN
;A SPOOLED DATA FILE HAS A BACKWARD LINK WHICH EITHER POINTS TO THE LAST
;BLOCK OF THE PREVIOUS SPOOLED DATA FILE OR = TO '-1' IF NONE PRESENT.
;THERE CAN BE ONE OR MORE RECORDS IN A BLOCK. THE MAXM. SIZE OF A
;RECORD IS 252 WORDS.
;THE DESPOOLER ROUTINE UNPACKS THE BLOCKED DATA INTO RECORDS & SENDS
;IT TO THE CALLER OR DRIVER TASK. TO SPEED UP THIS PROCESS THE DESPOOLER
;ROUTINES ARE DOUBLE BUFFERED. BESIDES THE CURRENT WORD POINTER, CURRENT
;BUFFER POINTER & NEXT BUFFER POINTER THE ONLY OTHER INFORMATION MAINTAINED
;ARE THE CBN, CRP & NBN ENTRIES IN THE TABLE. DESPOOLING OPERATIONS ARE
;TERMINATED WHEN CBN=LSB AND THE TASK IDLE SWITCH IS SET. A RECORD WITH
;'0' AS THE FIRST WORD INDICATES THE ABSENCE OF ANY MORE RECORDS IN THAT
;BLOCK.
;
;	CBN	CURRENT BLOCK NUMBER
;	CRP	CURRENT RECORD POINTER
;	NBN	NEXT BLOCK NUMBER
;	LFB	LAST FILE BLOCK(NUMBER)
;	LSB	LAST SPOOLED BLOCK(NUMBER)
;
	.SBTTL	LP INTERRUPT SERVICE
;
;THIS ROUTINE HANDLES COMPLETION OF I/O SOFTWARE INTERRUPT FROM THE
;DRIVER TASK IN PIREX. IT DESPOOLS THE SPOOLED DATA ONTO THE LP.
;
	.IFDF	$LP
LPDUMI:	.BYTE	0		;UNUSED
LPONCE:	.BYTE	0		;ONCE ONLY SW
LPBMD:	.BYTE	0		;BLOCK IN MOTION SW
LPBUFS:	.BYTE	0		;EMPTY BUFFER COUNT
LPCBIP:	0			;CURRENT BUFFER POINTER
LPWDIP:	0			;CURRENT WORD POINTER
LPOBIP:	0			;NEXT BUFFER POINTER
	.ENDC
;
;
	.IFNDF $LP
LPINT:	MOV	@#DEVST,R1
	MOVB	#IOPS77,LPSPER(R1)	;REPORT TASK NOT SUPPORTED
	RETURN
	.ENDC
	.IFDF $LP
;
LPINT:	MOV	TABCRT,R1
	BIS	#LVL5,@#PS	;INHIBIT DISK INTERRUPTS
	CMP	#-1,(R1)	;ANY MORE TO DO?
	BNE	1$
11$:	MOV	LPONAD,R3		;GET C(LPCBIP) IN R3
	CLRB	(R3)+		;RESET SW.'S
	CLRB	(R3)+		;BUMP TO LPBUFS
	INCB	(R3)+		;RELEASE BUFF.
	MOV	(R3),R3
	CALL	GIVBUF		;GIVE BACK BUFFER
2$:	BIC	#1,@#SPOLSW	;NO. SET LP IDLE SW
50$:	RETURN
1$:	TST	(R1)		;YES. BLOCK IN MOTION?
	BNE	3$
15$:	MOV	LPCPAD,R4	;SK-124 YES. GET ADD OF LLPCPADBIP IN R2
	MOV	(R4),R3		;RELEASE BUFFER
	CALL	GIVBUF
	INCB	-(R4)
10$:	TSTB	-1(R4)		;BLOCK READ IN?
	BEQ	4$
	CALL	WAITBK
	BR	10$
4$:
	MOV	TABCRT,R1	;DEBUG
	MOV	TABLE+NBN,TABLE+CBN	;SET CBN=NBN
	MOV	#4,TABLE+CRP		;SET CRP
	MOV	PC,R3		;GET LPOBIP ADD. IN R3
	ADD	#LPOBIP-.,R3
	MOV	(R3),R4		;GET C(LPOBIP) IN R3 & BUMP TO TWD1
	MOV	TWD1(R4),TABLE+NBN	;SET LP.NBN
	MOV	LPCPAD,R2		;GET ADD. OF LLPCPADBIP IN R2
	MOV	(R3),(R2)+	;SET LPCBIP
	MOV	(R3),(R2)	;SET LPWDIP
	ADD	#4,(R2)
	BR	5$		;SEND WRITE REQ IF NOT SHUT DOWN
3$:	MOV	LPCWAD,R2		;GET ADD OF LPWDIP IN R2
	MOV	@(R2),-(SP)
	ADD	#5,(SP)		;EVEN BYTE COUNT
	BIC	#177401,(SP)
	ADD	(SP),(R1)	;BUMP CRP
	ADD	(SP)+,(R2)	;BUMP LPWDIP
5$:	BIT	#40000,@#SPOLSW	;SHUT DOWN?
	BEQ	2$
	BIT	#1,@#SPOLSW	;SHUT LP?
	BEQ	2$
	BIT	#10000,@#SPOLSW	;SHUT DESPOOLER
	BEQ	2$
	TST	@(R2)		;FIRST RECORD A .CLOSE?
	BNE	13$
	CMP	-2(R1),4(R1)	;ANY MORE DATA?
	BNE	14$
	CALL	12$		;NO. SET TABLE ENTRIES
	BR	11$		;RESET SWITCHES & EXIT
14$:	MOV	LPONAD,R2	;DEBUG;SK-124 GET LPBUFS ADRRESS
	ADD	#2,R2		;DEBUG;SK-124
	CMPB	#1,(R2)		;DEBUG;SK-124 ONE FREE BUFFER?
	BNE	15$		;SK-124
	TSTB	-1(R2)		;DEBUG;SK-124 YES. BLOCK IN MOTION?
	BNE	15$		;SK-124
	CALL	9$		;SK-124 NO. GET NEXT BLOCK
	BR	15$		;SK-124 RELEASE BUFFER & WAIT FOR BLOCK TO COME IIN
;
;
13$:	MOV	@R2,R5		;NO. SAVE BUFF ADD ON STACK
	CALL	STUPLT		;SET UP TCB TO UNTI A LINE
	MOV	TABCRT,R1
	MOV	(R2),R4		;CHECK FOR BUFFER EMPTY
	MOV	@(R2),-(SP)	;GET BYTE COUNT
	ADD	#5,(SP)		;EVEN BYTE COUNT
	BIC	#177401,(SP)
	ADD	(SP)+,R4	;BUMP R4 TO POINT TO PT WORD OF NEXT
	MOV	PC,R2		;NO. GET ADD OF LPBUFS IN R2
	ADD	#LPBUFS-.,R2
	TST	(R4)		;LAST RECORD?
	BEQ	6$
	CMP	#-1,(R4)
	BEQ	6$
	CMPB	#1,(R2)		;LPBUFS=1
	BNE	50$
	TSTB	-(R2)		;YES. BLOCK IN NEXT?
	BNE	50$
	CMP	-2(R1),4(R1)	;NO. MORE TO DOE (CBN=LSB)
	BEQ	50$
	CALL	9$		;SK-124 GET NEXT BLOCK
	RETURN			;RETURN TO CALLER (BR-145)
;
;
;BUFFER EMPTY; TEST IF MORE BLOCK TO DO?
6$:	CMP	-2(R1),4(R1)	;MORE TO DO? (CBN=LSB)
	BEQ	7$
	CLR	(R1)		;SK-124 SET CRP=0
	CMPB	#1,(R2)		;LPBUFS=1?
	BNE	8$
	TSTB	-(R2)		;BLOCK IN TRANSIT?
	BNE	8$		;SK-124
	CALL	9$		;SK-124 GET NEXT BLOCK
8$:	RETURN			;RETURN TO CALLER (BR-145)
;NO MORE BLOCKS TO DO
7$:	CALL	12$		;SET TABLE ENTRIES
	RETURN			;RETURN TO CALLER (BR-145)
;
;
;GET NEXT BLOCK
9$:	PUSH	R1
	PUSH	R2
	CALL	GETBUF		;YES. GET BUFFER & READ NEXT BLOCK
	MOV	R1,R4		;SAVE BUFAD IN R4
	POP	R2
	POP	R1
	MOV	R4,LPOBIP		;SET LPOBIP
	INCB	(R2)		;SET LPBMS SW
	MOV	#LPCOD,R3		;GET DEV.CODE IN R3. FOR GETBLK
	MOV	R1,R2		;GET LP.CRP ADD. IN R2
	CALL	GETBLK		;GET BLOCK FROM DISK
	RETURN			;SK-124
;
12$:
	MOV	#-1,@R1		;SET CRP=-1
	MOV	#-1,6(R1)	;SET LFB=-1
	RETURN
;
	.ENDC
	.SBTTL	LP CALL SERVICE
;
;THIS ROUTINE SERVICES CALLS TO OUTPUT DATA ONTO THE LP. IT SPOOLS THE
;DATA SENT BY THE CALLER ONTO THE DISK.
;
	.IFDF	$LP
LPDUMC:	.BYTE	0		;UNUSED
LPBMS:	.BYTE	0		;BLOCK IN MOTION SW
LPCBCP:	0			;CURRENT BUFFER POINTER
LPWDCP:	0			;CURRENT WORD POINTER
LPOBCP:	0			;NEXT BUFF POINTER(DUMMY)
	.ENDC
;
;
	.IFNDF $LP
LPCALL:	MOV	@#DEVST,R1
	MOVB	#IOPS77,LPSPER(R1)	;(SCR-144)REPORT TASK NOT SUPPORTED
	CALL	DEQREQ
	.ENDC
	.IFDF $LP
LPCALL:	CMP	-(R1),-(R1)	;POINT R1 TO LPWDCP
	BIT	#20000,@#SPOLSW	;SHUT SPOOLER?
	BEQ	10$
	PUSH	R1		;SAVE R1.	NO
	MOV	(R1),R1		;GET CONTENTS OF LPWDCP IN R1,R4
	MOV	R1,R4
	MOV	10(R0),R3	;GET CALLER BUF. ADD. IN R3
	ASL	R3		;RELOCATE ADD.
	ADD	@#MEMSIZ,R3
	MOVB	(R3),R2		;GET BYTE COUNT FROM BUFFER IN R2
	ADD	#5,R2		;ADD HWD BYTE COUNT + EVEN BYTE COUNT
	BIC	#177401,R2
	ADD	R2,R1		;BUMP LPWDCP BY THE SIZE OF NEXT RECD.
	MOV	(SP),R5		;GET LPWDCP ADD. IN R4
	PUSH	-(R5)		;POINT TO LPCBCP & SAVE CONT. OF LPCBCP ON STACK
	ASR	R2		;CONVERT TO WORD COUNT
	SUB	(SP)+,R1		;COMPUTE SPACE REM.
	CMP	#770,R1		;SPACE LEFT?
	BLT	4$
	CALL	COPBUF		;COPY CALLER BUFFER
	POP	R4		;TEMP SAVE R1 IN R2
	CALL	6$		;CHECK FOR .CLOSE
	BR	8$		;NO
;
10$:	MOV	#-600,4(R0)	;SPOOLER SHUT DOWN. REPORT
	PUSH	R1		;DUMMY
	JMP	DEQRQ
;LAST RECORD WAS NOT A .CLOSE
8$:	MOV	LPCBAD,R1	;POINT R1 TO LPCBCP (BR-145)
	MOV	R1,R2		;SAVE IN R2
	TST	(R1)+		;BUMP R1 LPWDCP
	MOV	(R1),R1		;GET CURRENT WORD ADD. IN R1
	SUB	(R2),R1		;GET REMAINNING # OF WORDS
	CMP	#770,R1		;SPACE LEFT?
	BGT	2$
9$:	MOV	PC,R1		;GET ADD. OF LPWDCP IN R1
	ADD	#LPWDCP-.,R1
	CLR	@(R1)		;NO. PUT BUFFER ON DISK
	CALL	FINDBK		;GET DISK BLOCK #
	PUSH	R1		;SAVE BLOCK # ON STACK
	MOV	LPCBCP,R2		;GET C(LPCBIP) IN R2
	MOV	(SP),TWD1(R2)	;SAVE BLOCK # IN TWD1
	MOV	#LPCOD,R3		;GET LP.DEV CODE IN R3
	MOV	LPBMSA,R1	;SET LPBMSA
	INCB	(R1)
	CALL	PUTBLK		;PUT BUFF. ON DISK
	MOV	LPCBAD,R4		;GET ADD. OF LLPCBADBCP IN R3&R4
3$:	CALL	GETBUF		;GET A NEW BUF
	MOV	R1,(R4)+	;SET LPCBCP=BUFAD
	POP	(R1)		;SET BLOCK # IN HWD0 OF NEW BUFF.
	ADD	#4,R1		;BUMP R2 TO WORD 2 OF BUF
	MOV	R1,(R4)		;SET LPWDCP
2$:	CALL	DEQREQ		;DEQUE REQUEST & EXIT IN WAIT STATE
4$:	POP	R1		;RESTORE ADD. OF CURRENT WORD IN R1
	PUSH	R3		;SAVE R3,R2
	PUSH	R2
	CLR	@(R1)		;SET BUFF. END SW
	CALL	FINDBK		;GET DISK BLOCK #
	PUSH	R1		;SAVE BLOCK #
	CALL	GETBUF		;GET A BUFF.
	MOV	(SP),(R1)	;SET BLOCK # IN HWD0 OF NEW BUFF.
	MOV	LPCBAD,R4		;GET ADD. OF LLPCBADBCP IN R4
	PUSH	(R4)
	PUSH	(R4)		;SAVE CONT. OF LPCBCP
	ADD	#TWD1,(SP)	;BUMP TO TWD1
	MOV	4(SP),@(SP)+	;SET LINK IN OLD BUFF.
	MOV	R1,(R4)+	;SET LPCBCP & BUMP TO LPWDCP
	ADD	#4,R1		;POINT TO WORD 2 IN BUFF.
	PUSH	R4		;SAVE LPWDCP ADD. ON STACK
	MOV	R1,(R4)		;SET LPWDCP
	MOV	R1,R4		;GET CONT. OF LPWDCP
	MOV	6(SP),R2	;RESTORE R3,R2
	MOV	10(SP),R3
	CALL	COPBUF		;COPY CALLER BUFFER
	POP	R4		;SAVE LPWDCP ADD. IN R4
	POP	R2		;CONT. OF LPCBCP ON STACK TOP???
	MOV	#LPCOD,R3	;GET DEV.CODE IN R3. FOR PUTBLK
	ADD	#6,SP		;CLEAN STACK
	PUSH	R4		;SAVE R5
	MOV	LPBMSA,R1	;SET LPBMSA
	INCB	(R1)
	CALL	PUTBLK		;PUT BUFF. ON DISK
	POP	R4		;TEMP SAVE R1
	CALL	6$		;CHECK FOR .CLOSE
	BR	2$
6$:	MOV	R4,R1		;SAVE R4
	MOV	(R1),R4		;GET C(LPWDCP) IN R4
	CMP	#104001,-6(R4)	;TEST FOR EOF (.CLOSE) (BR-145)
	BNE	7$		;BRANCH IF NOT EOF (BR-145)
	MOV	R1,R4		;RESTORE R4
	ADR	TABLE+LFB,R2	;GET LP.LFB ADD. IN R2
	MOV	LPCBAD,R1
	PUSH	(R2)		;SAVE OLD LFB
	MOV	@(R1),(R2)	;SET LFB IN TABLE
	MOV	(R1),R1
	POP	2(R1)		;SET OLD LFB IN BUFFER
	MOV	#-1,TWD0(R1)	;SET EOF CODE IN BUFFER
	TST	(SP)+	;RETURN TO 9 (NOT SUB RETURN)
	BR	9$
7$:	RETURN
;
	.ENDC
COPBUF:
	CMP	SDCTSV,@#CTLCT	;DEBUG
	BNE	1$
	MOV	(R3)+,(R4)+	;COPY CALLER BUFFER
	DEC	R2
	BNE	COPBUF
	MOV	R4,@2(SP)
1$:	RETURN
;
	.SBTTL	PL INTERRUPT SERVICE
;
;THIS ROUTINE HANDLES COMPLETION OF I/O SOFTWARE INTERRUPT FROM THE
;DRIVER TASK IN PIREX. IT DESPOOLS THE SPOOLED DATA ONTO THE XY PLOTTER.
;
	.IFDF	$PL
PLDUMI:	.BYTE	0		;UNUSED
PLONCE:	.BYTE	0		;ONCE ONLY SW
PLBMD:	.BYTE	0		;BLOCK IN MOTION SW
PLBUFS:	.BYTE	0		;EMPTY BUFFER COUNT
PLCBIP:	0			;CURRENT BUFFER POINTER
PLWDIP:	0			;CURRENT WORD POINTER
PLOBIP:	0			;NEXT BUFFER POINTER
	.ENDC
;
;
	.IFNDF $PL
PLINT:	MOV	@#DEVST,R1
	MOVB	#IOPS77,PLSPER(R1)	;REPORT TASK NOT SUPPORTED
	RETURN
	.ENDC
	.IFDF $PL
;
PLINT:	MOV	TABPDT,R1
	BIS	#LVL5,@#PS	;INHIBIT DISK INT.
	CMP	#-1,(R1)	;ANY MORE TO DO?
	BNE	1$
11$:	MOV	PLONAD,R3		;GET C(PLCBIP) IN R3
	CLRB	(R3)+		;RESET SW.'S
	CLRB	(R3)+		;BUMP TO PLBUFS
	INCB	(R3)+		;RELEASE BUFF.
	MOV	(R3),R3
	CALL	GIVBUF		;GIVE BACK BUFFER
2$:	BIC	#4,@#SPOLSW	;NO. SET PL IDLE SW
50$:	RETURN
1$:	TST	(R1)		;YES. BLOCK IN MOTION?
	BNE	3$
15$:	MOV	PLCIAD,R4	;SK-124 YES. GET ADD OF PLCBIP IN R2
	MOV	(R4),R3		;RELEASE BUFFER
	CALL	GIVBUF
	INCB	-(R4)
10$:	TSTB	-1(R4)		;BLOCK READ IN?
	BEQ	4$
	CALL	WAITBK		;NO
	BR	10$
4$:	MOV	TABPDT,R2
	MOV	2(R2),-2(R2)	;SET CBN=NBN
	MOV	#4,(R2)		;SET CRP
	MOV	PLOIAD,R3		;GET PLOBIP ADD. IN R3
	MOV	(R3),R4		;GET C(PLOBIP) IN R3 & BUMP TO TWD1
	MOV	TWD1(R4),2(R2)	;SET PL.NBN
	MOV	R2,R1		;SAVE PL.CRP ADD. IN R1
	MOV	PLCIAD,R2		;GET ADD. OF PLCBIP IN R2
	MOV	(R3),(R2)+	;SET PLCBIP
	MOV	(R3),(R2)	;SET PLWDIP
	ADD	#4,(R2)
	BR	5$		;SEND WRITE REQ IF NOT SHUT DOWN
3$:	MOV	PLWDAD,R2		;GET ADD OF PLWDIP IN R2
	MOV	@(R2),-(SP)
	ADD	#5,(SP)		;EVEN BYTE COUNT
	BIC	#177401,(SP)
	ADD	(SP),(R1)	;BUMP CRP
	ADD	(SP)+,(R2)	;BUMP LPWDIP
5$:	BIT	#40000,@#SPOLSW	;SHUT DOWN?
	BEQ	2$
	BIT	#4,@#SPOLSW	;SHUT PL?
	BEQ	2$
	BIT	#10000,@#SPOLSW	;SHUT DESPOOLER
	BEQ	2$
	TST	@(R2)		;LAST RECORS?
	BNE	13$
	CMP	-2(R1),4(R1)	;YES. ANY MORE DATA?
	BNE	14$
	CALL	12$		;NO. SET TABLE ENTRIES
	BR	11$
14$:	MOV	PLONAD,R2	;SK-124 GET PLBUFS ADDRESS
	ADD	#2,R2		;SK-124
	CMPB	#1,(R2)		;SK-124 ONE FREE BUFFER?
	BNE	15$		;SK-124
	TSTB	-1(R2)		;SK-124 YES. BLOCK IN MOTION
	BNE	15$		;SK-124
	CALL	9$		;SK-124 NO. GET NEXT BLOCK
	BR	15$		;SK-124 WAIT FOR BLOCK TO COME IN
;
13$:	MOV	@R2,R5		;NO. SAVE BUFF ADD ON STACK
	CALL	STUPPT		;SET UP TCB TO UNTI A LINE
	MOV	PC,R1		;GET PL.CRP ADD. IN R1
	ADD	#TABLE+PLTEOF-.+4,R1
	MOV	(R2),R4		;CHECK FOR BUFFER EMPTY
	MOV	@(R2),-(SP)	;GET BYTE COUNT
	ADD	#5,(SP)		;EVEN BYTE COUNT
	BIC	#177401,(SP)
	ADD	(SP)+,R4	;BUMP R4 TO POINT TO PT WORD OF NEXT
	MOV	PC,R2		;NO. GET ADD OF PLBUFS IN R2
	ADD	#PLBUFS-.,R2
	TST	(R4)		;LAST RECORD?
	BEQ	6$
	CMP	#-1,(R4)
	BEQ	6$
	CMPB	#1,(R2)		;PLBUFS=1
	BNE	50$
	TSTB	-(R2)		;YES. BLOCK IN NEXT?
	BNE	50$
	CMP	-2(R1),4(R1)	;NO. MORE TO DOE (CBN=LSB)
	BEQ	50$
	CALL	9$		;SK-124 GET NEXT BLOCK
	BR	50$		;SK-124
;
;BUFFER EMPTY; TEST IF MORE BLOCK TO DO?
6$:	CMP	-2(R1),4(R1)	;MORE TO DO? (CBN=LSB)
	BEQ	7$
	CLR	(R1)		;SET CRP=0
	CMPB	#1,(R2)		;PLBUFS=1?
	BNE	8$
	TSTB	-(R2)		;BLOCK IN TRANSIT?
	BNE	8$		;SK-124
	CALL	9$
8$:	JMP	50$		;SK-125
;NO MORE BLOCKS TO DO
7$:	CALL	12$		;SET TABLE ENTRIES
	BR	8$
;
;
;GET NEXT BLOCK FROM DISK.
9$:	PUSH	R1
	PUSH	R2
	CALL	GETBUF		;YES. GET BUFFER & READ NEXT BLOCK
	MOV	R1,R4		;SAVE BUFAD IN R4
	POP	R2
	POP	R1
	MOV	PLOIAD,R3		;GET ADD. OF PLOBIP IN R3
	MOV	R4,(R3)		;SET PLOBIP
	INCB	(R2)		;SET PLBMS SW
	MOV	#PLCOD,R3	;GET DEV.CODE IN R3. FOR GETBLK
	MOV	R1,R2		;GET PL.CRP ADD. IN R2
	CALL	GETBLK		;GET BLOCK FROM DISK
	RETURN			;SK-124
;
12$:	MOV	#-1,@R1		;SET CRP=-1
	MOV	#-1,6(R1)	;SET LFB=-1
	RETURN
;
	.ENDC
;
	.SBTTL	PL CALL SERVICE
;
;THIS ROUTINE SRVICES CALLS TO OUTPUT DATA ONTO THE XY PLOTTER. IT
;SPOOLS THE DATA SENT BY THE CALLER ONTO THE DISK.
;
	.IFDF	$PL
PLDUMC:	.BYTE	0		;UNUSED
PLBMS:	.BYTE	0		;BLOCK IN MOTION SW
PLCBCP:	0			;CURRENT BUFFER POINTER
PLWDCP:	0			;CURRENT WORD POINTER
PLOBCP:	0			;NEXT BUFF POINTER(DUMMY)
	.ENDC
;
;
	.IFNDF $PL
PLCALL:	MOV	@#DEVST,R1
	MOVB	#IOPS77,PLSPER(R1)	;(SCR-144)REPORT TASK NOT SUPPORTED
	CALL	DEQREQ
	.ENDC
	.IFDF $PL
PLCALL:	CMP	-(R1),-(R1)	;POINT R1 TO PLWDCP
	BIT	#20000,@#SPOLSW	;SHUT SPOOLER?
	BEQ	10$
	PUSH	R1		;SAVE R1.	NO
	MOV	(R1),R1		;GET CONTENTS OF PLWDCP IN R1,R4
	MOV	R1,R4
	MOV	10(R0),R3	;GET CALLER BUF. ADD. IN R3
	ASL	R3		;RELOCATE ADD.
	ADD	@#MEMSIZ,R3
	MOVB	(R3),R2		;GET BYTE COUNT FROM BUFFER IN R2
	ADD	#5,R2		;ADD HWD BYTE COUNT + EVEN BYTE COUNT
	BIC	#177401,R2
	ADD	R2,R1		;BUMP PLWDCP BY THE SIZE OF NEXT RECD.
	MOV	(SP),R5		;GET PLWDCP ADD. IN R4
	PUSH	-(R5)		;POINT TO PLCBCP & SAVE CONT. OF PLCBCP ON STACK
	ASR	R2		;CONVERT TO WORD COUNT
	SUB	(SP)+,R1	;COMPUTE SPACE REM.
	CMP	#770,R1		;SPACE LEFT?
	BLT	4$
	CALL	COPBUF		;COPY CALLER BUFFER
	POP	R4		;TEMP SAVE R1 IN R2
	CALL	6$		;CHECK FOR .CLOSE
	BCC	8$		;NO
	BR	9$		;YES
;
10$:	MOV	#-600,4(R0)	;SPOOLER SHUT DOWN. REPORT
	PUSH	R1		;DUMMY
	JMP	DEQRQ
;LAST RECORD WAS NOT A .CLOSE
8$:	MOV	PLCBAD,R1	;POINT R1 TO PLCBCP (BR-145)
	MOV	R1,R2		;SAVE IN R2
	TST	(R1)+		;BUMP R1 PLWDCP
	MOV	(R1),R1		;GET CURRENT WORD ADD. IN R1
	SUB	(R2),R1		;GET REMAINNING # OF WORDS
	CMP	#770,R1		;SPACE LEFT?
	BGT	2$
9$:	MOV	PC,R1		;GET ADD. OF PLWDCP IN R1
	ADD	#PLWDCP-.,R1
	CLR	@(R1)		;NO. PUT BUFFER ON DISK
	CALL	FINDBK		;GET DISK BLOCK #
	PUSH	R1		;SAVE BLOCK # ON STACK
	MOV	PLCBCP,R2		;GET C(PLCBIP) IN R2
	MOV	(SP),TWD1(R2)	;SAVE BLOCK # IN TWD1
	MOV	#PLCOD,R3		;GET PL.DEV CODE IN R3
	MOV	PLBMSA,R1	;SET PLBMSA
	INCB	(R1)
	CALL	PUTBLK		;PUT BUFF. ON DISK
	MOV	PLCBAD,R4		;GET ADD. OF PLCBCP IN R3&R4
3$:	CALL	GETBUF		;GET A NEW BUF
	MOV	R1,(R4)+	;SET PLCBCP=BUFAD
	POP	(R1)		;SET BLOCK # IN HWD0 OF NEW BUFF.
	ADD	#4,R1		;BUMP R2 TO WORD 2 OF BUF
	MOV	R1,(R4)		;SET PLWDCP
2$:	CALL	DEQREQ		;DEQUE REQUEST & EXIT IN WAIT STATE
4$:	POP	R1		;RESTORE ADD. OF CURRENT WORD IN R1
	PUSH	R3		;SAVE R3,R2
	PUSH	R2
	CLR	@(R1)		;SET BUFF. END SW
	CALL	FINDBK		;GET DISK BLOCK #
	PUSH	R1		;SAVE BLOCK #
	CALL	GETBUF		;GET A BUFF.
	MOV	(SP),(R1)	;SET BLOCK # IN HWD0 OF NEW BUFF.
	MOV	PLCBAD,R4		;GET ADD. OF PLCBCP IN R4
	PUSH	(R4)
	PUSH	(R4)		;SAVE CONT. OF PLCBCP
	ADD	#TWD1,(SP)	;BUMP TO TWD1
	MOV	4(SP),@(SP)+	;SET LINK IN OLD BUFF.
	MOV	R1,(R4)+	;SET PLCBCP & BUMP TO PLWDCP
	ADD	#4,R1		;POINT TO WORD 2 IN BUFF.
	PUSH	R4		;SAVE PLWDCP ADD. ON STACK
	MOV	R1,(R4)		;SET PLWDCP
	MOV	R1,R4		;GET CONT. OF PLWDCP
	MOV	6(SP),R2	;RESTORE R3,R2
	MOV	10(SP),R3
	CALL	COPBUF		;COPY CALLER BUFFER
	POP	R4		;SAVE PLWDCP ADD. IN R4
	POP	R2		;CONT. OF PLCBCP ON STACK TOP???
	MOV	#PLCOD,R3	;GET DEV.CODE IN R3. FOR PUTBLK
	ADD	#6,SP		;CLEAN STACK
	PUSH	R4		;SAVE R5
	MOV	PLBMSA,R1	;SET PLBMS
	INCB	(R1)
	CALL	PUTBLK		;PUT BUFF. ON DISK
	POP	R4		;TEMP SAVE R1
	CALL	6$		;CHECK FOR .CLOSE
	BCC	2$
	BR	9$		;YES
6$:	MOV	R4,R1		;SAVE R4
	MOV	10(R0),R4	;EOF TEST. RECOMPUTE BUFFER HEADER
	ASL	R4
	ADD	@#MEMSIZ,R4	;NOW HAVE ADDR OF BUFFER
	TST	(R4)		;IF MINUS, IS EOF
	BPL	7$		;NOT NEG, BRANCH OUT TO END
	MOV	R1,R4		;RESTORE R4
	ADR	TABLE+PLTEOF+LFB,R2	;GET PL.LFB ADD. IN R2
	MOV	PLCBAD,R1
	PUSH	(R2)		;SAVE OLD LFB
	MOV	@(R1),(R2)	;SET LFB IN TABLE
	MOV	(R1),R1
	POP	2(R1)		;SET OLD LFB IN BUFFER
	MOV	#-1,TWD0(R1)	;SET EOF CODE IN BUFFER
	SEC
7$:	RETURN
;
	.ENDC
	.SBTTL	CD INTERRUPT SERVICE
;
;THIS ROUTINE HANDLES THE COMPLETION OF I/O SOFTWARE INTERRUPT FROM
;THE DRIVER TASK IN PIREX. IT SPOOLS THE CARDS ONTO THE DISK.
;
	.IFDF	$CD
CDDUMI:	.BYTE	0		;UNUSED
CDBMS:	.BYTE	0		;BLOCK IN MOTION SW
CDCNTI:	.BYTE 0			;CARD COUNT
CDBFS:	.BYTE 0			;BUFFER FULL SW
CDCBIP:	0			;CURRENT BUFFER POINTER
CDWDIP:	0			;CURRENT WORD POINTER
CDOBIP:	0			;NEXT BUFFER POINTER
	.ENDC
	.IFNDF $CD
CDINT:	MOV	@#DEVST,R1
	MOVB	#IOPS77,CDSPER(R1)	;REPORT TASK NOT SUPPORTED
	RETURN
	.ENDC
	.IFDF $CD
;
;
CDINT:	BIT	#40000,@#SPOLSW	;SHUT DOWN?
	BEQ	1$
	MOV	CDINTA,R1
	BIT	#2,@#SPOLSW	;SHUT CD?
	BEQ	1$
	BIT	#20000,@#SPOLSW	;SHUT SPOOLING?
	BEQ	1$
	MOV	-4(R1),R2	;POINT TO 1ST WORD IN RECORD
	SUB	#120,R2		;POINT TO WORD 1
	CMP	#CDEOD,(R2)	;EOD CARD?
	BEQ	2$
	TSTB	-7(R1)		;NO. CDBFS=0?
	BNE	3$
4$:	MOV	-4(R1),R5		;YES. SAVE BUFAD
	CALL	STUPCT		;SET UP TCB
	MOV	CDINTA,R1	;RESTORE ADD. OF CDINTA IN R1
	ADD	#124,-4(R1)	;BUMP CDWDIP
	INCB	-10(R1)		;INCREMENT CARD COUNT
	TSTB	-7(R1)		;CDBFS=0?
	BNE	5$
	CMPB	#6,-10(R1)	;CDCNTI=5?
	BNE	7$
	INCB	-7(R1)		;SET BUFFER FULL SW.
7$:	RETURN
;
1$:	BIC	#2,@#SPOLSW
	BR	7$
;
;
5$:	CLRB	-7(R1)		;RESET CDBFS
	INCB	-11(R1)		;SET CDBMS
	MOV	#CDCOD,R3	;SET UP FOR PUTBLK
	POP	R2
	CALL	PUTBLK
	BR	7$
;
8$:	TST	(SP)+		;PRUNE STACK
3$:	PUSH	-6(R1)		;SAVE BUFAD
	ADD	#TWD1,(SP)
	BR	6$
;
2$:	CMP	-(R2),-(R2)	;SET BUFEND SW
	MOV	#-1,@R2
	ADR	TABLE+CDTEOF+LFB,R2	;SET LFB IN TAABLE
	PUSH	-6(R1)
	MOV	(R2),R1		;SAVE OLD LFB
	MOV	@(SP),(R2)
	ADD	#2,(SP)		;BUMP TO HWD1
	MOV 	R1,@(SP)	;SET LFB IN BUFFER HWD1
	ADD	#772,(SP)	;BUMP TO TWD0
	MOV	#-1,@(SP)	;SET EOD CODE IN BUFF.
	ADD	#2,(SP)		;BUMP TO TWD1
	MOV	CDINTA,R1
6$:	CLRB	-10(R1)
	INCB	-7(R1)		;NO. SET IT
	CALL	FINDBK		;GET A BLOCK ON DISK
	MOV	R1,@(SP)+	;SET BLOCK # IN OLD BUFF.
	PUSH	R1		;SAVE BLOCK #
	CALL	GETBUF		;GET A BUFF.
	POP	(R1)		;SET BLOCK # IN HWD0 OF NEW BUFF.
	MOV	CDCPAD,R2	;SAVE CDCPAD & SET NEW VALUE
	PUSH	(R2)
	MOV	R1,(R2)+
	MOV	R1,(R2)		;SET CDWDIP
	ADD	#4,(R2)
	MOV	CDINTA,R1
	BR	4$
;
	.ENDC
;
	.SBTTL	CD CALL SERVICE
;
;THIS ROUTINE SERVICES CALLS TO READ A CARD. IT DESPOOLS THE SPOOLED
;DATA CARDS. DISK INTERRUPTS ARE INHIBITED WHEN THIS ROUTINE IS
;EXECUTED.
;
	.IFDF	$CD
CDCNTC:	.BYTE	0		;CARD COUNT
CDONCE:	.BYTE	0		;ONCE ONLY SW
CDBMD:	.BYTE	0		;BLOCK IN MOTION SW
CDBUFS:	.BYTE	0		;EMPTY BUFFER COUNT
CDCBCP:	0			;CURRENT BUFFER POINTER
CDWDCP:	0			;CURRENT WORD POINTER
CDOBCP:	0			;NEXT BUFFER POINTER
	.ENDC
;
	.IFNDF $CD
CDCALL:	MOV	@#DEVST,R1
	MOVB	#IOPS77,CDSPER(R1)	;(SCR-144)REPORT TASK NOT SUPPORTED
	CALL	DEQREQ
	.ENDC
	.IFDF $CD
CDCALL:	MOV	TABDCT,R2	;CD.CRP=-1?
	BIT	#10000,@#SPOLSW	;DESPOOLER ENABLED?
	BEQ	2$
	BIS	#LVL5,@#PS	;YES. INHIBIT DISK INT.(BR-120)
	CMP	#-1,(R2)
	BEQ	1$
	TST	(R2)		;CRP=0?
	BEQ	11$
4$:	MOV	-4(R1),R4	;NO. GET C(CDWDCP) IN R4
	MOV	10(R0),R3	;GET CALLER BUFF. ADD
	ASL	R3		;RELOC. ADD.
	ADD	@#MEMSIZ,R3
	MOV	#CDSIZE/2,R5	;COPY A CARD INTO CALLERS BUFF.
	CMP	#-1,(R4)	;FIRST CARD EOD?
	BNE	3$
	TSTB	-10(R1)		;EOD CARD. NEXT BLOCK IN?
	BNE	11$		;BRANCH IF BLOCK COMING
	TSTB	-7(R1)		;NO. BLOCK ALREADY IN?
	BEQ	11$		;BRANCH IF YES
	CMP	-2(R2),4(R2)	;NO. MORE BLOCKS ON DISK?
	BEQ	17$		;BRANCH IF NO
	CALL	15$		;YES. GET BLOCK
	MOV	CDCAAD,R1
	BR	11$
3$:	MOV	(R4)+,(R3)+
	DEC	R5
	BNE	3$
	MOV	R4,-4(R1)	;DONE. SET CDWDCP
	ADD	#CDSIZE,(R2)	;BUMP CRP IN TABLE
	MOV	-4(R1),R4	;MORE CARDS IN BUFFER?
	CMP	#-1,(R4)
	BEQ	5$
	INCB	-12(R1)		;FIRST COUNT CARD GIVEN
	CMPB	#6,-12(R1)
	BEQ	5$
	CMPB	#1,-7(R1)	;CDBUFS=1?
	BNE	6$
	TSTB	-10(R1)		;YES. CDBMS=0?
	BNE	6$
	MOV	TABDCT,R2	;RESTORE ADD. OF CD.CRP IN R2
	CMP	-2(R2),4(R2)	;YES. MORE CARDS ON DISK?
	BEQ	6$
14$:	CALL	15$		;GET BLOCK
6$:	CALL	DEQREQ		;EXIT
;
;
2$:	MOV	#-700,R1	;DESPOOLER DISABLED. REPORT
	CALL	DEQRQ
;
;NO CARDS ON DISK. SET CODE IN TABLE & SAVE THE REQUEST NODE
;
1$:	BIT	#134400,@#177160	;CHECK IF REAL ERROR (BR-120)
	BEQ	25$		;NOT A REAL ERROR (BR-119)
	MOV	@#DEVST,R1	;SET ERROR CODE IN PIREX TABLE
	ADD	#CDCOD*3*2+5,R1
	MOVB	#1,(R1)
25$:	MOV	RESTAD,R1	;SETUP FOR REINSERTING REQUEST AFTER 1 SEC.
	MOV	@#CLTABL,R2
	MOV	#CDTIME,CDCOD*4(R2) ;1000/60 SEC INTERVAL
	MOV	R1,CDCOD*4+2(R2)	;GOTO RESTRQ ON TIMER RUNOUT
	MOV	SPSTAD,R3		;SAVE TCBP
	MOV	-(R3),-(R1)
	MOV	-(R3),-(R1)
	CALL	DEQRQ0
;
11$:	MOV	TABDCT,R2
9$:	TSTB	-10(R1)		;CDBMS=0?
	BEQ	10$
	CALL	WAITBK
	BR	9$
10$:	CALL	12$		;UPDATE POINTERS
	MOV	CDCAAD,R1	;RESTORE R1
	BR	4$
;
;PROCESSING NEW BUFFER. MUST UPDATE POINTERS
5$:	CLRB	-12(R1)		;RESET CDCNTC
	MOV	TABDCT,R2	;CBN=LSB?
	CMP	4(R2),-2(R2)
	BEQ	7$
	CLR	(R2)		;SET CRP=0 FOR NOW
	TSTB	-10(R1)		;BLOCK READ IN. CDBMS=0?
	BNE	6$
	TSTB	-7(R1)		;NEXT BLOCK READ IN?
	BNE	14$		;GET BLOCK IF NO
	CALL	12$		;YES. UPDATE POINTERS
	BR	6$
;
7$:	CALL	16$
	BR	6$
;
17$:	CALL	16$
	BR	1$
;
;
12$:	MOV	R1,R3
	MOV	-6(R3),R4	;GET OLD BUFAD IN R4
	MOV	-2(R3),-6(R3)	;YES. SET CDCBCP=CDOBCP
	MOV	-2(R3),-4(R3)	;SET CDWDCP
	MOV	#4,(R2)		;SET CRP IN TABLE
	ADD	@R2,-4(R3)
	MOV	2(R2),-2(R2)	;SET CBN=NBN
	PUSH	-2(R3)		;SET CD.NBN IN TABLE
	ADD	#TWD1,(SP)
	MOV	@(SP)+,2(R2)
	INCB	-7(R3)		;RELEASE CURRENT BUFFER
	MOV	CDOBAD,R1	;SET CDOBAD
	MOV	R4,(R1)
	MOV	R4,R1		;RESET HWDS IN BUFF.
	CLR	(R1)+
	CLR	(R1)
	CMP	-2(R2),4(R2)	;NBN SPOOLED?
	BEQ	24$		;BRANCH TO GET BLOCK IF YES
13$:	INCB	-10(R3)		;SET CDBMS
	MOV	#CDCOD,R3	;GET BLOCK FROM DISK
	CALL	GETBLK
24$:
	RETURN
;
15$:	INCB	-10(R1)		;YES. SET CDBMS
	MOV	#CDCOD,R3	;GET CD.DEV.CODE IN R3
	MOV	CDOBCP,R4		;GET BUFF. ADD. IN R4
	CALL	GETBLK		;GET BLOCK FROM DISK
	RETURN
;
16$:	MOV	CDCBAD,R1	;RETURN BUFFER
	MOV	(R1),R3
	CLR	(R1)
	CALL	GIVBUF
	MOV	CDOBAD,R1
	MOV	(R1),R3
	CLR	(R1)
	CALL	GIVBUF
	MOVB	#2,CDBUFS
	MOV	#-1,6+TABLE+CDTEOF+CRP	;SET LFB=-1
	MOV	#-1,TABLE+CDTEOF+CRP
	CLRB	CDBUFS-2		;RESET CDONCE
	RETURN
	.ENDC
;
	.SBTTL	PUTBLK/GETBLK/RESTRQ
;
;THIS ROUTINE READS A BLOCK FROM DISK INTO CORE. A SOFTWARE INTERRUPT
;IS ISSUED WHEN THIS OPERATION IS COMPLETED.
;
;CALLING SEQUENCE:	MOV	#-COD,R3
;			ADR	BUFAD,R4
;			ADR	-.CRP,R2
;			CALL	GETBLK
;
GETBLK:	PUSH	R3		;SAVE DEV CODE
	PUSH	#READF		;SAVE DISK FUNCT
	PUSH	R4		;SAVE BUFF ADD
	PUSH	2(R2)		;SAVE BLOCK #(NBN)
	CALL	GETRKT		;GET RK TCB
	BR	GETCOM
;
;THIS ROUTINE WRITES A BLOCK ONTO DISK FROM CORE. A SOFTWARE INTERRUPT
;IS ISSUED WHEN THIS OPERATION IS COMPLETED
;
;CALLING SEQUENCE:	MOV	#-COD,R3
;			ADR	BUFAD,R2
;			CALL	PUTBLK
;
PUTBLK:	CALL	GETRKT		;GET A TCB
	PUSH	R3		;SAVE CALLING DEV CODE
	PUSH	#WRITEF		;SAVE DISK FUN.
	PUSH	R2		;SAVE BUFFER ADD
	PUSH	(R2)		;SAVE BLOCK #
GETCOM:
	CALL	GETPUT		;PUT BUFFER ON DISK
	ADD	#10,SP		;CLEAN UP STACK
	RETURN
;
;THE FOLLOWING ROUTINE IS USED BY THE 'CD CALL SERVICE ROUTINE' WHEN THERE
;ARE NO CARDS IN THE SPOOLER. IT SAVES THE TCBP INFO & SETS UP A TIMER
;REQUEST. WHEN THE TIMER RUNS OUT IT RECHECKS TO SEE IF ANY CARDS ARE
;PRESENT. IF NOT IT RESTARTS THE TIMER. IF CARDS ARE PRESENT IT PROCESSES THE
;READ REQUEST.
;
;THIS ROUTINE REINSERTS THE REQUEST PRESENT IN 'RESTRQ-2' INTO THE SPOOLER TRL
;ON GAINING CONTROL FROM TIMER RUNOUT
;
	.IFDF	$CD
	.BLOCK	2
RESTRQ:	MOV	CDONAD,R1	;CHECK IF CD ON?
	CMPB	#2,(R1)
	BNE	1$
	MOV	SPSTAD,R1		;IS SPOOLER BUSY?
	MOV	RESTAD,R0
	.INH
	TST	-2(R1)
	BNE	4$
	MOV	-(R0),-(R1)	;NO. SET STATUS TO RUN. SAVE TCBP
	MOV	-(R0),-(R1)
	CLR	(R0)+
	CLR	(R0)+
	CMP	(R1)+,(R1)+
	MOV	R1,-12(R1)		;SETUP PC ON STACK
	CLR	-10(R1)		;SET PS ON STACK
	MOV	@#ATLNP,R3
	MOV	SPCOD*2(R3),R2	;GET ATL NODE ADDRESS
	BIC	#17,6(R2)	;SET STATUS TO RUN
	SUB	#26,R1		;SET SP IN ATL NODE
	MOV	R1,4(R2)
	BR	3$
4$:	MOV	@#LISTHD,R1	;GET LISTHD ADD. IN R1
	MOV	SPCOD*4+2(R1),R1
	MOV	@#POL.LH,R2	;GET POL.LH ADD. IN R2
	MOV	(R2),R5		;YES. GET ADD. OF NODE
	MOV	-(R0),6(R5)
	MOV	-(R0),4(R5)
	CLR	(R0)+		;RESET SAVED TCBP IN 'RESTRQ-2/4'
	CLR	(R0)+
;DELETE NODE FROM POOL
	MOV	(R5),R2
	MOV	R2,@2(R5)	;SET FORWARD POINTER
	MOV	2(R5),2(R2)	;SET BACKWARD POINTER
;PUT NODE IN SPOOLER DEQUE
	MOV	@(R1),(R5)	;SET FORWARD POINTER OF NODE
	MOV	(R1),2(R5)	;SET BACKWARD POINTER
	MOV	R5,@(R1)	;SET FORWARD POINTER OF LAST NODE
	MOV	R5,(R1)		;SET BACKWARD POINTER OF LISTHEAD
3$:	.ENA
	RETURN
;
1$:	MOV	@#CLTABL,R2	;SETUP TIMER
	MOV	#CDTIME,CDCOD*4(R2)
	RETURN
;
	.ENDC
;
;
	.SBTTL	ADDRESS TABLE
;
ADRTBL:
RKCAD:	.WORD	RKTCBP
	.IFDF	$LP
LPONAD:	.WORD	LPONCE
	.ENDC
TABPLA:	.WORD	TABLE+PLTEOF
	.IFDF	$PL
PLONAD:	.WORD	PLONCE
	.ENDC
BTMPAD:	.WORD	BTMPST
STBKNA:	.WORD	STBKNM
TABLAD:	.WORD	TABLE
TABPCB:	.WORD	TABLE+CBN
TABPLC:	.WORD	TABLE+PLTEOF+CBN
TABCDC:	.WORD	TABLE+CDTEOF+CBN
TCBK1A:	.WORD	TCBDK1
.IFDF	$CD
CDCPAD:	.WORD	CDCBIP
CDCBAD:	.WORD	CDCBCP
	.ENDC
	.IFDF	$LP
LPCBAD:	.WORD	LPCBCP
LPCWAD:	.WORD	LPWDIP
	.ENDC
	.IFDF	$PL
PLCBAD:	.WORD	PLCBCP
PLWDAD:	.WORD	PLWDIP
	.ENDC
TCBK3A:	.WORD	TCBDK3
AFNDBK:	.WORD	FINDBK
ASPLFU:	.WORD	SPLFUL		;##139##
BUFLAD:	.WORD	BUFLHD
	.IFDF	$LP
LPCPAD:
LPCZAD:	.WORD	LPCBIP
LPBMSA:	.WORD	LPBMS
	.ENDC
TABCDT:	.WORD	TABLE+CDTEOF
TABCRT:	.WORD	TABLE+CRP
TABPDT:	.WORD	TABLE+PLTEOF+CRP
	.IFDF	$PL
PLCIAD:	.WORD	PLCBIP
PLOIAD:	.WORD	PLOBIP
PLBMSA:	.WORD	PLBMS
	.ENDC
	.IFDF	$CD
CDBMSA:	.WORD	CDBMS
CDINTA:	.WORD	CDINT
	.ENDC
TABDCT:	.WORD	TABLE+CDTEOF+CRP
CDCAAD:	.WORD	CDCALL
SPSTAD:	.WORD	SPST
	.IFDF	$CD
CDOBAD:	.WORD	CDOBCP
RESTAD:	.WORD	RESTRQ
CDONAD:	.WORD	CDONCE
	.ENDC
ONCEFL:	.WORD	0
ADTCNT=ADRTBL-./2
;
;
	.SBTTL	BITMAP & TABLE
;
BITMAP:	.BLOCK	14		;SPOOLER ID INFO
STBKNM:	.WORD	0		;SPOOLER AREA FBN
	.WORD	0		;SPOOLER AREA SIZE
BTMPST:	.BLOCK	362		;##133##START OF BIT MAP
BTMPSZ=.-BTMPST/2
BTMPED:	0			;POINTER TO END+2 OF BIT MAP
;
	.BLOCK	4		;HWD'S
TABLE:	.BLOCK	44		;3 DEVICES * 14(8) WORDS EACH
TABLSZ=.-TABLE/2
;
; TABLE ENTRIES ARE AS FOLLOWS FOR EACH TASK:
;	DEVCOD/CBN/CRP/NBN/LSB/LFB
;	0/2/4/6/10/12
;
	.SBTTL	TCB TEMPLATES
;
;DISK READ/WRITE TCB WITH ONLY SETTING OF EV
	TCBDK	TCBDK1
	TCBDK	TCBDK3
	TCBDK	TCBDK4
	TCBDK	TCBDK5
;DISK READ/WRITE TCB'S FOR SPOOLED DEVS.
TCBST=.
	.IFEQ	DEVCNT-1
	.REPT	DEVCNT*4+2		;(SCR-144)1 DEV. EXTRA BUFFER
	TCBRK
	.ENDR
	.ENDC
	.IFNE	DEVCNT-1
	.REPT	DEVCNT*4
	TCBRK
	.ENDR
	.ENDC
TCBEN=.
TCBCT=TCBEN-TCBST/30
TCBLIM=1
	.REPT TCBCT
TCBLIM=2*TCBLIM
	.ENDR
;
	.IFDF $LP
;LP WRITE TCB WITH RETURN ADDRESS & SET EV
TCBLP:	SPCOD		;0. API LVL & TRAP ADDRESS
	1600+LPCOD	;2. NO INT. + LP TASK + RETURN @SEND11
	0		;4. REV
	100000		;6. DONT RELOCATE ADDRESS
	0		;10. FA
	2		;12. SINGLE LINE/MULTI LINE SW
	0		;14. LP STATUS
	.ENDC
	.IFDF $PL
;
;
;PL WRITE TCB WITH RETURN ADDR AND SET EV
;
TCBPL:	SPCOD		;0. API LVL. & TRAP ADDRESS
	1600+PLCOD	;2. NO INT. + PL TASK + RETURN @SEND11
	0		;4. RETURN EVENT VARIABLE
	100000		;6. DON'T RELOCATE ADDRESS
	0		;10. FA
	.ENDC
	.IFDF $CD
;
;CD READ TCB WITH RETURN ADDRESS & SET EV
TCBCD:	SPCOD		;0. API LVL & TRAP ADDRESS
	1600+CDCOD	;2. NO INT. + CD TASK + RETURN @SEND11
	0		;4. REV
	100000		;6. DONT RELOCATE ADDRESS
	0		;10. FA
	0		;12. UNIT #
	.ENDC
;
;DISCONNECT SPOOLER TCB
TCBDIS:	0		;0 API LVL + TRAP ADD.
	600+SDCOD	;2. SD TASK + NO INT.
	0		;4. REV
	SPCOD		;6. SPOOLER TASK CODE
	100000		;10. DONT RELOC. ADD.
	0		;12. FA (SET UP)
	0		;14.
	SPOLSZ*2	;16.	SPOOLER SIZE
;
	.SBTTL	BUFFER POOL
;
BUFLHD:	.WORD	BUF1		;BUFFER LIST HEAD
	.WORD	BUF8
BUF1:	.WORD	.+1000
	.WORD	BUFLHD
	.BLOCK	376
	.IFEQ	DEVCNT-1
	.REPT	DEVCNT*4		;(SCR-144)1 DEV. EXTRA BUFFER
	.WORD	.+1000
	.WORD	.-1002
	.BLOCK	376
	.ENDR
	.ENDC
	.IFNE	DEVCNT-1
	.REPT	DEVCNT*4-2
	.WORD	.+1000
	.WORD	.-1000
	.BLOCK	376
	.ENDR
	.ENDC
BUF8:	.WORD	BUFLHD
	.WORD	.-1002
	.BLOCK	376
;
SPEND:	.END		;
