Trailing-Edge
-
PDP-10 Archives
-
bb-bt99l-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