.MCALL .MODULE .MODULE MTTEMT, VERSION=1201, 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 Post Release Edit History ;+ ; ; (12/01) 15-Sep-93 Don Bridgewater ; Changes to correct out-of-range branch target ; ; 13 13-Jan-1998 TDS Bump version number to 13 for ; V5.7 release ;- .NLIST CND .SBTTL ************************************** .SBTTL * Multi-Terminal EMT Service For The * .IF NE MMG$T .IF NE SB .SBTTL * Extended Background (XB) Monitor * .IFF ;NE SB .SBTTL * Extended Memory (XM) Monitor * .ENDC ;NE SB .IFF ;NE MMG$T .IF NE RTE$M .SBTTL * RT-11 Emulator (RTEM) Monitor * .IFF ;NE RTE$M .IF NE SB .SBTTL * Single Background (SB) Monitor * .IFF ;NE SB .SBTTL * Foreground/Background (FB) Monitor * .ENDC ;NE SB .ENDC ;NE RTE$M .ENDC ;NE MMG$T .SBTTL ************************************** .SBTTL Macro Calls .LIST CND .LIBRARY "SRC:EDTL.MLB" .LIBRARY "SRC:SYSTEM.MLB" ; .LIBRARY "SRC:HARDWA.MLB" ;+ ; Programmed Request and Miscellaneous Utility Macros ;- .MCALL .ADDR .ASSUME .BR ;SYSMAC .MCALL EMTER0 EMTER1 EMTER2 EMTER3 EMTER4 ;EDTL .MCALL EMTER5 ENSYS SPL ;EDTL ;+ ; Structure Definition Macros ;- .MCALL .EMTDF .ERRDF .IBKDF .IMPDF .MGTDF ;SYSTEM .MCALL .MSTDF .SYCDF .TASDF .TCBDF .TCFDF ;SYSTEM .MCALL .TC2DF .THKDF .TSTDF ;SYSTEM ;+ ; Invoke Structure Definition Macros ;- .EMTDF ;EMT Code and Subcode Definitions .ERRDF ;EMT Error Code Definitions .IBKDF ;I.BLOK Blocking Condition Bit Definitions FIX$ED=0 ;allow floating definition .IMPDF ;Impure Area Layout FIX$ED=1 .MGTDF ;.MTGET Return Area Format .MSTDF ;.MTSTAt Return Area Format .SYCDF ;$SYCOM Definitions .TASDF ;Asynchronous Terminal Status Word Supplied by User FIX$ED=0 ;allow floating definition .TCBDF ;Terminal Control Block Definitions FIX$ED=1 .TCFDF ;Terminal Configuration Bits .TC2DF ;T.CNF2 Second Terminal Status Word .IF NE MTY$HK .THKDF ;Multiterminal handler hooks support .ENDC ;NE MTY$HK .TSTDF ;T.STAT Contains Dynamic Terminal Status ;+ ; Delete Structure Definition Macros (Free Up Workfile Space) ;- .MDELET .EMTDF .ERRDF .IBKDF .IMPDF .MGTDF .MSTDF .MDELET .SYCDF .TASDF .TCBDF .TCFDF .TC2DF .THKDF .MDELET .TSTDF .SBTTL M$TTIO - Multi-terminal EMT Dispatcher .PSECT MTEMT$ ;+ ; The multi-terminal EMT service is called with EMT 375, CODE 37(8). ; The functions are sub-coded in the channel byte of the argument ; block and are reached through the following dispatcher. ; It is called from the EMT dispatcher with: ; ; R0 = User (virtual) buffer address ; R1 -> Unit number in argument block (mapped in XM) ; R4 = Function sub-code * 2 ; R5 -> Job impure area ; ; Sub-codes are: ; 0 .MTSET Set terminal status ; 1 .MTGET Get terminal status ; 2 .MTIN Get a character ; 3 .MTOUT Put a character ; 4 .MTRCTO Reset CTRL/O ; 5 .MTATCH Attach a terminal ; 6 .MTDTCH Detach a terminal ; 7 .MTPRNT Print a message ; 10 .MTSTAT Return system status ; ; Function routines are dispatched with: ; ; R3 -> Task control block (TCB) of unit ; R5 -> Job impure area ; ; CALL function routine ; ; C=0 if no error ; All registers undefined ; ; C=1 if error ; R1 = Error code, as follows: ; ; ER.INP 0 No character in buffer (.MTIN). ; ER.OUT 0 No room in buffer (.MTOUT). ; ER.NAT 1 Invalid unit number. The job did not attach it. ; ER.LUN 2 Non-existent unit number. ; ER.IFC 3 Invalid request - sub-code out of range. ; ER.ATT 4 Attempt to ATTACH/DETACH unit attached to another job. ; ER.TAD 5 In XM monitor only, buffer or status block is outside ; legal addressing bounds ; ER.ATH 6 Attempt to ATTACH/DETACH unit attached to handler ; ;- .ENABL LSB M$TTIO:: CMP #,R4 ;Is request subcode legal? BLOS 90$ ;No, Error code 3 (invalid function) MOVB (R1)+,R3 ;Yes, get the unit number. CMP #,R3 ;Is the unit number in range? BLOS 80$ ;No, Error code 2 (invalid LUN) CLR R2 ;Yes, set up and get ... BISB @R1,R2 ; ... character count (for .MTIN & .MTOUT) MOV R0,@SP ;Save user buffer address to return in R0 .IF NE MMG$T MOV R4,R1 ;Get the EMT sub-code ASR R1 ;Make it a byte offset ADD PC,R1 ;In a PIC way, ... MOVB BLKSIZ-.(R1),R1 ; ... get the block size for mapping .ENDC ;NE MMG$T CMP #<..MTST*2>,R4 ;Is it an MTSTAT call? BEQ 10$ ;Yes, no unit number is involved ASL R3 ;Make the unit number a word offset ADD PC,R3 ;Point to the TCB list ... MOV TCBLST-.(R3),R3 ; ... and get the TCB pointer TST T.CSR(R3) ;Is the device present here? BEQ 80$ ;No, Error code 2 (invalid LUN) CMP #<..MTAT*2>,R4 ;Is this an .MTATCH request (code 5)? BEQ 50$ ;Yes, go process it with no more checks CMP #<..MTGE*2>,R4 ;Is this an .MTGET request (code 1)? BEQ 10$ ;Yes, don't test ownership CMP R5,T.OWNR(R3) ;Is the job attached to the unit? BNE 70$ ;No, Error code 1 (not attached) 10$: .IF NE MMG$T CMP R4,#<..MTGE*2> ;.MTSET (0) or .MTGET (1) request? BLOS 40$ ;Yes, go map user parameter area CMP R4,#<..MTOU*2> ;Code 4+ (.MTRCT/.MTATC/.MTDTC/.MTPRN/.MTSTA)? BHI 30$ ;Yes, go map user parameter area (if needed) ;+ ; Else we have an .MTIN or .MTOUT request (code 2 or 3). ;- MOV R2,-(SP) ;Save the character count BEQ 20$ ;Byte count must be greater than zero MOV R2,R1 ;Set up byte count for ACHBKM routine 20$: CALL ACHBKM ;Map to user area MOV (SP)+,R2 ;Restore the character count BCS 100$ ;If C-bit set, invalid address (Error code 5) BR 50$ ;Else ok ............ 30$: CMP R4,#<..MTDT*2> ;Map parameter area? BLOS 50$ ;No 40$: CALL ACHBKM ;Map to user area (for .MTPRNt/.MTSTAt) BCS 100$ ;If C-bit set, invalid address (Error code 5) .ENDC ;NE MMG$T .BR 50$ ............ ;+ ; Dispatch to the EMT service ;- 50$: ADD PC,R4 ;Point into the dispatch list ... MOV MTTLST-.(R4),-(SP) ; ... and stack offset to the function ADD PC,@SP ;Get specified function address MTTDSP: CALL @(SP)+ ;Dispatch to the specified function BCC 60$ ;No error EMTER0 ;Set the carry bit in the program PS MOVB R1,@#$ERRBY ;Now set the real error code 60$: CALLR EMTRTI ;Return from EMT ............ 70$: EMTER1 ;Error code 1. Invalid unit number BR 60$ ;Return from EMT ............ 80$: EMTER2 ;Error code 2. Non-existent unit BR 60$ ;Return from EMT ............ 90$: EMTER3 ;Error code 3. Invalid request function code BR 60$ ;Return from EMT ............ ;;; EMTER4 ;Error code 4. ATT/DET of a unit owned ... ;;; BR 60$ ; ... by another job. ;;; ............ .IF NE MMG$T 100$: EMTER5 ;Error code 5. Buffer or status block ... BR 60$ ; ... outside legal addressing bounds. ............ .ENDC ;NE MMG$T ;;;.IF NE MTY$HK ;;; EMTER6 ;Error code 6. ATT/DET of a unit owned ... ;;; BR 60$ ; ... by a handler. ;;;.ENDC ;NE MTY$HK .DSABL LSB .SBTTL MTTLST - Multi-terminal Dispatch Tables MTTLST: .WORD < M$TTST - MTTDSP > ;0 Set status .WORD < M$TTGT - MTTDSP > ;1 Get status .WORD < M$TTIN - MTTDSP > ;2 Input character .WORD < M$TOUT - MTTDSP > ;3 Output character .WORD < M$RSTO - MTTDSP > ;4 Reset CTRL/O state .WORD < M$ATCH - MTTDSP > ;5 Attach a terminal .WORD < M$DTCH - MTTDSP > ;6 Detach a terminal .WORD < M$PRNT - MTTDSP > ;7 Print a message .WORD < M$STAT - MTTDSP > ;10 Get multi-terminal system status ............ MTTIMX =: < . - MTTLST > .IF NE MMG$T ;+ ; Used in ACHBKM routine to insure that the correct number of bytes are ; available. What the second word of the EMT BLOCK points to. ;- BLKSIZ: .BYTE M.TSIZ ;Set status .BYTE M.TSIZ ;Get status .BYTE 1 ;Get characters .BYTE 1 ;Put characters .BYTE 0 ;Reset CTRL/O .BYTE 2 ;Attach .BYTE 0 ;Detach .BYTE 1 ;Print (only checks first byte) .BYTE MST.SZ ;Return MTTY system status .EVEN .ENDC ;NE MMG$T .SBTTL .MTSET - Set Terminal Characteristics EMT ;+ ; M$TTST - Set terminal characteristics for this unit ; ; R0 -> User terminal status block ; R3 -> TCB ; R5 -> Job's impure area ; ; CALL M$TTST ; ; R1 = Undefined ; R2 = Undefined ;- .ENABL LSB M$TTST:: MOV R3,R1 ;Get pointer to TCB .Assume T.CNFG EQ 0 MOV @R1,-(SP) ;Save the terminal status word BIC #^c,@SP ;Extract the read only bit MOV (R0)+,R2 ;Get user's status word 1 BIC #,R2 ;Keep all the bits except REMOT$ BIS (SP)+,R2 ;Merge true remote status with other bits .Assume T.CNFG EQ 0 MOV R2,(R1)+ ;Set the new status TST T.STAT(R3) ;Is this our console? .Assume CONSL$ EQ 100000 BPL 10$ ;No, leave the $JSW alone BIC #^c,R2 ;Clear all but $JSW parallel bits MOV @#$JSW,-(SP) ;Save current $JSW value BIC #,@SP ;Clear only TTY bits in old $JSW BIS R2,@SP ;Set bits for new terminal status MOV (SP)+,@#$JSW ;Restore $JSW 10$: MOV (R0)+,(R1)+ ;Copy configuration word 2 MOV (R0)+,(R1)+ ;Get the fill character and count MOVB @R0,@R1 ;Get the carriage width CALL TTRSEC ;Now force new status into I.TERM .IF NE BIT #,T.STAT(R3) ;Is this a DZ or DH line? BEQ 50$ ;Nope, must be a DL... .IF NE DZ11$N .IF NE DH11$N BIT #,T.STAT(R3) ;Is this a DZ line? BEQ 20$ ;Nope, must be a DH... .ENDC ;NE DH11$ .Assume T.CNFG EQ 0 MOV @R3,R1 ;Get configuation word 1 BIC #^c,R1 ;Mask only the speed BISB T.CNF2(R3),R1 ;Get the length, stop, and parity bits ASLB R1 ;Shift them ... ASLB R1 ; ... over into ... ASLB R1 ; ... the right place BISB T.PUN(R3),R1 ;Get the physical unit number BIS #,R1 ;Set receiver clock on MOV T.CSR(R3),R2 ;Copy the pointer to the CSR CALL TTOEWT ;Wait for output buffer empty MOV R1,DZ.LPR(R2) ;Set the line parameters .IF NE DH11$N BR 50$ .ENDC ;NE DH11$N .ENDC ;NE DZ11$N .IF NE DH11$N 20$: MOV T.CNF2(R3),R1 ;R1 = Terminal configuration word 2 ; xxxxxxxx/xxxOPSDD ADD #ODDPR$,R1 ;Toggle the parity odd/even bit ; xxxxxxxx/xx?EPSDD BIC #^C,R1 ;Discard unimportant bits ; xxxxxxxx/xxxEPSDD SWAB R1 ; xxxEPSDD/xxxxxxxx ASR R1 ; xxxxEPSD/Dxxxxxxx ASR R1 ; xxxxxEPS/DDxxxxxx ASR R1 ; xxxxxxEP/SDDxxxxx ROLB R1 ; xxxxxxEP/DDxxxxx? Carry= S ROL -(SP) ; xxxxxxEP/DDxxxxx? (SP) = S ASR R1 ; xxxxxxxE/PDDxxxxx (SP) = S ASR R1 ; xxxxxxxx/EPDDxxxx (SP) = S ROR (SP)+ ; xxxxxxxx/EPDDxxxx Carry= S RORB R1 ; xxxxxxxx/SEPDDxxx MOV R1,-(SP) ;Save line parameter bits .Assume T.CNFG EQ 0 MOV @R3,R1 ;R1 = Terminal configuration word 1 BIC #^C,R1 ;Strip to line speed CMP R1,#DHSPSK ;Compare to DH skew speed BLT 40$ ; if < DZ 3600 baud, use it BGT 30$ ; if > DZ 3600 baud, skew it MOV #<7400+400>,R1 ; if = DZ 3600 baud, replace it ; (with DH code for 38.4kb) 30$: SUB #400,R1 ;Skew the code for DH speeds 40$: BIS R1,@SP ;Merge in the receive speed .REPT 4 ;Match transmit and receive speed ASL R1 .ENDR BIS R1,@SP ;Merge in the transmit speed MOV T.CSR(R3),R2 ;Copy the pointer to the CSR MOVB T.PUN(R3),R1 ;R1 = Line number BIS #,R1 ;Ensure interrupts remain enabled CALL TTOEWT ;Wait for output buffer empty MOV R1,@R2 ;Select the DH line MOV (SP)+,DH.LPR(R2) ; and configure it .ENDC ;NE DH11$N 50$: .ENDC ;NE CLC ;Make sure C-bit clear for good return RETURN .DSABL LSB .SBTTL .MTGET - Get Status EMT ;+ ; M$TTGT - Returns the status of a terminal to the user. ; ; Obtains and returns to the user the status of a terminal. ; ; Call: ; R0 -> User terminal status block ; R3 -> TCB for the specified unit ; ; CALL M$TTGT ; ; Return: ; R1 = undefined ; Status returned in user's status block ; PSW = 1, ; R1 = 4, unit attached by another job ; R0 = Job number of controlling job ; R1 = 6, unit attached by handler ; R0 = Rad50 physical handler name ; ;- M$TTGT:: MOV R3,R1 ;Get pointer to TCB MOV (R1)+,(R0)+ ;Put T.CNFG in user status block MOV (R1)+,(R0)+ ;Put T.CNF2 in status block MOV (R1)+,(R0)+ ;Put fill character & count MOVB (R1)+,(R0)+ ;Put carriage width MOVB T.STAT+1(R3),@R0 ;Put high status byte .IF NE MTY$HK BIT #HANMT$,T.STAT(R3) ;Is terminal owned by handler? BNE MTTER6 ;Yes, return error 6 .ENDC ;NE MTY$HK MOV T.OWNR(R3),R2 ;Get the pointer into impure area BEQ MTTER1 ;Terminal not in use, give Error code 1 .IF NE SB CLC ;Done, indicate success .IFF ;NE SB CMP R5,R2 ;Is it owned by this job? BNE MTTER4 ;No, Error code 4 and return job number ;CLC ;C=0 from CMP being equal .ENDC ;NE SB BIC #,T.STAT(R3) ;Clear CTRL/C status information RETURN ;Done ............ MTTER1: MOV #,R1 ;R1 = Error code 1 (unit not attached) MTTERC: SEC ;Set C to signal an error RETURN ............ .SBTTL .MTIN - Character Input EMT ;+ ; M$TTIN - Move a character from terminal's input ring buffer to user's buffr. ; ; Returns updated buffer address to user in R0. ; ; R0 -> User buffer (mapped in XM) ; R2 = Character count ; R3 -> TCB for the logical unit ; SP -> User (virtual) buffer address (returned in R0) ; ; CALL M$TTIN ; ; R2 = Undefined ; R4 = Undefined ; ; C=0 if the character is moved to the user buffer ; @SP is the updated user (virtual) buffer address ; ; C=1 if no character is transfered ; R1 = 0 (Error code 0: input buffer empty) ;- .ENABL LSB M$TTIN:: MOV R0,R4 ;Copy user buffer pointer MOV R2,-(SP) ;Save the character count on the stack 10$: CALL MTTIN ;Go get a character BCS 50$ ;Error, character not found BNE 20$ ;Not a CTRL/C TST T.STAT(R3) ;CTRL/C, is this the console? .Assume CONSL$ EQ 100000 BPL 20$ ;No, do not abort the job TST I.SCCA(R5) ;CTRL/C inhibited? BEQ 40$ ;No, go abort the job 20$: MOVB R0,(R4)+ ;Move and update user's buffer INC 4(SP) ;Bump the user pointer (return in R0) DEC @SP ;Count characters BGT 10$ ;Get next character if not done 30$: TST (SP)+ ;Dump count ;CLC ;*C*=0 from 'TST' above RETURN ;Return with C=0 ............ 40$: CMP (SP)+,(SP)+ ;No, clean stack for return CALLR GOEXIT ;Abort the job ............ 50$: CLR R1 ;Clear R1 (Error code 0: input buffer empty) COM (SP)+ ;Remove stacked word ;SEC ;*C*=1 from 'COM' above RETURN ............ .SBTTL .MTOUT - Single Character Output EMT ;+ ; M$TOUT - Move a char. from user's buffer to terminal's output ring buffer. ; ; Returns updated user virtual buffer address in R0, if successful. ; If TCBIT$ is set in the terminal configuration word via .MTSET (or in the ; $JSW for console unit, an immediate return is made if there is no room in ; the output buffer and Error code 0 is returned. Else the request waits ; until room is available. ; ; R0 -> User buffer (mapped in XM) ; R2 = Character count ; R3 -> TCB ; R5 -> Impure area ; @SP = User virtual buffer address, returned in R0 ; ; CALL M$TOUT ; ; R2 = Undefined ; ; C=0 if character moved to ring buffer ; @SP updated ; ; C=1 if no room and TCBIT$ set ; R0 = 0 (Error code 0: output buffer full) ;- M$TOUT:: MOV R0,-(SP) ;Save the mapped buffer address CALL TTRSEC ;Get $JSW mode bits if console 60$: MOV @SP,R0 ;Get buffer pointer MOVB @R0,R0 ;Get a character from the user buffer MOV R2,-(SP) ;Save the character count JSR R1,MTTPUT ;Put character into output ring buffer .WORD TCBIT$ ;Don't wait if TCBIT$ set MOV (SP)+,R2 ;Restore count BCS 50$ ;No room, return Error code 0 (buffer full) INC @SP ;Update the buffer address INC 4(SP) ;Update user's virtual buffer pointer DEC R2 ;Decrement the character count BGT 60$ ;If positive, get next character BR 30$ ;Purge count and exit ............ .DSABL LSB .SBTTL .MTATCH - Attach To Terminal EMT ;+ ; M$ATCH - Attach a terminal ; ; The following routine attempts to attach a line of the ; multiterminal monitor for use by the job issuing the ; programmed request. Attaching a terminal already owned ; by the job succeeds and resets the AST word. ; ; Call: ; R0 -> Asynchronous status word (virtual) ; R3 -> TCB ; R5 -> Impure area of requesting job ; ; CALL M$ATCH ; ; Return: ; R1 = Undefined ; R2 = Undefined ; PSW = 0, Line is attached ; PSW = 1, ; R1 = 4, unit attached by another job ; R0 = Job number of controlling job ; R1 = 6, unit attached by handler ; R0 = Rad50 physical handler name ; ;- .ENABL LSB .IF NE MMG$T MTTER5: MOV #,R1 ;R1 = Error 5 (address out of bounds) COM (SP)+ ;Get rid of address to check and C=1 RETURN ...... .ENDC ;NE MMG$T M$ATCH:: .IF NE MMG$T MOV R0,-(SP) ;Get address to check JSR R5,CHKSPD ;even is U-D; if SUP$Y odd is S-D BR MTTER5 ;If invalid address return code 5 TST (SP)+ ;Get rid of address to check .ENDC ;NE MMG$T .IF NE SB .IF NE MTY$HK BIT #HANMT$,T.STAT(R3) ;Terminal attached to handler? BNE MTTER6 ;Yes... .ENDC ;NE MTY$HK MOV R5,T.OWNR(R3) ;Attach the terminal .IFF ;NE SB MOV R5,R2 ;Copy impure pointer MOV SP,R1 ;Set non-0 flag, assume failure ENSYS 40$ ;Enter system state to avoid a race BIT #,T.STAT(R3) ;; Is this a shared console? BEQ 10$ ;; No, attach if free CMP R3,I.CNSL(R2) ;; Yes, is it this job's console? BNE 30$ ;; No, can't attach, return this job's number 10$: MOV R2,R5 ;; Copy this job's impure pointer .IF NE MTY$HK BIT #HANMT$,T.STAT(R3) ;; Is it owned by handler? BNE MTTER6 ;; Yes... .ENDC ;NE MTY$HK MOV T.OWNR(R3),R2 ;; Get owner's impure ptr. Terminal in use? BEQ 20$ ;; No, OK to attach CMP R5,R2 ;; Do we already own it? BNE 30$ ;; No, return Error code 4 and owner's job # 20$: MOVB I.JNUM(R5),T.JOB(R3) ;; Set this job's number in the TCB MOV R5,T.OWNR(R3) ;; Attach the terminal CLR R1 ;; Indicate success 30$: RETURN ;; Return to user state at 40$ ............ 40$: TST R1 ;Test success flag .IF EQ MTY$HK BNE MTTER4 ;Branch if failed... .BR 50$ .IFF ;EQ MTY$HK BEQ 50$ ;Success... CMP R1,#ER.ATH ;Terminal attached by handler? BNE MTTER4 ;Nope, attached to job, error 4 BR MTTER6 ;Yes, attached by handler, error 6 .ENDC ;EQ MTY$HK .ENDC ;NE SB 50$: .IF NE MAT$S .IF EQ MMG$T MOV R0,T.AST(R3) ;Store terminal flag address in TCB .IFF ;EQ MMG$T .IF EQ SB ;CLR R1 ;Set no PAR1 bias (R1=0 from BNE above) .IFF ;EQ SB CLR R1 ;Set no PAR1 bias .ENDC ;EQ SB MOV R0,R2 ;Get flag address in R2 .IF NE SUP$Y ASR R2 ;Get Supervisor/User mode bit in carry BEQ 70$ ;Branch if no address was supplied BCS 60$ ;Branch if Supervisor mode CALL $RELUD ;Yes, map terminal flag address (U-D mapping) BR 70$ ........... 60$: CALL $RELSD ;Yes, map terminal flag address (S-D mapping) .IFF ;NE SUP$Y BEQ 70$ ;Branch if no address was supplied CALL $RELOC ;Yes, map terminal flag address .ENDC ;NE SUP$Y 70$: MOV R2,T.AST(R3) ;Store the displacement ... MOV R1,T.AST+2(R3) ; ... and PAR1 bias .ENDC ;EQ MMG$T .ENDC ;NE MAT$S CALLR TTRSEC ;Reset terminal status if console, return C=0 ............ .IF EQ SB MTTER4: 80$: MOV I.JNUM(R2),2(SP) ;Return the job number in R0 90$: MOV #,R1 ;R1 = Error 4 (unit attached to another job) BR MTTERC ;C set to signal error ............ .ENDC ;EQ SB .IF NE MTY$HK MTTER6: MOV T.OWNR(R3),R2 ;R2 -> Handler hook point BNE 100$ ;Can be used to get handler name... MOV #<^RHAN>,2(SP) ;Return generic 'HAN' (this is done ; due to a race in which the HANMT$ ; bit could have been set but T.OWNR ; isn't) BR 110$ 100$: MOV -2(R2),2(SP) ;Return handler physical name in R0 110$: MOV #,R1 ;R1 = Error code 6 (unit attached ; by handler) BR MTTERC ;Take the error return .ENDC ;NE MTY$HK .DSABL LSB .SBTTL .MTRCTO - Reset CTRL/O EMT ;+ ; M$RSTO - Reset CTRL/O flag on this terminal ; ; R3 -> TCB ; R5 -> Impure area ; ; CALL M$RSTO ;- .ENABL LSB M$RSTO:: CALL TTRSEC ;Update the terminal status if console .Assume CONSL$ EQ 100000 BPL 10$ ;Not a console, clear flag in TCB CLRB I.OCTR+1(R5) ;Clear the CTRL/O flag in impure area RETURN ............ 10$: CLRB T.OCTR+1(R3) ;Clear the CTRL/O flag in TCB RETURN ............ .DSABL LSB .SBTTL .MTDTCH - Detach From A Terminal EMT ;+ ; M$DTCH - Detach a terminal from a job. ; ; Frees the terminal for use by another job and de-activates it. ; Unsolicited interrupts are ignored. ; ; R3 -> TCB ; R5 -> Impure area of requesting job ; ; NOTE: Terminal must be owned by requesting job ; ; CALL M$DTCH ; ; R2 = Undefined ;- .ENABL LSB M$DTCH:: .IF EQ SB BIT #,T.STAT(R3) ;Shared console? BNE 20$ ;If NE yes .IFF ;EQ SB TST T.STAT(R3) ;Is this the console? .Assume CONSL$ EQ 100000 BMI 20$ ;If MI yes .ENDC ;EQ SB BIS #,T.STAT(R3) ;Signal detach in progress .Assume T.CNFG EQ 0 TSTB @R3 ;Is the terminal XOFFed? .Assume PAGE$ EQ 200 BPL 10$ ;No MOV R4,-(SP) ;Yes, save R4 MOV T.CSR(R3),R4 ;Get the unit's CSR CALL CTRL.Q ;Reset XOFF state MOV (SP)+,R4 ;Restore R4 10$: CALL TTOEWT ;Wait for output ring to empty .IF EQ SB TST T.STAT(R3) ;Console? .Assume CONSL$ EQ 100000 BMI 30$ ;Yes, detach it .ENDC ;EQ SB MOV R3,R2 ;Not a console. Get the TCB pointer ADD #,R2 ;Point to the line count CLR (R2)+ ;Clear line count MOV (R2)+,(R2)+ ;Reset the buffer pointers CLR (R2)+ ;Clear the character count MOV T.IPUT-T.IGET(R2),@R2 ;Reset T.IGET ptr. (T.IGET=T.IPUT) .Assume T.CNFG EQ 0 BIC #,@R3 ;Clear TT mode bits 20$: .IF NE MAT$S CLR T.AST(R3) ;Clear asynchronous flag ; (must do before resetting T.OWNR ; to avoid race) .ENDC ;NE MAT$S CLR T.OWNR(R3) ;Detach the terminal 30$: BIC #,T.CNF2(R3) ;Clear pass-all bits BIC #,T.STAT(R3) ;Signal detach is done RETURN ............ .DSABL LSB .SBTTL .MTPRNT - Print Message EMT ;+ ; M$PRNT - Print a text string from the user's buffer. ; ; If the string is terminated with a null, The EMT supplies the . ; If the string is terminated with a 200, the text is terminated without ; adding a . ; ; R0 -> User buffer (mapped in XM) ; R3 -> TCB ; R5 -> Impure area ; @SP = User virtual buffer address, returned in R0 ; ; CALL M$PRNT ; ; R2 = Undefined ; ; Waits until all characters have been stuffed into the ring buffer. ;- .ENABL LSB M$PRNT:: MOV R0,R2 ;Get the pointer to the text buffer 10$: MOVB (R2)+,R0 ;Get a character BEQ 20$ ;If equal, null character. CMPB R0,#<200> ;End of string? BEQ 30$ ;Yes, return MOV R2,-(SP) ;No, save R2 JSR R1,MTTPUT ;Put character in output ring buffer .WORD 0 ;Wait for room MOV (SP)+,R2 ;Restore R2 BR 10$ ;Get next character ............ 20$: .ADDR #,R2 ;Point to message BR 10$ ;Go print the characters ............ 30$: RETURN ............ PRCRLF: .ASCII <200> ;<200> message to end text .EVEN .DSABL LSB .SBTTL .MTSTAT - Return Multi-terminal System Status EMT ;+ ; M$STAT - Return multi-terminal system status. ; ; R0 -> User terminal status block (consists of 4 words + 4 rsvd. words) ; R5 -> Impure area. ; ; CALL M$STAT ; ; R0 -> Fourth word of user status block ; R1 = Undefined ; ; NOTE: The subtract operation will clear the carry. ;- M$STAT:: MOV #,(R0)+ ;Get first terminal control block MOV I.CNSL(R5),@R0 ;Get console TCB SUB @#$SYPTR,(R0)+ ;Make it offset to console TCB MOV #,@R0 ;*C* Number of TCBs plus 1 DEC (R0)+ ;*C* Get rid of the extra (number of TCBs) MOV #,(R0)+ ;*C* Get the size of a TCB in bytes RETURN ;*C* Return C=0 ............ .SBTTL MTTIN - Single Character Input ;+ ; MTTIN - Get a character from a user's buffer and wait if necessary. ; ; Called by multi-terminal input and .TTYIN to do input for both console ; and non-console terminals. ; ; R3 -> TCB ; R5 -> Impure area ; ; CALL MTTIN ; ; R0 = Character (if there is one) ; R1 = Undefined ; R2 = Undefined ; C=1 if no input ; Z=1 if the character is a CTRL/C ;- .ENABL LSB MTTIN:: MOV R5,R1 ;Assuming it's the console, point ... ADD #,R1 ; ... to the line count in the impure area CALL TTRSEC ;Fix the $JSW if it's the console .Assume CONSL$ EQ 100000 BMI 10$ ;It is the console, use impure area data MOV R3,R1 ;Get the TCB ADD #,R1 ;Point to the line count in the TCB 10$: MOV R1,R2 ;Copy the line count pointer .Assume T.CNFG EQ 0 BIT #,@R3 ;Special mode input? BEQ 20$ ;No, line mode input ADD #,R2 ;Point to the character count 20$: TST @R2 ;Is there any input? BNE 30$ ;Yes, give it to the caller .Assume T.CNFG EQ 0 BIT #,@R3 ;No, should we wait for input? SEC ;If not, return with C-bit set BNE 70$ ;Return C=1 JSR R4,$SYSWT ;Wait for terminal input available .WORD TTIWT$ CMP @R2,#<1> ;; Is there input yet? Set C if not CALL @(SP)+ ;; Coroutine return for blocking check 30$: ADD #,R1 ;Point to IGET word in ring pointers .BR MTTGET ;Go get a character ............ .SBTTL MTTGET - Get A Character From The Ring Buffer ;+ ; MTTGET - Get a character from a terminal's input ring buffer ; ; R1 -> I.IGET in impure area (console) or T.IGET in TCB (non-console) ; R3 -> TCB ; ; CALL MTTGET ; ; R0 = Character ; R1 = Undefined ; C=0 ; Z=1 if character is CTRL/C ;- ;+ ; MTTGET (*** RTEM-11 HOOK ***) ; This routine is hooked by the RTEM-11 bootstrap ; with the following overlaying code: ; ; CALL $GETP ; .+12 NOP ;$GETP Returns to ret+6 ; ; The routine $GETP is in the RTEM-11 linkage routines. This ; modification allows RTEM-11 to raise it's effective priority ; to prevent race conditions. This modification spans ; both the CALL and the SPL instructions. ;- MTTGET:: ;(*** RTEM-11 HOOK ***) CALL GETPSW ;Copy the current priority on stack SPL 5 ;Prevent race condition INC @R1 ;;Bump the GET pointer CMP (R1)+,@R1 ;;Time to wrap the pointer? BNE 40$ ;;No SUB #,T.IGET-T.ITOP(R1) ;;Yes, wrap around 40$: MOVB @-(R1),R0 ;;Get the character DEC -(R1) ;;Decrease the count .IF NE MAT$S BNE 50$ ;;More data in the buffer CALL CLRIN ;;Report no input left 50$: .ENDC ;NE MAT$S CALL EOLTST ;;End of line? BNE 60$ ;;No DEC T.TTLC-T.ICTR(R1) ;;Yes, decrement line count ;+ ; MTTHOK (*** RTEM-11 HOOK ***) ; This routine is hooked by the RTEM-11 bootstrap ; with the following overlaying code: ; ; CALL $PTPS ; ; The routine $PTPS is in the RTEM-11 linkage routines. ; This modification allows RTEM-11 to lower it's effective ; priority to allow AST's. ;- MTTHOK:: ;;(*** RTEM-11 HOOK ***) 60$: CALL PUTPSW ;;Restore priority .Assume <.-MTTHOK> EQ 4 CMPB #,R0 ;CTRL/C? Z=1 if yes CLC ;Clear C to indicate character found 70$: RETURN ............ .DSABL LSB .SBTTL TTRSET - Reset Terminal Status Bits ;+ ; TTRSET - Reset terminal status bits to reflect those of the $JSW ; ; R3 -> TCB ; R5 -> Impure area ; ; CALL TTRSET ; CALL TTRSEC to reset TCB bits only if console ; ; R0 = Terminal status bits from $JSW ; T.CNFG = " ; I.TERM = " ; T.TFIL = Fill characteristics ; C=0 ; N=1 if console (BMI consol after call) ;- .ENABL LSB TTRSEC: TST T.STAT(R3) ;Is this a console? .Assume CONSL$ EQ 100000 BPL 20$ ;No, don't change configuration bits TTRSET:: MOV @#$JSW,R0 ;Get current $JSW BIC #^c,R0 ;Clear all bits but the TTY bits .Assume T.CNFG EQ 0 MOV @R3,-(SP) ;Save T.CNFG (prevent race condit) BIC #,@SP ;Clear only TTY bits in config wd BIS R0,@SP ;Merge TT mode bits from $JSW .Assume T.CNFG EQ 0 MOV (SP)+,@R3 ;Restore T.CNFG .Assume T.CNFG EQ 0 MOV @R3,I.TERM(R5) ; and copy to impure area for ; interrupt service CMP R3,BKCNSL ;Is this the background console? BNE 10$ ;No, don't copy fillers MOV @#$TTFILL,T.TFIL(R3) ;Yes, copy fill characteristics 10$: TST T.STAT(R3) ;Set N bit, clear carry 20$: RETURN ............ .DSABL LSB .SBTTL MTTPUT - Single Character Output ;+ ; MTTPUT - Put a character in the output ring buffer. ; ; Called by .MTTOUT and .TTYOUT to put a character in the output buffer. ; Waits for room if requested or returns carry bit set if there is no room. ; ; R0 = Character to print ; R3 -> TCB ; R5 -> Impure area ; ; JSR R1,MTTPUT ; .WORD bit to test for wait (for example: .WORD TCBIT$) ; ; R2 = Undefined ; R4 -> Receiver CSR ; C=0 if successful ; C=1 if no room ;- .ENABL LSB MTTPUT:: MOV R5,-(SP) ;Save R5 10$: MOV @SP,R5 ;Copy pointer to impure area MOV R5,R2 ;Assuming console, point to input ... ADD #,R2 ; ... ring buffer in impure area TST T.STAT(R3) ;Is this the console? .Assume CONSL$ EQ 100000 BMI 20$ ;Yes, good guess MOV R3,R2 ;Not console, point to input ... ADD #,R2 ; ... ring buffer in TCB 20$: MOV T.CSR(R3),R4 ;R4 points to receiver CSR .IF NE SYT$K 30$: TSTB T.XFLG(R3) ;^X sequence in progress? BNE 40$ ;Yes, don't allow output now .ENDC ;NE SYT$K MOV R2,-(SP) ;Save buffer pointer CALL TTOPT2 ;Try to output the character MOV (SP)+,R2 ;Restore register BCC 60$ ;Success 40$: .Assume T.CNFG EQ 0 BIT @R1,@R3 ;Should we wait? BNE 60$ ;No, return carry bit .IF NE SYT$K TSTB T.XFLG(R3) ;^X sequence in progress? BEQ 50$ ;No ENSYS 30$ ;Enter sys. state to await ^X sequence is over CALLR QWAIT ;; Call scheduler for our job number - 2 ............ 50$: .ENDC ;NE SYT$K JSR R4,$SYSWT ;Wait terminal output buffer not full .WORD TTOWT$ CMPB #,T.OCTR-T.ICTR(R2) ;; Is there room yet? CALL @(SP)+ ;; Coroutine return for blocking check BR 10$ ;Try again ............ 60$: BIT (R1)+,R0 ;Pop return register, leave carry alone MOV (SP)+,R5 ;Restore register RTS R1 ;Return ............ .DSABL LSB .SBTTL MTRSET - Stop And Detach All Terminals Attached To A Job ;+ ; MTRSET - Cancel I/O on all terminals attached by the job being aborted. ; ; Stops I/O and detaches all attached terminals ; ; Current job set up (CNTXT) ; ; CALL MTRSET ;- .ENABL LSB MTRSET:: JSR R3,SAVE30 ;Save registers 3-0 MOV R4,-(SP) ;Save R4 MOV R5,-(SP) ; and R5 MOV CNTXT,R5 ;Point to the job's impure area .ADDR #,R4 ;Point to list of TCB addresses MOV #,R0 ;Count of defined TCBs 10$: MOV (R4)+,R3 ;Point to next TCB BEQ 20$ ;No such hardware, skip it CMP R5,T.OWNR(R3) ;Is it attached to us? BNE 20$ ;No, do nothing CALL M$DTCH ;Detach the terminal 20$: DEC R0 ;Any more TCB's BGT 10$ ;Yes, do the next unit MOV (SP)+,R5 ;Restore MOV (SP)+,R4 ; registers RETURN ............ .DSABL LSB .SBTTL TTOEWT - Wait For Terminal Output Buffer To Empty ;+ ; TTOEWT - Stall job until output ring buffer of specified terminal is empty ; ; R3 -> TCB ; R5 -> Impure area of calling job ; ; CALL TTOEWT ;- .ENABL LSB TTOEWT:: JSR R4,$SYSWT ;Wait terminal output buffer empty .WORD TTOEM$ MOVB I.OCTR(R5),-(SP) ;; Stack the console terminal count TST T.STAT(R3) ;; Are we waiting for the console? .Assume CONSL$ EQ 100000 BMI 10$ ;; Yes, good guess MOVB T.OCTR(R3),@SP ;; No, get count in TCB 10$: NEGB (SP)+ ;; Set carry if count isn't 0 CALL @(SP)+ ;; Coroutine return for blocking check RETURN ;Return to caller ............ .DSABL LSB .END