	.SBTTL	COPYRIGHT
	.TITLE	PIREX.154
;
;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.
;
;			P I R E X
;
;	A MULTI-PROGRAMMING PERIPHERAL EXECUTIVE FOR THE UNICHANNEL-15
;
;
;
	.SBTTL	LEGEND
;
EDIT=154.
;
;  EDIT #075	SR	FIRST TRY AT PLOTTER DRIVER
;  EDIT #081	SK	TEMPORARY TASK FIX IN SD.DISCON
;  EDIT #082	SK	QUEUE REQ TO REAL TASK WHEN SPOOLER
;			HALTED + TEMPORARY TASK BUG FIX ON CTL 'C'
;  EDIT #083	SR	EXPERIMENTAL CHANGE FOR LP ?BUG?
;  EDIT #086	SR+KB	INSTALL LV11 TASK
;			FOR VERSATEK PRINTER/PLOTTER
;  EDIT #087	SR	FIX VERSATEK TASK NUMBER ERRORS FROM 086
;  EDIT #090	SR	FIX LV STACK SIZE.MAKE LP OK FOR IMAGE MODE.
;  EDIT #091	SR	#090 MISSED, TRY AGAIN
;  EDIT #092	SR	CD ERROR CODES. PL REST OF ASCII SET.
;  EDIT #093	SR	BRING BACK LV, FIX % IN PLOTTER.
;  EDIT #094	SR	TAKE OUT LEVEL 6 CLOCK REF. IN LP.
;  EDIT #095	SK	19-NOV-73	FIX CTL'C' IN ST TASK WITH RESET
;				+ PERMIT SOFTWARE INT. FACILITY FOR EACH TASK
;				+ REMOVE $CL COND.	+ GENERAL COMMENT FIXUP
;	096	SK	5-DEC-73	HANDLE DEVICE CONTROL REG. SETUP IN
;					INITIALIZATION ROUTINE, REMOVE RESET INSTT
;					FROM ST TASK, REPLACE CLR @-6( ) +
;					GENERAL FIXUP TO EDIT #095
;	097	SR	12/18/73	CD; MAKE COLUMN COUNT CHECK.
;					XY; OFF LINE FROM PDP-11 SWITCHES.
;					RK; PRIORITY OF RETRY.
;	098	SK	1/2/74		LP:	-		 4
;					ST,SD: REMOVE LEVEL CHANGE IF SPOOLING
;					MASREQ: REMOVE TEST FOR ST TASK ACTIVE
;	099	SK	1/31/74		ST: FIX SINGLE TASK STOP I/O FOR RSX
;	100	SCR	4/5/74	ST: GIVE CD A WINDOW AT LVL 5
;				CD: REMOVE IOPS75 ENTIRELY, REPLACE IOPS4
;				LV: CHANGE EXIT TO .TRAN
;	101	SCR	4/9/74	CD REWRITE INTERRUPT SECTION
;	102	SCR	4/10/74	FIX 101
;	103	SCR	4/12/74 ADD CD-2=0 LOGIC;LV OFF BY 1.
;	104	SCR	5/20/74	CHANGE LV STATUS AND DATA REG.'S
;	114	SCR	7/10/74	INSTALL XY311 SUPPORT
;	115	SCR	7/11/74	1.MAKE XY DRIVER MATCH EXACTLY.
;				2.ATTEMPT CD ERROR HANDLING FIX
;	116	BLR	7/15/74 FIX SPOL CNTRL C BUG
;	117	RKH	22-JUL-74	REMOVED DEBUG HALTS
;				FOR OUT OF RANGE DISK REFS
;	118	EIK	6-AUG-74	FIX BUG TO ALLOW FULL LIST
;	119	SK	12-NOV-74	ADD LP HALT ON CLOSE FEATURE
;	120	BLR	13-NOV-74	ADD MOVE DIRECTIVE
;					ADD MEMSIZ TO CORE STAT DIRECTIVE
;					REMOVE STOP ON SOFT ERROR FORM RK TASK
;	121	SK	15-NOV-74	PLOTTER EOF SPOOLING WAIT FEATURE
;	122	BR	8-DEC-74	SPOOLER DISK UNIT # ADDED
;	123	SCR	10-DEC-74	TRIAL CD PWER OFF-ON FIX; SPEED
;					LOOP FOR PL; REMAKE LV FROM LP.
;	124	SCR	11-DEC-74	EXTEND $NOSW;MINOR CD FIX
;	125	BLR	16-DEC-74	CLEAN UP MOVE DIRECTIVE
;	126	BLR	6-JAN-75	STOP ON SOFT DISK ERROR REMOVED
;	127	BLR	6-JAN-75	PRIORITY 5 WINDOW IN ERROR REPT. DIR ADDED
;	132	SCR	8-JAN-75	MADE FROM 127, ANOTHER TRY AT IOPS45
;	133	SCR	31-JAN-75	PL:FIX RETRY CONTROL BYTE FOREOF STOP
;	134	BLR	24-MAR-75	CLEAN UP SLOW CODE
;	135	BLR	25-MAR-75	FIX LP HALT EOF BUG
;	136	BLR	26-APR-75	EXTEND RK TRANSFERS TO 128K
;	137	SCR	5-MAY-75	FIX XY EOF LOGIC;REM @#
;	138	SCR	5-MAY-75	LOST INSTR. IN #137
;	139	BLR	6-JUN-75	RESCHED AFTER SEXIT 0 ADDED
;	140	RCHM	10-JUN-75	PREPARE PIREX FOR THE ACCEPTANCE OF THE
;					HURLEY PROTOCOL COMMUNICATIONS OPTION.
;	141	RCHM	20-JUN-75	REMOVE ILLINT HACK SO NEW DEVICES CAN BE
;					INSTALLED MORE EASILY
;	142	BLR	20-JUL-75	CHECK FOR OFLINE RK BEING SPOOLED
;	143	BLR	22-JUL-75	CHANGE SPOOLER ABORT ERROR TO #26
;	144	BLR	4-AUG-75	CLEAN UP XVM BYTE INTERFACE PROBLEM
;	145	BLR	18-AUG-75	CLEAN UP SOFTWARE DIR'CTVE BUG
;	146	BLR	18-AUG-75	ADD UNSUPPORTED POWER-FAIL ROUTINE
;	147	BLR	19-AUG-75	CHANGE WAY DISCONNECT FREE'S MEMORY
;	148	BLR	21-AUG-75	GIVE ERROR FOR TCB SENT FROM >28K
;	149	SCR	9/9/75		ALTERNATE XY CHAR SPACE($SPACE=0)
;	150	BLR	9/26/75		ILLEGAL BLOCK FIX
;	151	BLR	9/28/75		ADD STATUS REGS. TO EDIT 150
;	152	SCR	10/3/75		LP: EOF IN HDR, NOT A 6414 DATA
;	153	RCHM	11/03/75	PUT IN DEC CONFIGURATION DEFAULTS
;					FOR SECOND DL-11.
;	154	BLR	11/09/75	CHANGED COND. ASM FOR SPKILL

	.SBTTL	CONDITIONAL ASSEMBLY PARAMETERS
;
	.LIST	ME
	.LIST	TOC
	.ENABL	ABS
;
;
;	THIS SOURCE IS CONDITIONALISED TO PRODUCE DIFFERENT VERSIONS.
;	BY DEFINING A CONDITIONAL A TASK IS ASSEMBLED INTO THE PIREX VERSION 
;	THE FOLLOWING IS A LIST OF THE PARAMETERS:
;	EAE	FOR EAE OPTION	(UNSUPPORTED)***
;	$RK	FOR RK15/RK05 DISK CARTRIDGE TASK
;	$DT	FOR DT11 DECTAPE TASK	(UNSUPPORTED)***
;	$LP	FOR LP11/LS11 LINE PRINTER TASK
;	$CD	FOR CR11 CARD READER TASK
;	$PL	FOR XY11 PLOTTER TASK
;	$LV	FOR LV11 VERSATEK PRINTER/PLOTTER TASK	(UNSUPPORTED)***
;	$PL311	FOR XY311 INTERFACE TO CALCOMP 936 PLOTTER
;	$UNITS	FOR XY311:		STEP SIZE
;		DEFINED			.05 MM.
;		NOT DEFINED		.002 INCHES
;	$NOSW	DEFINE TO DISABLE ALL CONSOLE SWITCH INTERACTIONS
;	$HP	FOR HURLEY PROTOCOL (HP) COMMUNICATIONS OPTION. THE HP COMMUNICATIONS
;		OPTION UTILIZES A DL-11 AND A KG-11 TO COMMUNICATE WITH A DECSYSTEM-10.
;		AS SUPPLIED BY DIGITAL THE HP MODULE ASSUMES THE USE OF A DL-11 OTHER
;		THAN THE CONSOLE AND THE FIRST KG-11. IN ADDITION, FOR PROPER
;		OPERATION OF THE HP MODULE, THE DL-11 USED MUST BE MODIFIED TO INTERRUPT
;		AT API LEVEL 6.
;	DL.UN	A PARAMETER REQUIRED BY THE COMMUNICATIONS PACKAGE. THIS REPRESENTS THE
;		TOTAL NUMBER OF DL-11 UNITS INSTALLED ON THE PDP-11. THIS NUMBER INCLUDES
;		THE CONSOLE DL-11.
;	DL.NT	WHERE "N" IS AN OCTAL NUMBER SUCH THAT 0<=N<=17. THIS PARAMETER IS
;		SET TO INDICATE WHICH TASK IS TO UTILIZE THE DL-11. FOR EXAMPLE,
;		DL.1T=14 IMPLIES THAT DL-11 UNIT #1 (THE SECOND DL-11) IS TO BE USED
;		BY TASK NUMBER 14.
;		THE EXACT PARAMETERS ARE:
;		
;		$RK=100000
;		$LP=40000
;		$CD=20000
;		$PL=10000
;		$DT=0
;		$LV=0
;		EAESTK=3  FOR EAE ELSE EAESTK=0
;		$PL311=0 IN ADDITION TO $PL=10000
;		$UNITS=0 IN ADDITION TO $PL311=0 AND $PL=10000
;		$NOSW=0
;		$HP=0
;		DL.UN= (SEE ABOVE)
;		DL.?T= (SEE ABOVE)
;
;
;
;
DEVTYP=0
	.IFDF $HP		;(RCHM-140) HP OPTION SPECIFIED?
	.IFNDF DL.UN		;(RCHM-140) YES, IS A NUMBER OF DL-11'S SPECIFIED?
	.ERROR ;DL.UN NOT SPECIFIED AND HURLEY PROTOCOL OPTION SELECTED.
	.ENDC			;(RCHM-140)
	.ENDC			;(RCHM-140)
	.IFDF	$RK
DEVTYP=DEVTYP!$RK
	.ENDC
	.IFDF	$LP
DEVTYP=DEVTYP!$LP
.ENDC
.IFDF	$CD
DEVTYP=DEVTYP!$CD
	.ENDC
.IFDF	$PL
DEVTYP=DEVTYP!$PL
.ENDC
;
;
	.SBTTLE	SYMBOLIC EQUATES
;
R0=%0			;GENERAL PURPOSE REGISTERS
R1=%1
R2=%2
R3=%3
R4=%4
R5=%5
SP=%6
PC=%7
PS=-2			;PROCESSOR STATUS WORD
SW=177570		;SWITCH REGISTER
AC=177302		;EAE REGISTERS
MQ=177304
SC=177310
RETURN=207		;RETURN = RTS PC
;
CLSTS=177546		; LINE FREQ. CLOCK CONTROL REG.
TCBP=167764		;TASK CONTROL BLOCK POINTER REGISTER
TCBP18=167774		;TASK CONTROL BLOCK POINTER BITS 16 AND 17
TCBINT=167760		;TASK CONTROL BLOCK INTERRUPT ENABLE REGISTER
STKSZE=14+EAESTK	; STACK SIZE TO SAVE R0-R5 + EAE REGS.
POLSIZ=18.		;POOL SIZE SET AT 18+2=20 NODES
APIREG=167762		;API TRAP VECTORS FOR LEVELS 2 AND 3
			;    (LEVELS 0 AND 1 ARE AT APIREG+10).
APIDNE=167774		;API DONE FLAGS
;
TCN=2			;TASK CODE NUMBER
TEV=4			;TASK EVENT VARIABLE
;
STCOD=52324		;'EST':	ST TASK MNEMONIC
SDCOD=52304		;'ESD':	SD TASK MNEMONIC
RKCOD=41325		;'DKU':	RK TASK MNEMONIC
DTCOD=42425		;'DTU':	DT TASK MNEMONIC
LPCOD=142025		;'LPU':	LP TASK MNEMONIC
CDCOD=30425		;'CDU':	CD TASK MNEMONIC
PLCOD=72225		;'GRU':	PL TASK MNEMONIC
SPCOD=52320		;'ESP':	SP TASK MNEMONIC
LVCOD=142625		;'LVU': LV TASK MNEMONIC
;
;
SPTCOD=7		;SPOOLER TASK CODE
;
;
; ATL NODE EQUATES
;
A.SP=4			;SP REGISTER USED WHEN NOT RUNNING
A.TS=06			;TASK STATUS
A.TP=07			;TASK PRIORITY LEVEL
WAITST=2		; WAIT STATUS
EXITST=4		; EXIT STAUS
;
EAESTK=0		;DEFAULT EAE STACK SPACE IS NULL (ZERO)
	.IIF DF	EAE,EAESTK=6	;DEFINE EAE STACK SPACE IF EAE IS
				;    DEFINED.
;
	.SBTTL	MACRO DEFINITIONS
;
; RESERVE BLOCK OF ZEROED MEMORY
;
;
	.MACRO	.BLOCK	N
	.NLIST
	.REPT	N
	.WORD	0
	.ENDR
	.LIST
	.ENDM
;
; DEFINE A TASK LISTHEAD
;
	.MACRO	LISTHEAD	TK
TK'.LH:	.WORD	.
	.WORD	.-2
	.ENDM
;
; CALL SUBROUTINE
;
	.MACRO	CALL	ROUTINE
	JSR	PC,ROUTINE
	.ENDM
;
; PUSH ARGUMENTS ON STACK
;
	.MACRO	PUSH	CEL1,CEL2,CEL3,CEL4,CEL5,CEL6
	.NLIST
	.NARG	N
	.LIST
	MOV	CEL1,-(SP)
	.NLIST
	.IFGT	N-1
	.LIST
	MOV	CEL2,-(SP)
	.NLIST
	.IFGT	N-2
	.LIST
	MOV	CEL3,-(SP)
	.NLIST
	.IFGT	N-3
	.LIST
	MOV	CEL4,-(SP)
	.NLIST
	.IFGT	N-4
	.LIST
	MOV	CEL5,-(SP)
	.NLIST
	.IFGT	N-5
	.LIST
	MOV	CEL6,-(SP)
	.NLIST
	.ENDC
	.ENDC
	.ENDC
	.ENDC
	.ENDC
	.LIST
	.ENDM
;
; POP ARGUMENTS FROM STACK
;
	.MACRO	POP	CEL1,CEL2,CEL3,CEL4,CEL5,CEL6
	.NLIST
	.NARG	N
	.LIST
	MOV	(SP)+,CEL1
	.NLIST
	.IFGT	N-1
	.LIST
	MOV	(SP)+,CEL2
	.NLIST
	.IFGT	N-2
	.LIST
	MOV	(SP)+,CEL3
	.NLIST
	.IFGT	N-3
	.LIST
	MOV	(SP)+,CEL4
	.NLIST
	.IFGT	N-4
	.LIST
	MOV	(SP)+,CEL5
	.NLIST
	.IFGT	N-5
	.LIST
	MOV	(SP)+,CEL6
	.NLIST
	.ENDC
	.ENDC
	.ENDC
	.ENDC
	.ENDC
	.LIST
	.ENDM
;
; INHIBIT INTERRUPTS
;
	.MACRO	.INH
	PUSH	PS
	BIS	#340,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	TCBP
	MOV	TCBP,R5
	MOV	#100000,R4
	IOT
	.BYTE	1,0
	.ENDM
;
	.SBTTL	TRAP VECTORS
.=0				;(RCHM-141) SET INITIAL PC TO 0
	.BLOCK 1000		;(RCHM-141) INITIALIZE FIRST 1000 WORDS TO 0.
;
;DO NOT CHANGE THE LOCATION OR ORDER OF THE FOLLOWING REGISTERS UPTILL
;THE LINE MARKED *******END NO CHANGE******
;
;	THE FOLLOWING ARE PDP-11 TRAP VECTORS.
;
	.=0
	JMP	START		;(00) LOCATION ZERO IS A RESTART LOCATION
	NODEV			;(04) BUS ERRORS
	HALT
	.+2			;(10) RESERVED INSTRUCTION 
	HALT
	.+2			;(14) TRACE TRAP
	HALT
	IOTPRO			;(20) IOT TRAP
	7*40
	PWRFAL			;(24) POWER FAIL (LVL 07)
	7*40
	.+2			;(30) EMT TRAP
	HALT
	.+2			;(34) TRAP TRAP
	HALT
;
;	THE FOLLOWING LOCATIONS ARE USED BY PIREX TO STORE MISCELLANEOUS
;	INFORMATION.
;
MEMSIZ:	0			;(40) LOCAL MEMORY SIZE OF THE PDP-11
	EDIT			;(42) CURRENT EDIT NUMBER
LCLAST:	LASTLC			;(44) LAST LOCATION USED BY PIREX (BR-147)
DUMMY:	0			;(46) DUMMY CONTROL REGISTER
;
	.SBTTL	SYSTEM INTERRUPT VECTORS
;
;
;	THE FOLLOWING ARE THE DEVICE INTERRUPT VECTORS - PAIRS, CONSISTING
;	OF INTERRUPT ROUTINE ADDRESS & PRIORITY LEVEL - .
;	THE PRIORITY LEVEL OF "ALL" DEVICES SHOULD BE LVL-7 "ONLY".
;	THIS IS TO PERMIT PIREX TO DO A CONTEXT SWITCH BEFORE PROCESSING THE
;	INTERRUPT.
;
;
	.IFDF $HP		;(RCHM-141) HURLEY DEFINED?
	.IFDF DL.0T		;(RCHM-141) USING THE CONSOLE DL?
.=60				;(RCHM-141) START CONSOLE VECTORS AT 60.
	DL.0R			;(RCHM-141) TRANSFER VECTOR TO READ ROUTINE.
	000340			;(RCHM-141) AT LEVEL 7.
	DL.0S			;(RCHM-141) TRANSFER VECTOR TO SEND ROUTINE.
	000340			;(RCHM-141) AT LEVEL 7.
	.ENDC			;(RCHM-141)
	.ENDC			;(RCHM-141)
;
.=100				;(RCHM-141) CLOCK VECTORS AT 100.
	CLINT			;(100) $CL INTERRUPT VECTOR
	340
;
	.IFDF	$PL
.=120				;(RCHM-141) PLOTTER VECTORS AT 120.
	PLINT			;(120) PL INTERRUPT VECTOR(LVL 4)
	340
	.ENDC
;
	.IFDF	$LV
.=170				;(RCHM-141) LV VECTORS AT 170.
	LVINT
	340
	.ENDC
;
	.IFDF	$LP
.=200				;(RCHM-141) LP VECTORS AT 200
	LPINT			;(200) LP INTERRUPT VECTOR (LVL 04)
	340
	.ENDC
;
	.IFDF	$DT
.=214				;(RCHM=141) DT VECTORS AT 214.
	DTINT			;(214) DT INTERRUPT VECTOR (LVL 07)
	340
	.ENDC
	.IFDF	$RK
.=220				;(RCHM-141) RK VECTORS AT 220.
	DKINT			;(220) RK INTERRUPT VECTOR (LVL 05)
	340
	.ENDC
;
	.IFDF	$CD
.=230				;(RCHM-141) CD VECTORS AT 230.
	CDINT			;(230) CD INTERRUPT VECTOR (LVL 6)
	340
	.ENDC
;
	.IFDF $HP		;(RCHM-153) STICK IN THE DEFAULT ASSIGNMENTS
	.IFDF DL.1T		;(RCHM-153) SO THAT CERTAIN PEOPLE WILL
.=300
	DL.1R			;(RCHM-153) WILL NOT HAVE ANY PROBLEMS
	000340			;(RCHM-153) INSTALLING THIS OPTION.
	DL.1S			;(RCHM-153)
	000340		;(RCHM-153)
	.ENDC			;(RCHM-153)
	.ENDC			;(RCHM-153)
;
.=310				;(RCHM-141) PDP-15 INTERRUP VECTOR LINK THROUGH 310.
	MASREQ			;(310) LEVEL 7 INTERRUPT VECTOR (LVL 07)
	340
;
	.SBTTL	SYSTEM STACK AND REGISTERS
	.=1000
;
SSTACK:				;START OF SYSTEM STACK
SYS.SP:	1000			;SYSTEM STACK POINTER
;
; SYSTEM REGISTERS BEGIN HERE
;
	SEND11			;INT. RETURN ADD. (ON 11) ON END OF I/O
CURTSK:	000000			; CURRENT TASK RUNNING
	POL.LH			; ADDRESS OF POOL LISTHEAD
	LISTHD			; ADDRESS OF TASK LISTHEADS
	R.SAVE			; ENTRY POINT TO REGISTER SAVE
	R.REST			; ENTRY POINT TO REGISTER RESTORE
	AS.E1			; ENTRY POINT TO ATL RESCAN
	MOVEN			; ENTRY POINT TO NODE MOVER
	DEQU			; ENTRY POINT TO DEQUEUE
	SEND15			; ENTRY POINT TO SEND INTERRUPT
	EMPTY			; ENTRY POINT TO EMPTY A DEQUE
	ATLNP			; ATL NODE POINTER TABLE
	RATLN			; ENTRY POINT TO RETURN ATL NODE
	SPOLSW			;SPOOLER SWITCHES ADDRESS
	RTURN			;REUTURN INST. ADD. FOR PIC CODE
NBRTEV:	NTEV			; CURRENT NBR OF TASKS
PWRDWN:	RTURN			; ENTRY POINT TO PWR FAIL DOWN
PWRUP:	RTURN			; ENTRY POINT TO PWR FAIL UP
SPOLSW:	0			;SPOOLER SWITCHES
	DEVST			;DEVICE ERROR STATUS TABLE
	CLTABL			;TABLE, A TIME-ADDR PAIR FOR EACH TASK
	DEQU1			; ENTRY TO -SET TASK IN WAIT STATE- ROUTINE
	CEXIT			; ENTRY TO -SET TASK IN RUN STATE- ROUTINE
	TEVADD			; TABLE OF TASK START ADDRESSES
DEVARE:	.WORD	DEVTYP
DEVSPL:	.WORD	0		;DEVICES SPOOL:ED SWITCH
CTLCNT:	.WORD	0		;PDP-15 CTL C RUNNING COUNTER (BR-116)
SPUNIT:	.WORD	0		;SPOOLER DISK UNIT NR. (BR-122)
;
;
;********END NO CHANGE**********
;
	.SBTTL	SYSTEM TABLES
;
; TASK START ADDRESS TABLE
;
;	EACH TASK HAS A 2 CHAR. MNEMONIC 'XX' WHICH IS ALSO THE LABEL
;	OF THE FIRST EXECUTABLE INST. IN THE TASK. VIZ..
;	XX:	MOV	.....
;
;	EVERY TASK IN PIREX HAS A TASK CODE 'X'. X CAN TAKE A VALUE
;	UPTO A MAXIMUM OF 177 OCTAL. BY DEFAULT ALL TASKS ARE SPOOLED
;	TASKS. TO CREATE AN UNSPOOLED TASK ADD '200' TO THE TASK CODE.
;	VIZ..	'200+X'
;
;
TEVADD:	.WORD	ST		;STOP TASKS (TASK CODE = 200)
	.WORD	SD		;SOFTWARE DIRECTIVES (TASK CODE = 201)
	.IFDF	$RK
	.WORD	DK		;RK05 (TASK CODE = 202)
	.ENDC
	.IFNDF	$RK
	.WORD	0
	.ENDC
	.IFDF	$DT
	.WORD	DT		;DT11 (TASK CODE = 203)
	.ENDC
	.IFNDF	$DT
	.WORD	0
	.ENDC
	.IFDF	$LP
	.WORD	LP		;LP11 (TASK CODE = 4)
	.ENDC
	.IFNDF	$LP
	.WORD	0
	.ENDC
	.IFDF	$CD
	.WORD	CD		;CR11 (TASK CODE = 5)
	.ENDC
	.IFNDF	$CD
	.WORD 0
	.ENDC
	.IFDF	$PL
	.WORD	PL		;XY PLOTTER(TASK CODE=6)
	.ENDC
	.IFNDF	$PL
	.WORD	0
	.ENDC
	.WORD	0		;SPOOLER (TASK CODE = 207)
	.IFDF	$LV
	.WORD	LV		;LV PRINTER/PLOTTER CODE 210
	.ENDC
	.IFNDF	$LV
	.WORD	0
	.ENDC
	.IFDF $HP		;(RCHM-140) HURLEY PROTOCOL COMMUNICATIONS OPTION (211)
	.WORD HP.ENT		;(RCHM-140) POINTER TO INTERFACE TASK ENTRY POINT.
	.IFF			;(RCHM-140) 
	.WORD 0			;(RCHM-140) HP COMMUNICATIONS OPTION NOT SELECTED.
	.ENDC			;(RCHM-140)
; INSERT PERMANENT TASKS BEFORE THIS LINE ONLY!!!!!!
NTEV=.-TEVADD/2			;NUMBER OF TASKS
; INSERT TEMPORARY TASKS AFTER THIS LINE ONLY!!!
	.WORD	0		;SPARE TASK(TASK CODE=212)
	.WORD	0		;SPARE TASK(TASK CODE=213)
	.WORD	0		;SPARE TASK(TASK CODE=214)
; INSERT TEMPORARY TASKS BEFORE THIS LINE ONLY!!!   (BR-147)
NTSK=.-TEVADD/2			;NUMBER OF TOTAL TASKS (BR-147)
;
;	TASK SCHEDULING PRIORITY LEVEL TABLE
;
	.BYTE	7*40		;LEVEL 7 - CL :-1
LEVEL:	.BYTE	7*40		;LEVEL 7 - ST :0
	.BYTE	7*40		;LEVEL 7 - SD :1
	.BYTE	5*40		;LEVEL 5 - DK :2
	.BYTE	6*40		;LEVEL 6 - DT :3
	.BYTE	4*40		;LEVEL 4 - LP :4
	.BYTE	6*40		;LEVEL 6 - CD :5
	.BYTE	5*40		;LEVEL 5 - PL :6
	.BYTE	0*40		;LEVEL 0 - SP :7
	.BYTE	4*40		;LEVEL 4 - LV :10
	.BYTE 6*40		;(RCHM-140) LEVEL 6 - HP :11
	.BYTE	0,0,0
	.EVEN
;
;	THE TK.END TABLE IS USED TO CONTROL ALLOCATION OF MEMORY TO TEMP. TASKS
;	VIA THE CONNECT AND DISCONNECT DIRECTIVES. THE CONNECT DIR. CAUSES
;	THE TASK'S LAST LOC+1 TO BE ENTERED INTO THE TK.END ENTRY CORRESPONDING
;	TO THE TASK'S 'TASK-CODE-NUMBER'. EACH DISCONNECT CAUSES THE
;	THE ENTRY FOR THAT TASK TO BE CLEARED. THE TK.END TABLE IS THE SCANNED
;	TO FIND THE HIGHEST MEMORY ADR. WHICH THEN BECOMES THE NEXT AVAILABLE
;	LOC. (LCLAST).THIS ROUTINE ASSURES THAT ANY HOLES LEFT BY TASKS
;	DISCONNECTING IN A DIFFERENT ORDER THAN THEY CONNECTED, WILL BE
;	RECOVERED - EVENTUALY.
;
;	NOTE:	THE RESIDENT PERM. SECTION OF PIREX HAS AN ENTRY
;		IN TK.END+0 (ST: ENTRY). THIS WAS DONE BECAUSE ANY OTHER
;		ENTRIES WOULD BE REDUNDANT AND TO ALLOW USERS TO DELETE
;		PIREX TASKS AND USE THEIR ENTRIES FOR TEMP. TASKS.
;
;	NOTE2:	UNDER THE FOLLOWING CONDITIONS THE NEXT FREE LOC. POINTER
;		'LCLAST' IS RESET TO THE END OF PIREX+1 (LASTLC):
;			INITIALIZATION
;			RESTART FROM 0
;			POWERFAIL RECOVERY
;
TK.END:	.REPT	NTSK	;NUMBER OF ENTRIES=NUMBER OF TASKS (BR-147)
	.WORD	0	;INITIALIZED TO 0 (BR-147)
	.ENDR		;END OF TABLE (BR-147)
