.TITLE KERCON - KERMIT connect module .SBTTL S Hecht/D Stevens/R McQueen ;++ ; This module contains the terminal emulation code for Pro/Kermit. ;-- ; Version number .IDENT /1.0.05/ ; Directives .ENABLE LC ; Enable lower case in ASCIx .NLIST BEX .LIBRARY /KERMLB/ ; Kermit macro library file .SBTTL Revision History ;++ ; Version 1.0.00 ; ; 1.0.00 By: Authors On: Many days ; Create this module ; ; 1.0.01 By: Robert C McQueen On: 28-Feb-1984 ; Rewrite lost of the console terminal processing so that ; Ctl-O, Ctl-C, etc get to the -10 a lot faster. ; ; 1.0.02 By: Robert C. McQueen On: 27-March-1984 ; Try once again to fix the ^C problem. ; ; 1.0.03 By: Robert C. McQueen On: 6-April-1984 ; Send RIS character sequence to the terminal after we exit ; the connect processing. ; ; 1.0.04 By: Robert C. McQueen On: 16-April-1984 ; Make this a seperate task. Solves some of the problem ; of needing a DTE equiv for Tool kit and also get lots of ; address space for logging. ; ; 1.0.05 By: Robert C. McQueen On: 11-May-1984 ; Fix local echo for the F11 to F13 keys (ESC, BS, LF). ;-- .SBTTL External symbols ; Get the KERMLB definitions .MCALL KERDEF KERDEF ; Get the general symbol definitions .MCALL CHRDEF ; Get the character definition macro CHRDEF ; Define the special characters .MCALL IOSBDF ; IOSB definitions IOSBDF ; Define the offsets .MCALL BLSRTN ; Allow use of BLISS macros from .MCALL BLSCAL ; library .MCALL TABLE ; Macro to generate tables .MCALL MSG ; Macro to define text literals. .MCALL PJMP ; Jump and return from routine .MCALL ND ; If not defined, define symbol macro ; ; System routines used in Kercon ; .MCALL QIO$S ; QIO on the stack .MCALL QIOW$S ; QIOW using the stack .MCALL QIOW$C ; QIOW .MCALL ASTX$S ; Exit from an AST routine .MCALL CLEF$S ; Clear event flag .MCALL MRKT$S ; Mark time .MCALL SETF$S ; Set event flag .MCALL WTSE$S ; Wait for single EFN using stack .MCALL ALUN$C ; Assign a LUN .MCALL EXIT$S ; Exit from the routines .SBTTL Macro definitions -- Escape commands ;++ ; This macro contains the valid commands that can follow an escape character ;-- .MACRO ESCCMD $TABA 'C,C$EXIT ;; Close communications port $TABA 'B,C$BREAK ;; Send a break $TABA 'S,C$STAT ;; Issue the status $TABA '?,C$HELP ;; Issue the help text .ENDM ; ; Now expand the table. ; TABLE ESC,ESCCMD .SBTTL Macro definitions -- Function keys allowed ;++ ; The following macro will generate the possible function keys that we ; can handle. ;-- .MACRO FNCKEY KY '13~',C$BREAK, ; F3 - Break key KY '20~',C$EXIT, ; F9 - Main Screen KY '21~',C$EXIT, ; F10 - Exit key KY '23~',C$CHAR,.CHESC ; F11 - Generate an escape character KY '24~',C$CHAR,.CHCNH ; F12 - Generate a backspace character KY '25~',C$CHAR,.CHLFD ; F13 - Generate a line feed character KY '28~',C$HELP, ; F15 - Call help routine .ENDM ; ; Now generate the tables ; .MACRO KY TEXT,ROUTIN,ADDTNL,?TXTADR ;; ;; Save the current state of the psects ;; .SAVE ;; Save the current PSECT .ENABL LSB ;; Start local symbol block ;; ;; First generate the text ;; .PSECT $TEXT$, RO, D ;; $TEXT$ psect ;; TXTADR: .ASCIZ TEXT .EVEN ;; ;; Now store the address in the table ;; .RESTORE ;; Restore the PSECT ;; ;; Generate the address of the item ;; .WORD TXTADR .DSABL LSB ;; End of local symbol block ;; .ENDM ; ; Now generate the table of text ; .PSECT $TABL$, RO, D T$KEY: FNCKEY ; Generate the function keys KEY$L=.-T$KEY ; Length of the table ; ; Now generate the routines that get called. ; .MACRO KY TEXT,ROUTINE,ADDTNL,?TXTADR .WORD ROUTINE .ENDM FNCKEY ; Generate the routine addresses ; ; Now generate the addition information ; .MACRO KY TEXT,ROUTINE,ADDTNL,?TXTADR .IF NB .WORD ADDTNL .IFF .WORD 0 .ENDC .ENDM FNCKEY .SBTTL Symbol definitions ;++ ; The following are local symbol definitiosn for the KERCON module. ;-- ; \/ \/ MUST BE A POWER OF 2. ND NM.TIC, 64. ; Allow 64 characters input buffer ND NM.QIO, 4. ; Up to four output QIO's pending at once ; /\ /\ MUST BE A POWER OF 2. .SBTTL State definitions for Console Terminal Input ;++ ; The following define the various states of the Console Terminal Input ; routines. These input routines are all at AST level and the states ; describe what happens there. ;-- $CSINI= 0 ; Initial state $CSESC= 1*2 ; Saw an $CSCSI= 2*2 ; Saw a CSI $CSSQB= 3*2 ; Saw a [ $CSDG1= 4*2 ; Saw first digit $CSDG2= 5*2 ; Saw second digit $CSCEC= 6*2 ; Saw connect escape character (ESCCHR) .SBTTL General storage locations .PSECT $OWN$, RW, D INPCHR: .BLKW 1 ; Place to read characters into CONXIT: .BLKW 1 ; Exit connect processing FNCPTR: .BLKW 1 ; Pointer into FNCTXT FNCTXT: .BLKW 3 ; Function key text NOBIT8: .BLKW 1 ; No bit 8 ; ; Terminal input data ; TILOCK: .BLKW 1 ; Interlock for the terminal data base TTIBUF: .BLKB NM.TIC ; Number of terminal characters allowed TTINCH: .BLKW 1 ; Number of characters in TRMBUF TTIIDX: .BLKW 1 ; Index into TTIBUF TTISTO: .BLKW 1 ; Index to store characters into TTIBUF TIIOSB: .BLKB IB.MSZ ; IOSB for QIO TIQIO: .BLKW 1 ; QIO pending for the console input STATE: .BLKW 1 ; State of the AST routine TBC: .BLKB 2 ; Type ahead buffer count QIOIDX: .BLKB 1 ; Current output QIO number .EVEN ; ; Terminal output data ; TOIOSB: .BLKB IB.MSZ ; IOSB for non-AST level outputs TOIOS0: .BLKB ; IOSB's for QIO TOLOCK: .BLKW 1 ; Interlock for console type out OUTCHR: .BLKW 1 ; Character to be output .SBTTL CONNECT processing ;++ ; The following is the main processing for the terminal emulation. ;-- .PSECT $CODE$, RO, I MAIN: ALUN$C XKLUN,XK,0,$CODE$ ; Assign XK LUN ALUN$C TERLUN,TI,0,$CODE$ ; Assign the terminal LUN JSR PC,INILIB ; Initialize the library routines JSR PC,CRECON ; Make the connect character ascii BLSCAL TT.INIT ; Initialize terminal processing JSR PC,CONECT ; Do the connect processing JSR PC,S$CLEAR ; Clear the screen EXIT$S ; Exit the task .SBTTL Main connect routine (entry point) ;++ ; This routine will handle the processing of the CONNECT command. It is ; called directly from the command dispatch processing. ; ; Usage: ; JSR PC,CONNECT ; (Return) ; ;-- .PSECT $CODE$, RO, I CONECT:: ; ; First initialize some local parameters, so we don't have to do this ; every time ; MOV #FALSE,NOBIT8 ; Assume we are not removing bit 8 CMP #PR.MARK,PARITY ; Using mark parity? BEQ 5$ ; Yes, must remove the bit BIT #TRUE,TRM7BT ; Only passing 7 bit codes? BNE 10$ ; Don't have to remove the bit 5$: MOV #TRUE,NOBIT8 ; Flag we must remove bit 8 ; ; Initialize the two different ports ; 10$: CLR CONXIT ; Clear the exit flag JSR PC,CT.INI ; Initialize the CT port BCS 90$ ; Failed, print an error message CLR R0 ; Use the default 13$: MOV #DUMPXK,R1 ; Routine to do direct XK dumps JSR PC,XK.INI ; Open the XK port BCS 100$ ; Could not get XK ; ; At this point we have the two ports attached, so we just clear the ; screen and output the banner for terminal emulation. ; JSR PC,S$CLEAR ; Clear screen JSR PC,C$BANR ; Output the connect banner ; ; The following is commented out since most systems will screw up when getting ; the leading CSI's from the function keys. Everything at this point ; expects [ rather than . ; ; Set up terminal subsystem so that we get correct type of codes from ; the keys. ; MOV #RTN7BT,R0 ; Assume we want 7 bit codes ; CMP #PR.NONE,PARITY.TYPE ; No parity? ; BNE 15$ ; If not, we can't pass 8 bit codes anyway ; BIT #TRUE,TRM7BT ; 7-bit desired? ; BNE 15$ ; Yes, do that ; MOV #RTN8BT,R0 ; No, use 8-bit data 15$: BLSCAL TT.TEXT,R0 ; Send the string BLSCAL TT.OUTPUT ; And force it out JSR PC,CT.QIO ; Post the initial QIO for the terminal ; CMP DUPLEX,#DP.HAL ; Check for half duplex ; BNE 20$ ; If not skip ; ; MOV IBM.CHAR,R0 ; If half then send turn around char. ; JSR PC,CT.PAR ; Generate the parity ; JSR PC,XK.OUT ; Write the character with parity ; ; ; Here to start the terminal emulation ; 20$: JSR PC,DUMPXK ; Dump XK input to console screen JSR PC,DUMPCT ; Dump the console input to the XK JSR PC,XK.QIO ; Make sure a QIO is posted for the XK JSR PC,CT.QIO ; Make sure there is a QIO posted TST CONXIT ; Must we exit? BNE 40$ ; Yes, just exit ; ; Here to wait for the EFNs to be set by somebody ; WTSE$S #CONEFN ; Wait until we have input CLEF$S #CONEFN ; Clear so we know when none. MRKT$S #CONEFN,#1.,#2. ; Make sure we run at least once a second BR 20$ ; Loop for more input ; ; Here to exit from the connect processing ; 40$: JSR PC,XK.SHT ; Shut down the XK JSR PC,CT.SHT ; Shut this down too BLSCAL TT.TEXT,#M$RIS ; Send the reset string BLSCAL TT.OUTPUT ; Force it out RTS PC ; Return to the caller ; ; Here if we can not get the console terminal ; 90$: BLSCAL BL$MOV,<#CTBS$L,#M$CTBS,#MSG1> ; Console is busy JSR PC,S$CLEAR ; Clear the screen BLSCAL TT.TEXT,#M$CTBS,+ ; Port is busy BLSCAL TT.TEXT,#RESTXT,+ ; Say he should type resume BLSCAL TT.OUTPUT,,- ; Force the output CALL WTRES ; Wait for resume key RTS PC ; And return ; ; Here if we can not get the XK port ; 100$: JSR PC,CT.SHT ; Release the console terminal BLSCAL BL$MOV,<#XKBS$L,#M$XKBS,#MSG1> ; XK is busy JSR PC,S$CLEAR ; Clear the screen BLSCAL TT.TEXT,#M$XKBS,+ ; Port is busy BLSCAL TT.TEXT,#RESTXT,+ ; Say he should type resume BLSCAL TT.OUTPUT,,- ; Force the output CALL WTRES ; Wait for resume key RTS PC ; And return ; Text for various items above .PSECT $PLIT$, RO, D ; This is data M$RIS: .ASCIZ <.CHESC>/c/ ; Reset to initial state MSG XKBS, MSG CTBS, RESTXT: .ASCIZ <.CHCRT><.CHLFD>/Press RESUME to continue/<.CHCRT><.CHLFD> ;RTN8BT: .ASCIZ <.CHESC>/ G/ ; Want 8-bit codes from function keys RTN7BT: .ASCIZ <.CHESC>/ F/ ; Want 7-bit codes from function keys .EVEN ; Make sure we are on a word boundary .SBTTL C$BANR - Connect banner type out ;++ ; This routine will type the banner for the connect. This is displayed when ; terminal emulation is entered. ;-- .PSECT $PLIT$, RO, D CONMG1: .ASCII <.CHCR><.CHLF><.CHLF>\PRO/Kermit - \ .ASCII \Terminal Emulation version 1.0\ .ASCII <.CHCR><.CHLF><.CHLF><.CHLF> .ASCII \Now entering Terminal Emulation mode\<.CHCR><.CHLF><.CHLF> .ASCIZ \Type \ CONMG2: .ASCIZ \C \ CONMG3: .ASCIZ \or press MAIN SCREEN or EXIT \ CONMG4: .ASCII \to return to PRO/Kermit, \ .ASCIZ <.CHCR><.CHLF>/Type / CONMG5: .ASCIZ \? \ CONMG6: .ASCIZ \or press HELP \ CONMG7: .ASCIZ \for help.\<.CHCR><.CHLF> .EVEN .PSECT $CODE$, RO, I C$BANR: BLSCAL TT.TEXT,#CONMG1,+ ; Output the first part BLSCAL TT.TEXT,#CONCHR,+ ; And the connect character BLSCAL TT.TEXT,#CONMG2,+ ; Second part BIT #TRUE,TRMTRN ; Terminal in transparent mode? BNE 10$ ; Yes, don't output the following BLSCAL TT.TEXT,#CONMG3,+ ; Output some more 10$: BLSCAL TT.TEXT,#CONMG4,+ ; Output the rest of the line BLSCAL TT.TEXT,#CONCHR,+ ; And the connect character BLSCAL TT.TEXT,#CONMG5,+ ; And the last part BIT #TRUE,TRMTRN ; Transparent mode? BNE 20$ ; Yes, skip this about HELP key BLSCAL TT.TEXT,#CONMG6,+ ; Output about HELP 20$: BLSCAL TT.TEXT,#CONMG7,+ ; Finish message off BLSCAL TT.OUTPUT,,- ; Output the rest of the characters RTS PC ; Return to the caller .SBTTL C$CHAR - Send a special character to the remote ;++ ; This routine will send a special character to the remote. ; ; Usage: ; R1/ Information from table ; JSR PC,C$CHAR ; (Return) ;-- .PSECT $CODE$, RO, I C$CHAR: PJMP XKOUT ; Send it .SBTTL C$EXIT - Exit from terminal emulation ;++ ; This routine will be called to exit from the terminal emulation. It ; will cause the flag to be set so that the loop level notices that we ; have to exit. ; ; Usage: ; JSR PC,C$EXIT ; (Return) ; ;-- .PSECT $CODE$, RO, I C$EXIT: MOV #1,CONXIT ; Set the flag RTS PC ; Return to the caller .SBTTL C$BREAK - Send a break to the remote ;++ ; This routine will send a break character to the remote connection. ; ; Usage: ; JSR PC,C$BREAK ; (Return) ; ;-- .PSECT $CODE$, RO, I C$BREAK: JSR PC,XK.BRK ; Send the break RTS PC ; Return to the caller .SBTTL C$STAT - Output the connection status ;++ ; This routine will output the connection status. This routine is called ; after the escape character has been typed followed by an 'S'. ;-- .PSECT $PLIT$, RO, D STAMG1: .ASCIZ <.CHCRT><.CHLFD><.CHLFD>/[The baud rate is / STAMG2: .ASCIZ \ (T)/\ STAMG3: .ASCIZ / (R) bits per second.]/<.CHCRT><.CHLFD>/[Local echo / STAMG4: .ASCIZ /]/<.CHCRT><.CHLFD><.CHLFD> MSG ON, MSG OFF, .MACRO SPD $TAB S.50,<50> $TAB S.75,<75> $TAB S.100,<100> $TAB S.110,<110> $TAB S.134,<134> $TAB S.150,<150> $TAB S.200,<200> $TAB S.300,<300> $TAB S.600,<600> $TAB S.1200,<1200> $TAB S.1800,<1800> $TAB S.2000,<2000> $TAB S.2400,<2400> $TAB S.3600,<3600> $TAB S.4800,<4800> $TAB S.7200,<7200> $TAB S.9600,<9600> $TAB S.19.2,<19200> ; $TAB S.38.4,<38400> .ENDM ; Now define the item in the table TABLE SPD,SPD ; Define the speed table .PSECT $CODE$, RO, I C$STAT: BLSCAL TT.TEXT,#STAMG1,+ ; Output the message. MOV #TC.XSP,R0 ; Get the transmit speed parameter MOV #CURXKP,R1 ; Use the current parameters JSR PC,FNDXKP ; Find the parameter in the block JSR PC,C$SBAU ; Output the baud rate BLSCAL TT.TEXT,#STAMG2,+ ; Output the message. MOV #TC.RSP,R0 ; Get the receive speed parameter MOV #CURXKP,R1 ; Use the current parameters JSR PC,FNDXKP ; Find the parameter in the block JSR PC,C$SBAU ; Output the baud rate BLSCAL TT.TEXT,#STAMG3,+ ; Output the message. MOV #M$ON,R2 ; Assume local echo BIT #TRUE,LCLECH ; Local echo? BNE 10$ ; If non-zero we are using local echo MOV #M$OFF,R2 ; If zero, we aren't 10$: BLSCAL TT.TEXT,R2,+ ; Output the message. BLSCAL TT.TEXT,#STAMG4,+ ; Output the message. BLSCAL TT.OUTPUT,,- ; Output the rest of the mess RTS PC ; Return to the caller ; ; Subroutine to output the baud rate given the index. ; C$SBAU: MOVB (R0),R2 ; Get the index MOV #T$SPD,R0 ; Get the table MOV #SPD$L/2,R1 ; Get the length JSR PC,FNDOFS ; Find the offset TST R0 ; Is this zero? BEQ 99$ ; Yes, just return ADD #SPD$L,R0 ; Point to the entry MOV (R0),R2 ; Get the item MOVB (R2)+,R3 ; Get the length TST -(SP) ; Allocate one word 10$: MOVB (R2)+,(SP) ; Get the character JSR PC,TT.CHAR ; Output the character SOB R3,10$ ; Loop for all character TST (SP)+ ; Clear up the stack 99$: RTS PC ; Return to the caller .SBTTL C$HELP - Help command for the connect processing ;++ ; This routine will issue the help message to the user's terminal. It will ; then return to the calling routine. ; ; Usage: ; JSR PC,C$HELP ; (Return) ; ;-- .PSECT $PLIT$, RO, D CNHLP1: .ASCII <.CHCRT><.CHLFD>/CONNECT escape commands:/<.CHCRT><.CHLFD> .ASCII <.CHLFD> .ASCII / B Send a break/<.CHCRT><.CHLFD> .ASCII \ C Close connect and return to PRO/Kermit\<.CHCRT><.CHLFD> .ASCII / S Type Status/<.CHCRT><.CHLFD> .ASCII / ? Help (this message)/<.CHCRT><.CHLFD> .ASCIZ / / CNHLP2: .ASCIZ / Send the escape character/<.CHCRT><.CHLFD> CNHLP3: .ASCII \Press MAIN SCREEN or EXIT to return to PRO/Kermit\<.CHCRT><.CHLFD> .ASCIZ \Press HELP for this message\<.CHCRT><.CHLFD> .EVEN .PSECT $CODE$, RO, I C$HELP: BLSCAL TT.TEXT,#CNHLP1,+ ; Output the first part of the help message BLSCAL TT.TEXT,#CONCHR,+ ; Output the escape character BLSCAL TT.TEXT,#CNHLP2,+ ; Last part of the text BIT #TRUE,TRMTRN ; Transparent mode? BNE 10$ ; Yes, don't say anything about function keys BLSCAL TT.TEXT,#CNHLP3,+ ; No, tell him about other keys 10$: BLSCAL TT.OUTPUT,,- ; Output the rest of the mess RTS PC ; Return to the caller .SBTTL CT.INI - Initialize the terminal processing ;++ ; This routine will initialize the terminal connect processing. ; ; Usage: ; JSR PC,CT.INI ; (Return - Status in R0) ; ;-- .PSECT $CODE$, RO, I CT.INI: CLR TTIIDX ; Clear the pointers CLR TTISTO ; . . . CLR TTINCH ; . . . CLR STATE ; Clear the character processing state MOV #1,TILOCK ; Clear the interlock MOV #1,TOLOCK ; Clear the interlock MOV #-1,TIQIO ; And the QIO pending flag QIOW$C IO.ATT,TERLUN,TTAEFN, , , , ,$CODE$ ; Grab the device ; ; Now get the directive status and determine if we really did it correctly ; MOV $DSW,R0 ; Get the status BGE 10$ ; Branch if no error SEC ; Mark the failure RTS PC ; Return to the caller ; ; Set the terminal for binary input. This keeps control-C's from ;killing us. ; 10$: QIOW$C SF.SMC,TERLUN,TTAEFN, , , ,,$CODE$ ; ; Clear out the flag bytes in the output IOSB's so that they can be used. ; MOV #NM.QIO,R0 ; Get the count MOV #TOIOS0-IB.SIZ,R1 ; Point before first block 20$: ADD #IB.SIZ,R1 ; Point to next IOSB CLRB IB.FLG(R1) ; Clear the flag SOB R0,20$ ; And loop for all IOSB's ; ; Give a good return ; CLC ; Clear the carry for the caller RTS PC ; Return to the caller ; Parameter list for SF.SMC function. Sets the terminal for binary ;I/O. .PSECT $TEXT$, RO, D SMCBIN: .BYTE TC.BIN,1 ; Turn binary on SMCBNL=.-SMCBIN ; Length of block .SBTTL CT.SHT - Shut down the terminal processing ;++ ; This routine will shut down the connect terminal processing. ; ; Usage: ; JSR PC,CT.SHT ; (Return - Status in R0) ; ;-- .PSECT $CODE$, RO, I CT.SHT: QIOW$C IO.KIL,TERLUN,TTAEFN, , , , ,$CODE$ ; Kill QIO's QIOW$C SF.SMC,TERLUN,TTAEFN, , , ,,$CODE$ ; Clear binary QIOW$C IO.DET,TERLUN,TTAEFN, , , , ,$CODE$ ; Detach the device MOV #-1,TIQIO ; No QIO pending any more RTS PC ; And return .PSECT $TEXT$, RO, D SMCCBN: .BYTE TC.BIN, 0 ; Clear binary input SMCCBL=.-SMCCBN ; Length of block .SBTTL CT.INP - Read a character from the CT buffer ;++ ; This routine will read a character from the CT buffer. It will then ; return the character to the calling routine ; ; Usage: ; JSR PC,CT.INP ; (Return) ; ; On return: ; Carry - Clear if no characters, set if there was one ; R1/ Character if any there ;-- .PSECT $CODE$, RO, I CT.INP: DEC TILOCK ; Do I have the interlock? BNE 90$ ; No, skip this ; ; Here with the interlock, see if there are characters to process ; MOV TTINCH,R0 ; Get the number of characters BEQ 10$ ; Branch if none ; ; Here if we have characters that can be passed back to the caller ; MOV TTIIDX,R1 ; Get the index MOVB TTIBUF(R1),R1 ; Get the character DEC TTINCH ; Decrement the number of characters INC TTIIDX ; Increment BIC #^C,TTIIDX ; Make sure we don't go over the end ; of the buffer CLC ; Clear the carry MOV #1,TILOCK ; Clear the interlock RTS PC ; Return to the caller ; ; Here if there were no characters, set the carry and return ; 10$: SEC ; Set the carry MOV #1,TILOCK ; Clear the interlock RTS PC ; Return to the caller ; ; Here if we could not get the interlock. Just return as if there were no ; characters. ; 90$: SEC ; Set the carry RTS PC ; Return to the caller .SBTTL CT.QIO - Post initial QIO for console terminal ;++ ; This routine will post the initial QIO for the console terminal. ; ; Usage: ; JSR PC,CT.QIO ; (Return) ; ;-- .PSECT $CODE$, RO, I CT.QIO: INC TIQIO ; Need a QIO? BNE 99$ ; No, just return CMP TTINCH,#NM.TIC ; Buffer full? BEQ 10$ ; Branch if so MOV R1,-(SP) ; Save R1 MOV TTISTO,R1 ; Get the index ADD #TTIBUF,R1 ; Get the address to output CLR TIQIO ; Flag QIO is posted QIO$S #IO.RAL!IO.RNE,#TERLUN,#TTREFN,,#TIIOSB,#CTIAST, MOV (SP)+,R1 ; Restore R1 99$: RTS PC ; Return to the caller ; Here if there is no room to read into. Remember we don't have a QIO ;outstanding. 10$: MOV #-1,TIQIO ; No QIO RTS PC ; Return .SBTTL CTIAST - Handle ASTs for incoming characters ;++ ; This routine will handle console terminal input ASTs. This routine ; will normally be called because there was a single character QIO ; outstanding for the console terminal. ; ; Usage: ; AST level call. ; ;-- .PSECT $CODE$, RO, I CTIAST::MOV R0,-(SP) ; Save this register MOV 2(SP),R0 ; Get the current IOSB JSR PC,1$ ; Call the processing routine MOV (SP)+,R0 ; Restore the register TST (SP)+ ; Remove the IOSB from the stack ASTX$S ; Exit from the AST level routine ; ; The following is the main routine for the AST level processing. ; 1$: MOV #-1,TIQIO ; No QIO pending now ; ; Now determine if there is an error from the QIO. ; TSTB IB.STS(R0) ; Was there any errors? BGE 10$ ; Branch if there were no errors RTS PC ; Just return if errors ; ; Here if we have input some characters, determine the number and update ; the counts ; 10$: MOV IB.CNT(R0),R0 ; Get the count of characters BEQ 20$ ; No characters, just exit ; ; Here if we have read some characters from the console terminal ; SETF$S #CONEFN ; Set the event flag ADD R0,TTISTO ; Point the index to the end BIC #^C,TTISTO ; Make sure queue works correctly ADD R0,TTINCH ; Count up number of characters available 20$: JSR PC,DUMPCT ; Dump console to the XK PJMP CT.QIO ; Issue the QIO .SBTTL CTDUMP - Dump the console input ;++ ; This routine will dump the console input to the communications line. It ; will return when all of the characters have been processed. ; ; Usage: ; JSR PC,DUMPCT ; Call the routine ; (Return) ; ;-- DUMPCT: JSR R1,$SAVE4 ; Save some registers 10$: JSR PC,CT.INP ; Get a character BCS 99$ ; Branch if no more characters ; ; Now branch to the correct state. ; MOV STATE,R0 ; Get the state MOV CTIDSP(R0),R0 ; Get the routine address JSR PC,@R0 ; Dispatch to the routine BR 10$ ; Loop for the next character ; ; Here to return to the caller ; 99$: RTS PC ; Return ;++ ; The following is the dispatch table for the various routines. These ; routines will process the character that we received from the console ; terminal. ;-- .PSECT $PLIT$, RO, D CTIDSP: .WORD ASTINI ; Initial state .WORD ASTESC ; Saw an .WORD ASTCSI ; Saw a CSI .WORD ASTSQB ; Saw a [ .WORD ASTDG1 ; Saw first digit .WORD ASTDG2 ; Saw second digit .WORD ASTCEC ; Saw connect escape character (ESCCHR) .SBTTL CTDUMP - ASTINI - Initial state ;++ ; This routine will handle the initial state for the AST processing. ; ; Usage: ; R1/ Character ; JSR PC,@R0 ; (Return) ; ;-- .PSECT $CODE$, RO, I .ENABL LSB ; Start local symbol block ; (QIOW$C causes problems) ASTINI: CMP R1,ESCCHR ; Is this the escape character? BEQ 30$ ; Yes, handle differently CMP R1,#.CHCSI ; Is this a CSI? BEQ 40$ ; Check if allowed CMP R1,#.CHESC ; Start of an escape sequence? BEQ 40$ ; Yes, handle it differently 10$: JSR PC,XKOUT ; Output the character RTS PC ; Return to the caller ; ; Here after we have gotten an escape character in the initial state ; 30$: MOV #$CSCEC,STATE ; Set the new state RTS PC ; Return to the caller ; ; Here after we have gotten an Escape (33 octal) or a CSI ; 40$: BIT #TRUE,TRMTRN ; Terminal transparent mode? BNE 10$ ; Branch if so ; ; Now determine if we have enough character coming from the keyboard for this ; to possibly be a function key. ; MOVB #TC.TBF,TBC ; Store the function QIOW$C SF.GMC,TERLUN,TTREFN,,TIIOSB,,,$CODE$ CMPB #4,TBC+1 ; Do we have enough characters? ; BLE 50$ ; Skip if enough ; JMP 10$ ; Else output the character BGT 10$ ; No, output the escape/CSI ; ; Here if we may have the start of an escape sequence. ; 50$: CLR FNCTXT ; Clear this CLR FNCTXT+2 ; block CLR FNCTXT+4 ; of characters MOV #FNCTXT,R2 ; Get a pointer to the block MOVB R1,(R2)+ ; Store the characters MOV R2,FNCPTR ; Store the pointer MOV #$CSESC,STATE ; Assume we got an escape CMP #.CHESC,R1 ; Correct? BEQ 99$ ; Yes, just return MOV #$CSCSI,R1 ; No, return CSI state 99$: RTS PC ; Return to the caller .DSABL LSB ; End of local symbol block .SBTTL CTDUMP - ASTESC - Process after an ;++ ; This routine will handle the processing after an .CHESC character ; has been input. It will determine if the next character is a square ; bracket and change state to handle it if it is. ; ; Usage: ; R1/ Character ; JSR PC,@R0 ; (Return) ; ;-- .PSECT $CODE$, RO, I ASTESC: MOVB R1,@FNCPTR ; Store the character INC FNCPTR ; Point to the next position CMPB #'[,R1 ; Is this a square bracket? BEQ 10$ ; Yes, process it MOV #$CSINI,STATE ; Store the new state PJMP CT.DFK ; Dump the function key ; ; Here to get the new state ; 10$: MOV #$CSSQB,STATE ; Set the new state RTS PC ; Return to the caller .SBTTL CTDUMP - ASTCSI - Process after a CSI ;++ ; This routine will handle the processing after a CSI character has ; been input. It will determine if the next character is a digit and ; change state, so that the ASTDG1 routine is called if it is. ; ; Usage: ; R1/ Character ; JSR PC,@R0 ; (Return) ; ;-- .PSECT $CODE$, RO, I ASTCSI: MOVB R1,@FNCPTR ; Store the character INC FNCPTR ; Point to the next position JSR PC,CHKDIG ; Is this character a digit? BCS 10$ ; Branch if that was a digit JSR PC,CT.DFK ; Dump the function key text MOV #$CSINI,STATE ; Back to the initial state RTS PC ; Return to the caller ; ; Here if the information was a digit, change to the next possible state ; ($CSDG1) ; 10$: MOV #$CSDG1,STATE ; Set the state RTS PC ; Return to the caller .SBTTL CTDUMP - ASTSQB - Process after a square bracket. ;++ ; This routine will handle the processing after an escape [ has been seen. ; It will determine if the next character is a digit and then proceed to ; process them. ; ; Usage: ; R1/ Character ; JSR PC,@R0 ; (Return) ; ;-- .PSECT $CODE$, RO, I ASTSQB= ASTCSI .SBTTL CTDUMP - ASTDG1 - Here after the first digit of a function key ;++ ; This routine will handle the processing after the first digit of a function ; key. It is assumed that either another digit or a tilda will follow the ; function key that was input. If the function key is followed by a tilda ; then we will attempt to find the function key in the table. If it is not ; in the table then the information will be output to the user's terminal. ; ; Usage: ; R1/ Character ; JSR PC,@R0 ; (Return) ; ;-- .PSECT $CODE$, RO, I ASTDG1: MOVB R1,@FNCPTR ; Store the character INC FNCPTR ; Point to the next position CMPB #'~,R1 ; Is this a tilda? BEQ 20$ ; Yes, process it JSR PC,CHKDIG ; Is this character a digit? BCS 10$ ; Branch if that was a digit JSR PC,CT.DFK ; Dump the function key text BR 30$ ; Output the function key ; ; Here if the information was a digit, change to the next possible state ; ($CSDG1) ; 10$: MOV #$CSDG2,STATE ; Set the state RTS PC ; Return to the caller ; ; Here if we have gotten the last character of the function key. Attempt ; to find it in the table. If it is in the table then we will process ; the function, else we will output the function key to the XK port ; 20$: JSR PC,CT.FFK ; Find the function key BCC 30$ ; Branch if we did the function JSR PC,CT.DFK ; Didn't, so dump the function key 30$: MOV #$CSINI,STATE ; Set the new state RTS PC ; Return to the caller .SBTTL CTDUMP - ASTDG2 - Here after the second digit of a function key ;++ ; This routine will be called after the second digit of a function key. It ; wants a tilda to be the character that was input in this state. If the ; character is not a tilda, then the function key is output to the XK port. ; ; Usage: ; R1/ Character ; JSR PC,@R0 ; (Return) ; ;-- .PSECT $CODE$, RO, I ASTDG2: MOVB R1,@FNCPTR ; Store the character INC FNCPTR ; Point to the next position CMPB #'~,R1 ; Is this a tilda? BEQ 20$ ; Yes, process it JSR PC,CT.DFK ; Dump the function key text BR 30$ ; Exit the routine ; ; Here if we have gotten the last character of the function key. Attempt ; to find it in the table. If it is in the table then we will process ; the function, else we will output the function key to the XK port ; 20$: JSR PC,CT.FFK ; Find the function key BCC 30$ ; Branch if we did the function JSR PC,CT.DFK ; Didn't, so dump the function key 30$: MOV #$CSINI,STATE ; Set the new state RTS PC ; Return to the caller .SBTTL CTDUMP - ASTCEC - Saw connect escape character ;++ ; Here after we have seen a connect escape character. This routine will ; determine if the character following it is a valid command character. If ; it is then it will dispatch to the correct routine, else it will send a bell ; to the console. ; ; Usage: ; R1/ Character ; JSR PC,@R0 ; (Return) ; ;-- .PSECT $CODE$, RO, I ASTCEC: MOV R1,R2 ; Copy the character CMPB #'a,R2 ; Is this a lower case character? BGT 10$ ; Branch if it is SUB #'a-'A,R2 ; Convert to upper case 10$: CMPB R2,ESCCHR ; Is this the escape character? BNE 30$ ; No, go find it in the table JSR PC,XKOUT ; Output the character BR 99$ ; Finish up ; ; Here if we have to find the character in the table. ; 30$: MOV #T$ESC,R0 ; Get the escape character table MOV #,R1 ; And the length JSR PC,FNDOFS ; Find the item TST R0 ; Find it? BNE 20$ ; Branch if we did JSR PC,CT.BEL ; Output a bell and then the characters BR 99$ ; Finish up ; ; Here if we have found the entry in the table ; 20$: ADD #ESC$L,R0 ; Point to the other entry MOV (R0),R0 ; Get the address of the routine JSR PC,@R0 ; Jump to the routine ; ; Here to reset the state ; 99$: MOV #$CSINI,STATE ; Store the new state RTS PC ; Return to the caller .SBTTL CT.FFK - Find a function key ;++ ; This routine will find a function key. It is assume that the function ; key text has been accumulated in the FNCTXT locations. ; ; Usage: ; JSR PC,CT.FFK ; (Return) ; ; On return: ; If carry set - Not found ; If carry clear - Found and processed. ;-- CT.FFK: MOV #,R0 ; Get the number of function keys MOV #T$KEY,R1 ; Get the address of the table ; ; Now loop to find the function key ; 10$: MOV (R1)+,R2 ; Get the address of the text MOV #4,R3 ; Number of characters to check MOV #FNCTXT+2,R4 ; First character CMPB FNCTXT,#.CHCSI ; First character of string a CSI? BNE 20$ ; No, just enter loop DEC R4 ; Yes, start one character earlier 20$: CMPB (R4)+,(R2)+ ; Is this the same? BNE 30$ ; Jump if not SOB R3,20$ ; Loop for all characters BR 40$ ; Found what we need, go handle it 30$: SOB R0,10$ ; Loop for all function keys possible SEC ; Set the carry RTS PC ; And return to the caller 40$: ADD #KEY$L-2,R1 ; Point to the entry MOV (R1),R0 ; Get the routine address ADD #KEY$L,R1 ; Point to the addition information MOV (R1),R1 ; Get it JSR PC,(R0) ; Call the routine and return CLC ; Clear the carry RTS PC ; Return to the caller .SBTTL CT.DFK - Dump a function key ;++ ; This routine will unwind a function key we have be accumlating in the ; FNCTXT locations. The text will be output to the XK port and then ; the routine will return. ; ; Usage: ; JSR PC,CT.DFK ; (Return) ; ;-- .PSECT $CODE$, RO, I CT.DFK: MOV #5,R3 ; Maximum number of characters MOV #FNCTXT,R2 ; Address of the text 10$: MOVB (R2)+,R1 ; Get a character BEQ 20$ ; Branch if finished JSR PC,XKOUT ; Output it SOB R3,10$ ; Loop for all keys read 20$: RTS PC ; Return to the caller ; ; SUBROUTINE - CHKDIG - Check to see if R1 contains a digit ; CHKDIG: CMPB #'0,R1 ; Compare against zero BGT 10$ ; If less than zero not a digit CMPB #'9,R1 ; Compare against nine BLT 10$ ; If greater than nine not a digit SEC ; Set the carry bit RTS PC ; Return to the caller ; ; Here if not a digit, clear the carry ; 10$: CLC ; Clear the carry RTS PC ; Return to the caller .SBTTL CT.BEL - Output a bell to the user ;++ ; This routine will output a bell to the console terminal. This is done ; for the internal buffers being full, or the fact that the user has ; given a bad escape command. ; ; Usage: ; JSR PC,CT.BEL ; (Return) ; ;-- .PSECT $CODE$, RO, I CT.BEL: QIO$S #IO.WVB,#TERLUN,#TTWEFN,,#TOIOSB,,<#M$BELL,#1> RTS PC .PSECT $PLIT$, RO, I M$BELL: .ASCIZ <.CHCNG> .SBTTL CT.PAR - Add parity to a character ;++ ; This routine will append the parity bit to the character given it. ; ; Usage: ; R0/ Character ; JSR PC,CT.PAR ; (Return - R0 with character + parity) ; ;-- .PSECT $CODE$, RO, I CT.PAR: ; FROM BLISS-16 code of GEN.PARITY BIT #TRUE,DEV.PARITY.FLAG ; Have hardware doing the parity? BEQ 99$ ; Yes, just return JSR R1,$SAVE2 ; BIT #1,IBM.FLAG ; BEQ 1$ BR 9$ 1$: MOV R1,R2 ; CHARACTER,* MOV PARITY.TYPE,R0 ; ASL R0 ADD P.AAQ(R0),PC ; Case dispatch 3$: MOV R2,R1 ; RTS PC 4$: MOV R2,R1 ; BR 9$ 5$: MOV R2,R1 ; *,TEMP.CHAR BIC #177600,R1 ; *,TEMP.CHAR BIS #200,R1 ; *,TEMP.CHAR BR 7$ ; 6$: MOV R2,R1 ; *,TEMP.CHAR BIC #177600,R1 ; *,TEMP.CHAR 7$: MOV R1,R0 ; TEMP.CHAR,* ASH #-4,R0 XOR R0,R1 ; *,TEMP.CHAR MOV R1,R0 ; TEMP.CHAR,* ASR R0 ASR R0 XOR R0,R1 ; *,TEMP.CHAR MOV R1,R0 ; TEMP.CHAR,* BIC #177774,R0 CMP R0,#1 BEQ 8$ BIC #177774,R1 CMP R1,#2 BNE 10$ 8$: MOV R2,R1 ; BIC #177600,R1 9$: BIS #200,R1 RTS PC 10$: MOV R2,R1 BIC #177600,R1 99$: RTS PC ; .PSECT $PLIT$, RO , D P.AAQ: ; CASE Table for GEN.PARITY 2$: .WORD 0 ; [3$] .WORD 4 ; [4$] .WORD 24 ; [6$] .WORD 10 ; [5$] .WORD 114 ; [10$] .SBTTL Create escape character ; Create the ascii for the escape character .PSECT $CODE$, RO, I CRECONCHR:: MOV ESCCHR,R1 ; Get the escape character MOV #CONCHR,R0 ; Point to the place to store info CMPB R1,#40 ; Compare against 40 BLT 10$ ; Branch if less than CMPB R1,#177 ; Is this a delete? BEQ 30$ ; Jump if it is JMP 20$ ; Jump to the right routine. ; Here if we have a control character 10$: MOVB #'^,(R0)+ ; Store it ADD #'A-1,R1 ; Make this a real character 20$: MOVB R1,(R0)+ ; Store it CLRB (R0)+ ; Clear the last character location RTS PC ; Return to sender ; Here if we have a delete, store the 30$: MOVB #'<,(R0)+ ; Store the opening bracket MOVB #'d,(R0)+ ; Store the d MOVB #'e,(R0)+ ; Store the e MOVB #'l,(R0)+ ; Store the l MOVB #'>,(R0)+ ; Store the closing bracket CLRB (R0)+ ; Clear the last byte RTS PC ; Return to sender .SBTTL CT.OUT - Output a single character to the screen ;++ ; This routine will output a single character to the screen. ; It is used for the local echo processing. ; ; Usage: ; ; R1/ Character ; JSR PC,CT.OUT ; return here always ; ;-- .PSECT $CODE$, RO, I CT.OUT: MOV R1,OUTCHR ; Save the character QIOW$C IO.WVB,TERLUN,TTWEFN,,TOIOSB,,, $CODE$ RTS PC ; And return .SBTTL DUMPXK - Dump directly from the XK buffer ;++ ; This routine will be called directly from the XK ast input routine. This ; routine will do a QIO to directly output the characters so that there ; can be no delay in processing the input from the XK. The only way we will ; delay is if there is input from the console terminal pending. ;-- DUMPXK: DEC TOLOCK ; Do I have the interlock? BNE 99$ ; No, just exit JSR R1,$SAVE3 ; Save R1-3 ; ; Here if we can queue the XK output directly to the user terminal. ; 10$: CMP XKNXTC,XKFREC ; Is the buffer empty? BEQ 90$ ; Yes, just exit ; ; Here if we have something in the buffer ; MOVB QIOIDX,R2 ; And set up the pointer ASL R2 ; Mul by two MOV R2,R0 ; Get a copy ASL R2 ; So we have address offset ADD R0,R2 ; For correct IOSB ADD #TOIOS0,R2 ; Point at correct IOSB TSTB IB.FLG(R2) ; Is this IOSB free? BNE 90$ ; No, we must wait INCB IB.FLG(R2) ; Flag this IOSB is in use INCB QIOIDX ; Count up to next IOSB BICB #^C,QIOIDX ; Make sure it stays in range ; ; Determine how big a QIO we can post to output the information to the ; console ; MOV #XKBUFLEN,R0 ; Get the length of the buffer SUB XKNXTC,R0 ; Compute the pointer to end of buffer CMP XKNXTC,XKFREC ; Determine if in the right order BGT 20$ ; If free is before next then just ; output to the end of the buffer MOV XKFREC,R0 ; Get the address of the next free SUB XKNXTC,R0 ; Subtract the next character pointer ; ; Here after we have determine the amount of characters to output to the ; terminal ; 20$: MOV XKNXTC,R1 ; Get the pointer to the next character ADD #XKBUFF,R1 ; Point to the buffer ; ; At this point we must determine if we must strip the 8th bit from the ; characters that we just read or can leave them on. ; BIT #TRUE,NOBIT8 ; Must strip the 8th bit? BNE 40$ ; No, just do the QIO ; ; Here to loop removing the 8th bit from the input (bit number 7) ; MOV R0,-(SP) ; Save the length MOV R1,-(SP) ; Save the address 30$: BICB #200,(R1)+ ; Clear the bit SOB R0,30$ ; Loop for all characters MOV (SP)+,R1 ; Restore R1 MOV (SP)+,R0 ; And R0 ; ; Now do the QIO to output the information to the user's screen ; 40$: QIO$S #IO.WVB,#TERLUN,#TTWEFN,,R2,#CTOAST, ADD R0,XKNXTC ; Update the pointer to the next BIC #^C,XKNXTC ; Make sure we are a circular buffer BR 10$ ; Loop and see if anything more ; ; Now clear the interlock, restore R1 and return ; 90$: MOV #1,TOLOCK ; Release the interlock 99$: RTS PC ; Return to the caller .SBTTL CTOAST - AST routine XK to CT dump routine ;++ ; This routine will handle the ASTs that are generated by the dumping of ; data directly from the XK (Comm port) to the CT (Console Terminal) ; It will update the counters that the XK port uses to store information ; into its buffer. It will also light the CONEFN so that if we are ; waiting we will start up again. ;-- CTOAST: SETF$S #CONEFN ; Light the event flag ADD #IB.CNT,(SP) ; Point to count word in IOSB ADD @(SP),XKFREE ; Update the number of free characters SUB @(SP),XKUSED ; Decrease the amount used ADD #IB.FLG-IB.CNT,(SP) ; Point to flag byte CLRB @(SP) ; Clear the flag - IOSB is free TST (SP)+ ; Remove the IOSB from the stack ASTX$S ; Return from the AST routine .SBTTL XKOUT - Support local echo ;++ ; This routine will support the local echo processing and add any parity ; character before sending the character to the XK port. ; ; Usage: ; R0/ Character ; JSR PC,XKOUT ; (Return via XK.OUT) ; ;-- XKOUT: BIT #TRUE,LCLECH ; Local echo? BEQ 10$ ; No, just send it to XK JSR PC,CT.OUT ; Yes, write on screen also 10$: JSR PC,CT.PAR ; Generate the parity PJMP XK.OUT ; Write the character .SBTTL End of KERCON .END MAIN