Google
 

Trailing-Edge - PDP-10 Archives - bb-bt99m-bb - dnlp20.p11
There are 4 other files named dnlp20.p11 in the archive. Click here to see a list.
.SBTTL	LP20 DRIVER FOR ANF10 NETWORK NODES  /D. LYONS  18 DEC 84

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
; OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) 1978,1979,1980,1981,1984 BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.

VRLP20=004			;FILE EDIT NUMBER

.IF NE LP20N			;ASSEMBLE ONLY IF WE HAVE ANY LP20'S


; The LP20 Line Printer System is a hard-copy printer system designed to 
; interface with the PDP-11 Unibus.  Each printer system comprises a 
; self-contained, free-standing printer and a seperate solid-state
; controller (LP20 Controller).  The controller consists of three logic
; modules, a wired backplane assembly, and associated cabling.
;
; Design of the LP20 Line Printer System provides for large amounts of
; formatted or unformatted text to be printed with minimum software
; intervention.  This is accomplished by transferring characters under
; direct memory access (DMA) control and by using a random access memory
; (RAM) in the LP20 Controller to control actions taken on individual
; characters.  Thus, software need only handle errors and situations
; that cannot be handled by data stored in the RAM.
;
; Serval types of line printers are supported by the LP20 Controller; the
; line printers are plug-for-plug compatible and use identical cabling.
;
; Line printers that may be connected to the LP20 are listed below.
;
;	LP05 (Modified DPC 2230)
;	LP07 (Modified DPC 2550)
;	LP10 (Modified DPC 2470)
;	LP14 (Modified DPC 2290)
;
; Only the LP10 does not support software defined DAVFU
	.SBTTL	THEORY (OR HOPES) OF OPERATION

; SINCE THE LP20 IS A DMA DEVICE, THE DRIVER USES A DOUBLE BUFFERING
; METHOD TO TRY AND KEEP THE LINE PRINTER RUNNING AT ALL TIMES.
; A BUFFER (WHICH IS LARGE ENOUGH TO HOLD ANY RAM OR VFU) IS DEFINED
; IN THE DDB FOR EACH PRINTER.  THE DRIVER USES THIS SPACE AS TWO BUFFERS.
; WHILE ON IS PRINTING, THE OTHER IS FILLING UP.  THIS SPACE IS USED FOR
; NORMAL DATA AS WELL AS EXPANSION OF COMPRESSED DATA.  THE BUFFER IS
; FILLED TO THE END, AND ANY EXTRA COMPRESSED COUNTS OR SPACES ARE STORED
; IN DB.CCN (COUNT) AND DB.HLD (BYTE).  THESE ARE CHECKED WHEN THE PRINTER
; BUFFERS ARE SWAPPED, AND PRINTING CONTINUES.
; IF THERE IS A VFU OR RAM ERROR, THE ERROR BIT IS SET, AND THE DATA FOR THE 
; PRINTER IS FLUSHED UNTIL A NEW RAM OR VFU IS RECIEVED. (IN THE FIRST VERSION,
; THE RAM WILL BE RELOADED ON THE SPOT, AND PRINTING WILL CONTINUE.)
;DB.DCS STATUS BITS FOR LPT SERVICE

	SLP.FE=	B0	;FATAL ERROR
	SLP.FL=	B1	;OFF LINE
	SLP.PZ=	B2	;PAGE COUNT ZERO
	SLP.VE=	B3	;VFU ERROR
	SLP.RE=	B4	;RAM ERROR
	SLP.IC=	B5	;ILLEGAL CHAR
	SLP.PE=	B7	;PARITY ERROR
	SLP.DE=	B8	;DEMAND ERROR
	SLP.ME=	B9	;MASTER SYNC ERROR
	SLP.SV= B15	;SUPPRESS VFU ("IMAGE" DATA)


;DB.DVT ATTRIBUTES BITS FOR LPT SERVICE

	DLP.LL=	B2	;LOWER CASE
	DLP.FC=	B14	;FULL CHARACTER SET
	DLP.8B=	B15	;EIGHT-BIT CHARACTER DATA (NO COMPRESSION)


;DATA FOR LINE PRINTER IS COMPRESSED AS FOLLOWS:
;	1CCCCCCC	CCCCCCC IS CHARACTER
;	01XXXXXX	XXXXXX IS NUMBER OF BLANKS
;	001XXXXX	XXXXX IS REPETITION FOR FOLLOWING CHAR
	.SBTTL	ALLOCATE DATA STORRAGE IN THE DDB FOR LP20

