.MCALL .MODULE .MODULE LS,VERSION=37,COMMENT= ; Copyright (c) 1998 by Mentec, Inc., Nashua, NH. ; All rights reserved ; ; This software is furnished under a license for use only on a ; single computer system and may be copied only with the ; inclusion of the above copyright notice. This software, or ; any other copies thereof, may not be provided or otherwise ; made available to any other person except for use on such ; system and to one who agrees to these license terms. Title ; to and ownership of the software shall at all times remain ; in Mentec, Inc. ; ; The information in this document is subject to change without ; notice and should not be construed as a commitment by Digital ; Equipment Corporation, or Mentec, Inc. ; ; Digital and Mentec assume no responsibility for the use or ; reliability of its software on equipment which is not supplied ; by Digital or Mentec, and listed in the Software Product ; Description. .SBTTL Abstract and Edit History ;++ ; Facility: RT-11 SERIAL LINE PRINTER HANDLER ; ; Author: Numerous ; ; Abstract: The serial printer handler (LS) was originally designed ; to allow a terminal/printer attached to a DL-type ; interface to be used as a line printer. Recent changes ; have added the ability to use any line of a multi- ; terminal configuration (DL, DZ or DH) for communicating ; with the printer. ; ; ; Edit Who Date Description of modification ; ---- --- ---- --------------------------- ; 001 WLD 01-MAY-90 In the routine GETOVR, an unnecessary ; PUSH and POP of R0 was removed. The ; JSR R0,10$ performs the desired save ; of R0. This change fixes a bug if ; a read error is reported. It had been ; possible to BCS SET.NOR with an extra ; copy of R0 still on the stack. ; ; (029) 17-Aug-90 MBG Added multiterminal handler hook support ; ; (030) 17-Sep-90 MBG Major restructuring to correct some assembly ; errors. ; ; (031) 21-Sep-90 MBG Previous restructuring made a MTYHK-only version ; of LS feasible, finished changes to do so. ; ; (032) 11-Jan-91 MBG Fix of GETC routine which was losing XOFF/XON ; when on the PRO. Minor change to O.SPEED routine ; so only low byte of O$SPEE is altered when the ; command is issued. ; ; (033) 12-Jan-91 MBG Code change to allow installation of the handler ; when set MTTY on a system that does not have the ; DL interface specified by INSCSR. ; ; (034) 28-Mar-91 MBG Added FETCH/LOAD code to check the installation CSR ; against those of a multiterminal monitor to ensure ; no CSR or VECTOR usage conflict when set NOMTTY. ; ; (035) 01-Apr-91 MBG Change to previous method for detecting handler ; hooks support ; ; (036) 22-Apr-91 MBG Fix to FETCH code to use proper vectors ; ; (037) 21-May-91 MBG Replaced over-ride definition of LS$CSR if LS$PDP=0 and ; LS$PC = 1 (was accidently removed at some point). ; ;-- .SBTTL Conditional assembly summary ;+ ;COND ; ; LS$PC (0) No support for PRO-3xx ; 1 Support for PRO-3xx ; ; LS$PDP 0 No support for traditional PDPs ; (1) Support for traditional PDPs ; ; LS$MTY (0) Generate support for MTTY handler hooks ; 1 ; ; Any combination of the above bits is allowed, with the ; requirement that at least one must be specified. ; ; LS$LUN (1) Number of default LUN to attach ; ; LS$HANG (TIM$IT) support hang message ; 0 no hang message support ; 1 hang message support ; ; EIS$I (MMG$T) use SOB instruction ; 0 simulate SOB ; 1 use SOB ; ; LS$PRI (4) interrupt priority ; 4--7 possible values (use 5 for SBC) ; LS.CSZ (132.) default WIDTH ; ?? ; ; LS.PSZ (66.) default LENGTH ; ?? ; ; LS$VCX (470) "temporary" vector ; ; LS$CSR (176500) default CSR (if PDP supported) ; LS$CSR (173400) default CSR (if ONLY PRO supported) ; ; LS$VEC (300) default VECTOR (if PDP supported) ; LS$VEC (220) default VECTOR (if ONLY PRO supported) ; ; PC.CSR = 173400 fixed CSR for a PRO ; PC.VEC = 220 fixed vector for a PRO ; ; MMG$T std conditional ; TIM$IT std conditional (code effect via LS$HANG) ; ERL$G std conditional (no code effects) ;- .LIBRARY "SRC:SYSTEM.MLB" .SBTTL ORDER and LABEL PSECTS .PSECT LSDVR .PSECT $$$PAD .PSECT SETOVR .PSECT PC$PDP PCBASE: .PSECT LSDVR .SBTTL MACROS AND DEFINITIONS .DSABL GBL ; Declare the RT system macros we'll use .MCALL .DRDEF, .INTEN, .MTPS .MCALL .ADDR, .ASSUM, .BR .MCALL .READC, .WRITE, .WRITC .MCALL .FORK, .TIMIO, .CTIMIO .MCALL .MTSTA ; Assembly defaults .IIF NDF LS$PC LS$PC = 0 ;Default to no support for PRO-3xx .IIF NDF LS$PDP LS$PDP = 1 ;Support for Traditional PDPs .IIF NDF LS$MTY LS$MTY = 0 ;Default to no support for MTY hooks .IIF NDF LS$LUN LS$LUN = 1 ;Default to LUN 1 .Assume NE 0 MESSAGE= .IIF NDF TIM$IT TIM$IT= 0 ;Assume no timer support .IIF NE TIM$IT TIM$IT= 1 .IIF NDF LS$HANG LS$HANG = TIM$IT .IIF NE LS$HANG LS$HANG = 1 .IIF NE MMG$T EIS$I = 1 .IIF NDF EIS$I EIS$I = 0 .IIF EQ EIS$I .MCALL SOB .IIF NDF LS$PRI LS$PRI = 4 ;Interrupt processing level for DL .IIF NDF LS.CSZ LS.CSZ = 132. ;DEFAULT COLUMN SIZE (WIDTH) .IIF NDF LS.PSZ LS.PSZ = 66. ;DEFAULT PAGE SIZE .IIF NDF LS$VCX LS$VCX = 470 ;Default temporary vector PC.CSR = 173400 ;Fixed CSR for a PRO PC.VEC = 220 ; ... vector ; Set the audit trail .LSGEN = LS$PDP ! ! ! .LSGEN = .LSGEN ! .AUDIT .LS ;The handler .AUDIT .LSGEN ; and the conditionals in effect ; .FORK block offsets F.BADR = 2 ; Now define the device .IF NE LS$PC .IF EQ LS$PDP LS$CSR = PC.CSR LS$VEC = PC.VEC .ENDC ;EQ LS$PDP .ENDC ;NE LS$PC .IF NE .IF NE LS$PDP .DRDEF LS,41,,0,176500,300,DMA=NO .IFF ;NE LS$PDP .DRDEF LS,41,,0,173400,220,DMA=NO .ENDC ;NE LS$PDP .IFF ;EQ .IF NE LS$MTY .DRDEF LS,41,,0,0,0,DMA=NO .ENDC ;EQ LS$MTY .ENDC ;NE .IF NE LS$MTY .DRPTR FETCH=FETCH,LOAD=LOAD,UNLOAD=UNLOAD,RELEASE=RELEAS .IFF ;NE LS$MTY .IF NE LS$PDP .DRPTR FETCH=FETCH,LOAD=LOAD .ENDC ;NE LS$PDP .ENDC ;NE LS$MTY .IF NE .DREST CLASS=DVC.LP,MOD2=DV2.V2 .IFF ;NE .DREST CLASS=DVC.LP .ENDC ;NE ; RT-11 file structured request codes CLOS.. =:1 ;Close request LOOK.. =:3 ;Lookup request ENTE.. =:4 ;Enter request .READ =:10 ;.READ request (byte val) .WRITE =:11 ;.WRITE request (byte val) ; RT-11 System communication area .MCALL .SYCDF .SYCDF ; RMON fixed offset area .MCALL .FIXDF .CF1DF .CF2DF .MCALL .SGNDF .FIXDF ;Define RMON fixed offsets .CF1DF ;Define config word 1 bits .CF2DF ;Define config word 2 bits .SGNDF ;Define SYSGEN features word bits ; Multiterminal status block .MCALL .MSTDF .MSTDF ;Define .MTSTA status block ; Handler header definitions .MCALL .HBGDF .HBGDF ;Define handler header ; Multiterminal handler hooks .MCALL .TCBDF .THKDF .TSTDF .TCBDF ;Define TCB offsets .THKDF ;Define handler hooks data structure .TSTDF ;Define T.STAT bits ; Significant other definitions V.TRP4 =: 004 ; Trap to 4 vector BLK =: 1000 ; Block size for disks BLOCK0 = 0 ; Block 0 PSW = 177776 ;Processor status word PR0 =:000000 ;Priority 0 PR7 =:000240 ;Priority 7 CARRY =:000001 ;Carry Bit SYSCHN = 17 ; Overlay channel ; Interface bit definitions RC.IE = 000100 ;Receiver interrupt enable XC.IE = 000100 ;Transmitter interrupt enable .IF NE LS$PC ; PRO-3xx interrupt controller registers IC0DR = 173200 ;Interrupt controller 0 data register IC0CR = IC0DR+2 ;Interrupt controller 0 CSR register C.CSM = 050 ;Clear single IMR bit C.SSM = 070 ;Set single IMR bit C.CSI = 110 ;Clear single IRR bit C.SSI = 130 ;Set single IRR bit RC.ID = 005 ;Receiver ID XC.ID = 006 ;Transmitter ID ; PRO-3xx printer port registers LS$BUF = PC.CSR ;RECV/XMIT buffer register LS$STA = PC.CSR+2 ;Status register LS$MOD = PC.CSR+4 ;Mode registers 1 and 2 LS$CMD = PC.CSR+6 ;Command register ; Status register bit definitions ST.DSR = 200 ;Data set ready ST.FE = 040 ;Framing error ST.OE = 020 ;Overrun error ST.PE = 010 ;Parity error ST.RD = 002 ;Receiver done ST.TR = 001 ;Transmitter ready ; Mode register 1 bit definitions M1.SBM = 300 ;Stop bit mask SB.1 = 100 ;1 stop bit SB.15 = 200 ;1.5 stop bits SB.2 = 300 ;2 stop bits M1.PT = 040 ;Parity type (on selects even) M1.PEN = 020 ;Parity enable M1.CLM = 014 ;Character length mask CL.5 = 000 ;5 bit characters CL.6 = 004 ;6 bit characters CL.7 = 010 ;7 bit characters CL.8 = 014 ;8 bit characters M1.REQ = 002 ;Required bits ; Mode register 2 bit definitions M2.REQ = ^B10110000 ;Required bits B.50 = 00 ; 50 baud B.75 = 01 ; 75 baud B.110 = 02 ; 110 baud B.134 = 03 ; 134.5 baud B.150 = 04 ; 150 baud B.300 = 05 ; 300 baud B.600 = 06 ; 600 baud B.1200 = 07 ; 1200 baud B.1800 = 10 ; 1800 baud B.2000 = 11 ; 2000 baud B.2400 = 12 ; 2400 baud B.3600 = 13 ; 3600 baud B.4800 = 14 ; 4800 baud B.7200 = 15 ; 7200 baud B.9600 = 16 ; 9600 baud B.192K = 17 ; 19.2K baud ; Command mode register bit definitions CM.OM1 = 200 ;Operating mode 1 CM.OM0 = 100 ;Operating mode 0 CM.RTS = 040 ;Request to send CM.RE = 020 ;Reset error CM.FB = 010 ;Force BREAK CM.RXE = 004 ;Receiver enable CM.DTR = 002 ;Data terminal ready CM.TXE = 001 ;Transmitter enable .ENDC ;NE LS$PC ; Characters C.HT = 11 C.LF = 12 C.FF = 14 C.CR = 15 C.CTLQ = 'Q-100 C.CTLS = 'S-100 C.SPAC = 40 .SBTTL Block 0 of handler file ; Tables for SET code .ASECT . = 0 REF0:: . = 120 ; ROMCHK ; Insure that the location we access as a CSR is not ROM. (The ; PRO300 CSR addr is a ROM on many PDPs.) .ENABL LSB .IF NE LS$PDP ROMCHK: .IF EQ LS$PC CLRB @INSCSR ;*C=0* Make sure the CSR addr is read/write .IFF ;EQ LS$PC CLRB @DISCSR ;*C=0* Make sure the CSR addr is read/write .ENDC ;EQ LS$PC BCS 10$ ;Failed .IF EQ LS$PC BITB #177,@INSCSR ;Did we clear it (for "writable" ROM) ;Note that bit seven may be on in a CSR ;(DONE) .IFF ;EQ LS$PC BITB #177,@DISCSR ;Did we clear it (for "writable" ROM) ;Note that bit seven may be on in a CSR ;(DONE) .ENDC ;EQ LS$PC BEQ 10$ ;Yes, then probably a CSR SEC ;No, not a CSR 10$: RETURN ;Return the carry as found .ENDC ;NE LS$PDP .DSABL LSB .IF NE LS$MTY .IF NE ONOMTT: .IF EQ LS$PC MOV CSRSAV,INSCSR ;Restore install-time CSR .ENDC ;EQ LS$PC MOV VECSAV,H1.VEC ;Restore vector information OMTTY: MOVB R3,I$MTTY ;Set/Reset 'MTTY hooks in use' flags MOVB R3,O$MTTY ; ... BR BS.NOR .ENDC ;NE .ENDC ;NE LS$MTY .ASSUME . LE MESSAGE= .SBTTL INSTALLATION CODE .ENABL LSB .IF NE .DRINS -LS,PC.CSR .IFF ;NE .IF EQ LS$MTY .DRINS LS .IFF ;EQ LS$MTY .DRINS -LS .ENDC ;EQ LS$MTY .ENDC ;NE BR 10$ ;Install as data device BR 40$ ;Never install as a system device 10$: MOV @#$SYPTR,R0 ;R0->$RMON .IF NE LS$MTY TSTB I$MTTY ;Are handler hooks needed? BEQ 20$ ;Nope... BIT #PROS$,$CNFG2(R0) ;Yes, installing on a PRO-3xx? BNE 40$ ;Yes, then reject installation TST $THKPT(R0) ;Is handler hooks support available? BEQ 40$ ;Nope, reject installation .IF NE BR 30$ ;Yes, nothing to do until Fetch/Load .ENDC ;NE .ENDC ;NE LS$MTY 20$: .IF NE BIT #PROS$,$CNFG2(R0) ;Installing on a PRO-3xx? .IF EQ LS$PC BNE 40$ ;Yes, but no support, don't install .ENDC ;EQ LS$PC .IF EQ LS$PDP BEQ 40$ ;No, but no PDP support, don't install .IFF ;EQ LS$PDP BEQ ROMCHK ;Nope, beware of ROM as CSR .ENDC ;EQ LS$PDP .IF NE LS$PC TSTB @#LS$CMD ;Reset internal access to MR1 MOVB #,@#LS$MOD ;Set 1 stop bit, no parity, ; 8 bit characters O$SPEE ==: <. + 2> ;For SET code reference MOVB #,@#LS$MOD ;Now set RECV and XMIT speed MOVB #,@#LS$CMD ;Set ; normal operation, RTS, ; reset errors, receiver enable, ; DTR, transmitter enable .ENDC ;NE LS$PC .ENDC ;NE BS.NOR: 30$: TST (PC)+ 40$: SEC RETURN .DSABL LSB .IF NE LS$PC ; SPEED table. Mask for given speed is same as the word offset into table. ; to select 134.5bps, specify 134 in the SET command SPEEDT: .WORD 50., 75., 110., 134. .WORD 150., 300., 600., 1200. .WORD 1800., 2000., 2400., 3600. .WORD 4800., 7200., 9600., 19200. .WORD 0 ;Fence .ENDC ;NE LS$PC .IF NE LS$PDP ; SET LS VECTOR=octal_address I.VEC: .IF NE MOV R0,LX$VTB ;Save the input .IFF ;NE MOV R0,LS$VTB ;Save the input .IFTF ;NE ADD #4,R0 .IFT ;NE MOV R0,LX$VTB+6 ; and output vector addresses .IFF ;NE MOV R0,LS$VTB+6 ; and output vector addresses .ENDC ;NE CMP R3,R0 ;Check the base address ; (returns c-bit=1 if too high) RETURN .ENDC ;NE LS$PDP .IF NE LS$MTY I$MTTY: .BYTE -1 ; : Install-time 'hooks required' flag .BLKB ;reserved .IF NE VECSAV: .WORD </2-1>+100000 ; : Vector info for SET NOMTTY CSRSAV: .IF NE .WORD 0 ; : CSR info for SET NOMTTY .IFF ;NE .WORD LS$CSR ; : CSR info for SET NOMTTY .ENDC ;NE .ENDC ;NE .ENDC ;NE LS$MTY .ASSUME . LE 400 MESSAGE= .SBTTL SET OPTION PARAMETER TABLE ; Option Data Routine syntax ; ------ ------ ------- ------ .DRSET BIT8 O.BIT8/2 GETOVR NO ;[NO]BIT8 .DRSET CR O.CR/2 GETOVR NO ;[NO]CR .IF NE LS$PDP .DRSET CSR O.CSR/2 GETOVR OCT ;CSR=n .ENDC ;NE LS$PDP .DRSET CTRL O.CTRL/2 GETOVR NO ;[NO]CTRL .DRSET ENDPAG O.ENDP/2 GETOVR NUM ;ENDPAG=n .DRSET FORM O.FF/2 GETOVR NO ;[NO]FORM .DRSET FORM0 O.FORM0/2 GETOVR NO ;[NO]FORM0 .DRSET GRAPH O.GRAP/2 GETOVR NO ;[NO]GRAPHIC .IF NE LS$HANG .DRSET HANG O.HANG/2 GETOVR NO ;[NO]HANG .ENDC ;NE LS$HANG .DRSET LC O.LC/2 GETOVR NO ;NO[LC] .DRSET LENGTH O.LENG/2 GETOVR NUM ;LENGTH=n .IF NE LS$MTY .DRSET LINE O.LINE/2 GETOVR NUM ;LINE=n .IF NE .DRSET MTTY -1 O.MTTY NO ;[NO]MTTY .ENDC ;NE .ENDC ;NE LS$MTY .DRSET SKIP O.SKIP/2 GETOVR NUM ;SKIP=n .IF NE LS$PC .DRSET SPEED O.SPEE/2 GETOVR NUM ;SPEED=n .ENDC ;NE LS$PC .DRSET TAB O.TAB/2 GETOVR NO ;[NO]TAB .IF NE LS$PDP .DRSET VECTOR 477 O.VEC OCT ;VECTOR=n .ENDC ;NE LS$PDP .DRSET WIDTH O.WIDTH/2 GETOVR NUM ;WIDTH=n .SBTTL SET OPTION PROCESSING ROUTINES .IF NE LS$PDP ; SET LS VECTOR=vector_address O.VEC: BR I.VEC .ENDC ;NE LS$PDP .IF NE LS$MTY ; SET LS [NO]MTTY .IF NE O.MTTY: BR 10$ ;Entry point for MTTY NOP ;placekeeper CLR R3 ;Entry point for NOMTTY JMP ONOMTT 10$: CLR INSCSR ;Nope, reset install-time CSR and CLR H1.VEC ; vector so handler installs JMP OMTTY .ENDC ;NE .ENDC ;NE LS$MTY .SBTTL GETOVR - Get Overlay SET code routine from disk ;+ ; GETOVR - The following routine will read an overlay from disk ; containing the requested SET routine. It will also calculate ; the entry point in the overlay for the specific routine. ; If 'NO' was specified in the SET command, GETOVR+4 will be ; called by the monitor. In this case, GETOVR will jump to ; the routine+4. ; ; Input : R3 = addr/2 of routine to enter ; ; NOTE: The Overlays will be read to block 0 - but not an entire block will ; be read! A routine will always be kept in block 0 to bring the real ; block zero into memory when the overlay has finished. ;- .ENABL LSB .Assume . LE 662 MESSAGE= . = 662 ; Put the read routine at top of ; block 0 VALWCT =: ./2 ; Read till here - protect the rest OVRSIZ =: . ; Use in .Assume in overlay code .SBTTL GETBK0 - Read block zero - resident routine ;+ ; GETBK0 - This routine will not be overlayed by the SET code - instead ; it will always be called by the SET code routines to exit. ; The routine reads the real block zero from disk! ;- GETBK0: MOV #SET.EX/2,R3 ; Fake GETOVR into loading block 0 ; then transferring control to SET.EX .BR GETOVR GETOVR:: CMPB -(R3),-(R3) ; Adjust for "NO" adjust NOP ; Next line is 'NO' entry pt. .Assume . EQ GETOVR+4 CMPB (R3)+,(R3)+ ; Add 4 to the routine address SWAB R3 ; Get BLK number into low byte MOVB R3,REABLK ; Store the BLK into EMT BIC #377,R3 ; Clear BLK, OFFSET in high ;;; BIS #BLOCK0/BLK,R3 ; User BUFFER block for ADDR .Assume BLOCK0 EQ 0 JSR R0,10$ ; Save R0, R0 -> EMT REAFUN: .BYTE 17,10 ; CHANNEL , READ REABLK: .BLKW 1 ; Block number to read REABUF: .BLKW 1 ; Buffer addr to read .WORD VALWCT ; Words to read! .WORD 0 ; Wait mode I/O 10$: .ADDR #BLOCK0,R5,PUSH ; Get addr of buffer MOV R5,REABUF ; Save into EMT MOV (SP)+,R5 ; Restore R5 EMT 375 ; ***.READW*** MOV (SP)+,R0 ;*C* Pop R0, Save carry BCS SET.NOR ; Branch if error SWAB R3 ; Get addr back ASL R3 ; Make into byte offset ADD REABUF,R3 ; Make into real address JMP @R3 ; Go to routine ; Common exit for everyone (including overlays) SET.EX: TST R2 ; Any previous errors ? BEQ SET.NOR ; No, branch DEC R2 ; Usual error BEQ SET.ERR ; Yes, branch ADD #2,(SP) ; Write protect error - return SET.ERR:SEC ; Indicate error SET.NOR:RETURN .DSABL LSB .Assume . LE 1000 MESSAGE= .SBTTL DRIVER ENTRY .ENABL LSB .IF EQ LS$MTY .DRBEG LS .IFF ;EQ LS$MTY .DRBEG LS,0 .ENDC ;EQ LS$MTY MOV LSCQE,R4 ;R4->Current queue element MOVB Q$FUNC(R4),R5 ;Special request? BNE FILREQ ;Yes ASL Q$WCNT(R4) ;Convert from word to byte count BEQ LSDONE ;Seeks complete immediately BCC LSERR ;And reads are illegal... MOV SP,DIDIO ; indicate a WRITE was done CALL ENAINI ;Enable input interrupts DOINT: TST STALLF ;Starting out stalled? .IF EQ LS$HANG BNE 20$ ;Yes... .IFF ;EQ LS$HANG BNE O$HANG ;Yes... .ENDC ;EQ LS$HANG CALL ENAOUI ;Enable output interrupts 20$: RETURN .DSABL LSB .SBTTL FILREQ - File request processing ;+ ; ; FILREQ ; Entered through driver entry code on receipt of a ; positive function (USR operation) ; ;- FILREQ: ;Condition codes set from above BMI LSDONE ;SPFUN request, ignore it CLR Q$WCNT(R4) ;Force to 0 length request CMPB R5,#ENTE.. ;Enter request? BEQ 10$ ;Yes, just ignore it quietly CMPB R5,#CLOS.. ;Close request? BEQ DOINT ;Yes CMPB R5,#LOOK.. ;Lookup request? BNE LSDONE ;no 10$: CLR DIDIO ;Clear I/O was done flag BR LSDONE ;and finished .SBTTL REGISTERS AND VECTOR TABLES .IF NE LS$PDP RCSR: .WORD LS$CSR ;Receiver CSR (non-PRO) RBUF: .WORD LS$CSR+2 ;Receiver buffer (non-PRO) XCSR: .WORD LS$CSR+4 ;Transmitter CSR (non-PRO) XBUF: .WORD LS$CSR+6 ;Transmitter buffer (non-PRO) .ENDC ;NE LS$PDP .IF NE .IF NE .DRVTB LS,LS$VCX,LIINT ;Dummy input interrupt entry .DRVTB ,LS$VCX+4,LSINT ;Dummy output interrupt entry .DRVTB LX,LS$VEC,LIINT ;Input interrupt entry (for XON/XOFF) .IFF ;NE .DRVTB LS,LS$VEC,LIINT ;Input interrupt entry (for XON/XOFF) .ENDC ;NE .DRVTB ,LS$VEC+4,LSINT ;Output interrupt entry .ENDC ;NE .SBTTL INPUT INTERRUPT SERVICE .ENABL LSB .IF NE .DRAST LI,LS$PRI,LSABT .ENDC ;NE HIINT: ;Input interrupt hook point .IF NE CALL GETC ;Get a character .ENDC ;NE BIC #^C<177>,R5 ;Strip the parity bit CMPB R5,#C.CTLQ ;Are we being XON'd BNE 20$ ;Nope, check for XOFF .IF NE LS$HANG CALL CTIMER ;Cancel any active timer request .ENDC ;NE LS$HANG CLR STALLF ;Unstall us CALLR ENAOUI ; and enable output interrupts 20$: CMPB R5,#C.CTLS ;Are we being XOFF'd? BNE 30$ ;Nope, then ignore the character CALL DISOUI ;Turn off output interrupts MOV SP,STALLF ;Indicate we're stalled .IF NE LS$HANG TST LSCQE ;Is there an active queue element? BEQ 30$ ;Nope, ignore the interrupt. ;*** SET *** O$HANG: BR EXIT ;HANG (BR EXIT) ;NOHANG (NOP) .Assume O$HANG-LSSTRT LT 1000 MESSAGE= TST TCOMPL ;Active timer already? BNE 30$ ;Yes, don't need to do all this! MOV LSCQE,R4 ;R4 => queue element. MOVB Q$JNUM(R4),R4 ;Get job number of this request. ASR R4 ;Shift it ASR R4 ; to the right ASR R4 ; 3 bits BIC #^C<16>,R4 ;Isolate the job number. MOV R4,TJOBNM ;Save it for .TIMIO .ADDR #OFFLIN,R4 ;Calculate .TIMIO compl rtne addr. MOV R4,TCOMPL ;Stuff it in timer block. .FORK LIFBLK ;Fork for possible upcoming timer req. .TIMIO TBLOCK,0,60.*5 ;Wait 5 sec - timeout means not ready. .ENDC ;NE LS$HANG 30$: EXIT: RETURN ;OK to leave now. .DSABL LSB .SBTTL OPERATION COMPLETE .ENABL LSB LSABT: .IF NE LS$HANG CALL LSCLR ;Shut things down CALL CTIMER ; and cancel any outstanding timer .ENDC ;NE LS$HANG CLR STALLF ;Unstall us .IF NE MOVB #C.CR,R5 ;R5 = CALL PRINTC ;Print it, enabling interrupts ; which will be turned back off ; in a few instructions, at LSCLR .ENDC ;NE BR LSDONE ;Now back to our show... LSERR: BIS #HDERR$,@-(R4) ;Flag the error LSDONE: CALL LSCLR ;Shut things off .IF EQ LS$MTY .DRFIN LS ;Tell RT we're done .IFF ;EQ LS$MTY .ADDR #LSCQE,R4 ;R4 -> Device queue MOV @#$SYPTR,R5 ;R5->$RMON CALL @$QCOMP(R5) ;Tell RT we're done via modified DRFIN SEC RETURN .ENDC ;EQ LS$MTY LSCLR: .IF NE LS$HANG CLR LIFBLK+F.BADR ;Disable outstanding input .FORK .ENDC ;NE LS$HANG ;;; CLR LOFBLK+F.BADR ;Disable outstanding output .FORK CALL DISOUI ;Disable output CALL DISINI ; and input interrupts 20$: RETURN .DSABL LSB .IF NE LS$MTY .SBTTL MultiTerminal Handler Hooks support data ; *** SET *** O$MTTY: .BYTE -1 ;Default support to used .Assume O$MTTY-LSSTRT LT 1000 MESSAGE= ; *** SET *** O$LINE: .BYTE LS$LUN ;Default LUN .Assume O$LINE-LSSTRT LT 1000 MESSAGE= ISPND: .BYTE -1 ; : Input suspend flag OSPND: .BYTE -1 ; : Output suspend flag .SBTTL LSHOOK - Multiterminal Handler Hooks hook routine ;+ ; ; LSHOOK ; Entered from terminal interrupt service. Used to supply the ; next outgoing character. ; ; Call (TH.GOC): ; R0 = function code ; ; Return (TH.GOC): ; PSW = 0, R5 = character ; PSW = 1, no character available ; ; Call (TH.PIC): ; R0 = function code ; R5 = character ; ;- .ENABL LSB LSPNAM: .Rad50 /LS/ ; : Rad50 physical name ; loaded by FETCH/LOAD code LSHOOK: .Assume EQ 2 MESSAGE= MOV R4,-(SP) ;Save register for awhile ; Function code = TH.GOC = 1 ; (Get output character) CMP R0,#TH.GOC ;'Get Output Character' request? BNE 10$ ;Nope... TSTB OSPND ;Is output suspended? BNE 20$ ;Yep... CALL HOINT ;Hook output interrupt BR 30$ ;*C* ; Function code = TH.PIC = 2 ; (Put input character) 10$: CMPB R0,#TH.PIC ;'Put Input Character' request? BNE 20$ ;Nope... TSTB ISPND ;Is input suspended? BNE 20$ ;Yep... CALL HIINT ;Hook input interrupt BR 30$ 20$: SEC ;Return with failure 30$: MOV (SP)+,R4 ;*C* Restore previously saved register RETURN .DSABL LSB .ENDC ;NE LS$MTY .SBTTL OUTPUT INTERRUPT SERVICE .ENABL LSB .IF NE .DRAST LS,LS$PRI,LSABT .IFF ;NEQ .IF NE LS$MTY BR LSABT LSINT: .ENDC ;NE LS$MTY .ENDC ;NE HOINT: ;Output interrupt hook point MOV LSCQE,R4 ;Are we really doing anything? BEQ 50$ ;Nope, ignore the interrupt CMPB #CLOS..,Q$FUNC(R4) ;Close request? BNE 10$ ;Nope DIDIO =: <. + 2> TST #.-. ;Any Writes done? BEQ LSDONE ;If not then don't do ENDPAG (yet) ;*** SET *** O$ENDP =: <. + 2> MOV #0,Q$WCNT(R4) ;Indicate number of FF to do .Assume O$ENDP-LSSTRT LT 1000 MESSAGE= BEQ LSDONE ;None, finished MOVB #<100!CLOS..>,Q$FUNC(R4) ;Change request to strange function 10$: CMPB #<100!CLOS..>,Q$FUNC(R4) ;Doing ENDPAG FFs? BEQ 20$ ;Yes, emit any previous FF TST @R4 ;Is this block 0? ;*** SET *** O$FORM: BEQ BLK0 ;FORM0 (BEQ BLK0): Print initial ;NOFORM0 (NOP) : Nothing special .Assume O$FORM-LSSTRT LT 1000 MESSAGE= TST STALLF ;Are we stalled? BNE 50$ ;Yes, so just return ASLB (PC)+ ;Tab expansion in progress? TABFLG: .WORD 0 ; : Expansion count flag BNE TAB ;Yes, expand using spaces 20$: MOV (PC)+,R5 ;Doing a ? FFFLAG: .WORD 0 ; : Form feed flag BNE DOFORM ;Yes, go handle it CMPB #<100!CLOS..>,Q$FUNC(R4) ;Doing ENDPAG FFs? BNE 30$ ;No, continue normally DEC Q$WCNT(R4) ;Any left to do? BGE BLKZ ;Yes, print 1 BR LSDONE ;No, finished 30$: ;;; .FORK LOFBLK ;Fork for following code IGNORE: TST Q$WCNT(R4) ;Any characters left to transfer? BEQ LSDONE ;Nope, this request is done... .IF EQ MMG$T MOVB @Q$BUFF(R4),R5 ;Get a byte from the user's buffer INC Q$BUFF(R4) ;Bump the pointer for next time .IFF ;EQ MMG$T CALL @$GTBYT ;Get a byte from the user's buffer MOV (SP)+,R5 ; into R5 .ENDC ;EQ MMG$T INC Q$WCNT(R4) ;One less character to do... ;*** SET *** O$BIT8 =: <. + 2> ;^c377/177 for SET BIT8/NOBIT8 BIC #^C<177>,R5 ;Strip to 7 bit ascii .Assume O$BIT8-LSSTRT LT 1000 MESSAGE= BEQ IGNORE ; and nulls are not to be suffered ASRB (PC)+ ;Did we just skip the perf.? SKPFLG: .WORD 0 ; : Perforation skip flag BCC 40$ ;Nope... CMPB R5,#C.FF ;Yes, followed by another ? BEQ IGNORE ;Yes, ignore it 40$: CMPB R5,#C.SPACE ;Is character printable? BLO CHRTST ;Nope, check for special ones... CMPB R5,#'A!40 ;Is it lower case? BLO PCHAR ;Nope... CMPB R5,#'Z!40 ;Maybe, check upper limit BHI PCHAR ;Definately not... BIC (PC)+,R5 ;Yes, make it upper case (if set NOLC) ;*** SET *** O$LC: .WORD 0 ;LC (0) ;NOLC (40) .Assume O$LC-LSSTRT LT 1000 MESSAGE= PCHAR: DEC COLCNT ;Room on the line for this character? ;*** SET *** O$GRAP: BLT IGNORE ;NOGRAPHIC Nope, try another character ;GRAPHIC (NOP) Print everything .Assume O$GRAP-LSSTRT LT 1000 MESSAGE= ASLB (PC)+ ;Yes, update tab expansion counter TABCNT: .WORD 1 ; : Tab expansion counter (shifty) BEQ RSTTAB ;Hit another one, reset the counter PRINTC: .IF NE CALL PUTC ;Output the character .ENDC ;NE TST (PC)+ 50$: SEC 60$: RETURN ; SPECIAL CHARACTERS CHRTST: CMPB R5,#C.HT ;Is character a ? ;*** SET *** O$TAB: BEQ TABSET ;NOTAB (BEQ TABSET) : Use spaces ;TAB (BEQ HDWTAB) : Use real CMPB R5,#C.FF ;Is it a ? BEQ SENDFF ;Yes, go process it CMPB R5,#C.CR ;Is it a ? ;*** SET *** O$CR: BEQ RSTC ;CR (BEQ RSTC) : Send it ;NOCR (NOP) : Nothing special CMPB R5,#C.LF ;Is it a ? ;*** SET *** O$CTRL: BNE PRINTC ;CTRL (BNE PRINTC) : Print all others ;NOCTRL (BNE IGNORE) : Ignore it CMP LINCTR,(PC)+ ;Time to skip a perforation? ;*** SET *** O$SKIP: .WORD 0 ; : Perforation skip count BLE SKIPFF ;Yes, go handle it DOFORM: DEC LINCTR ;Nope, at end of page? BGT RSTC ;Not yet... ; *** Begin critical ordering *** .IF EQ <.-LSSTRT>&777-774 NOP .ENDC NEWPAG: MOV (PC)+,(PC)+ ;Yes, reset line count ;*** SET *** O$LENG: .WORD LS.PSZ ; : Total lines per page LINCTR: .WORD LS.PSZ ; : Lines left on this page .Assume </1000> EQ </1000> MESSAGE= ; *** End Critical Ordering CLR FFFLAG ;Reset form feed flag ; *** Begin Critical Ordering *** .IF EQ <.-LSSTRT>&777-774 NOP .ENDC RSTC: MOV (PC)+,(PC)+ ;Reset carriage position ;*** SET *** O$WIDT: .WORD LS.CSZ ; : Total columns per line COLCNT: .WORD LS.CSZ ; : Columns left one this line .Assume </1000> EQ </1000> MESSAGE= ; *** End critical ordering *** CLR TABFLG ;Reset tab expansion flag RSTTAB: MOV #1,TABCNT ;Reset the tab stop counter BR PRINTC ;Phew...print the character BLKZ: BLK0: INC @R4 ;Block 0, ensure we come here once SENDFF: MOVB #C.CR,R5 ;If filling, restore the carriage ;*** SET *** O$FF ==: <. + 2> MOV #C.FF,FFFLAG ;Get the (or 100000! filler) BMI RSTC ;If doing 's, go count them CLR LINCTR ;Real , do it only once BR RSTC ;Send a to reset carriage TABSET: MOV TABCNT,TABFLG ;Set up expansion counter TAB: MOVB #C.SPACE,R5 ;And print a space BR PCHAR HDWTAB: ASLB TABCNT ;Hardware tabs, adjust tab count BEQ RSTTAB ;Count columns for each extra space DEC COLCNT ;Adjust column count BR HDWTAB ;Continue until next tab position SKIPFF: INC SKPFLG ;Set the skip flag BR SENDFF ;And go do a .DSABL LSB .IF NE LS$HANG .SBTTL TIMER SUPPORT ROUTINES ; CTIMER ; Used to cancel an active timer CTIMER: TST TCOMPL ;Is timer active? BEQ 10$ ;Nope, then nothing to cancel .FORK LIFBLK ;Must fork before .CTIMIO TBLOCK ; cancelling timer CLR TCOMPL ;Make sure it's inactive 10$: RETURN ; OFFLIN ; Completion routine entered when the timer expires. Used to ; abort a transfer. OFFLIN: MOV @SP,-(SP) ;Save the return address .IF EQ MMG$T CLR 2(SP) ; and fake a PS=0 (for an RTI) .IFF MOV @#PSW,2(SP) ; (under XM, retain previous mode) .ENDC ;EQ MMG$T .MTPS #340 ;Now, up to priority 7 .INTEN 0,PIC ;;;Now enter system state ; (the preceeding has been done ; to simulate the affects of ; a .DRAST) CLR TCOMPL ;De-activate the timer MOV LSCQE,R4 ;Set up R4 for .DRFIN JMP LSERR ;Exit with hard error .ENDC ;NE LS$HANG .IF NE .SBTTL GETC - Get an input character ;+ ; ; GETC ; Gets a character from the input device ; ; Return: ; R5 = Character ; ;- .ENABL LSB GETC: .IF NE LS$MTY TSTB O$MTTY ;Terminal hooks in use? BNE 10$ ;Yes, character already in R5 ; due to entry through hook point .ENDC ;NE LS$MTY .IF NE PDPA1: .ENDC ;NE .IF NE LS$PDP MOVB @RBUF,R5 ;Get a character (DL) .ENDC ;NE LS$PDP .IF NE PDPZ1 =:.-PDPA1 .SAVE .PSECT PC$PDP PCA1: .ENDC ;NE .IF NE LS$PC MOVB @#LS$BUF,R5 ;Get a character (PRO) .ENDC ;NE LS$PC .IF NE PCZ1 =:.-PCA1 .RESTORE .Assume PDPZ1 EQ PCZ1 .ENDC ;NE 10$: RETURN .DSABL LSB .SBTTL PUTC - Output a character ;+ ; ; PUTC ; Puts a character to the output device ; ; Call: ; R5 = Character ; ;- .ENABL LSB PUTC: .IF NE LS$MTY TSTB O$MTTY ;Terminal hooks in use? BNE 10$ ;Yes, simply return the character ; when we return to hook routine .ENDC ;NE LS$MTY .IF NE PDPA2: .ENDC ;NE .IF NE LS$PDP MOVB R5,@XBUF ;Print the character (DL[V]) .ENDC ;NE LS$PDP .IF NE PDPZ2 =:.-PDPA2 .SAVE .PSECT PC$PDP PCA2: .ENDC ;NE .IF NE LS$PC MOVB R5,@#LS$BUF ;Print the character (PRO) .ENDC ;NE LS$PC .IF NE PCZ2 =:.-PCA2 .RESTORE .Assume PDPZ2 EQ PCZ2 .ENDC ;NE 10$: RETURN .DSABL LSB .ENDC ;NE .SBTTL DISINI - Disable input interrupts .SBTTL ENAINI - Enable input interrupts .ENABL LSB DISINI: .IF NE LS$MTY .IF NE TSTB O$MTTY ;Terminal hooks in use? BEQ 10$ ;Nope... .IFTF ;NE MOVB #-1,ISPND ;Suspend input interrupt processing .IFT ;NE BR 20$ .ENDC ;NE .ENDC ;NE LS$MTY 10$: .IF NE PDPA3: .ENDC ;NE .IF NE LS$PDP BIC #RC.IE,@RCSR ;Nope, disable input interrupts .ENDC ;NE LS$PDP .IF NE PDPZ3 =:.-PDPA3 .SAVE .PSECT PC$PDP PCA3: .ENDC ;NE .IF NE LS$PC MOVB #,@#IC0CR ;Disable input interrupts .ENDC ;NE LS$PC .IF NE PCZ3 =:.-PCA3 .RESTORE .Assume PDPZ3 EQ PCZ3 .ENDC ;NE 20$: RETURN .DSABL LSB .ENABL LSB ENAINI: .IF NE LS$MTY .IF NE TSTB O$MTTY ;Terminal hooks in use? BEQ 10$ ;Nope... .IFTF ;NE CLRB ISPND ;Resume input interrupt processing .IFT ;NE BR 20$ .ENDC ;NE .ENDC ;NE LS$MTY 10$: .IF NE PDPA4: .ENDC ;NE .IF NE LS$PDP BIS #RC.IE,@RCSR ;Enable input interrupts .ENDC ;NE LS$PDP .IF NE PDPZ4 =:.-PDPA4 .SAVE .PSECT PC$PDP PCA4: .ENDC ;NE .IF NE LS$PC MOVB #,@#IC0CR ;Enable input interrupts .ENDC ;NE LS$PC .IF NE PCZ4 =:.-PCA4 .RESTORE .Assume PDPZ4 EQ PCZ4 .ENDC ;NE 20$: RETURN .DSABL LSB .SBTTL DISOUI - Disable output interrupts .SBTTL ENAOUI - Enable output interrupts .ENABL LSB DISOUI: .IF NE LS$MTY .IF NE TSTB O$MTTY ;Terminal hooks in use? BEQ 10$ ;Nope... .IFTF ;NE MOVB #-1,OSPND ;Suspend output interrupt processing .IFT ;NE BR 20$ .ENDC ;NE .ENDC ;NE LS$MTY 10$: .IF NE PDPA5: .ENDC ;NE .IF NE LS$PDP BIC #XC.IE,@XCSR ;Nope, disable output interrupts .ENDC ;NE LS$PDP .IF NE PDPZ5 =:.-PDPA5 .SAVE .PSECT PC$PDP PCA5: .ENDC ;NE .IF NE LS$PC MOVB #,@#IC0CR ;Disable output interrupts .ENDC ;NE LS$PC .IF NE PCZ5 =:.-PCA5 .RESTORE .Assume PDPZ5 EQ PCZ5 .ENDC ;NE 20$: RETURN .DSABL LSB .ENABL LSB ENAOUI: .IF NE LS$MTY .IF NE TSTB O$MTTY ;Terminal hooks in use? BEQ 10$ ;Nope... .IFTF ;NE CLRB OSPND ;Enable output interrupt processing MOV TCBADX,R3 ;R3 -> TCB CALL @MTOENX ; and then enable output interrupts .IFT ;NE BR 20$ .ENDC ;NE .ENDC ;NE LS$MTY 10$: .IF NE PDPA6: .ENDC ;NE .IF NE LS$PDP BIS #XC.IE,@XCSR ;Nope, enable output interrupts .IF NE LS$PC NOP NOP NOP .ENDC ;NE LS$PC .ENDC ;NE LS$PDP .IF NE PDPZ6 =:.-PDPA6 .SAVE .PSECT PC$PDP PCA6: .ENDC ;NE .IF NE LS$PC MOVB #,@#IC0CR ;Ensure an interrupt is pending MOVB #,@#IC0CR ; and then enable input interrupts .ENDC ;NE LS$PC .IF NE PCZ6 =:.-PCA6 .RESTORE .Assume PDPZ6 EQ PCZ6 .ENDC ;NE 20$: RETURN .DSABL LSB .SBTTL IMPURE DATA AREAS STALLF: .WORD 0 ; : Stall flag (non-zero = stalled) ;;;LOFBLK: .WORD 0,0,0,0 ;Output fork block .IF NE LS$HANG TBLOCK: .WORD 0,0,0 ;Timer block (hi,lo,link) TJOBNM: .WORD 0 ;Job number. .WORD 177000+LS$CODE ;System sequence (ID). .WORD -1 ;System queue element. TCOMPL: .WORD 0 ;Completion routine address. LIFBLK: .WORD 0,0,0,0 ;INPUT FORK BLOCK. .ENDC ;NE LS$HANG .IF NE LS$MTY MTOENX: .BLKW ;-> Output enable routine TCBADX: .BLKW ;-> TCB owned by handler .ENDC ;NE LS$MTY .DREND LS .SBTTL OVRBK0 -- overlay block number zero ; OVRBK0 ; This code overlays the in-core copy of block zero. This overlay ; is for SET routines which need to alter locations in blocks other ; than block one of the handler image. .PSECT SETOVR ; this PSect must be block aligned OVRBK0: ; base for this overlay BIAS == ; bias due to overlay ; SET LS [NO]CR ; ; ??? BUG ??? SET LS NOCR does not ignore CRs, it just ignores column and ; tab counts O.CR: BR 20$ ;CR entry point NOP ;placekeeper MOV (PC)+,R0 ;NOCR entry point NOP ;When is found, ignore it BR 30$ 20$: MOV (PC)+,R0 ;CR - Use next instruction BEQ RSTC-O$CR+. ;When CR is found, go send it 30$: MOV #O$CR,R3 ;R3 = Offset to change ;;; CALLR CHANGE BR CALTER ; SET LS [NO]CTRL O.CTRL: BR 20$ ;CTRL entry point NOP ;placekeeper MOV (PC)+,R0 ;NOCTRL entry point BNE IGNORE-O$CTRL+. BR 30$ 20$: MOV (PC)+,R0 ;CTRL - Use next instruction BNE PRINTC-O$CTRL+. ;Pass all non-printing characters 30$: MOV #O$CTRL,R3 ;R3 = Location to alter ;;; CALLR CHANGE ;Perform the alteration BR CALTER ; SET LS [NO]FORM O.FF: CLR R0 ;FORM - Ensure NOFORM flag is off BR 20$ ;Skip around NO entry point MOV #100000,R0 ;NOFORM - Ensure flag is on 20$: ADD #C.FF,R0 ;Merge in the character MOV #O$FF,R3 ;R3 = location to alter ;;; CALLR CHANGE ;Perform the alteration BR CALTER .IF NE LS$PDP ; SET LS CSR=octal_address .Assume EQ MESSAGE= O.CSR: CMP R0,#160000 ;Are CSRs in valid range? BLO BS.ERR ;Branch if not CLR R3 ;We want handler block 0 in memory CALL CORWRT ; after block 1 is written out BCS BS.IGN ;Branch if error .IF NE LS$MTY .IF NE MOV R0,(R2) ;Make sure we save it for NOMTTY .ENDC ;NE .ENDC ;NE LS$MTY .IF EQ LS$PC .IF NE LS$MTY TSTB (R2) ;Are handler hooks in use? BNE 10$ ;Yes, don't set install-time CSR .ENDC ;NE LS$MTY MOV R0,(R2) ;Let installation code know about it 10$: .ENDC ;EQ LS$PC MOV R0,(R2) ;Set the display CSR CALL CORREA ;Read block 1 back in BCS BS.IGN ;Branch if error .ADDR #RCSR+BIAS,R1 ;Point to CSR pointers MOV #4,R2 ;Move 4 CSRs 20$: .Assume RCSR+2 EQ RBUF .Assume RBUF+2 EQ XCSR .Assume XCSR+2 EQ XBUF MOV R0,(R1)+ ;Save a CSR addr ADD #2,R0 ;Addr of next CSR SOB R2,20$ BR S.NOR BS.ERR: BR S.ERR ; *** BR Chain *** BS.IGN: BR S.IGN ; *** BR Chain *** .ENDC ;NE LS$PDP ; SET LS LENGTH=page_length O.LENG: TST R0 ;Minimum check - no less than 1 BLE S.ERR ;Branch if error MOV #,R3 ;R3 = Block containing O$LENG CALL CORWRT ;Get the block BCS S.IGN ;In case of error MOV R0,(R2) ;Move in the value MOV R0,(R2) ;Move in the value BR CORXIT ;Exit after rewriting it ; SET LS SKIP=line_count O.SKIP: CMP R0,#255. ;In range? BHI S.ERR ;Nope... TST R0 ;Turning it off? BEQ 10$ ;Yes, set it then check INC R0 ;No, bump it 10$: MOV #O$SKIP,R3 ;R3 = Location to alter CALTER: CALLR CHANGE ;Perform the alteration .IF NE LS$PC ; SET LS SPEED=baud_rate .Assume EQ MESSAGE= O.SPEE: .IF NE MOV @#$SYPTR,R3 ;R3 -> $RMON BIT #PROS$,$CNFG2(R3) ;Running on a PRO? BEQ S.ERR ;Nope, so can't alter speed setting .ENDC ;NE MOV #,R3 ;R3 = Block containing speed table CALL CORWRT ;Update block 1, read block to alter BCS S.IGN ;In case of error... MOV R2,R3 ;R3 -> Speed table ADD #,R3 ; in block zero 30$: TST @R3 ;End of table? BEQ S.ERR ;Yes, requested speed is invalid CMP R0,(R3)+ ;Nope, is this the requested speed? BNE 30$ ;Nope, try another entry SUB PC,R3 ;Yes, now determine the speed mask SUB #,R3 ; ... ASR R3 ;Convert from byte to word offset BIS #M2.REQ,R3 ;Merge in the required bits TSTB @#LS$CMD ;Reset internal pointer to MR1 TSTB @#LS$MOD ;Now make it point to MR2 MOVB R3,@#LS$MOD ;Change the speed now MOVB R3,(R2) ;Let install code know the setting BR CORXIT .ENDC ;NE LS$PC ; SET LS WIDTH=width O.WIDT: CMP R0,#30. ;Minimum check - no less than 30 BLT S.ERR ;Branch if error MOV #,R3 ;R3 = Block containing O$WIDT CALL CORWRT ;Get the block BCS S.IGN ;In case of error MOV R0,(R2) ;Move in the value MOV R0,(R2) ;Move in the value BR CORXIT ;Exit after rewriting it ; SET LS [NO]TAB O.TAB: BR 20$ ;TAB NOP ;placekeeper MOV (PC)+,R0 ;NOTAB - Use NOP BEQ TABSET-O$TAB+. BR 30$ 20$: MOV (PC)+,R0 ;TAB - Use next instruction BEQ HDWTAB-O$TAB+. ;Pass all non-printing characters 30$: MOV #O$TAB,R3 ;R3 = Location to alter ;;; CALLR CHANGE ;Perform the alteration BR CALTER ; This stub causes the altered block to be written back to the ; handler image and block one to be read back in. CORXIT: CALL CORREA ;Put real block 1 back BCS S.IGN ;Error .BR S.NOR ;Return with success .SBTTL ADIOS - Common exit point for overlayed code ;+ ; Common exit back to block 0 resident part ; ; Set code error and success exits ;- S.NOR: CLR R2 ; Indicate no error S.IGN: CMP (PC)+,(PC)+ ; SKip next; Error already set R2 S.ERR: MOV #1,R2 ; Indicate common error JMP GETBK0+BIAS ; GO TO BLOCK ZERO .SBTTL CHANGE - Routine to alter single handler locations ;+ ; CHANGE ; This routine is to be used by routines which have a single ; word to alter in a block. The routine causes the current ; contents of block one to be written back to disk. The block ; to be altered is then read in and altered. Exit is through ; the routine which causes the altered block to be written and ; block one to be read in again ; ; Call: ; R0 = value ; R3 = location to be altered ; CALLR CHANGE ; ; Return: ; none, routine should be entered via CALLR (JMP) ; ;- CHANGE: MOV R3,-(SP) ;Save address of word to alter ASR R3 ;Discard block offset bit <00> CLRB R3 ; and then bits <08:01> SWAB R3 ;R3 = Block number to read CALL CORWRT ;Update block one, read block to alter BCS 10$ ;In case of error... BIC #^C<777>,@SP ;Discard all but block offset ADD R2,@SP ;Build address of location to alter MOV R0,@(SP)+ ;Alter the location BR CORXIT 10$: TST (SP)+ ;Discard saved location BR S.IGN .SBTTL CORE - Sub/Coroutine for core reads/writes ;+ ; This routine will write block 1 to disk - read block n indicated by ; register 3 - return to caller - write block n back to disk with the ; changes the caller made - read block 1 back - return to caller. ; It is assumed that after the first call to CORWRT then modifications ; will be made and a call to CORREA is performed. ; In one case the bootstrap block is read - in another case block zero ; is read to modify the installation CSR etc. ; ; Input: R3 = block to read ; Output: R2 = buffer ; Output/Input: R1 = EMT area (output from CORWRT input to CORREA) ;- ; EMT area used for accessing handler file ;;;BAREA: .BYTE 17,11 ; Channel 17, write ;;; .BLKW ; Block number ;;; .BLKW ; Buffer address ;;; .WORD 256. ; Transfer length (256. words) ;;; .WORD 0 ; Wait-mode .ENABL LSB CORWRT: ;;; MOV R0,-(SP) ;Save value during routine ;;; .ADDR #BAREA+4,R1 ; R1 -> BAREA+4 (buffer address) JSR R0,5$ ;Save R0 across call, R0 -> EMT area BAREA: .BYTE 17,11 ; Channel 17, write .BLKW ; Block number .BLKW ; Buffer address .WORD 256. ; Transfer length (256. words) .WORD 0 ; Wait-mode 5$: MOV R0,R1 ;Make copy of pointer to EMT area .ADDR #1000+BIAS,R2 ;R2 -> Buffer to write ; in-core copy of block 1 ;;; MOV R2,@R1 ; Set the buffer address ;;; MOV #1,-(R1) ; Set up to save the current ;;; TST -(R1) ; block one as it may have been ;;; ; altered by a previous SET command TST (R0)+ ;Bypass ET subcode and channel MOV #1,(R0)+ ;Set to save current block one MOV R2,@R0 ; as it may have already been altered ; by a previous SET command BR 10$ CORREA: MOV R0,-(SP) ;Save value across routine MOV #1,R3 ;Force block to read to block 1 10$: MOV R1,R0 ; R0 -> EMT area again EMT 375 ; *** .WRITW *** BCS C2.ERR ; In case write fails... MOV R1,R0 ; R0 -> EMT area (one more time...) DECB 1(R0) ; Change it back to a read MOV R3,2(R0) ; of the desired block EMT 375 ; *** .READW *** BCS C.ERR ; In case read fails... INCB 1(R1) ; Restore EMT block to WRITE BR C.NOR .DSABL LSB C2.ERR: MOV #2,R2 ; Indicate failure BR C.NOR C.ERR: MOV #1,R2 ; Indicate failure C.NOR: MOV (SP)+,R0 ;*C* Restore saved value RETURN .ASSUME <.-OVRBK0> LE OVRSIZ MESSAGE= OVRSZ0 == . - OVRBK0 OVRSP0 == OVRSIZ - OVRSZ0 .SBTTL OVRBK1 -- overlay block number one ; OVRBK1 ; This code overlays the in-core copy of block zero. This overlay ; is for SET routines which need to alter locations in block one of ; the handler image. . = OVRBK0+1000 ; Align to a new block OVRBK1: ; base for this overlay BIAS == ; bias due to overlay ; SET LS [NO]BIT8 O.BIT8: BR 20$ ;BIT8 NOP ;Skip to entry point for NOBIT8 MOV #^c177,R3 ;Set mask for NOBIT8 BR 30$ 20$: MOV #^c377,R3 ;Set mask for passing eighth bit 30$: MOV R3,O$BIT8+BIAS ;Move in the instruction BR S.1NOR ; SET LS ENDPAG=N O.ENDP: MOV R0,O$ENDP+BIAS ;Set number of FFs to do at .CLOSE BR S.1NOR ;Exit with success status ; SET LS [NO]FORM0 O.FORM0:BR 20$ ;FORM0 NOP ;Skip to entry point for NOFORM0 MOV (PC)+,R3 ;NOFORM0 - Use NOP NOP BR 30$ 20$: MOV (PC)+,R3 ;FORM0 - Use next instruction BEQ BLK0-O$FORM+. ;When FORM0 is found, go send it 30$: MOV R3,O$FORM+BIAS ;Move in the instruction BR S.1NOR ; SET LS [NO]GRAPHIC O.GRAP: BR 20$ ;GRAPHIC NOP MOV (PC)+,R3 ;NOGRAPHIC - only print what fits on line BLT IGNORE-O$GRAP+. BR 30$ 20$: MOV (PC)+,R3 ;GRAPHIC - print everything NOP 30$: MOV R3,O$GRAP+BIAS ;Move in the instruction BR S.1NOR ; SET LS [NO]HANG .IF NE LS$HANG O.HANG: BR 20$ ;HANG NOP ;Skip to entry point for NOHANG MOV (PC)+,R3 ;NOHANG - Use NOP NOP BR 30$ 20$: MOV (PC)+,R3 ;HANG - Use next instruction BR EXIT-O$HANG+. 30$: MOV R3,O$HANG+BIAS ;Move in the instruction BR S.1NOR .ENDC ;NE LS$HANG ; SET LS [NO]LC O.LC: CLR R3 ;For 'LC', leave lower case alone BR 20$ MOV #40,R3 20$: MOV R3,O$LC+BIAS ;Move in the instruction BR S.1NOR .IF NE LS$MTY ; SET LS LINE=n 0 <= n <= 16. O.LINE: CMP R0,#16. ;Is line number valid? BGT S.1ERR ;Nope, not at all... MOVB R0,O$LINE+BIAS ;Set line number to use BR S.1NOR ;Exit with success .ENDC ;NE LS$MTY .SBTTL ADIOS - Common exit point for overlayed code ;+ ; Common exit back to block 0 resident part ; ; Set code error and success exits ;- S.1NOR: CLR R2 ; Indicate no error S.1IGN: CMP (PC)+,(PC)+ ; SKip next; Error already set R2 S.1ERR: MOV #1,R2 ; Indicate common error JMP GETBK0+BIAS ; GO TO BLOCK ZERO .ASSUME <.-OVRBK1> LE OVRSIZ MESSAGE= OVRSZ1==.-OVRBK1 OVRSP1==OVRSIZ-OVRSZ1 .IF NE .SBTTL FETCH/LOAD CODE ;+ ; ; LOAD/FETCH ; This routine is entered on FETCH or LOAD of the LS handler ; and is used 1) to verify use of the handler on the specific ; configuration and, if needed, 2) to establish the required ; connections between the handler and the terminal service of ; a monitor with support for multiterminal handler hooks. ; ;- .ENABL LSB FETCH:: LOAD:: MOV R5,ENTRY$ ;Save entry point MOV R2,SLOT$ ; and table size MOV @R5,R5 ;-> point to handler in memory MOV @#$SYPTR,R0 ;R0->$RMON .IF NE BIT #PROS$,$CNFG2(R0) ;Running on a pro? BEQ 20$ ;Nope... PCMSK =: 360/<<15.*>>/8.>+1> PCLOC =: $LOWMA+ BISB #PCMSK,PCLOC(R0) ;Protect PC vectors MOV (R5),R1 ;Get current vector addr MOV #PC.VEC,R2 ; and new vector value CALL VECMOV ;Copy vector .ADDR #PCBASE,R1 ;R1 -> PC code to patch over PDP code .ADDR #REPL,R4 ;R4 -> Table describing patching 10$: MOV (R4)+,R0 ;Get count of words to move BEQ 80$ ;End of list, done MOV R5,R2 ;copy memory pointer ADD (R4)+,R2 ;point to current place to patch CALL DATMOV ;move the data/instructions BR 10$ ;and until all patches done .ENDC ;NE 20$: .IF NE LS$MTY TSTB (R5) ;Should we attach to a terminal line? BEQ 40$ ;Nope... MOV $THKPT(R0),R1 ;Get pointer to multiterminal handler ; hooks data structure BEQ 90$ ;Monitor doesn't have the support... TSTB (R1)+ ;Bypass structure size byte MOVB (R1)+,R2 ;R2 = Count of LUNs MOV (R1)+,R3 ;R3 -> TCB list MOV (R1)+,(R5) ;Set pointer to output enable routine MOVB (R5),R0 ;R0 = Line to attach to BMI 90$ ;Invalid LUN... CMPB R0,R2 ;Is LUN in this configuration? BGE 90$ ;Nope, invalid LUN... ASL R0 ;Shift for word offset into TCB list ADD R0,R3 ;R3 -> TCB list entry MOV @R3,R3 ;R3 -> TCB for LUN TST T.CSR(R3) ;Is the line present in hardware? BEQ 90$ ;Nope... TST T.STAT(R3) ;Is the line a console? .Assume CONSL$ EQ 100000 BMI 90$ ;Yes, can't use it... MOV R5,R0 ;R0 -> Handler hook routine in LS ADD #,R0 ; ... TST T.OWNR(R3) ;Is the line already attached? BEQ 30$ ;Nope, take it... CMP R0,T.OWNR(R3) ;Yes, by this handler? BNE 90$ ;Nope... 30$: MOV ENTRY$,R1 ;R1 -> $ENTRY entry SUB SLOT$,R1 ;R1 -> $PNAME ENTRY MOV @R1,-2(R0) ;Inform handler of its physical name, MOV R3,(R5) ; link the handler to the TCB, BIS #HANMT$,T.STAT(R3) ; declare line owned by the handler, MOV R0,T.OWNR(R3) ; and link the TCB to the handler BR 80$ .ENDC ;NE LS$MTY 40$: .IF NE LS$PC BIT #PROS$,$CNFG2(R0) ;Running on a pro? BNE 70$ ;Yes, then no conflict... .ENDC ;NE LS$PC .IF NE LS$PDP BIT #MTTY$,$SYSGE(R0) ;Is this a multiterminal monitor? BEQ 70$ ;Nope, then there can't be a conflict .ADDR #MTAREA,R0 ;R0 -> .MTSTAT EMT area .ADDR #MTSTAT,R1 ;R1 -> Status block .MTSTA R0,R1 ;Get info about multiterminal system BCS 90$ ;Errors? MOV @#$SYPTR,R0 ;R0 -> $RMON MOV MTSTAT,R1 ;R1 -> First TCB in system ADD R0,R1 ; ... MOV MTSTAT+MST.LU,R2 ;R2 = Highest LUN on the system ; (Number_of_LUNs - 1) 50$: TST T.CSR(R1) ;Is this a configured line? BEQ 60$ ;Nope... CMP (R5),T.CSR(R1) ;Will use of the CSR conflict? BEQ 90$ ;Yes, reject the load .IF NE CMP (R5),T.VEC(R1) ;Will use of the VECTOR conflict? .IFF ;NE CMP (R5),T.VEC(R1) ;Will use of the VECTOR conflict? .ENDC ;NE BEQ 90$ ;Yes, reject the load 60$: ADD MTSTAT+MST.ST,R1 ;On to next TCB DEC R2 ;More TCB's to check? BGE 50$ ;Yep... .ENDC ;NE LS$PDP 70$: .IF NE MOV (R5),R2 ;Get real vector MOV R0,-(SP) ;save $SYPTR MOV R2,-(SP) ;save vector addr ADD #$LOWMA,R0 ;point to $LOWMA MOV #2,R4 ;protect 2 vectors CALL PROTECT ;call routine MOV #LS$VCX,R1 ;Get temporary vector MOV (SP)+,R2 ;Restore vector address CALL VECMOV ;Copy vector MOV (SP)+,R0 ;Now restore $SYPTR LXMSK =: 360/<<15.*>>/8.>+1> LXLOC =: $LOWMA+ BICB #LXMSK,LXLOC(R0) ;UnProtect temporary vectors MOV (R5),(R5) ;Point to real vectors MOV (R5),(R5) ; ... .BR 80$ .ENDC ;NE 80$: TST (PC)+ ;Return success 90$: SEC ;Return failure RETURN .DSABL LSB .IF NE ; VECMOV ; Moves four words from one location in memory to another. ; ; Call: ; R1 -> Source ; R2 -> Destination ; ; Return: ; R0 = 0 ; R1 -> Source + <2*4> ; R2 -> Destination + <2*4> .ENABL LSB VECMOV: MOV #4,R0 ;4 words to move ; DATMOV ; Moves the specified number of words from one location in memory ; to another. ; ; Call: ; R0 = Count of words to move ; R1 -> Source ; R2 -> Destination ; ; Return: ; R0 = 0 ; R1 -> Source + <2 * count> ; R2 -> Destination + <2 * count> DATMOV: ;N words to copy 10$: MOV (R1)+,(R2)+ ;Copy vector contents SOB R0,10$ ;4 times RETURN ; PROTECT ; ; Call: ; R0 -> Low memory protection bitmap ; R2 = Vector to protect ; R4 = Number of vector locations to protect ; ; Return: ; ? PROTEC: ASR R2 MOV R2,R1 ;save it BIC #177407,R2 ;this byte is index into ccb (*20) BIC #177770,R1 ;this is bit number within byte ASR R2 ;make it a byte index into ccb ASR R2 ASR R2 ADD R0,R2 ;add address of desired ccb 20$: CLR R0 ;clear mask register SEC ;start with carry bit 30$: RORB R0 ;rotate DEC R1 ;count BPL 30$ ;mask not ready yet 40$: BISB R0,@R2 ;set bit in correct byte DEC R4 ;any more bits to set? BMI 50$ ;no, return RORB R0 ;shift bit again BCC 40$ ;set next bit in this word INC R2 ;go to next byte BR 20$ ;go initialize pattern 50$: RETURN .DSABL LSB REPL: .IRPC x,<123456> .WORD PDPZ'x/2,PDPA'x-LSLQE .ENDR .WORD 1,LS$VTB-LSLQE ;Also update the vector table .WORD 1,LS$VTB+6-LSLQE .WORD 0 .ENDC ;NE ENTRY$: .BLKW ; : -> $ENTRY table entry SLOT$: .BLKW ; : Size of a monitor handler table MTAREA: .BLKW 3 ; : EMT area for .MTSTAT MTSTAT: .BLKW 8. ; : Status block from .MTSTAT .ENDC ;NE .IF NE LS$MTY .SBTTL Unload/Release code UNLOAD:: RELEAS:: MOV @R5,R5 ;R5 -> Handler entry point .IF NE TSTB (R5) ;Terminal hooks in use? BEQ 10$ ;Nope, nothing to do... .ENDC ;NE MOV (R5),R0 ;R0 -> TCB hooked to us BEQ 10$ ;There isn't one... CLR T.OWNR(R0) ;Disconnect TCB from handler BIC #HANMT$,T.STAT(R0) ; ... 10$: RETURN .ENDC ;NE LS$MTY .ASSUME <.-OVRBK1> LE 2000 MESSAGE= ;Also contents of PC$PDP must ;be in these two blocks .PSECT PC$PDP .WORD PC.VEC ;Also update the vector table .WORD PC.VEC+4 .END