; PLINK.ASM ; (latest version OCT 18 1980) ; ; PLINK - SUPPORT COMMUNICATIONS LINK WITH CYBER ; ;PLINK IS A CP/M TRANSIENT COMMAND WHICH ALLOWS THE USER TO ;ESTABLISH A COMMUNICATIONS LINK WITH A REMOTE COMPUTER ; ; ORIGINAL BY L.E. HUGHES EDCAM JULY, 1977 ; ; This version by Keith Petersen, W8SDZ. ; WITH HEATH EQUATES ADDED BY TOM JORGENSON ; ; TRS-80 MODEL 1 mods by Steve Vinokuroff, Vanc CBBS ; Optional Triger characters by Steve Vinokuroff ; TRS-80 mods by Dennis Breckenridge, Burnaby CBBS ; D.C.Hayes mods by Bruce Ratoff, Iselin NJ Remote CP/M ; ;This program currently supports the following modems ; or computers via conditional assembly. ; ; 1. PMMI modem ; 2. ANY serial i/o board (TUART INCLUDED) ; 3. TRS-80 model 1 ; 4. TRS-80 model 2 ; 5. HEATH H8 WITH 8251 UART AT PORT 330Q ; 6. D.C.Hayes 80-103A or Micromodem 100 ; ; ;-->NOTE: IF ASSEMBLED AS WRITTEN WILL WORK WITH D.C.Hayes 80-103A ; OR MICROMODEM 100 AT PORT 90H ; ;PLINK CURRENTLY SUPPORTS TWO WAY TRANSFER OF TEXT FILES ;BETWEEN THE CP/M DISK AND THE REMOTE COMPUTER. THE FOLLOWING ;CONTROL CODES MAY BE INITIATED FROM THE CONSOLE KEYBOARD: ; ; **************************************************** ; * COMMANDS: * ; * * ; * CONTROL E EXIT PLINK TO CP/M WARM BOOT * ; * CONTROL T TRANSMIT ASCII FILE TO MODEM. * ; * ASKS FOR DRIVE AND FILENAME.TYP * ; * CONTROL C ABORT FILE SEND TO MODEM * ; * CONTROL Y SAVE INCOMING ASCII IN RAM BUFFER * ; * FOR LATER TRANSFER TO DISK * ; * CONTROL Q WRITE RAM BUFFER TO DISK - ASKS * ; * FOR DRIVE AND FILENAME.TYP * ; * DELETE BACKSPACE WHEN IN COMMAND MODE * ; * ASKING FOR FILENAME * ; * CONTROL U ABORT CURRENT LINE WHEN IN COMMAND * ; * MODE ASKING FOR FILENAME * ; * * ; * (NOTE: ALL OTHER CONTROL CODES ARE PASSED TO * ; * MODEM OUTPUT) * ; **************************************************** ; ; ;CONDITIONAL ASSEMBLY SWITCHES <<-- SET FOR YOUR SYSTEM ; TUART SET 0 ;CROMEMCO TUART I/O BOARD PMMI EQU 0 ;PUT A 1 HERE IF YOU HAVE A PMMI DCH EQU 1 ;PUT A 1 HERE IF YOU HAVE A D.C.HAYES TRS1 EQU 0 ;PUT A 1 HERE IF YOU HAVE TRS80-MOD1 TRSPT EQU 0 ;PUT 1 HERE IF YOU HAVE TRS80-MOD2 ;USING PICKLES & TROUT CP/M 2.X H84 EQU 0 ;PUT 1 HERE IF YOU HAVE H8/H8-4 IF H84 TUART SET 1 ENDIF ; INIT$REQUIRED EQU 1 ;PUT 1 HERE IF INITIALIZATION NEEDED ; IF TRS1 OR PMMI OR TUART OR DCH PORT EQU 1 ENDIF ; IF TRSPT PORT EQU 0 ;STILL NEED THE SWITCH ENDIF ; ; ; ;BDOS ENTRY POINT AND FUNCTION CODES ; IF NOT TRS1 BASE SET 0 ;STANDARD CPM ENDIF ; IF TRS1 OR H84 BASE SET 4200H ;TRS-80 MODEL 1 CP/M BASE ADDRESS ENDIF ; BDOS EQU BASE+5 RESDSK EQU 13 ;RESET DISK SYSTEM OFFC EQU 15 ;OPEN FILE CFFC EQU 16 ;CLOSE FILE DFFC EQU 19 ;DELETE FILE RRFC EQU 20 ;READ RECORD WRFC EQU 21 ;WRITE RECORD MFFC EQU 22 ;MAKE FILE ; ; TRS80 PICKLES AND TROUT SIO CALLS ; OFFSET BY -3 THAT IS ADD 3 TO ALL CALLS ; SETSIO EQU 30H ;SET UP Z80 SIO SIOTST EQU 33H ;READ SIO STATUS SIOINP EQU 36H ;INPUT A CHAR SIOOUT EQU 39H ;OUTPUT A CHAR ; ;DEFAULT FCB AND FIELD DEFINITIONS ; FCB EQU BASE+5CH FN EQU 1 ;FILE NAME FIELD (REL) FT EQU 9 ;FILE TYPE FIELD (REL) EX EQU 12 ;FILE EXTENT FIELD (REL) NR EQU 32 ;NEXT RECORD FIELD (REL) DBUF EQU BASE+80H ;DEFAULT DISK BUFFER ADDRESS ; ;ASCII CONTROL CHARACTERS ; CR EQU 0DH ;CARRIAGE RETURN LF EQU 0AH ;LINE FEED DEL EQU 7FH ;DELETE (RUBOUT) BELL EQU 07H ;BELL SIGNAL TAB EQU 09H ;HORIZONTAL TAB XON EQU 11H ;X-ON CHARACTER NULL EQU 00H ;NULL CHAR ; ;THE FOLLOWING "TRIGER" EQUATE IS SET TO "LF" (LINEFEED) ;BY DEFAULT. AN OPTIONAL TRIGER CHAR MAY BE PASSED VIA FCB1 ; ; IE: PLINK B WILL SET TRIGER TO "BELL" ; ;THE FOLLOWING OPTIONS ARE ALLOWED ; ; 1. B = BELL 07H ; 2. X = XON 11H ; 3. U = UPLOAD NO TRIGER CHECK AT ALL ;ANY OTHER ASCII CHARACTER MAY BE PASSED THROUGH FCB1 ; ; TRIGER EQU LF ;DEFAULT VALUE ; ; ;WARNING CHARACTER FOR LOW MEMORY ; WRNSIG EQU BELL ;IF YOU HAVE ONE, PUT 'BELL' HERE ;...ELSE PUT '*' HERE. ; ;MODEM I/O PORT ADDRESSES ; IF PMMI MODD EQU 0C1H ;MODEM DATA PORT MODS EQU 0C0H ;MODEM STATUS PORT MODINIT EQU 29H ;INITIALIZE BYTE ORIGINATE, ;7 DATA, EVEN PARITY, 1 STOP ENDIF ; IF DCH MODD EQU 90H ;MODEM DATA PORT MODS EQU 91H ;MODEM STATUS PORT MODINIT EQU 05H ;7 DATA, EVEN PARITY, 1 STOP ENDIF ; IF TRS1 MODD EQU 0EBH ;TRS80 MOD 1 RS232 DATA PORT MODS EQU 0EAH ; AND THE RS232 STATUS PORT ENDIF ; IF TUART MODD EQU 0D8H ;<<--MODIFY FOR YOURS MODS EQU 0DDH ;<<--MODIFY FOR YOURS ENDIF ; ;MODEM STATUS PORT BIT DEFINITIONS ; IF PMMI MTBE EQU 01H ;MODEM TRANS. BUFFER READY FLAG MRDA EQU 02H ;MODEM RECEIVE DATA AVAIL. FLAG MXOR EQU 03H ;MASK TO MAKE MTBE AND MRDA "LOW TRUE" ENDIF ; IF DCH MTBE EQU 02H ;MODEM TRANS. BUFFER READY FLAG MRDA EQU 01H ;MODEM RECEIVE DATA AVAIL. FLAG MXOR EQU 03H ENDIF ; IF TRS1 MTBE EQU 40H ;TRS80 MOD1 RS232 BUFFER READY MRDA EQU 80H ;MODEM RECEIVE DATA AVAIL. MXOR EQU 0C0H ENDIF ; IF TUART ;<<--OR ANY OTHER SERIAL I/O MTBE EQU 20H ;<<--MODIFY FOR YOURS MRDA EQU 1H ;<<--MODIFY FOR YOURS MXOR EQU 21H ;<<--MODIFY FOR YOURS ENDIF ; ; **MAIN PROGRAM** ; ORG BASE+100H ; LINK: LXI SP,STACK+64 ;CREATE LOCAL STACK LHLD BASE+1 ;POINT TO CP/M JMP TABLE LXI D,3 ;GET READY TO ADD 3 DAD D ;POINT TO CON STATUS JMP SHLD CITCAL+1 ;MODIFY CALL ADRS DAD D ;POINT TO CON IN JMP SHLD RCCAL+1 ;MODIFY CALL ADRS DAD D ;POINT TO CON OUT JMP SHLD WCCAL+1 ;MODIFY CALL ADRS LDA FCB+1 ;SEE IF OPTIONAL TRIGER CHAR CPI 20H ;BLANK.. ? JZ SKP ;..BLANK SO USE DEFAULT "LF" CPI 'B' ;BELL WANTED JZ TRGBEL CPI 'X' ;XON WANTED JZ TRGXON CPI 'U' ;UPLOADING NO CHECKING FOR TRIGER JZ TRGUPL ; SETTRG STA OVERLY+1 ;STORE THE CHARACTER AS IS THEN JMP SKP ; TRGBEL MVI A,BELL JMP SETTRG ; TRGXON MVI A,XON JMP SETTRG ; TRGUPL XRA A ;ZERO OUT JUMP STA OVERL1+1 ;CHANGE CHECK FOR C/R TO NULL STA OVERL2+1 ;AND SEND LINEFEEDS AS WELL JMP SKP ; SKP EQU $ IF H84 MVI A,80H; SET DLAB BIT IN 8250 UART OUT 0DBH; 8250 AT PORT D8H (330Q) NOP ! NOP ! NOP NOP ! NOP MVI A,01H; MSB OF BAUD RATE DIVISOR OUT 0D9H; ...TO UART NOP ! NOP ! NOP NOP ! NOP MVI A,80H; LSB OF BAUD RATE DIVISOR OUT 0D8H; ...TO UART NOP ! NOP ! NOP NOP ! NOP MVI A,03H; 8 BITS, 1 STOP BIT, NO PARITY, DLAB RESET OUT 0DBH; ...TO UART NOP ! NOP ! NOP NOP ! NOP MVI A,0; RESET CONTROL REGISTER OUT 0DCH; ...TO UART JMP CONT ENDIF IF INIT$REQUIRED AND NOT H84 OR PMMI AND NOT H84 MVI A,MODINIT OUT MODS ;INITIALIZE MODEM PORT ENDIF ; IF TUART MVI A,80H ;DSR ON BIT 7 PARL PORT B OUT 54H ENDIF ; IF TRSPT ;MUST SET UP SERIAL CHANNEL RESET: LXI H,INITR ;STORE RETURN ADDRESS PUSH H LHLD 1 LXI D,SETSIO ;SIO SETUP ROUTINE DAD D PUSH H ;STORE ON STACK MVI C,00H ;NO PARITY CHAN-A MVI D,0E6H ;8 bits ,1 STOP MVI E,3 ;300 BAUD MVI L,00H ;DISABLE EXT/ACK SIO FUNCTIONS MVI H,'S'-40H ;CONTROL S (X-ON) RET ;TROUGH SETUP PROG INITR NOP ;DO IT TO IT ENDIF ; IF TRS1 ;INIT FOR TRS80 MOD1 RS232 OUT 0E8H ;RESET RS232 IN 0E9H ;READ THE SWITCHES ANI 0F8H ORI 5 OUT 0EAH ;SET DSR AND CTS MVI A,55H ;300 BAUD OUT 0E9H ENDIF ; ; IF PORT IN MODD ;CLEAR MODEM UART READ BUFFERS IN MODD ENDIF ; CONT XRA A ;CLEAR CHAR BUFFERS STA INCH STA OUTCH STA FLAG ;CLEAR TEXT SAVE FLAG LXI H,TBUF ;SET PTR TO TBUF SHLD PTR LXI H,0 ;SIZE = 0 SHLD SIZE LXI H,LINKMS ;PRINT SIGN-ON MESSAGE CALL WCS ; ; MAIN LOOP ; LINK3: CALL CITEST ;JUMP IF NO DATA FROM CONSOLE JZ LINK4 CALL RCC ;ELSE READ CONSOLE DATA CPI 20H CC PCC ;CALL PCC IF CONTROL CHAR JC LINK4 ;JUMP IF PCC HANDLED CHAR ORI 80H ;ELSE SET VALID DATA BIT STA INCH ;AND STORE IN INPUT CHAR BUFFER LINK4: LDA OUTCH ;JUMP IF NO DATA FOR CONSOLE ORA A JP LINK5 ANI 7FH ;ELSE DISCARD VALID DATA BIT CALL WCC ;SEND CHAR TO CONSOLE XRA A ;THEN CLEAR OUTPUT CHAR BUFFER STA OUTCH LINK5: CALL MITEST ;JUMP IF NO DATA FROM MODEM JZ LINK6 CALL RMC2 ;ELSE READ MODEM DATA CALL SAVE ;SAVE CHAR IN TEXT BUFFER IF FLAG ON ORI 80H ;SET DATA VALID BIT STA OUTCH ;STORE IN OUTPUT CHAR BUFFER LINK6: CALL MOTEST ;JUMP IF MODEM XMIT BUFFER BUSY JZ LINK7 LDA INCH ;JUMP IF NO DATA FOR MODEM ORA A JP LINK7 ANI 7FH ;DISCARD VALID DATA BIT ; IF PORT OUT MODD ;OUTPUT CHAR TO MODEM ENDIF ; IF TRSPT PUSH B ;STORE REGISTERS PUSH H PUSH D CALL WMC ;SEND CHAR POP D POP H POP B ENDIF ; XRA A ;...THEN CLEAR INPUT CHAR BUFFER STA INCH LINK7: JMP LINK3 ;END OF MAIN LOOP ; LINKMS: DB CR,LF,'PLINK as of 25-SEP-80' DB CR,LF,LF,'READY',CR,LF,LF,0 ; ; PCC - PROCESS CONTROL CHARACTER ; PCC: CPI 'E'-40H ;JUMP OUT IF CTRL E JNZ PCC1 PUSH H LXI H,AYS ;PRINT 'ARE YOU SURE' CALL WCS POP H CALL RCC ;GET ANSWER CALL WCC ;ECHO IT ANI 5FH ;MAKE UPPER CASE CPI 'Y' ;YES? JZ PCCEX ;EXIT CALL WCCR ;CRLF STC ;TELL LINK TO IGNORE THIS CHARACTER ; IF TRSPT POP PSW ;GOBBLE UP CALL ADDRESS JMP RESET ;RE-INITIALIZE SIO ENDIF ; IF PORT RET ENDIF ; PCC1: CPI 'T'-40H ;JUMP IF NOT CONTROL-T JNZ PCC2 CALL STF ;TRANSMIT TEXT FILE TO MODEM STC ;TELL LINK TO IGNORE THIS CHARACTER RET ; PCC2: CPI 'Y'-40H ;JUMP IF NOT CONTROL-Y JNZ PCC3 MVI A,1 ;TURN ON TEXT SAVE FLAG STA FLAG LXI H,PCCMR ;PRINT 'SAVING INCOMING TEXT IN MEMORY' CALL WCS STC ;TELL LINK TO IGNORE THIS CHARACTER RET ; PCC3: CPI 'Q'-40H ;JUMP IF NOT CONTROL-Q JNZ PCC4 XRA A ;TURN OFF TEXT SAVE FLAG STA FLAG CALL WTB ;WRITE TEXT BUFFER TO DISK STC RET ; PCC4: STC ;LET LINK HANDLE ALL OTHER CONT. CODES CMC RET ; PCCEX: LXI H,DISMS ;PRINT 'MODEM NOT DISCONNECTED' CALL WCS JMP BASE ;EXIT TO WARM BOOT ; AYS: DB CR,LF,'EXIT TO CP/M - ARE YOU SURE (Y OR N)?',0 IF PMMI OR DCH DISMS: DB CR,LF,'++DON''T FORGET - THE MODEM ' DB 'IS NOT DISCONNECTED++',CR,LF DB 'USE "MODEM D" TO DISCONNECT',0 ENDIF ; IF NOT PMMI AND NOT DCH DISMS: DB CR,LF,'+++ EXIT TO CP/M +++',CR,LF,0 ENDIF ; PCCMR: DB CR,LF,'SAVING INCOMING TEXT IN MEMORY',CR,LF,0 ; ; STF - SEND TEXT FILE (TO MODEM) ; STF: CALL GFN ;GET NAME OF DISK FILE TO SEND JC STF6 ;JUMP IF FILE NAME ERROR CALL OPEN ;TRY TO OPEN SPECIFIED FILE CPI 255 ;JUMP IF FILE NOT FOUND JZ STF7 STF1: CALL READ ;READ NEXT RECORD INTO DBUF CPI 1 ;JUMP IF END-OF-FILE JZ STF5 LXI H,DBUF ;POINT TO DISK BUFFER MVI C,128 STF2: MOV A,M ;FETCH NEXT CHAR FROM DBUF INX H CPI 'Z'-40H ;JUMP IF END-OF-FILE CHARACTER JZ STF5 OVERL2 CPI LF ;IGNORE LINE FEEDS JZ STF4 CALL WMC ;WRITE CHARACTER TO MODEM CALL WCC ;WRITE CHARACTER TO CONSOLE OVERL1 CPI CR ;JUMP IF NOT CARRIAGE RETURN JNZ STF4 STF3: CALL CITEST ;CHECK CONSOLE DATA READY JZ STF3A ;NO DATA THERE CALL RCC ;GET CONSOLE CHARACTER CPI 'C'-40H ;CONTROL C ABORTS IT JZ STF8 STF3A: CALL MITEST ;WAIT FOR NEXT MODEM KHARACTER JZ STF3 CALL RMC2 ;CHECK MODEM FOR TRIGGER CHAR. OVERLY CPI TRIGER JNZ STF3 CALL WCCR ;SEND CRLF TO CONSOLE STF4: DCR C ;LOOP THRU REST OF DBUF JNZ STF2 JMP STF1 ;GO GET NEXT RECORD FROM DISK ; STF5: LXI H,STFSM ;PRINT 'FILE SEND COMPLETE' CALL WCS RET ; STF6: LXI H,STFS1 ;PRINT 'FILE NAME ERROR' CALL WCS RET ; STF7: LXI H,STFS2 ;PRINT 'FILE NOT FOUND' CALL WCS RET ; STF8: LXI H,STFSA ;PRINT 'FILE SEND ABORTED' CALL WCS RET ; STFSM: DB 'FILE SEND COMPLETE',CR,LF,0 STFS1: DB 'FILE NAME ERROR',CR,LF,0 STFS2: DB 'FILE NOT FOUND',CR,LF,0 STFSA: DB CR,LF,'FILE SEND ABORTED',CR,LF,0 ; ; SAVE - SAVE CHAR IN TEXT BUFFER IF FLAG ON ; ; ENTRY CONDITIONS ; A - CHARACTER TO SAVE ; SAVE: PUSH PSW LDA FLAG ORA A JNZ SAVE1 POP PSW RET ; SAVE1: POP PSW CPI DEL ;RUBOUT (DEL) ? RZ ;YES, IGNORE IT CPI 20H ;TEST FOR CONTROL CHARACTERS JNC SAVE2 ;JUMP IF NOT CONTROL CHAR. CPI CR ;ALLOW CR TO BE SAVED JZ SAVE2 CPI LF ;ALLOW LF TO BE SAVED JZ SAVE2 CPI TAB ;ALLOW TAB TO BE SAVED JZ SAVE2 RET ;IGNORE ALL OTHER CONTROL CHARS. ; SAVE2: PUSH H LHLD SIZE ;SIZE = SIZE + 1 INX H SHLD SIZE LHLD PTR MOV M,A INX H SHLD PTR PUSH PSW LDA BASE+7 ;GET SYSTEM SIZE SUI 1 ;SO WE DONT CRASH CP/M CMP H ;ARE WE OUT OF ROOM? JZ SAVEAB ;YES, ABORT SUI 4 ;LEAVE SOME ROOM (1K) CMP H MVI A,WRNSIG ;SIGNAL CONSOLE RUNNING OUT OF SPACE CC WCC POP PSW POP H RET ; ; SAVEAB - RAN OUT OF ROOM, ISSUE MESSAGE AND FLOW ; THROUGH TO DISK SAVE ROUTINE ; SAVEND: DB BELL,CR,LF,'ABORTING - NO ROOM LEFT',0 ; SAVEAB: LXI SP,STACK+64 ;REINITIALIZE STACK LXI H,SAVEND ;PRINT 'ABORTING - NO ROOM LEFT' CALL WCS LXI H,LINK ;SET UP RETURN ADDRESS PUSH H ;LEAVE IT ON THE STACK ; ; WTB - WRITE TEXT BUFFER TO DISK ; WTB: LHLD SIZE ;JUMP IF TEXT BUFFER EMPTY MOV A,L ORA H JZ WTB5 MVI C,RESDSK ;RESET IN CASE READ-ONLY CALL BDOS CALL GFN ;GET FILE NAME JC WTB6 ;JUMP IF FILE NAME ERROR CALL DELT ;DELETE OLD FILE, IF ANY CALL MAKE ;MAKE NEW FILE LHLD SIZE ;DE = TBUF SIZE XCHG LXI H,DBUF ;TOP OF STACK POINTS TO DBUF PUSH H LXI H,TBUF ;HL POINTS TO TBUF WTB1: MVI C,128 ;DISK BUFFER SIZE WTB2: MOV A,M ;FETCH NEXT BYTE OF TBUF INX H XTHL MOV M,A ;STORE IN DBUF INX H XTHL DCX D ;SIZE = SIZE - 1 MOV A,D ;EXIT LOOP IF SIZE = 0 ORA E JZ WTB3 DCR C ;LOOP UNTIL DBUF FULL JNZ WTB2 CALL WRITE ;WRITE FULL DBUF TO DISK XTHL ;TOP OF STACK POINTS TO DBUF LXI H,DBUF XTHL JMP WTB1 ;LOOP UNTIL END OF TBUF ; WTB3: POP H ;HL POINTS TO CURRENT PLACE IN DBUF WTB4: MVI M,'Z'-40H ;STORE EOF CODE INX H DCR C ;LOOP THRU REST OF DBUF JNZ WTB4 CALL WRITE ;WRITE LAST SECTOR TO DISK CALL CLOSE ;CLEAN UP ACT AND GO HOME LXI H,TBUF ;CLEAR TEXT BUFFER SHLD PTR LXI H,0 SHLD SIZE LXI H,WTBSM ;PRINT 'BUFFER SAVED ON DISK' CALL WCS RET ; WTB5: LXI H,WTBS1 ;PRINT 'TEXT BUFFER EMPTY' CALL WCS RET ; WTB6: LXI H,WTBS2 ;PRINT 'FILE NAME ERROR' CALL WCS RET ; WTBSM: DB CR,LF,'BUFFER SAVED ON DISK',CR,LF DB 'MEMORY SAVE CANCELLED',CR,LF,0 WTBS1: DB 'TEXT BUFFER EMPTY',CR,LF,0 WTBS2: DB 'FILE NAME ERROR',CR,LF,0 ; ; WCS - WRITE CONSOLE STRING ; ; ; ENTRY CONDITIONS ; HL - POINTS TO STRING (TERM BY ZERO BYTE) ; WCS: MOV A,M INX H ORA A RZ CALL WCC JMP WCS ; ; WCCR - WRITE CONSOLE CARRIAGE RETURN (AND LINE FEED) ; WCCR: MVI A,CR CALL WCC MVI A,LF ; ; WCC - WRITE CONSOLE CHARACTER ; ; ENTRY CONDITIONS: ; A - CHARACTER TO WRITE ; WCC: PUSH PSW PUSH B PUSH D PUSH H MOV C,A ;GET CHARACTER FOR CBIOS WCCAL: CALL $-$ ;MODIFIED BY INIT. POP H POP D POP B POP PSW RET ; ; RCS - READ CONSOLE STRING (WITH ECHO) ; ; EXIT CONDITIONS ; B - NUMBER OF CHARACTERS READ (<255) ; HL - POINTS TO LAST CHAR STORED (CR) ; RCS: LXI H,IBUF MVI B,0 RCS1: CALL RCC ;READ NEXT CHAR FROM CONSOLE CPI DEL ;JUMP IF NOT DEL JNZ RCS2 INR B ;IGNORE DEL IF IBUF ALREADY EMPTY DCR B JZ RCS1 DCX H ;ELSE DISCARD LAST CHAR MOV A,M ;ECHO DISCARDED CHAR TO CONSOLE CALL WCC DCR B ;DECREMENT COUNT JMP RCS1 ; AND LOOP ; RCS2: CPI 'U'-40H ;JUMP IF NOT CONTROL U JNZ RCS3 CALL WCCR ;ELSE ABORT CURRENT LINE JMP RCS ; AND START OVER ; RCS3: CALL WCC ;ECHO CHAR TO CONSOLE MOV M,A ;STORE CHAR IN IBUF INR B ;INCREMENT COUNT CPI CR ;JUMP IF CARRIAGE RETURN JZ RCS4 INX H ;ELSE ADVANCE POINTER JMP RCS1 ; AND LOOP ; RCS4: MVI A,LF ;ISSUE LINE FEED AND RETURN CALL WCC RET ; ; RCC - READ CONSOLE CHARACTER ; ; EXIT CONDITIONS ; A - CHARACTER READ ; RCC: PUSH B PUSH D PUSH H RCCAL: CALL $-$ ;MODIFIED BY INI\. POP H POP D POP B RET ; ; WMC - WRITE MODEM CHARACTER ; ; ENTRY CONDITIONS ; A - CHARACTER TO WRITE ; ; IF PORT WMC: PUSH PSW WMCL: IN MODS XRI MXOR ANI MTBE JNZ WMCL POP PSW ANI 7FH ;STRIP PARITY BIT OUT MODD RET ENDIF ; IF TRSPT WMC: PUSH H PUSH D PUSH PSW WMCL: CALL MOTEST ;TEST STATUS JZ WMCL ;LOOP TILL TX EMPTY POP PSW ;RESTORE CHAR ANI 7FH ;STRIP PARITY PUSH B ;STORE B MOV C,A ;PUT CHAR INTO C MVI B,00H ;CHANNEL A LXI H,WMCRE ;STORE RETURN ADDRESS PUSH H LHLD 1 ;GET BASE ADDRESS LXI D,SIOOUT DAD D PCHL ;JUMP TO IT WMCRE: POP B ;RESTORE IT POP D POP H RET ENDIF ; ; RMC - READ MODEM CHARACTER ; ; EXIT CONDITIONS: ; A - CHARACTER READ ; ; IF PORT RMC: IN MODS XRI MXOR ANI MRDA JNZ RMC RMC2: IN MODD ANI 7FH RET ENDIF ; IF TRSPT RMC: CALL MITEST ;CHAR AVAILABLE JZ RMC ;LOOP IF NOT READY RMC2: PUSH B ;STORE B PUSH D PUSH H MVI B,00H ;CHANNEL A LXI H,RMCRE ;RETURN ADDRESS PUSH H LHLD 1 LXI D,SIOINP DAD D PCHL RMCRE: POP H POP D POP B ANI 7FH ;STRIP PARITY RET ENDIF ; ; ; GFN - GET FILE NAME ; GFN: LXI H,GFNSD ;PRINT 'WHICH DRIVE?' CALL WCS CALL RCC ;GET ANSWER FROM CONSOLE CALL WCC ;ECHO IT TO CONSOLE ANI 5FH ;MAKE UPPER CASE SUI 'A'-1 JC GFN ;REQUIRE ALPHABETIC JZ GFN CPI 17 ;ALLOW 16 DRIVES (AS IN CP/M 2.X) JNC GFN STA FCB GFNB: LXI H,GFNS1 ;PRINT 'FILENAME? ' CALL WCS CALL RCS ;READ RESPONSE INTO IBUF LXI H,FCB+FN ;BLANK FILL FN AND FT FIELDS MVI C,11 GFN1: MVI M,' ' INX H DCR C JNZ GFN1 LXI H,IBUF ;POINT TO INPUT BUFFER LXI D,FCB+FN ;SCAN OFF FN FIELD MVI C,9 GFN2: MOV A,M ;FETCH NEXT CHAR FROM IBUF INX H CPI 61H ;IF LC, CONVERT TO UC JC GFN2A SUI 20H GFN2A: CPI CR ;JUMP IF END OF LINE JZ GFN5 CPI '.' ;JUMP IF END OF NAME JZ GFN3 STAX D ;ELSE STORE CHAR IN FN FIELD INX D DCR C ;LOOP IF 8 OR LESS CHARS SO FAR JNZ GFN2 JMP GFN6 ;ELSE TAKE ERROR EXIT ; GFN3: LXI D,FCB+FT ;SCAN OFF FT FIELD MVI C,4 GFN4: MOV A,M ;FETCH NEXT CHAR FROM IBUF INX H CPI 61H ;IF LC, CONVERT TO UC JC GFN4A SUI 20H GFN4A: CPI CR ;JUMP IF END OF LINE JZ GFN5 STAX D ;ELSE STORE CHAR IN FT FIELD INX D DCR C ;LOOP IF 3 OR LESS CHARS SO FAR JNZ GFN4 JMP GFN6 ;ELSE TAKE ERROR EXIT ; GFN5: XRA A STA FCB+EX ;SET EXTENT NUMBER TO ZERO STA FCB+NR ;SET RECORD NUMBER TO ZERO STC ;CLEAR ERROR FLAG AND RETURN CMC RET ; GFN6: STC ;SET ERROR FLAG AND RETURN RET ; GFNSD: DB CR,LF,'WHICH DRIVE? ',0 GFNS1: DB CR,LF,'FILENAME? ',0 ; ; OPEN - OPEN DISK FILE ; OPEN: PUSH H PUSH D PUSH B LXI D,FCB MVI C,OFFC CALL BDOS POP B POP D POP H RET ; ; READ - READ RECORD FROM DISK FILE ; READ: PUSH H PUSH D PUSH B LXI D,FCB MVI C,RRFC CALL BDOS POP B POP D POP H RET ; ; CLOSE - CLOSE DISK FILE ; CLOSE: PUSH H PUSH D PUSH B LXI D,FCB MVI C,CFFC CALL BDOS POP B POP D POP H RET ; ; DELT - DELETE DISK FILE ; DELT: PUSH H PUSH D PUSH B LXI D,FCB MVI C,DFFC CALL BDOS POP B POP D POP H RET ; ; WRITE - WRITE RECORD TO DISK ; WRITE: PUSH H PUSH D PUSH B LXI D,FCB MVI C,WRFC CALL BDOS POP B POP D POP H RET ; ; MAKE - MAKE NEW DISK FILE ; MAKE: PUSH H PUSH D PUSH B LXI D,FCB MVI C,MFFC CALL BDOS POP B POP D POP H RET ; ; CITEST - CHECK CONSOLE INPUT STATUS ; CITEST: PUSH B PUSH D PUSH H CITCAL: CALL $-$ ;MODIFIED BY INIT. ORA A ;SET ZERO FLAG POP H POP D POP B RET ;ZERO FLAG CARRIES ANSWER ; ; MITEST - CHECK MODEM INPUT STATUS ; IF PORT MITEST: IN MODS ;GET MODEM UART STATUS XRI MXOR ;INVERT HIGH-TRUE BITS ANI MRDA ;ANY DATA AVAILABLE? MVI A,0 JNZ MITST1 CMA MITST1: ORA A RET ;ZERO FLAG CARRIES ANSWER ENDIF ; ; IF TRSPT ; MITEST: PUSH B PUSH H PUSH D MVI B,00 ;CHANNEL A LXI H,MITSTR PUSH H LHLD 1 LXI D,SIOTST DAD D PCHL MITSTR: POP D POP H ANI 01 ;TX EMPTY POP B RET ;ZERO FLAG HOLDS THE ANSWER ENDIF ; ; MOTEST - CHECK MODEM OUTPUT STATUS ; ; IF PORT MOTEST: IN MODS ;GET MODEM UART STATUS XRI MXOR ;INVERT HIGH-TRUE BITS ANI MTBE ;UART READY FOR CHARACTER? MVI A,0 JNZ MOTST1 ;ZERO FLAG CARRIES ANSWER CMA MOTST1: ORA A ;SET ZERO FLAG IF READY RET ENDIF ; IF TRSPT MOTEST: PUSH B PUSH H PUSH D MVI B,00 ;CHANNEL A LXI H,MOTSTR PUSH H LHLD 1 LXI D,SIOTST DAD D PCHL MOTSTR: ANI 02 ;BUFFER EMPTY POP D POP H POP B RET ENDIF ; ; DATA AREA ; INCH: DS 1 ;INPUT CHAR BUFFER (TO CYBER) OUTCH: DS 1 ;OUTPUT CHAR BUFFER (FROM CIBER) STACK: DS 80 ;LOCAL STACK IBUF: DS 256 ;INPUT BUFFER ; ; TEXT BUFFER ; FLAG: DS 1 ;TEXT SAVE FLAG PTR: DS 2 ;TEXT BUFFER POINTER SIZE: DS 2 ;TEXT BUFFER SIZE TBUF: EQU $ ;START OF TEXT BUFFER ; END LINK ;