;ATTRIBUTES FOR THE LP11-SERVICED PRINTERS
;
;	LP-.LL		LPT- IS LOWER CASE
;	LP-FCS		LPT- IS FULL CHARACTER SET (NO TAB SIMULATION,
;			  NO FREE CRLF [WARNING!!!], PASS ALL NON-VFE
;			  CHARACTERS - <ESC>, ETC.)
;	LP-8BT		LPT- IS AN 8-BIT-ASCII PRINTER (THEREFORE CAN'T
;			  SUPPORT DATA COMPRESSION)
;	LP-DVU		LPT- "DVU" (PRINTER TYPE - 1=LP05, 2=LN01, ETC)


L2.DAT=	DB.SIZ		; DATA BUFFER FOR OUTPUT TO LP20
			; MUST BE LARGE ENOUGH FOR RAM LOADING
L2.BP0=	L2.DAT+<2*^D256>; BUFFER POINTER 0
L2.BC0=	L2.BP0+2	; BUFFER COUNTER 0
L2.BP1=	L2.BC0+2	; BUFFER POINTER 1
L2.BC1=	L2.BP1+2	; BUFFER COUNTER 1
L2.WP=	L2.BC1+2	; WORKING POINTER USED TO FILL BUFFERS
L2.WC=	L2.WP+2		; WORKING COUNTER 
L2.STA=	L2.WC+2		; STATE WORD FOR INTERUPT DRIVER
	; THIS WORD IS DIVIDED INTO TWO HALFS,  THE UPPER HALF IS FOR
	; FLAG STATE BITS, AND THE LOWER HALF IS USED AS A DISPATCH INDEX
	; FOR THE PROPER ACTION WHEN A CHARACTER IS RECIEVED

	L2S.RP=	100000	; RESTART THE PRINTER. GO WAS CLEARED, AND
			; THERE IS MORE DATA TO BE PRINTED IN THE BUFFER
	L2S.DM=	40000	; SOME BITS IN DB.DCS WERE CHANGED ON THE LAST PASS
			; THRU THE STATE CHECKING ROUTINE
	L2S.AB=	20000	; THE CURRENT BUFFER IS THE SECOND BUFFER (THIS IS
			; FOR FILLING, NOT PRINTING)
	L2S.FE=	10000	; FLAG ERROR.  SET BY INTERUPT SERVICE TO
			; LET THE SERVICE ROUTINE KNOW TO DO ERROR
			; FIXUP OR CORRECTION

	L2S.PD=	0	; PRINTING DATA, ALL IS OK WITH PRINTER
	L2S.DD=	2	; DUMPING DATA, WAITING FOR RAM AND/OR VFU
	L2S.BV=	4	; BUILDING A VFU TO LOAD
	L2S.BR=	6	; BUILDING A RAM TO LOAD
	L2S.PL=	10	; PRINTING PENDING LOAD OF RAM OR VFU
	L2S.MX=	10	; MAX STATE

L2.SIZ=	L2.STA+2	; END OF DDB


.MACRO	DDXGEN	DEV,DV,DRQ,XBITS,XZZ
	.BLKB	<L2.SIZ-DB.SIZ>	; ALLOCATE SPACE FOR THE LPT WORK SPACE
.ENDM


DRESET=0

	DDBGEN	LP2,L2,LP20N,4,<DS.OUT>

.MACRO	DDXGEN
.ENDM
	.SBTTL	RECIEVED DATA FORMAT

; RAM DATA

;	RAM DATA IS IN THE INPUT STREAM, WHEN A STATUS MESSAGE
;	IS RECEIVED FROM THE -10 WITH THE RAM DATA BIT SET IN
;	DB.DCS.  AT THAT TIME, THE DATA FOR THE PRINTER WILL BE FLUSHED
;	(IF ITS THE RIGHT THING TO DO) OR PRINTED, AND THE TWO BUFFERS
;	WILL BE FILLED UNTIL THE RAM DATA BIT GETS CLEARED BY THE -10
;	THEN, THE RAM WILL BE LOADED FROM THE BUFFERS
;
;	THE DATA FOR THE RAM WILL BE SENT AS EXTENSIBLE NUMBERS
;	THE LARGEST VALUE ALLOWED IS 1777 (THIS IS A RAM RESTRICTION)



