* PROGRAM: TERMBLS (EXTENDED BUFFER LOAD SUBSYSTEM OF TERM II) * AUTHOR: RICHARD CONN * VERSION: 4.7 * DATE: 6 JUL 81 * PREVIOUS VERSIONS: 1.0 (18 MAY 81) * 4.5 (20 JUN 81), 4.6 (26 JUN 81) VERS EQU 47 ; Version Number * THE FOLLOWING SHOULD BE CHANGED IF YOU DO NOT HAVE A STANDARD (ORG 0) * CP/M SYSTEM CPM$BASE EQU 0 ; BASE OF CP/M SYSTEM * ASCII EQUATES CR EQU 0DH LF EQU 0AH BEL EQU 'G'-'@' TAB EQU 'I'-'@' BS EQU 'H'-'@' DL EQU 7FH CTRLC EQU 'C'-'@' CTRLS EQU 'S'-'@' CTRLZ EQU 'Z'-'@' ESC EQU 1BH * CP/M EQUATES WBOOT EQU CPM$BASE BOOT EQU CPM$BASE+1 BDOS EQU CPM$BASE+5 FCB EQU CPM$BASE+5CH BUFF EQU CPM$BASE+80H * SPECIAL EQUATES TENTH$SEC$DELAY EQU 7500 ; 0.1 SEC DELAY FOR 1 MHZ CPAUS EQU 4000H ; PAUSE BEFORE COMMAND MENU IS DISPLAYED JBASE EQU CPM$BASE+103H ; BASE OF JUMP TABLE * * OVERLAY BUFFERS * BUFFER$START EQU JBASE+120 INIT$CMND EQU BUFFER$START TERM$ENTRY EQU BUFFER$START+1 EXIT$CHAR EQU BUFFER$START+2 PROCESSOR$SPEED EQU BUFFER$START+3 BREAK$CHAR EQU BUFFER$START+4 ECHOFL EQU BUFFER$START+5 PRFL EQU BUFFER$START+6 BUFLG EQU BUFFER$START+7 XLATE$IN$FLAG EQU BUFFER$START+8 XLATE$OUT$FLAG EQU BUFFER$START+9 MASK$IN$FLAG EQU BUFFER$START+10 MASK$OUT$FLAG EQU BUFFER$START+11 OUTPUT$MASK EQU BUFFER$START+12 XLATE$IN$ACTIVE EQU BUFFER$START+13 XLATE$OUT$ACTIVE EQU BUFFER$START+14 M2$ON EQU BUFFER$START+15 CTRLS$FLAG EQU BUFFER$START+16 BFL$FLAG EQU BUFFER$START+17 AUTO$INIT EQU BUFFER$START+18 RFU EQU BUFFER$START+19 TABLE$BASE EQU BUFFER$START+39 XLATE$IN$TABLE EQU TABLE$BASE XLATE$OUT$TABLE EQU TABLE$BASE+256 PHONE$NUMBERS EQU TABLE$BASE+512 END$BUFFERS EQU PHONE$NUMBERS+512 TERM$LOADER EQU END$BUFFERS/256*256+256+256 * **** START OF PROGRAM **** * ORG CPM$BASE+100H XRA A ; A=0 MVI B,17 LXI H,BUFFER$START ZFILL: MOV M,A ; STORE ZEROES INX H DCR B JNZ ZFILL MVI A,'E'-'@' ; SET EXIT CHAR STA EXIT$CHAR MVI A,2 ; 2MHZ PROCESSOR SPEED STA PROCESSOR$SPEED JMP START ; TERMBLS IS SELF-EXECUTING ORG TERM$LOADER+256 START: LXI SP,STACK ; SP=TERM STACK * SET NO FILE SPECIFIED MVI A,' ' ; A= STA FCB+1 ; SET NO FILE * SET EXIT CHAR IN COMMAND TABLE LDA EXIT$CHAR ; GET CURRENT EXIT CHAR STA CTAB ; SAVE IT IN CTAB * DETERMINE END ADDRESS OF BUFFER LHLD BDOS+1 ; GET ADDRESS OF FBASE MVI L,0 MOV A,H ; SET END OF BUFFER TO BEFORE THE CCP SUI 10 ; CCP IS 2K, SO SET 10 PAGES (2K + 2 BLOCKS) MOV H,A SHLD BUFEND ; SET END OF BUFFER * DETERMINE ADDRESS OF CON: I/O ROUTINES LDA BOOT+1 ; GET HIGH BYTE OF BIOS VECTOR MOV H,A ; ... IN H MVI L,6 ; CONSOLE STATUS ADR SHLD STADR MVI L,9 ; CONSOLE INPUT ADR SHLD INADR MVI L,12 ; CONSOLE OUTPUT ADR SHLD OUTADR * DETERMINE START OF BUFFER CALL SP$END ; GET END OF SUPPORT PACKAGE SHLD BUFFER ; SET BUFFER PTR SHLD BUF$NEXT ; SET NEXT BYTE TO LOAD JMP TEXIT * * **** TERMINAL MODE **** * OPTD: * CHECK FOR MODEM 2 ENABLED LDA M2$ON ; GET FLAG ORA A ; 0=NO JNZ OPTD1 ; GO TO TERMINAL MODE IF SO * CHECK FOR TELEPHONE INTERFACE SUPPORT CALL STAT$TI ; TELEPHONE INTERFACE IN SUPPORT PACKAGE? JZ OPTD1 ; GO TO TERMINAL MODE IF NOT * CHECK FOR SIGNAL ON LINE CALL TI$CST ; TELEPHONE CARRIER? JNZ OPTD1 CALL PRINT$MESSAGE DB 'No Signal on Telephone Line -- Returning to TERM II',0 CALL PAUSE ; 2 SEC DELAY JMP TERM4 * ENTER TERMINAL MODE AND PRINT OPENING MESSAGE OPTD1: CALL SCREEN$CLEAR CALL PRINT$ID CALL PRINT$MESSAGE DB CR,LF,'++ Terminal Mode ++',CR,LF,0 CALL ECHOMS ; PRINT ECHO MESSAGE CALL BUFMS ; PRINT BUFFER LOAD MESSAGE CALL MODMS ; PRINT MODEM MESSAGE CALL XLATEMS ; PRINT TRANSLATION MESSAGE CALL BREAKMS ; PRINT BREAK CHAR MESSAGE CALL EXITCHMS ; PRINT EXIT CHAR MESSAGE * * ** TERMINAL ** * * TERMINAL PROGRAM -- * ALLOWS THE USER TO COMMUNICATE IN A NORMAL TIMESHARING * FASHION WITH AN EXTERNAL COMPUTER. FACILITIES ARE INCLUDED * FOR BUFFER LOAD AND DUMP. * TERMINAL: CALL LOS ; CHECK FOR LOSS OF SIGNAL CALL ST$CON ; CHECK CONSOLE STATUS JNZ TERMC ; GET CONSOLE CHAR IF READY CALL ST$MOD ; CHECK MODEM STATUS JZ TERMINAL ** MODEM INPUT/CONSOLE OUTPUT SECTION ** TERMM: CALL IN$MOD ; GET MODEM CHAR CALL OUT$CON ; PRINT CALL BFLOAD ; LOAD BUFFER IF FLAG SET JMP TERMINAL ** CONSOLE INPUT/MODEM OUTPUT SECTION ** TERMC: CALL CON$CHAR ; GET CONSOLE CHAR AND ECHO IF SET CALL EXIT$CHECK ; CHECK FOR EXIT CHAR JZ TEXITXX ; TEXIT WITH DELAY CALL BREAK$CHECK ; CHECK FOR BREAK CHAR JZ TRANSMIT$BREAK CALL OUT$MOD ; SEND TO MODEM JMP TERMINAL ** TRANSMIT EXIT CHAR ** TRANSMIT$EXITCH: LDA EXIT$CHAR ; GET CHAR CALL OUT$MOD ; TRANSMIT IT JMP TERMINAL ** TRANSMIT BREAK IF ABLE ** TRANSMIT$BREAK: MVI A,0 ; CAN SYSTEM? CALL SP$BREAK JNZ TRANS$BREAK CALL PRINT$MESSAGE DB CR,LF,'Sorry, BREAK Function Not Supported',0 CALL PAUSE JMP TERMINAL TRANS$BREAK: MVI A,0FFH ; TRANSMIT IT CALL SP$BREAK CALL PRINT$MESSAGE DB CR,LF,'** Break Transmitted **',CR,LF,0 JMP TERMINAL SP$BREAK: PUSH PSW ; SAVE FUNCTION CODE LDA M2$ON ; SELECT MODEM ORA A ; 0=1 JZ SP$BR1 POP PSW ; GET FUNCTION CODE JMP BR$MOD2 SP$BR1: POP PSW ; GET FUNCTION CODE JMP BR$MOD1 ** LOAD BUFFER IF FLAG SET ** BFLOAD: MOV C,A ; CHAR IN C ORA A ; DON'T SAVE NULL RZ CPI 7FH ; DON'T SAVE RZ LDA BUFLG ; CHECK FLAG ORA A ; 0=NO JZ BFLD PUSH D ! PUSH H LHLD BUFEND ; GET PTR TO END OF BUFFER XCHG LHLD BUF$NEXT ; GET PTR TO CURRENT CHAR MOV A,H ; EQUAL? SUB D JC BFL1 * BUFFER FULL BFL0: XRA A ; TURN OFF BUFFER LOAD STA BUFLG CALL PRINT$MESSAGE DB CR,LF,'Buffer Full -- Load OFF',CR,LF,0 JMP BFL1X * PLACE CHAR IN BUFFER BFL1: MOV M,C ; PUT CHAR INX H ; PT TO NEXT SHLD BUF$NEXT XCHG ; ADDRESS IN DE LHLD BUFEND ; CHECK FOR 1K LESS THAN END ADDRESS DCR H ; 1K LESS DCR H DCR H DCR H DCR H ; 1 MORE MOV A,H ; COMPARE AGAINST CURRENT PAGE CMP D JNC BFL2 ; OK IF D CZ BFL$STAT POP H ! POP D BFLD: MOV A,C ; GET CHAR RET * RING BELL EVERY 10 COUNTS BEEP10: LDA BELLCTR ; DECREMENT COUNTER DCR A STA BELLCTR RNZ CALL RING$BELL MVI A,10 ; RESET COUNTER STA BELLCTR RET * RING BELL ON CONSOLE RING$BELL: PUSH B PUSH D MVI E,BEL MVI C,2 CALL BDOS POP D POP B RET * PRINT STATUS LINE FOR BUFFER LOAD IF FLAG SET BFL$STAT: LDA BFL$FLAG ; GET FLAG FOR STATUS DISPLAY ORA A ; 0=NO DISPLAY RZ CALL SCREEN$MESSAGE DB 1,40,'++ Buffer Space Left = ',0 LHLD BUF$NEXT ; GET ADDRESS OF NEXT BYTE XCHG LHLD BUFEND ; GET END ADDRESS OF BUFFER MOV A,H ; SUBTRACT SUB D CALL DECIMAL$OUT ; PRINT IN DECIMAL CALL PRINT$MESSAGE DB ' Pages ++',0 CALL SCREEN$MESSAGE ; GOTO END OF SCREEN DB 24,1,0 RET * * LOS -- LOSS OF SIGNAL * THIS ROUTINE CHECKS FOR LOSS OF THE TELEPHONE SIGNAL AND ABORTS * TO THE TERMINAL EXIT ROUTINE IF LOSS OF SIGNAL OCCURS * LOS: LDA M2$ON ; FAKE CARRIER IF MODEM 2 IS ON ORA A ; SET FLAGS RNZ ; MODEM 2 IS ON SO CARRIER PRESENT CALL STAT$TI ; TELEPHONE INTERFACE AVAILABLE? RZ ; RETURN IF NOT CALL TI$CST ; CHECK FOR CARRIER RNZ ; RETURN IF CARRIER CALL PRINT$MESSAGE DB BEL,CR,LF,'ERROR -- Loss of Carrier Signal',CR,LF DB 'Returning to TERM II',CR,LF,0 JMP TERM4 * * * TOGGLE BUFFER LOAD * BUF$TOGGLE: LDA BUFLG ; GET FLAG CMA STA BUFLG ORA A ; SET FLAG CZ BUFMS ; PRINT MESSAGE IF FLAG OFF MVI A,10 ; SET ALARM COUNTER STA BELLCTR LDA BUFLG ; INIT BUFFER IF NECESSARY ORA A JZ TERMINAL CALL SCREEN$CLEAR CALL PRINT$ID CALL SCREEN$MESSAGE DB 4,9,'++ TERM II BLS Buffer Load Facility ++',0 CALL PRINT$MESSAGE DB CR,LF,LF,'Load Buffer from Disk or Modem (D/M/^C/=M)? ',0 CALL GET$RESPONSE CPI CTRLC ; ABORT? JZ TEXIT CPI 'D' ; DISK? JZ TBUF$DISK XRA A ; A=0 STA BFL$FLAG ; SET STATUS FLAG OFF STA CTRLS$FLAG ; SET ^S FLAG OFF CALL PRINT$MESSAGE DB CR,LF,LF,'Transmit ^S if Buffer is Almost Full (Y/N/=N)? ' DB 0 CALL GET$RESPONSE CPI 'Y' JNZ TBUF$MODEM1 MVI A,0FFH ; SET ^S STA CTRLS$FLAG TBUF$MODEM1: CALL PRINT$MESSAGE DB CR,LF,'Clear Memory Buffer (Y/N/=N)? ',0 CALL GET$RESPONSE CPI 'Y' JNZ TBUF$MODEM2 LHLD BUFFER ; BUFFER ON -- SET PTR SHLD BUF$NEXT TBUF$MODEM2: CALL PRINT$MESSAGE DB CR,LF,'Display Buffer Status (Y/N/=N)? ',0 CALL GET$RESPONSE CPI 'Y' JNZ OPTD MVI A,0FFH ; TURN ON FLAG STA BFL$FLAG ; SET FLAG JMP OPTD * ** LOAD BUFFER FROM DISK ** * TBUF$DISK: XRA A STA BUFLG ; SET BUFFER LOAD OFF LHLD BUFFER SHLD BUF$NEXT ; INITIALIZE BUFFER CALL INIT$FCB ; INITIALIZE FCB LXI D,FCB ; OPEN FILE MVI C,15 CALL BDOS INR A ; ERROR? JZ FNF$ERROR LHLD BUFFER ; PT TO START OF BUFFER SHLD BUF$NEXT ; SAVE PTR TO NEXT BYTE IN BUFFER LXI D,BUFF ; SET DMA ADDRESS MVI C,26 CALL BDOS * READ SECTOR OF FILE TBUF$DISK1: LXI D,FCB ; READ SECTOR OF FILE MVI C,20 CALL BDOS LHLD BUFEND ; GET END OF BUFFER IN PREP FOR ERROR EXIT ORA A ; OK? JNZ TBUF$DISK$DONE * STORE SECTOR IN BUFFER XCHG ; END OF BUFFER IN DE LHLD BUF$NEXT ; GET PTR TO NEXT BYTE IN BUFFER MOV A,H SUB D JC TBUF$DISK2 CALL PRINT$MESSAGE DB CR,LF,BEL,'Buffer Overflow -- Load Incomplete',0 CALL PAUSE JMP TEXIT TBUF$DISK2: LXI D,BUFF ; PT TO SECTOR IN MEMORY * LOAD SECTOR INTO BUFFER TBUF$DISK3: LDAX D ; GET CHAR CPI CTRLZ ; EOF? JZ TBUF$DISK$DONE MOV M,A INX H ; PT TO NEXT INX D MOV A,D ; DONE? CPI 1 JNZ TBUF$DISK3 SHLD BUF$NEXT ; SAVE PTR TO NEXT BYTE OF BUFFER JMP TBUF$DISK1 TBUF$DISK$DONE: DCX H ; PT TO LAST BYTE IN BUFFER SHLD BUF$NEXT * CLOSE FILE AND EXIT JMP TEXIT * FILE NOT FOUND ERROR FNF$ERROR: CALL PRINT$MESSAGE DB CR,LF,'ERROR -- File Not Found',0 CALL PAUSE JMP TEXIT * * **** DUMP STORAGE BUFFER TO MODEM OR DISK **** * TEXIT ENTRY POINT * DUMP$BUFFER: CALL SCREEN$CLEAR CALL PRINT$ID CALL PRINT$MESSAGE DB CR,LF,LF,' ++ TERM II BLS Buffer Dump Facility ++',CR,LF,0 XRA A ; (A=0) TURN OFF BUFFER LOAD STA BUFLG CALL BUFMS ; PRINT MESSAGE CALL PRINT$MESSAGE DB CR,LF,LF,'Dump to Disk or Modem (D/M/^C/=D)? ',0 CALL GET$RESPONSE CPI CTRLC ; ABORT? JZ TEXIT CPI 'M' JZ DUMP$TO$MODEM * ** DUMP TO DISK ** * LXI H,BUFF ; PT TO SECTOR BUFFER SHLD BUF$PTR ; SET PTR CALL INIT$FCB ; SET FCB CALL ERASE$OLD$FILE CALL MAKE$NEW$FILE LHLD BUFFER ; START OF BUFFER * CHECK FOR COMPLETION OF DUMP DISK$DUMP$NEXT: PUSH H ; SAVE HL XCHG ; SAVE HL LHLD BUF$NEXT ; CHECK FOR DONE XCHG ; HL PTS TO NEXT BYTE, DE PTS TO END OF BUFFER MOV A,D ; START OF BUFFER? SUB H JC DC1 JNZ DC2 MOV A,E SUB L JC DC1 JNZ DC2 DC1: CALL PRINT$MESSAGE DB CR,LF,'** Buffer Dump Complete **',CR,LF,0 POP H JMP DC3 DC2: POP H JMP DISK$DUMP$BLOCK ; DUMP NEXT BLOCK * CLEAN UP DISK DUMP DC3: LHLD BUF$PTR ; PT TO NEXT BYTE IN BUFFER DDN1: MVI M,CTRLZ ; FILL SECTOR W/CTRL-Z'S INR L ; PT TO NEXT JNZ DDN1 * WRITE LAST SECTOR AND CLOSE FILE LXI D,FCB MVI C,21 ; WRITE PUSH D ; SAVE FCB PTR CALL BDOS ORA A ; OK? JNZ WRITE$ERROR POP D MVI C,16 ; CLOSE CALL BDOS JMP TEXIT * DUMP BUFFER TO DISK DISK$DUMP$BLOCK: XCHG ; DE PTS TO BYTE LHLD BUF$PTR ; PT TO NEXT BYTE IN DISK BUFFER MOV A,H ; BUFFER FULL? CPI 1 JZ DDB2 LDAX D ; GET BYTE ORA A ; SKIP NULLS JZ DDB1 MOV M,A ; PLACE IN BUFFER INX H ; INCR BUFFER PTR SHLD BUF$PTR DDB1: XCHG ; HL NOW PTS TO CURRENT BYTE CALL ABORT ; CHECK FOR ABORT INX H ; PT TO NEXT BYTE JMP DISK$DUMP$NEXT * WRITE SECTOR TO DISK DDB2: LXI H,BUFF ; RESET BUFFER PTR SHLD BUF$PTR XCHG ; HL PTS TO BYTE PUSH H ; SAVE IT MVI C,21 ; WRITE TO FILE LXI D,FCB ; PT TO FCB CALL BDOS ORA A ; OK? JNZ WRITE$ERROR POP H ; GET PTR TO CURRENT BYTE JMP DISK$DUMP$BLOCK * ERROR IN WRITING TO DISK -- FULL WRITE$ERROR: CALL PRINT$MESSAGE DB CR,LF,'ERROR -- Disk Full -- Dump Aborted',CR,LF,0 JMP TEXIT * ** DUMP TO MODEM ** * DUMP$TO$MODEM: CALL SET$MONITOR ; SET MONITORING OF OUTPUT CALL SET$DELAY ; SET DELAY OF EACH CHAR CALL SET$LF$DELAY ; SET DELAY FOR PROCESSING LHLD BUFFER ; START OF BUFFER * CHECK FOR COMPLETION OF DUMP MODEM$DUMP$NEXT: CALL DUMP$COMPLETE ; DONE? JNZ TEXIT ; GO TO TEXIT WHEN DONE * SEND CHAR TO MODEM MOV A,M ; GET CHAR ANI 7FH ; MASK OUT MSB JZ MODEM$DUMP$SKIP ; DON'T OUTPUT CPI 7FH ; DON'T OUTPUT JZ MODEM$DUMP$SKIP CALL SEND ; SEND CHAR MODEM$DUMP$SKIP: CALL ABORT ; CHECK FOR ABORT INX H ; PT TO NEXT CHAR JMP MODEM$DUMP$NEXT * DETERMINE IF DUMP IS FINISHED; A=0 IF NO, A=0FFH IF YES DUMP$COMPLETE: PUSH H ; SAVE HL XCHG ; SAVE HL LHLD BUF$NEXT ; CHECK FOR DONE XCHG ; HL PTS TO NEXT BYTE, DE PTS TO END OF BUFFER MOV A,D ; START OF BUFFER? SUB H JC DMPC1 JNZ DMPC2 MOV A,E SUB L JC DMPC1 JNZ DMPC2 DMPC1: CALL PRINT$MESSAGE DB CR,LF,'** Buffer Dump Complete **',CR,LF,0 XRA A ; TURN OFF SKIP STA LF$SKIP CMA ; A=0FFH ORA A ; SET FLAGS POP H RET DMPC2: XRA A ; A=0 POP H RET * ** SEND CHARS TO MODEM WITH PROCESSING ** * SEND: PUSH PSW PUSH H PUSH D PUSH B MOV C,A ; CHAR IN C CPI LF JNZ SEND1 LDA LF$SKIP ; SKIP ? ORA A ; 0=YES JNZ SEND2 SEND1: MOV A,C ; GET CHAR CALL OUT$MOD ; SEND IT SEND2: LDA MONIT$FLAG ; MONITOR? ORA A ; 0=YES MOV A,C ; PREP FOR MONITOR CZ OUT$CON LDA DELAY ; INTER-CHAR DELAY? ORA A ; 0=NO JZ SEND3 CALL CDELAY ; PAUSE BETWEEN CHARS SEND3: MOV A,C CPI LF JNZ SEND4 LDA CR$DELAY ; DELAY ON ? ORA A ; 0? JZ SEND4 MOV B,A ; COUNT IN B SEND$LF$DEL: CALL CDELAY ; PAUSE DCR B JNZ SEND$LF$DEL SEND4: POP B POP D POP H POP PSW RET * DELAY ROUTINE CDELAY: LXI D,CPAUS CDELAY1: DCX D MOV A,D ORA E JNZ CDELAY1 RET * ** REMOTE I/O FLAG SETTINGS BY USER ** * * SET (SCROLLING) DELAY TIMER SET$LF$DELAY: * SET TRANSMISSION XRA A ; TURN OFF FLAG STA LF$SKIP CALL PRINT$MESSAGE DB CR,LF,'Transmit ''s (Y/N/=N)? ',0 CALL GET$RESPONSE CPI 'Y' ; TRANSMIT ? JZ SLFD1 MVI A,0FFH ; TURN ON FLAG STA LF$SKIP * SET TIMER SLFD1: XRA A ; NO DELAY STA CR$DELAY CALL PRINT$MESSAGE DB CR,LF,' Delay (0 ... 9, =0)? ',0 CALL GET$RESPONSE SUI '0' ; CONVERT 0-9 ASCII TO BINARY CPI 10 ; OK IF LESS THAN 10 RNC INR A ; ADD 1 STA CR$DELAY RET * SET MODEM DELAY TIMER SET$DELAY: XRA A ; SET NO DELAY STA DELAY CALL PRINT$MESSAGE DB CR,LF,'Transmit Delay (SHORT/LONG/=SHORT)? ',0 CALL GET$RESPONSE CPI 'L' ; KEY ON LONG RNZ MVI A,20H ; SET LONG DELAY STA DELAY RET * SET FILE SEND/RECEIVE MONITOR FLAG SET$MONITOR: XRA A ; A=0 STA MONIT$FLAG ; TURN ON MONITOR BY DEFAULT CALL PRINT$MESSAGE DB CR,LF,'Monitor Information Transfer (Y/N/=Y)? ',0 CALL GET$RESPONSE CPI 'N' ; NO? RNZ STA MONIT$FLAG ; SET FLAG RET * * * TOGGLE ECHO FLAG * ECHO$TOGGLE: LDA ECHOFL ; FLIP FLAG CMA STA ECHOFL JMP OPTD ; CONTINUE TERMINAL MODE * * * HANG UP THE TELEPHONE * PH$HANG: CALL STAT$TI ; TELEPHONE INTERFACE AVAILABLE? JZ PH$HANG$ERROR CALL PRINT$MESSAGE DB CR,LF,'Disconnecting Telephone -- ',0 CALL TI$HANG ; HANG UP PHONE CALL PRINT$MESSAGE DB 'Telephone is Disconnected',CR,LF,0 JMP WBOOT ; RETURN TO CP/M PH$HANG$ERROR: CALL PRINT$MESSAGE DB CR,LF,'Telephone Interface Not Supported -- Returning to CP/M' DB 0 JMP WBOOT * * * LOAD TERM.COM INTO MEMORY OVER THIS ROUTINE * TERM4: LXI H,TERMFCB LXI D,FCB MVI B,32 ; COPY 'TERM.COM' FCB INTO DEFAULT FCB CALL MOVE CALL PRINT$MESSAGE DB CR,LF,'++ Reloading TERM II ++',CR,LF,0 JMP TERM$LOADER * * * TERMINAL EXIT ROUTINE -- * THIS ROUTINE GIVES THE OPERATOR CONTROL OF TERM. HE MAY ENTER IT * FROM TERMINAL OR CONVERSATION MODES BY CTRL-E OR HE MAY BE PLACED HERE * BY A NUMBER OF THE INTERNAL ROUTINES (I.E., SEND FILE) WITHIN TERM * TEXITXX: LXI SP,STACK ; RESET STACK CALL XLATE$OFF ; TURN OFF TRANSLATION * ** IMMEDIATE INPUT SECTION ** * THIS SECTION DELAYS DISPLAY OF OPTIONS TO GIVE USER TIME TO ENTER * OPTION BEFORE THE DISPLAY; IF HE TYPES A , THE OPTION DISPLAY * IS INVOKED IMMEDIATELY * LXI D,CPAUS ; PROCESS IMMEDIATE INPUT TEXIT$IMMED: CALL ST$CON ; CHECK STATUS JZ TEXIT1$IMMED ; CONTINUE LOOP IF NO CHAR YET CALL IN$CON ; GET CHAR CALL CAPS ; CAPITALIZE JMP TEXIT$ENTRY ; PROCESS OPTION TEXIT1$IMMED: DCX D ; COUNT DOWN MOV A,D ORA E ; DONE? JNZ TEXIT$IMMED ; CONTINUE LOOPING IF NOT DONE ** TERMINAL EXIT OPTION DISPLAY AND PROMPT ** * INITIAL COMMAND ENTRY POINT TEXIT: LXI SP,STACK CALL XLATE$OFF ; TURN OFF TRANSLATION CALL SCREEN$CLEAR CALL PRINT$ID CALL SCREEN$MESSAGE DB 4,5,'++ TERM II Exit Mode -- Buffer Load Subsystem (BLS) ' DB 'Command Level ++',0 CALL PRINT$CINDEX ; PRINT HEADER CALL PRINT$MESSAGE DB CR,LF DB '^B Transmit Break B Toggle Buffer Load D Perform ' DB 'Buffer Dump',CR,LF DB ' E Toggle Echo H Hang Up Telephone Q Quit to ' DB 'TERM II',CR,LF DB ' T Terminal Mode X Exit to CP/M Y Display ' DB 'Status',CR,LF DB 0 CALL SCREEN$MESSAGE DB 18,15 DB 'TERM II BLS Command -- ',0 CALL GET$RESPONSE ; GET ANS AND CAPITALIZE ** ENTRY POINT FOR TEXIT WITH COMMAND IN REG A USING TEXIT COMMANDS ** TEXIT$ENTRY: LXI SP,STACK LXI H,CTAB ; PT TO FULL COMMAND TABLE CPI ' ' ; IS VALID -- REPRINT DISPLAY JZ TEXIT CPI CR ; CR IS VALID -- REPRINT DISPLAY JZ TEXIT CALL TEXIT0 ; PROCESS COMMANDS CALL IC$MSG ; INVALID COMMAND JMP TEXIT ; GO BACK IF ERROR IN COMMAND * * PRINT COMMAND INDEX HEADER * PRINT$CINDEX: CALL PRINT$MESSAGE DB CR,LF,LF DB ' -- Command Index --',CR,LF DB 'Cmd Function Cmd Function Cmd Function' DB CR,LF DB '--- -------- --- -------- --- --------' DB 0 RET ** INVALID COMMAND MESSAGE ** IC$MSG: CALL SCREEN$MESSAGE DB 20,12,BEL,'-- Invalid Command --',0 CALL PAUSE RET ** ENTRY POINT FOR COMMAND PROCESSING WITH COMMAND IN REG A AND HL=TABLE ** TEXIT0: MOV B,A ; USER COMMAND IN B TEXIT1: MOV A,M ; GET TABLE COMMAND ORA A ; DONE IF ZERO RZ ; RETURN TO CALLER CMP B ; COMPARE AGAINST COMMAND JZ TEXIT2 INX H ; SKIP ADDRESS INX H INX H JMP TEXIT1 * EXECUTE COMMAND TEXIT2: POP D ; CLEAR RETURN ADDRESS FROM STACK INX H ; PT TO ADDRESS MOV E,M ; GET LOW INX H MOV D,M ; GET HIGH XCHG ; ADDRESS IN HL PCHL ; TRANSFER TO PROGRAM * * * SUPPORT ROUTINES * * **** PRINT, SCREEN DISPLAY, AND INPUT/OUTPUT UTILITIES **** * * * CAPITALIZE CHAR IN REG A * CAPS: CPI 61H ; SMALL A? RC CPI 7BH ; SMALL Z + 1? RNC SUI ' ' ; CAPITALIZE RET * * BRIEF DELAY * PAUSE: PUSH B MVI B,20 ; 2 SEC PAUSE PAUSE1: CALL ST$CON ; ABORT PAUSE? JNZ PAUSE2 CALL TI$TIME$X ; DELAY FOR 0.1 SEC DCR B ; COUNT DOWN JNZ PAUSE1 POP B RET PAUSE2: POP B ; CLEAR STACK CALL IN$CON ; GET CHAR RET * 0.1 SEC DELAY TI$TIME$X: PUSH H PUSH B LDA PROCESSOR$SPEED ; GET SPEED OF PROCESSOR MOV B,A ; ... IN B TI$TIME$X0: LXI H,TENTH$SEC$DELAY TI$TIME$X1: DCX H ; COUNT DOWN MOV A,H ORA L JNZ TI$TIME$X1 DCR B ; COUNT DOWN FOR PROCESSOR JNZ TI$TIME$X0 POP B POP H RET * * CLEAR CRT SCREEN IF ROUTINE AVAILABLE * SCREEN$CLEAR: CALL STAT$CRT ; CHECK CRT STATUS RZ JMP CRT$CLR ; CLEAR IT * * PRINT AND POSITION MESSAGE ENDING IN 0 PTED TO BY RET ADR; FIRST 2 BYTES * ARE ROW AND COL OF WHERE MESSAGE IS TO BE PLACED * SCREEN$MESSAGE: XTHL ; HL PTS TO MESSAGE MOV D,M ; GET ROW VALUE INX H MOV E,M ; GET COL VALUE INX H ; PT TO MSG CALL STAT$CRT ; CURSOR ADDRESSING AVAILABLE? JZ SCREEN$MSG0 XCHG ; HL CONTAINS LOC, DE PTS TO MSG CALL GOTOXY ; POSITION ON SCREEN XCHG ; HL PTS TO MSG JMP SCREEN$MSG1 SCREEN$MSG0: CALL CRLF ; NEW LINE INSTEAD OF CURSOR POSITIONING SCREEN$MSG1: XTHL ; RESTORE STACK VALUE AND HL JMP PRINT$MESSAGE ; PROCESS TEXT OF MESSAGE * PRINT NAME OF PROGRAM AND VERSION NUMBER PRINT$ID: CALL PRINT$MESSAGE DB 'TERM II Terminal Program, Version ' DB VERS/10+'0','.',(VERS MOD 10)+'0' DB CR,LF,' ++ Buffer Load Subsystem ++' DB CR,LF,0 RET * PRINT MESSAGE ENDING IN 0 PTED TO BY RET ADR PRINT$MESSAGE: XTHL ; GET ADDRESS OF STRING IN HL PUSH B MVI C,1 ; SET TAB COUNTER PR$MESS$LOOP: MOV A,M ; GET BYTE INX H ; PT TO NEXT ORA A ; END OF STRING? JZ PR$MESS$DONE CPI CR ; RESET CHAR COUNT? JZ PR$MESS$CR CPI LF ; JUST MOVE DOWN ONE LINE JZ PR$MESS$LF CPI TAB ; TAB? JZ PR$MESS$TAB INR C ; INCREMENT TAB COUNTER CALL OUT$CON ; PRINT CHAR JMP PR$MESS$LOOP PR$MESS$DONE: POP B XTHL ; RET ADR ON STACK RET PR$MESS$CR: MVI C,1 ; RESET TAB COUNT PR$MESS$LF: CALL OUT$CON ; OUTPUT CHAR JMP PR$MESS$LOOP PR$MESS$TAB: MVI A,' ' ; PRINT CALL OUT$CON INR C ; INCREMENT COUNT MOV A,C ; DONE? ANI 7 JNZ PR$MESS$TAB JMP PR$MESS$LOOP * PRINT EXIT CHAR AS SPECIAL CHAR PRINT$EXIT$CHAR: LDA EXIT$CHAR ; GET CHAR * PRINT CONTROL CHAR (FALL THRU TO FROM PRINT$EXIT$CHAR) PRINT$CONTROL$CHAR: ANI 7FH ; MASK MSB ORA A ; JZ PCC$NULL CPI CR ; JZ PCC$CR CPI LF ; JZ PCC$LF CPI BS ; JZ PCC$BS CPI TAB ; JZ PCC$TAB CPI ESC ; JZ PCC$ESC CPI DL-1 ; TILDE JZ PCC$TIL CPI DL ; JZ PCC$DEL CPI ' ' ; CHECK FOR < JC PCC CALL OUT$CON ; PRINT CHAR RET PCC: PUSH PSW ; SAVE CHAR MVI A,'^' ; PRINT ^ CALL OUT$CON POP PSW ; GET CHAR ADI '@' ; CONVERT TO CHAR CALL OUT$CON RET PCC$NULL: CALL PRINT$MESSAGE DB '',0 RET PCC$CR: CALL PRINT$MESSAGE DB '',0 RET PCC$LF: CALL PRINT$MESSAGE DB '',0 RET PCC$BS: CALL PRINT$MESSAGE DB '',0 RET PCC$TAB: CALL PRINT$MESSAGE DB '',0 RET PCC$ESC: CALL PRINT$MESSAGE DB '',0 RET PCC$TIL: CALL PRINT$MESSAGE DB '',0 RET PCC$DEL: CALL PRINT$MESSAGE DB '',0 RET * MOVE (HL) TO (DE) FOR B BYTES MOVE: MOV A,M ; GET BYTE STAX D ; PUT BYTE INX H ; PT TO NEXT INX D DCR B ; COUNT DOWN JNZ MOVE RET * CRLF ROUTINE CRLF: MVI A,CR CALL OUT$CON MVI A,LF * ** POLLING INPUT/OUTPUT ROUTINES ** * * SEND CHAR TO CON: OUT$CON: PUSH H ! PUSH D ! PUSH B PUSH PSW ; SAVE CHAR MOV C,A ; CHAR IN C LXI H,RET0 ; SET UP RET ADR PUSH H LHLD OUTADR ; ADR OF OUTPUT ROUTINE PCHL RET0: POP PSW ; RESTORE CHAR RET1: POP B ! POP D ! POP H ORA A ; SET FLAGS RET * INPUT CHAR FROM CON: IN$CON1: PUSH H ! PUSH D ! PUSH B LXI H,RET2 ; SET UP RET ADR PUSH H LHLD INADR ; ADR OF INPUT ROUTINE PCHL RET2: ANI 7FH ; MASK JMP RET1 IN$CON: CALL IN$CON1 ; GET CHAR CALL EXIT$CHECK ; DON'T TRANSLATE EXIT CHAR RZ CALL BREAK$CHECK ; DON'T TRANSLATE BREAK CHAR RZ CALL XLATE$OUT ; TRANSLATE CONSOLE OUTPUT RET * GET CON: INPUT STATUS ST$CON: PUSH H ! PUSH D ! PUSH B LXI H,RET1 ; SET UP RET ADR PUSH H LHLD STADR ; ADR OF STATUS ROUTINE PCHL * GET CHAR FROM CON: AND ECHO IF NECESSARY CON$CHAR: PUSH B ! PUSH D ! PUSH H CALL IN$CON ; GET CHAR FROM CONSOLE MOV C,A ; SAVE CHAR CALL EXIT$CHECK JZ CON$C1 CALL BREAK$CHECK JZ CON$C1 LDA ECHOFL ; ECHO ENABLED? ORA A ; ZERO MEANS NO JZ CON$C1 PUSH B ; SAVE CHAR MOV A,C ; GET CHAR CALL XLATE$IN ; PERFORM OUTPUT TRANSLATION CALL OUT$CON ; PRINT CHAR CALL BFLOAD ; LOAD BUFFER IF FLAG SET POP B ; RESTORE CHAR CON$C1: MOV A,C ; GET CHAR POP H ! POP D ! POP B RET * FLUSH CHARACTER FROM INPUT BUFFER (IF CHAR PRESENT) C1$FLUSH: CALL ST$CON ; CHAR PRESENT? RZ CALL IN$CON1 ; GET IT IF THERE RET * CHECK FOR EXIT CHAR AND SET ZERO FLAG IF SO EXIT$CHECK: PUSH PSW ! PUSH B ANI 7FH ; MASK OUT MSB MOV B,A LDA EXIT$CHAR ; GET EXIT CHAR CMP B ; COMPARE AGAINST MASKED CHAR IN A JZ EXIT$CHECK$MATCH POP B ! POP PSW ORA A ; SET FLAG TO NON-ZERO RET EXIT$CHECK$MATCH: POP B ! POP PSW ; IT IS THE EXIT CHAR XRA A ; SET ZERO FLAG LDA EXIT$CHAR ; GET EXIT CHAR RET * CHECK FOR BREAK CHAR AND SET ZERO FLAG IF SO BREAK$CHECK: PUSH PSW ! PUSH B ANI 7FH ; MASK MSB MOV B,A LDA BREAK$CHAR ; GET BREAK CHAR ORA A ; NOT DEFINED JZ BREAK$CHECK$FAIL CMP B ; COMPARE JZ BREAK$CHECK$MATCH BREAK$CHECK$FAIL: POP B ! POP PSW ORA A ; SET FLAG TO NON-ZERO RET BREAK$CHECK$MATCH: POP B ! POP PSW XRA A ; SET ZERO FLAG LDA BREAK$CHAR RET * SEND CHAR TO MODEM OUT$MOD: PUSH PSW ; SAVE CHAR LDA M2$ON ; GET MODEM NUMBER (0=1,0FFH=2) ORA A ; SET FLAGS JZ OUT1$MOD POP PSW ; SEND TO MODEM 2 JMP OUT$MOD2 OUT1$MOD: POP PSW ; SEND TO MODEM 1 JMP OUT$MOD1 * GET CHAR FROM MODEM WITH MASKING AND TRANSLATION IN$MOD: CALL IN$MODX ; GET INPUT WITHOUT TRANSLATION CALL MASK$IN ; MASK INPUT MSB CALL XLATE$IN ; TRANSLATE INPUT RET * GET CHAR FROM MODEM IN$MODX: LDA M2$ON ; GET MODEM NUMBER (0=1,0FFH=2) ORA A ; SET FLAGS JZ IN$MODX1 CALL IN$MOD2 ; GET INPUT FROM MODEM 2 RET IN$MODX1: CALL IN$MOD1 ; GET INPUT FROM MODEM 1 RET * GET MODEM INPUT STATUS ST$MOD: LDA M2$ON ; GET MODEM NUMBER (0=1,0FFH=2) ORA A ; SET FLAGS JZ ST$MOD1 JMP ST$MOD2 * ABORT -- CHECK FOR EXIT$CHAR AND ABORT IF TYPED ABORT: CALL ST$CON ; CHAR TYPED? RZ ; ZERO=NO CHAR CALL IN$CON ; GET CHAR CALL EXIT$CHECK ; CHECK EXIT CHAR JZ TEXIT ; TEXIT WITHOUT DELAY RET * DETERMINE IF INPUT IS TO BE MASKED AND DO SO IF SET MASK$IN: PUSH B ; SAVE BC MOV B,A ; BYTE IN B LDA MASK$IN$FLAG ; GET FLAG ORA A ; 0=NO JZ MASK$IN$NO MOV A,B ; GET BYTE ANI 7FH ; MASK MSB POP B ; RESTORE BC RET MASK$IN$NO: MOV A,B ; GET BYTE POP B ; RESTORE BC RET * DETERMINE IF OUTPUT IS TO BE MASKED AND DO SO IF SET MASK$OUT: PUSH B ; SAVE BC MOV B,A ; BYTE IN B LDA MASK$OUT$FLAG ; GET FLAG ORA A ; 0=NO JZ MASK$OUT$NO LDA OUTPUT$MASK ; GET MASK FOR MSB ANA B ; AND WITH CHAR POP B ; RESTORE BC RET MASK$OUT$NO: MOV A,B ; GET BYTE POP B ; RESTORE BC RET * DETERMINE IF INPUT IS TO BE TRANSLATED AND DO SO IF SET XLATE$IN: PUSH H ! PUSH B MOV C,A ; SAVE BYTE LDA XLATE$IN$ACTIVE ; GET FLAG ORA A ; 0=NO JZ NO$XLATE LXI H,XLATE$IN$TABLE PERFORM$XLATE: MVI B,0 ; SET HIGH-ORDER TO 0 FOR INDEX DAD B ; OFFSET INTO TABLE BY CHAR VALUE MOV A,M ; GET TRANSLATE BYTE POP B ! POP H RET NO$XLATE: MOV A,C ; GET BYTE POP B ! POP H RET * DETERMINE IF OUTPUT IS TO BE TRANSLATED AND DO SO IF SET XLATE$OUT: PUSH H ! PUSH B MOV C,A ; SAVE BYTE LDA XLATE$OUT$ACTIVE ; GET FLAG ORA A ; 0=NO JZ NO$XLATE LXI H,XLATE$OUT$TABLE JMP PERFORM$XLATE * ACTIVATE TRANSLATOR XLATE$ON: LDA XLATE$IN$FLAG ; GET USER'S SELECTION STA XLATE$IN$ACTIVE ; SET IT LDA XLATE$OUT$FLAG ; SAME STA XLATE$OUT$ACTIVE RET * DEACTIVATE TRANSLATOR XLATE$OFF: XRA A ; TURN OFF ACTIVE FLAGS STA XLATE$IN$ACTIVE STA XLATE$OUT$ACTIVE RET * CONVERT A TO HEX AND PRINT HEX$OUT: PUSH PSW ; SAVE RLC ; EXCHANGE NYBBLES RLC RLC RLC CALL NYBBLE$OUT ; PRINT HIGH NYBBLE POP PSW ; GET VALUE AND PRINT LOW NYBBLE CALL NYBBLE$OUT MVI A,' ' ; PRINT TRAILING JMP OUT$CON * PRINT LOW-ORDER NYBBLE OF A AS HEX DIGIT NYBBLE$OUT: ANI 0FH ; MASK FOR LOW NYBBLE CPI 10 ; CHAR/DIGIT BOUNDARY JC DEC$OUT ADI 'A'-10 ; CONVERT CHAR TO ASCII JMP OUT$CON ; PRINT IT DEC$OUT: ADI '0' ; CONVERT DIGIT TO ASCII JMP OUT$CON * CONVERT A TO ASCII DECIMAL CHARS AND OUTPUT DECIMAL$OUT: PUSH B PUSH PSW ; SAVE A XRA A ; TURN ON LEADING SPACE FLAG STA LDSP POP PSW ; GET A MVI B,100 ; PRINT 100'S CALL DECIMAL$DIGIT MVI B,10 ; PRINT 10'S CALL DECIMAL$DIGIT CALL DEC$OUT ; PRINT 1'S POP B RET DECIMAL$DIGIT: MVI C,0 ; SET DIGIT DDIG$LOOP: SUB B ; A=A-B JC DDIG$DONE INR C ; ADD 1 TO COUNT JMP DDIG$LOOP DDIG$DONE: ADD B ; A=A+B FOR ADJUSTMENT PUSH PSW ; SAVE A MOV A,C ; GET DIGIT ORA A ; ZERO? JNZ DDIG$NUM LDA LDSP ; LEADING ? ORA A ; 0=YES MOV A,C ; PREP FOR PRINT JNZ DDIG$NUM MVI A,' ' ; PRINT LEADING CALL OUT$CON POP PSW ; GET REST OF NUMBER RET DDIG$NUM: CALL DEC$OUT ; PRINT DIGIT MVI A,0FFH ; TURN OFF FLAG STA LDSP POP PSW RET * * GET RESPONSE FROM CONSOLE, CAPITALIZE, ECHO, SEND * GET$RESPONSE: CALL IN$CON1 ; GET CHAR CALL CAPS ; CAPITALIZE CALL OUT$CON ; ECHO PUSH PSW ; SAVE CHAR CALL CRLF POP PSW ; GET CHAR RET * **** SUPPORT SECTION -- STATUS MESSAGE DISPLAYS **** * * * PRINT STATUS REPORT ON FACILITIES ENABLED IN SUPPORT PACKAGE * DISPLAY$STATUS: CALL PRINT$STATUS JMP TEXIT PRINT$STATUS: CALL SCREEN$CLEAR CALL PRINT$ID CALL PRINT$MESSAGE DB CR,LF,'++ TERM II Status Display ++',CR,LF,0 CALL EXITCHMS ; EXIT CHAR CALL BREAKMS ; BREAK CHAR CALL PRINT$MESSAGE DB CR,LF,'** Support Package Functions **' DB CR,LF,' CRT Clear Screen and Cursor Addressing: ',0 CALL STAT$CRT ; GET CRT STATUS CZ PS$OFF ; PRINT OFF IF ZERO CNZ PS$ON ; PRINT ON IF NOT ZERO CALL PRINT$MESSAGE DB CR,LF,' Printer: ',0 CALL STAT$TTY ; GET PRINTER STATUS CZ PS$OFF CNZ PS$ON CALL PRINT$MESSAGE DB CR,LF,' Modem 1: ',0 CALL STAT$M1 ; GET MODEM 1 STATUS CZ PS$OFF CNZ PS$ON CALL PRINT$MESSAGE DB CR,LF,' Modem 2: ',0 CALL STAT$M2 ; GET MODEM 2 STATUS CZ PS$OFF CNZ PS$ON CALL PRINT$MESSAGE DB CR,LF,' Telephone System Interface: ',0 CALL STAT$TI ; GET TELEPHONE INTERFACE STATUS CZ PS$OFF CNZ PS$ON CALL STAT$TI JZ PR$ST$1 ; SKIP CARRIER CHECK IF NO INTERFACE CALL PRINT$MESSAGE DB CR,LF,' Telephone System Carrier Status: ',0 CALL TI$CST ; CHECK CARRIER STATUS CZ PS$OFF CNZ PS$ON PR$ST$1: CALL PRINT$MESSAGE DB CR,LF,LF,'** TERM II File Specification **',0 LDA FCB+1 ; CHECK FOR FILE NAME CPI ' '+1 ; OR LESS IF NONE JC PR$ST$2 CALL PRINT$FN ; PRINT FILE NAME JMP PR$ST$3 PR$ST$2: CALL PRINT$MESSAGE DB CR,LF,' File Name Not Specified',CR,LF,0 PR$ST$3: CALL PRINT$MESSAGE DB CR,LF,'** TERM II Buffer Status **',CR,LF DB ' Overlay is NOT Loaded',CR,LF DB ' Starting Page of Memory Buffer: ',0 LHLD BUFFER ; GET STARTING ADDRESS MOV A,H ; GET PAGE NUMBER CALL HEX$OUT CALL PRINT$MESSAGE DB ' Hexadecimal',CR,LF DB ' Ending Page of Memory Buffer: ',0 LHLD BUFEND MOV A,H DCR A CALL HEX$OUT CALL PRINT$MESSAGE DB ' Hexadecimal',CR,LF DB ' Space Left in Memory Buffer: ',0 LHLD BUF$NEXT ; GET CURRENT XCHG LHLD BUFEND ; GET END MOV A,H ; SUBTRACT CURRENT FROM END SUB D CALL DECIMAL$OUT ; PRINT IN DECIMAL CALL PRINT$MESSAGE DB ' Pages',CR,LF,0 CALL PRINT$MESSAGE DB 'End of Page 1 -- Type ^C to Abort/Any Other Char to ' DB 'Continue - ',0 CALL GET$RESPONSE CPI CTRLC ; ABORT? RZ PR$FLAGS: CALL SCREEN$CLEAR CALL PRINT$ID CALL PRINT$MESSAGE DB '++ Flag Settings ++',CR,LF,LF,0 CALL PR$INIT$CMND ; INITIAL EXIT COMMAND SETTING CALL PR$TERM$ENTRY ; TERMINAL MODE ENTRY STATUS CALL PRSPDMS ; PROCESSOR SPEED CALL CRLF CALL ECHOMS ; ECHO CALL PRMS ; PRINTER CALL BUFMS ; BUFFER LOAD CALL MODMS ; MODEM CALL CRLF CALL EXITCHMS ; EXIT CHAR CALL BREAKMS ; BREAK CHAR CALL CRLF CALL XLATEMS ; TRANSLATION CALL MASKMS ; MASKS CALL PRINT$MESSAGE DB CR,LF,'**** End of TERM II Status Display ****',CR,LF DB '- Type Any Char to Continue - ',0 CALL GET$RESPONSE RET ** LOAD FILE NAME INTO FCB ** LOAD$FCB: CALL PRINT$MESSAGE DB CR,LF,'File Name (D:FILENAME.TYP)? ',0 CALL C1$FLUSH LXI D,FN$BUFFER ; FILE NAME BUFFER MVI C,10 ; READ FROM CONSOLE W/EDITING CALL BDOS CALL CRLF LXI H,FN$BUFFER+1 ; LOAD FCB NOW XRA A ; SET DEFAULT DRIVE STA FCB * CLEAR FCB LXI D,FCB+1 ; PT TO FN ENTRY MVI C,11 ; CLEAR 11 BYTES PUSH D MVI A,' ' ; STORE LFCB0: STAX D ; PUT CHAR INX D ; PT TO NEXT DCR C ; DECR COUNT JNZ LFCB0 CALL ZERO$FCB ; ZERO OUT FIELDS OF FCB * LOAD FCB WITH FILE NAME POP D ; GET PTR TO FN ENTRY IN FCB MOV A,M ; GET CHAR COUNT ORA A ; 0=CLEAR FCB RZ MOV C,M ; GET CHAR COUNT INX H ; CHECK FOR DRIVE SPEC INX H MOV A,M ; IS IT COLON? DCX H ; PT BACK TO CHAR COUNT DCX H CPI ':' ; COLON MEANS WE HAVE A DRIVE SPEC JNZ LFCB1 DCR C ; ADJUST CHAR COUNT DCR C RZ ; ABORT IF JUST DRIVE SPEC INX H ; GET DRIVE LETTER MOV A,M CALL CAPS ; CAPITALIZE INX H ; SKIP OVER COLON SUI 'A'-1 ; INVALID SPEC? JC BADDSPEC JZ BADDSPEC CPI 6 ; A-D JNC BADDSPEC STA FCB ; SET DRIVE SPEC LFCB1: INX H ; PT TO NEXT CHAR MOV A,M ; GET CHAR CPI '.' ; EXT? JZ LFCB2 CPI ' '+1 ; SKIP CHAR IF <= JC LFCB1S CALL CAPS ; CAPITALIZE STAX D ; STORE CHAR INX D ; PT TO NEXT LFCB1S: DCR C ; DECR COUNT RZ JMP LFCB1 * LOAD FCB WITH FILE TYPE LFCB2: INX H ; PT TO TYP DCR C ; DECR COUNT FOR '.' RZ LXI D,FCB+9 ; PT TO EXT IN FCB LFCB3: MOV A,M ; GET CHAR CPI ' '+1 ; SKIP CHAR IF <= JC LFCB3S CALL CAPS ; CAPITALIZE STAX D ; PUT IT INX D ; PT TO NEXT LFCB3S: INX H DCR C ; COUNT DOWN JNZ LFCB3 RET BADDSPEC: CALL PRINT$MESSAGE DB 'ERROR - Invalid Drive Specification',CR,LF,0 JMP LOAD$FCB * CLEAR FCB DATA INIT$FCB: LDA FCB+1 ; CHECK FOR PRESENCE OF FILE NAME CPI ' '+1 JC INIT$FCB$ERR FCB0: PUSH H ! PUSH D ! PUSH B CALL ZERO$FCB ; ZERO OUT FIELDS OF FCB CALL PRINT$FN ; PRINT FILE NAME CALL PRINT$MESSAGE DB ' Verify File Name (Y/N/=N)? ',0 CALL GET$RESPONSE CPI 'Y' JNZ INIT$FCB$OPT POP B ! POP D ! POP H RET INIT$FCB$OPT: CALL PRINT$MESSAGE DB ' Specify Different File (Y/N/=Y)? ',0 CALL GET$RESPONSE CPI 'N' ; ABORT TO TEXIT JZ TEXIT JMP INIT$FCB$ERR1 INIT$FCB$ERR: PUSH H ! PUSH D ! PUSH B CALL PRINT$MESSAGE DB CR,LF,'File Name Not Specified',0 INIT$FCB$ERR1: CALL LOAD$FCB ; GET FILE NAME POP B ! POP D ! POP H JMP FCB0 * ZERO OUT ALL BUT DISK NUMBER, FILE NAME, AND FILE TYPE FIELDS OF FCB ZERO$FCB: PUSH H PUSH B LXI H,FCB+12 ; START AT 12TH POSITION MVI B,24 ; 24 BYTES (INCL RANDOM I/O BYTES) ZERO$FCB$LOOP: MVI M,0 ; STORE ZERO INX H DCR B JNZ ZERO$FCB$LOOP POP B POP H RET * ERASE DESITINATION FILE IF IT EXISTS ERASE$OLD$FILE: CALL ZERO$FCB * SEE IF FILE EXISTS LXI D,FCB MVI C,17 ;SEE IF IT EXISTS CALL BDOS INR A ;FOUND? RZ ;NO, RETURN * FILE EXISTS -- ASK USER IF HE REALLY WANTS TO DELETE IT CALL PRINT$MESSAGE DB 'File Exists -- Type Y to Erase (Y/N/=N)? ',0 CALL GET$RESPONSE CPI 'Y' JNZ TEXIT ; EXIT OPTIONS IF NOT ERASE * ERASE OLD FILE LXI D,FCB MVI C,19 CALL BDOS RET * CREATE THE DESTINATION FILE ON DISK MAKE$NEW$FILE: CALL ZERO$FCB LDA FCB ; DETERMINE DEFAULT DRIVE ORA A ; 0=DO IT JNZ MF1 MVI C,25 ; DETERMINE DEFAULT DRIVE NUMBER CALL BDOS INR A ; ADJUST TO 1-16 STA FCB ; SET FCB TO IT MF1: LDA FCB ; LOG IN DISK DCR A ; ADJUST TO 0-15 MOV E,A MVI C,14 ; LOG IN DISK CALL BDOS XRA A ; ZERO OUT USER NUMBER STA FCB LXI D,FCB MVI C,22 CALL BDOS INR A ;FF=BAD RNZ ;OPEN OK * DIRECTORY FULL - CAN'T MAKE FILE CALL PRINT$MESSAGE DB CR,LF,'ERROR - Can''t Create File -- ' DB 'Directory must be full',0 CALL PAUSE JMP TEXIT * PRINT FN AND EXT IN FCB ON CON: PRINT$FN: CALL PRINT$MESSAGE DB CR,LF,'File Name: ',0 CALL PR$FN$DISK ; DISK NAME LXI H,FCB+1 ; PT TO FN MVI C,8 ; 8 CHARS CALL PR$FN$LOOP MVI A,'.' ; SEPARATOR CALL OUT$CON MVI C,3 ; 3 CHARS IN EXT CALL PR$FN$LOOP CALL CRLF RET PR$FN$LOOP: MOV A,M ; GET CHAR INX H ; PT TO NEXT CALL OUT$CON DCR C JNZ PR$FN$LOOP RET PR$FN$DISK: LDA FCB ; GET SELECTED DISK ORA A ; DEFAULT? JNZ PR$FN$DISK1 PUSH H PUSH D PUSH B MVI C,25 ; RETURN CURRENT DISK CALL BDOS POP B POP D POP H INR A ; A=A+1 FOR FOLLOWING PRINT PR$FN$DISK1: ADI 'A'-1 ; PRINT LETTER CALL OUT$CON MVI A,':' CALL OUT$CON RET * CRT STATUS STAT$CRT: CALL SP$STAT ; GET SUPPORT PACKAGE STATUS ANI 1 ; 0=NOT SUPPORTED RET * TTY STATUS STAT$TTY: CALL SP$STAT ; GET SUPPORT PACKAGE STATUS ANI 10B ; 0=NOT SUPPORTED RET * MODEM 1 STATUS STAT$M1: CALL SP$STAT ; GET SUPPORT PACKAGE STATUS ANI 100B ; 0=NOT SUPPORTED RET * MODEM 2 STATUS STAT$M2: CALL SP$STAT ; GET SUPPORT PACKAGE STATUS ANI 1000B ; 0=NOT SUPPORTED RET * TELEPHONE INTERFACE STATUS STAT$TI: CALL SP$STAT ; GET SUPPORT PACKAGE STATUS ANI 1000$0000B ; 0=NOT SUPPORTED RET * STATUS ROUTINE (HL NOT CHANGED) SP$STAT: PUSH H ; SAVE HL CALL SP1$STAT POP H RET * SUPPORT ROUTINES TO PRINT 'ON' AND 'OFF' PS$OFF: PUSH PSW ; SAVE FLAGS CALL PRINT$MESSAGE DB 'OFF',0 POP PSW RET PS$ON: PUSH PSW ; SAVE FLAGS CALL PRINT$MESSAGE DB 'ON',0 POP PSW RET * * CHECK ECHO FLAG AND DISPLAY ECHO MESSAGE * ECHOMS: LDA ECHOFL ; GET ECHO FLAG ORA A ; ZERO MEANS NO JZ ECHONO CALL PRINT$MESSAGE DB '-- Echo ON --',CR,LF,0 RET ECHONO: CALL PRINT$MESSAGE DB '-- Echo OFF --',CR,LF,0 RET * * CHECK PRINTER FLAG AND DISPLAY MESSAGE * PRMS: LDA PRFL ; CHECK FLAG ORA A JZ PRNO CALL PRINT$MESSAGE DB '-- Printer ON --',CR,LF,0 RET PRNO: CALL PRINT$MESSAGE DB '-- Printer OFF --',CR,LF,0 RET * * CHECK BUFFER LOAD FLAG AND DISPLAY MESSAGE * BUFMS: LDA BUFLG ; CHECK FLAG ORA A JZ BUFNO CALL PRINT$MESSAGE DB '-- Buffer Load ON --',CR,LF,0 RET BUFNO: CALL PRINT$MESSAGE DB '-- Buffer Load OFF --',CR,LF,0 RET * * CHECK MODEM FLAG AND DISPLAY MESSAGE * MODMS: LDA M2$ON ; CHECK FLAG ORA A JZ MODNO CALL PRINT$MESSAGE DB '-- Modem 2 ON --',CR,LF,0 RET MODNO: CALL PRINT$MESSAGE DB '-- Modem 1 ON --',CR,LF,0 RET * * CHECK TRANSLATION TABLE FLAGS AND DISPLAY MESSAGE * XLATEMS: LDA XLATE$IN$FLAG ; INPUT TRANSLATION ORA A ; 0=NO JZ XLATEINO CALL PRINT$MESSAGE DB '-- Input Translation ON, ',0 JMP XLATEO XLATEINO: CALL PRINT$MESSAGE DB '-- Input Translation OFF, ',0 XLATEO: LDA XLATE$OUT$FLAG ; OUTPUT TRANSLATION ORA A ; 0=NO JZ XLATEONO CALL PRINT$MESSAGE DB 'Output Translation ON --',CR,LF,0 RET XLATEONO: CALL PRINT$MESSAGE DB 'Output Translation OFF --',CR,LF,0 RET * * DISPLAY PROCESSOR SPEED * PRSPDMS: CALL PRINT$MESSAGE DB ' Processor Speed is ',0 LDA PROCESSOR$SPEED ADI '0' ; CONVERT TO ASCII CALL PRINT$CONTROL$CHAR CALL PRINT$MESSAGE DB 'MHz',CR,LF,0 RET * * DISPLAY EXIT CHARACTER * EXITCHMS: CALL PRINT$MESSAGE DB 'Exit Character is ',0 CALL PRINT$EXIT$CHAR CALL CRLF RET * * DISPLAY BREAK CHARACTER * BREAKMS: CALL PRINT$MESSAGE DB 'Break Character is ',0 LDA BREAK$CHAR ; GET CHAR ORA A ; 0=NOT DEFINED JZ BREAKMS$NO CALL PRINT$CONTROL$CHAR CALL CRLF RET BREAKMS$NO: CALL PRINT$MESSAGE DB 'Not Defined',CR,LF,0 RET * * DISPLAY MASKING INFORMATION * MASKMS: CALL PRINT$MESSAGE DB 'Modem Character Input Masking is ',0 LDA MASK$IN$FLAG ; GET FLAG ORA A ; 0=OFF CZ PS$OFF CNZ PS$ON CALL CRLF CALL PRINT$MESSAGE DB 'TERM II Character Output Masking is ',0 LDA MASK$OUT$FLAG ; GET FLAG ORA A ; 0=OFF CZ PS$OFF CNZ PS$ON CALL CRLF LDA MASK$OUT$FLAG ; PRINT MSB MASK SETTING IF ON ORA A ; 0=OFF RZ CALL PRINT$MESSAGE DB ' Most-Significant-Bit (MSB) Output is ',0 LDA OUTPUT$MASK ; GET MASK (BIT 7 SIG) ANI 80H ; GET BIT 7 CZ PS$OFF CNZ PS$ON CALL CRLF RET * * PRINT TERM ENTRY POINT * PR$TERM$ENTRY: CALL PRINT$MESSAGE DB ' Terminal Mode Entry is ',0 LDA TERM$ENTRY ; GET FLAG ORA A ; 0=NO DIR JZ PRTE1 CALL PRINT$MESSAGE DB 'with',0 JMP PRTE2 PRTE1: CALL PRINT$MESSAGE DB 'without',0 PRTE2: CALL PRINT$MESSAGE DB ' Telephone Directory Display',CR,LF,0 RET * * PRINT INITIAL MASTER COMMAND LEVEL MESSAGE * PR$INIT$CMND: CALL PRINT$MESSAGE DB ' Initial Exit Mode is ',0 LDA INIT$CMND ; GET FLAG ORA A ; 0=FULL, 0FFH=ABBREVIATED JZ PRIC$MAST1 CALL PRINT$MESSAGE DB 'Abbreviated',CR,LF,0 JMP PRIC$CONT PRIC$MAST1: CALL PRINT$MESSAGE DB 'Master',CR,LF,0 PRIC$CONT: RET * * * COMMAND TABLE * CTAB: DB 'E'-'@' ; ^E=EXIT CHAR DW TRANSMIT$EXITCH DB 'B'-'@' ; ^B=TRANSMIT BREAK DW TRANSMIT$BREAK DB 'B' ; TOGGLE BUFFER LOAD DW BUF$TOGGLE DB 'D' ; PERFORM BUFFER DUMP DW DUMP$BUFFER DB 'E' ; TOGGLE ECHO DW ECHO$TOGGLE DB 'H' ; HANG UP TELEPHONE DW PH$HANG DB 'Q' ; RETURN TO TERM II DW TERM4 DB 'T' ; TERMINAL MODE DW OPTD DB 'X' ; RETURN TO CP/M DW WBOOT DB 'Y' ; STATUS DW DISPLAY$STATUS DB 0 ; END OF TABLE * * * BUFFERS * TERMFCB: DB 0,'TERM COM',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 DB 0,0,0,0,0,0 BUFLEN EQU 40 ; BUFFER LENGTH OF FILE NAME BUFFER FN$BUFFER: DB BUFLEN ; BUFFER SIZE DS 1 ; CHAR COUNT DS BUFLEN LF$SKIP: DS 1 ; LINE FEED SKIP FLAG CR$DELAY: DS 1 ; LINE FEED DELAY COUNTER MONIT$FLAG: DS 1 ; MONITOR (0=YES) FLAG DELAY: DS 1 ; INTER-CHAR DELAY LDSP: DS 1 ; 0=PRINT LEADING , 0FFH=NO LEADING STADR: DS 2 ; BIOS STATUS ROUTINE INADR: DS 2 ; BIOS INPUT ROUTINE OUTADR: DS 2 ; BIOS OUTPUT ROUTINE BUFFER: DS 2 ; BEGINNING OF BUFFER BUFEND: DS 2 ; END OF BUFFER BUF$PTR: DS 2 ; BUFFER PTR BUF$NEXT: DS 2 ; NEXT CHAR IN BUFFER BELLCTR: DS 1 ; RING COUNTER FOR BELL DS 100 ; 50-ELT STACK STACK: DS 2 ; SAVED SP * * * SUPPORT PACKAGE INTERFACE * ORG $/256*256+256 ; PAGE BOUNDARY BASE EQU $ XRA A ; RETURN NO SUPPORT RET NOP SP$END: LXI H,$/256*256+256 ; NEXT PAGE RET * EQUATES FOR INDEXING INTO SUPPORT PACKAGE SP1$STAT EQU BASE CRT$CLR EQU BASE+24 GOTOXY EQU BASE+27 ST$MOD1 EQU BASE+48 IN$MOD1 EQU BASE+54 OUT$MOD1 EQU BASE+57 BR$MOD1 EQU BASE+60 ST$MOD2 EQU BASE+66 IN$MOD2 EQU BASE+72 OUT$MOD2 EQU BASE+75 BR$MOD2 EQU BASE+78 TI$HANG EQU BASE+138 TI$CST EQU BASE+153 END