T.END=.			;ADR. OF END OF TABLE (BR-147)
;
; TASK ATL NODE POINTERS ARE STORED IN THIS TABLE WHEN TASK IS ACTIVE
; EACH TASK HAS A ONE WORD ENTRY IN THE TABLE WHICH IS '0' IF TASK
; IS INACTIVE
;
	CLKNOD			;CL	-1
ATLNP:	0			;ST	0
	0			;SD	1
	0			;RK	2
	0			;DT	3
	0			;LP	4
	0			;CD	5
	0			;PL	6
SPLNP:	0			;SP	7 (BR-145)
	0			;LV	10
	0			;(RCHM-140) HP 11
	0			;	12
	0			;	13
	0			;(RCHM-140)	14
;
;	THE FOLLOWING IS A TABLE OF TRANSFER VECTORS TO HANDLE COMPLETION
;	OF I/O INT.(FUNCTION CODE IN TCB = 2)
;
SEND11:	0			;ST	0
	0			;SD	1
	0			;RK	2
	0			;DT	3
	0			;LP	4
	0			;CD	5
	0			;PL	6
	0			;SP	7
	0			;LV	10
	0			;(RCHM-140) HP 11
	0			;	12
	0			;	13
	0			;(RCHM-140)	14
;
;	TASK STATUS CODED AS FOLLOWS IS STORED IN THIS TABLE
;
;	WORD 1: TASK MNEMONIC IN SIXBIT/RAD50
;	WORD 2: SPARE
;	WORD 3: ERROR CODE(XXXX)
;		SPOOLER ERROR CODE(HIGH BYTE)
;		TASK ERROR CODE(LOW BYTE)
;
DEVST=.
ST.EST=.
	STCOD
	.WORD	0,0		;ST STATUS
SD.EST=.
	SDCOD
	.WORD	0,0		;SD STATUS
RK.EST=.
	RKCOD
	.WORD	0,0		;RK STATUS
DT.EST=.
	DTCOD
	.WORD	0,0		;DT STATUS
LP.EST=.
	LPCOD
	.WORD	0,0		;LP STATUS
CD.EST=.
	CDCOD
	.WORD	0,0		;CD STATUS
PL.EST=.
	PLCOD
	.WORD	0,0		;PL STATUS
SP.EST=.
	SPCOD
	.WORD	0,0		;SP STATUS
LV.EST=.
	LVCOD
	.WORD	0,0		;LV STATUS
HP.EST=.			;(RCHM-140)
	.WORD 0,0,0		;(RCHM-140) HP STATUS (UNUSED AT PRESENT).
T1.EST=.
	.WORD	0,0,0		;SPARE 1
T2.EST=.
	.WORD	0,0,0		;SPARE 2
T3.EST=.
	.WORD	0,0,0		;SPARE 3
NDEVST=.-DEVST/3
;
;
;
;
;  IF CLOCK DEFINED A TABLE FOR ONE TIMING REQUEST FROM EACH TASK.
;  TWO WORDS: FIRST IS TIME TO GO, PAIR IS DISABLED WITH 0 TIME;
;  SECOND WORD IS ADDR FOR JSR PC,XXX  .THIS IS CALLED AT
;  CLOCK INTERRUPT LEVEL (6). THE USER MUST OF COURSE DO
;  A RTS PC. TIME IS IN TICKS, I.E. 1/60 SEC.
;  A TASK MAY CANCELL A TIMING REQUEST BY CLEARING THE TIME WORD.
;  TO MAKE A REQUEST, PUT THE ADDR OF SUBROUTINE TO BE CALLED
;  WHEN TIME COMES DUE IN ADDR WORD. PUT THE DELAY TIME IN TICKS
;  IN THE TIME WORD, IN THAT SEQUENCE.
;
;
CLTABL=.
ST.CL=.
	.WORD	0,0
SD.CL=.
	.WORD	0,0
DK.CL=.
	.WORD	0,0
DT.CL=.
	.WORD	0,0
LP.CL=.
	.WORD	0,0
CD.CL=.
	.WORD	0,0
PL.CL=.
	.WORD	0,0
SP.CL=.
	.WORD	0,0
LV.CL=.
	.WORD	0,0
HP.CL=.				;(RCHM-140) HP CLOSK INTERVAL ENTRY.
	.WORD 0,0		;(RCHM-140)
T1.CL=.
	.WORD	0,0
T2.CL=.
	.WORD	0,0
T3.CL=.
	.WORD	0,0
CLEND=.
;
;
;
;	EACH TASK HAS A LINKED LIST OF NODES, EACH NODE CONTANING THE
;	TCBP OF A REQUEST. THE LIST IS CALLED THE "TASK REQUEST LIST"
;	(TRL).
;	THE FOLLOWING ARE THE TASK LISTHEADS(POINTERS)
;
;
LISTHD:	LISTHEAD	ST	;ST = STOP TASKS
	LISTHEAD	SD	;SD = SOFTWARE DIRECTIVES
	LISTHEAD	DK	;DK = RK05 DISK
	LISTHEAD	DT	;DT = DECTAPE
	LISTHEAD	LP	;LP = LINE PRINTER
	LISTHEAD	CD	;CD = CARD READER
	LISTHEAD	PL	;PL = XY PLOTTER
	LISTHEAD	SP	;SP = SPOOLER
	LISTHEAD	LV	;LV = LV PLOTTER/PRINTER
	LISTHEAD HP		;(RCHM-140) HP = HURLEY PROTOCOL COMMUNICATIONS OPTION.
	LISTHEAD	T1	;SPARE TASK
	LISTHEAD	T2	;SPARE TASK
	LISTHEAD	T3	;SPARE TASK
;
;	PIREX MAINTAINS INFORMATION(VIZ.. STACK POINTER,PRIORITY
;	LEVEL, TASK CODE, TASK STATUS) OF ACTIVE TASKS IN A LINKED
;	LIST CALLED THE "ACTIVE TASK LIST"(ATL). THE FOLLOWING IS THE
;	ATL LISTHEAD WITH ITS PERMANENT ENTRIES(CLKNOD+NULNOD)
;
;
ATL.LH:	.WORD	CLKNOD		;CLOCK & NUL JOB ARE ALWAYS ACTIVE
	.WORD	NULNOD
;
; CLOCK ATL NODE
;
CLKNOD:	.WORD	NULNOD		;POINTS TO NUL JOB NODE
	.WORD	ATL.LH		;POINTS TO ATL LIST HEAD
	.WORD	CLINT-EAESTK	;STACK POINTER
	.WORD	167762		;LVL 7 + '-1' TASK CODE + WAIT STATE
;
; NUL JOB ATL NODE
;
NULNOD:	.WORD	ATL.LH		;INITIALLY POINTS TO ATL LIST
	.WORD	CLKNOD		;POINTS TO CLOCK NODE
	.WORD	NULPC		;NUL JOB'S STACK POINTER (BR-134)
	.WORD	0		;TASK IS ALWAYS RUNNABLE AT MAIN-
				;    STREAM LEVEL.
;
	.SBTTL	POOL OF EMPTY NODES
;
;	THE FOLLOWING IS A POOL OF EMPTY NODES. THE POOL EXISTS IN A
;	LINKED LIST FORM.
;
;
POL.LH:	.WORD	.+4
	.WORD	POLEND
;
	.WORD	.+10
	.WORD	POL.LH
	.BLOCK	2
;
	.REPT	POLSIZ
;
	.WORD	.+10
	.WORD	.-12
	.BLOCK	2
	.ENDR
;
	.WORD	POL.LH
	.WORD	.-12
	.BLOCK	2
;
POLEND=.-10
;
	.SBTTL	SYSTEM REGISTER SAVE/RESTORE ROUTINES
;
; THIS ROUTINE SAVES SYSTEM REG.'S R0-R5 &EAE (IFDEFINED) AND SAVES
; TASK SP IN ATL NODE AND DOES A CONTEXT SWITCH TO INT. PRC. TASK
;
; CALLING SEQUENCE:	JSR	R0,R.SAVE
;			TASKCODE/-2
;			......		INSTRUCTION  TO BE EXECUTED
;						ON RETURN
;			REGS. USED: R0-R3
;
R.SAVE:
	CMP	#NULNOD,CURTSK		;TEST FOR NUL TASK (BR-134)
	BEQ	2$			;BRANCH IF NULTASK (BR-134)
	PUSH	R1,R2,R3,R4,R5	;SAVE R0-R5 (R0 SAVED ON CALL)
	.IFDF	EAE
	PUSH	AC,MQ,SC	;SAVE EAE REGISTERS ALSO
	.ENDC
	MOV	CURTSK,R2	;SAVE CURRENT TASK SP
	MOV	SP,A.SP(R2)
2$:	MOV	(R0)+,R1	;GET CALLING TASK CODE (BR-134)
	CMP	#-2,R1	;SKIP SWITCH STACK?
	BEQ	1$
	MOV	R1,R3		;SAVE TASK CODE IN R3
	ASL	R1		;CONVERT TO WORD OFFSET
	MOV	ATLNP(R1),R2	;SWITCH STACK
	MOV	R2,CURTSK	;SET CURTSK
	MOV	A.SP(R2),SP	;SP
	BIC	#17,A.TS(R2)	;SET STATUS TO RUN
	MOVB	LEVEL(R3),PS	;SET PRIRITY
1$:	MOV	R0,PC		;RETURN TO CALLER
;
;	THIS ROUTINE RESTORES EAE REGS.(IF DEFINED) & SYSTEM REGISTERS
;	R0-R5.
;
;		REGS. USED: NONE
;
R.REST:
	CMP	#NULNOD,CURTSK		;TEST FOR RESTORE OF NULTASK(BR-134)
	BEQ	2$			;BRANCH IF NULTSK (BR-134)
	TST	(SP)+		;FORGET CALL R0
	.IFDF	EAE
	POP	SC,MQ,AC	;RESTORE THE EAE REGISTERS
	.ENDC
	POP	R5,R4,R3,R2,R1	;RESTORE R1-R5
2$:	RTS	R0		;R0 RESTORED ON EXIT (BR-134)
;
	.SBTTL	POWER FAIL HANDLER
;
;	THIS ROUTINE CURRENTLY HANDLES POWER FAILURE.
;	*******IT IS UNSUPPORTED*******
;	IT CLEARS ALL INTS. AND CALLS THE INITIALIZATION ROUTINE
;	WHEN POWER IS BROUGHT UP.
;	NO ATTEMPT IS MADE TO CONTINUE PREVIOUS WORK.
;	INDEED THE SPOOLER IS KILLED ON EVERY POWER-UP AND MUST
;	BE RESTARTED.
;
PWRFAL:
	MOV	#RSTART,@#24	;RESTART ADDRESS DURING POWER UP
	HALT			;HALT DURING POWER DOWN
;
;
;ENTER HERE ON AUTO RECOVERY OF POWER FAIL
;
RSTART:
	MOV	#PWRFAL,@#24	;RESTORE POWER FAIL ADR AT VECTOR (BR-146)
	RESET			;CLEAR ALL REG,I/O ETC. (BR-146)
	JMP	START		;GO TO PIREX INIT. ROUTINE (BR-146)
;
	.SBTTL	NUL TASK
;
; THIS IS THE NUL TASK WHICH RUNS WHEN ALL OTHER TASKS CANNOT.
; THE TASK IS ALWAYS RUNNNABLE
; IT CONSISTS OF 2 INSTRUCTIONS.  THE"WAIT" INSTRUCTION IS USED TO
; INCREASE UNIBUS THROUGHPUT.
;
	.BLOCK EAESTK*2+14.
NULPC:	.WORD NULJOB		;PC SETUP FOR START OF NULJOB (BR-134)
	.WORD 0			;PS SETUP .......
        .WORD DUMMY
        .WORD 0
        .WORD 0
NULJOB:
	WAIT
	BR	NULJOB
;
	.SBTTL	INTER-TASK REQUEST COMMUNICATION HANDLER
;
; THIS IS THE INTER-TASK REQUEST COMMUNICATION HANDLER. REQUESTS
; ARE ISSUED BY PASSING THE ADDRESS/POINTER OF/TO A BLOCK OF INFORMATION
; (CALLED THE "TASK CONTROL BLOCK"-TCB-). WHEN REQUESTS ARE ISSUED FROM
; THE PDP-15 THE READING OF THE TCB REGISTER SETS THE "DONE" FLAG IN THE PDP-15.
; WHEN PIREX RECEIVES A REQUEST FROM THE PDP-15 IT FIRST SAVES THE
; GENERAL PURPOSE REGISTERS, READS IN AN 18 BIT TCBP AND THEN
; RELOCATES THE TCBP TO A PDP-11 ADDRESS.  
; WHEN REQUESTS ARE ISSUED FROM THE PDP-11 THE TCBP IS ALREADY PRESENT IN
; R4(2 MSB'S) & R5(16 LSB'S). A CHECK IS THEN MADE
; TO DETERMINE IF THE TASK IN REFERENCE IS BUSY.  IF BUSY, THE
; REQUEST IS QUEUED TO THE TASK REFERENCED.  IF NOT, THE REQUEST
; IS ENTERED INTO  THE TASK IDLE SWITCH AND AN ATL SCAN IS MADE STARTING
; FROM THE TOP OF THE LIST, TO RUN THE HIGHEST PRIORITY TASK.
;
; WHEN THE PIREX COMPLETELY FINISHES A REQUEST FOR THE PDP-15, IT SIGNALS
; THE PDP-15 OF THIS FACT BY ISSUING AN API INTERRUPT IF REQUESTED AT A LEVEL
; CORRESPONDING TO THAT WHICH WAS SPECIFIED IN THE ACTIVE LEVELS
; TABLE. A SOFTWARE INTERRUPT ON THE PDP-11 IS ISSUED IF
; THE REQUEST IS MADE BY A TASK RUNNING ON THE PDP-11 IF REQUESTED IN THE TCB.
; IN EITHER CASE THE REQUEST EVENT VARIABLE(REV) IN THE TCB IS SET
; TO THE APPROPRIATE VALUE ON COMPLETION OF THE REQUEST. IF MORE REQUESTS EXIST
; IN THE TASKS DEQUES AT THE COMPLETION OF A PREVIOUS REQUEST, THE NEXT
; ENTRY IS REMOVED AND PROCESSED.  THIS CONTINUES UNTIL THE ENTIRE DEQUE
; IS EMPTY AT WHICH TIME THE TASK GOES INTO AN WAIT STATE(IF IT IS A PERMANENET TASK)
; OR EXIT STATE(IF IT IS A TEMPORARAY TASK).
;
;
; THIS ROUTINE IS ENTERED AT "MASREQ" WHEN A REQUEST IS ISSUED BY THE
; PDP-15 AND AT "CALLTK" WHEN REQUEST IS ISSUED BY A TASK RUNNING ON THE
; PDP-11 THRO' THE IREQ MACRO.
;
;		REGS. USED: ALL
;
MASREQ:
	JSR	R0,R.SAVE	;SAVE REGISTERS
	-2			;SKIP SWITCH STACK
	MOV	SYS.SP,SP
				;NOTE:  UPPER 2 BITS OF
	MOV	TCBP18,R4	;    TCB ARE SAVED BUT NOT USED HERE.
	BIC	#177774,R4	;    IF 11 HAS AN MX11, THESE EXTEND
				;    BITS WILL HAVE TO BE ACCOUNTED FOR.
	MOV	TCBP,R5		;GET THE TCBP FROM THE 15.  READING
				;    THE TCBP REGISTER AUTOMATICALLY
				;    SETS THE "DONE" FLAG FOR THE 15.
	ADD	MEMSIZ,R5	;ADJUST TCBP TO REFLECT THE 11'S
	ADC	R4		;    REAL ADDRESS.
	TST	R4		;WAS TCB SENT FROM COMMON MEMORY? (BR-148)
	BNE	HI.TCB		;BRANCH IF TCB NOT IN COMMON MEMORY (BR-148)
	CMP	#160000,R5	;28K IS THE LIMIT (BR-148)
	BLO	HI.TCB		;BRANCH IF TCB NOT IN COMMON MEMORY (BR-148)
CALTSK:	TSTB	TCN(R5)		;SPOOLED TASK?
	BMI	CALLTK
	BIT	#140000,SPOLSW	;YES. SPOOLER ENABLES?
	BEQ	CALLTK
	MOV	#SPTCOD,R1	;YES. CALL SPOOLER
	BR	CALTK0
HI.TCB:	MOV	#602,SD.EST+4	;SET ERROR IN POLLER TABLE,SINCE TCB
				;EVENT VARIABLE IS OUT OF RANGE (BR-148)
	JMP	AS.E1		;RESCAN ATL FOR NEXT TASK (BR-148)
CALLTK:
	MOVB	TCN(R5),R1	;GET TASK CODE NUMBER FROM TCB
	BIC	#177600,R1	;CLEAR SPOOLED/UNSPOOLED BIT
	CMPB	NBRTEV,R1	;LEGAL TASK CODE? (BR-134)
	BLT	LVL703		;NO:  RETURN WITH ERROR CODE IN CALLERS (BR-134)
CALTK0:	MOV	R1,R2		;    TCB (EVENT VARIABLE).
	ASL	R1
	MOV	TEVADD(R1),R3	;GET STARTING ADDRESS OF TASK
	BEQ	LVL703		;NO TASK CONNECTED TO THIS SLOT
	TST	-(R3)		;IS THE TASK IN REFERENCE TO THIS
	BNE	LVL701		;    REQUEST CURRENTLY BUSY?
	MOV	R5,(R3)		;USE TCBP TO SET TASK'S IDLE/BUSY
	MOV	R4,-(R3)	;   SWITCH.
	CLR	TEV(R5)		;CLEAR TASK EVENT VARIABLE IN
				;    THE TCB.
	MOV	ATLNP(R1),R1	;GET ATL NODE ADDRESS IF PRESENT
	BEQ	1$		;    ALLOCATED FOR THIS TASK.
	MOV	R1,R0		;FOUND ONE, SET STATUS TO RUNNABLE
	BR	4$		;    AND RESCAN THE ATL.
1$:	MOV	#ATL.LH,R0	;SCAN THE ATL FOR A POSITION FOR
3$:	MOV	@R0,R1		;    THIS NEW NODE ENTRY.
	CMPB	A.TP(R1),LEVEL(R2)
	BLO	2$		;FOUND ONE, BACK UP ONE AND LINK A
				;    NODE FROM THE POOL TO IT.
	CMP	#NULNOD,R1	;END OF ATL?
	BEQ	2$		;YES:  LINK BEFORE NUL TASK NODE
	MOV	R1,R0		;LINK TO NEXT NODE
	BR	3$
2$:	CMP	#POL.LH,POL.LH	;ANY NODES LEFT IN THE POOL?
	BEQ	LVL705		;NO:  TELL CALLER AND EXIT
	MOV	R0,R1		;USE PREVIOUS NODE TO LINK TO
	MOV	POL.LH,R0	;MOVE NODE FROM THE POOL NOW
	ASL	R2		;CONVERT TASK CODE TO WORD OFFSET
	MOV	R0,ATLNP(R2)	;SAVE ATL NODE ADDRESS IN ATLNP TABLE
	ASR	R2		;GET BACK TASK CODE
	CALL	MOVEN
4$:	SUB	#4,R3		;R3-4 (BR-134)
	PUSH	R2		;SAVE TASK CODE #
	MOVB	LEVEL(R2),(R3)	;    SET PS IN TASK'S STACK AREA.
	PUSH	R3		;SAVE TASK STARTING ADDRESS(PC) IN STACK
	ADD	#10,(SP)	;    AREA.
	POP	-(R3)
	SUB	#STKSZE,R3	;NOW EXTABLISH THE STACK
	MOV	R3,A.SP(R0)
	ASL	R2		;SAVE TASK CODE # IN ATL
	ASL	R2
	ASL	R2
	ASL	R2
	MOV	R2,A.TS(R0)	;    ..... AND AT THE SAME TIME,
	BICB	#340,A.TP(R0)	;SET PRIORITY LVL OF TASK IN ATL
	POP	R2		;GET TASK CODE
	BISB	LEVEL(R2),A.TP(R0)
	BR	AS.E1		;    SET TASK STATUS TO RUNNABLE.
;
LVL701:	ASL	R1		;LINK A NODE FROM POOL TO TASK'S DEQUE
	TST	(R1)+		;(POINTS TO BACKWARD POINTER OF LISTHEAD)
	MOV	LISTHD(R1),R1
	CMP	#POL.LH,POL.LH	;ANY POOL NODES LEFT?
	BEQ	LVL705		;NO:  TELL USER
	MOV	POL.LH,R0	;GET A NODE FROM THE POOL
	MOV	R5,6(R0)	;SAVE TCBP IN NODE
	MOV	R4,4(R0)
	CALL	MOVEN		;MOVE NODE
	CLR	TEV(R5)		;CLEAR TASK EVENT VARIABLE IN TCB.
	BR	AS.E1		;RESCAN THE ATL
LVL705:	MOV	#-777,R1	;TELL USER HE'S OUT OF POOL
	BR	LVL704		;    AND RESCAN THE ATL.
;
LVL703:	MOV	#-200,R1	;ILLEGAL TASK SPECIFIED, RETURN
LVL704:	MOV	R5,R0
	CALL	SEND15
	BR	AS.E1		;RESCAN ATL NOW
;
	.SBTTL	SCAN OF ACTIVE TASK LIST
;
; THE ACTIVE TASK LIST (ATL) IS A PRIORITY ORDERED LIST
; (LINKED NODES) OF TASKS TO BE PROCESSED.
;
; THE SYSTEM IS DRIVEN BY SCANNING THE ATL FROM THE TOP (HIGHEST
; PRIORITY).  A TASK IS CAPABLE OF EXECUTION ONLY IF ITS
;  STATUS IS ZERO.  ALL OTHER CODES RESULTS IN SPECIAL
; HANDLING.
;
; THERE ARE THREE ENTRY POINTS TO THE ATL SCAN ROUTINE
;
; AS.E1 -- TO SCAN THE ATL DOWNWARD FROM THE TOP.
;
; AS.SCN-- TO SCAN THE ATL DOWNWARD STARTING FROM THE NEXT NODE
;          POINTED TO BY R0.
;
; AS.E2 -- TO SCAN THE ATL DOWNWARD STARTING AT THE NODE POINTED
;          TO BY R0.
;
; CONTROL IS ALWAYS TRANSFERRED TO THE SCANNER WITH THE
; CURRENT TASKS PS, PC, AND THE GENERAL PURPOSE REGISTERS
; PUSHED ON THE STACK.
;
;		REGS. USED: R0,R1,R2
;
AS.E1:				;SCAN FROM TOP OF ATL
	MOV	#ATL.LH,R0	;SET R0 TO THE FIRST ATL NODE
;
; SCAN LOOP -- AFTER PROCESSING AN ATL ENTRY, CONTROL IS
; TRANSFERRED EITHER:  (1) TO 'AS.SCN' TO PROCESS THE NEXT ATL NODE,
; OR (2) TO 'AS.TE' TO TERMINATE THE ATL SCAN (A RUNNABLE TASK HAS BEEN
; FOUND).
;
; CONTROL IS TRANSFERRED HERE FROM AN ATL SCAN SERVICE ROUTINE
; (SPECIAL HANDLING ROUTINE) WITH THE STACK AND R0 UNCHANGED FROM
; THE DISPATCH TO THAT SERVICE ROUTINE.
;
AS.SCN:	MOV	@R0,R0		;ADVANCE R0 TO THE NEXT ATL NODE
AS.E2:	MOVB	A.TS(R0),R1	;    AND DISPATCH PER ACTIVE TASK STATUS,
	BIC	#177760,R1	;    WITH R0=ATL NODE ADDR AND R1=STATUS.
	JMP	@AS.E3(R1)
AS.E3:				;DISPATCH ADDRESS TABLE
	AS.TE			;(00) TASK IS RUNNABLE
	AS.SCN			;(02) TASK IS IN A WAIT STATE
	AS.STP			;(04) TASK MUST BE STOPPED AND CLEANED UP
;
; TERMINATE THE ATL SCAN.  A RUNNABLE TASK HAS BEEN FOUND
;
AS.TE:	MOV	SP,SYS.SP	;SAVE SYSTEM STACK POINTER
	MOV	R0,CURTSK	;ESTABLISH NEW CURRENT TASK
	MOV	A.SP(R0),SP	;RESTORE THIS TASK'S REGISTERS
	CMP	#NULNOD,R0	;IS THIS THE NULL TASK (BR-134)
	BEQ	2$		;YES BRANCH (BR-134)
	.IFDF	EAE
	POP	SC,MQ,AC	;EAE REGS
	.ENDC
	POP	R5,R4,R3,R2,R1,R0
2$:	RTI			;RETURN CONTROL TO INTERRUPTED TASK (BR-134)
;
; STOP TASK NOW BY REMOVING HIS NODE FROM THE ATL & ZEROING ENTRY IN ATLNP TABLE
;
AS.STP:	MOV	#POL.LH,R1	;RETURN NODE TO POOL
	CLR	4(R0)		;ZERO ENTRY BEFORE RETURNING
	MOV	6(R0),R2	;GET TASK CODE
	ASR	R2		;CONVERT TO WORD OFFSET
	ASR	R2
	ASR	R2
	BIC	#177601,R2	;CLEAR JUNK
	CLR	ATLNP(R2)	;CLEAR ATL NODE ENTRY IN SYSTEM TABLE
	CLR	6(R0)
	ASR	R2		;GET TASK CODE
	CMPB	NBRTEV,R2	;TEMPORARY TASK (BR-134)
	BNE	1$
	DEC	NBRTEV
1$:	MOV	@R0,R2		;SAVE LINK TO NEXT NODE
	CALL	MOVEN
	MOV	R2,R0		;NOW LOOK AT NEXT NODE
	BR	AS.E2
;
;
	.SBTTL	IOT PROCESSOR
;
;	PROCESSES THE FOLLOWING MACRO REQUESTS:
;	  SEXIT S - EXIT FROM TASK IN STATE "S"
;			MACRO EXPANSION:
;			IOT
;			.BYTE 0,S
;	  IREQ TCBP  - ISSUE A TASK REQUEST
;			MACRO EXPANSION:
;			MOV TCBP,R5
;			MOV #100000,R4
;			IOT
;			.BYTE 1,0
;
; THIS ROUTINE IS ENTERED WHEN AN IOT IS EXECUTED.
;
;		REGS. USED: R0,R1,R2
;
IOTPRO:	JSR	R0,R.SAVE	;SAVE CURRENT TASK'S REGISTERS ON HIS
	-2			;SKIP SWITCH STACK
	MOV	@14(SP),R1	;GET FUN. & ARG.
	MOV	CURTSK,R0	;GET ATL NODE ADDRESS
	MOV	R1,R2		;SPLIT UP FUNCTION AND ARGUMENT
	ASL	R1
	SWAB	R2
	BIC	#177400,R1
	BIC	#177400,R2
	JMP	@1$(R1)		;CALL APPROPRIATE ROUTINE
;
1$:				;DISPATCH TABLE ADDRESS
	IOTS			;(00) SET TASK IN STATE "S"
	SLAREQ			;(01) ISSUE TASK REQUEST
;
; EXIT FROM TASK IN STATE "S"
;
IOTS:	BIC	#17,A.TS(R0)	;CLEAR OUT OLD REQUEST
	BIS	R2,A.TS(R0)	;SET NEW REQUEST
	MOV	SP,A.SP(R0)	;SAVE IN ATL NODE
	MOV	SYS.SP,SP	;SWITCH TO SYSTEM STACK
	TST	R2		;WAS STATE REQUESTED 0 ? (BR-139)
	BEQ	1$		;YES BRANCH (BR-139)
	ADD	#20,A.SP(R0)	;INCREMENT STACKS (BR-139)
	JMP	@AS.E3(R2)	;PROCESS REQUEST NOW