; DAVFU DATA

;	SAME AS RAM DATA
;	EXECPT THE LARGEST VALUE WILL BE 37777.
	.SBTTL	LP20 SERVICE ROUTINES

; HERE WHEN DNDEV WANTS TO CONNECT TO THIS LP20 FOR SOME LOSER

LP2SER:	CMP	#LPTMML,DB.MML(J)	; IS THE LENGTH REASONABLE ?
	BPL	10$			; YES, USE HIS
	MOV	#LPTMML,DB.MML(J)	; NO, USE MINE
10$:	MOVB	#DCM.AS!DCM.CF,DB.DCM(J); SET MODE ASCII AND COMPRESSED
	MOVB	#5,DB.DVV(J)		; LP-20 IS LPT CONTROLLER TYPE 5
	JSR	PC,LP2CVR		; CHECK VFU AND RAM FOR RIGHT STATE
	CLRB	DB.HLD(J)
	CLRB	DB.CCN(J)
	MOV	J,R0			; COPY POINTER TO DDB
	ADD	#L2.DAT,R0		; POINT TO THE START OF THE AREA
	MOV	#<L2.SIZ-L2.DAT>,R1	; NUMBER OF BYTES TO ZAP
20$:	CLRB	(R0)+			; CLEAR BYTE OUT
	SOB	R1,20$			; AND LOOP TILL DONE
	BIS	#L2S.DM,DB.DCS(J)	; FORCE THE FIRST DCS SEND
	JSR	PC,DVCCFM		; CONFIRM THAT HE HAS THIS PRINTER
					; WE WILL COME HERE THE REST OF THE
					; TIME WHEN THE DEVICE IS QUEUED
	TRACE	DV			; LEAVE TRACKS FOR DEBUGGING
	JSR	PC,LP2CVR		; CHECK VFU AND RAM FOR RIGHT STATE
	BIT	#L2S.DM,L2.STA(J)	; DO WE NEED TO SEND STATUS ?
	BEQ	21$			;  NO, SKIP IT
	BIC	#L2S.DM,L2.STA(J)	; WE SENT IT
	JSR	PC,DVXDCS		; SEND DEVICE STATUS TO THE OWNER
21$:	JSR	PC,DVXDRQ		; ASK FOR DATA IF WE NEED IT
	MOV	DB.OBF(J),R0		; GET POINTER TO THE OUTPUT
	BEQ	40$			; NONE, SO WAIT FO IT
;
; HERE TO CHECK FOR FILLING THE BUFFERS OF THE LPT WITH MORE DATA
;
60$:	MOVB	L2.STA(J),R3		; GET STATE OF THE PRINTER
	JMP	@61$(R3)		; DISPATCH TO RIGHT SECTION

61$:	LP2PDA				; PRINTING DATA
	LP2DDA				; DUMPING DATA
	LP2BVF				; BUILDING VFU
	LP2BRA				; BUILDING RAM
	LP2WPD				; WAITING FOR DATA TO PRINT


LP2ESR:
40$:	BIT	#DS.DIE!DS.DSC,(J)	; ARE WE GIVING UP ON LOSER ?
	BEQ	50$			; NO, WE ARE JUST WAITING
	JSR	PC,DVCCFM		; SEND DISCONNECT
50$:	RTS	PC
LP2PDA:	;
	;	HERE WHEN WE ARE PRINTING DATA IN THE NORMAL WAY
	;
	TST	L2.BP1(J)		; GOT A PLACE TO PUT IT ?
	BNE	LP2ESR			; NO. GO TO END OF SERVICE ROUTINE
	JSR	PC,L20NST		; SEE IF WE SHOULD CHANGE
					; THE STATE (ON ERROR) (MAY NOT RETURN)
	;
	; R3 WILL BE THE POINTER TO THE NEW BUFFER
	; R2 WILL BE THE COUNT FOR THE NEW BUFFER
	;
	MOV	J,R3			; POINTER TO DDB
	ADD	#L2.DAT,R3		; POINT TO FIRST BUFFER
	BIT	#L2S.AB,L2.STA(J)	; ARE WE TO USE SECOND BUFFER ?
	BEQ	10$			; NO, THIS ONE WILL DO
	ADD	#^D256,R3		; HARD WIRED HALF OF THE BUFFER
	CLR	R2			; NO DATA YET
