Google
 

Trailing-Edge - PDP-10 Archives - BB-F492Z-DD_1986 - 10,7/703mon/lp2ser.mac
There are 8 other files named lp2ser.mac in the archive. Click here to see a list.
TITLE LP2SER - LINE PRINTER SERVICE FOR LP20 CONTROLLER ON 2020 - V021
SUBTTL	D. DETROY/DBD	10 SEP 85
	SEARCH	F,S
	$RELOC
	$HIGH

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
.CPYRT<1978,1986>
;COPYRIGHT (C) 1978,1979,1980,1982,1984,1986
;BY DIGITAL EQUIPMENT CORP., MAYNARD, MASS.
;ALL RIGHTS RESERVED.

;



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

	ENTRY	LP2SER
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
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-RECOVERABLE 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	LPT SERVICE DISPATCH TABLE

;LINE PRINTER SERVICE DISPATCH TABLE

	JRST	LPTONL		;SEE IF LPT IS ON LINE NOW
	JRST	LPTDVP		;DEVOP. UUO
	JRST	REGSIZ##	;GET BUFFER SIZE FROM DDB
	JRST	LPTINI		;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

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

	;NOTE:  THE LPTINI CODE FORCES IOGO IN SYSINI TO INVOKE
	;       LPTINI 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 LPTINI CODE
	;       IS DEPENDENT UPON THE IOGO CODE WHICH SHOULD BE:
	;
	;		PUSHJ P,DINI(P3)
	;		HRRZM P3,SAVITM

LPTINI:	MOVE	T1,LPTBAS##(F)		;GET BASE ADDRESS OF IO REGISTERS
	PUSHJ	P,UBGOOD##		;IS LP20 ALIVE ON THE UNIBUS?
	  PJRST	CPOPJ1##		;NO--JUST RETURN
	HRRZ	T1,LPTVEC##(F)		;GET INTERRUPT VECTOR ADDRESS
	LSH	T1,-2			;DIVIDE BY 4
	HLRZ	T2,LPTBAS##(F)		;UNIBUS ADAPTOR NUMBER
	ADD	T1,.EPVIT##-1(T2)	;ADD INT VECTOR TABLE ADDRESS
	MOVE	T2,LPTIVI##(F)		;GET INT VECTOR INSTRUCTION
	MOVEM	T2,(T1)			;PUT INTO VECTOR TABLE
	TLO	S,LPTRAM+LPTVFU		;MARK RAM AND VFU FOR LOADING
	PUSHJ	P,LPTREL		;GO THRU RELEASE CODE
	MOVSI	T1,-.HCSIZ		;LOAD LENGTH OF ERROR BLOCK
	HRRI	T1,LPTDAE##(F)		;MAKE AN AOBJN POINTER
	MOVEM	T1,LPTDAP##(F)		;AND STORE IT
	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
	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

LPTINT::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
IFN FTPI,<
	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
	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
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
	MOVE	T2,JBTPPN##(J)		;PICK UP PPN
	MOVEM	T2,LPTDAE##+.HCUID(F)	;SAVE IT
	MOVE	T2,JBTPRG##(J)		;PICK UP PROGRAM NAME
	MOVEM	T2,LPTDAE##+.HCPGM(F)	;SAVE IT
	MOVEI	T1,.ERHCC		;LOAD SYSERR TYPE
	HRLI	T1,LPTDAP##(F)		;POINTER TO AOBJN POINTER
	PJRST	DAEERR##		;CALL DAEMON
;HERE TO SETUP HARDWARE CHARACTERISTICS WORD AND DETERMINE CONTROLLER TYPE
LPTTYP:	SKIPL	DEVCHR(F)		;A LOWER CASE PRINTER?
	TDZA	T3,T3			;NO, UPPER CASE
	MOVSI	T3,(HC.LCP)		;YES, NOTE THAT
	SKIPL	DEVCHR(F)		;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
	SKIPGE	DEVCHR(F)		;A LOWER CASE PRINTER?
	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