1$:	JMP	AS.E1		;RESCHEDULE FROM TOP (BR-139)
;
; ISSUE TASK REQUEST
;
SLAREQ:	ADD	#2,14(SP)	;BUMP PC ON STACK TO RET. ADD.
	MOV	SYS.SP,SP	;SWITCH TO SYSTEM STACK
	JMP	CALLTK		;ISSUE REQUEST
;
	.SBTTL	MOVE A NODE
;
; SUBROUTINE TO MOVE A NODE FROM ONE DEQUE TO ANOTHER DEQUE.
;
; CALLING SEQUENCE:
;    NODE ADDRESS IN R0
;    INHIBIT INTERRUPTS
;    ADDRESS OF WHERE NODE WILL END UP IN R1
;    CALL MOVEN
;    ENABLE INTERRUPTS
;
;		REGS. USED: R0,R1
;
MOVEN:
	PUSH	R1		;SAVE R1 TEMP
	MOV	(R0),R1		;DELETE NODE FROM SOURCE DEQUE
	MOV	R1,@2(R0)
	MOV	2(R0),2(R1)
	POP	R1		;RESTORE R1
	PUSH	(R1)		;INSERT NODE IN DESTINATION DEQUE
	ADD	#2,(SP)
	MOV	(R1),(R0)
	MOV	R1,2(R0)
	MOV	R0,(R1)
	MOV	R0,@(SP)+
RTURN:	RETURN			;RETURN TO CALLER
;
;
	.SBTTL	RETURN ATL NODE TO POOL
;
; THIS ROUTINE RETURNS THE ATL NODE(IF PRESENT) TO THE POOL & ZEROS
; THE ATL NODE POINTER ENTRY IN "ATLNP" TABLE.
; THE TASK CODE IS SPECIFIED IN R2. ROUTINE MUST BE CALLLED
; AT LEVEL 7.
;
; CALLING SEQUENCE:
;	MOV #TASCOD,R2
;	INHIBIT INT.
;	CALL RATLN
;	....		;RETURN
;
;		REGS. USED: R0,R1
;
RATLN:
	ASL	R2		;CONVERT TASK CODE TO WORD OFFSET
	MOV	ATLNP(R2),R1	;LOOK FOR ATL NODE
	BEQ	1$		;NO ENTRY IN ATL
	CLR	ATLNP(R2)	;RESET ENTRY
	MOV	R1,R0		;NOW RETURN NODE TO POOL
	MOV	#POL.LH,R1
	CLR	4(R0)		;ZERO ENTRY BEFORE RETURNING
	CLR	6(R0)
	CALL	MOVEN
1$:	RETURN			;RETURN TO CALLER
;
	.SBTTL	DEQUEUE A NODE FROM TASK'S DEQUE
;
; ROUTINE TO TEST IF TASK HAS MORE ENTRIES IN HIS TRL.  IF
; SO, THE ENTRY IS PROCESSED IMMEDIATELY, OTHERWISE HE
; REMAINS IDLE AND EXITS ALLOWING LOWER PRIORITY TASKS TO BE RUN.
; ROUTINE MUST BE CALLED AT LEVEL 7.
;
; CALLING SEQUENCES:
;	ADDRESS OF TASK LISTHEAD IN R1
;	ADDRESS OF TASK IN R3
;	JMP DEQU		;ROUTINE ""MUST"" BE CALLED WITH
;				;    TASK'S IDLE/BUSY SWITCH 
;				;    CLEARED.
;
;		REGS. USED: R0,R1
;
DEQU:
	CMP	(R1),R1		;DOES A NODE EXIST IN THE TASK'S DEQUE? (BR-134)
	BEQ	DEQU1		;NO:  EXIT IMMEDIATELY
	MOV	(R1),R0		;GET ADDRESS OF NODE
	MOV	4(R0),-4(R3)	;SET BUSY IDLE SWITCH OF TASK
	MOV	6(R0),-2(R3)
	MOV	#POL.LH,R1	;RETURN NODE TO POOL
	CLR	4(R0)		;ZERO ENTRY BEFORE RETURNING TO POOL
	CLR	6(R0)
	CALL	MOVEN
	MOV	CURTSK,R0	;SET TASK STATUS IN ATL NODE TO RUN
	MOV	A.TS(R0),R1	;SET PRIORITY
	SWAB	R1
	MOV	R1,PS
	JMP	@R3		;EXIT TO TASK
;
; NO NODES IN TRL
;
; CALLING SEQUENCE:
;	JMP DEQU1
;
;		REGS. USED: R0
;
DEQU1:	BIS	#340,PS		;RAISE TO LVL 7
	MOV	CURTSK,R0	;SAVE TASK SP
	MOV	SP,A.SP(R0)
	BIC	#17,A.TS(R0)	;SET STATUS TO WAIT
	BIS	#WAITST,A.TS(R0)
	MOV	SYS.SP,SP	;SWITCH TO SYSTEM STACK
	JMP	AS.E1		;SCHEDULE NEXT TASK
;
	.SBTTL	SEND COMPLETION OF I/O INTERRUPT TO CALLER
;
;
; ROUTINE TO SEND COMPLETION OF I/O INTERRUPT TO THE CALLER.  CALL TO 
; THIS ROUTINE MUST BE DONE AT LEVEL 7.  IF FUNCTION CODE (BIT 0)
; IN TCB IS = 1, API INTERRUPT TO PDP-15 IS NOT ISSUED. IF EQUAL TO
; ZERO IT IS ISSUED. IF FUNCTION CODE IS = 2, A SOFTWARE INTERRUPT IS ISSUED TO THE 
; CALLER.	VIZ..	CALL @SEND11(TASK CODE*2).
; THE REV IN TCB IS ALWAYS SET TO THE VALUE IN R1 IRRESPECTIVE OF THE FUNCTION CODE 
; BEFORE ISSUING THE INTERRUPT.
;
; CALLING SEQUENCE:
;	ADDRESS OF TCB IN R0
;	EVENT VARIABLE IN R1
;	CALL SEND15
;	REGISTERS USED:  R2 THRU R5
;
SEND15:
	BIT	#400,2(R0)	;FUNCTION CODE BIT 0 = 1?
	BNE	3$		;YES:  IGNORE SENDING INTERRUPT
	MOVB	(R0),R2		;GET API TRAP LEVEL SPECIFIED BY TCB
	CMP	#3,R2		;LEVEL MUST BE 0, 1, 2, OR 3 (BR-134)
	BLT	4$		;ILLEGAL LEVEL GIVEN,  TELL USER OF
				;   ERROR. (BR-134)
5$:	MOV	#APIREG,R3	;BUILD THE CORRECT API LEVEL VECTOR
	MOV	#APIDNE,R4	;    AND "DONE" FLAG TEST VECTOR.
	MOV	#100,R5
	BIT	#2,R2		;API LEVELS 2 AND 3 TEST
	BNE	1$
	ASL	R5		;API LEVELS 0 AND 1
	BIS	#10,R3
1$:	BIT	#1,R2		;API LEVELS 1 AND 3 TEST
	BEQ	2$
	CMPB	(R3)+,(R4)+	;API LEVELS 1 AND 3 USES ODD BYTES
				;    (R3=R3+1, R4=R4+1).
2$:	BITB	(R4),R5		;WAIT FOR RECEIPT OF PREVIOUS INTERRUPT (BR-134)
	BEQ	2$		;    REQUESTS BY THE PDP15.
	PUSH	(R0)		;OK, NOW SEND INTERRUPT TO THE
	SWAB	(SP)		;    15 AT THE CORRECT API LEVEL.
	MOV	R1,TEV(R0)	;SET TASK'S EVENT VARIABLE IN
				;    CALLERS TCB.
	MOVB	(SP),(R3)
	TST	(SP)+		;POP STACK
	RETURN			;RETURN TO CALLER
3$:	MOV	R1,TEV(R0)	;SET TASK'S EVENT VARIABLE IN
	BIT	#1000,2(R0)	;RETURN @SEND11?
	BEQ	6$
	MOVB	2(R0),R1	;GET TASK CODE
	BIC	#177600,R1
	MOVB	LEVEL(R1),R2	;LOWER TO DEVICE LEVEL
	COMB	R2
	BICB	R2,PS		;SET PS
	MOVB	(R0),R1		;GET CALLER TASK CODE
	BICB	#177600,R1	;CLEAR JUNK
	ASL	R1		;CONVERT TASK CODE TO WORD OFFSET
	CALL	@SEND11(R1)	;YES.
				;    CALLERS TCB.
6$:	RETURN		;NO
;
4$:	MOV	#-300,TEV(R0)	;ILLEGAL LEVEL. TELL USER OF ERROR
	MOV	#3,R2		;RETURN AT LEVEL 3
	BR	5$
;
	.SBTTL	EMPTY A TASKS DEQUE
;
; THIS ROUTINE WILL EMPTY A TASKS DEQUE BY RETURNING ALL UNUSED
; NODES BELONGING TO THE 15 TO THE SYSTEM POOL.
;
; CALLING SEQUENCE:
;	ROUTINE MUST BE CALLED AT PROTECTED LEVEL (LVL 7)
;	ADDRESS OF TASK'S LISTHEAD IN R2
;	CALL EMPTY
;	REGISTERS USED:  R0, R1, R2 AND R3
;
EMPTY:
	PUSH	R2		;SAVE R2 TEMPORARILY
	MOV	R2,R3
2$:	CMP	(R2),R3		;ANY NODES IN THIS TASK'S DEQUE (BR-134)
	BEQ	1$		;ALL EMPTY
	MOV	(R2),R0		;RETURN THIS NODE TO THE POOL ONLY IF
	TST	4(R0)		;    IT WAS INSERTED BY A 15 REQUEST.
	BMI	3$		;NO:  SKIP PAST THIS NODE
	MOV	#POL.LH,R1
	CLR	4(R0)		;ZERO NODE ENTRY BEFORE RETURNING
	CLR	6(R0)
	CALL	MOVEN
	MOV	(SP),R2		;RESTORE R2
	CMP	2(R2),R3	;ARE WE PAST THE BOTTOM NODE OF
				;    THE DEQUE?
	BNE	2$		;NO:  TRY FOR ANOTHER NODE
1$:	POP	R2		;RESTORE R2 AND STACK
	RETURN			;RETURN
3$:	MOV	R0,R2		;LINK TO NEXT NODE
	BR	2$		;LOOK AT NEXT NODE
;
	.SBTTL	INITIALIZATION
;
; THIS ROUTINE INITIALLY STARTS THE SYSTEM GOING BY ARMING THE TCB
; REGISTER AND SCHEDULING THE NUL TASK.
;
START:
	RESET			;RESET THE HARDWARE
	MOV	APIDNE,R0	;DETERMINE LOCAL MEMORY SIZE
	BIC	#170377,R0	;    OF THE 11.
	ASL	R0
	ASL	R0
	ASL	R0
	ASL	R0
	ASL	R0
	MOV	R0,MEMSIZ
	MOV	#1000,SP	;SETUP THE SYSTEM STACK POINTER
	BIS	#340,PS		;PROTECT WHILE SETTING UP THE SYSTEM
; SETUP DEVICE CONTROL REGISTERS BASED ON EXISTING HARDWARE IN SYSTEM
	MOV	NBRTEV,R3	;GET NUMBER OF TASKS IN PIREX
	CLR	R1
NXTSK:	TST	(R1)+		;BUMP INDEX
	MOV	TEVADD(R1),R2	;GET TASK START ADDRESS
	BEQ	NXTASK		;SKIP SETUP IF TASK NOT ASSEMBLED
	CLR	@-6(R2)		;TASK PRESENT. CHECK IF HARDWARE EXISTS
NXTASK:	DEC	R3
	BNE	NXTSK		;DONE?
	MOV	#6,@#4		;YES. RESET TRAP VECTOR
	MOV	#CLTABL,R0	;GET ADR. OF CLOCK TABLE (BR-146)
1$:	CLR	(R0)+		;CLEAR CLOCK TABLE ENTRY (BR-146)
	CMP	#CLEND,R0	;ARE WE DONE ? (BR-146)
	BNE	1$		;REPEAT IF NOT DONE (BR-146)
	MOV	#LASTLC,LCLAST	;SET UP INITIAL NEXT FREE LOC. (BR-147)
	MOV	#LASTLC,TK.END	;DO SAME FOR TK.END TABLE (BR-147)
	MOV	#TK.END+2,R0	;START TO CLEAR TK.END TABLE AFTER (BR-147)
				;FIRST ENTRY (BR-147)
2$:	CLR	(R0)+		;CLEAR TK.END ENTRY (BR-147)
	CMP	#T.END,R0	;DONE ? (BR-147)
	BNE	2$		;BRANCH IF NOT DONE (BR-147)
	MOV	#LASTLC,R0	;DUMMY ATL NODE ADDRESS FOR STARTUP
	MOV	R0,CURTSK	;ESTABLISH IT AS THE CURRENT TASK
	BIS	#100,TCBINT	;ARM THE TCB INTERRUPT FROM THE 15
;
; START CLOCK
;
	MOV	#100,CLSTS
	TST	SPLNP		;IS SPOOLER CONNECTED ? (BR-146)
	BEQ	3$		;BRANCH IF NO SPOOLER (BR-146)
	CALL	SPKILL		;SPOOLER CONNECTED - KILL IT (BR-146)
3$:	MOV	#ST.TCB,R5	;STOP ALL I/O REQUESTS AND CLEAR (BR-146)
	CLR	R4		;OUT ALL DEQUES AND QUEUES (BR-146)
	JMP	CALLTK		;NOW START UP THE NUL JOB
;
NODEV:	CLR	TEVADD(R1)	;CLEAR TASK FROM TABLE
	BR	NXTASK		;TEST IF DONE
;
; ST TASK CONTROL BLOCK TO STOP ALL TASKS AND I/O CURRENTLY UNDERWAY.
;
ST.TCB:	.WORD	0,200,0
;
	.SBTTL	LINE CLOCK INTERRUPT SERVICE
;
;   A CLOCK TICK INTERRUPT HANDLER
;
CLSTS=177546
;
	.BLOCK	8.+EAESTK*3	;CLOCK STACK
;
CLINT:	JSR	R0,R.SAVE	;SAVE REGISTERS INCASE WE CALL ANYONE
	-1			;CLOCK TASK CODE
	CLR	CLSTS		;DISABLE CLOCK INT
	CLR	CLTMP		;USE AS 'DID ANYONE TIME-OUT' FLAG
	MOV	#CLTABL-4,R0	;SET UP POINTER TO TABLE
1$:	ADD	#4,R0		;BUMP TO NEXT ENTRY (BR-134)
	CMP	R0,#CLEND	;DONE YET
	BEQ	4$		;YES IF EQUAL
	TST	(R0)		;TIME ENTRY OF THIS PAIR 0??
	BEQ	1$		;IF ZERO, THIS PAIR DISABLED, CHECK NEXT
	DEC	(R0)		;NOT ZERO, DO COUNTDOWN
;
;  WARNING, IF BETWEEN TST AND DEC, SOMEONE AT LEVEL SEVEN ZEROED
;  A PREVIOUSLY NON-ZERO ENTRY, WE WILL LOSE, SETTING IN MOTITION
;  A 2^16 TICK TIME REQUEST.
;
	BNE	1$		;UNLESS !BECAME! 0, ALL WE DO NOW
	MOV	R0,CLTMP	;SAVE REG #0, OUR POINTER
	JSR	PC,@2(R0)	;CALL INTERRUPT LEVEL SERVICE ROUTINE
	MOV	CLTMP,R0	;RESTORE REG #0
;
;  CALLED ROUTINE CAN ASSUME REGISTERS HAVE BEEN SAVED, AND
;  R0 POINTS TO TIME COUNTER FOR HIS SLOT IN CLOCK TABLE!!
;  RETURN BY DOING A RTS PC. NOTE YOU ARE CALLED AT LEVEL 6. DO
;
	BR	1$		;GO CHECK NEXT ENTRY
;
4$:	MOV	#100,CLSTS	;ENABLE CLOCK INT
	JMP	DEQU1		;SCHEDULE NEXT TASK
;
CLTMP:	0
;
;
	.SBTTL	STOP ONE OR ALL TASKS
	.EVEN
;
; THIS TASK IS USED TO STOP TASKS AND/OR I/O CURRENTLY UNDERWAY FOR
; ALL TASKS OR FOR A PARTICULAR TASK.  IT DOES SO BY RESETTING THE SYSTEM OR DEVICE
; CONTROLLERS(IF NECESSARY), CLEARING TASK DEQUES, AND ZEROING TASKS
; REGISTERS.
;
	.BLOCK	8.+EAESTK*3
	.WORD	DUMMY		;DUMMY REGISTER
	.WORD	0		;TCB POINTER (EXTENDED 2 BITS)
	.WORD	0		;	      (LOWER 16 BITS)
				;    THIS WORD IS USED AS THE IDLE/BUSY
				;    SWITCH FOR THE TASK.
;
ST:
;
	MOV	ST-2,R0
	MOVB	3(R0),R2	;STOP ALL TASKS?
	BIC	#177600,R2	;TEMPORARILY REMOVE SIGN BIT
	BNE	2$		;NO:  JUST CLEAR THE SPECIFIED TASK
	INC	CTLCNT		;INC CTL C RUNNING COUNTER (BR-116)
	MOV	#2,R5		;ZERO ALL IDLE/BUSY REGISTERS (TCBP'S)
	CLR	-(SP)