10$:	JSR	PC,L20GNC		; GET NEXT CHAR TO PRINT
	BR	11$			; NO MORE DATA, SO CALL IT QUITS
	BR	12$			; WE HAVE EATEN A MESSAGE TYPE
	MOVB	R0,(R3)			; SAVE CHAR IN BUFFER
	INC	R2			; AND COUNT CHAR
	CMP	#^D256,R2		; DID WE FILL THE BUFFER YET?
	BNE	10$			; NO, GET MORE DATA

11$:	TST	R2			; DID WE WIN ANYTHING ?
	BEQ	LP2ESR			; NO, WHAT A LOSE
	PIOFF				; YEST, SO POST THE BUFFER
	NEG	R2			; MINUS THE COUNT
	TST	L2.BP0(J)		; DOES HE HAVE ANY DATA ?
	BEQ	14$			; NO WHAT A LOSE
	MOV	R3,L2.BP1(J)		; POST BUFFER 2
	MOV	R2,L2.BC1(J)		; AND THE NUMBER OF BYTES
	BR	15$

14$:	MOV	R3,L2.BP0(J)		; POST AS BUFFER 1
	MOV	R2,L2.BC0(J)		; AND THE NUMBER OF BYTES
	MOV	DB.HDW(J),R0		; POINT TO DEVICE
	BIC	#L2.A17!L2.A16!L2.DL!L2.TM,(R0)
	BIS	#L2.PEN!L2.ENB,(R0)	; POKE DEVICE
	MOV	L2.BP0(J),L20ADR(R0)	; POINT TO BUFFER
	MOV	L2.BC0(J),L20CNT(R0)	; NUMBER OF BYTES
	BIS	#L2.GO,(R0)		; START DEVICE
	BIS	#DS.ACT,(J)		; SET ACTIVE STATUS
15$:	PION				; DONE
	BIT	#L2S.AB,L2.STA(J)	; WHICH BUFFER WAS THAT ?
	BNE	16$			; THE SECOND ONE
	BIS	#L2S.AB,L2.STA(J)	; USE THE SECOND ONE THE NEXT TIME
	BR	LP2PDA			; SEE IF WE CAN FILL UP ANOTHER
16$:	BIC	#L2S.AB,L2.STA(J)	; USE THE FIRST BUFFER NEXT TIME
	BR	LP2PDA			; SEE IF WE CAN DO MORE

12$:	; HERE ON MESSAGE TYPE
	DEC	R0
	BEQ	10$			; WON A DATA MESSAGE
	DEC	R0
	BEQ	10$			; ANOTHER DATA MESSAGE
	DEC	R0
	BEQ	18$			; CONTROL MESSAGE (PAGE COUNT ?)
	DEC	R0
	BEQ	19$			; STATUS MESSAGE
.IF NE DGUTS
	CTYMSG	NCL
20$:	JSR	PC,DVGBYT		; EAT MESSAGE ALL UP
	BR	20$
	BR	12$			; NEW MESSAGE TYPE
	BR	11$			; END OF MESSAGE
.IFF
	TRAP
.ENDC
	.SBTTL	LP2CVR	CHECK THE VFU AND RAM, FIX STATUS BITS IF NEED BE


.MACRO	LP20ER	R1BITS,R2BITS,R3BITS
	MOV	#R1BITS,R1		; ERROR BIT
	MOV	#R2BITS,R2		; DB.DCS BIT
	MOV	#R3BITS,R3		; EXTRA BITS
	JSR	PC,L20TEB		; TEST THE ERROR BITS
.ENDM



LP2CVR:	SAVE	<R0,R1,R2,R3>
	MOV	DB.HDW(J),R0		; POINT TO DEVICE
	ADD	#2,R0			; POINT TO CSRB
	LP20ER	L2.DNR,SLP.VE,0
	LP20ER	L2.POL,SLP.FL,0
.IF NE RPLPOL
	BCC	10$
	CTYMSG	LPT
.ENDC
10$:	LP20ER	L2.LPE,SLP.PE,0
	LP20ER	L2.MPE,SLP.PE,0
	LP20ER	L2.RPE,SLP.RE,0
	LP20ER	L2.MST,SLP.ME,0
	LP20ER	L2.DTE,SLP.DE,0
	ADD	#-2,R0			; MOVE POINTER BACK TO CSRA
	LP20ER	L2.PZE,SLP.PZ,0		; PAGE COUNT ZERO
	LP20ER	L2.UCD,SLP.IC,SLP.RE	; UNDEFINED CHAR
	RESTORE	<R3,R2,R1,R0>
	RTS	PC


