.TITLE PHOAST - PHONE AST ROUTINES .IDENT /1.1/ .ENABL LC ;+ ; ; Free software BY ; Project Software & Development, Inc. ; ; This software is furnished for free and may be used and copied as ; desired. This software or any other copies thereof may be provided or ; otherwise made available to any other person. No title to and ; ownership of the software is hereby transferred or allowed. ; ; The information in this software is subject to change without notice ; and should not be construed as a commitment by PROJECT SOFTWARE ; AND DEVELOPMENT, INC. ; ; PROJECT SOFTWARE assumes no responsibility for the use or reliability ; of this software on any equipment whatsoever. ; ; Project Software & Development, Inc. ; 14 Story St. ; Cambridge, Ma. 02138 ; 617-661-1444 ; ; ; Title: PHOAST.MAC ; Author: Robin Miller ; Date: August 13, 1982 ; ; Description: ; ; This module contains the PHONE AST routines to handle unsolicited ; AST input from the terminals. ; ; ; Modification History: ; ;- .ENABL AMA .NLIST BEX .MCALL ASTX$S, DSAR$S, ENAR$S, QIO$S, QIOW$S, USTP$S .SBTTL GARY - UNSOLICITED AST ROUTINE ;+ ; ; GARY - Unsolicted AST routine. ; ; This routine is used to process a character typed at the local terminal. ; The character is then echoed to both the local and phoned terminals. ; ; Inputs: ; (SP) = the character input in the low byte. ; ; Outputs: ; All registers are preserved. ; ;- GARY:: MOV R0,-(SP) ; SAVE R0 MOV 2(SP),R0 ; GET THE INPUT CHARACTER MOV (SP)+,(SP) ; CLEANUP THE STACK BIT #B.MSG,STATUS ; IS THERE A MESSAGE ON LINE 3 ? BEQ 10$ ; IF EQ, NO CALL CLRMSG ; YES, CLEAR THE MESSAGE LINE 10$: CALL DOTTYS ; UPDATE SCREEN ON BOTH TTYS MOV (SP)+,R0 ; REGISTERS ASTX$S ; NOW EXIT... .SBTTL DOTTYS - UPDATE SCREEN ON BOTH TTYS ;+ ; ; DOTTYS - Update screen on both terminals. ; ; Inputs: ; R0 = the character to write. ; ; Outputs: ; All registers are preserved. ; ;- DOTTYS::CALL $SAVAL ; SAVE ALL REGISTERS MOV #TITBL,R3 ; ADDRESS OF TABLE ENTRY TO USE BIC #^C177,R0 ; ISOLATE THE ACTUAL CHARACTER MOV R0,O.CHAR(R3) ; SAVE THIS CHARACTER MOV R0,TOTBL+O.CHAR ; AND HERE FOR PHONED TERMINAL ; Check for hanging up the phone. 10$: CMPB R0,#CTRLZ ; IS IT CTRL/Z ? BEQ 20$ ; IF EQ, YES CMPB R0,#CTRLC ; IS IT CTRL/C ? BNE 30$ ; IF NE, NO ; Set flag to show we are hanging up the phone. 20$: BIS #B.HANG,STATUS ; SHOW WE ARE HANGING UP BIS #B.HANG,O.FLAG(R3) ; AND SHOW WHICH TERMINAL CALL SNDHNG ; SEND A HANGUP TO OTHER PHONER USTP$S #TNAME ; UNSTOP THE MAINLINE CODE ; CALL CHKDIR ; CHECK/REPORT DIRECTIVE ERROR BR 100$ ; AND EXIT THE AST ; Process the character input. 30$: BIT #B.ANS,STATUS ; ARE WE TALKING TO SOMEONE ? BEQ 100$ ; IF EQ, NO (IGNORE CHARACTER) CALL PROCESS ; PROCESS THE CHARACTER MOV #TOTBL,R3 ; NOW DO THE CALL PROCESS ; PHONED TERMINAL 100$: RETURN .SBTTL PROCESS - PROCESS THE CHARACTER INPUT ;+ ; ; PROCESS - Process the character input. ; ; Since this routine may be called from a non-AST state, AST's are ; disabled until we return so the buffer manipulation routines won't ; be interrupted. ; ; Inputs: ; R3 = the table entry address. ; ; Outputs: ; All registers are preserved. ; ;- PROCESS:: CALL $SAVAL ; SAVE ALL REGISTERS DSAR$S ; DISABLE ASTS MOV BUFPTR,-(SP) ; SAVE THE CURRENT POINTER CALL GETFRE ; GET A FREE BUFFER --> R0 BCS 130$ ; IF CS, NONE AVAILABLE MOV R0,O.BUFF(R3) ; SAVE THE BUFFER ADDRESS MOV O.CHAR(R3),R0 ; COPY THE CHARACTER INPUT CMPB R0,#DELETE ; IS IT A DELETE ? BEQ 70$ ; IF EQ, YES CMPB R0,#SPACE ; IS THIS A CONTROL CHARACTER ? BGE 100$ ; IF GT, NO CMPB R0,#CR ; IS IT A CARRIAGE RETURN ? BEQ 90$ ; IF EQ, YES (NEXT LINE) CMPB R0,#LF ; IS IT A LINE FEED ? BEQ 90$ ; IF EQ, YES (NEXT LINE) CMPB R0,#ESC ; IS IT AN ESCAPE ? BEQ 90$ ; IF EQ, YES (NEXT LINE) CMPB R0,#CTRLU ; IS IT A CTRL/U ? BNE 10$ ; IF NE, NO ; Process a CTRL/U character. CMP O.COL(R3),#1 ; ARE WE ALREADY AT COLUMN 1 ? BNE 5$ ; IF NE, NO (CLEAR CURRENT LINE) CMP O.LINE(R3),O.INIT(R3) ; ARE WE AT THE TOP LINE ? BEQ 5$ ; IF EQ, YES (CLEAR CURRENT LINE) DEC O.LINE(R3) ; NO, CLEAR THE PREVIOUS LINE 5$: MOV #1,O.COL(R3) ; SET TO COLUMN 1 BR 80$ ; BR TO COMMON CODE ; Process a clear screen. Either CTRL/E or CTRL/L. 10$: CMPB R0,#CTRLE ; IS IT A CTRL/E ? BEQ 20$ ; IF EQ, YES CMPB R0,#FF ; IS IT A CTRL/L ? BNE 30$ ; IF NE, NO 20$: CALL CLRREG ; CLEAR THE REGION BR 120$ ; AND OUTPUT THE BUFFER ; Process a horizontal tab. Convert to spaces. 30$: CMPB R0,#HT ; HORIZONTAL TAB ? BNE 50$ ; IF NE, NO MOV O.COL(R3),R5 ; COPY THE COLUMN NUMBER DEC R5 ; ADJUST THE COLUMN NUMBER CLR R4 ; CLEAR THE LOW BITS DIV #8.,R4 ; DIVIDE BY TAB SIZE MOV #8.,R4 ; PRESUME A FULL TAB STOP SUB R5,R4 ; CALCULATE THE SPACE COUNT CALL MAKBUF ; MAKE THE INITIAL BUFFER 40$: MOVCHR ; MOVE IN A SPACE INC O.COL(R3) ; COUNT THIS COLUMN SOB R4,40$ ; AND LOOP UNTIL DONE BR 120$ ; NOW OUTPUT THE BUFFER ; Process a bell character. Don't count the bell. 50$: CMPB R0,#BELL ; IS THIS A BELL ? BNE 60$ ; IF NE, NO CALL MAKBUF ; MAKE THE INITIAL BUFFER MOVCHR ; MOVE IN A BELL BR 120$ ; AND OUTPUT THE BUFFER ; Process screen refresh ... CTRL/W of course. 60$: CMPB R0,#CTRLW ; REFRESH THE SCREEN ? BNE 65$ ; IF NE, NO CALL SCRMSG ; WRITE THE INITIAL SCREEN BR 80$ ; BR TO COMMON CODE ; Unrecognized control character, free the unused buffer. 65$: MOV O.BUFF(R3),R0 ; GET THE CURRENT BUFFER ADDRESS CALL FREBUF ; AND FREE IT (WE DON'T NEED IT) BR 130$ ; IGNORE ALL OTHERS FOR NOW ; Delete character detected. 70$: CMP O.COL(R3),#1 ; ALREADY AT LEFT MARGIN ? BEQ 65$ ; IF EQ, YES (IGNORE DELETE) DEC O.COL(R3) ; ADJUST THE COLUMN # 80$: CALL MAKBUF ; MAKE THE INTIAL BUFFER CALL CEOL ; ERASE TO END OF LINE BR 120$ ; AND OUTPUT THE BUFFER ; Line terminator detected, position to the next line. 90$: CALL NXTLIN ; POSITION TO THE NEXT LINE BR 120$ ; AND POSITION THE CURSOR ; Build the buffer to output to the terminal. 100$: CALL MAKBUF ; MAKE THE INITIAL BUFFER CMP O.COL(R3),#80. ; ARE WE AT THE RIGHT MARGIN ? BLE 110$ ; IF LT, NO CALL NXTLIN ; YES, POSITION TO NEXT LINE 110$: MOVB R0,@BUFPTR ; COPY THE CHARACTER INPUT INC BUFPTR ; BUMP THE BUFFER POINTER INC O.COL(R3) ; BUMP THE COLUMN NUMBER ; Write the current buffer. 120$: CALL WRTBUF ; WRITE THE CURRENT BUFFER 130$: MOV (SP)+,BUFPTR ; RESTORE ORIGINAL POINTER ENAR$S ; REENABLE ASTS RETURN .SBTTL WRTBUF - WRITE THE CURRENT BUFFER ;+ ; ; WRTBUF - Write the current buffer. ; ; Inputs: ; R3 = the table entry address. ; ; Outputs: ; C bit clear/set = success/failure. ; ; All registers are preserved. ; ;- WRTBUF::JSR R2,$SAVVR ; SAVE R0 - R2 MOV O.BUFF(R3),R0 ; COPY THE LAST BUFFER ADDRESS MOV R0,R1 ; COPY THE BUFFER ADDRESS TST (R0)+ ; POINT TO THE I/O STATUS BLOCK ADD #6,R1 ; POINT TO THE DATA AREA MOV BUFPTR,R2 ; COPY UPDATED BUFFER POINTER SUB R1,R2 ; CALCULATE THE BYTE COUNT ; Issue the QIO to either the local or phoned terminal. CMP R3,#TITBL ; IS THIS THE LOCAL TERMINAL ? BNE 10$ ; IF NE, NO (MUST BE PHONED TTY) QIO$S #IO.WAL,#OULUN,,,R0,#TIAST, BR 20$ ; AND CHECK FOR ERRORS 10$: QIO$S #IO.WBT!TF.WAL,#TOLUN,,,R0,#TOAST, 20$: CALL CHKDIR ; CHECK/REPORT DIRECTIVE ERROR ; If no error occured, add this buffer to the end of the queue. MOV O.BUFF(R3),R0 ; COPY THE LAST BUFFER ADDRESS BCS 30$ ; IF CS, DIRECTIVE ERROR CALL ADDBUF ; ADD BUFFER TO END OF QUEUE BR 40$ ; AND CONTINUE ... ; Since the directive failed, we must free the buffer since ; there isn't an AST queued to free it. 30$: CALL FREBUF ; RETURN BUFFER TO FREE QUEUE 40$: RETURN .SBTTL CLRREG - CLEAR THE REGION FOR THE ENTRY ;+ ; ; CLRREG - Clear the region for the current entry. ; ; Inputs: ; R3 = address of table entry. ; ; Outputs: ; All registers are preserved. ; ;- CLRREG::JSR R2,$SAVVR ; SAVE R0 - R2 MOV O.INIT(R3),O.LINE(R3) ; START AT THE TOP LINE MOV #1,O.COL(R3) ; AND COLUMN 1 CALL MAKBUF ; POSITION TO TOP LINE MOV O.MAX(R3),R2 ; COPY THE MAXIMUM LINE # SUB O.INIT(R3),R2 ; CALCULATE NUMBER OF LINES INC R2 ; INCLUSIVE NUMBER ; Clear the current window. 10$: CALL CEOL ; CLEAR TO END OF LINE DEC R2 ; ADJUST THE COUNT BEQ 20$ ; IF EQ, DONE MOVCHR ; ELSE, GO TO NEXT LINE BR 10$ ; AND LOOP ; Reposition the cursor at the top line. 20$: MOV O.LINE(R3),R1 ; COPY THE CURRENT LINE # MOV O.COL(R3),R2 ; COPY THE CURRENT COLUMN # CALL MAKCUR ; MAKE THE CURSOR ADDRESS RETURN .SBTTL MAKBUF - MAKE THE INITIAL BUFFER ;+ ; ; MAKBUF - Make the initial buffer. ; ; This routine builds the cursor address for the next character. ; ; Inputs: ; R3 = the table entry address. ; ; Outputs: ; All registers are preserved. ; ;- MAKBUF::JSR R2,$SAVVR ; SAVE R0 - R2 CALL GETADR ; GET/SETUP BUFFER POINTER MOV O.LINE(R3),R1 ; COPY THE CURRENT LINE # MOV O.COL(R3),R2 ; COPY THE CURRENT COLUMN # CALL MAKCUR ; MAKE THE CURSOR ADDRESS RETURN .SBTTL MAKREG - MAKE THE SCROLLING REGION ;+ ; ; MAKREG - Make the scrolling region. ; ; This routine makes the scrolling region. ; ; Inputs: ; R3 = the table entry address. ; ; Outputs: ; All registers are preserved. ; ;- MAKREG::JSR R2,$SAVVR ; SAVE R0 - R2 CALL GETADR ; GET/SETUP BUFFER POINTER MOV O.INIT(R3),R1 ; COPY THE TOP LINE # CALL MAKLIN ; MAKLIN DOES "$[n;" MOV O.MAX(R3),R1 ; COPY THE BOTTOM LINE # CALL MAKNUM ; MAKE THE ASCII LINE # MOVCHR ; LAST PART OF SCROLL REGION ; Setting the scroll region positions the cursor home, ; so we reposition the cursor to wherever. MOV O.LINE(R3),R1 ; COPY THE CURRENT LINE # MOV O.COL(R3),R2 ; COPY THE CURRENT COLUMN # CALL MAKCUR ; MAKE THE CURSOR ADDRESS RETURN ; Scroll the region up. SCRUP: JSR R2,$SAVVR ; SAVE R0 - R2 MOVCHR ; FORCE A SCROLL UP CALL NOREG ; DISABLE THE SCROLLING REGION MOV O.LINE(R3),R1 ; COPY THE CURRENT LINE # MOV O.COL(R3),R2 ; COPY THE CURRENT COLUMN # CALL MAKCUR ; MAKE THE CURSOR ADDRESS RETURN .SBTTL NXTLIN - POSITION TO THE NEXT LINE ;+ ; ; NXTLIN - Position the cursor to the next line. ; ; Inputs: ; R3 = the table entry address. ; ; Outputs: ; O.COL and O.LINE adjusted. ; ; All registers are preserved. ; ;- NXTLIN::MOV #1,O.COL(R3) ; START AT COLUMN 1 CMP O.LINE(R3),O.MAX(R3) ; ARE WE OVER THE MAX LINE ? BLT 20$ ; IF LT, NO (BUMP LINE #) BIT #B.SCR,STATUS ; ARE WE SCROLLING THE WINDOW ? BNE 10$ ; IF NE, YES ; Wrap around instead of scrolling. MOV O.INIT(R3),O.LINE(R3) ; BACK TO THE TOP LINE CALL MAKBUF ; MAKE THE CURSOR ADDRESS BR 30$ ; AND CONTINUE ... ; Scroll the display window up one line. 10$: CALL MAKREG ; MAKE THE SCROLLING REGION CALL SCRUP ; NOW SCROLL THE REGION UP RETURN ; Position to the next line. 20$: INC O.LINE(R3) ; BUMP THE LINE NUMBER CALL MAKBUF ; MAKE THE CURSOR ADDRESS BIT #B.SCR,STATUS ; ARE WE SCROLLING ? BNE 40$ ; IF NE, YES 30$: CALL CEOL ; ELSE, CLEAR THE LINE 40$: RETURN .SBTTL GETADR - GET/SETUP THE BUFFER POINTER ;+ ; ; GETADR - Get and setup the buffer address in the buffer pointer. ; ; Inputs: ; R3 = the table entry address. ; ; Outputs: ; BUFPTR = setup with the buffer pointer. ; ;- GETADR: MOV O.BUFF(R3),BUFPTR ; GET THE LAST BUFFER ADDRESS ADD #6,BUFPTR ; POINT TO THE DATA PORTION RETURN .SBTTL TIAST - LOCAL TERMINAL QIO AST ROUTINE .SBTTL TOAST - PHONED TERMINAL QIO AST ROUTINE ;+ ; ; TIAST - Local terminal QIO AST routine. ; TOAST - Phoned terminal QIO AST routine. ; ; This routine is entered when the QIO request is completed. The buffer ; used for the QIO is returned to the free buffer queue. ; ; Inputs: ; SP(0) = the I/O status block used for this QIO. ; ; Outputs: ; All registers are preserved. ; ;- .ENABL LSB TIAST:: MOV R3,-(SP) ; SAVE R3 MOV #TITBL,R3 ; SET UP THE TABLE ADDRESS BR 10$ ; AND CONTINUE ... TOAST:: MOV R3,-(SP) ; SAVE R3 MOV #TOTBL,R3 ; SET UP THE TABLE ADDRESS 10$: MOV R0,-(SP) ; SAVE R0 CALL REMBUF ; REMOVE BUFFER FROM QUEUE BCS 20$ ; IF CS, NO BUFFERS QUEUED CALL FREBUF ; FREE THE BUFFER USED MOV 4(SP),R3 ; I/O STATUS BLOCK ADDRESS TSTB (R3) ; DID WE SUCCEED ? BPL 20$ ; IF PL, YES MOV (R3),R0 ; NOPE, COPY THE ERROR CODE BIC #^C377,R0 ; SHOW ITS AN I/O ERROR CALL WRTERR ; AND WRITE THE ERROR MESSAGE 20$: MOV (SP)+,R0 ; RESTORE R0 MOV (SP)+,R3 ; AND R3 TST (SP)+ ; CLEAN OFF THE STACK ASTX$S ; AND EXIT THE AST .END