Trailing-Edge
-
PDP-10 Archives
-
bb-jr93h-bb
-
7,6/ap021/lp2ser.x21
There are 3 other files named lp2ser.x21 in the archive. Click here to see a list.
TITLE LP2SER - LINE PRINTER SERVICE FOR LP20 CONTROLLER ON 2020 - V035
SUBTTL D. DETROY/DBD 25-OCTOBER-88
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,035 ;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
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: 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