L20TEB:	CLC				; FLAG NO ERROR ON FIRST TIME
	BIT	R1,(R0)			; CHECK ERROR BIT
	BNE	10$			; ERROR IS SET
	BIT	R2,DB.DCS(J)		; DID I TELL -10 ABOUT ERROR ?
	BEQ	15$			; NO, WE NEVER TOLD HIM THERE WAS ONE
	BIC	R2,DB.DCS(J)		; CLEAR ERROR, AND GO TELL -10 ITS OK
	BIC	R3,DB.DCS(J)		; CLEAR OTHER BITS, TOO
	BR	20$

10$:	BIT	R2,DB.DCS(J)		; IS THIS AN OLD ERROR ?
	BNE	15$			; YES, NOTHING WORTH GETTING UPSET ABOUT
	SEC				; TELL CALLER THIS IS A NEW ERROR
	BIS	R2,DB.DCS(J)		; SET STATUS FLAG BIT
	BIS	R3,DB.DCS(J)		; AND OTHER ERROR FLAGS
20$:	BIS	L2S.DM,L2.STA(J)	; SAY SOMTHING CHANGED
15$:	RTS	PC
	.SBTTL	LP2TIM	TIMER ACTION FOR LP20

LP2TIM:	BIT	#DS.ACT,(J)		; ARE WE ACTIVE ?
	BEQ	10$			; NO, SO JUST WAKE US UP
	MOVB	#-5,DB.TIM(J)		; CHECK IN NEXT 30 SECONDS
	JSR	PC,LP2CVR		; CHECK FOR ERRORS ET ALL
	BCC	20$			; IF CARRY IS SET, THE WE ARE BACK
					; IN BUSINESS, AND NEED TO WAKE US UP
10$:	JSR	PC,QUEDEV		; ASK FOR SOME MORE DATA
20$:	RTS	PC
	.SBTTL	INTERUPT SERVICE FOR THE LP20

DEVINT	LP20,L2

LP20INT:	BIT	#L2.ERR!L2.PZE!L2.UCD,@DB.HDW(J)
					; CHECK FOR ANY OF THREE ERRORS
	BEQ	10$			; NO ERRORS, SO KEEP GOING
	BIC	#L2.ENB,@DB.HDW(J)	; SHUT OFF DEVICE FOR NOW
	BIS	#L2S.FE,L2.STA(J)	; FLAG WE HAD AN ERROR
	CLRB	DB.TIM(J)		; RESET THE TIMER TO 0 TIME
12$:	JSR	PC,QUEDEV		; QUE THIS DEVICE FOR SERVICE
	RESTORE	<J>
	RTI

10$:
;
;	HERE TO START NEXT BUFFER AND RETURN FOR SERVICE
;
	MOV	L2.BP1(J),L2.BP0(J)	; COPY BUFFER POINTER UP
	BEQ	11$			; NOTHING, SO SHUT IT DOWN
	MOV	L2.BC1(J),L2.BC0(J)	; COPY COUNT ALSO
	BEQ	11$			; NO COUNT, NO DATA EITHER
	CLR	L2.BP1(J)
	CLR	L2.BC1(J)		; CLEAR OLD POINTERS
	SAVE	<R0>
	MOV	DB.HDW(J),R0
	BIC	#L2.A17!L2.A16!L2.DL!L2.TM,(R0)
	BIS	#L2.PEN!L2.ENB,(R0)
	MOV	L2.BP0(J),L20ADR(R0)	; SET ADDRESS OF OUTPUT
	MOV	L2.BC0(J),L20BCT(R0)	; AND THE NUMBER OF BYTES
	BIS	L2.GO,(R0)		; AND START THE PRINTER
	RESTORE	<R0>
	BR	12$

11$:
;
;	HERE WHEN WE ARE DONE WITH THE DEVICE
;
	BIC	#DS.ACT,(J)		; SET DEVICE STOPPED
	BIC	#L2.ENB,@DB.HDW(J)	; STOP DEVICE, TOO
	BR	12$			; ASK FOR MORE SERVICE
.ENDC