Google
 

Trailing-Edge - PDP-10 Archives - bb-bt99q-bb - lp2ser.x23
There is 1 other file named lp2ser.x23 in the archive. Click here to see a list.
TITLE LP2SER - LINE PRINTER SERVICE FOR LP20 CONTROLLER ON 2020 - V036
SUBTTL	D. DETROY/DBD	7-MARCH-89

	SEARCH	F,S,DEVPRM
	$RELOC
	$HIGH

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED
;  OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 
;1978,1979,1980,1982,1984,1986,1988.
;ALL RIGHTS RESERVED.

.CPYRT<1978,1988>


XP VLP2SR,036		;DEFINE GLOBAL VERSION NUMBER FOR LOADER MAP

LP2SER:	ENTRY	LP2SER
SUBTTL	LP20 REGISTER DEFINITIONS

; OFFSETS INTO THE EXTERNAL PAGE REGISTERS

LPCSRA==0			;CONTROL AND STATUS REGISTER A
LPCSRB==2			;CONTROL AND STATUS REGISTER B
LPBSAD==4			;BUS ADDRESS REGISTER (CURRENT ADDRESS)
LPBCTR==6			;BYTE COUNT REGISTER (2'S COMPLEMENT)
LPPCTR==10			;PAGE COUNTER
LPRAMD==12			;RAM DATA REGISTER
LPCBUF==14			;(BYTE) CHARACTER BUFFER REGISTER
LPCCTR==15			;(BYTE) COLUMN COUNT REGISTER
LPTDAT==16			;(BYTE) PRINTER DATA REGISTER
LPCKSM==17			;(BYTE) CHECKSUM REGISTER

;WORD BIT DEFINITIONS IN LPCSRA

LPWDON==000200			;LP DONE
LPWIEN==000100			;LP INTERRUPT ENABLE
LPWA17==40			;B17 OF PDP-11 ADDRESS (EXTENDED)
LPWA16==20			;B16
LPWDVU==000010			;LOAD DAVFU
LPWTM==000004			;TEST MODE
LPWPEN==000002			;PARITY ENABLE
LPWGO==000001			;GO
LPWERR==<200>B<35-8>		;ERROR (COMPOSITE)
LPWPZR==<100>B<35-8>		;PAGE COUNTER REACHED 0
LPWCI==<40>B<35-8>		;UNDEFINED CHARACTER INTERRUPT
LPWDR==<20>B<35-8>		;DAVFU READY
LPWOL==<10>B<35-8>		;ON LINE
LPWDH==<4>B<35-8>		;DELIMITER HOLD
LPWRSE==<2>B<35-8>		;RESET ERROR
LPWINT==<1>B<35-8>		;LP INITIALIZE

;BYTE BIT DEFINITIONS IN LPCSRA

LP1DON==000200			;LP DONE
LP1IEN==000100			;LP INTERRUPT ENABLE
LP1A17==40			;B17 OF PDP-11 ADDRESS (EXTENDED)
LP1A16==20			;B16
LP1DVU==000010			;LOAD DAVFU
LP1TM==000004			;TEST MODE
LP1PEN==000002			;PARITY ENABLE
LP1GO==000001			;GO

;BYTE BIT DEFINITIONS IN LPCSRA+1 (-11 LPCSRA BITS 15,14,13,12,11,10,9,8)

LP1ERR==200			;ERROR (COMPOSITE)
LP1PZR==100			;PAGE COUNTER REACHED 0
LP1CI==40			;UNDEFINED CHARACTER INTERRUPT
LP1DR==20			;DAVFU READY
LP1OL==10			;ON LINE
LP1DH==4			;DELIMITER HOLD
LP1RSE==2			;RESET ERROR
LP1INT==1			;LP INITIALIZE
;WORD LPCSRB BIT DEFINITIONS

LPWOFL==000200			;OFF LINE
LPWDVN==000100			;DAVFU NOT READY
LPWPER==000040			;LINE PRINTER PARITY ERROR
LPWMPE==000020			;MEMORY PARITY ERROR
LPWRPE==000010			;RAM PARITY ERROR
LPWSYE==000004			;MASTER SYNC ERROR
LPWDME==000002			;DEMAND TIME-OUT ERROR
LPWGOE==000001			;GO ERROR
LPWVDT==200B<35-8>		;VALID DATA
LPWPNR==40B<35-8>		;PRINTER NOT READY
LPWDPB==20B<35-8>		;LINE PRINTER DATA PARITY BIT
LPWOVF==10B<35-8>		;OPTICAL VFU

;BYTE LPCSRB BIT DEFINITIONS

LP1OFL==000200			;OFF LINE
LP1DVN==000100			;DAVFU NOT READY
LP1PER==000040			;LINE PRINTER PARITY ERROR
LP1MPE==000020			;MEMORY PARITY ERROR
LP1RPE==000010			;RAM PARITY ERROR
LP1SYE==000004			;MASTER SYNC ERROR
LP1DME==000002			;DEMAND TIME-OUT ERROR
LP1GOE==000001			;GO ERROR

;BYTE LPCSRB+1 BIT DEFS

LP1VDT==200			;VALID DATA
LP1PNR==40			;PRINTER NOT READY
LP1DPE==20			;LINE PRINTER DATA PARITY ERROR
LP1OVF==10			;OPTICAL VFU
SUBTTL	LPT SPECIFIC DDB DEFINITIONS

;GENERAL BITS IN LH OF DEVIOS
	IOSMON==400000		;DEVICE IS DOING IO FROM THE MONITOR
				; USED BY MAPIO ROUTINE

;DEVICE DEPENDENT BITS IN LH OF DEVIOS
	LPTSYN==Z(1B11)		;CRFF AFTER CLOSE HAS BEEN SENT
	LPTEND==Z(1B10)		;CLOSE UUO HAS BEEN DONE
	LPTVFU==Z(1B9)		;VFU NEEDS RELOADING
	LPTOPB==Z(1B8)		;POSSIBLE PARTIAL BUFFER ALREADY OUTPUT
	LPTRAM==Z(1B7)		;RAM NEEDS RELOADING
	LPTARW==Z(1B6)		;DOING UP-ARROW TRANSLATION

;DEVICE DEPENDENT BITS IN RH OF DEVIOS
	LPTNFF==100		;SUPPRESS FREE FORM FEEDS

;MISCELLANEY
MAXLBZ==:^D253			;MAX WORD SIZE OF USER'S LPT BUFFERS
				;(LPTSPL USES THIS NUMBER)
SUBTTL	LP20 SYSERR DATA BLOCK DEFINITIONS

;WORDS ARE IN EACH LINEPRINTER DDB FOR DAEMON ERROR REPORTING.

	.HCNAM==0		;DEVICE NAME
	.HCTYP==1		;CONTROLLER/DEVICE TYPE
	  HC.CTL==77B5		  ;CONTROLLER TYPE BYTE
	  .CTILL==0		  ;ILLEGAL
	  .CTB10==1		  ;BA10
	  .CTLP1==2		  ;LP100
	  .CTLP2==3		  ;LP20
	  .CTCD2==4		  ;CD20
	  HC.DEV==77B11		  ;DEVICE TYPE BYTE
	  .DEILL==0		  ;ILLEGAL
	  .DELPT==1		  ;LPT
	  .DECDR==2		  ;CDR
	  .DECDP==3		  ;CDP
	  .DEPLT==4		  ;PLT
	  HC.RTY==777777B35	  ;RETRY COUNT FIELD
	  .RTNON==1B17		  ;NON-ECOVERABLE FLAG
	.HCUID==2		;PPN OF USER
	.HCPGM==3		;PROGRAM NAME
	.HCSBP==4		;SUB-BLOCK POINTER
				; (XWD .HCL25-.HCSBP,,.HCL20)
	.HCL20==5		;UBA STATUS REGISTER
	.HCL21==6		;UBA MAP SLOT
	.HCL22==7		;LPCSRA,,LPCSRB
	.HCL23==10		;LPBSAD,,LPBCTR
	.HCL24==11		;LPPCTR,,LPRAMD
	.HCL25==12		;LPCBUF,,LPTDAT

	.HCSIZ==13		;SIZE OF BLOCK
SUBTTL	AUTOCONFIGURE


;DRIVER CHARARCTERISTICS
;	LP2	= LPTCNF
;	LPT	= DEVICE TYPE (LINE PRINTER)
;	7	= MAXIMUM DEVICES IN SYSTEM
;	0	= KONTROLLER TYPE
;	0	= MAXIMUM DRIVES PER KONTROLLER
;	0	= HIGHEST DRIVE NUMBER ON KONTROLLER
;	MDSEC0	= SECTION FOR KDB/UDB
;	MDSEC0	= SECTION FOR DDB
DRVCHR	(LP2,LPT,7,0,0,0,MDSEC0,MDSEC0,<DR.GCC!DR.NET>)

	 .ORG	DEVLEN

LPTDAP:!BLOCK	1		;PLACE TO BUILD AOBJN POINTER TO LPTDAE
LPTDAE:!BLOCK	.HCSIZ		;SYSERR BLOCK
LPTSTS:!BLOCK	1		;MORE DEVICE STATUS
LPTRSV:!BLOCK	1		;SAVE AREA DURING UP-ARROW TRANSLATION
LPTWSV:!BLOCK	1		;...
LPTUDC:!BLOCK	1		;UNDEFINED CHAR INTERRUPT DATA SAVED
LPTPAG:!BLOCK	1		;PAGE COUNTER WORD
LPTVEC:!BLOCK	1		;ADDRESS OF VECTOR INTERRUPT CODE
LPTBAS:!BLOCK	1		;LP20 BASE DEVICE ADDRESS
LPTFNC:!BLOCK	1		;CURRENT FUNCTION BITS SAVED HERE
LPTBYT:!BLOCK	1		;OUTPUT BYTE COUNT STORED HERE
LPTCDB:!BLOCK	1		;ADDRESS OF CHANNEL DATA BLOCK
LPTPTR:!BLOCK	1		;IOWD POINTER TO DATA BUFFER
LPTBUF:!BLOCK <<MAXLBZ*5>/4>+1	;ENOUGH ROOM FOR LPTSPL 7 TO 8 BIT BYTE CONVERSION
LPTBFZ==.-LPTBUF		;SIZE OF THE LPT BUFFER
LPTFRM:!BLOCK	1		;FORMS TYPE NAME (SIXBIT)
LP2LEN:!			;LENGTH OF LPT DDB

	 .ORG


LP2DDB:	DDBBEG	(LPT,LP2LEN)
	SETWRD	(DEVCHR,<6*HUNGST+DVLPTL,,LPTSIZ##>) ;DEVCHR
	SETWRD	(DEVSER,<MCSEC0+LPTDSP>)	;DEVSER
	SETWRD	(DEVMOD,<DVOUT!DVLPT,,<1_A+1_AL+1_I>>) ;DEVMOD
	SETWRD	(DEVTYP,<<.TYLPT*.TYEST>!.SPLPT!DEPLEN,,0>) ;DEVTYP
	SETWRD	(DEVCPU,<LPTCHN##>)		;DEVCPU
	SETWRD	(LPTDAP,<-.HCSIZ,,LPTDAE>)	;LPTDAP
	DDBEND


;CONSO SKIP CHAIN CODE (AUTCON WILL FILL IN THE BLANKS)
LP2ICD:	PHASE	0
	EXP	0		;(00) OLD PC FLAGS
	EXP	0		;(01) OLD PC
	EXP	IC.UOU		;(02) NEW PC FLAGS
	EXP	.+1		;(03) NEW PC
	JSR	PIERR##		;(04) SAVE ACS AND SETUP PDL
	DMOVE	T1,0		;(05) GET INTERRUPT FLAGS AND PC
	DMOVEM	T1,-1		;(06) SAVE IN TRADITIONAL PLACE FOR XJEN CH'N
	SKIPA	F,.+1		;(07) SET UP DDB ADDRESS
	EXP	0		;(10) DDB ADDRESS
	XJRST	.+1		;(11) CALL INTERRUPT HANDLER
	EXP	0		;(12) INTERRUPT HANDLER ADDRESS
	DEPHASE
LP2ICL==.-LP2ICD		;LENGTH OF CONSO SKIP CHAIN CODE

EQUATE	(LOCAL,0,<LP2CKT,LP2KDB,LP2KLN,LP2UDB,LP2ULN>)
EQUATE	(LOCAL,0,<LP2ULB,LP2ULP>)

LP2DSP:	DRVDSP	(LP2,LPTCHN##,LP2DDB,LP2LEN,URDDIA##)

;DEFAULT MONGEN'ED DEVICE TABLE
DEFMDT:	MDKS10	(7,LP11IV,LP11CA,0,0,<MD.KON>)
	MDTERM

;BITS FOR MDT ENTIRES ARE ALLOCATED HERE
	LPT.UC==:1		;UPPER-CASE ONLY PRINTER
LP2CFG:	XMOVEI	T1,LP2MDT##	;MONGEN'ED DEVICE TABLE
	XMOVEI	T2,DEFMDT	;DEFAULT TABLE
	MOVNI	T3,1		;NO MASSBUS UNIT OR DRIVE INFORMATION
	MOVEI	T4,MD.KON	;MATCH ON KONTROLLER DEFINITION
	PUSHJ	P,AUTMDT##	;SCAN THE TABLES
	  JRST	CPOPJ1##	;NO MATCHES
	PUSH	P,T1		;PRESERVE MDT DATA
	MOVEI	T1,LPTBAS	;WORD CONTAINING AN I/O INSTRUCTION
	PUSHJ	P,AUTFND##	;SEE IF THERE'S ALREADY A DDB
	  JRST	LP2CF1		;JUST MAKE SURE THE NUMBERS ARE OK
	PUSHJ	P,AUTADN##	;ALLOCATE A DEVICE NUMBER
	HRLI	T1,'LPT'	;INCLUDE GENERIC DEVICE NAME
	SETZ	T2,		;LOCAL DEVICE
	PUSHJ	P,AUTDDB##	;CREATE A DDB
	   JRST	TPOPJ##		;NO CORE
	ADDM	F,LPTDAP(F)	;FIX UP DAEMON ERROR POINTER
LP2CF1:	LDB	T1,[POINT 21,.CPDVC##,35] ;GET UNIBUS ADDRESS
	MOVEM	T1,LPTBAS(F)	;SAVE IN DDB
	MOVSI	T1,CP.LP2	;GET CHANNEL TYPE BITS
	PUSHJ	P,AUTCHN##	;ALLOCATE CHANNEL DATA BLOCK
	  JRST	LP2CF2		;NO CORE
	MOVE	T1,.CPCHA##	;GET CHANNEL DATA BLOCK ADDRESS
	MOVEM	T1,LPTCDB(F)	;SALT IT AWAY
	HLRZ	T1,LPTBAS(F)	;GET UNIBUS ADAPTER NUMBER
	MOVEI	T2,2		;NUMBER OF MAPPING REGISTERS NEEDED
	PUSHJ	P,AUTAMR##	;ALLOCATE MAPPING REGISTERS
	  JRST	TPOPJ##		;SORRY
	MOVE	T4,LPTCDB(F)	;GET CHANNEL DATA BLOCK ADDRESS BACK
	MOVEM	T1,CHNIMR(T4)	;STORE THE DATA AWAY
	MOVEM	T2,CHNMRC(T4)
	MOVEM	T3,CHNIEA(T4)
	SKIPE	LPTVEC(F)	;BEEN HERE BEFORE?
	JRST	LP2CF4		;THEN DON'T MESS WITH INTERRUPT CODE
	MOVE	T1,F		;DATA BLOCK ADDRESS
	XMOVEI	T2,LP2INT	;INTERRUPT SERVICE
	PUSHJ	P,AUTICD##	;GENERATE INTERRUPT ROUTINES
LP2CF2:	  SKIPA	T2,F		;NO CORE
	JRST	LP2CF3		;ONWARD
	MOVEI	T1,LP2LEN	;GET DDB LENGTH
	PUSHJ	P,AUTKIL##	;DELETE THE DDB
	PUSHJ	P,AUTDDN##	;DEALLOCATE DEVICE NUMBER
	JRST	TPOPJ##		;PHASE STACK AND RETURN
LP2CF3:	MOVEM	T2,LPTVEC(F)	;SAVE IN CASE ANYONE IS INTERESTED
	PUSHJ	P,AUTVII##	;COMPUTE VECTOR INSTRUCTION ADDRESS
	MOVE	T2,LPTVEC(F)	;GET VECTOR ROUTINE ADDRESS
	HRLI	T2,(XPCW)	;INTERRUPT INSTRUCTION
	MOVEM	T2,(T1)		;SAVE IN VECTOR TABLE
	MOVE	T1,DEVNAM(F)	;GET DEVICE NAME
	MOVEM	T1,LPTDAE+.HCNAM(F) ;SET IT UP
	MOVE	T1,[XWD .HCL25-.HCSBP,.HCL20] ;GET SUB-BLOCK POINTER
	MOVEM	T1,LPTDAE+.HCSBP(F) ;SET IT UP
LP2CF4:	POP	P,T1		;RESTORE MDT DATA
	MOVSI	T2,DVLPTL	;LOWERCASE LPT
	TRNE	T1,LPT.UC	;IF AN UPPER-CASE ONLY PRINTER,
	ANDCAM	T2,DEVCHR(F)	;CLEAR IT FOR LPTTYP
	POPJ	P,		;ALL DONE
SUBTTL	LPT SERVICE DISPATCH TABLE

;LINE PRINTER SERVICE DISPATCH TABLE

	JRST	LPTONL		;S IF LPT IS ON LINE NOW
	JRST	LPTDVP		;DEVOP. UUO
	JRST	REGSIZ##	;GET BUFFER SIZE FROM DDB
	JRST	LP2INI		;INITIALIZE
	JRST	LPTHNG		;HUNG DEVICE ERROR
LPTDSP:	JRST	LPTREL		;RELEASE
	JRST	LPTCLS		;CLOSE
	JRST	LPTOUT		;OUTPUT
	JRST	ILLINP##	;INPUT
SUBTTL	SYSTEM START-UP DEVICE INITIALIZATION

;LP2INI IS CALLED AT SYSTEM INITIALIZATION TIME FROM
;IOGO IN SYSINI WITH THE DDB ADDRESS IN F

	;NOTE:  THE LP2INI CODE FORCES IOGO IN SYSINI TO INVOKE
	;       LP2INI FOR EACH LINE PRINTER ON THE SYSTEM RATHER
	;       THAN FOR THE NORMAL CASE WHERE IT INVOKES THE
	;       INITIALIZATION CODE ONCE FOR EACH DISPATCH TABLE.
	;
	;       THEREFORE, THE CORRECT OPERATION OF THE LP2INI CODE
	;       IS DEPENDENT UPON THE IOGO CODE WHICH SHOULD BE:
	;
	;		PUSHJ P,DINI(P3) 
	;		HRRZM P3,SAVITM

LP2INI:	CAIN	F,LP2DDB	;PROTOTYPE?
	JRST	CPOPJ1##	;YES, SKIP SO IOGO CALLS INI ROUTINE AGAIN
	MOVSI	T4,DVOFLN	;OFF-LINE BIT
	ANDCAM	T4,DEVCHR(F)	;ASSUME LPT IS ON-LINE
	PUSHJ	P,LPTONL	;IS IT REALLY?
	  IORM	T4,DEVCHR(F)	;NO--SET OFF-LINE BIT
	TLO	S,LPTRAM+LPTVFU	;MARK RAM AND VFU FOR LOADING
	PUSHJ	P,LPTREL	;GO THRU RELEASE CODE
	PJRST	CPOPJ1##	;SKIP RETURN TO FORCE CALL FOR EACH LPT
SUBTTL	OUT/OUTPUT UUO

LPTOUT:	TLO	S,IO		;INDICATE OUTPUT
	PUSHJ	P,LPTOFL	;IF OFF-LINE, GET IT FIXED
	TLZE	S,LPTRAM	;RAM NEED DEFAULT RELOADING?
	PUSHJ	P,RESRAM	;YES--GO DO IT
	TLNN	S,LPTVFU	;VFU NEED DEFAULT RELOADING?
	JRST	LPTOU1		;NO--GO ON
	PUSHJ	P,LPTSTV	;YES--SETUP FOR VFU LOAD
	JRST	LPTGO		; AND GO DO IT
LPTOU1:	TRNE	S,LPTNFF	;SUPPRESS FORM FEED?
	TLZA	S,IOBEG		;YES--CLEAR IOBEG AND OUTPUT BUFFER
	TLNN	S,IOBEG		;NO--1ST OUTPUT?
	JRST	LPTOU2		;NO--JUST DO NEXT USER BUFFER
	PUSHJ	P,LPTSTI	;YES--SETUP INITIAL OUTPUT BUFFER
	JRST	LPTGO		; AND GO DO IT
LPTOU2:	PUSHJ	P,LPTSET	;SET UP USER'S OUTPUT BUFFER
	  PJRST	STOIOS##	;ERROR IN BUFFER, RETURN

;HERE TO START THE PRINTER GOING

LPTGO:	MOVE	T1,LPTBAS(F)	;GET BASE ADDRESS OF IO REGISTERS
	MOVEI	T2,7777		;12 BITS IN THE BYTE COUNTER
	TION	T2,LPBCTR(T1)	;IS THERE REALLY SOMETHING TO PRINT?
	  JRST	LPTSTP		;NO--JUST SHUT DOWN I/O
	MOVEI	T2,LPWRSE	;ERROR RESET BIT
	BSIO	T2,LPCSRA(T1)	;ENSURE LPWERR IS CLEAR
	RDIO	T2,LPBCTR(T1)	;COPY BYTE COUNTER TO ITSELF TO
	WRIO	T2,LPBCTR(T1)	; CLEAR DONE FROM LPWRSE ABOVE
	RDIO	T3,LPCSRA(T1)	;PICK UP CSRA
	HRLM	T3,LPTSTS(F)	;SAVE HERE FOR ANALYZING GO ERRORS
	RDIO	T3,LPCSRB(T1)	;PICK UP CSRB
	HRRM	T3,LPTSTS(F)	;SAVE HERE FOR ANALYZING GO ERRORS
	TRO	S,IOACT		;SET IOACT
	MOVEM	S,DEVIOS##(F)
	MOVE	T1,LPTBAS(F)	;GET BASE ADDRESS OF IO REGISTERS
	MOVEI	T2,LP1IEN+LP1PEN ;INTERRUPT ENABLE AND PARITY ENABLE BITS
	BSIOB	T2,LPCSRA(T1)	;SET THEM
	MOVEI	T2,LP1GO	;GO BIT
	BSIOB	T2,LPCSRA(T1)	;START THE PRINTER
	PJRST	SETHNG##	;SET HUNG TIMER AND RETURN

;HERE DURING OUTPUT UUO TO SEE IF DEVICE EXISTS
LPTOFL:	PUSHJ	P,LPTONL	;SEE IF LPT IS ON-LINE
	  SKIPA			;IT'S NOT, TELL THE USER
	POPJ	P,		;IT IS, JUST RETURN
	MOVEM	S,DEVIOS(F)	;YES, SAVE S (LPTRBL OFF)
	MOVSI	T4,DEPADV	;WANT BUFFER LEFT ALONE
	IORM	T4,DEVADV(F)	;
	MOVSI	T4,DVOFLN	;MARK LPT OFF LINE
	IORM	T4,DEVCHR(F)
	PUSHJ	P,HNGSTP##	;HALT JOB & PRINT REMINDER
	MOVSI	T4,DEPADV	;LOAD "DONT ADV BUFFERS"
	ANDCAM	T4,DEVADV(F)	;AND CLEAR IT IN THE DDB
	JRST	LPTOFL		;BACK HERE ON CONT, TRY AGAIN
SUBTTL	CLOSE UUO - RELEASE UUO

;CLOSE UUO  -  WHEN A CLOSE UUO IS EXECUTED (OR CLOSE COMMAND)
;	LPTCLS IS CALLED.  LPTCLS RESETS SOME STATUS FLAGS AND
;	LIGHTS LPTEND SO THE FINAL CRFF CAN BE SETUP NEXT TIME
;	LPTOUT IS CALLED.  LPTCLS RETURNS BY BRANCHING TO "OUT"
;	SO THE LAST PARTIAL BUFFER IS OUTPUT.

LPTCLS:	TLO	S,LPTEND	;SET "CLOSE DONE"
	TLZ	S,LPTSYN	;MAKE SURE THIS CLEAR
	MOVEM	S,DEVIOS(F)	;STORE S
	JRST	OUT##		;AND CALL OUT FOR LAST BUFFER



;RELEASE UUO  -  WHEN A "RESET" IS DONE ON THE LPT, LPTREL IS
;	CALLED.  THE LINEPRINTER IS "TURNED-OFF" (SEE LPTSTP)
;	THE PAGE COUNTER IS TURNED OFF AND THE DDB IS CLEANED UP.

LPTREL:	MOVE	T1,LPTBAS(F)	;GET BASE ADDRESS OF I/O REGISTERS
	PUSHJ	P,UBGOOD##	;IS LP20 ALIVE ON THE UNIBUS?
	  JRST	LPTRE1		;NO--DON'T TRY TO ACCESS IT
	MOVEI	T2,LPWINT	;INITIALIZE BIT
	WRIO	T2,LPCSRA(T1)	;CLEAR PRINTER
	PUSHJ	P,LPTTYP	;SETUP LINEPRINTER TYPE
LPTRE1:	MOVSI	T2,DEPADV	;GET "DONT ADV BUFFER" BIT
	ANDCAM	T2,DEVADV(F)	;TURN IT OFF
	TLZ	S,LPTOPB!LPTARW!LPTSYN ;CLEAR THESE OUT
	SETOM	LPTPAG(F)	;TURN OFF PAGE COUNTER
	PJRST	LPTSTP		;CLEAR PRINTER + IOACT, SAVE S AND RETURN


	LPTHNG==LPTREL		;HUNG DEVICE IS SAME AS RELEASE
SUBTTL	GENERAL INTERRUPT ROUTINE

;ENTER HERE ON ALL INTERRUPTS

LP2INT:	PUSHJ	P,IOSET##	;SETUP ACS R AND S
	LDB	J,PJOBN##	;SET UP J WITH JOB NUMBER
	MOVE	T1,LPTBAS(F)	;GET BASE ADDRESS OF I/O REGISTERS
	RDIO	T2,LPCSRA(T1)	;PICK UP CSRA
	RDIO	T3,LPCSRB(T1)	;PICK UP CSRB
	HRLM	T2,DEVSTS(F)	;SAVE STATUS AT INTERRUPT
	HRRM	T3,DEVSTS(F)	;...
	TRNN	T2,LPWDON	;SKIP IF DONE IS UP
	JRST	LPTERR		;ELSE HANDLE ERROR INTERRUPT
	TLZE	S,LPTARW	;WAS THIS AN UP-ARROW TRANSLATION?
	JRST	ARWFIN		;YES--GO RESUME NORMAL PATH
	SKIPE	T2,LPTFNC(F)	;WERE WE LOADING THE RAM/VFU?
	JRST	CHKVFU		;YES--GO CHECK IF DEFAULT LOAD
	TLZE	S,IOBEG		;NO BUFFER ADVANCE ON 1ST OUTPUT
	JRST	LPTNX1		;YES, SETUP NEXT BUFFER AND RETURN
	TLZE	S,LPTEND	;CLOSE DONE?
	JRST	LPTNX2		;YES, OUTPUT CRFF
	TLZN	S,LPTSYN	;WAS CRFF JUST OUTPUT?
	PUSHJ	P,ADVBFE##	;NO, ADVANCE TO NEXT BUFFER
	  PJRST	LPTSTP		;CANT ADVANCE, BUFFER UNAVAIL
	PUSHJ	P,SETIOD##	;ARRANGE FOR JOB TO RUN AGAIN
LPTNX1:	PUSHJ	P,LPTSET	;SET UP NEW BUFFER POINTER
	  PJRST	LPTSTP		;ERROR IN BUFFER, SHUT DOWN IO
	PJRST	LPTGO		;GO START IT UP
LPTNX2:	TRNE	S,LPTNFF	;SUPPRESS FORM FEEDS?
	PJRST	LPTSTP		;YES--GO SHUT DOWN IO
	TLO	S,LPTSYN	;NO--MARK CRFF SENT SO DON'T ADVANCE BUFFERS
	PUSHJ	P,LPTSTI	;SET OUTPUT FOR CRFF
	PJRST	LPTGO		;GO START IT UP

;HERE TO CHECK IF THE VFU WAS BEING LOADED BY MONITOR
; AND NOT BY USER (DEVOP.); IF SO, OUTPUT UUO MUST BE CONTINUED
CHKVFU:	CAIN	T2,LPWDVU	;WERE WE LOADING THE VFU?
	TLZN	S,LPTVFU	;YES--WAS IT BY MONITOR, NOT USER?
	PJRST	LPTSTP		;NO--NOTHING ELSE TO DO NOW
	PJRST	LPTOU1		;YES--CONTINUE THE OUTPUT UUO
SUBTTL	ERROR INTERRUPT ROUTINES -- DISPATCH

LPTERR:	TRNE	T3,LPWDVN	;VFU ERROR?
	JRST	LPTVFE		;YES HANDLE VFU ERROR
	TRNE	T2,LPWPZR	;PAGE-ZERO?
	JRST	LPTPZR		;YES, HANDLE ZERO PAGE COUNTER
	TRNE	T2,LPWCI	;UNDEFINED CHARACTER?
	JRST	LPTUCI		;YES, HANDLE IT
	TRNE	T3,LPWPER	;LINE PRINTER PARITY?
	JRST	LPTPAR		;YES, HANDLE PARITY ERROR
	TRNE	T3,LPWRPE	;RAM PARITY ERROR?
	JRST	LPTRPE		;YES, HANDLE IT
	TRNE	T3,LPWSYE!LPWDME!LPWMPE ;ANY HARD ERRORS?
	JRST	LPTHRD		;YES, HANDLE IT
	TRNE	T3,LPWOFL	;OFF-LINE?
	JRST	LPTNOL		;YES, HANDLE IT
	TRNE	T3,LPWGOE	;GO ERROR?
	JRST	LPTGOE		;YES, HANDLE IT

;HERE IF ON-LINE OR ERROR RESET INTERRUPT
	MOVSI	T1,DVOFLN	;OFF-LINE BIT
	TDNN	T1,DEVCHR(F)	;WAS THE LPT OFF-LINE?
	POPJ	P,		;NO--ERROR CLEARING, JUST DISMISS
	ANDCAM	T1,DEVCHR(F)	;YES--CLEAR OFF-LINE BIT
	PUSHJ	P,PSIONL##	;TELL USER LPT IS NOW ON-LINE
	POPJ	P,		;DISMISS
SUBTTL	ERROR INTERRUPT ROUTINES -- HANDLERS

;HERE ON PAGE-COUNTER ZERO INTERRUPT
LPTPZR:	MOVE	T2,LPTPAG(F)	;GET THE PAGE COUNTER
	MOVEI	T1,IOPLE%	;LOAD THE ERROR CODE
	JUMPE	T2,LPTPZ2	;IT'S EMPTY, TELL USER
	PUSHJ	P,LPTSPC	;ELSE, SET IT
	PJRST	LPTGO		;GO RESTART PRINTER, IF NECESSARY
LPTPZ2:	TLO	S,LPTOPB	;SET PARTIAL BUFFER PENDING
	PJRST	LPTIOE		;GIVE USER ERROR AND RETURN

;HERE ON LINE-PRINTER PARITY ERROR
LPTPAR:	PUSHJ	P,LPTSYR	;DO SYSERR REPORTING
	MOVEI	T1,IOPAR%	;LOAD PARITY ERROR
	PJRST	LPTIOE		;GIVE USER ERROR AND RETURN

;HERE ON LINE-PRINTER VFU ERROR
LPTVFE:	PUSHJ	P,LPTSYR	;TELL SYSERR
	PUSHJ	P,LPTNOL
	TLO	S,LPTVFU	;MARK VFU FOR RELOADING IF USER DOESN'T
	MOVEI	T1,IOVFE%	;VFU ERROR
	PJRST	LPTIOE		;GIVE USER ERROR AND RETURN

;HERE WHEN LINE PRINTER IS OFF-LINE
LPTNOL:	MOVSI	T1,DVOFLN	;MARK LPT OFF-LINE
	IORM	T1,DEVCHR(F)	;FOR ON-LINE INTERRUPT
	TLO	S,LPTOPB	;INDICATE POSSIBLE PARTIAL BUFFER
	PJRST	DEVERR##	;CAUSE UUOCON TO RETRY ON UUO LEVEL

;HERE ON RAM PARITY ERROR
LPTRPE:	PUSHJ	P,LPTSYR	;DO SYSERR REPORTING
	TLO	S,LPTRAM	;MARK RAM FOR RELOADING IF USER DOESN'T
	MOVEI	T1,IORPE%	;LOAD RAM PARITY ERROR
	PJRST	LPTIOE		;GIVE IT TO USER

;HERE ON "HARD" ERRORS
LPTHRD:	PUSHJ	P,LPTSYR	;DO SYSERR REPORTING
	MOVE	U,LPTCDB(F)	;GET CHAN DATA BLOCK
	MOVEI	T1,UNBTMO!UNBBME
	BSIO	T1,@CHNUBA(U)	;CLEAR ANY UBA ERRORS
	MOVEI	T1,IODER%	;LOAD ERROR CODE
	PJRST	LPTIOE		;GIVE IT TO USER

;HERE ON A GO ERROR
LPTGOE:	HRRZ	T1,LPTSTS(F)	;GET CSRB BEFORE LAST "GO"
	TRNE	T1,LPWOFL	;DID THE LPT DROP OFF-LINE?
	PJRST	LPTGO		;YES--JUST GO RESTART IT
	PUSHJ	P,LPTSYR	;NO--DO SYSERR REPORTING
	STOPCD	CPOPJ##,JOB,ULE	;++UNEXPECTED LP20 ERROR
;HERE ON UNDEFINED CHARACTER
LPTUCI:	RDIOB	T3,LPRAMD(T1)	;GET RAM DATA FOR THIS CHARACTER
	CAIE	T3,"^"		;IS THIS FOR UP-ARROW TRANSLATION?
	JRST	LPTUC1		;NO--HANDLE AS REAL ERROR
	TLO	S,LPTARW	;FLAG DOING UP-ARROW MODE
	RDIO	T3,LPBSAD(T1)	;READ CURRENT BUS ADDRESS
	TRZ	T2,777717	;ISOLATE HIGH-ORDER ADDRESS BITS IN CSRA
	LSH	T2,14		;SHIFT TO BITS 19-20 (16-17 OF -11)
	IORI	T3,(T2)		;FORM COMPLETE 18-BIT ADDRESS
	HRLM	T3,LPTRSV(F)	; AND SAVE IT
	RDIO	T2,LPBCTR(T1)	;READ CURRENT BYTE COUNTER
	HRRM	T2,LPTRSV(F)	; AND SAVE IT
	MOVEI	T2,LPTBUF(F)	;ADDRESS OF FIRST WORD IN LPT BUFFER
	MOVE	T3,(T2)		;GET CONTENTS
	MOVEM	T3,LPTWSV(F)	; AND SAVE IT
	MOVEI	T3,"^"		;GET AN UP-ARROW
	DPB	T3,[POINT 8,(T2),17] ;PUT WHERE IT WILL BE PRINTED FROM
	RDIOB	T3,LPCBUF(T1)	;GET THE CONTROL CHARACTER
	TRO	T3,100		;MAKE IT A PRINTING CHARACTER
	ANDI	T3,177		;GET RID OF ANY GARBAGE BITS
	DPB	T3,[POINT 10,(T2),9] ;PUT IN BUFFER & CLEAR BITS 0-1
	MOVNI	T2,2		;NEGATIVE NUMBER OF CHARS TO PRINT
	MOVE	P3,LPTCDB(F)	;POINT TO THE CDB TO GET INITIAL ADDR
	PUSHJ	P,REGSE2	;SET LP20 REGISTERS
	PJRST	LPTGO		;PRINT THE TWO CHARACTERS

LPTUC1:	RDIO	T2,LPRAMD(T1)	;GET RAM DATA
	HRLM	T2,LPTUDC(F)	; AND SAVE HERE (FOR POSSIBLE DEVOP.)
	RDIO	T2,LPCBUF(T1)	;GET CHAR BUFFER DATA
	HRRM	T2,LPTUDC(F)	; AND SAVE HERE
	MOVEI	T1,IOUNC%	;LOAD ERROR CODE
	PJRST	LPTIOE		;GIVE USER ERROR AND RETURN

;HERE WHEN WE FINISHED AN UP-ARROW TRANSLATION TO CONTINUE NORMAL PRINTING
ARWFIN:	MOVE	T2,LPTWSV(F)	;GET SAVED BUFFER WORD
	MOVEM	T2,LPTBUF(F)	; AND RESTORE IT
	HRRZ	T2,LPTRSV(F)	;GET SAVED BYTE COUNTER
	WRIO	T2,LPBCTR(T1)	; AND RESTORE IT
	HLRZ	T2,LPTRSV(F)	;GET SAVED BUS ADDRESS
	PUSHJ	P,REGSE3	; AND RESTORE IT
	PJRST	LPTGO		;CONTINUE PRINTER

SUBTTL	SETUP NEXT BUFFER ROUTINES

;HERE FOR NEXT REGULAR BUFFER (OR LAST PARTIAL)
;SKIP RETURN IF NO ERRORS

LPTSET:	MOVE	T1,LPTBAS(F)	;GET BASE ADDRESS OF I/O REGISTERS
	TLZN	S,LPTOPB	;POSSIBLE PARTIAL BUFFER PENDING?
	JRST	LPTSE1		;NO--GO AHEAD
	MOVEI	T3,7777		;12 BITS IN THE BYTE COUNTER
	TIOE	T3,LPBCTR(T1)	;IS THERE SOMETHING LEFT?
	  PJRST	CPOPJ1##	;YES--RETURN TO COMPLETE PARTIAL
LPTSE1:	MOVEI	T2,@DEVOAD(F)	;GET USER ADDR. OF CURRENT BUFFER
	MOVN	T3,1(T2)	;GET NEG WORD COUNT FROM BUFFER HEADER
	JUMPE	T3,LPTSTN	;ZERO LENGTH? SEND NULLS TO GET DONE INTERRUPT
	HRLI	T2,(T3)		;FORM IOWD IN T2
	AOS	T2		;BUMP T2 FOR IOWD; DO THIS BUFFER
	MOVN	T3,T3		;POSITIVE WORD COUNT
	CAIG	T3,MAXLBZ	;EXCEEDING MAX BUFFER SIZE POSSIBLE?
	JRST	LPTSE2		;NO--PROCEED
	TRO	S,IOBKTL	;YES--SET BLOCK TOO LARGE
	POPJ	P,		;GIVE NON-SKIP RETURN
LPTSE2:	AOS	(P)		;SET FOR SKIP RETURN
	IMULI	T3,5		;CONVERT WDS TO BYTES (5 7-BIT BYTES/WD)
	MOVEM	T3,LPTBYT(F)	;SAVE IT HERE
LPTSE3:	SETZM	LPTFNC(F)	;SET FOR REGULAR PRINT FUNCTION
	PJRST	REGSET		;GO SET IT UP

;HERE TO SETUP NEXT OUTPUT AS <NUL><NUL>
LPTSTN:	AOS	(P)		;SET FOR SKIP RETURN
	SKIPA	T2,[LPNULL-1]	;MAKE IOWD TO NULLS, FALL INTO LPTSTI

;HERE TO SETUP NEXT OUTPUT AS <CR><FF>
LPTSTI:	HRRI	T2,LPCRFF-1	;MAKE IOWD TO CRFF
	HRLI	T2,-1		;PUT IN WORD COUNT
	MOVEI	T3,2		;BYTE COUNT
	MOVEM	T3,LPTBYT(F)	;SAVE IT
	TLO	S,IOSMON	;INDICATE MONITOR IO TO MAPIO
	PJRST	LPTSE3		;GO SET IT UP

LPNULL:	BYTE	(7)0,0		;<NUL><NUL>
LPCRFF:	BYTE	(7)15,14	;<CR><FF>

;HERE TO SETUP NEXT OUTPUT AS THE DEFAULT VFU LOAD

LPTSTV:	HRRI	T2,VFUBUF-1	;MAKE IOWD TO DATA
	HRLI	T2,-VFUBFZ	;PUT IN WORD COUNT
	MOVE	T3,VFUBUF+VFUBFZ-1 ;GET BYTE COUNT
	MOVEM	T3,LPTBYT(F)	;SAVE IN DDB
	MOVEI	T3,LPWDVU	;VFU LOAD FUNCTION BITS
	MOVEM	T3,LPTFNC(F)	;SAVE IN DDB
	TLO	S,IOSMON	;INDICATE MONITOR IO TO MAPIO
	PJRST	REGSET		;GO SET IT UP
SUBTTL	SETUP REAL BUFFER AND LP20 REGISTERS ROUTINE

; HERE WITH IOWD IN T2 TO SETUP "REAL" OUTPUT BUFFER AND THEN
; SET THE LP20 REGISTERS.

REGSET:	MOVEM	T2,LPTPTR(F)	;LPTPTR GETS IOWD TO BUFFER
	HRRZI	T3,1(T2)	;SOURCE BUFFER ADDRESS TO RH(T3)
	HRLI	T3,(<POINT 7,0>);FORM BYTE POINTER TO IT
	MOVE	T4,LPTBYT(F)	;BYTE COUNT TO T4
	MOVE	U,LPTFNC(F)	;FUNCTION BITS
	CAIN	U,LPWDVU+LPWTM	;ARE WE LOADING THE RAM?
	JRST	REGSE1		;YES--CONTINUE
	MOVEI	T2,LPTBUF(F)	;NO--"REAL" OUTPUT BUFFER ADDRESS TO T2
	CAIN	U,LPWDVU	;ARE WE LOADING THE VFU?
	PUSHJ	P,SHUFLR	;YES--REPACK DATA AND SKIP RETURN
	PUSHJ	P,SHUFL		;NO--REPACK DATA AND RETURN
	HRRI	T2,LPTBUF-1(F)	;BUFFER ADDRESS-1 TO T2
	HRLI	T2,-LPTBFZ	;FORM COMPLETE IOWD FOR MAPIO
	TLO	S,IOSMON	;INDICATE MONITOR IO TO MAPIO
REGSE1:	SETZB	P1,P4		;FIRST CALL,NO FRAME COUNT
	MOVE	P3,LPTCDB(F)	;GET POINTER TO CHANNEL DATA BLOCK
	PUSHJ	P,MAPIO##	;SET UP UNIBUS ADAPTOR REGISTERS
	  JRST	LPTSTP		;SHOULDN'T HAPPEN
	TLZ	S,IOSMON	;CLEAR MONITOR IO BIT
	MOVN	T2,LPTBYT(F)	;GET NEGATIVE BYTE COUNT
REGSE2:	WRIO	T2,LPBCTR(T1)	;SET IN BYTE COUNT REGISTER
	MOVE	T2,CHNIEA(P3)	;GET -11 STYLE ADDRESS
REGSE3:	WRIO	T2,LPBSAD(T1)	;SET IN BUS ADDRESS REGISTER
	LSH	T2,-14		;ISOLATE TWO HIGH ORDER BITS OF ADDRESS
	TRZ	T2,777717	; IN PROPER POSITION FOR LPCSRA
	IOR	T2,LPTFNC(F)	;PUT IN THE FUNCTION BITS
	WRIOB	T2,LPCSRA(T1)	;SET THEM
	POPJ	P,		; AND RETURN
SUBTTL	DEVOP UUO INTERFACE -- DISPATCH

;HERE ON DISPATCH FROM UUOCON
;	F=DDB
;	T1=FUNCTION

LPTDVP:	MOVSI	T2,-LPTDVL	;GET TABLE LENGTH SETUP AOBJN PTR
LPTDV1:	HLRZ	T3,LPTDVT(T2)	;GET THE FUNCTION CODE
	HRRZ	T4,LPTDVT(T2)	;GET THE DISPATCH ADDRESS
	CAMN	T1,T3		;DO CODES MATCH?
	JRST	(T4)		;YES, DISPATCH
	AOBJN	T2,LPTDV1	;NO, LOOP
	PJRST	ECOD2##		;NO MATCH, GIVE AN ERROR

LPTDVT:	XWD	11,DVLRAM	;LOAD RAM
	XWD	12,DVLVFU	;LOAD VFU
	XWD	1000,DVPC	;READ PAGE COUNTER
	XWD	2000,DVPC	;SET PAGE COUNTER
	XWD	1004,DVDCS	;READ DEVICE STATUS
	XWD	1005,DVFRMR	;READ FORMS TYPE NAME
	XWD	2005,DVFRMS	;SET FORMS TYPE NAME
	LPTDVL==.-LPTDVT	;DISPATCH TABLE LENGTH
SUBTTL	DEVOP UUO INTERFACE -- HANDLERS

;HERE TO LOAD RAM OR VFU WITH DATA FROM USER
DVLRAM:	PUSHJ	P,LPTOFL	;IF OFF-LINE, GET IT FIXED
	MOVEI	T3,LPWDVU+LPWTM	;FUNCTION BITS FOR RAM LOAD
	TLZ	S,LPTRAM	;CLEAR DEFAULT LOAD BIT
	SETZ	P2,0		;RAM FLAG
	JRST	DVLVF0		;CONTINUE
DVLVFU:	PUSHJ	P,LPTOFL	;IF OFF-LINE, GET IT FIXED
	MOVEI	T3,LPWDVU	;FUNCTION BITS FOR VFU LOAD
	TLZ	S,LPTVFU	;CLEAR DEFAULT LOAD BIT
	MOVEI	P2,1		;VFU FLAG
DVLVF0:	MOVEM	S,DEVIOS(F)	;UPDATE DDB COPY
	PUSHJ	P,WAIT1##	;MAKE SURE ANY IO HAS STOPPED
	PUSHJ	P,GETWR1##	;GET RAM/VFU BYTE COUNT ARGUMENT
	  PJRST	ECOD3##		;ERROR
	JUMPLE	T1,ECOD3##	;ERROR IF .LE. ZERO
	MOVEM	T1,LPTBYT(F)	;SAVE BYTE COUNT HERE
	ADDI	T1,3(P2)	;FUDGE REMAINDER
	IDIVI	T1,4(P2)	;MAKE T1 A WORD COUNT
	CAILE	T1,^D128	;WITHIN RANGE?
	  PJRST	ECOD3##		;NO--ERROR
	PUSH	P,T1		;SAVE IT
	MOVN	T2,T1		;NEGATIVE WORD COUNT
	HRLZS	T2		;FORM LH OF IOWD
	PUSHJ	P,GETWR1##	;GET ADDRESS OF RAM/VFU DATA
	  PJRST	RTM1##		;COULDN'T--GIVE ADDRESS ERROR
	HRRI	T2,-1(T1)	;FORM COMPLETE IOWD
	MOVEM	T2,LPTPTR(F)	;SAVE HERE
	MOVEM	T3,LPTFNC(F)	;PUT FUNCTION BITS HERE
	CAIE	T3,LPWDVU	;IS THIS A VFU LOAD?
	JRST	DVLRA1		;NO--JUST GO ON
	HRRZI	T3,1(T2)	;USER VIRT ADDRESS HERE
	MOVE	T1,0(P)		;WORD COUNT HERE
	PUSHJ	P,GTEVBF##	;GO MAP THIS INTO EVM
	  STOPCD TPOPJ1,JOB,NEM, ;++NO EXEC VIRTUAL MEMORY
	MOVEM	T1,0(P)		;SAVE EVM USAGE WORD
	MOVE	T2,LPTPTR(F)	;GET IOWD
	HRRI	T2,-1(T3)	;UPDATE WITH EXEC ADDRESS
DVLRA1:	MOVE	T1,LPTBAS(F)	;GET BASE ADDRESS OF I/O REGISTERS
	PUSHJ	P,REGSET	;GO SET UP LP20
	MOVEI	T1,LPWDVU	;VFU LOAD FUNCTION BITS
	CAME	T1,LPTFNC(F)	;LOADING THE VFU?
	JRST	DVLRA2		;NO--PROCEED
	MOVE	T2,0(P)		;GET EVM USAGE WORD
	LDB	T1,[POINT 9,T2,35] ;NO. OF PAGES
	PUSHJ	P,GIVEVM##	;RETURN THE STUFF
DVLRA2:	PUSHJ	P,LPTGO		;START UP THE IO
	PJRST	TPOPJ1##	;GIVE A GOOD RETURN
;HERE TO READ OR SET THE PAGE COUNTER
DVPC:	MOVE	T3,DEVHCW(F)	;GET CHARACTERISTICS
	TLNN	T3,(HC.PGC)	;DEVICE HAVE PAGE COUNTER?
	  PJRST	ECOD11##	;NO, ERROR
	TRNE	T1,1000		;READ?
	  JRST	DVPC1		;YES
	PUSHJ	P,GETWR1##	;NO, SET T1=PAGE ARG
	  PJRST	RTM1##		;ERROR
	SETOM	LPTPAG(F)	;ASSUME -1
	JUMPE	T1,CPOPJ1##	;RETURN
	MOVEM	T1,LPTPAG(F)	;STORE NEW PAGE COUNTER WORD
	PUSHJ	P,LPTSPC	;SET PAGE COUNTER
	JRST	CPOPJ1##

DVPC1:	SKIPGE	LPTPAG(F)	;ATTEMPT TO READ WHEN
	PJRST	ECOD10##	; NOT SET
	MOVE	T1,LPTBAS(F)	;GET BASE ADDRESS OF I/O REGISTERS
	RDIO	T1,LPPCTR(T1)	;GET PAGE COUNTER
	ANDI	T1,7777		;ONLY THESE BITS
	ADD	T1,LPTPAG(F)	;ADD IN REMAINING AMOUNT
	PJRST	STOTC1##	;RETURN WITH PAGE COUNT IN T1


;HERE TO READ LPT STATUS
DVDCS:	MOVEI	T1,0		;INITIALIZE
	MOVE	T2,LPTBAS(F)	;GET BASE ADDRESS OF I/O REGISTERS
	RDIO	T2,LPCSRB(T2)	;GET SECOND STATUS REGISTER
	TRNE	T2,LPWOFL	;OFF-LINE?
	TLO	T1,(DV.OFL)	;YES
	TRNE	T2,LPWDVN	;DAVFU ERROR?
	TRO	T1,DV.VFE	;YES
	PJRST	STOTC1##	;STORE STATUS/GOOD RETURN

;HERE TO READ OR SET THE FORMS TYPE NAME
DVFRMR:	MOVE	T1,LPTFRM(F)	;GET FORMS NAME
	JRST	STOTC1##	;GIVE IT TO THE USER

DVFRMS:	PUSHJ	P,GETWR1##	;FETCH USER'S ARGUMENT
	  JRST	RTM1##		;ADDRESS CHECK ERROR
	MOVEM	T1,LPTFRM(F)	;SAVE IT FOR POSTERITY
	JRST	CPOPJ1##	;SUCCESS RETURN
SUBTTL	VARIOUS UTILITY ROUTINES

;SUBROUTINE TO SET THE HARDWARE PAGE COUNTER
;	IF SOFTWARE PAGE COUNTER WORD (SPCW) IS .EQ. 0, JUST RETURN
;	ELSE SET HARDWARE PAGE COUNTER TO MAX(SPCW,7777) I IF THE
;	SPCW IS NOT-NEGATIVE, DECREMENT IT BY THE AMOUNT SET.

LPTSPC:	SKIPN	LPTPAG(F)	;IS THERE ANYTHING TO SET?
	POPJ	P,		;NO, JUST RETURN
	SKIPL	U,LPTPAG(F)	;GET THE SPCW
	CAILE	U,7777		;WITHIN RANGE OF HARDWARE?
	MOVEI	U,7777		;NO, PUT WITHIN RANGE
	MOVE	T1,LPTBAS(F)	;GET BASE ADDRESS OF I/O REGISTERS
	WRIO	U,LPPCTR(T1)	;SET THE PAGE COUNTER
	MOVNS	U		;NEGATE THE AC
	SKIPL	LPTPAG(F)	;DONT DECREMENT IF NOT SET
	ADDM	U,LPTPAG(F)	;DECREMENT THE SPCW
	POPJ	P,		;AND RETURN

;SUBROUTINE TO SEE IF THE LPT IS ON LINE
LPTONL:	MOVE	T1,LPTBAS(F)	;GET BASE ADDRESS OF I/O REGISTERS
	PUSHJ	P,UBGOOD##	;IS LP20 ALIVE ON THE UNIBUS?
	  POPJ	P,		;NO--RETURN OFF-LINE
	RDIO	T2,LPCSRB(T1)	;YES--GET SECOND STATUS REGISTER
	TRNN	T2,LPWOFL	;IS PRINTER OFF-LINE?
	AOS	(P)		;NO--IT'S ON-LINE, SO SKIP RETURN
	POPJ	P,		;EITHER ON-LINE OR OFF

;HERE TO STOP THE LPT AND START THE USER.
LPTSTP:	MOVE	T1,LPTBAS(F)	;GET BASE ADDRESS OF IO REGISTERS
	PUSHJ	P,UBGOOD##	;IS LP20 ALIVE ON THE UNIBUS?
	  JRST	LPTST1		;NO--DON'T TRY TO ACCESS IT
	MOVEI	T2,LP1IEN	;INTERRUPT ENABLE BIT
	BCIOB	T2,LPCSRA(T1)	;TURN'EM OFF
LPTST1:	PUSHJ	P,SETIOD##	;CLEAR IOW, REQUE IF NEEDED
	PUSHJ	P,CLRACT##	;CLEAR IOACT, UPDATE S
	PJRST	RTEVMO##	;RETURN ANY EVM

;HERE TO GIVE THE USER AN I/O ERROR AND DISMISS THE INTERRUPT.
;	ERROR CODE IN T1.
LPTIOE:	DPB	T1,PDVESE##	;STORE THE ERROR CODE
	TRO	S,740000	;SET ALL ERRORS
	PJRST	LPTSTP		;GO SHUTDOWN IO AND START USER
;HERE TO DO DAEMON ERROR REPORTING FOR SYSERR
LPTSYR:	MOVE	U,LPTCDB(F)	;GET CHAN DATA BLOCK
	RDIO	T2,@CHNUBA(U)	;READ UBA STATUS REGISTER
	MOVEM	T2,LPTDAE+.HCL20(F) ;SAVE IT
	MOVE	T1,LPTBAS(F)
	RDIO	T3,LPCSRA(T1)	;GET CSRA
	LSH	T3,-4		;POSITION 2 BIT ADDRESS EXTENSION
	RDIO	T2,LPBSAD(T1)	;GET ENDING BUS ADDRESS
	DPB	T3,[POINT 2,T2,19] ; AND PUT IN HIGH ORDER BITS
	IDIVI	T2,UBAMUL	;COMPUTE MAP REGISTER OFFSET
	ADDI	T2,UBAEXP	;ADD IN THE BASE ADDRESS
	HLL	T2,CHNUBA(U)	;PUT IN PROPER UBA NUMBER
	RDIO	T3,(T2)		;READ OUT MAP SLOT OF LAST WORD XFER'ED
	MOVEM	T3,LPTDAE+.HCL21(F) ;SAVE IT
	RDIO	U,LPCSRA(T1)	;GET FIRST STATUS REGISTER
	RDIO	T2,LPCSRB(T1)	;GET SECOND STATUS REGISTER
	HRLI	T2,(U)		;PUT IN LH(T2)
	MOVEM	T2,LPTDAE+.HCL22(F) ;SAVE IT
	RDIO	U,LPBSAD(T1)	;GET BUS ADDRESS REGISTER
	RDIO	T2,LPBCTR(T1)	;GET BYTE COUNTER
	HRLI	T2,(U)		;PUT IN LH(T2)
	MOVEM	T2,LPTDAE+.HCL23(F) ;SAVE IT
	RDIO	U,LPPCTR(T1)	;GET PAGE COUNTER
	RDIO	T2,LPRAMD(T1)	;GET RAM DATA
	HRLI	T2,(U)		;PUT IN LH(T2)
	MOVEM	T2,LPTDAE+.HCL24(F) ;SAVE IT
	RDIO	U,LPCBUF(T1)	;GET CHAR BUFFER AND COL COUNT
	RDIO	T2,LPTDAT(T1)	;GET PRINTER DATA AND CHECKSUM
	HRLI	T2,(U)		;PUT IN LH(T2)
	MOVEM	T2,LPTDAE+.HCL25(F) ;SAVE IT

	SETZ	T1,		;CAUSE SEB ALLOCATION TO HAPPEN
	XMOVEI	T2,ELGTBL	;POINT TO TRANSFER TABLE
	PUSHJ	P,XFRSEB##	;FILL AND QUEUE UP RECORD
	  JFCL			;NO CORE
	POPJ	P,		;RETURN


ELGTBL:	SEBTBL	(.ERHCC,ELGEND,<EX.QUE!EX.SYE!EX.DEL>)
	MOVE	DEVNAM(F)	;(R00) DEVICE NAME
	MOVE	LPTDAE+.HCTYP(F) ;(R01) CONTROLLER TYPE, ETC.
	MOVE	JBTPPN##(J)	;(R02) PPN
	MOVE	JBTNAM##(J)	;(R03) PROGRAM NAME
	MOVE	LPTDAP(F)	;(R04) WORDS IN SUB-BLOCK,,OFFSET
	MOVE	LPTDAE+.HCL20(F) ;(R05) UBA STATUS REGISTER
	MOVE	LPTDAE+.HCL21(F) ;(R06) UBA MAP SLOT
	MOVE	LPTDAE+.HCL22(F) ;(R07) LPCSRA,,LPCSRB
	MOVE	LPTDAE+.HCL23(F) ;(R10) LPBSAD,,LPBCTR
	MOVE	LPTDAE+.HCL24(F) ;(R11) LPPCTR,,LPRAMD
	MOVE	LPTDAE+.HCL25(F) ;(R12) LPCBUF,,LPTDAT
ELGEND:!			;END OF TABLE
;HERE TO SETUP HARDWARE CHARACTERISTICS WORD AND DETERMINE CONTROLLER TYPE
LPTTYP:	MOVSI	T3,DVLPTL	;GET LOWER CASE PRINTER BIT
	TDNN	T3,DEVCHR(F)	;A LOWER CASE PRINTER?
	TDZA	T3,T3		;NO, UPPER CASE
	MOVSI	T3,(HC.LCP)	;YES, NOTE THAT
	TLNN	T3,(HC.LCP)	;A LOWER CASE PRINTER?
	TDZA	T2,T2		;NO, UPPER CASE
	MOVEI	T2,.HCC95	;YES, THEN FLAG AS 96-CHAR SET ALSO
	DPB	T2,[POINT 3,T3,8] ;STORE IN HARDWARE CHARACTERISTICS
	MOVEI	T2,LPWOVF	;OPTICAL VFU BIT
	SETZ	T4,		;ASSUME WE HAVE AN OPTICAL UNIT
	TION	T2,LPCSRB(T1)	;DO WE?
	MOVEI	T4,.HCVTD	;NO, MUST BE DAVFU
	DPB	T4,[POINT 3,T3,5] ;STORE THAT
	CAIE	T4,.HCVTD	;DID WE DECIDE IT WAS A LOADABLE VFU?
	TLZ	S,LPTVFU	;NO, CLEAR THE FLAG REQUESTING VFU LOAD
	TLO	T3,(HC.PGC)	;LP20 HAS A HARDWARE PAGE COUNTER
	MOVEI	T2,.CTLP2	;INDICATE LP20
	DPB	T2,[POINT 3,T3,11] ;STORE THAT
	TLO	T3,(<.HCULP>B14) ;LP05 CLASS PRINTER
	HLLM	T3,DEVHCW(F)	;STORE HARDWARE CHARACTERISTICS
	DPB	T2,[POINT 6,LPTDAE+.HCTYP(F),5] ;AND CONTROLLER TYPE
	MOVEI	T2,.DELPT	;INDICATE LPT DEVICE
	DPB	T2,[POINT 6,LPTDAE+.HCTYP(F),11] ;STORE IT
	POPJ	P,		;RETURN
;ROUTINE TO CLEAR AND THEN SET THE RAM FOR STANDARD SETTINGS

RESRAM:	MOVE	T1,LPTBAS(F)	;GET BASE ADDRESS OF IO REGISTERS
	MOVEI	T2,377		;MAXIMUM RAM ADDRESS
	SETZ	T3,		;A ZERO
RESRA1:	WRIOB	T2,LPCBUF(T1)	;SET THIS RAM ADDRESS
	WRIO	T3,LPRAMD(T1)	;ZERO THIS RAM ENTRY
	SOJGE	T2,RESRA1	;GO THRU THE WHOLE RAM
	MOVEI	T2,RAMTSZ-1	;SIZE OF RAMTAB MINUS 1
RESRA2:	HLRZ	T3,RAMTAB(T2)	;GET RAM CHAR (=RAM ADDRESS)
	WRIOB	T3,LPCBUF(T1)	;SET THIS RAM ADDRESS
	HRRZ	T3,RAMTAB(T2)	;GET CORRESPONDING RAM BITS TO LOAD
	WRIO	T3,LPRAMD(T1)	;LOAD THEM
	SOJGE	T2,RESRA2	;BACK FOR ANOTHER
	MOVSI	T2,DVLPTL	;A LOWER CASE PRINTER?
	TDNE	T2,DEVCHR(F)
	POPJ	P,		;YES--RETURN
	MOVEI	T2,36		;NO--NUMBER OF LOWER CASE CODES
RESRA3:	MOVEI	T3,140(T2)	;THE LOWER CASE CHARACTER CODE
	WRIOB	T3,LPCBUF(T1)	;SET THIS RAM ADDRESS
	MOVEI	T3,1000-40(T3)	;TRANS BIT + UPPER CASE CODE
	WRIO	T3,LPRAMD(T1)	;SET IN RAM
	SOJGE	T2,RESRA3	;BACK FOR ANOTHER
	POPJ	P,		;RETURN

RAMTAB:	XWD	12,1407		;LF,,CHANNEL 8
	XWD	13,1406		;VT,,CHANNEL 7
	XWD	14,1400		;FF,,CHANNEL 1
	XWD	20,1401		;DLE,,CHANNEL 2
	XWD	21,1402		;DC1,,CHANNEL 3
	XWD	22,1403		;DC2,,CHANNEL 4
	XWD	23,1404		;DC3,,CHANNEL 5
	XWD	24,1405		;DC4,,CHANNEL 6

RAMTSZ==.-RAMTAB		;SIZE OF RAMTAB
;ROUTINE TO CHANGE CONTIGUOUS BYTES IN -10 FORMAT TO SHUFFLED BYTES
;IN -11 FORMAT. CALL:
;	T2/ ADDRESS TO RECEIVE SHUFFLED BYTES
;	T3/ BYTE POINTER TO CONTIGUOUS BYTES
;	T4/ NUMBER OF BYTES TO DO

SHUFL:	PUSHJ	P,SAVE2##	;NEED A COUPLE OF THESE REGISTERS
SHUFL1:	SOJL	T4,CPOPJ##	;DONE, SO QUIT
	ILDB	P1,T3		;GET FIRST BYTE
	SOJL	T4,SHUFL3	;DONE AFTER FIRST BYTE
	ILDB	P2,T3		;GET NEXT CHARACTER
	LSH	P2,^D8		;SHIFT INTO POSITION
	IOR	P2,P1		;PUT CHARACTERS TOGETHER
	HRLZM	P2,(T2)		;STORE CHARACTERS
	SOJL	T4,CPOPJ##	;DONE
	ILDB	P1,T3		;GET ANOTHER CHARACTER
	SOJL	T4,SHUFL4	;DONE
	ILDB	P2,T3		;GET LAST CHARACTER
	LSH	P2,^D8		;PUT INTO POSITION
	IOR	P2,P1		;PUT CHARACTERS TOGETHER
	HRRM	P2,(T2)		;STORE CHARACTERS
	AOJA	T2,SHUFL1	;NEXT WORD

SHUFL3:	HRLZM	P1,(T2)		;STORE CHARACTER
	POPJ	P,		;RETURN

SHUFL4:	HRRM	P1,(T2)		;STORE CHARACTER
	POPJ	P,		;RETURN
;ROUTINE TO CHANGE CONTIGUOUS BYTES IN -10 FORMAT TO SHUFFLED BYTES
;IN -11 FORMAT. ALSO CONVERT BA10/LP100 START/STOP CODES TO LP20 STYLE.
;CALL:
;	T2/ ADDRESS TO RECEIVE SHUFFLED BYTES
;	T3/ BYTE POINTER TO CONTIGUOUS BYTES
;	T4/ NUMBER OF BYTES TO DO
;GIVES A SKIP RETURN ALWAYS (FOR CONVENIENCE OF HOW IT WAS CALLED)

SHUFLR:	PUSHJ	P,SAVE3##	;NEED A COUPLE OF THESE REGISTERS
	SETO	P3,		;SET FLAG INDICATING FIRST BYTE
SHUFR1:	SOJL	T4,CPOPJ1##	;DONE, SO QUIT
	ILDB	P1,T3		;GET FIRST BYTE
	PUSHJ	P,CHKSTR	;DO START CODE CONVERSION IF NEEDED
	PUSHJ	P,CHKST1	;DO STOP CODE CONVERSION
	SOJL	T4,SHUFR3	;DONE AFTER FIRST BYTE
	ILDB	P2,T3		;GET NEXT CHARACTER
	PUSHJ	P,CHKST2	;DO STOP CODE CONVERSION
	LSH	P2,^D8		;SHIFT INTO POSITION
	IOR	P2,P1		;PUT CHARACTERS TOGETHER
	HRLZM	P2,(T2)		;STORE CHARACTERS
	SOJL	T4,CPOPJ1##	;DONE
	ILDB	P1,T3		;GET ANOTHER CHARACTER
	PUSHJ	P,CHKST1	;DO STOP CODE CONVERSION
	SOJL	T4,SHUFR4	;DONE
	ILDB	P2,T3		;GET LAST CHARACTER
	PUSHJ	P,CHKST2	;DO STOP CODE CONVERSION
	LSH	P2,^D8		;PUT INTO POSITION
	IOR	P2,P1		;PUT CHARACTERS TOGETHER
	HRRM	P2,(T2)		;STORE CHARACTERS
	AOJA	T2,SHUFR1	;NEXT WORD

SHUFR3:	HRLZM	P1,(T2)		;STORE CHARACTER
	PJRST	CPOPJ1##	;RETURN

SHUFR4:	HRRM	P1,(T2)		;STORE CHARACTER
	PJRST	CPOPJ1##	;RETURN
;HERE TO DO START CODE CONVERSION
CHKSTR:	SKIPN	P3		;IS THIS THE FIRST BYTE?
	POPJ	P,		;NO--RETURN
	CAIN	P1,25		;STANDARD START CODE?
	MOVEI	P1,356		;YES--LP20 VERSION
	CAIN	P1,26		;6 LPI?
	MOVEI	P1,354		;YES--LP20 VERSION
	CAIN	P1,27		;8 LPI?
	MOVEI	P1,355		;YES--LP20 VERSION
	SETZ	P3,		;CLEAR FIRST BYTE FLAG
	POPJ	P,		;RETURN

;HERE TO CONVERT STOP CODE IN P1
CHKST1:	CAIN	P1,126		;IS IT THE STOP CODE?
	MOVEI	P1,357		;YES--LP20 VERSION
	POPJ	P,		;RETURN

;HERE TO CONVERT STOP CODE IN P2
CHKST2:	CAIN	P2,126		;IS IT THE STOP CODE?
	MOVEI	P2,357		;YES--LP20 VERSION
	POPJ	P,		;RETURN
SUBTTL	MACROS FOR GENERATING DEFAULT VFU DATA

; THE FOLLOWING MACROS ARE USED TO GENERATE VFUBUF, WHICH CONTAINS
; THE DEFAULT VFU DATA TO BE LOADED. THE DEFAULT DATA IN COMBINATION WITH
; THE DEFAULT RAM DATA LOADED BY THE RESRAM ROUTINE WILL MAKE
; THE LP20 AND ITS PRINTER OPERATE SIMILIARLY TO A BA10/LP100 STYLE SYSTEM.

DEFINE MOD(A,B),<A-<<A/B>*B>>	;TAKE A MODULO B

; MACRO OUTBYT - USED TO GENERATE A STREAM OF 7-BIT BYTES. CALLED EACH TIME
; A BYTE NEEDS OUTPUTING. ASSEMBLES 5 7-BIT BYTES AND THEN OUTPUTS A
; EXP PSEUDO-OP.

DEFINE OUTBYT(B),<
	..BC==..BC+1		;;INCREMENT THE BYTE COUNT
	..BP==..BP+7		;;BUMP THE POSITION POINTER BY BYTE SIZE
	B==<B&177>_<^D35-..BP>	;;MAKE SURE ONLY 7 BITS WIDE AND THEN
				;;SHIFT TO PROPER POSITION IN CURRENT WORD
	..B==..B!B		;;PUT BYTE INTO ACCUMULATOR
	IFE ..BP-^D34,<		;;IF WE'RE AT THE LAST BYTE IN CURRENT WORD
		..BP==-1	;;RESET POSITION POINTER TO BEGINNING
	EXP	..B		;;ASSEMBLE THE WORD
		..B=0		;;CLEAR OUT THE ACCUMULATOR
	>;END IFE
>;END DEFINE

; MACRO LASBYT - MUST BE CALLED AFTER ANY USAGE OF OUTBYT MACRO TO ENSURE
; THAT THE LAST BYTE(S) GET OUTPUT.

DEFINE LASBYT,<
	IFN ..B,<		;;IF THERE IS SOMETHING LEFT IN THE ACCUMUALTOR
	EXP	..B		;; ASSEMBLE IT
	>;END IFN
	EXP	..BC		;;ASSEMBLE BYTE COUNT AS LAST WORD
>;END DEFINE
; MACRO VFUBIT - CALLED TO OUTPUT TWO BYTES OF DATA FOR A PARTICULAR
; LINE NUMBER IN THE VFU. GENERATES CHANNEL BIT SETTINGS FOR
; A STANDARD VFU TAPE.

DEFINE VFUBIT(LINE),<
	..BT==0			;;ZERO THE BIT ACCUMULATOR

					;;DO 1ST BYTE - CHANNELS 1-6
	IFE LINE,<..BT==..BT!1>		;;LINE 0 GETS CHANNEL 1 (TOP OF FORM)
	IFE MOD(LINE,36),<..BT==..BT!2>	;;EVERY 30 LINES GETS CHANNEL 2
	IFE MOD(LINE,2),<..BT==..BT!4>	;;EVEN NUMBERED LINES GET CHANNEL 3
	IFE MOD(LINE,3),<..BT==..BT!10>	;;EVERY 3RD LINE GETS CHANNEL 4
	IFE MOD(LINE,12),<..BT==..BT!40>;;EVERY TEN LINES GETS CHANNEL 6
	IFLE LINE-^D59,<..BT==..BT!20>	;;ALL LINES GET CHANNEL 5
	IFGE LINE-^D60,<..BT==20>	;;LINES 60-65 GET ONLY CHANNEL 5
	OUTBYT(..BT)			;;OUTPUT THIS BYTE

					;;DO 2ND BYTE - CHANNELS 7-12
	..BT==0				;;ZERO THE BIT ACCUMULATOR
	IFE MOD(LINE,24),<..BT==..BT!1>	;;EVERY 20 LINES GET CHANNEL 7
	IFLE LINE-^D59,<..BT==..BT!2>	;;LINES 0-59 GET CHANNEL 8
	IFE LINE-^D59,<..BT==..BT!40>	;;LINE 59 GETS CHANNEL 12
	IFGE LINE-^D60,<..BT==0>	;;LINES 60-65 GET NOTHING
	OUTBYT(..BT)			;;OUTPUT THIS BYTE
>;END DEFINE
SUBTTL	DEFAULT VFU DATA BUFFER

	..BP==-1		;INITIALIZE POSITION FOR FIRST BYTE
	..B==0			;INITIALIZE BYTE ACCUMULATOR
	..BC==0			;INITIALIZE BYTE COUNT

	..L==0			;INITIALIZE LINE COUNTER
	STARTC==25		;DEFINE START CODE
	STOPC==126		;DEFINE STOP CODE

VFUBUF:
	SALL
	OUTBYT(STARTC)		;OUTPUT THE START CODE
REPEAT ^D66,<			;66 LINES/PAGE
	VFUBIT(..L)		;DO BYTES FOR THIS LINE
	..L==..L+1		;BUMP LINE COUNTER
>;END REPEAT
	OUTBYT(STOPC)		;OUTPUT THE STOP COODE
	LASBYT			;FINISH UP
	XALL
VFUBFZ==.-VFUBUF		;SIZE OF DATA BUFFER

$LIT
END