1$:	INC	(SP)		;DO NEXT TASK
	MOV	TEVADD(R5),R4	;RETURN ALL NODES
	BEQ	11$		;    IN THE TASKS DEQUES THAT
	TSTB	3(R0)		;    BELONG TO THE 15 ONLY.
	BMI	7$
	TST	-4(R4)		;(NOTE:  PREVIOUS TSTB WAS USED TO
	BMI	3$		;    CLEAR ALL REQUESTS INCLUDING 11'S)
7$:	CLR	-4(R4)		;RESET TASK BUSY/IDLE SWITCH
	CLR	-2(R4)
	CLR	@-6(R4)		;SHUT DOWN DEVICE
	MOV	(SP),R2
	MOV	R2,R3		;GET WORD OFFSET IN R3
	ASL	R3
	MOV	ATLNP(R3),R1	;GET ATL NODE ADDRESS IF PRESENT
				; &   SET HIS STATUS TO "STOP"
	BEQ	11$		;NO ATL NODE WAS FOUND
	BIC	#17,A.TS(R1)	;SET TASK STATUS TO "STOP"
	MOV	#EXITST,R3		;    OR "WAIT" DEPENDING ON
	CMPB	#NTEV,R2	;    WHETHER THEY ARE PERMANENT (BR-134)
	BLE	9$		;    ONES OR NOT. (BR-134)
	ASR	R3
9$:	BIS	R3,A.TS(R1)
3$:	MOV	R5,R2
	ASL	R2
	ADD	#LISTHD,R2
	PUSH	R0		;SAVE R0 TEMP
	CALL	EMPTY		;(EMPTY TASKS DEQUE)
	POP	R0		;RESTORE R0
11$:	BIC	#100,PS		;OPEN WINDOW FOR CD LVL 6 INTERRUPT
;				;ONCE EACH ITERATION AT THIS 'SAFE' PLACE
	TST	(R5)+		;DO NEXT TASK
	PUSH	NBRTEV
	ASL	(SP)
	BIS	#100,PS		;CLOSE WINDOW , RETURN TO 7
	CMP	(SP)+,R5	;ALL DONE ? (BR-134)
	BGE	1$		;NO:  CONTINUE (BR-134)
	TST	(SP)+		;CLEAN UP STACK
	BR	13$		;TELL 15 THAT REQUEST IS COMPLETE
;
2$:	MOV	R2,R5		;SAVE TASK CODE
	ASL	R2		;GET ADDRESS OF TASK IN
	MOV	TEVADD(R2),R4	;    REFERENCE.
	BEQ	12$
	TSTB	3(R0)		;IF NEG., REMOVE ALL ENTRIES
	BMI	8$
	TST	-4(R4)		;IGNORE TCBP IN TASKS BUSY SWITCH
	BMI	4$		;    IF IT WASN'T A FROM A 15 REQUEST.
8$:	CLR	-4(R4)		;ZERO THE IDLE/BUSY REGISTER FOR THIS
	CLR	-2(R4)		;    TASK ONLY IF IT'S A REQUEST THAT
				;    CAME FROM THE PDP15.
	CLR	@-6(R4)		;NOW DISABLE THE TASK
	MOV	ATLNP(R2),R1	;IF ATL NODE PRESENT SET STATUS TO STOP
	BEQ	4$		;NO ATL NODE EXISTS FOR THIS TASK
	BIC	#17,A.TS(R1)	;SET TASK STATUS TO "STOP"
	MOV	#EXITST,R3		;    OR "WAIT" DEPENDING ON
	CMPB	#NTEV,R5	;    WHETHER THEY ARE PERMANENT (BR-134)
	BLE	10$		;    ONES OR NOT. (BR-134)
	ASR	R3
10$:	BIS	R3,A.TS(R1)
4$:	ASL	R2		;EMPTY TASKS DEQUE
	ADD	#LISTHD,R2
	CALL	EMPTY
13$:	MOV	#1,R1		;TELL CALLER ALL OK
5$:	BIS	#340,PS		;INHIBIT INTERRUPTS
	MOV	ST-2,R0		;RESTORE R0 (TCBP)
	CLR	ST-2		;CLEAR OUT THIS TCBP (I.E. "ST" DRIVER")
	CLR	ST-4
	MOV	R1,TEV(R0)	;TELL 15 THAT REQUEST IS COMPLETE
	MOV	#ST.LH,R1	;TEST FOR ANY PENDING REQUESTS (BR-145)
	CMP	(R1),R1		;ANY PENDING ? (BR-145)
	BNE	14$		;BRANCH IF ANY PENDING REQ. (BR-145)
	SEXIT	EXITST		;RETURN ATL NODE TO POOL AND
				;    EXIT BACK TO THE ATL SCANNER.
12$:	MOV	#-600,R1	;TELL CALLER ATL NODE MISSING
	BR	5$
14$:	MOV	#ST,R3		;SET UP RETURN TO ST: FOR DEQU (BR-145)
	JMP	DEQU		;EXIT - WITH RETURN IF ANY MORE REQUESTS (BR-145)
;
	.SBTTL	SOFTWARE DIRECTIVE PROCESSING
	.EVEN
;
; THIS TASK CARRIES OUT FUNCTIONS CALLED "DIRECTIVES".
; THE FOLLOWING DIRECTIVES ARE CURRENTLY SUPPORTED.
;
;	FUNCTION CODE			DIRECTIVE
;
;		00		DISCONNECT TASK FROM PIREX & REMOVE ATL
;		01		CONNECT TASK TO PIREX & RUN TASK
;		02		REPORT CORE STATUS IN LOCAL MEMORY TO CALLER
;		03		REPORT ERROR STATUS OF TASKS
;
	.BLOCK	8.+EAESTK*4
	.WORD	DUMMY		;DUMMY CONTROL REG SINCE SOFTWARE
				;    ROUTINES DO NOT NEED HARDWARE
				;    SHUT DOWNS.
	.WORD	0		;TCB POINTER (EXTENDED BITS)
	.WORD	0		;TCB POINTER (LOWER 16 BITS). THIS
				;    WORD IS USED AS THE IDLE/BUSY
				;    SWITCH FOR THE SD TASK.
SD:
	MOV	SD-2,R0		;TCBP
	MOVB	7(R0),R1	;GET FUNCTION CODE FROM TCB
	CMP	NBRFCT,R1	;FUNCTION OUT OF RANGE? (BR-134)
	BGT	1$		;NO (BR-134)
	MOV	#-400,R1	;RETURN ILLEGAL FUNCTION CODE IN TCB
	CALL	SEND15
	SEXIT	EXITST		;EXIT AND RETURN ATL NODE TO POOL
;
1$:	MOVB	6(R0),R2	;GET TASK CODE
	ASL	R1
	JMP	@DIRDSP(R1)	;DISPATCH TO APPROPRIATE ROUTINE
;
; DIRECTIVE DISPATCH TABLE
;
DIRDSP:	DISCON			;DISCONNECT DIRECTIVE
	CONNEC			;CONNECT DIRECTIVE
	COREPT			;CORE STATUS REPORT DIRECTIVE
	ERREPT			;ERROR REPORT DIRECTIVE;
	SPLSTS			;SPOOLER STATUS (BR-120)
	MOVEIT			;MOVE INFO DIRECTIVE (BR-120)
NBRFCT:	.-DIRDSP/2
;
; CONNECT DIRECTIVE
;
CONNEC:
	CMP	NBRTEV,R2	;USE NEW TASK CODE # FOR UPPER (BR-134)
	BGE	1$		;    LIMIT IF ITS LARGER. (BR-134)
	MOV	R2,NBRTEV
1$:	MOV	R2,R4		;SAVE IN R4
	ASL	R2		;CONVERT TASK CODE TO WORD OFFSET
	MOV	14(R0),R1	;GET START ADDRESS
	TST	10(R0)		;11'S REQUEST?
	BMI	2$
	ASL	R1		;CONVERT TO BYTE ADDRESS
	ADD	MEMSIZ,R1	;ADD 11'S LOCAL MEMSIZE
	BR	3$
2$:	ADD	16(R0),LCLAST	;UPDATE LAST LOCATION (BR-147)
	MOV	LCLAST,TK.END(R2) ;SET 'NEXT-FREE-LOC.' IN TK.END TABLE (BR-147)
3$:	MOV	R1,TEVADD(R2)	;SET TASK FA IN SYSTEM TABLE
	MOV	#LISTHD,R3	;NOW INITIALIZE THE LISTHEAD
	ADD	R2,R3
	ADD	R2,R3
	MOV	R3,(R3)		;FORWARD POINTER
	MOV	R3,2(R3)	;BACKWARD POINTER
	MOVB	20(R0),LEVEL(R4);ESTABLISH TASK RUN PRIORITY
	MOV	TEVADD(R2),R2	;NOW UNBUSY THE TASK
	CLR	-4(R2)
	CLR	-2(R2)
	MOV	#1,R1		;TELL CALLER  ALL OK
CONN3:	MOV	SD-2,R0		;SET UP R0 WITH TCBP (BR-145)
	CALL	SEND15		;TELL CALLER THAT HIS REQUEST HAS BEEN (BR-145)
				;COMPLETED (BR-145)
	BIC	#100,PS		;ALLOW PENDING PRIORITY 6,7 INTER. (BR-145)
	NOP			;GIVING A TWO INSTRUCTION WINDOW (BR-145)
	BIS	#100,PS		;THEN LOCK-OUT INTS. AGAIN (BR-145)
	CLR	SD-2		;ALLOW NEXT TCB (BR-145)
	CLR	SD-4		;DITTO (BR-145)
	MOV	#SD,R3		;SETUP RETURN FROM DEQU IF ANY PENDING TCB'S (BR-145)
	MOV	#SD.LH,R1	;TELL DEQU WHERE TRL IS (BR-145)
	JMP	DEQU		;GET ANY PENDING TCB'S (BR-145)
;
; DISCONNECT DIRECTIVE
;
DISCON:	CMPB	NBRTEV,R2	;TEMPORARY TASK? (BR-134)
	BNE	1$
	DEC	NBRTEV		;YES. UPDATE HIGHEST TASK CODE #
1$:	BIS	#340,PS		;RAISE TO LVL 7
	MOV	R2,R3		;SAVE TASK CODE
	ASL	R3		;CONVERT TASK CODE TO WORD OFFSET
	MOV	ATLNP(R3),R1	;GET ATL NODE ADDRESS
	BEQ	4$		;REPORT IF ATL NODE MISSING
	CALL	RATLN		;RETURN ATL NODE
	CLR	TEVADD(R3)	;DISCONNECT TASK
	MOV	R3,R4		;SAVE TASK-CODE*2 (BR-147)
	ASL	R3		;SETUP FOR EMPTY
	MOV	R3,R2
	ADD	#LISTHD,R2	;SETUP FOR EMPTY
	CALL	EMPTY		;CLEAR DEQUE
	MOV	SD-2,R0		;SAVE TCBP
	TST	10(R0)		;11'S REQUEST?
	BPL	2$
	CLR	TK.END(R4)	;CLEAR THIS TASK'S MEMORY REQUIREMENT (BR-147)
	CLR	R4		;SET MAX 'NEXT-FREE-LOC.' TO ZERO (BR-147)
	MOV	#TK.END,R1	;POINT TO FIRST ENTRY IN TK.END TABLE (BR-147)
5$:	CMP	(R1)+,R4	;DOES R4 CONTAIN THE HIGHEST LOC. (BR-147)
	BLE	6$		;BRANCH IF SO (BR-147)
	MOV	-2(R1),R4	;NO - UPDATE R4 (BR-147)
6$:	CMP	#T.END,R1	;ARE WE DONE? (BR-147)
	BNE	5$		;NO - TRY NEXT ENTRY (BR-147)
	TST	R4		;YES - DOES R4 CONTAIL VALID LOC. (BR-147)
				;IF VALUE IS 0 - LOC. IS NOT VALID (BR-147)
	BEQ	7$		;NO - FATAL ERROR -TELL USER (BR-147)
	MOV	LCLAST,R1	;SAVE OLD 'NEXT-FREE-LOC.' (BR-147)
	MOV	R4,LCLAST	;UPDATE 'NEXT-FREE-LOC.' WITH R4 (BR-147)
	CMP	R1,R4		;DID WE DELETE A HOLE IN MIDDLE? (BR-147)
				;NOTE: THIS IS BEING DONE TO MAINTAIN
				;COMPATABILITY WITH OLDER PIREX SYSTEMS.
				;A HOLE IN MIDDLE WILL NOW BE RECOVERED WHEN
				;HIGER (IN MEMORY) TASKS ARE DISCONNECTED.
	BEQ	3$		;BRANCH IF HOLE IN MIDDLE (BR-147)
2$:	MOV	#1,R1		;TELL	CALLER ALL OK
	BR	CONN3		;UNBUSY SD TASK & EXIT
3$:	MOV	#2,R1		;NO. TELL	CALLER THAT HOLE IS CREATED
	BR	CONN3
4$:	MOV	#-600,R1	;TELL CALLER ATL NODE MISSING
	BR	CONN3
7$:	MOV	#-601,R1	;TELL CALLER - SERIOUS MEMORY PROBLEM (BR-147)
	MOV	#601,SD.EST+4	;TELL USER VIA POLLER OF PROBLEM
				;THIS IS DONE SO THAT USER PROGRAM NEED
				;NOT DETECT THIS ERROR . COMPATABILITY
				;WITH PREVIOUS (PRE VER 148) PIREX SYSTEMS IS
				;MAINTAINED. ALSO THIS ERROR IS SO SERIOUS
				;THAT THE OPERATOR SHOULD ALWAYS BE TOLD.
				;NOTE THAT LCLAST IS NOT RESET WHEN THIS
				;ERROR IS DETECTED,BUT REMAINS SET AT IT'S OLD 
				;VALUE ,THIS PRESERVES OCCUPIED MEMORY. (BR-148)
	JMP	CONN3		;AND EXIT (BR-147)
;
;
; TASK ERROR STATUS REPORT DIRECTIVE
;
ERREPT:	BIC	#100,PS		;##127##KICK DOWN TO LVL 5 FOR CD
	MOV	R0,R1		;POINT R1 TO MESAG WORD
	ADD	#10,R1
	MOV	#NTEV+2*3,R2	;SET # OF ENTRYS
	MOV	#DEVST,R3
1$:	MOV	(R3)+,(R1)+	;COPY TABLE
	DEC	R2
	BNE	1$
	BIC	#100,PS		;##127## AGAIN IN CASE RECHEDULED
	MOV	#NTEV+2,R2	;RESET TABLE ENTRIES
	MOV	#DEVST,R3
2$:	ADD	#4,R3		;BUMP TO ERROR WORD (BR-134)
	CLR	(R3)+
	DEC	R2
	BNE	2$
	BIS	#340,PS		;##127##AND BACK TO 7 FOR REMAINDER
	MOV	#1,R1
	JMP	CONN3		;AND EXIT (BR-147)
;
;
;CORE REPORT STATUS DIRECTIVE
;
COREPT:	MOV	MEMSIZ,R2	;GET SIZE OF LOCAL MEMORY
	SUB	MEMSIZ+4,R2	;DEDUCT LAST LOCATION
	ASR	R2		;CONVERT TO WORD
	BPL	1$
	MOV	#-500,R1	;NO FREE	CORE!!
	JMP	CONN3		;AND EXIT (BR-147)
1$:	MOV	R2,16(R0)	;SET FREE CORE SIZE IN TCB
	MOV	MEMSIZ+4,12(R0)	;SET LAST LOCATION IN TCB
	MOV	MEMSIZ,10(R0)	;SET LOCAL MEMORY SIZE (BR-120)
	MOVB	NBRTEV,6(R0)	;SET CURRENT HIGHEST TASK CODE # IN TCB
	MOV	6(R0),6(R0)	;THIS CLEARS THE PARITY BITS IN COMMON MEMORY
				;AFTER THE ABOVE XVM BYTE OPERATION (BR-143)
	MOV	#1,R1		;TELL CALLER ALL OK
	JMP	CONN3		;AND EXIT (BR-147)
;
;
;	SPOOLER STATUS DIR.
;
;
SPLSTS:	MOV	SPOLSW,10(R0)	;SET UP SPOOL STATUS
	MOV	DEVARE,12(R0)
	MOV	DEVSPL,14(R0)
	MOV	SPUNIT,16(R0)	;MOVE SPOOLER DISK UNIT NR. (BR-122)
	MOV	#1,R1		;RETURN STATUS OK
	JMP	CONN3		;AND RETURN TO CALLER
;
;
;	PIREX MOVE DIRECTIVE
;
;
MOVEIT:	MOV	10(R0),R1	;GET  FROM  LOCATION (BR-125)
	MOV	12(R0),R2	;GET  TO  LOCATION (BR-125)
	MOV	14(R0),R3	;GET NUMBER OF WORDS TO MOVE (BR-125)
	CMP	R1,R2		;WHICH IS GREATER ? (BR-120)
	BLO	1$		;BRANCH IF FROM LESS THAN TO (BR-120)
4$:	MOV	(R1)+,(R2)+	;MOVE DATA BOTTOM UP (BR-120)
	DEC	R3		;KEEP COUNT OF HOW MANY MOVES (BR-120)
	BNE	4$		;DONE YET? (BR-120)
	BR	2$		;YES (BR-120)
1$:	INC	R1		;SET UP FOR -(RX) CONSTRUCT (BR-120)
	INC	R1		;DITTO (BR-120)
	INC	R2		;DITTO (BR-120)
	INC	R2		;DITTO (BR-120)
5$:	MOV	-(R1),-(R1)	;MOVE DATA FORM TOP DOWN (BR-120)
	DEC	R3		;KEEP COUNT OF HOW MANY MOVES (BR-120)
	BNE	5$		;DONE YET? (BR-120)
2$:	MOV	#1,R1		;YES - SAY SO (BR-120)
	JMP	CONN3		;AND RETURN TO CALLER (BR-120)
;
;
	.NLIST
	.IFDF	$RK
	.LIST
	.SBTTL	DISK DRIVER FOR RK11/15
	.EVEN
;
RKDS=177400
RKER=177402
RKCS=177404
RKWC=177406
RKBA=177410
RKDA=177412
RKWC15=14
RKUNFC=16
RKCS15=20
RKER15=22
RKDS15=24
;
; CALL TO ROUTINE HAS ADDRESS OF TCB IN HANDLER BUSY (IDLE) REGISTER
;
	.BLOCK	8.+EAESTK*4
	.WORD	RKCS		;ADDRESS OF RKCS CONTROL STATUS REGISTER
				;    USED TO RESET DEVICE ON STOP I/O
				;    REQUESTS.
	.WORD	0		;TCB POINTER (EXTEND BITS)
	.WORD	0		;TCB POINTER (LOWER 16 BITS)  THIS
				;    WORD IS USED AS THE IDLE SWITCH
				;    FOR THE DEVICE DRIVER.
DK:
	MOV	#400,DKREPT	;CLEAR RETRY INDICATOR
DKRTRY:
	CLR	DK.CL		;STOP TIMED WAKEUP (BR-142)
	MOV	DK-2,R0		;SETUP R0 TO POINT TO TCB
	MOV	RKUNFC(R0),R1	;GET UNIT IN R1(13-15)
	SWAB	R1
	BIC	#177770,R1
	ASR	R1		;LEFT-JUSTIFY UNIT
	ROR	R1
	ROR	R1
	ROR	R1		;UNIT NOW AS DESIRED
	ADD	#6,R0		;POINTER TCB+BLOCK
	MOV	(R0)+,R2
	TST	R2		;IS BLOCK WITHIN BOUNDS (BR-134)
	BMI	5$		;NEGATIVE BLOCK NUMBERS ILLEGAL
	CMP	#4872.,R2	;TEST UPPER BOUND (BR-134)
	BHI	2$		;YES BRANCH (BR-134)
				;    ROUTINE TO PROCESS ERROR.
5$:	MOV	DK-2,R0		;SETUP TCB TO REFLECT ERROR
	BEQ	DKXT		;IGNORE IF ITS ALREADY BEEN STOPPED BY
				;A STOP I/O REQUEST.
	MOV	#RKDS,R5		;POINTER TO RK REGISTER SET (BR-151)
	MOV	(R5)+,RKDS15(R0)	;MOVE RKDS INTO TCB (BR-151)
	MOV	(R5)+,RKER15(R0)	;MOVE RKER INTO TCB (BR-151)
	BIS	#140,RKER15(R0)		;SET ILLEGAL BLOCK ERROR (BR-151)
	MOV	(R5),RKCS15(R0)		;MOVE RKCS INTO TCB (BR-151)
	BIS	#100000,RKCS15(R0)	;SET GLOBAL ERROR (BR-151)
	BR	DKXIT		;EXIT NOW
				;CALCULATE CYLINDER ADDRESS
3$:	ADD	#40,R1		;+1 TO CYLINDER ADDRESS
2$:	SUB	#24.,R2
	BGE	3$
	ADD	#24.,R2		;RESET OVERFLOW
	CMP	#12.,R2		;IF >=12. CAUSE A SURFACE INCREM. (BR-134)
	BGT	4$
	ADD	#4,R2
4$:	ADD	R2,R1
	MOV	#RKDA,R4
7$:	TSTB	-6(R4)		;CONTROL READY?
	BPL	7$
	MOV	R1,@R4		;YES. SET UP DISK ADDRESS
	MOV	(R0)+,R2	;SETUP MEMORY ADDRESS (M.S.)
	MOV	(R0)+,R3	;SETUP MEMORY ADDRESS (L.S.)
	BIC	#77774,R2	;CLEAR JUNK AND DO NOT RELOC ADR WHEN PDP11 (BR-136)
	BMI	6$		;BRANCH IF PDP11 REQ (BR-136)
1$:	ASL	R3		;RELOCATE ADDRESS (WORD TO BYTE)
	ROL	R2
	ADD	MEMSIZ,R3	;(+ 11'S OWN LOCAL MEMORY)
	ADC	R2
6$:	ASL	R2	;SHIFT TO POSITION IN CONTROL WORD (BR-136)
	ASL	R2
	ASL	R2
	ASL	R2
	MOV	R3,-(R4)	;MEMORY ADDRESS (L.S.)
	MOV	(R0)+,-(R4)	;SET UP WORD COUNT
	BIT	#4,-6(R0)	;TEST FOR EXTRA 64K TRANSFER (BR-136)
	BEQ	10$		;NOT NEEDED - BRANCH (BR-136)
	CLR	(R4)		;NEEDED - CAUSE INITIAL 64K TRANSFER (BR-136)
10$:	MOV	(R0)+,R1	;PUT IN THE FUNCTION (BR-136)
	BIS	#101,R1		;SET I.D.E. , GO (BR-120)
	BIC	#177460,R1	;CLEAR GARBAGE (BR-126)
	BIS	R2,R1		;ADD IN EXTENDED MEMORY BITS
	MOV	R1,-(R4)	;NO. SEND FUNCTION TO CONTROL
	SEXIT	WAITST		;ENTER A WAIT STATE AND RESCAN 
				;    THE ATL NOW.
;
;	INTERRUPT PROCESSOR
;
DKINT:
	JSR	R0,R.SAVE	;SAVE REGISTERS
	2			;TASK CODE
	MOV	DK-2,R0		;GET THE TCBP
	BEQ	DKXT		;IGNORE IF ITS ALREADY BEEN STOPPED BY
				;    A STOP I/O REQUEST.
	MOV	#RKDS,R5
	MOV	(R5)+,R1	;SAVE THE RKDS, RKER, AND RKCS IN TCB
	MOV	R1,RKDS15(R0)
	MOV	(R5)+,R2
	MOV	R2,RKER15(R0)
	MOV	@R5,R4
	MOV	R4,RKCS15(R0)
	BMI	DKERP		;BRANCH ON ERROR
	BIT	#10,R4		;WAS LAST FUNCTION A DRIVE RESET?
	BNE	DKER00		;YES:  BRANCH
DKXIT:
	MOV	DK-2,R0		;POINT TO TCB START (BR-136)
	BIT	#4,10(R0)	;WAS 64KW TRANSFER JUST DONE ? (BR-136)
	BEQ	1$		;NO - BRANCH TO NORMAL EXIT (BR-136)
	ADD	#400,6(R0)	;INCREMENT THE STARTING DISK ADR. (BR-136)
	BIC	#4,10(R0)	;CLEAR EXTRA 64K FLAG AND TEST FOR PDP11 REQUEST (BR-136)
	BPL	2$		;NO - BRANCH (BR-136)
	ADD	#2,10(R0)	;YES - ADD 128KB TO STARTING MEM ADR (BR-136)
	BIC	#4,10(R0)	;CLEAR POSSIBLE OVERFLOW (BR-136)
	JMP	DK		;DO SECOND TCB [WC-64KW] (BR-136)
2$:	INC	10(R0)		;ADD 64KW TO STARTING MEM ADR (BR-136)
	BIC	#4,10(R0)	;CLEAR POSSIBLE OVERFLOW (BR-136)
	JMP	DK		;DO SECOND TCB [WC-64KW] (BR-136)
1$:	BIS	#340,PS		;INHIBIT INTERRUPTS (BR-136)
	MOV	#1,R1		;SEND AN API INTERRUPT TO THE 15 NOW
	CALL	SEND15		;    TELLING HIM THAT HIS REQUEST HAS
				;     BEEN PROCESSED.
DKXT:
	BIS	#340,PS		;INHIBIT INTERRUPTS
	CLR	DK-2		;CLEAR BUSY (IDLE) FLAG
	CLR	DK-4
	MOV	#DK.LH,R1	;POINT TO RK TRL (BR-145)
	CMP	(R1),R1		;ARE THERE ANY REQUESTS PENDING (BR-145)
	BNE	DKXT1		;YES - GO GET THEM (BR-145)
	TST	SPOLSW		;ARE WE SPOOLING (BR-142)
	BPL	DKXT1		;NO - DO NOTHING (BR-142)
	MOV	#RKCHK,DK.CL+2	;MOVE TIMER WAKEUP ADR. TO CLK TABLE (BR-142)
	MOV	#170,DK.CL	;ASK FOR WAKEUP IN 2 SECONDS TO TEST (BR-142)
				;IF DISK IS ENABLED (BR-142)
DKXT1:	MOV	#DK,R3		;DEQUEUE ANOTHER REQUEST IF ANY EXISTS
	JMP	DEQU
RKCHK:	TST	DK-2		;IS DISK ACTIVE (BR-142)
	BNE	3$		;BRANCH IF ACTIVE - DISABLE CLOCK WAKEUP (BR-142)
	TST	SPOLSW		;IS THE SPOOLER STILL ACTIVE (BR-142)
	BPL	3$		;BRANCH IF NOT ACTIVE - STOP WAKEUPS (BR-142)
	TSTB	RKCS		;TEST TO SEE IF CONTROLER IS BUSY (BR-142)
	BPL	2$		;BRANCH IF BUSY - RETRY LATER (BR-142)
	MOV	SPUNIT,R2	;GET UNIT # OF RK BEING SPOOLED TO (BR-142)
	ROR	R2		;SHIFT INTO POSITION FOR LOAD INTO RKDA (BR-142)
	ROR	R2		;"" (BR-142)
	ROR	R2		;"" (BR-142)
	ROR	R2		;"" (BR-142)
	MOV	R2,RKDA		;SELECT UNIT "SPUNIT" (BR-142)
	TSTB	RKDS		;IS SPUNIT ENABLED (BR-142)
	BPL	1$		;BRANCH IF NOT ENABLED (BR-142)
2$:	MOV	#170,(R0)	;ASK FOR ANOTHER WAKEUP (BR-142)
3$:	RTS	PC		;RETURN TO CLOCK ROUTINE (BR-142)
1$:	MOVB	#26,SP.EST+4	;TELL USER SPOOLER DISCONNECTED (BR-143)
	CALL	SPKILL		;DISCONNECT AND ABORT SPOOLER (BR-145)
	RTS	PC		;RETURN TO CLOCK ROUTINE (BR-145)
	.NLIST
	.ENDC
	.LIST
	.SBTTL	SPOOLER ABORT ROUTINE
	.EVEN
SPKILL:				;SPOOLER ABORT ROUTINE (BR-145)
	MOV	SPUNIT,SP.EST+2	;TELL USER WHICH UNIT WAS SPOOLING (BR-143)
	IREQ	#KILLSP		;DISCONNECT SPOOLER (BR-142)
	RTS	PC		;RETURN TO CALLER (BR-145)
KILLSP:	.WORD	0		;TCB TO TELL SPOOLER TO GO AWAY (BR-142)
				;NO RETURN VIA SEND11 WANTED (BR-142)
	.WORD	607		;SPOOLER STOP CODE (BR-142)
	.WORD	0		;(BR-142)
	.WORD	4		;(BR-142)
;
	.NLIST
	.IFDF	$RK
	.LIST
	.SBTTL	DISK ERROR PROCESSOR
	.EVEN
;
;	ERROR PROCESSOR
;
DKERP:
	ASL	R4		;HARD ERROR?
	BMI	DKHER		;YES:  BRANCH
DKER00:
	ROL	(PC)+		;TRIED 8 TIMES?
DKREPT:	.WORD	0
	BCC	DKER25		;IF NOT, TRY AGAIN
	BR	DKXIT		;EXIT AND SHOW ERROR TO THE 15
;
;	HARD ERROR
;
DKHER:	MOV	#1,@R5		;CLEAR THE CONTROL
DKHR00:	TSTB	@R5		;DONE YET?
	BPL	DKHR00		;NO - LOOP
	BIT	#1000,R1	;IS IT SEEK INCOMPLETE?
	BEQ	DKHR05		;NO - BRANCH
	MOV	R1,6(R5)	;REPLACE DRIVE #
	MOV	#115,@R5	;SET UP FOR DRIVE RESET
	BR	DKXIT		;TAKE INTERIM EXIT
DKHR05:	BIT	#11400,R2	;CAN WE POSSIBLY GO ON?
	BNE	DKER00		;YES - BRANCH
	BR	DKXIT		;NO:  SHOW ERROR TO THE 15
;
DKER25:	BIS	#340,PS		;INHIBIT INTERRUPTS
	MOV	#4,R3		;SEE IF THERE'S AN ATL NODE 
	MOV	ATLNP(R3),R1
	BEQ	DKXT		;NO ATL NODE, FORGET RE-TRYING THEN
	MOV	#DK,R2		;SETUP FOR CEXIT
	MOV	#DKRTRY,-12(R2)
	ASR	R3		;GET RK TASK CODE
	MOVB	LEVEL(R3),-10(R2)
;
	.NLIST
	.ENDC
;
	.LIST
; CALLING SEQUENCE:	ATL NODE ADDRESS IN R1
;			TASK START ADDRESS IN R2
;			JMP CEXIT
;
;			REGS.USED: R2
CEXIT:
	BIS	#340,PS		; INHIBIT INT.
	BIC	#17,A.TS(R1)	;DECLARE TASK RUNNABLE
	ADD	#-26,R2
	MOV	R2,A.SP(R1)	;SET SP
	MOV	SYS.SP,SP	;SWITCH TO SYSTEM STACK
	JMP	AS.E1		;SCHEDULE NEXT TASK
;
	.NLIST
	.IFDF	$LP
	.LIST
	.SBTTL	LINE PRINTER DRIVER FOR LP11/15
	.EVEN
;
LPCSR=177514
LPBUF=177516
LPSA=6
LPIOT=12
LPSTAT=14
LPEST=LP.EST+4	;ADDR IN PIREX ERROR TABLE FOR NOT READY
LPUNN=LP.EST+2	;ADDR FOR UNIT # (FOR NOW 0)
LPTCOD=4	;LINE PRINTER TASK CODE
LPEOF=6414		;EOF CODE(DATA) FOR SPOOLING
;
;
;
;
;  MAKE THE PDP-15 DO ALL THE WORK. THE PDP-11 SIMPLY GET S A COUNT
;  OF CHARACTERS TO PRINT OUT. WE TREAT THE CONTROL CHARACTERS
;  12,15, AND 14 ONLY. A MINUS CHARACTER IS CONVERTED INTO MINUS
;  THAT NUMBER OF SPACES. NOTE ALL REAL ASCII CHAR'S HAVE A ZERO LEADING BIT!
;  EACH LINE HAS AN IMPLIED CARRIAGE RETURN THAT IS ADDED BY THE DRIVER
;  RATHER THAN SENT BY THE PDP-15
;
;  NOTE, IF HEADER WORD OF BUFFER HAS 400 BIT SET, IT IS
;  IMAGE MODE, AND WE NIETHER BUT ON LF OR CR!!
;
;
; CALL TO ROUTINE HAS ADDRESS OF TCB IN HANDLER BUSY (IDLE) REGISTER
;
	.BLOCK	8.+EAESTK*4
	.WORD	LPCSR		;ADDRESS OF LPCSR CONTROL STATUS
				;    REGISTER USED TO RESET DEVICE
				;    ON STOP I/O OPERATIONS.
	.WORD	0		;TCB POINTER (EXTENDED BITS)
	.WORD	0		;TCB POINTER (LOWER 16 BITS). THIS
				;    WORD IS USED AS THE IDLE/BUSY
				;    SWITCH FOR THE DEVICE DRIVER.
;
LP:
	CLR	LP.CL		;CLEAR OUT ANY PENDING TIMER REQUESTS FOR US.
	MOV	LP-2,R0		;SETUP R0 TO POINT TO TCB
	CLR	LPSTAT(R0)	;CLEAR STATUS FLAG IN TCB
	MOV	LPSA+2(R0),R1	;GET BUFFER START ADDRESS
	TST	LPSA(R0)	;DON'T RELOCATE ADDRESS IF BIT 15
	BMI	1$		;    IS ON.
	ASL	R1		;RELOCATE ADDRESS (WORD TO BYTE POINTER)
	ADD	MEMSIZ,R1	;(+ 11'S OWN LOCAL MEMORY)
1$:	MOV	(R1)+,R2		;(SCR-152)FULL HEADR WORD
	MOVB	#15,LPEOL	;DEFAULT, ASCII, HERE IS <CR>
	MOV	#5000,(R1)+		;(SCR-152)DEFAULT PRECEED WITH LF
	CLRB	LPERWT		;RESET ERROR WAIT SWITCH
	.IFNDF	$NOSW		;##124##IF $NOSW, DISABLE ALL SWITCH INTERACT
	BIT	#140000,SPOLSW	;SPOOLER ENABLED & RUNNNG
	BEQ	6$		;GO TO DISABLE HALT AT EOF (BR-135)
	TST	R2		;(SCR-152)EOF IF TOP BIT ON
	BMI	5$		;(SCR-152)GOT AN EOF
	TSTB	LPEFWT		;WAS LAST RECORD AN EOF ? (BR-135)
	BEQ	2$		;NO - BRANCH TO NORMAL CODE (BR-135)
	CLRB	LPEFWT		;YES - CLEAR SWITCH FOR NEXT USE (BR-135)
	BIT	#2,SW		;IS SWITCH 2 UP ON 11 CONSOLE ? (BR-135)
	BEQ	2$		;NO - RESUME NORMAL CODE (BR-135)
	MOV	#LPECHK,LP.CL+2	;YES - SET UP CLOCK (BR-135)
	MOV	#170,LP.CL	;TWO SECOND RETRY (BR-135)
	SEXIT	WAITST		;EXIT TO SYSTEM
5$:	INCB	LPEFWT		;SET EOF FLAG FOR NEXT TCB (BR-135)
	BR	2$		;RESUME NORMAL CODE (BR-135)
6$:	CLRB	LPEFWT		;CLEAR FLAG - IN CASE SPOOLER JUST TURNED OFF (BR-135)
	.ENDC
2$:	BIT	#400,R2		;(SCR-152)BIT SET IF IMAGE MODE
	BEQ	3$		;NOT IMAGE, CHECK FORMS CONTROL
	CLRB	LPEOL		;IMAGE, DON'T FORCE CR AFTER MESSAGE
	BR	4$		;ALLOW ALL FORMS CONTROL
3$:	CMPB	#14,(R1)	;FIRST CHAR FORM FEED?
	BEQ	4$		;YES, DON'T ADD LINE FEED TO LINE
	CMPB	#15,(R1)	;FIRST CHAR CARRIAGE RETURN
	BEQ	4$		;YES, DON'T ADD LINE FEED TO LINE
	DEC	R1		;MOVE POINTER BACK TO LINE FEED
	INC	R2		;COUNT ADDITION OF LF TO BUFFER
4$:	BIC	#177400,R2	;(SCR-152)CLEAR MODE BYTE FROM COUNT
	MOV	R2,LPBTCT	;SAVE COUNT
	MOV	R1,LPBUFF	;SAVE POINTER
	CLRB	LPTAB
	TSTB	LPBUF		;HISTORY SAYS THIS HERE
	BIS	#100,LPCSR	;ENABLE INTERRUPTS TO LP GOING
	SEXIT	WAITST		;EXIT IN A WAIT STATE AND RESCAN
				;    THE ATL NOW.
;
;
;	LP INTERRUPT ENTRANCE
;
LPINT:
	BIC	#100,LPCSR	;DISABLE LP INTERRUPT
	JSR	R0,R.SAVE	;SAVE REGISTERS
	4			;TASK CODE
	MOV	LP-2,R0		;GET TCB POINTER
	BEQ	LPXT		;IGNORE IF ITS ALREADY BEEN STOPPED BY
				;    A STOP I/O REQUEST.
	TST	LPCSR		;CHECK FOR ERROR
	BMI	LPERR		;YES
	CLR	LP.CL		;CLEAR OUT ANY PENDING TIMER REQUEST FOR US.
LPLOP:
	TSTB	LPCSR		;IS PRINTER CURRENTLY GOING?
	BPL	LPSTIL		;YES:  FORGET CHAR FOR NOW
	TSTB	LPTAB		;IN TAB EXPANSION TO SPACES?
	BMI	4$		;YES
	DEC	LPBTCT		;DECR CHAR COUNT
	BMI	5$		;WENT TO -1, MAKE CR TO FINISH LINE
	TSTB	@LPBUFF		;MINUS BYTE IS TAB EXPANSION COUNT
	BMI	6$		;IS ONE, GO SET UP
	MOVB	@LPBUFF,LPBUF	;STICK CHAR INTO LINE PRINTER BUFFER
	INC	LPBUFF		;MOVE POINTER TO NEXT CHAR
	BR	LPLOP		;GO DO NEXT
;
6$:	MOVB	@LPBUFF,LPTAB	;SET UP TAB COUNT (MINUS, A LA 15)
	INC	LPBUFF
4$:	INCB	LPTAB		;COUNT A SPACE FOR THIS TAB
	MOVB	#40,LPBUF	;SPACE TO LINE PRINTER
	BR	LPLOP		;GO DO NEXT
5$:	TSTB	LPEOL		;IMAGE OR ASCII
	BEQ	7$		;IMAGE, DON'T FORCE <CR>
	MOVB	LPEOL,LPBUF	;ASCII, HERE IS <CARRIAGE RETURN>
7$:	INC	LPSTAT(R0)	;SET REV TO GOOD COMPLETION
	BR	LPXIT
;
LPSTIL:	BIS	#100,LPCSR	;ENABLE INTERRUPT ON LP
	BR	LPXIT1		;RESTORE R0-R5 AND RETURN
;
LPERR:	INCB	LPERWT		;SET ERROR WAIT SW.
	MOVB	#4,LPEST	;ERROR CODE 1,NOT READY TO TABLE
LPERR1:	MOV	#LPCHK,LP.CL+2	;ADDR. FOR TIMER REQ.
	MOV	#170,LP.CL	;2 SECS. IN TICKS(OCTAL)
LPXIT1:	JMP	DEQU1		;SCHEDULE NEXT TASK
;
LPXIT:	CLRB	LPEST		;INDICATE SUCCESSFULL OPERATION
	BIS	#340,PS		;INHIBIT INTERRUPTS
	CLR	LPCSR		;SHUT DOWN DEVICE
	MOV	#1,R1		;TELL CALLER DONE
	MOV	LP-2,R0		;GET TCBP
	CALL	SEND15		;TELL CALLER DONE
LPXT:
	BIS	#340,PS		;INHIBIT INTERRUPTS
	CLR	LP-2		;CLEAR BUSY(IDLE) FLAG
	CLR	LP-4
	MOV	#LP,R3		;DEQUEUE ANOTHER REQUEST IF ANY
	MOV	#LP.LH,R1	;    IN THIS DRIVERS DEQUE.
	JMP	DEQU
;
;
;
;		SUBROUTINE TO FIELD CLOCK COUNT-DOWN
;
;
LPECHK:	TST	LP-2		;HAVE WE BEEN DISABLED  ? (BR-135)
	BEQ	LPCX		;YES - RETURN TO CLOCK - NO RETRY (BR-135)
	BIT	#2,SW		;NO - IS SWITCH 2 STILL UP ? (BR-135)
	BNE	LPCXIT		;YES - SET UP CLOCK RETRY (BR-135)
	BR	LPCLK		;NO - SET UP RETRY OF TCB (BR-135)
LPCHK:	TST	LP-2		;HAVE WE BEEN DISABLED
	BEQ	LPCX		;IF YES, EXIT, LEAVING CLOCK DISABLED (BR-135)
	TST	LPCSR		;DOES ERROR STILL EXIST ? (BR-135)
	BMI	LPCXIT		;YES - SET UP CLOCK RETRY (BR-135)
LPCLK:	MOV	#LPTCOD*2,R2	;SCAN ATL FOR OUR NODE (BR-135)
	MOV	ATLNP(R2),R1
	MOV	#LP,LP-12	;RESTART AT BEGINNING OF REQ.
	BIC	#17,A.TS(R1)	;R1 POINTS TO OUR NODE, MAKE RUNNABLE
	MOV	#LP-26,A.SP(R1)	;SET UP STACK POINTER
	ASR	R2		;MAKE BYTE ADDRESSING
	MOVB	LEVEL(R2),LP-10	;SET UP PS
	RTS	PC		;RETURN TO CLOCK (BR-135)
LPCXIT:	MOV	#170,(R0)	;R0 POINTS TO TIMER ENTRY
LPCX:	RTS	PC		;RETURNS TO CLOCK
;
LPBUFF:	.WORD	0		;BUFFER POINTER
LPBTCT:	.WORD	0		;BYTE COUNT
LPTAB:	.WORD	0		;TAB LOCATION
LPEOL:	.BYTE	0		;0 IF IMAGE, 15 IF ASCII
LPERWT:	.BYTE	0		;MAKE EVEN
LPEFWT:	.BYTE	0		;EOF WAS LAST RECORD FLAG (BR-135)
	.EVEN			;MAKE EVEN (BR-135)
;
	.NLIST
	.ENDC
;
	.IFDF	$CD
	.LIST
	.SBTTL	CR11 CARD READER DRIVER
	.EVEN
;
CDS=177160			;STATUS AND CONTROL REGISTER
CDB1=177162			;READ CARD COLUMN IN BINARY
CDB2=177164			;READ IN COMPRESSED COLUMN
;
CDEST=CD.EST+4			;ADDR OF DRIVER ERROR STATUS BYTE
CDUNN=CD.EST+2			;ADDR OF UNIT # (FOR NOW ONLY 0)
CDBUF=10			;TCB OFFSET EQUALITY FOR BUFFER ADDR.
CDUNI=12			;TCB OFFSET FOR UNIT # (NOT PRESENTLYUSED)
CDTCOD=5			;OUR TASK NUMBER UNDER PIREX
CDCOLC=80.			;COLOUMN COUNT
CDCOLD=CDCOLC+CDCOLC		;BYTES PER80 FULL BINARY COL.'S
;
;  ERROR CODES PLACED IN CDEST IN TABLE IN PIREX
;   NOTE, ERRORS 12&74 ARE 'HARD' ERRORS, ERROR 4 IS 'SOFT'
;
;  0  OPERATION COMPLETED OK
; 74  COLUMN DONE INTERRUPT BFORE PREVIOUS ONE SERVICED
; 12  READ CHECK (COVERS A VARIETY OF SINS)
; 72  ILLEGAL PUNCH COMBINATION
;  4  READER OFF LINE (NOT RETURNED IF SPOOLING) A NUMBER OF CAUSES..
; 75  HARDWARE IS BUSY, BUT DRIVER IS NOT.(NOW DONE AS IOPS4)
; 76  HARD ERROR !BETWEEN CARDS! , TROUBLE!
; 45  MORE THAN 80 COLUMNS FOUND ON CARD
;  3  ILLEGAL INTERRUPT, OR UNEXPECTED READER-TO-ON-LINE
;
	.BLOCK	8.+EAESTK*4	;STACK (WE'RE AT LEVEL 6)
	.WORD	CDS		;FOR PIREX, ADDR CONTROL REGISTER
	.WORD	0		;HIGH ORDER PART TCB ADDR.
	.WORD	0		;LOW ORDER; SERVES AS IDLE/BUSY
;
CD:	MOV	CD-2,R0		;TCB ADDR
	CLRB	CDEWT		;CLEAR WAIT FOR ERROR BYTE
	MOV	CDBUF(R0),R1	;CALLER'S BUFFER ADDR.
	MOV	#CDS,R2		;ADDR. OF CONTROL REGISTER 
	TST	CD-4		;PDP15 OR PDP 11 REQUEST?
	BMI	1$		;BRANCH IF PDP11
	ASL	R1		;PDP15 ADDR. *2 WORDS TO BYTES
	ADD	MEMSIZ,R1	;ADD OUR MEMORY SIZE TO OFFSET ADDR.
1$:	MOV	#CDCOLC,(R1)+	;BYTE COUNT IN FIRST WORD OF 2 WORD
;				;HEADER. MOVE POINTER UP 2 BYTES
;
; !!HOOK!!
;	FOR BLANK COMPRESSION, LEAVE OUT PLACEMENT OF 120
;
	CLR	(R1)+		;CLEAR CHECKSUM WORD. POINT TO FIRST DATA
	MOV	R1,CDBUFI	;SAVE INITIAL POINTER FOR RETRY
	MOV	R1,CDBUFP	;ALL READY TO PLACE DATA IN BUFFER
	MOV	#CDBUFX,CDBUFQ	;LOAD POINTR FOR COLUMN BINARY BUFFER
	CLRB	CDUNN		;THIS PRESENT DRIVER HAS ONLY UNIT #0
	CLR	(R2)+		;##132##CLR STATUS, REAL ERRORS STAY UP
	MOV	(R2),R5		;##132##READ A COLUMN TO CLR COLUMN REDY
	BIT	#135400,-(R2)	;##123##UNIT IN ERROR (NEW BIT PATTERN)
	BNE	2$		;TREAT AT 2
	MOV	#101,(R2)	;SEEMS OK, READ A CARD
	BR	4$
2$:	INCB	CDEWT		;HANG UNTIL READER GOES ON LINE. 
;				;WE GET AN INTERRUPT IN THAT CASE.
	MOV	#76,R3		;DEFAULT ERROR CODE FOR HARD ERROR
	BIT	#14000,(R2)	;CHECK HARD ERROR BITS
	BNE	3$		;GOT ONE, GO PUT ERROR CODE OF 76
;
;	HERE USED TO BE IOPS75 HANDLING, TREAT AS IOPS4!
;
	MOV	#4,R3		;ERROR CODE OF 4 FOR NOT READY
	TST	SPOLSW		;SPOOLING ON?
	BPL	3$		;NO, LEAVE FOUR CODE NOT READY
	CLR	R3		;YES, NOT READY IS NOT ERROR
3$:	MOVB	R3,CDEST	;PLACE ERROR STATUS
	MOV	#100,(R2)	;ENABLE INTERRUPTS AND WAIT
4$:	SEXIT	WAITST
;
;
;	REWRITE INTERRUPT HANDLER TO OPERATE ENTIRELY AT LEVEL7
;	DURING THE CARD, BECAUSE SYSTEM OVERHEAD DESTROYS LEVEL6.
;	RUNNING AT LEVEL6 LEADS TO LOSS OF CARD COLUMNS WHILE SPOOLING.
;	AT END OF CARD, LOWER TO LEVEL6 (EVEN LOWER BETTER??) TO DO
;	COLUMN VALIDITY CHECKING AND CHECKSUMMING. THIS APPRAOCH
;	REQUIRES A 120 WORD BUFFER FOR THE COLUMN BINIARY, AS IT
;	MUST BE SAVED UNTIL THE END OF THE CARD. COMPRESSED COLUMN
;	WILL BE PLACED INTO THE USER'S BUFFER AT INTERRUPT LEVEL.
;	IF THE CARD TURNS OUT TO BE OK, THIS STORED DATA IS OK.
;
;	INTERRUPT CODE (EXCEPT END OF CARD) SAVES AND RESTORES R0
;	USING THAT REGISTER !!ONLY!!
;
CDINT:	TST	CD-2		;DID WE GET TURNED OFF
	BEQ	70$		;IF SO GO FINISH UP
	PUSH	R0		;SAVE R0 ON STACK (ONLY REG. USE
;				;UNLESS END OF CARD)
	MOV	CDS,R0		;##123##TRIAL FIX FOR IOPS45
	TSTB	CDEWT		;WAITING FOR ERROR RECOVERY???
	BNE	30$		;TO 30 IF YES
	BIT	#2000,R0	;##123##TRIAL FOR IOPS45
	BNE	76$		;##123##GOT ONLINE WHEN NOT WANTED!!
	TST	R0		;##123##SET UP FOR ERROR TEST
	BMI	50$		;IF MINUS, ERROR, GO TREAT
	TSTB	R0		;CHECK COLUMN DONE BIT (7)
	BMI	40$		;GOT A COLUMN
	ASL	R0		;CARD DONE BIT TO AC15
	BMI	20$		;CARD DONE
	BR	76$		;NONE OF ABOVE!?!?!? JUST EXIT
;
;	ERROR HANDLING
;
50$:	CMP	CDBUFQ,#CDBUFX+CDCOLD ;IF ALREADY 80 CC, IGNORE ERR.,
	BEQ	21$		;IS SUPPLY ERROR ON LAST CARD IN HOPPER
	BIC	#173777,R0	;CLEAR XCPT TIMING ERROR
	ADD	#174012,R0	;12 HARD ERROR BYTE.
	BMI	60$		;BRANCH ON HARD ERROR, BYTE SET UP
	MOV	#74,R0		;MISSED COLUMN BYTE
62$:	MOV	#102,CDS	;EJECT REST OF CARD ON MISSED COUMN
60$:	MOVB	R0,CDEST	;COME TO 60$ ERROR BYTE IN R0.SET IN TABLE
	MOVB	R0,CDEWT	;SET WAITING FOR ERROR BYTE.
76$:	MOV	#100,CDS	;##124##REARRANGE;  CLEAR OUT STATUS REG
	MOV	CDB1,R0		;##132##CLEAR COLUMN DONE BIT
	BR	75$		;##124##REARRANGE;  GO EXIT
;
;	GET A COLUMN
;
40$:	MOV	CDBUFQ,R0	;FULL BINARY COLUMN POINTER
	CMP	#CDBUFX+CDCOLD,R0	;ALREADY 80? (BR-134)
	BLE	49$		;YES ERROR (BR-134)
	MOV	CDB1,(R0)+	;TO BUFFFER
	MOV	R0,CDBUFQ	;SAVE POINTER
	MOVB	CDB2,@CDBUFP	;COMPRESSED COLUMN FOR BUFFER
	INC	CDBUFP		;MOVE UP POINTER
75$:	POP	R0		;RESTORE R0
	RTI			;EXIT
;
49$:	MOV	#45,R0		;ERROR CODE FOR TOO MANY CC.
	BR	62$		;EJECT CARD, REGISTER ERROR
;
;
70$:	CLR	CDS		;STOP DEVICE
	CLRB	CDEWT		;WE'RE NO LONGER WAITING
	JSR	R0,R.SAVE	;SAVE REG'S TO JOIN SYSTEM
	CDTCOD			;OUR TASK CODE
	BR	28$		;SYSTEM EXIT CODE
;
;	WAITING FOR ERROR TO BE FIXED CODE
;
30$:	BIT	#2000,R0	;##123##TO ON LINE INTERRUPT??
	BEQ	76$		;##123##NO JUST IGNORE
	CLR	CDS		;##123##MAKE ANY REAL ERRORS REAPPEAR
	BIT	#135400,CDS	;##124##DEVICE STILL!! IN ERROR???
	BNE	76$		;##123##YES, JUST KEEP WAITING
;
; WHEN READER GOES TO ON LINE, AN INTERRRUPT IS GIVEN. WE ASSUME
; THE OPERATOR HAS FIXED THE PROBLEM, AND RETRY THE CARD
;
77$:	CLRB	CDEST		;CLEAR ERROR BYTE IN TABLE (IF STILLSET)(BR-112)
	CLRB	CDEWT		;CLEAR OUR WAITING FOR ERROR BYTE
	MOV	CDBUFI,CDBUFP	;RESET COMPRESSED COLUMN BUFFER POINTER
	MOV	#CDBUFX,CDBUFQ	;RESET FULL BINARY BUFFER POINTER
	MOV	#101,CDS	;READ A CARD
	BR	75$		;EXIT FROM INTERRRUPT
;
;	END OF CARD PROCESSING
;
20$:	MOVB	#74,R0		;ERROR BYTE FOR MISSED COLUMN
	CMP	CDBUFQ,#CDBUFX+CDCOLD ;BETTER HAVE 80
	BNE	60$		;NO , GO REGISTER COMPLAINT
21$:	POP	R0		;NOW WE GO TO SAVE ALL REGISTERS
;
;  CODE SNARFERS WATCH IT, R.SAVE EXPECTS R0 POINTING TO CALL+2 
;
	JSR	R0,R.SAVE	;THIS SAVES R0, DON'T SAVE TWICE
	CDTCOD			;OUR TASK CODE
;
; WE NOW COME DOWN TO LEVEL 6 , CURTESY OF R.SAVE
;
	MOV	#CDBUFX,R5	;GO THRU COLUMN BINARY BUFFER
	MOV	(R5),R0		;TO ENSURE LEGAL PUNCHES
	BIC	#170777,R0	;TEST 1,EOF CARD IF 12,11,0 ALLIN COL. 1
	CMP	#7000,R0	;EOF CARD IF EQUAL
	BEQ	26$		;CARD OK, CLOSE OUT DEVICE
;
; !!HOOK!!
;
;	FOR SPOOLER UPGRADE, TEST FOR ALT-ALT END OF DECK CARD HERE
;	AND PLACE -2 IN TOP BYTE OF BUFFER (CDBUFI-3).
;	SIMILARLY, THE EOF CARD ABOVE SHOULD PLACE A -1 IN THE SAME
;	BYTE, SO THAT THE SPOOLER DOESN'T HAVE TO WORRY ABOUT
;	DEVICE PECULAIRITIES!!!!!!!!
;
24$:	MOV	(R5)+,R0	;MAIN VERIFICATION LOOP, NEXT COL.
	MOV	R0,R3		;ANOTHER COPY
	BIC	#170777,R3	;CHECK IF MORE THAN 1 OF 12,11,0
	MOV	R3,R1		;TWO COPIES OF 12,11,0
	NEG	R1		;ONLY COMMON BIT ON IS LOWEST OF 12,11,0
	BIC	R1,R3		;CLEAR IT! IF MORE THAN 1, R3 LEFT NON0!
	BNE	29$		;IF NON0, AN ILLEGAL PUNCH, GO TO ERROR
	BIT	#776,R0		;ANY 1-8 PUNCHES?
	BEQ	25$		;NO, CARD MUST BE LEGAL
	BIT	#1,R0		;A NINE PUNCH WITH 1-8? (SHOULD ROR,HACKERS)
	BNE	29$		;THAT'S ILLEGAL, ERROR OUT
	CMP	#4402,R0	;IS SPECIFICALLY 12-1-8 ALT MODE
	BEQ	25$		;YES OK
	MOV	#402,R1		;1-8 PUNHES TO R1
	BIC	R0,R1		;1 AND 8 ILLEGAL, SEE IF BOTH THERE
	BEQ	29$		;IF BOTH CLEARED, AN ERROR
	BIC	#177003,R0	;KEEP 1-7, TO SEE IF MORE THAN 1 OF THEM
	MOV	R0,R3		; A COPY
	NEG	R3		;ONLY COMMON BIT IS LOWEST OF 1-7
	BIC	R3,R0		;SO R0 MUST BE CLEARED IF OK
	BNE	29$		;MISSED, GO ERROR
25$:	CMP	#CDBUFX+CDCOLD,R5	;DONE
	BGE	24$		;NOPE
26$:	CLR	CDS		;CLEAR OUT DEVICE
;
; !!HOOK!!
;
;	AT THIS POINT, COLUMN COMPRESSION SHOULD BE DONE
;	GO THRU THE USER BUFFER, ALL CONSECUTIVE BLANKS ARE REMOVED
;	AND REPLACED BY ONE BYTE, WHICH IS MINUS THE COUNT OF BLANKS
;	INCLUDING -1 FOR ONE BLANK. BLANKS AT THE END OF THE CARD ARE
;	IGNORED. THE RESULTING COUNT OF BYTES IS PLACED IN THE
;	BUFFER HEADER (CDBUFP-4) COUNT IS A BYTE WIDE!
;
	CLRB	CDEST		;SAY OK OPERATION
	MOV	CDBUFI,R5	;POINT TO START OF DATA
	MOV	R5,R1		;RUNNING POINTER
	MOV	-4(R5),R4	;CHECKSUM INCLUDES HEADER
	MOVB	R4,R3		;MAKE CONTROL COUNT
	ADD	R1,R3		;GOT CONTROL COUNT
22$:	ADD	(R1)+,R4	;ADD INTO CHECKSUM
	CMP	R1,R3		;DONE?
	BLT	22$		;NO IF R1 MOT UP TO R3
	MOV	R4,-2(R5)	;PLACE CHECKSUM IN HEADER+2
;
;	 SYSTEM CALLS, USE AS IS!
;
	BIS	#340,PS		;LOCK OUT INTERRUPTS
	MOV	#1,R1		;SEND EVENT VARIABLE TO PDP-15 OK!
	MOV	CD-2,R0		;AND TCB ADDR FOR SEND15
	CALL	SEND15
28$:	BIS	#340,PS		;LOCK OUT INTERRUPTS
	CLR	CD-4		;CLEAR OUT OUR BUSY/IDLE FLAG
	CLR	CD-2
	MOV	#CD,R3		;RESCHEDULE OURSELVES IF NECESSARY
	MOV	#CD.LH,R1
	JMP	DEQU
;
;  EXTRA BUNCH OF CODE FOR ILLEGAL PUNCH ERROR
;
29$:	MOVB	#72,CDEST	;PLACE ILLEGAL PUNCH IN TABLE
	MOV	#100,CDS	;CLEAR DEVICE EXCPT INTERRUPTS
	MOVB	#72,CDEWT	;SAVE WE'RE WAITING FOR ERROR
	JMP	DEQU1		;RELEASE INTERRUPT
;				;WE'VE CALLED R.SAVE,SO EXIT THRU SYSTEM
;				;EXIT, DEQU1 RESTORES, SCANS ATL, RTI'S.
;
;
;  STORAGE
;
CDBUFP:	.WORD	0		;POINTER TO BYTE BUFFER
CDBUFI:	.WORD	0		;POINT TO BEGINNING OF BYTE BUFFER
CDBUFQ:	.WORD	0		;POINT TO FULL BINARY COLUMN BUFFER
CDBUFX:	.BLOCK	120	;SAVE FULL COLUMN BINARY
CDEWT:	.BYTE	0	;ERROR FLAG. NON0 IF WAITING FOR ERROR FIX
CDXX:	.BYTE	0	;EXTRA BYTE TO COME OUT EVEN
;
	.NLIST
	.ENDC
;
	.IFDF	$PL
	.LIST
	.SBTTL	XY11 DRIVER/XY311 DRIVER CONDITIONAL ASSY PARAMETERS
	.EVEN
;
XYCS=172554	;PLOTTER STATUS REG
XYDB=172556	;PLOTTER DATA BUFFER
PLSA=6		;BUFFER ADDR OFFSET IN TCB
PLEST=PL.EST+4		;POINTER TO ERROR TABLE LOCATION
PLUNN=PL.EST+2		;UNIT NUMBER (NOT NOW USED)
;
;  CONDITIONAL ASSEMBLY FOR CHARACTER POSITION.
;
;  CHARACTERS ARE 'DRAWN' INSIDE A LOGICAL BOX HAVING 11 HORIZONTAL
;  AND 11 VERTICAL POSITIONS.  THE CHARACTER TABLE IS SET UP TO
;  DEFAULT THAT THE CHARACTER IS CENTERED IN THE BOX ALONG THE
;  X-AXIS. (THE BOX INCLUDES THE INTERCHARACTER SPACING.) IT MIGHT
;  BE DESIRABLE TO MAKE THE CHARACTER EITHER RIGHT OR LEFT JUSTIFIED
;  IN THE BOX. TO DO SO DEFINE $RIGHT=0 OR $LEFT=0.
;
;  DEFAULT SETUP
;
	.IFNDF	$SPACE		;##149## ONLY WITHOUT EXPERIMNT
	.IFNDF $RIGHT
	.IFNDF $LEFT
STEPIN=12			;INITIALIZE POSITION (X) FOR FIRST CHAR
STEPOU=0			;POSITION PEN AFTER LAST CHAR
	.ENDC
	.ENDC
;
;  RIGHT
;
	.IFDF $RIGHT
STEPIN=11
STEPOU=1
	.ENDC
;
;  LEFT
;
	.IFDF $LEFT
STEPIN=13
STEPOU=-1
	.ENDC
CHRWID=12			;##149##EQUATE FOR WIDTH
	.ENDC			;##149##
;
	.IFDF	$SPACE		;##149## GREATER INTERCHAR SPACE
	.IFNDF	$RIGHT		;##149##
	.IFNDF	$LEFT		;##149##
STEPIN=14			;##149##
STEPOU=0			;##149##
	.ENDC			;##149##
	.ENDC			;##149##
	.IFDF	$RIGHT		;##149##
STEPIN=13			;##149##
STEPOU=1			;##149##
	.ENDC			;##149##
	.IFDF	$LEFT		;##149##
STEPIN=15			;##149##
STEPOU=-1			;##149##
	.ENDC			;##149##
CHRWID=14			;##149## CHARACTER WIDTH
	.ENDC			;##149##
;
;
;
;  THE CALCOMP PLTTER DOES NOT HAVE AN OFFLINE SWITCH. THIS
;  LEADS TO DIFFICULTY IN STOPPING THE PLOTTER TO
;  REFIL PEN, TAKE OFF PLOTS ETC. BIT 2 SWITCH OF THE PDP-11
;  CONSOLE SWITCHES IS TO BE USED AS THE OFFLINE
;  SWITCH FOR THE CALCOMP. IF YOU DO  !!NOT!! WISH THIS FEATURE
;  DEFINE $NOSW=0.
;  NOTE, FOR $PL311, THIS IS AUTOMATICALLY DISABLED, DON'T DEFINE!!
;
;
;  CONDITIONAL ASSEMBLY FOR XY11 OR XY311 PLOTTER INTERFACE
;
;  $PL311 IF DEFINED WILL GENERATE THE CONTROL BYTES REQUIRED
;  FOR CALCOMP'S 936.IF UNDEFINED,THE CONTROL BYTES FOR CALCOMP'S
;  500 SERIES ARE GENERATED.IF $PL311 IS DEFINED THEN THE
;  UNITS FOR THE PLOTTER STEP SIZE SHOULD BE 
;  SPECIFIED.$UNITS DEFINED GENERATES A METRIC PLOTTER,UNDEFINED
;  GIVES ONE IN INCHES.
;
;
;
	.IFDF	$PL311
	.RADIX	10
	.IFDF	$UNITS
PENDIS=1520/5		;PEN DISPL.=1.52 CM./0.05 MM.
	.ENDC
	.IFNDF	$UNITS
PENDIS=600/2		;PEN DISPL.=0.6 INCHES/0.002 INCHES
	.ENDC
	.RADIX	8
PY=0			;+Y
PYPX=1			;+Y,+X
PX=2			;   +X
NYPX=3			;-Y,+X
NY=4			;-Y
NYNX=5			;-Y,-X
NX=6			;   -X
PYNX=7			;+Y,-X
ESFM=10			;ENTER SPECIAL FUNCTION MODE
PENUP=11		;PEN UP
PENPUL=11		;PEN SELECT PULSE
PENDWN=12		;PEN DOWN
PENNOP=13		;NO OPERATION
;14,15 ARE NOT CURRENTLY USED
LSFM=16			;LEAVE SPECIAL FUNCTION MODE
;17 IS NOT USED
	.ENDC
	.IFNDF	$PL311
PENUP=40		;XY11 CODE
PENDWN=20
	.ENDC
;
;
;
;

	.SBTTL	XY11 DRIVER/XY311 DRIVER
;
;
;
;  THE LOWEST LEVEL SUBROUTINE 'PLOT' ISSUES DATA TO PLOTTER
;  DATA BUFFER, RELEASES CONTROL, AND IS WAKEN UP BY INTERRUPT.
;  THIS IS ALL WELL AND GOOD, BUT IT LEADS TO SAVE AND RESTORE
;  QUESTIONS ABOUT REGISTERS AND STACK.
;
;  THEREFORE, SINCE THIS THING HAS TO COME UP IN A SUPER HURRY,
;  SUBROUTINE CALLS ARE MADE BY SIMULATING PDP-15 JMS, THE RETURN
;  ADDRESSS IS STORED IN CORE. SIMILARLY, NO REGISTERS ARE
;  ASSUMED TO LIVE THRU A CALL TO A LOWER LEVEL SUBROUTINE.
;
;  LEVEL 3, THE LOWEST LEVEL, CALLED BY LEVEL 2
;
;  THE ONLY ROUTINE IS 'PLOT' ISSUES HARDWARE REQUESTS TO XY
;
;  LEVEL 2, CAKLLED BY LEVEL 1
;
;  ROUTINE 'APPR' DOES LINE APPROXIMATION
;  ROUTINE 'PEN' DOES PEN UP AND DOWN MOVEMENTS
;
;  LEVEL 1.5, CALLS LEVEL 3 AND THEN CALLS LEVEL 1 TO RETURN TO PDP-15
;
;  ROUTINE 'SELPEN' SELECTS THE PEN NUMBER WHICH IS TO BE ACTIVE
;     CALLS 'PLOT' TO ISSUE CONTOL BYTES TO XY311
;     CALLS 'LINE' TO POSITION NEW PEN OVER CURRENT COORDINATE(ORDINATE)
;
;  LEVEL 1
;
;  ROUTINE 'LINE' DOES LINES AND POSITIONING
;     CALLS 'PEN' AND 'APPR'
;  ROUTINE 'CHAR' DOES CHARACTERS
;     CALLS 'PEN' AND 'APPR'
;  ROUTINE 'CLOS' PICKS UP THE PEN IRREGARDLESS OF PRESENT
;     CALLS 'PEN'
;  ROUTINE 'INIT' LIFTS PEN, AND OBTAINS CHARACTER DECRIPTION
;     CALLS 'PEN'
;
;  BUFFER FORMAT (MODELED AFTER LP TO SPEED SPOOLER CODING)
;
;  WORD 1	MODE,,BYTE COUNT
;  WORD 2	CHECKSUM (NOT PRESENTLY IMPLEMENTED)
;  WORD 3-N	DATA
;
;  MODE VALUES
;
;	1	LINE DATA
;	2	CHARACTER DATA, ASCII CHAR'S TWO PER WORD.
;	3	INIT; LIFT PEN, SET UP CHAR DATA
;	4	PEN SELECT #1,2 OR 3 IF XY311 INSTALLED
;	-1	END OF FILE, MAINLY FOR SPOOLER, PICK UP PEN
;
;  NOTE SPOOLER IGNORES HIGH HALF OF FIRST WORD.
;
;
;
	.BLOCK	8.+EAESTK*4	;(115 SCR)BRING STACK UP TO DATE
	.WORD	XYCS		;POINTER TO STATUS REG.
	.WORD	0		;2 WORDS FOR TCB
	.WORD	0		;LOW ONE ALSO IDLE/BUSY 0=IDLE
;
;
PL:	CLRB	XYXIT		;FLAG NON-INTERRUPT EXIT!
	MOV	PL-2,R0		;TCB POINTER
	MOV	PLSA+2(R0),R1	;BUFFER POINTER
	TST	PLSA(R0)	;PDP-11 OR PDP-15 REQUEST
	BMI	1$		;DON'T RELOCATE FOR PDP-11 REQ
	ASL	R1		;WORD ADDR TO BYTE
	ADD	MEMSIZ,R1	;PLUS OFFSET FOR PDP-11 MEMORY
1$:	CLR	XYCNT		;CLEAR OUT HIGH HALF
	MOVB	(R1)+,XYCNT	;BYTE COUNT FOR LOOP CONTROL
	MOVB	(R1)+,R2	;WHICH MODE FOR BUFFER
	ADD	#2,R1	;POINT R1 TO DATA (BR-134)
	.IFNDF	$NOSW		;##124##IF $NOSW, DISABLE ALL SWTICH INTERACT
	BIT	#140000,SPOLSW	;SPOOLING?
	BEQ	2$
	BICB	#10,MASK	;##137##CLEAR OEF WAIT BIT
	BISB	PLERWT,MASK	;##137##SET IF LAST TCB A CLOSE
	.ENDC
2$:	CLRB	PLERWT		;##137##CLEAR CLOSE FLAG
	MOV	R1,XYPNT	;SAVE POINTER
	DEC	R2		;CHECK FOR ALINE
	BEQ	LINE		;IT IS
	DEC	R2		;CHECK FOR CHARACTER STRING
	BEQ	CHAR		;YES
	DEC	R2		;CHECK FOR INIT
	BEQ	INIT		;YUP, IF NOT IT, FALL THRU TO CLOS
	.IFDF	$PL311
	DEC	R2		;CHECK FOR PEN # SELECTION
	BNE	CLOS		;IF NON ZERO CLOSE
	JMP	SELPEN		;MODE 4,SELECT A PEN
CLOS:	CLR	R0		;PLUS R0 SAYS PEN UP
	.IFNDF	$NOSW
	MOVB	#10,PLERWT	;##137##SET CLOSE FLAG FOR NEXT TCB
	.ENDC
	MOV	#CLOS1,PEN	;SET RETURN FOR
	JMP	PEN+2		;JMS
CLOS1:	MOV	#1,@XYPNT	;FORCE SELECTION OF PEN #1
	JMP	SELPEN		;RETURNS VIA LINE TO CLOSRT
;
;
	.ENDC
	.IFNDF	$PL311
CLOS:	CLR	R0		;PLUS R0 SAYS PEN UP(R1 NON-0
;				;ALREADY TO FORCE ACTION)
	.IFNDF	$NOSW
	MOVB	#10,PLERWT	;##137##SET CLOSE FLAG FOR NEXT TCB
	.ENDC
	MOV	#CLOSRT,PEN	;JMS PEN
	JMP	PEN+2
	.ENDC
CLOSRT:	BIS	#340,PS		;TO LEVEL 7 WHILE WE CLOSE OUT
	MOV	PL-2,R0		;TCB ADR REQUIRED IN R0
	MOV	#1,R1		;FOLLOWING IS VERY TRICKY
	CALL	SEND15
PLHMM:	BIS	#340,PS		;REJOIN HERE ON PHANTOM TURN OFF
	CLR	PL-2
	CLR	PL-4
	MOV	#PL,R3
	MOV	#PL.LH,R1
	JMP	DEQU		;GONE (WARNING, THIS ASSUMES WE
;				;ARE EXITING FROM AN INTRRUPT, AND
;				;MUST SOMETIME DO AN  RTI
;
;*************************************************************
;		LEVEL 1 CODE
;**************************************************************
;
;
LINE:	ASR	XYCNT		;DIVIDE BY FOUR BYTE COUNT
	ASR	XYCNT		;SO WORD PAIR COUNT
LINLOO:	MOV	@XYPNT,R0	;DO ANY PEN ACTION NEEDED
;				;UP-DOWN XOR'ED IN TOP BIT OF DX
	ADD	#40000,R0	;MAKE PLUS FOR UP, MINUS FOR DOWN
	CLR	R1		;R1=0 SAYS NO ACTION IF PEN ALREADY OK
	MOV	#LINRT1,PEN	;JMS PEN
	JMP	PEN+2
LINRT1:	MOV	XYPNT,R2	;BRING POINTER TO GET DY AND DX
	MOV	(R2)+,R0	;DX
	ADD	UPDWN,R0	;CORRECT DATA VALUE FOR XOR'ED PEN!!
	MOV	(R2)+,R1	;DY
	MOV	R2,XYPNT	;SAVE UPDATED POINTER
	MOV	#LINRT2,APPR	;JMS APPROX
	JMP	APPR+2
LINRT2:	DEC	XYCNT		;DONE YET
	BGT	LINLOO		;NO
	BR	CLOSRT		;IN COMMON WITH CLOSE RETURN TO PDP15
;
;
;
;
;
;  SOME LOCAL STORAGE
;
XYPNT:	.WORD	0		;POINTER TO DATA COMING TO US
XYCNT:	.WORD	0		;COUNT OF DATA ITEMS
XYXIT:	.BYTE	0		;0 IF 'CAL' EXIT, NON0 IF INTERRUPT EXIT
STROKC:	.BYTE	0		;STROK COUNT FOR CHAR'S
STROKP:	.WORD	0		;POINTER TO STROKE BYTE
;
;  DATA TO DECRIBE SIZE OF UNIT CHARACTER. WE HAVE STORED CHAR'S
;  ON AN 11X11 GRID. MUST DESCRIBE DX AND DY OF GRID UNIT IN X
;  DIRECTION, AND DX AND DY OF GRID UNIT IN Y DIRECTION. THE PDP-15
;  CALCULATES THESE, AND SENDS WITH 'INIT' CALL. EACH QUANTITY
;  MUST BE DOUBLE PRECISION TO PREVENT US LOSING TRACK OF THE
;  PEN POSITION. THE ORDER OF THESE VARIABLES MUST MATCH
;  THAT IN THE PDP-15!
;
;
XDXH:	.WORD	2		;HIGH HALF
XDXL:	.WORD	0		;LOW HALF OF DX FOR X GRID UNIT STEP
YDYH:	.WORD	2		;Y GRID, Y DIRECTION, HIGH HALF
YDYL:	.WORD	0		;LOW HALF
XDYH:	.WORD	0		;HIGH HALF
XDYL:	.WORD	0		;DY FOR X GRID, NEEDED IF CHAR'S TIPPED
YDXH:	.WORD	0
YDXL:	.WORD	0
;
XLOCH:	.WORD	0		;CHAR'S, HIGH HALF X DISPLACEMENT
XLOCL:	.WORD	100000		;OF TOTAL STRING.LOW HALF
YLOCH:	.WORD	0		;SAME FOR Y
YLOCL:	.WORD	100000		;
XSTEP:	.WORD	0		;INTEGER GRID UNIT STEP X,Y
YSTEP:	.WORD	0		;WE ARE NOW AT
;
INIT:	MOV	#XDXH,R2	;POINTER TO PLACE 8 WORDS
	MOV	#10,R3		;COUNT FOR LOOP CONTROL
1$:	MOV	(R1)+,(R2)+	;MOVE FROM CALLER BUFFER TO OUR STORE
	DEC	R3		;CONTRO COUNT
	BGT	1$		;IF STILL >0, KEEP GOING
;
;  NOW FORCE THE PEN UP
;
	CLR	R0		;THIS SAYS UP, R1 NON0 TO FORCE
	.IFDF	$PL311
	TST	(R1)		;ARE WE A REAL INIT, OR JUST A SET CHAR?
	BEQ	CLOSRT		;0 JUST A SET CHAR, DON'T CHANGE PEN
	MOV	#INITR1,PEN	;RETURN ADR FOR
	JMP	PEN+2		;JMS
INITR1:	MOV	#1,@XYPNT	;FORCE SELECTION OF PEN #1 AT INIT
	JMP	SELPEN		;RETURNS VIA LINE TO CLOSRT
	.ENDC
	.IFNDF	$PL311
	MOV	#INITR,PEN	;JMS PEN, HERE IS OUR RETURN
	JMP	PEN+2		;GO THERE
INITR:	BR	CLOSRT		;THAT'S ALL, GO TO COMMON FINISH UP
	.ENDC
;
;  ONCE PER CHARACTER STRING CODE
;
CHAR:	CLR	XLOCH		;HIGH HALF OF X LOC REL TO START
	CLR	YLOCH		;AND Y;OF THE STRING
	MOV	#100000,XLOCL	;THIS IS TO HELP UP ROUND RIGHT
	MOV	#100000,YLOCL	;AND Y; WHEN MAKING DX AND DY
	MOV	#CHARR3,APPR	;WE OWN APPROX. LEAVE OUR RETURN ADDR.
	CLR	YSTEP		;ACCUMULATED Y STEPS PRIOR TO 'THIS' CHAR
	MOV	#STEPIN,XSTEP	;POSITION CHARACTERS CENTER,RIGHT,OR LEFT
;				;'FALSE' POSITION GENERATED IS CANCLLD
;				;AT EXIT. 12 FOR CENTER IS CANCELLED AT
;				;LOCATION CHARL1 IN LOOP.
;
;  NOW LOOP PER EACH CHAR
;
CHARL1:	CLR	R0		;RAISE THE PEN (ONLY IF NEEDED)
	CLR	R1		;R1=0 SAY CONDITIONAL RAISE
	MOV	#CHARR1,PEN	;JMS PEN, HERE IS REUTNR ADDR.
	JMP	PEN+2		;GO
CHARR1:	SUB	#CHRWID,XSTEP	;##149##!!TOUGH!!WE ARE NOW IN THE NEXT CHAR
;				;SO THE IN CHAR GRID MEMORY HAS TO BE
;				;MOVED BY THE INTERCHARACTER SPACING.
;
	MOVB	@XYPNT,R0	;GET CHARACTER FOR TABLE LOOK UP ON STROKE
	INC	XYPNT		;MOVE POINTER TO NEXT
	SUB	#40,R0		;NRMALIZE 40-137 RANGE TO 0-77
	MOVB	TABPNT(R0),R4	;RELATIVE POINTER TO THIS CHAR
	MOVB	TABPNT+1(R0),R5	;AND RELATIVE POINTER TO NEXT CHAR
;
;  WHILE WE ARE HERE. THE RELATIVE POINTERS  ARE:
;     ADDR OF FIRST STROKE OF CHAR MINUS TABLE BEGINNING ADDR
;     MINUS 8 TIMES (THE CHARACTER VALUE MINUS 40 (OCTAL))
;
;  ALL THIS JAZZ IS SO THAT WE CAN STORE THE ADDR. IN ONE BYTE.
;
	SUB	R4,R5		;DIFFERENCE IN POINTERS IS CONTROL
	ADD	#10,R5		;COUNT FOR # OF STROKES PER CHAR.
	BNE	1$		;SKIP IF REAL CHAR (I.E. SOME STROKES)
	JMP	CHARR4		;NOPE, GO END OF LOOP
1$:	MOVB	R5,STROKC	;SAVE STROKE CONTROL COUNT
	ASL	R0		;R0*8 TO CALCULATE REAL STROKE ADDR.
	ASL	R0		;FROM RELATIVE POINTER
	ASL	R0
	ADD	R0,R4		;RELATIVE+8*(CHAR-32)
	ADD	#TABCHR,R4	;+ADDR OF TOP OF TABLE
	MOV	R4,STROKP	;WE NEED REG'S, SAVE POINTER
	BR	CHARR2		;WATCH IT! TOP OF LOOP ALWAYS TRIES TO
;				;PUT THE PEN DOWN. FOR THE FIRST STROKE
;				;THE PEN IS ALWAYS UP, SO WE WILL ENTER
;				;THE LOOP A LITTLE FURTHER DOWN, SINCE
;				;THE PEN IS NOW KNOWN TO BE UP
;
;
;  PER STROKE LOOP
;
CHARL2:	MOV	UPDWN,R0	;GET STATE OF PEN
	MOVB	@STROKP,R1	;CHECK FOR SPECIAL STROKE -1
;				;WHICH IS A PEN CONTROL STROKE 
	CMP	#-1,R1		;-1 SAYS PUT PEN UP FOR NEXT STROKE
	BNE	1$		;NOT IT, GO DO OTHER WORK
	INC	STROKP		;GOT A -1, MOVE POINTER+COUNT
	DECB	STROKC		;TO A REAL MOVE CONTROLLER
	BR	2$		;GO GET IN THE PEN CHANGING ACTION
1$:	TST	R0		;REGULAR CHECK; IS PEN UP?
	BMI	CHARR2		;ON MINUS NO; GO JOIN LOOP
2$:	COM	R0		;BOTH GUYS WANT ONE THING, INVERT PEN!
	MOV	#CHARR2,PEN	;JMS PEN, HERE IS OUR RETURN
	JMP	PEN+2
;
;  COMPUTE GRID STEP CONTROL FROM STROKE BYTE
;
CHARR2:	MOVB	@STROKP,R1	;GET THE STROKE BYTE
	INC	STROKP		;MOVE POINTER TO NEXT
	MOV	R1,R0		;MAKE A COPY FOR X CHANGE
	ASR	R0		;X IS IN HIGH 4 BITS OF BYTE
	ASR	R0		;SO RIGHT JUSTIFY
	ASR	R0
	ASR	R0
	BIC	#177760,R0	;STRIP GARBAGE FROM BOTH CO-ORD.
	BIC	#177760,R1
	MOV	R0,R4		;KEEP A COPY, SINCE WE NEED DX,DY
	MOV	R1,R5		;COMPUTED FROM XSTEP, YSTEP
	SUB	XSTEP,R4	;DX IN GRID STEPS
	SUB	YSTEP,R5	;DY IN GRID STEPS
	MOV	R0,XSTEP	;SAVE PRESENT FOR NEXT TIME AROUND
	MOV	R1,YSTEP
;
;  NOW BRING UP THE RUNNING TOTALS OF WHERE ARE WE
;
	MOV	XLOCH,R0	;HIGH HALVES
	MOV	YLOCH,R1
	MOV	XLOCL,R2	;LOW HALVES
	MOV	YLOCL,R3
;
;NOW HERE IS DOUBLE PRECISION GRID CALCULATION
;
	TST	R4		;+,0,-?
	BEQ	10$		;0, NO CHANGE OF X GRID
	BMI	4$		;-,SUBTRACK GRID UNIT STEPS FROM TOTALS
1$:	ADD	XDXL,R2	;+, ADD IN GRID UNIT STEPS, LOW 1/2 X
	ADC	R0		;IF CARRY, ADD TO HIGH HALF
	ADD	XDXH,R0		;AND HIGH HALF FOR UNIT STEP
	ADD	XDYL,R3		;Y DIRECTION OF UNIT X STEP
	ADC	R1		;CARRY TO HIGH HALF
	ADD	XDYH,R1		;HIGH HALF
	DEC	R4		;DECREMENT CONTROL COUNT
	BGT	1$		; IF >0, NOT DONE YET
	BR	10$		;GO DO Y UNIT STEPS
4$:	SUB	XDXL,R2		;SUBTRACT SINCE MINUS X UNIT STEPS
	SBC	R0
	SUB	XDXH,R0
	SUB	XDYL,R3
	SBC	R1
	SUB	XDYH,R1
	INC	R4
	BLT	4$
;
;  Y UNIT STEP 
;
10$:	TST	R5		;+,0,-?
	BEQ	20$		;0, NO Y STEPS TO DO
	BMI	14$		;-, SUBTRACT
11$:	ADD	YDXL,R2		;+, ADD X COMPONENT Y STEP TO TATOL
	ADC	R0		;CARRY TO HIGH HALF
	ADD	YDXH,R0		;HIGH HALF X COMPONENT
	ADD	YDYL,R3		;Y COMPONENT Y STEP
	ADC	R1
	ADD	YDYH,R1		;Y COMPONENT Y STEP, HIGH HALF
	DEC	R5		;COUNT DOWN ON UNIT STEPS
	BGT	11$		;NOT DONE YET
	BR	20$		;DONE
14$:	SUB	YDXL,R2		;-,JUST SUBTRACT INSTEAD OF ADD
	SBC	R0
	SUB	YDXH,R0
	SUB	YDYL,R3
	SBC	R1
	SUB	YDYH,R1
	INC	R5
	BLT	14$
;
;  WHEW, HAVE UPDATED POSITION, NOW SAVE, AND CALCULATE DX,DY
;
20$:	MOV	R2,XLOCL	;SAVE LOW HALVES
	MOV	R3,YLOCL
	MOV	R0,R2		;SAVE COPY OF HIGH, SINCE WE SUBTRACT
	MOV	R1,R3		;ON THE OTHER COPY
	SUB	XLOCH,R0	;THIS IS DX FOR APPROXIMATOR
	SUB	YLOCH,R1	;AND DY
	MOV	R2,XLOCH	;SAVE PRESENT VALUE FOR NEXT TIME
	MOV	R3,YLOCH
	JMP	APPR+2		;CALL LINE APPROIMATOR
;
CHARR3:	DECB	STROKC		;ANY MORE STROKES PER CHAR
	BGT	CHARL2		;YES, GO DO
CHARR4:	DEC	XYCNT		;AND MORE CHARACTERS
	BGT	1$		;DEFINITELY YES, GO TO CHARL1
	BLT	2$		;DEFINITELY NO, GO FINISH
;
;				;SORT OF, WE INVENT A CHARACTER
;				;SO THE THE PEN IS FORCED TO THE LOWER
;				;RIGHT OF THE LAST CHARACTER
;				;140 IS THE CHARACTER; IT HAS ONE STROKE
;				;TO 0,0!!
	MOV	#MAGIC,XYPNT	;MOVE POINTER TO 140 TO INPUT CHAR GETTER
	ADD	#STEPOU,XSTEP	;CANCELL LEFT-RIGHT FUDGE  AT BEGINNING
;				;OF CHARCTER STRING
1$:	JMP	CHARL1		;AND GO DO IT. SORRY ABOUT THAT.
2$:	JMP	CLOSRT		;CLOSE UP OPERATION
;
	.IFDF	$PL311
;
;**************************************************************
;		LEVEL 1.5 CODE
;**************************************************************
;
;
;  SELPEN ROUTINE
;
;  USED TO ACTIVATE THE PEN NUMBER CONTAINED IN THE
;  FIRST DATA WORD OF THE TCB
;
;  LOCAL STORAGE
;
CURPEN:	.WORD	1	;THE NUMBER OF THE CURRENTLY ACTIVE PEN
PENCT:	.WORD	0	;LOOPN CONTROL FOR CONTROL BYTES PEN SELCT.
;NOW FOLLOWS A TABLE OF 5 STEP VALUES ONE OF THESE MUST BE ISSUED EACH TIME
;A PEN SELECTION IS MADE TO KEEP THE ACRIVE PEN OVER THE CURRENT COORDINATE.
	.WORD	-2*PENDIS
	.WORD	-1*PENDIS
STEPS:	.WORD	+0*PENDIS
	.WORD	+1*PENDIS
	.WORD	+2*PENDIS
;
;
SELPEN:	CLR	R0		;MOVE UP PEN
	CLR	R1		;ONLY IF NOT ALREADY UP
	MOV	#SELP1,PEN	;JMS TO PEN
	JMP	PEN+2
SELP1:	MOV	XYPNT,R3	;TCB ADDRESS OF THE PEN NUMBER
;
;PERFORM A RANGE TEST ON PEN #;
;  IS # < OR = 3?
;  IS # > OR = 1?
;
	SUB	#3,(R3)		;TOO LARGE?
	BGT	1$		;BRANCH IF # IS >3,WE WILL FORCE #=1
	ADD	#2,(R3)		;TOO SMALL?
	BGE	2$		;BRANCH IF # IS>0,IT'S OK
1$:	CLR	(R3)		;PREPARE FOR #1 FORCE
2$:	ADD	#1,(R3)		;RESET TO ORIGINAL OR AC-
;				;CEPTABLE VALUE
	MOV	CURPEN,R2	;PEN NUMBER UNTIL NOW
	MOV	(R3),CURPEN	;UPDATE CURRENT PEN NUMBER
;
;  NOW BUILD AN XY INCREMENT BUFFER TO ENSURE THAT SELECTED PEN
;  STAYS ON STATION
;
	SUB	(R3),R2		;PEN NUMBER "DISPLACEMENT"
	ASL	R2		;USE AS AN ADDRESS INDEX
	CLR	(R3)+		;SET # OF IX=0 AND FLAG FOR PEN UP
	MOV	STEPS(R2),(R3)	;INSERT # OF IY INCREMENTS REQUIRED
	MOV	#4,XYCNT	;BYTE COUNT FOR ONE XY PAIR
;
;   MAKE THE SELECTED PEN ACTIVE BY CALLS TO PLOT
;
	MOV	CURPEN,PENCT	;PEN NUMBER GIVES NUMBER OF LOOPS
	MOV	#ESFM,R0	;ENTER SPECIAL FN MODE
	MOV	#SLPN1,PLOT
	JMP	PLOT+2
SLPN1:	MOV	#PENPUL,R0	;PEN PULSE IS NEXT CTL BYTE
	MOV	#SLPN2,PLOT
	JMP	PLOT+2
SLPN2:	DEC	PENCT		;1,2 OR 3 PULSES ONLY TO BE SENT
	BNE	SLPN1		;PULSE AGAIN
	MOV	#LSFM,R0	;PEN IS NOW SELECTED,LEAVE SPECIAL FN MODE
	MOV	#SLPN3,PLOT
	JMP	PLOT+2
;
;  SELECTED PEN IS NOW ACTIVE AND MUST BE POSITIONED.
;  AT ADR INDEXED BY TCB DATA (XYPNT) TO DO THIS.
;  EXIT FROM "LINE" WILL BE TO PDP-15
;
SLPN3:	JMP	LINE
;
;
	.ENDC
;
;
;
;**************************************************************
;		LEVEL 2 CODE
;**************************************************************
;
;
;
;
;
;
;  PEN SUBROUTINE
;
;  CALLING SEQUENCE ARGUMENTS
;
;  PEN  MUST CONTAIN RETURN ADDR FOR JMP INDIRECT
;  R0 IS + FOR PEN UP AND - FOR PEN DOWN
;  R1 IS NON0 IF PEN ACTION ALWAYS TO TAKE PLACE
;  R1 IS 0 IF PEN MOVED ONLY WHEN NEEDED
;
;  LOCAL STORAGE
;
UPDWN:	.WORD	0		;0 WHEN PEN NOW UP, 100000 WHEN DOWN
;
PEN:	.WORD	0		;PLACE ADDR HERE
	TST	R1		;CONDITIONAL MOVE?
	BNE	1$		;GO TO 1$ ON NO
	ADD	UPDWN,R0	;IS REQUEST SAME AS IT ALREADY IS
	BPL	PENRET		;YES, JUST EXIT
	ADD	UPDWN,R0	;RESTORE R0 TO ORIGINAL
1$:	BIC	#77777,R0	;KEEP ONLY SIGN BIT
	MOV	R0,UPDWN	;SAVE THAT AS STATUS
	ADD	#PENUP,R0	;DEFAULT ON R0=0, UP CODE FOR XY
	BPL	2$		;IF POSITIVE, ALLL SET
	MOV	#PENDWN,R0	;DOWN CODE
2$:	MOV	#PENRET,PLOT	;JMS PLOT, BYTE IN R0
	JMP	PLOT+2
PENRET:	JMP	@PEN		;RETURN TO CALLER
;
;
;  LINE APPROXIMATION ROUTINE
;
;  DOES ALL X AND Y MOVEMENTS, BUT NO PEN MOVEMENT
;
;  CALL WITH RETURN ADDR IN APPR
;  CALL WITH DX IN R0
;  CALL WITH DY IN R1
;
;
;  DX AND DY IN INTEGER PLOTTER UNITS.
;  LOCAL STORAGE
;
TOTAL:	.WORD	0	;'AC' FOR APPROXIMATION CALCULATION
COUNT:	.WORD	-1	;CONTROL COUNT OF NUMBER OF STEPS
;			;##123##ALSO USED AS DOING LINE SWITCH, SO IT
;			;##123##MUST REMAIN - FOR NON-LINES
PLUS:	.WORD	0	;ADD IN ON DIAGONAL MOVE
MINUS:	.WORD	0	;AND ADD ON ORTHOGONAL
MINUSD:	.BYTE	0	;PLOTTER CONTROL BYTE
PLUSD:	.BYTE	0	;PLOTTER CONTROL BYTE
;
;
APPR:	.WORD	0
	MOV	#APPRET,PLOT	;RETURN FROM PLOT FOR WHOLE LOOP
	.IFNDF	$PL311
	MOV	#5,R5		;DEFAULT DIAGONAL LINE +X,+Y
	TST	R1		;IS DY POSITIVE
	BPL	1$		;IF SO NO ACTION
	NEG	R1		;MAKE POSITIVE
	ADD	#4,R5		;MAKE CONTROL BYTE -Y
1$:	TST	R0		;IS DX POSITIVE
	BPL	2$		; YUP, ALREADY OK
	NEG	R0		;NOW POSITIVE
	INC	R5		;CONTROL BYTE REMEMBER -X
2$:	MOV	R5,R4		;ANOTHER COPY CONTRO  BYTE
	CMP	R0,R1		;X OR Y BIGGER
	BMI	3$
	MOV	R0,COUNT	;X BIGGER, IT GIVES STEP COUNT
	BIC	#14,R4		;ORTHOGONAL CONTROL BYTE
	.ENDC
	.IFDF	$PL311
	MOV	R0,R2		;SAVE SIGN OF DX
	MOV	R1,R3		;SAVE SIGN OF DY
	MOV	#PYPX,R5	;DEFAULT DIAG. +X,+Y CTL BYTE
	TST	R1		;DY +VE?
	BPL	1$		;IF SO,NO ACTION
	NEG	R1		;MAKE +VE
	MOV	#NYPX,R5	;MAKE CTL BYTE +X,-Y
	TST	R0		;DX +VE?
	BPL	2$		;IF SO,NO ACTION
	NEG	R0		;MAKE +VE
	MOV	#NYNX,R5	;MAKE CTL BYTE-X,-Y
2$:	CMP	R0,R1		;X OR Y BIGGEST?
	BMI	3$		;BRANCH IF Y
	MOV	R0,COUNT	;X DETERMINES STEP COUNT
	MOV	#PX,R4		;ASSUME ORTHOG.CTL BYTE IS +X
	TST	R2		;IS DX +VE?
	BPL	5$		;IF SO NO ACTION
	MOV	#NX,R4		;CTL BYTE FOR -VE DX
	.ENDC
5$:	ASL	R0		;*2 FOR LOOP APPROX
	ASL	R1
	MOV	R1,MINUS
	SUB	R1,R0
	NEG	R0
	MOV	R0,PLUS
	BR	4$		;REJOIN OTHER LINE
	.IFNDF	$PL311
3$:	MOV	R1,COUNT	;Y BIGGER, STEP COUNT
	BIC	#3,R4		;ORTHOG CONTROL Y DIRECTION
	.ENDC
	.IFDF	$PL311
1$:	TST	R0		;DX IS +VE ASSUMED
	BPL	2$		;IF SO NO ACTION
	NEG	R0		;MAKE DX +VE
	MOV	#PYNX,R5	;MAKE CTL BYTE -X,+Y
	BR	2$		;NOW CHECK FOR ORTHOG. STEPS
;
;
;
3$:	MOV	R1,COUNT	;Y IS BIGGER,GIVES STEP COUNT
	MOV	#PY,R4		;ASSUME A +DY CTL BYTE(KEEP INST FMT SAME
	TST	R3		;IS DY +VE?
	BPL	6$		;IF SO NO CHANGE
	MOV	#NY,R4		;MAKE CTL BYTE -Y
	.ENDC
6$:	ASL	R0
	ASL	R1
	MOV	R0,MINUS
	SUB	R0,R1
	NEG	R1
	MOV	R1,PLUS
4$:	MOVB	R5,PLUSD	;SAVE DIAG CONTROL BYTE
	MOVB	R4,MINUSD	;ORTHOG
	ADD	R1,R0		;OBTAIN STARTING TOTAL
	ASR	R0
	MOV	R0,TOTAL
;
;  APPROXIMATIONS LOOP
;
APPRET:	DEC	COUNT		;ANY MORE STEPS TO DO
	BMI	2$		;THIS ALSO PICKS UP ZERO LENGTHLINE
	TST	TOTAL		;MINUS OR PLUS
	BMI	1$		;'ADD' OR 'SUBTRACT' DEPENDING
	ADD	PLUS,TOTAL
	MOVB	PLUSD,R0	;CONTROL BYTE
	JMP	PLOT+2		;ADDR ALREADY IN PLOT, GO DO IT
1$:	ADD	MINUS,TOTAL
	MOVB	MINUSD,R0
	JMP	PLOT+2
2$:	JMP	@APPR		;DONE, RETURN TO CALLER
;
;**************************************************************
;		LEVEL 3 CODE
;**************************************************************
;
;  PLOT ROUTINE, DO ACTUAL HARDWARE PUSH, WAIT FOR INTRRUPT
;
;  CALLING SEQUENCE, PLACE RETURN ADDR IN PLOT
;  PLACE BYTE FOR XY IN R0
;  BYTE XYXIT IS ZERO FOR 'CAL' EXIT, NON0 FOR INTERRUPT EXIT
;
;  LOCAL STORAGE
;
;
PLOT:	.WORD	0
	.IFNDF	$NOSW		;##138## REARRANGE CONDITIONALS
	BITB	MASK,SW		;##137##TEST FOR OFFLINE,EOF WAIT
	BNE	PLCHK1		;##123##
	.ENDC			;##123##
	.IFDF	$PL311
	BIT	#40,XYCS	;PL311 HAS REAL OFF LINE, USE THAT!!
	BNE	PLCHK1		;##123##
	.ENDC
PLOTGO:	MOVB	R0,XYDB		;CONTROL BYTE TO DEVICE
	BISB	#100,XYCS	;ENABLE INTERRUPTS
PLEXIT:	TSTB	XYXIT		;FIGURE OUT WHICH KIND OF EXIT
	BLE	1$		;BRANCH ON WAIT OR CLOCK RETURN
	JMP	DEQU1		;RESTORE REG.'S AND RTI
1$:	BNE	2$		;BRANCH ON CLOCK RETURN
	SEXIT	WAITST		;WAIT FOR FIRST INTERRUPT
2$:	RTS	PC		;CLOCK CALLED HERE AS SUBROUTINE
;
;
;  COME BACK FROM INTERRUPT
;
;
PLINT:	DEC	COUNT	;##123##SPEED LOOP FOR LINES
	BMI	PLINT1		;##123##ISN'T A LINE, OR LINE DONE
	.IFDF	$PL311		;##123## OFF LINE TEST
	BIT	#40,XYCS	;##123## PL311 CHECK STATUS REG.
	BNE	PLINT1		;##123##OFF LINE;ALL FUNNIES REJOIN
	.ENDC			;##123##MAIN LOOP, GET RESORTED LATER
	.IFNDF	$PL311		;##123##REGULAR PLOTTER USES CONSOLE
	.IFNDF	$NOSW		;##123##SWITCHES UNLESS DEFINED OUT
	BIT	#4,SW		;##123##BIT IS SAME AS IN SPOOLER STATUS
	BNE	PLINT1		;##123##WORD
	.ENDC			;##123##
	.ENDC			;##123##
	TST	PL-2		;##123## DID WE GET TURNED OFF
	BEQ	PLINT1		;##123##YUP
	TST	TOTAL		;##123##DO LINE APPROX
	BPL	1$		;##124##MAKE ORTHOGONAL TAKE SHORTED PATH
	ADD	MINUS,TOTAL	;##123##
	MOVB	MINUSD,XYDB	;##123##
	RTI			;##123##
1$:	ADD	PLUS,TOTAL	;##124##CHANGE SHORTEST PATH TO ORTHOG
	MOVB	PLUSD,XYDB	;##124##
	RTI			;##124##
;
PLINT1:	INC	COUNT		;##123##CANCELL PREVIOUS DEC!!!!
	JSR	R0,R.SAVE	;SAVE REGISTERS
	6			;TASK CODE
	BIC	#100,XYCS	;TURN OFF INTERRUPTS
	MOVB	#100,XYXIT	;INTERRUPT EXIT FLAG
	TST	PL-2		;DID WE GET TURNED OFF
	BNE	1$		;NOPE
	JMP	PLHMM		;CLEAN UP BUT DON'T SEND TO PDP-15
1$:	JMP	@PLOT		;RETURN TO LEVEL 2 CALLER
;
;
;  SUBROUTINE TO RECEIVE CLOCK COUNTDOWN
;
PLCHK:	MOVB	PLSAVB,R0	;PLOTTER CONTROL BYTE IF NEEDED
	MOVB	#377,XYXIT	;SAY WE HAVE TO EXIT TO CLOCK
	TST	PL-2		;DID DRIVER GET TURNER OFF
	BEQ	PLEXIT		;YES, JUST GO AWAY
	.IFNDF	$NOSW		;##124##
	BITB	MASK,SW		;##137##BOTH SWITCHES OK??
	BNE	PLCHK1		;##124##
	.ENDC			;##124##
	.IFDF	$PL311
	BIT	#40,XYCS	;CHECK STATUS REG FOR READY
	BNE	PLCHK1		;##124##
	.ENDC
	BEQ	PLOTGO
PLCHK1:	MOVB	R0,PLSAVB	;SAVE PLTTER BYTE
	MOV	#PLCHK,PL.CL+2 ;SET UP ADDR FOR CLOCK REQ.
	MOV	#170,PL.CL	;AND TIME, THAT'S IT
	BR	PLEXIT		;AND DO APPROPRIATE EXIT
PLSAVB:	.BYTE	0		;SAVE PLOTTER BYTE HERE
PLERWT:	.BYTE	0		;EOF SPOOL WAIT SW.SET TO 10 BY CLOSE
	.IFDF	$PL311
MASK:	.BYTE	0		;##137##DEFAULT, NO CONSOLE FOR 311
	.ENDC
	.IFNDF	$PL311
MASK:	.BYTE	4		;##137##DEFAULT, OFF LINE FOR XY11
	.ENDC
;
;
;
;  THE FOLLOWING IS A TABLE OF BYTES TO DESCRIBE THE STARTING
;  ADDRESSES OF THE STROKES WHICH MAKE UP THE CHARACTERS
;  IN ORDER TO FIT THESE ADDRESSES INTO SINGLE BYTES, THESE BYTES HAVE
;  THE FORM [ADDRESS-TOP OF STROKE TABLE ADDRESS-8*(CHAR-BLANK)]
;  CHAR-BLANK IS THE DIFFERENCE IN THE ASCII CHARACTER VALUES BETWEEN
;  THE CHARACTER IN QUESTION AND BLANK. I.E. FOR A 'B', IT WOULD
;  BE 42 OCTAL.  THE VALUE OF 8 IS EASY TO MULTIPLY BY, AND TURNS
;  OUT TO BE ROUGHLY THE AVERAGE NUMBER OF STROKES PER CHARACTER.
;
;  FURTHERMORE, THE DIFFERENCE IN ADJACENT TABLE ENTRIES+8 GIVES
;  A CONTROL COUNT FOR # OF STROKES PER CHARACTER.
;
;  NOTE, THE PDP-15 RESTRICTS THE CHARACTER RANGE SENT TO 40-137.
;
TABPNT:	.BYTE	KCTBLA-TABCHR
	.BYTE	KCTEXC-TABCHR-10
	.BYTE	KCTDQO-TABCHR-20
	.BYTE	KCTPOU-TABCHR-30
	.BYTE	KCTDOL-TABCHR-40
	.BYTE	KCTPCT-TABCHR-50
	.BYTE	KCTAMP-TABCHR-60
	.BYTE	KCTSQO-TABCHR-70
	.BYTE	KCTOPR-TABCHR-100
	.BYTE	KCTCPR-TABCHR-110
	.BYTE	KCTAST-TABCHR-120
	.BYTE	KCTPLU-TABCHR-130
	.BYTE	KCTCOM-TABCHR-140
	.BYTE	KCTMIN-TABCHR-150
	.BYTE	KCTPER-TABCHR-160
	.BYTE	KCTSLA-TABCHR-170
	.BYTE	KCT0-TABCHR-200
	.BYTE	KCT1-TABCHR-210
	.BYTE	KCT2-TABCHR-220
	.BYTE	KCT3-TABCHR-230
	.BYTE	KCT4-TABCHR-240
	.BYTE	KCT5-TABCHR-250
	.BYTE	KCT6-TABCHR-260
	.BYTE	KCT7-TABCHR-270
	.BYTE	KCT8-TABCHR-300
	.BYTE	KCT9-TABCHR-310
	.BYTE	KCTCOL-TABCHR-320
	.BYTE	KCTSEM-TABCHR-330
	.BYTE	KCTOAN-TABCHR-340
	.BYTE	KCTEQU-TABCHR-350
	.BYTE	KCTCAN-TABCHR-360
	.BYTE	KCTQES-TABCHR-370
	.BYTE	KCTATS-TABCHR-400
	.BYTE	KCTA-TABCHR-410
	.BYTE	KCTB-TABCHR-420
	.BYTE	KCTC-TABCHR-430
	.BYTE	KCTD-TABCHR-440
	.BYTE	KCTE-TABCHR-450
	.BYTE	KCTF-TABCHR-460
	.BYTE	KCTG-TABCHR-470
	.BYTE	KCTH-TABCHR-500
	.BYTE	KCTI-TABCHR-510
	.BYTE	KCTJ-TABCHR-520
	.BYTE	KCTK-TABCHR-530
	.BYTE	KCTL-TABCHR-540
	.BYTE	KCTM-TABCHR-550
	.BYTE	KCTN-TABCHR-560
	.BYTE	KCTO-TABCHR-570
	.BYTE	KCTP-TABCHR-600
	.BYTE	KCTQ-TABCHR-610
	.BYTE	KCTR-TABCHR-620
	.BYTE	KCTS-TABCHR-630
	.BYTE	KCTT-TABCHR-640
	.BYTE	KCTU-TABCHR-650
	.BYTE	KCTV-TABCHR-660
	.BYTE	KCTW-TABCHR-670
	.BYTE	KCTX-TABCHR-700
	.BYTE	KCTY-TABCHR-710
	.BYTE	KCTZ-TABCHR-720
	.BYTE	KCTOSQ-TABCHR-730
	.BYTE	KCTBSL-TABCHR-740
	.BYTE	KCTCSQ-TABCHR-750
	.BYTE	KCTUAR-TABCHR-760
	.BYTE	KCTBAR-TABCHR-770
	.BYTE	KCTEOT-TABCHR-1000
	.BYTE	KCTEOF-TABCHR-1010	;CONTROL FOR 140 FLUSH OUT BYTE
;
;  CHARACTER TABLE
;
;  CHARACTERS ARE DECRIBED AS ABSOLUTE CO-ORDINATE POINTS ON
;  AN 11X11 GRID. A BYTE DESCRIBES AN X-Y CO-ORDINATE PAIR.
;  THE FORMAT IS 16*X+Y. NUMBERS ARE INDECIMAL FOR VIEWING
;  CONVENIENCE. IT IS ASSUMED THAT THE MOVE TO GET TO THE
;  FIRST CO-ORDINATE PAIR IS UNINTENSIFIED. OTHERWISE
;  THE PEN WILL STAY DOWN THRU THE CHARACTER. EXCEPTION, THE
;  BYTE -1 SAYS MOVE THE PEN UP FOR NEXT STROKE ONLY.
;  LOGIC IN TOP OF LOOP PUTS PEN DOWN UNLESS OTHERWISE NOTIFIED.
;  AT THE END OF THE CHARACTER THE PEN (IN CONCEPT) IS MOVED TO LOWER
;  RIGHT CORNER OF THE 'BOX' CONTAINING THE CHAR. IN
;  PRACTICE THAT MOVE IS ADDED TO THE UNINTENSIFIED STROKE
;  LEADING OFF THE NEXT CHAR.
;
;  Y VALUES RANGE 0-10, I.E. THE WHOLE BOX. X VALUES RANGE FROM 1-9;
;  THIS GIVES THE INTERCHARACTER SPACING ALONG X-AXIS. CNETERING
;  OF THE CHARACTER IN TE BOX IS DISCUSSED AT THE TOP OF THE PLOTTER SECTION.
;  CHRACTER STROKES MAY BE CHANGED OR REMOVED ENTIRELY. NOTE THAT
;  IF THERE ARE NO STROKES FOR A CHARACTER (SEE BLANK (KCTBLA)), A BALNK
;  CHARACTER WILL BE PRODUCED. IT MIGHT PROVE CONVENIENT TO
;  DO THIS IF CORE WAS TIGHT, AND SOME OF THE ASCII SET WAS NOT TO
;  BE USED. IT IS NOT NECESSARY TO CHANGE TABPNT TABLE WHEN CHANGING
;  CHARACTER STROKES. YOU MUST, HOWEVER, LEAVE IN ALL THE LABELS!
;
;
	.RADIX 10
;
TABCHR:				;TOP OF TABLE ADDRESS FOR TABPNT
;
KCTBLA:				;BLANK
KCTEXC:
	.BYTE	16*4+0		;!
	.BYTE	16*6+0
	.BYTE	16*6+2
	.BYTE	16*4+2
	.BYTE	16*4+0
	.BYTE	-1		;LIFT PEN
	.BYTE	16*5+3
	.BYTE	16*4+6
	.BYTE	16*4+10
	.BYTE	16*6+10
	.BYTE	16*6+6
	.BYTE	16*5+3
KCTDQO:
	.BYTE	16*3+7		;"
	.BYTE	16*3+8
	.BYTE	16*2+8
	.BYTE	16*2+10
	.BYTE	16*4+10
	.BYTE	16*4+8
	.BYTE	16*3+7
	.BYTE	-1
	.BYTE	16*7+7
	.BYTE	16*7+8
	.BYTE	16*6+8
	.BYTE	16*6+10
	.BYTE	16*8+10
	.BYTE	16*8+8
	.BYTE	16*7+7
KCTPOU:
	.BYTE	16*1+4		;#
	.BYTE	16*4+4
	.BYTE	16*4+0
	.BYTE	16*4+4
	.BYTE	16*6+4
	.BYTE	16*6+0
	.BYTE	16*6+4
	.BYTE	16*9+4
	.BYTE	16*6+4
	.BYTE	16*6+6
	.BYTE	16*9+6
	.BYTE	16*6+6
	.BYTE	16*6+10
	.BYTE	16*6+6
	.BYTE	16*4+6
	.BYTE	16*4+10
	.BYTE	16*4+6
	.BYTE	16*1+6
	.BYTE	16*4+6
	.BYTE	16*4+4
KCTDOL:
	.BYTE	16*2+2		;$
	.BYTE	16*3+1
	.BYTE	16*7+1
	.BYTE	16*8+2
	.BYTE	16*8+4
	.BYTE	16*7+5
	.BYTE	16*3+5
	.BYTE	16*2+6
	.BYTE	16*2+8
	.BYTE	16*3+9
	.BYTE	16*5+9
	.BYTE	16*7+9
	.BYTE	16*8+8
	.BYTE	16*7+9
	.BYTE	16*5+9
	.BYTE	16*5+10
	.BYTE	16*5+0
KCTPCT:
	.BYTE	16*1+1		;%
	.BYTE	16*9+9
	.BYTE	-1
	.BYTE	16*3+9
	.BYTE	16*1+9
	.BYTE	16*1+7
	.BYTE	16*3+7
	.BYTE	16*3+9
	.BYTE	-1
	.BYTE	16*7+3
	.BYTE	16*9+3
	.BYTE	16*9+1
	.BYTE	16*7+1
	.BYTE	16*7+3
KCTAMP:
	.BYTE	16*9+1		;&
	.BYTE	16*3+7
	.BYTE	16*3+9
	.BYTE	16*4+10
	.BYTE	16*5+10
	.BYTE	16*6+9
	.BYTE	16*6+7
	.BYTE	16*5+6
	.BYTE	16*3+6
	.BYTE	16*1+4
	.BYTE	16*1+1
	.BYTE	16*2+0
	.BYTE	16*6+0
	.BYTE	16*9+3
KCTSQO:
	.BYTE	16*5+7		;'
	.BYTE	16*5+8
	.BYTE	16*4+8
	.BYTE	16*4+10
	.BYTE	16*6+10
	.BYTE	16*6+8
	.BYTE	16*5+7
KCTOPR:
	.BYTE	16*7+10		;(
	.BYTE	16*5+8
	.BYTE	16*5+2
	.BYTE	16*7+0
KCTCPR:
	.BYTE	16*3+0		;)
	.BYTE	16*5+2
	.BYTE	16*5+8
	.BYTE	16*3+10
KCTAST:
	.BYTE	16*3+3		;*
	.BYTE	16*5+5
	.BYTE	16*7+7
	.BYTE	16*5+5
	.BYTE	16*3+7
	.BYTE	16*5+5
	.BYTE	16*7+3
	.BYTE	16*5+5
	.BYTE	16*2+5
	.BYTE	16*5+5
	.BYTE	16*8+5
KCTPLU:
	.BYTE	16*2+5		;+
	.BYTE	16*8+5
	.BYTE	16*5+5
	.BYTE	16*5+8
	.BYTE	16*5+5
	.BYTE	16*5+2
KCTCOM:
	.BYTE	16*5+0		;,
	.BYTE	16*5+1
	.BYTE	16*4+1
	.BYTE	16*4+3
	.BYTE	16*6+3
	.BYTE	16*6+1
	.BYTE	16*5+0
KCTMIN:
	.BYTE	16*2+5		;-
	.BYTE	16*8+5
KCTPER:
	.BYTE	16*4+1		;.
	.BYTE	16*6+1
	.BYTE	16*6+3
	.BYTE	16*4+3
	.BYTE	16*4+1
KCTSLA:
	.BYTE	16*1+1		;/
	.BYTE	16*9+9
KCT0:
	.BYTE	16*2+1		;0
	.BYTE	16*1+3
	.BYTE	16*1+7
	.BYTE	16*2+9
	.BYTE	16*4+10
	.BYTE	16*6+10
	.BYTE	16*8+9
	.BYTE	16*9+7
	.BYTE	16*9+3
	.BYTE	16*8+1
	.BYTE	16*6+0
	.BYTE	16*4+0
	.BYTE	16*2+1
KCT1:
	.BYTE	16*2+7		;1
	.BYTE	16*5+10
	.BYTE	16*5+0
	.BYTE	16*1+0
	.BYTE	16*5+0
	.BYTE	16*9+0
KCT2:
	.BYTE	16*1+9		;2
	.BYTE	16*2+10
	.BYTE	16*8+10
	.BYTE	16*9+9
	.BYTE	16*9+6
	.BYTE	16*8+5
	.BYTE	16*2+5
	.BYTE	16*1+4
	.BYTE	16*1+0
	.BYTE	16*9+0
KCT3:
	.BYTE	16*1+9		;3
	.BYTE	16*2+10
	.BYTE	16*8+10
	.BYTE	16*9+9
	.BYTE	16*9+6
	.BYTE	16*8+5
	.BYTE	16*3+5
	.BYTE	16*8+5
	.BYTE	16*9+4
	.BYTE	16*9+1
	.BYTE	16*8+0
	.BYTE	16*2+0
	.BYTE	16*1+1
KCT4:
	.BYTE	16*9+3		;4
	.BYTE	16*1+3
	.BYTE	16*8+10
	.BYTE	16*8+0
KCT5:
	.BYTE	16*1+1		;5
	.BYTE	16*2+0
	.BYTE	16*8+0
	.BYTE	16*9+1
	.BYTE	16*9+5
	.BYTE	16*8+6
	.BYTE	16*1+6
	.BYTE	16*1+10
	.BYTE	16*9+10
KCT6:
	.BYTE	16*1+4		;6
	.BYTE	16*2+5
	.BYTE	16*8+5
	.BYTE	16*9+4
	.BYTE	16*9+1
	.BYTE	16*8+0
	.BYTE	16*2+0
	.BYTE	16*1+1
	.BYTE	16*1+4
	.BYTE	16*1+9
	.BYTE	16*2+10
	.BYTE	16*8+10
	.BYTE	16*9+9
KCT7:
	.BYTE	16*1+10		;7
	.BYTE	16*9+10
	.BYTE	16*1+0
KCT8:
	.BYTE	16*2+0		;8
	.BYTE	16*1+1
	.BYTE	16*1+4
	.BYTE	16*2+5
	.BYTE	16*8+5
	.BYTE	16*2+5
	.BYTE	16*1+6
	.BYTE	16*1+9
	.BYTE	16*2+10
	.BYTE	16*8+10
	.BYTE	16*9+9
	.BYTE	16*9+6
	.BYTE	16*8+5
	.BYTE	16*9+4
	.BYTE	16*9+1
	.BYTE	16*8+0
	.BYTE	16*2+0
KCT9:
	.BYTE	16*1+1		;9
	.BYTE	16*2+0
	.BYTE	16*8+0
	.BYTE	16*9+1
	.BYTE	16*9+6
	.BYTE	16*9+9
	.BYTE	16*8+10
	.BYTE	16*2+10
	.BYTE	16*1+9
	.BYTE	16*1+6
	.BYTE	16*2+5
	.BYTE	16*8+5
	.BYTE	16*9+6
KCTCOL:
	.BYTE	16*4+6		;:
	.BYTE	16*4+8
	.BYTE	16*6+8
	.BYTE	16*6+6
	.BYTE	16*4+6
	.BYTE	-1
	.BYTE	16*6+4
	.BYTE	16*6+2
	.BYTE	16*4+2
	.BYTE	16*4+4
	.BYTE	16*6+4
KCTSEM:
	.BYTE	16*4+6		;;
	.BYTE	16*4+8
	.BYTE	16*6+8
	.BYTE	16*6+6
	.BYTE	16*4+6
	.BYTE	-1
	.BYTE	16*6+4
	.BYTE	16*6+2
	.BYTE	16*5+1
	.BYTE	16*5+2
	.BYTE	16*4+2
	.BYTE	16*4+4
	.BYTE	16*6+4
KCTOAN:
	.BYTE	16*7+10		;<
	.BYTE	16*2+5
	.BYTE	16*7+0
KCTEQU:
	.BYTE	16*2+3		;=
	.BYTE	16*8+3
	.BYTE	-1
	.BYTE	16*2+7
	.BYTE	16*8+7
KCTCAN:
	.BYTE	16*3+10		;>
	.BYTE	16*8+5
	.BYTE	16*3+0
KCTQES:
	.BYTE	16*2+9		;?
	.BYTE	16*3+10
	.BYTE	16*7+10
	.BYTE	16*8+9
	.BYTE	16*8+7
	.BYTE	16*7+6
	.BYTE	16*6+6
	.BYTE	16*5+5
	.BYTE	16*5+3
	.BYTE	-1
	.BYTE	16*6+2
	.BYTE	16*6+0
	.BYTE	16*4+0
	.BYTE	16*4+2
	.BYTE	16*6+2
KCTATS:
	.BYTE	16*4+1		;@
	.BYTE	16*2+3
	.BYTE	16*2+7
	.BYTE	16*4+9
	.BYTE	16*6+9
	.BYTE	16*8+7
	.BYTE	16*8+3
	.BYTE	16*7+2
	.BYTE	16*6+3
	.BYTE	16*5+3
	.BYTE	16*4+4
	.BYTE	16*4+6
	.BYTE	16*5+7
	.BYTE	16*6+7
	.BYTE	16*6+3
KCTA:
	.BYTE	16*1+0		;A
	.BYTE	16*3+5
	.BYTE	16*5+10
	.BYTE	16*7+5
	.BYTE	16*3+5
	.BYTE	16*7+5
	.BYTE	16*9+0
KCTB:
	.BYTE	16*1+0		;B
	.BYTE	16*1+5
	.BYTE	16*1+10
	.BYTE	16*8+10
	.BYTE	16*9+9
	.BYTE	16*9+6
	.BYTE	16*8+5
	.BYTE	16*1+5
	.BYTE	16*8+5
	.BYTE	16*9+4
	.BYTE	16*9+1
	.BYTE	16*8+0
	.BYTE	16*1+0
KCTC:
	.BYTE	16*9+9		;C
	.BYTE	16*8+10
	.BYTE	16*2+10
	.BYTE	16*1+9
	.BYTE	16*1+1
	.BYTE	16*2+0
	.BYTE	16*8+0
	.BYTE	16*9+1
KCTD:
	.BYTE	16*1+0		;D
	.BYTE	16*1+10
	.BYTE	16*8+10
	.BYTE	16*9+9
	.BYTE	16*9+1
	.BYTE	16*8+0
	.BYTE	16*1+0
KCTE:
	.BYTE	16*9+10		;E
	.BYTE	16*1+10
	.BYTE	16*1+5
	.BYTE	16*6+5
	.BYTE	16*1+5
	.BYTE	16*1+0
	.BYTE	16*9+0
KCTF:
	.BYTE	16*1+0		;F
	.BYTE	16*1+5
	.BYTE	16*6+5
	.BYTE	16*1+5
	.BYTE	16*1+10
	.BYTE	16*9+10
KCTG:
	.BYTE	16*9+9		;G
	.BYTE	16*8+10
	.BYTE	16*2+10
	.BYTE	16*1+9
	.BYTE	16*1+1
	.BYTE	16*2+0
	.BYTE	16*8+0
	.BYTE	16*9+1
	.BYTE	16*9+5
	.BYTE	16*6+5
KCTH:
	.BYTE	16*1+0		;H
	.BYTE	16*1+5
	.BYTE	16*1+10
	.BYTE	16*1+5
	.BYTE	16*9+5
	.BYTE	16*9+10
	.BYTE	16*9+5
	.BYTE	16*9+0
KCTI:
	.BYTE	16*2+0		;I
	.BYTE	16*5+0
	.BYTE	16*8+0
	.BYTE	16*5+0
	.BYTE	16*5+10
	.BYTE	16*2+10
	.BYTE	16*5+10
	.BYTE	16*8+10
KCTJ:
	.BYTE	16*1+2		;J
	.BYTE	16*1+1
	.BYTE	16*2+0
	.BYTE	16*8+0
	.BYTE	16*9+1
	.BYTE	16*9+10
KCTK:
	.BYTE	16*1+0		;K
	.BYTE	16*1+4
	.BYTE	16*1+10
	.BYTE	16*1+4
	.BYTE	16*4+7
	.BYTE	16*7+10
	.BYTE	16*4+7
	.BYTE	16*9+0
KCTL:
	.BYTE	16*1+10		;L
	.BYTE	16*1+0
	.BYTE	16*9+0
KCTM:
	.BYTE	16*1+0		;M
	.BYTE	16*1+10
	.BYTE	16*5+0
	.BYTE	16*9+10
	.BYTE	16*9+0
KCTN:
	.BYTE	16*1+0		;N
	.BYTE	16*1+10
	.BYTE	16*9+0
	.BYTE	16*9+10
KCTO:
	.BYTE	16*1+1		;O
	.BYTE	16*1+9
	.BYTE	16*2+10
	.BYTE	16*8+10
	.BYTE	16*9+9
	.BYTE	16*9+1
	.BYTE	16*8+0
	.BYTE	16*2+0
	.BYTE	16*1+1
KCTP:
	.BYTE	16*1+0		;P
	.BYTE	16*1+5
	.BYTE	16*1+10
	.BYTE	16*8+10
	.BYTE	16*9+9
	.BYTE	16*9+6
	.BYTE	16*8+5
	.BYTE	16*1+5
KCTQ:
	.BYTE	16*7+2		;Q
	.BYTE	16*8+1
	.BYTE	16*9+3
	.BYTE	16*9+7
	.BYTE	16*8+9
	.BYTE	16*6+10
	.BYTE	16*4+10
	.BYTE	16*2+9
	.BYTE	16*1+7
	.BYTE	16*1+3
	.BYTE	16*2+1
	.BYTE	16*4+0
	.BYTE	16*6+0
	.BYTE	16*8+1
	.BYTE	16*9+0
KCTR:
	.BYTE	16*1+0		;R
	.BYTE	16*1+5
	.BYTE	16*1+10
	.BYTE	16*8+10
	.BYTE	16*9+9
	.BYTE	16*9+6
	.BYTE	16*8+5
	.BYTE	16*4+5
	.BYTE	16*1+5
	.BYTE	16*4+5
	.BYTE	16*9+0
KCTS:
	.BYTE	16*1+1		;S
	.BYTE	16*2+0
	.BYTE	16*8+0
	.BYTE	16*9+1
	.BYTE	16*9+4
	.BYTE	16*8+5
	.BYTE	16*2+5
	.BYTE	16*1+6
	.BYTE	16*1+9
	.BYTE	16*2+10
	.BYTE	16*8+10
	.BYTE	16*9+9
KCTT:
	.BYTE	16*5+0		;T
	.BYTE	16*5+10
	.BYTE	16*1+10
	.BYTE	16*5+10
	.BYTE	16*9+10
KCTU:
	.BYTE	16*1+10		;U
	.BYTE	16*1+1
	.BYTE	16*2+0
	.BYTE	16*8+0
	.BYTE	16*9+1
	.BYTE	16*9+10
KCTV:
	.BYTE	16*1+10		;V
	.BYTE	16*5+0
	.BYTE	16*9+10
KCTW:
	.BYTE	16*1+10		;W
	.BYTE	16*3+0
	.BYTE	16*5+10
	.BYTE	16*7+0
	.BYTE	16*9+10
KCTX:
	.BYTE	16*1+0		;X
	.BYTE	16*5+5
	.BYTE	16*9+10
	.BYTE	16*5+5
	.BYTE	16*1+10
	.BYTE	16*5+5
	.BYTE	16*9+0
KCTY:
	.BYTE	16*1+10		;Y
	.BYTE	16*5+5
	.BYTE	16*9+10
	.BYTE	16*5+5
	.BYTE	16*5+0
KCTZ:
	.BYTE	16*1+10		;Z
	.BYTE	16*9+10
	.BYTE	16*1+0
	.BYTE	16*9+0
KCTOSQ:
	.BYTE	16*7+10		;[
	.BYTE	16*5+10
	.BYTE	16*5+0
	.BYTE	16*7+0
KCTBSL:
	.BYTE	16*1+9		;\
	.BYTE	16*9+1
KCTCSQ:
	.BYTE	16*3+10		;]
	.BYTE	16*5+10
	.BYTE	16*5+0
	.BYTE	16*3+0
KCTUAR:
	.BYTE	16*3+8		;^
	.BYTE	16*5+10
	.BYTE	16*7+8
	.BYTE	16*5+10
	.BYTE	16*5+0
KCTBAR:
	.BYTE	16*3+3		;_
	.BYTE	16*1+5
	.BYTE	16*3+7
	.BYTE	16*1+5
	.BYTE	16*9+5
KCTEOT:
	.RADIX 8
	.BYTE	0		;140 FORCE MOVE TO RIGHT OF LAST CHAR
;
KCTEOF:				;ADDR FOR CONTROL CALCULATE ON 140
;
MAGIC:	.BYTE	140		;THE 140 TO FEED IN, SINCE DOESN'T COME
;				;FROM THE PDP-15
;
	.NLIST
	.ENDC
;
	.IFDF	$LV
	.LIST
	.SBTTL	LINE PRINTER/PLOTTER  DRIVER FOR LV11/15
	.EVEN
;
LVCSR=164000
LVBUF=164002
LVSA=6
LVIOT=12
LVSTAT=14
LVEOF=6414
LVEST=LV.EST+4	;ADDR IN PIREX ERROR TABLE FOR NOT READY
LVUNN=LV.EST+2	;ADDR FOR UNIT # (FOR NOW 0)
LVTCOD=10	;VERSATEK TASK CODE
;
;
;
;
;  MAKE THE PDP-15 DO ALL THE WORK. THE PDP-11 SIMPLY GET S A COUNT
;  OF CHARACTERS TO PRINT OUT. WE TREAT THE CONTROL CHARACTERS
;  12,15, AND 14 ONLY. A MINUS CHARACTER IS CONVERTED INTO MINUS
;  THAT NUMBER OF SPACES. NOTE ALL REAL ASCII CHAR'S HAVE A ZERO LEADING BIT!
;  EACH LINE HAS AN IMPLIED CARRIAGE RETURN THAT IS ADDED BY THE DRIVER
;  RATHER THAN SENT BY THE PDP-15
;
;  NOTE, IF HEADER WORD OF BUFFER HAS 400 BIT SET, IT IS
;  IMAGE MODE, AND WE NIETHER BUT ON LF OR CR!!
;
;
; CALL TO ROUTINE HAS ADDRESS OF TCB IN HANDLER BUSY (IDLE) REGISTER
;
	.BLOCK	8.+EAESTK*4
	.WORD	LVCSR		;ADDRESS OF LVCSR CONTROL STATUS
				;    REGISTER USED TO RESET DEVICE
				;    ON STOP I/O OPERATIONS.
	.WORD	0		;TCB POINTER (EXTENDED BITS)
	.WORD	0		;TCB POINTER (LOWER 16 BITS). THIS
				;    WORD IS USED AS THE IDLE/BUSY
				;    SWITCH FOR THE DEVICE DRIVER.
;
LV:
	CLR	LV.CL		;CLEAR OUT ANY PENDING TIMER REQUESTS FOR US.
	MOV	LV-2,R0		;SETUP R0 TO POINT TO TCB
	CLR	LVSTAT(R0)	;CLEAR STATUS FLAG IN TCB
	CLR	LVPLT		;CLEAR PLOT MODE FLAG
	MOV	LVSA+2(R0),R1	;GET BUFFER START ADDRESS
	TST	LVSA(R0)	;DON'T RELOCATE ADDRESS IF BIT 15
	BMI	1$		;    IS ON.
	ASL	R1		;RELOCATE ADDRESS (WORD TO BYTE POINTER)
	ADD	MEMSIZ,R1	;(+ 11'S OWN LOCAL MEMORY)
	MOV	16(R0),R2	;GET TRAN WORD COUNT
	BMI	6$
1$:	MOVB	(R1)+,R2
	BIC	#177400,R2	;CLEAR OUT TOP OF REGISTER
	MOVB	#15,LVEOL	;DEFAULT, ASCII, HERE IS <CR>
	CMPB	(R1)+,(R1)+	;R1=R1+2
	MOVB	#12,(R1)+	;DEFAULT, PRECEED LINE WITH LINE FEED
	CLRB	LVERWT		;RESET ERROR WAIT SWITCH
	.IFNDF	$NOSW		;##124##
	BIT	#140000,SPOLSW	;SPOOLER ENABLED & RUNNNG
	BEQ	2$
	CMP	#LVEOF,(R1)	;EOF RECORD?
	BNE	2$
	BIT	#40,SW		;CONSOLE SW. BIT '2' UP?
				;INDICATES WAIT AFTER NEXT EOF RECORD
	BEQ	2$
	MOV	#40,LVMASK	;SETUP TIMER MASK
	MOV	#SW,LVADDR	;SETUP TIMER ADRESS
	INCB	LVERWT		;SET ERROR WAIT SW.
	.ENDC
2$:	BITB	#1,-3(R1)	;400  BIT SET IN HEADER IF IMAGE
	BEQ	3$		;NOT IMAGE, CHECK FORMS CONTROL
	CLRB	LVEOL		;IMAGE, DON'T FORCE CR AFTER MESSAGE
	BR	4$		;ALLOW ALL FORMS CONTROL
3$:	CMPB	#14,(R1)	;FIRST CHAR FORM FEED?
	BEQ	4$		;YES, DON'T ADD LINE FEED TO LINE
	CMPB	#15,(R1)	;FIRST CHAR CARRIAGE RETURN
	BEQ	4$		;YES, DON'T ADD LINE FEED TO LINE
	DEC	R1		;MOVE POINTER BACK TO LINE FEED
	INC	R2		;COUNT ADDITION OF LF TO BUFFER
4$:	MOV	R2,LVBTCT	;SAVE COUNT
	MOV	R1,LVBUFF	;SAVE POINTER
	CLRB	LVTAB
	TSTB	LVBUF		;HISTORY SAYS THIS HERE
	BIS	#100,LVCSR	;ENABLE INTERRUPTS TO LV GOING
5$:	SEXIT	WAITST		;EXIT IN A WAIT STATE AND RESCAN
;				;    THE ATL NOW.
;
6$:	CLR	16(R0)		;DON'T KNOW WHY!???
	ASL	R2		;WORD COUNT TO BYTE COUNT
	MOV	#101,LVCSR	;SET UP FOR PLOT MODE
	TSTB	LVCSR		;READY?
	BPL	8$		;NO, SET UP TO WAIT FOR READY INTTRPT
	MOVB	(R1)+,LVBUF	;PLACE ON CHAR NOW, REST AFTER INTR.
7$:	MOV	R1,LVBUFF	;SAVE BUFFER POINTER
	MOV	R2,LVPLT	;WATCH IT, SAVE -COUNT-1  !!
	BR	5$
8$:	DEC	R2		;-1 FOR -COUNT-1
	BR	7$		;REJOIN
;
;
;	LV INTERRUPT ENTRANCE
;
LVINT:
	BIC	#100,LVCSR	;DISABLE LV INTERRUPT
	JSR	R0,R.SAVE	;SAVE REGISTERS
	LVTCOD			;TASK CODE
	MOV	LV-2,R0		;GET TCB POINTER
	BEQ	LVXT		;IGNORE IF ITS ALREADY BEEN STOPPED BY
				;    A STOP I/O REQUEST.
	TST	LVCSR		;CHECK FOR ERROR
	BMI	LVERR		;YES
	CLR	LV.CL		;CLEAR OUT ANY PENDING TIMER REQUEST FOR US.
	MOV	LVPLT,R2	;CHECK FOR PLOT MODE
	BMI	LVPIC		;YUP,GO DO IT
LVLOP:
	TSTB	LVCSR		;IS PRINTER CURRENTLY GOING?
	BPL	LVSTIL		;YES:  FORGET CHAR FOR NOW
	TSTB	LVTAB		;IN TAB EXPANSION TO SPACES?
	BMI	4$		;YES
	DEC	LVBTCT		;DECR CHAR COUNT
	BMI	5$		;WENT TO -1, MAKE CR TO FINISH LINE
	TSTB	@LVBUFF		;MINUS BYTE IS TAB EXPANSION COUNT
	BMI	6$		;IS ONE, GO SET UP
	MOVB	@LVBUFF,LVBUF	;STICK CHAR INTO LINE PRINTER BUFFER
	INC	LVBUFF		;MOVE POINTER TO NEXT CHAR
	BR	LVLOP		;GO DO NEXT
;
6$:	MOVB	@LVBUFF,LVTAB	;SET UP TAB COUNT (MINUS, A LA 15)
	INC	LVBUFF
4$:	INCB	LVTAB		;COUNT A SPACE FOR THIS TAB
	MOVB	#40,LVBUF	;SPACE TO LINE PRINTER
	BR	LVLOP		;GO DO NEXT
5$:	TSTB	LVEOL		;IMAGE OR ASCII
	BEQ	7$		;IMAGE, DON'T FORCE <CR>
	MOVB	LVEOL,LVBUF	;ASCII, HERE IS <CARRIAGE RETURN>
7$:	INC	LVSTAT(R0)	;SET REV TO GOOD COMPLETION
	BR	LVXIT
;
LVSTIL:	BIS	#100,LVCSR	;ENABLE INTERRUPT ON LV
	BR	LVXIT1		;RESTORE R0-R5 AND RETURN
;
LVERR:	INCB	LVERWT		;SET ERROR WAIT SW.
	MOVB	#4,LVEST	;ERROR CODE 1,NOT READY TO TABLE
	MOV	#100000,LVMASK	;SET TIMER MASK
	MOV	#LVCSR,LVADDR	;SET TIMER ADDRESS
LVERR1:	MOV	#LVCHK,LV.CL+2	;ADDR. FOR TIMER REQ.
	MOV	#170,LV.CL	;2 SECS. IN TICKS(OCTAL)
LVXIT1:	JMP	DEQU1		;SCHEDULE NEXT TASK
;
LVXIT:	CLRB	LVEST		;INDICATE SUCCESSFULL OPERATION
	TSTB	LVERWT		;ERROR WAIT?
	BNE	LVERR1
	BIS	#340,PS		;NO. INHIBIT INT.
	CLR	LVCSR		;SHUT LV INT. ENABLE
	MOV	#1,R1		;TELL CALLER DONE
	MOV	LV-2,R0		;GET TCBP
	CALL	SEND15		;TELL CALLER DONE
LVXT:
	BIS	#340,PS		;INHIBIT INTERRUPTS
	CLR	LV-2		;CLEAR BUSY(IDLE) FLAG
	CLR	LV-4
	MOV	#LV,R3		;DEQUEUE ANOTHER REQUEST IF ANY
	MOV	#LV.LH,R1	;    IN THIS DRIVERS DEQUE.
	JMP	DEQU
;
LVPIC:	INC	R2		;CHECK IF WE FINISHED LAST TIME
	BEQ	LVXIT		;YES, JUSTEXIT
	MOV	LVBUFF,R1	;SET UP FETCH POINTER
	MOV	#LVCSR,R3	;FOR QUICKER ACCESS TO STATUS
	MOV	#LVBUF,R4	;AND DATA REG'S
	MOV	#101,(R3)
1$:	TSTB	(R3)		;CAN TAKE A BYTE
	BPL	2$		;NOPE, GET OUT FOR NOW
	MOVB	(R1)+,(R4)	;DATA TO DEVICE
	INC	R2		;LOOP CONTROL
	BMI	1$		;MORE
2$:	DEC	R2		;MAKE -1 WAITING FOR COMPLETION INTR.
	MOV	R2,LVPLT
	MOV	R1,LVBUFF
	BR	LVXIT1
;
;
;		SUBROUTINE TO FIELD CLOCK COUNT-DOWN
;
;
LVCHK:	TST	LV-2		;HAVE WE BEEN DISABLED
	BEQ	10$		;IF YES, EXIT, LEAVING CLOCK DISABLED
	BIT	LVMASK,@LVADDR	;ERROR STILL EXISTS?
	BNE	7$
	CLRB	LVERWT		;NO. PROCESS REQ.
	MOV	#LVTCOD*2,R2	;SCAN ATL FOR OUR NODE
	MOV	ATLNP(R2),R1
	MOV	#LV,LV-12	;RESTART AT BEGINNING OF REQ.
	BIC	#17,A.TS(R1)	;R1 POINTS TO OUR NODE, MAKE RUNNABLE
	MOV	#LV-26,A.SP(R1)	;SET UP STACK POINTER
	ASR	R2		;MAKE BYTE ADDRESSING
	MOVB	LEVEL(R2),LV-10	;SET UP PS
	BR	10$
7$:	MOV	#170,(R0)	;R0 POINTS TO TIMER ENTRY
10$:	RTS	PC		;RETURNS TO CLOCK
;
LVBUFF:	.WORD	0		;BUFFER POINTER
LVPLT:	.WORD	0		;PLOT MODE BYTE COUNT AND SWITCH
LVBTCT:	.WORD	0		;BYTE COUNT
LVTAB:	.WORD	0		;TAB LOCATION
LVEOL:	.BYTE	0		;0 IF IMAGE, 15 IF ASCII
LVERWT:	.BYTE	0		;MAKE EVEN
LVMASK:	.WORD	0		;MASK FOR TIMER
LVADDR:	.WORD	0		;POINTER TO TIMER ERROR CHECK
;
	.NLIST
	.ENDC
;;
	.IFDF	$DT
	.LIST
	.SBTTL	DECTAPE DRIVER FOR DT11/15
	.EVEN
;
DTCST=177340	;CONTROL & STATUS REGISTER
DTCCM=177342	;COMMAND REGISTER
DTCWC=177344	;WORD COUNT ..
DTCBA=177346	;BUS ADDRESS ..
DTCDT=177350	;DATA ..
;
; TCB INDEX VARIABLES
DF=2
EV=4
BN=6
SA1=10
SA2=12
WC=14
FN=16
SA=20
RP1=22
RP2=24
RP3=26
;
; THIS IS A DECTAPE DRIVER ON THE PDP 11 FOR THE STANDARD
; DEVICE HANDLERS ON THE PDP 15
;
; CALLER SETS UP THE BUSY(IDLE) SWITCH(DT-2) TO POINT TO TCB
;
	.BLOCK	8.+EAESTK*2
	.WORD DTCCM
	.WORD 0
	.WORD 0
DT:
	MOV #10,DT.RTC	;INITIALIZE RETRY COUNT
L10=.-4
DTRST1:
	MOV DT-2,R0	;SETUP R0 TO POINT TO TCB
	MOV #DTCWC,R1	;GET ADDRESS OF WC REG.
	MOV WC(R0),(R1)	;SET UP WC
	PUSH SA2(R0)		;...STARTING ADDRESS
	MOV SA1(R0),R2		;DON'T RELOCATE ADDRESS IF
	BMI 1$			;    BIT 15 IS ON.
	ASL (SP)
	ROL R2
	ADD MEMSIZ,(SP)
	ADC R2
1$:	POP 2(R1)
	MOV BN(R0),DT.BRQ	;SAVE BLOCK # FOR LATER
DTRST2:
	CLRB DTINT	;SET INT. SW TO SEARCH
	MOV DT.BRQ,DT.BCK	;SET BLOCK CONTROL FOR SEARCH
	MOV #100,R3	;USED IN NEXT SEQUENCE
	MOV R3,DT.TAC	;SET TURN AROUND COUNT
	PUSH FN(R0)	;GET UNIT,DIR. & FUN.
	BIC #7517,(SP)	;CLEAR POSSIBLE GARBAGE
	TSTB R2		;XBA ON?
	BEQ 1$		;NO, SKIP XBA COMMAND REG. SET UP
	BIC #177774,R2	;REMOVE GARBAGE BITS
	ASL R2		;SHIFT LEFT(4) TO PROPER POS.
	ASL R2
	ASL R2
	ASL R2
	BIS R2,(SP)	;SET UP XBA BITS IN COMMAND REG.
1$:	MOVB (SP),DT.FRQ	;SAVE FUN. FOR LATER
	MOVB #102,(SP)	;RESET FUN. TO SEARCH
	ASL R3		;(NOW CONTAINS 200)
	BIT (SP),#4000	;TRAVEL FWD.?
	BNE 2$
	INC R3		;IF SO, R3 NOW =201 & SO...
2$:	MOVB R3,DT.SSW	;MAKING BPL OR BMI AS REQD.
	POP -(R1)	;SET DT COMMAND REG.
	SEXIT	WAITST		;EXIT IN A WAIT STATE AND RESCAN
				;    THE ATL NOW.
;
;
; INTERRUPT SERVICE- SEARCH COMPLETE?
;
DT.SIP:
	TST @#DTCCM	;CHK. FOR ERROR
	BMI DT.SER	;IF ERROR, FIND WHAT ERROR
	CMP @#DTCDT,DT.BRQ	;CHK. IF BLOCK FOUND
	BEQ DT.BFD	;YES, CHK. DIR. OF ROT.
	BMI DT.SXT	;NO, GET TO BLOCK THIS WAY?
DT.SSW=.-1		;(BPL IF BKWD.)
DT.TA1:
	BICB #40,PS	;LOWER PRIORITY TO LVL 6
	ASRB #0		;HOW MANY TURNS
DT.TAC=.-2
	BCS DT.BER	;IF 6, CAN'T FIND BLOCK?
	PUSH #4000	;OTHERWISE MUST TURN AROUND
	PUSH #2		;ASSUME TRAVEL NOW FWD.
	RORB DT.SSW	;CHK. DIR.
	BCS DT.TA2	;IF FWD., OMIT NEXT 2 INST.
	NEG 2(SP)	;BKWD., REVERSE ALL
	NEG (SP)
DT.TA2:	SUB (SP)+,DT.BRQ	;ALLOW 2 BLOCKS FOR TURN AROUND
	ADD (SP)+,@#DTCCM	;DISABLE DELAY INHIBIT
	ROLB DT.SSW	;RESET DIR. SW(C BIT REVERSES)
DT.SXT:	.INH			;INHIBIT INTERRUPTS WHILE LOOKING
	TST DT-2		;    AT TCBP FOR THIS REQUEST SINCE
	BEQ DT.SX1		;    IT COULD CHANGE ON US IN THE
				;    MIDDLE.
	INCB @#DTCCM	;CONTINUE SEARCH
DT.SX1:	.ENA			;REENABLE INTERRUPTS
	JMP DEQU1
;BLOCK FOUND- CHK. TRAVEL DIR.
;
DT.BFD:
	CMP #0,#0	;TRAVEL AS BEFORE?
DT.BRQ=.-4
DT.BCK=.-2
	BNE DT.TA1	;NO, MUST TURN AROUND
	INCB DTINT	;RESET INT. SW FOR TFR.
	MOVB #0,@#DTCCM
DT.FRQ=.-4
	JMP	DEQU1
;
; INTERRUPT SERVICE- TRANSFER COMPLETE?
;
DTINT:
	BR .+2		;INTERRUPT SW ....
	BR DT.SIP	;FOR SEARCH COMES HERE
	JSR R0,R.SAVE	;SAVE REGS.
	3		;TASK CODE
	BICB #40,PS	;LOWER TO LVL 6
	MOV #DTCCM,R1	;GET COMMAND REG. ADDRESS
	TST (R1)	;ERROR CAUSE INT.?
	BMI DT.TER	;IF YES, CHK. WHY?
	MOV #1,EVAR	;NO, INDICATE IN EV
DTNXIT:
	MOVB L10,(R1)	;STOP TAPE
DTXIT:
	MOV DT-2,R0	;GET TCB ADDRESS IN R0
	BEQ	DTXT		;IGNORE IF ITS ALREADY BEEN STOPPED BY
				;    A STOP I/O REQUEST.
	MOV DTCCM,RP1(R0)	;RETURN INFO. TO 15 ......
	MOV DTCWC,RP2(R0)	; ......
	MOV DTCBA,RP3(R0)	; ......
	MOV DTCST,SA(R0)	; ......
	BIS #340,PS		;INHIBIT INTERRUPTS
	MOV EVAR,R1	;LOAD R1 WITH EV
	CALL SEND15	; ....& TELL 15 CURRENT REQ. COMPLETE
DTXT:
	BIS #340,PS		;INHIBIT INTERRUPTS
	CLR DT-2		;CLEAR BUSY SW
	CLR DT-4
	MOV #DT,R3	;SET UP FOR DEQUEUE
	MOV #DT.LH,R1
	JMP DEQU	;CLEAN LIST & CHK. ANY MORE REQ.
DTINXT:
	JMP DEQU1
;
; SEARCH ERROR- DETERMINE CAUSE?
;
DT.SER:
	TST @#DTCST	;IN END ZONE?
	BMI DT.TA1	;IF YES, TURN AROUND
	BICB #40,PS	;LOWER TO LVL 6
	MOV #-1,EVAR	;SET EV TO SEARCH ERROR
	BR DTNXIT	;CALL 15, CLEAN UP & EXIT
;
; BLOCK NOT FOUND ON SEARCH
;
DT.BER:
	MOV #-2,EVAR	;REFLECT IN EV
	BR DTNXIT	;CALL 15, CLEAN UP & EXIT
;
; TRANSFER ERROR
;
DT.TER:
	BIT #14000,-(R1)	;ILO/SELE ERROR?
	BNE DT.ER1	;IF SO, REFLECT IN EV & EXIT
	BIT #100400,(R1)+	;ENDZ/NEX ?
	BNE DT.FER	;IF SO, REFLECT IN EV & EXIT
	BIT #20000,-(R1)	;MTE ?
	BNE DT.ER2		;IF SO,REFLECT IN EV & EXIT
	MOV DT-2,R0	;GET TCB ADDRESS IN R0
	BEQ	DTXT		;IGNORE IF ITS ALREADY BEEN STOPPED BY
				;    A STOP I/O REQUEST.
;
; RECOVERABLE ERRORS- TIMING/PARITY
;
	ASL #0		;TRIED 8 TIMES ?
DT.RTC=.-2
	BCC DT.RXT	;IF NOT, RETRY
	MOV #-5,EVAR	;YES, REFLECT IN EV
	MOVB L10,(R1)+	;STOP TAPE IN CASE ......
	MOV 1(R1),R2	;ELSE GET WC IN TCB ....
	BEQ DTXIT	;IF SO, THATS IT!
	SUB WC(R0),R2	;ELSE GET WC IN TCB
	SWAB R2		; .....& # OF BLOCKS DONE
	BITB L10,(R1)+	;CHK. PRESENT TRAVEL DIR.
	BEQ 1$
	NEG R2
1$:	ADD R2,DT.BRQ	;MODIFY SEARCH START BLOCK #
	MOV L10,DT.RTC	; ....RESET RETRY COUNT
	TST (R1)+	;BUMP R1 TO POINT DTCWC
	MOV #DTRST2,R3	;GO SET UP & RESTART
	BR DTRTRY	; .....& TAKE INTERIM EXIT
;
; FATAL ERROR- END ZONE/NEXM
;
DT.FER:
	MOV #-4,EVAR	;REFLECT IN EV
	BR DTNXIT	; ....TELL 15,RESET ALL, EXIT
;
; PARITY/TIMING ERROR- TRY AGAIN
;
DT.RXT:
	MOV #DTRST1,R3	;RESTART OPERATION
DTRTRY:
	BIS #340,PS	;INHIBIT INTERRUPTS
	MOV #6,R2	;FIND ATL NODE
	MOV ATLNP(R2),R1
	BEQ DTXIT	;FORGET RETRYING IF NO ATL NODE EXISTS
	MOV R3,DT-12	;NEW PC
	MOV #6*40,DT-10	;NEW PS
	JMP CEXIT	;NOW RETRY IT
;
; OPERATOR ERROR
;
DT.ER1:
	MOV #-3,EVAR	;REFLECT IN EV
	BR DTNXIT	;CALL 15, CLEAN UP & EXIT
;
; MARK TRACK ERROR
;
DT.ER2:
	MOV #-6,EVAR	;REFLECT IN EV
	BR DTNXIT	;CALL 15, CLEAN UP & EXIT
;
EVAR:	.WORD 0
;
	.NLIST
	.ENDC
;
LASTLC:				;LAST LOCATION USED BY PIREX
;
	.END	START
