name ('link80') title Link-80 Source Code Version 1.68 .tfcond .8080 .comment ~ ************************************************************************** ************************************************************************** *** *********** *** *** *** *** *** *********** *** *** *** *** *** *** **** *** *** *** *** *** ***** *** *** *** *** *** ****** *** *** *** *** *** *** *** *** ****** ****** ****** *** *** *** *** *** ******* ** ** ** ** *** *** *** ****** *** *** ** ** ** ** *** *** *** ***** *** *** ****** ** ** *** *** *** **** *** *** ** ** ** ** ************ *********** *** *** *** *** ** ** ** ** ************ *********** *** *** *** *** ****** ****** ************************************************************************** ************************************************************************** L O A D E R . M A C Verison 1.68 Creation Date: 21 April 1982 MODULE: 1.00 Date Last Revised: 7 January 1983 CP/M Computer Communications Software Edit History: 21 Apr 82 - Created by David Norris. 06 Jan 83 - Set up for Macro-80 by Mike Pinkston. 07 Jan 83 - Fix made for all 16 drives available. ~ subttl Title page page 60 .comment ~ **************************************************************** * * * L I N K 8 0 * * * * Copyright (C) 1980, 1981 by David C. Norris * * Maranatha Software Systems * * 500 Catalina Road #305, Cocoa Beach, FL 32931 * * Phone (305) 783-1963 * * * **************************************************************** written by DAVID C. NORRIS with assistance from: DR. GEORGE ORR ( Co-originator ) SCOTT DYE ( Extensive field testing ) ****************** * Change Summary * ****************** 1.60 - Wildcard options supported in the "SEND" command only. Directory printouts no longer have extensions printed. BDOS error messages on remote system reported correctly. LINKSBS module has origin of 2400h. 1.63 - Terminal mode file transmit routines wait a second after lines are transmitted to allow time for the remote editor to catch up. Support for versions of CP/M which only return the last extent of a file using the file search call. 1.65 - Wildcard bug fixed; files longer than 1 extent can be sent. 1.66 - Terminal mode options no longer reset when terminal mode is re-entered. Terminal mode options may be typed in lower case. 1.67 - Conversational mode operates properly in half-duplex. 1.68 - Fix made to allow all 16 drives to be used. ~ subttl Copyright Notice page .comment ~ 2210, 21 April 1982 all rights reserved note: This program has been written so that CP/M users may exchange programs between each other using a carefully tested intercommunication protocol. The source listing is provided as a courtesy to the user and so that non CP/M users may adapt LINK80 to their own computers. Major additions or deletions other than configuration defeat the purpose of this program. LINK80 has been designed with as many practical features necessary as well as some fancy additions. THIS IS COPYRIGHTED SOFTWARE! Please restrain yourself from making any additions to LINK80 other than those required to get the program up on your system. Should you find any bugs in the system, whether particular to your machine or not, or have any helpful suggestions please contact me and I will try to incorporate them in a future release of LINK80. Thanks. - Dave Norris ~ subttl Global and External references page EXTERNAL Init, Clrcm1, Cmchk1, Cmin1, Cmout1, Clear, Drives, Speed EXTERNAL Ptrig, Phalt, Pwait, Pcont, Pabort subttl Module Equate Statements page ;**************************************************************** ;* System equates * ;**************************************************************** FCB EQU 5CH ;File control block area FCBDN EQU FCB+0 ;Disk name FCBFN EQU FCB+1 ;File name FCBFT EQU FCB+9 ;File type FCBRL EQU FCB+12 ;Reel number FCBRC EQU FCB+15 ;Record count FCBCR EQU FCB+32 ;Current (next) record number) FCBLN EQU FCB+33 ;FCB length ;**************************************************************** ;* Ascii equates * ;**************************************************************** NULL EQU 0 ;Null SOH EQU 1 ;Start of header STX EQU 2 ;Start of text ETX EQU 3 ;End of text EOT EQU 4 ;End of transmission ENQ EQU 5 ;Inquiry ACK EQU 6 ;Acknowledge BEL EQU 7 ;Bell (message waiting) BS EQU 8 ;Back space LF EQU 10 ;Line feed CR EQU 13 ;Carriage return DLE EQU 16 ;Data link escape DC1 EQU 17 ;Direct control 1 DC2 EQU 18 ;Direct control 2 DC3 EQU 19 ;Direct control 3 DC4 EQU 20 ;Direct control 4 NAK EQU 21 ;Negative Acknowledge ESC EQU 27 ;Escape DEL EQU 7FH ;Delete subttl Version Number Data Area page JMP START ;skip version number DB CR SMSG: DB 'LINK80 ' VERS: DB 'Version ' MARK: DB '1.' ; Major revision number ( Protocol change ) VERSION: DB '6' ; Version number ( Update from series of ) ; ( patch levels or new command implemented ) PATCH: DB '8' ; Patch level ( minor updates or fixes ) DB CR,LF DB 'Copyright (C) 1980, 1981',CR,LF DB 'Maranatha Software Systems',CR,LF DB 'Version for Systems Group CPC-2810',CR,LF DB '$',8,' ',CR,LF DB 1AH ; LINK80.COM was not meant to be printed subttl System Initialization Area page ;**************************************************************** ;* System initialization * ;**************************************************************** START: LXI SP,STACK ;Reset stack pointer LHLD Clear## ;Get address of user supplied clear string XCHG CALL PRMSG ;Print clear string LXI D,SMSG ;Startup message CALL PRMSG CALL Init## ;Go to user provided initialization CALL CLRCOM ;Clear the communications channel MVI A,'A' CALL LOGIN ;Start on drive A ;**************************************************************** ;* Initial prompt and command input for the INITIAL state * ;**************************************************************** PRMPT: LXI SP,STACK ;Reinitialize stack (just in case) CALL CRLF MVI A,ACK STA MFLG ;Clear the messages waiting flag LDA DISK MOV E,A CALL PRCHR ;Print the disk we are now on MVI E,':' CALL PRCHR ;Print colon MVI C,2 MVI E,'*' CALL 5 ;Initial state prompt CALL CLRBUF ;Clear and zero input buffer LXI D,INBUF ;Point to input buffer MVI C,10 CALL 5 ;Input command string CALL JUSLF LDA INBUF+1 ;Get input string length ORA A ;Null string dropout JZ PRMPT ; We have initial state command input, process now... LXI H,INTBL CALL PARSE ;Process and execute command string ; Only errors on command string allowed past here LXI D,ERMSG CALL PRMSG ;Print "What?" JMP PRMPT ;**************************************************************** ;* INITIAL state directory * ;**************************************************************** IDIR: CALL DIR CALL CRLF JMP PRMPT ;**************************************************************** ;* Print help menu for the initial mode * ;**************************************************************** INHEP: LXI D,INHEMS CALL PRMSG JMP PRMPT ;**************************************************************** ;* STDISK - log on to disk A or B * ;**************************************************************** STDISK: LDA INBUF+2 CALL LOGIN JMP PRMPT ;**************************************************************** ;* TERMINAL mode * ;**************************************************************** TERM: LXI D,TEMSG CALL PRMSG ;Inform user he is entering mode MVI A,1 ;Set mode to terminal, no file STA TFLG ; transfers pending TERM1: CALL CONV ;Use CONV mode routine ; User has typed the escape key, process TERMINAL mode function LDA TMFLG ORA A ;Check menu print flag JZ TEIN LXI D,TAMSG CALL PRMSG ;Print auto-linefeed string LDA AFLG ORA A JZ TO1 LXI D,ONMSG ;Auto-linefeed on message JMP TO2 TO1: LXI D,OFMSG ;Auto-linefeed off message TO2: CALL PRMSG LXI D,TCMSG CALL PRMSG ;Print duplex string LDA PLXFLG ORA A JZ TO3 LXI D,HAFMSG ;Half-duplex message JMP TO4 TO3: LXI D,FULMSG ;Full-duplex message TO4: CALL PRMSG LXI D,TBMSG CALL PRMSG ;Print rest of menu TEIN: MVI C,1 CALL 5 ;Get command PUSH PSW LDA TMFLG ;Get menu flag ORA A CNZ CRLF ;CRLF after input if menu mode POP PSW CALL CTUC ;convert to upper case CPI 'B' JZ TERMB ;Reinitialize baud rate CPI 'M' JZ TERMM ;Toggle auto-menu CPI 'A' JZ TERMA ;Toggle auto-line feed CPI 'D' JZ TERMD ;Toggle duplex CPI 'S' JZ TERMS ;Send program CPI 'I' JZ TERMI ;Input program CPI 'R' JZ TRESET ;Reset disks CPI ESC JZ TERME ;Exit TERMINAL mode CPI 'E' JNZ TERM1 ;Nonexistent command, continue MVI A,ESC CALL CMOUT ;Output an escape to the remote mainframe JMP TERM1 ;Continue TERMB: CALL Init## ;Reinitialize baud rate CALL CRLF JMP TERMR TERMM: LDA TMFLG CMA ;Complement flag STA TMFLG JMP TERMR TERMA: LDA AFLG CMA ;Complement flag STA AFLG JMP TERMR TERMD: LDA PLXFLG CMA ;Complement flag STA PLXFLG JMP TERMR TRESET: CALL RESET ;Reset disks JMP TERMR TERMS: CALL INPFLN ;Input file name to send ORA A JNZ TERMS7 ;Bad file name if not zero LDA WILD ORA A JZ TERMS5 ;Only unambiguous file names allowed LXI D,UFOMSG CALL PRMSG JMP TERMR ;Re-enter terminal mode TERMS7: LXI D,BFMSG CALL PRMSG ;Tell him he messed up JMP TERMR TERMS5: LXI D,FCB MVI C,15 CALL 5 ;Open file CPI 255 ;File opened ok? JNZ TERMS1 LXI D,FOEMSG CALL PRMSG ;Print no such file CALL PRFLNM JMP TERMR TERMS1: LXI D,FCB MVI C,20 CALL 5 ;Read 1 record ORA A JZ TERMS3 ;Read ok CPI 1 JZ TERMS2 ;End of file LXI D,FIEMSG CALL PRMSG TERMS2: LXI D,FCB MVI C,16 CALL 5 ;Close the file JMP TERMR ;Return to TERMINAL mode TERMS3: LXI H,80H MVI C,80H TERMS4: PUSH H ;Save pointer PUSH B ;Save count MVI C,11 CALL 5 ;Check for console input ORA A POP B ;Restore count POP H ;Restore pointer JZ TERMS6 ;No input PUSH H ;User hit a key, resave pointer PUSH B ;Resave count MVI C,1 CALL 5 ;Get rid of strike key LXI D,ABMSG CALL PRMSG ;Ask user if he wants to abort MVI C,1 CALL 5 CPI ESC ;Does he want to? POP B ;Restore count POP H ;Restore pointer at any rate JNZ TERMS6 ;No abort, continue LXI D,TIEMSG CALL PRMSG ;Print abort message JMP TERMR ;Return to Terminal mode TERMS6: MOV A,M CPI 'Z'-40H ;Check for CP/M end of file JZ TERMS1 ;Get next record (which doesn't exist) CPI LF ;Dont send line feeds, delay a bit instead JZ TERMS8 CALL CMOUT ;Output program byte MOV E,A CALL PRCHR ;Print the character we are sending TERMS9: INX H DCR C ;Decrement byte count JNZ TERMS4 ;Not done with this record yet JMP TERMS1 ;Get next record TERMS8: CALL JUSLF ;Do line feed but don't send it PUSH B PUSH H MVI B,3 ;Delay for 1/2 sec for remote host CALL TIMOT ;to keep up with LINK80 amazing speed POP H ; (Thanks, Jeff) POP B JC TERMS9 ;Timed out, bump pointer & send next line MOV E,A LDA PLXFLG ORA A ;Check duplex JZ TERMS8+3 ;If full duplex we don't want to echo program CALL PRCHR ;Print character recieved from remote JMP TERMS8+3 TERMI: CALL INPFLN ;Get file name ORA A JNZ TERMS7 LDA WILD ORA A JZ TERMI6 ;Only unambiguous file names allowed LXI D,UFOMSG CALL PRMSG JMP TERMR ;Re-enter terminal mode TERMI6: CALL PRPFIL ;Prepare file for writing JNC TERMI1 TERMIQ: LXI D,TIEMSG CALL PRMSG ;Error, print abort message JMP TERMR TERMI1: LXI H,Buffer ;Point to start of user input buffer SHLD BPOINT ;Where we are LXI D,TIMSG CALL PRMSG ;Tell user what we are doing LHLD Ptrig## CALL TOUT ;Issue the list trigger (usually CR) TERMI2: MVI C,128 ;Ratio of remote check vs. console check TERMI3: CALL CMCHK JNZ TERMI5 ;Input from remote, go process DCR C JNZ TERMI3 ;Not time to check console yet.... MVI C,11 CALL 5 ;Check console for user break.... ORA A JZ TERMI2 ;No user input, continue loop MVI C,1 CALL 5 ;Drop last keystrike CALL THALT ;Issue halt string and wait LXI D,TABMSG CALL PRMSG ;Issue abort? string MVI C,1 CALL 5 CPI ESC ;User want an abort? JZ TERMI4 CPI 'Q' ;User want to save what he has? JNZ TPGO LXI D,TIDMSG CALL PRMSG CALL TDUMP JC TICLS ;Error in dump; close file & quit LXI D,Buffer MVI C,26 CALL 5 ;Reset DMA to start of buffer LHLD BPOINT MVI M,'Z'-40H ;Insert CP/M end-of-file LXI D,FCB MVI C,21 CALL 5 ;Dump 1 more record to disk TICLS: LXI D,FCB MVI C,16 CALL 5 ;Close the file JMP TERMR TPGO: LXI D,TCNTMG CALL PRMSG ;Inform user we are continuing LHLD Pcont## CALL TOUT ;Issue continue string JMP TERMI2 ;Continue input TERMI4: LHLD Pabort## CALL TOUT ;Issue abort string JMP TERMIQ ;Go quit TERMI5: LHLD BPOINT CALL CMIN ;Get the byte MOV M,A MOV E,A CALL PRCHR ;Print the character so user can see INX H SHLD BPOINT LDA 7 ;Get hi byte of BDOS address DCR A DCR A ;Leave some room (just in case) DCR A DCR A ; leave 1/2K of memory for overrun CMP H JNZ TERMI2 ;Haven't reached buffer limit yet... CALL THALT ;Tell remote to shut up while we work... CALL TDUMP ;Dump what we have JC TICLS ;Check for error indicator JMP TPGO ;Continue load TERMR: LXI D,TREMSG CALL PRMSG ;Inform user he is re-entering terminal mode JMP TERM1 TERME: XRA A STA TFLG ;Reset mode to conversational LXI D,80H MVI C,26 CALL 5 ;Reset DMA buffer JMP PRMPT ;Exit terminal mode ;**************************************************************** ;* INQ - check status of remote user, enter command mode * ;**************************************************************** INQ: MVI A,ENQ CALL CMOUT ;Throw an to the remote computer MVI B,1 ;Set wait byte for TIMOT to 1/4 second CALL TIMOT ;Call CMIN but do a time out JNC INQ1 ;No carry = routine didn't time out ; No response from remote - bomb back to INITIAL state INQ2: LXI D,NOTMSG ;Print link not established CALL PRMSG JMP PRMPT ; Remote sent a byte in response to our ; evaluate and respond accordingly INQ1: CPI ACK ;Acknowledge? JZ ESRL ;Establish the link CPI BEL ;Bell? (message waiting) JNZ INQ2 ;remote must send ACK or BEL LXI D,MSWTMS CALL PRMSG ;Print messages waiting ESRL: LXI D,RLEMSG ;Print remote link established CALL PRMSG JMP CNPMT ;**************************************************************** ;* Enter message and go into WAIT state * ;**************************************************************** LVMSG: LXI D,PMTMSG CALL PRMSG ;Request message CALL MSGIN ;Input the message CALL CRLF MVI A,BEL STA MFLG ;Set the messages waiting flag ; Wait for remote input or keyboard depress WT: LXI D,WATMSG CALL PRMSG ;**************************************************************** ;* Enter the WAIT state * ;**************************************************************** WAIT: LXI SP,STACK ;Reinitialize stack (just in case) CALL CMCHK JNZ WAITIN ;Remote input MVI C,11 CALL 5 RRC JNC WAIT ;No keyboard input MVI C,1 CALL 5 CPI ESC ;Did he hit an escape? JNZ WAIT ;No, keep looping LDA MFLG CPI ACK ;Did he have a message waiting? JZ PRMPT LXI D,MWFCMG CALL PRMSG ;He doesn't now JMP PRMPT WAITIN: CALL CMIN ;Get character CPI ENQ ;Did remote inquire us? JZ STLINK CPI STX ;STX? (message waiting) JZ RCVMSG CPI SOH ;SOH? (incoming program) JZ WRDPGM CPI DC1 ;DC1 (remote sent us a TR) JZ ACKCN CPI DLE ;DLE? (end remote link) JZ ENLNK1 CPI BEL ;BEL? (wants the message we left) JZ SNLVMS CPI ESC ;ESC? (conversational mode?) JZ WTCON CPI DC2 ;DC2? (remote wants our directory) JZ SNDIR CPI DC3 ;DC3? (remote wants a program) JZ WTSNPM CPI DC4 ;DC4? (remote wants to select a disk) JZ WTDSK WTNAK: MVI A,NAK ;Negative acknowledge (what?) CALL CMOUT JMP WAIT ;**************************************************************** ;* Receive disk from remote, log on * ;**************************************************************** WTDSK: MVI A,ACK CALL CMOUT ;acknowledge command MVI B,1 ;He should be ready to send byte now CALL TIMOT ;get disk letter (A,B,C,D) JC WTNAK PUSH PSW LXI D,RSDMSG CALL PRMSG ;Tell user what is happening POP PSW MOV E,A CALL PRCHR ;Print disk remote is trying CALL CRLF CALL LOGIN ;log onto that disk JC WTNAK ;Error on disk logon, send NAK MVI A,ACK CALL CMOUT ;Gotcha, 'pardner! JMP WAIT ;**************************************************************** ;* Receive the program from remote by calling RDPGM * ;**************************************************************** WRDPGM: CALL RDPGM JMP WAIT ;Done (error or not) ;**************************************************************** ;* Remote has requested a program * ;* send ACK, get file name and type * ;* fall into the SNDPGM routine when set up * ;**************************************************************** WTSNPM: CALL RSTFCB ;Reset the file control block parameters MVI A,ACK LXI H,FCBFN ;Point to area for file name/type MVI C,11 ;# characters in name CALL CMOUT ;request name WTSNP1: CALL CMIN MOV M,A INX H DCR C JNZ WTSNP1 ;get 11 characters from remote LXI D,FCB MVI C,15 CALL 5 ;See if the file exists CPI 255 JNZ WOPNOK ;file opened ok LXI D,FOEMSG CALL PRMSG ;error in file open MVI A,NAK CALL CMOUT ;tell remote to forget it JMP WAIT WOPNOK: MVI A,ACK CALL CMOUT ;tell remote file is on its way, CALL CMIN ;remote sends an ACK when it is setup ;(ignore response) LXI D,SRFMSG CALL PRMSG ;Tell user we are sending remote a pgm CALL PRFLNM ;Print file name CALL SNFLNM ; enter SNDPGM to avoid unneeded stuff JMP WT ;**************************************************************** ;* Enter conversational mode * ;**************************************************************** WTCON: MVI A,ESC ;Acknowledge conversational mode CALL CMOUT CALL SACON JMP WT ;**************************************************************** ;* Send the remote computer our directory * ;**************************************************************** SNDIR: MVI A,0FFH STA VECTOR ;Tell PRCHR to output dir to remote LXI D,DIMSG CALL PRMSG ;Tell user what is going on LXI H,RDDMSG CALL PRHL0 ;Tell remote what drive he is on LDA DISK MOV E,A CALL PRCHR ;send remote what disk letter CALL CRLF CALL CRLF CALL DIR CALL CRLF CALL CRLF XRA A STA VECTOR ;Reset PRCHR routine MVI A,DC2 CALL CMOUT ;Tell remote we are done JMP WT ;**************************************************************** ;* Establish the remote link * ;**************************************************************** STLINK: LDA MFLG ;Get the message waiting flag CALL CMOUT ;Acknowledge control by remote LXI D,RLEMSG CALL PRMSG ;Print remote link established JMP WAIT ;**************************************************************** ;* Receive remote message * ;**************************************************************** RCVMSG: MVI A,ACK CALL CMOUT ;Acknowledge input of message LXI D,IMMSG ;Print incoming message CALL PRMSG LXI H,INBUF+2 MVI C,0 ;(C) has number of characters NXTCHR: CALL CMIN CPI ETX ;End? JZ PRNMSG ;Yes, print message MOV M,A INX H INR C JMP NXTCHR PRNMSG: LXI H,INBUF+2 ;Pointer to start of text MOV B,C ;B has # characters in message PRMS1: MOV A,M MOV E,A MVI C,2 PUSH H PUSH B CALL 5 ;Print character in string POP B POP H INX H DCR B ;Out of characters? JNZ PRMS1 JMP WAIT ;**************************************************************** ;* Send the message we left to the remote computer * ;**************************************************************** SNLVMS: LDA MFLG CPI BEL ;Did we in fact leave a message? JZ SNLVM2 LXI H,NMMSG MVI C,21 ;Remote wants a message - send him ;"No messages" message! JMP SNLMSG SNLVM2: LXI D,RRMMSG CALL PRMSG ;Tell user what is happening LXI H,INBUF+2 LDA INBUF+1 MOV C,A ;HL points to message we left SNLMSG: MOV A,M CALL CMOUT DCR C INX H JNZ SNLMSG ;Send another character MVI A,ETX CALL CMOUT ;All done MVI A,ACK STA MFLG ;Clear the messages waiting flag JMP WAIT ;**************************************************************** ;* End remote link * ;**************************************************************** ENLNK1: MVI A,DLE ;Data link escape CALL CMOUT ENLNK: LXI D,ERLMSG CALL PRMSG JMP 0 ;Exit to CP/M ;**************************************************************** ;* Acknowledge control * ;**************************************************************** ACKCN: MVI A,ACK CALL CMOUT ; Print command prompt and process command state input CNPMT: LXI SP,STACK ;Reinitialize stack (just in case) CALL CRLF LDA DISK ;Print disk we are on MOV E,A CALL PRCHR LXI D,CPMSG CALL PRMSG ;Print command mode prompt CALL CLRBUF ;Clear and zero input buffer LXI D,INBUF MVI C,10 CALL 5 ;Get command string CALL JUSLF LDA INBUF+1 ORA A JZ CNPMT CALL CLRCOM ;Clear garbage out of buffer LXI H,CMTBL ;Point to command table CALL PARSE ;Decode and execute command string ; Only errors in command string past here... LXI D,ERMSG CALL PRMSG JMP CNPMT ;**************************************************************** ;* Print directory * ;**************************************************************** CDIR: CALL DIR CALL CRLF JMP CNPMT ;**************************************************************** ;* Command state disk reset * ;**************************************************************** CRESET: CALL RESET JMP CNPMT ;**************************************************************** ;* Send the remote a program using the SNDPGM routine * ;**************************************************************** CSNDPGM:CALL INPFLN ;Get the file name ORA A JNZ CNPMT ;Error (INPFLN prints error message) LDA WILD ;Get wild card flag ORA A JNZ CSNDWLD LXI D,FCB MVI C,15 ;Try to open file CALL 5 CPI 255 JNZ CSNDPM1 ;File opened ok CALL PTNSF ;File not opened, print error JMP CNPMT CSNDPM1:CALL SNDPGM ;Send program in FCB JMP CNPMT CSNDWLD:CALL COMDIR ;Compile the directory using afn LDA NFILES ;Get number of files matching afn ORA A JNZ CSWD1 LXI D,DMTMSG CALL PRMSG ;No files match the afn he gave us JMP CNPMT CSWD1: LXI H,Buffer ;Point to directory entries CSWD2: MOV A,M CPI 0FFH ;Is this entry an extent? JZ CSWDNX ;Do next entry PUSH H ;Save pointer to file name we want CALL RSTFCB ;Reset the file control block POP H LXI D,FCBFN MVI C,11 CSWD3: MOV A,M ;Move file name to file control block STAX D INX H INX D ;Bump pointers DCR C JNZ CSWD3 SHLD BPOINT ;Save pointer to directory table for later LXI D,FCB MVI C,15 CALL 5 ;Try to find program (it should be there) CPI 255 JNZ CSWD5 CSWD4: LXI D,SIEMSG CALL PRMSG ;Print file transfer aborted JMP CNPMT CSWD5: LXI D,SNGMSG CALL PRMSG ;Print "sending....." CALL PRFLNM ;Print file name we are sending CALL SNDPGM ;Send the program LDA XERROR ;Check for errors CPI ACK JNZ CSWD4 CSWDNX: LHLD BPOINT ;File xfered ok or was extent - do next CALL BUMPHL ;Point to next directory entry SHLD BPOINT ;if extent, save so next bump will point correctly LDA NFILES DCR A ;Check number of files in table STA NFILES JNZ CSWD2 ;Send next file JMP CNPMT ;**************************************************************** ;* Get a program from the remote computer * ;* send the remote a file name, then fall into the RDPGM routine* ;**************************************************************** GTRMPM: CALL INPFLN ;input the file we want ORA A JNZ CNPMT ;goof on file name LDA WILD ;Get wild card flag ORA A JNZ GTRNA CALL CLRCOM ;Clear garbage out of buffer MVI A,DC3 CALL CMOUT ;tell remote we want a program MVI B,1 CALL TIMOT ;time out on response JC CMBOM ;BOMB OUT! GTRMP1: CPI ACK JNZ CMNAK ;Remote did not respond with a NAK LXI H,FCBFN MVI C,11 ;# characters in name GTRMP2: MOV A,M CALL CMOUT INX H DCR C JNZ GTRMP2 MVI B,16 CALL TIMOT ;allow remote enough time to check disk JC CMBOM CPI ACK JNZ GTRNE ;sorry! CALL RDPGM ;remote will start sending name JMP CNPMT GTRNE: CALL PTNSF ;print remote file does not exist JMP CNPMT GTRNA: LXI D,UFOMSG CALL PRMSG ;Unambiguous file name only JMP CNPMT ;**************************************************************** ;* Print command menu * ;**************************************************************** COHEP: LXI D,COHEMS CALL PRMSG JMP CNPMT ;**************************************************************** ;* Enter conversational mode * ;**************************************************************** COGO: MVI A,ESC ;Request conversational mode CALL CMOUT MVI B,1 ;Set time byte for TIMOT CALL TIMOT JC CMBOM ;Timed out, bomb out! CPI ESC JNZ CMNAK ;Sent NAK CALL SACON JMP CNPMT ;**************************************************************** ;* Print NAK from remote, re-enter Command state * ;**************************************************************** CMNAK: LXI D,NAKMSG ;Remote is active, sent a NAK CALL PRMSG JMP CNPMT ;**************************************************************** ;* Print no response from remote, bomb back to initial state * ;**************************************************************** CMBOM: LXI D,NOMSG ;Remote dead, no response... CALL PRMSG JMP PRMPT ;**************************************************************** ;* Print the remote directory * ;**************************************************************** GTRMDR: LXI D,DIRMSG CALL PRMSG LXI H,Dirstr ;Point to dir string MVI A,DC2 CALL CMOUT ;Say we are ready MVI B,6 ;He has to get to the directory track CALL TIMOT ;Should start sending directory ASAP JC CMBOM CPI NAK ;did he ACK or NAK? JNZ GTRD2 JMP CMNAK ;must not have this capability GTRD1: CALL CMIN ;Get character of directory GTRD2: MOV M,A CPI DC2 ;Check for end of dir JZ GTRD3 ;Done, go print dir INX H LDA 7 ;Get high addr of BDOS CMP H ;Have we run out of buffer space? JNZ GTRD1 ;No, coninue getting dir characters DCX H ;Yes, back up a byte MVI M,DC2 ;Fake end of directory LXI D,OVMSG CALL PRMSG ;Inform user we had an overflow GTRD4: MVI B,1 ;See if remote is still sending dir CALL TIMOT JC GTRD3 ;Timed out, go print dir CPI DC2 JNZ GTRD4 ;Remote ain't done yet (ho hum) GTRD3: LXI H,Dirstr CALL PRHL0 ;Print the directory now JMP CNPMT ;**************************************************************** ;* CNDISK selects disk A,B,C,D * ;**************************************************************** CNDISK: LDA INBUF+2 CALL LOGIN JMP CNPMT ;**************************************************************** ;* STRMDR selects disk on the remote computer * ;**************************************************************** STRMDR: MVI A,DC4 ;tell remote to select disk CALL CMOUT MVI B,4 ;Not long wait CALL TIMOT JC CMBOM CPI ACK JC CMNAK ;insure remote knows what we are doing LDA INBUF+3 CALL CMOUT ;send the remote the disk number MVI B,20 ;Give him 5 seconds to log on CALL TIMOT JC CMNAK ;We timed out - bomb out! CPI ACK JZ CNPMT ;We did ok LXI D,DSEMSG CALL PRMSG ;We screwed up JMP CNPMT ;**************************************************************** ;* Get the message remote left us * ;**************************************************************** INWMSG: MVI A,BEL LXI H,INBUF+2 MVI C,0 ;HL has buffer area, C has count CALL CMOUT ;Signal remote we want message INWMS1: MVI B,4 CALL TIMOT ;Give him a seconds to respond JC CMBOM ;No response JMP INWMS4 CALL CMIN INWMS4: CPI ETX ;End of text? JZ INWMS2 MOV M,A ;Stuff letter INX H INR C ;Advance pointers JMP INWMS1 INWMS2: LXI H,INBUF+2 MOV E,C ;Put the length into DE MVI D,0 DAD D ;HL points to last character in string INX H MVI M,'$' ;Stuff CP/M end-of-string LXI D,INBUF+2 CALL PRMSG ;Print string CALL CRLF JMP CNPMT ;**************************************************************** ;* Transfer control to remote * ;**************************************************************** TRCON: MVI A,DC1 ;Transfer control CALL CMOUT MVI B,1 ;Should ACK this right away CALL TIMOT JC CMBOM CPI ACK ;Control acknowledged? JNZ CNT LXI D,CTMSG CALL PRMSG ;Control transferred message JMP WT CNT: LXI D,TDCMSG CALL PRMSG JMP CMNAK ;Print control not xferd, NAK! ;**************************************************************** ;* Send a message to remote * ;**************************************************************** SNDMSG: MVI A,STX CALL CMOUT MVI B,1 ;Just acknowledge command here CALL TIMOT JC CMBOM ;remote timed out CPI ACK JNZ CMNAK ;Received ACK ok? SM1: LXI D,PMTMSG CALL PRMSG CALL MSGIN ;Get message CALL CRLF ; Now to send message LXI H,INBUF+2 LDA INBUF+1 ;Get length of message MOV C,A SMLUP: MOV A,M INX H CALL CMOUT DCR C JNZ SMLUP MVI A,0DH CALL CMOUT MVI A,0AH CALL CMOUT MVI A,ETX CALL CMOUT JMP CNPMT ;**************************************************************** ;* * ;* MAIN LINK80 SUBROUTINES * ;* * ;**************************************************************** ;**************************************************************** ;* Command parser * ;**************************************************************** ; HL is assumed to point to the start of the appropriate ; command table, organized as follows: ; ; ,,,..............,,, ; <0> - signifies end of table PARSE: MOV A,M ;Length of this entry ORA A JZ TRYDSK ;End of table, try disk command MOV B,A LXI D,INBUF+1 LDAX D ;Get length of input string CMP B JZ CHECK ;Equal, check characters NEXT: MOV E,B MVI D,0 DAD D ;Add length to pointer INX H ;Past length byte INX H INX H ;Past routine address JMP PARSE CHECK: INX H INX D ;Do next character LDAX D CPI 61H ;<"z"? JM CHECK1 SUI 20H ;Adjust lower case CHECK1: CMP M ;Equal? JZ CNTCHK DCR B ;Fixup character count JMP NEXT ;Do next command CNTCHK: DCR B JNZ CHECK ;Not done yet INX H ;Strings equal! GTOHL: MOV E,M INX H ;Get routine address MOV D,M XCHG ;HL has address to go to POP D ;Dummy pop, we called this routine PCHL ;Go to routine TRYDSK: INX H ;HL points to disk select routine PUSH H ;Save for later LXI H,INBUF+1 ;Point to start of input string MOV A,M ;Get length MOV E,A MVI D,0 ;DE has length DAD D ;Point to last character in string MOV A,M CPI ':' ;Disk select command? POP H ;Restore stack RNZ ;Input error, return LDA INBUF+1 ;Get length CPI 2 ;Disk select "d:"? JZ GTOHL ;HL has vector, exit as above CPI 3 ;Disk select "Rd:"? RNZ ;Input error, return LDA INBUF+2 CPI 'R' ;Disk select "Rd:"? RNZ ;Input error, return JMP STRMDR ;Go select remote drive ;**************************************************************** ;* TERMINAL mode subroutines * ;**************************************************************** ; Send string pointed to by HL to remote computer TOUT: MOV A,M ;Get the byte ORA A RZ ;Done on a zero byte CALL CMOUT ;Output INX H JMP TOUT ;Next ; Output halt string to remote computer, wait until it is ready THALT: LHLD Phalt## CALL TOUT ;Output the halt string LHLD Pwait## ;Get address of wait string MOV A,M ;Get first byte ORA A ;Zero? JZ THLUP ;Have to loop a bit... THWAT: CALL CMCHK ORA A JNZ THWAT1 ;Process input MVI C,11 CALL 5 ORA A JZ THWAT ;No user-provided break... MVI C,1 CALL 5 ;Retrieve user keystrike CPI ESC JNZ THWAT RET ;User has hit an escape, assume input has stopped THWAT1: CALL CMIN ;Get the byte CMP M JZ THWAT2 ;Equal, continue LHLD Pwait## ;Not equal, reset pointer and start all over JMP THWAT THWAT2: INX H MOV A,M ORA A JNZ THWAT ;Haven't reached end of string yet, keep trying RET ;Success! THLUP: MVI B,8 CALL TIMOT ;Delay 2 seconds - once we time out we can assume ;that remote output has stopped RC ;We timed out, return LHLD BPOINT MOV M,A ;Stuff another input byte... INX H ;Increment pointer SHLD BPOINT JMP THLUP ;Continue process ; Dump what we have to the disk and ; move the excess (That which is not ; enough to put on a record) down to ; the start of the buffer. Reset the ; buffer pointer to the end of this ; data and resume. TDUMP: LXI H,Buffer ;Where to start TDUMP1: LDA BPOINT+1 CMP H ;Last page yet? JNZ TDUMPIT ;No, dump this record to disk LDA BPOINT ;Check hi or lo part of page SUB L ANI 80H ;Enough for another record? JZ TDUMP2 ;Go move excess down if less than 80H; ;If less than a page but more than a record ;(80H-FFH) dump a record THEN move excess TDUMPIT:MOV D,H MOV E,L ;DE has DMA address PUSH H MVI C,26 CALL 5 ;Set DMA address LXI D,FCB MVI C,21 CALL 5 ;Write sequential record POP H ORA A ;Was write successful? JZ TDUMPC ;Yes, continue dumping records LXI D,TBDMSG CALL PRMSG ;Inform user of a bad write STC ;Set error indicator RET TDUMPC: LXI D,80H DAD D ;Advance to next page JMP TDUMP1 TDUMP2: LDA BPOINT ;Get lower byte of address pointer ANI 7FH ORA A LXI D,Buffer ;Start at beginning if even boundary JZ TDUMP5 ;We are on an even boundary LHLD BPOINT ;HL has "from" address ;DE has "to" address (Buffer) MOV A,L ANI 7FH ;Get the number of excess bytes MOV C,A MOV A,L ANI 80H ;Round the from pointer to start of page MOV L,A ;HL points to start of page TDUMP3: MOV A,M STAX D ;Move the excess data down INX D INX H DCR C ;Loop thru data JNZ TDUMP3 TDUMP5: XCHG SHLD BPOINT ;Where we will start new data STC CMC ;Reset error indicator RET ;**************************************************************** ;* Print directory * ;**************************************************************** DIR: LXI H,FCBFN MVI C,12 DIR5: MVI M,'?' ;Look for all files INX H DCR C JNZ DIR5 XRA A STA FCBDN CALL COMDIR ;Compile the directory LXI H,Buffer ;Point to entries LDA NFILES MOV C,A ;Save in C as counter ORA A JNZ DIR1 LXI H,DMTMSG MVI B,9 CALL PRHL ;Print directory empty RET DIR1: MVI B,3 ;3 entries per line DIR2: MOV A,M CPI 0FFH ;Blanked out? JZ DIR3 PUSH B ;Save counter MVI B,8 CALL PRHL ;Print name CALL SPACE MVI B,3 CALL PRHL ;Print type INX H INX H INX H ;Bump to length MOV E,M INX H MOV D,M ;Stuff length to DE CALL PRDE ;Print length POP B ;Recover counters DCR C RZ ;Check for last file CALL BUMPHL ;Go to next file at any rate DCR B PUSH PSW CZ CRLF ;Last file in line, new line POP PSW JZ DIR1 ;Reset # files in line CALL PRCOL ;Not last file in line, print colon JMP DIR2 DIR3: DCR C RZ CALL BUMPHL ;Point to next entry JMP DIR2 ;*************************************************************** ;* Bump HL to next even 16 bytes * ;*************************************************************** BUMPHL: MOV A,L ANI 0F0H ;Strip down to lower even 16 MOV L,A LXI D,16 ;Add 16 DAD D RET ;**************************************************************** ;* Prepare file for writing * ;**************************************************************** PRPFIL: LXI H,FCBRL XRA A ;Set file extent to 0 MOV M,A INX H MOV M,A INX H MOV M,A INX H MOV M,A ;Set record count to 0 LXI H,FCBCR MOV M,A ;Set next record (R/W) to 0 LXI D,FCB MVI C,17 CALL 5 CPI 255 ;Was there an existing program? JZ CRFL ;No, create one ; File already exists, see if user wants to create new ; file name or write over old file LXI D,FEMSG CALL PRMSG MVI C,1 ;Get "D" for delete or any other char CALL 5 PUSH PSW ;Save input CALL CRLF ;New line, please! POP PSW ;Recover input CPI 'D' ;Write over old file? JZ OPNRD ; Input new file name CALL CRLF PRPFL1: CALL INPFLN ORA A ;Did he botch it? JNZ RDPNAK LDA WILD ;Check for wild card ORA A JZ CRFL ;Ok, open file LXI D,UFOMSG CALL PRMSG ;No wild cards here JMP PRPFL1 ;Try again ; RDPNAK: STC RET ;Return an error condition ; CRFL: LXI D,FNEMSG CALL PRMSG ;Print new file LXI D,FCB MVI C,22 CALL 5 ;Create file in directory CPI 255 ;Error? JNZ OPNRD ; Directory full (or other error) LXI D,DFMSG CALL PRMSG JMP RDPNAK ; File ready for opening.... OPNRD: LXI D,FCB MVI C,15 CALL 5 ;Open file for writing STC CMC ;Reset error condition RET ;**************************************************************** ;* Recieve program from remote * ;**************************************************************** RDPGM: LXI D,PGMMSG CALL PRMSG ;Print incoming program MVI A,ACK LXI H,FCBFN ;Read in the file name MVI C,11 CALL CMOUT ;Tell remote we want name RDPM1: CALL CMIN MOV M,A INX H DCR C JNZ RDPM1 CALL PRFLNM ;Print name of incoming program ; File name is in FCB, see if it is on disk... CALL PRPFIL ;Prepare file for writing JNC RDPM2 ;No errors, send ACK MVI A,NAK CALL CMOUT ;Error in file preparation RET ; Send to remote RDPM2: MVI A,10 STA PASS MVI A,ACK CALL CMOUT LXI H,1 ;Start at record 1 SHLD RECNUM ; File is set up for writing. Remote will now send one ; of three command bytes: ; - one 128 byte data block with CRC ; - remote file error, crash! ; - end of transmission, file transfer complete RDBLOK: CALL CMIN CPI SOH JZ RDATA ;Get data block CPI NAK JZ RDCRSH ;Read crash, close everything down CPI EOT JZ ENDRD ;End read, close file MVI A,NAK CALL CMOUT ; on last command byte RDCRSH: LXI D,FCB MVI C,19 CALL 5 ;Delete that file LXI D,RERMSG CALL PRMSG ;Signal remote error RET ENDRD: CALL CRLF ;Done, next line after record number LXI D,FCB MVI C,16 CALL 5 ;Close file LXI D,EOFMSG CALL PRMSG ;Signal file xfer successful MVI A,ACK CALL CMOUT ;Acknowledge end of file RET ; Read program data RDATA: CALL PRRNM ;Print record number and junk LXI H,80H ;DMA buffer MVI C,80H ;Number of bytes to read MVI B,0 ;Zero CRC byte MVI A,SOH CALL CMOUT RDAT1: CALL CMIN MOV M,A ADD B ;Update CRC byte MOV B,A INX H DCR C JNZ RDAT1 CALL CMIN ;Get CRC byte CMP B ;Same? JZ STDAT ;Yes, store data LDA PASS DCR A ;Last pass? JZ HDRDER STA PASS MVI A,BEL ;Signal remote we want last rec again CALL CMOUT JMP RDBLOK ; Failed sending record 10 times, bomb out HDRDER: CALL CRLF LXI D,FCB MVI C,16 CALL 5 ;Delete file MVI A,NAK CALL CMOUT ; to remote LXI D,CRCMSG CALL PRMSG ;Signal remote link unstable RET STDAT: LXI D,FCB MVI C,21 CALL 5 ;Write this record onto disk ORA A JZ DATGUD ;Successful write ; Did not successfully write this record - report error CALL CRLF CPI 1 LXI D,EXTMSG JZ RDERRP ;Report extend error CPI 2 LXI D,EDDMSG JZ RDERRP ;Report end of disk data error CPI 255 LXI D,DFMSG JZ RDERRP ;Report no directory space LXI D,FLERMG RDERRP: CALL PRMSG ;Report error MVI A,NAK CALL CMOUT ;Signal remote we had an error LXI D,FCB MVI C,19 CALL 5 ;Delete file RET DATGUD: MVI A,10 STA PASS LDA DISK CALL LOGIN ;Re-login disk LHLD RECNUM INX H SHLD RECNUM ;Increment record number MVI A,ACK CALL CMOUT ; good data JMP RDBLOK ;Wait for next command byte from remote ;**************************************************************** ;* Print no such file and filename in FCB * ;**************************************************************** PTNSF: LXI D,FOEMSG CALL PRMSG ;Print no such file CALL PRFLNM ;Print file name RET ;**************************************************************** ;* Send program to remote computer * ;**************************************************************** SNDPGM: CALL CLRCOM ;Clear garbage out of buffer MVI A,SOH CALL CMOUT MVI B,8 ;Give him a few seconds to print message CALL TIMOT JC OPNOK1 ;Remote time-out CPI ACK ;Remote acknowledged input? JZ SNFLNM OPNOK1: LXI D,NAKMSG CALL PRMSG ;Print from remote JMP CLSFLE ;Close file and return ; Send filename to remote computer SNFLNM: MVI A,NAK ;Assume error, routine STA XERROR ; must have correct CRC & force non-error LXI H,FCBFN ;Point to filename MVI C,11 ;Number of characters in file (name+type) NMLP: MOV A,M ANI 7FH ;CP/M 2.0 does funny things to bits! CALL CMOUT INX H DCR C JNZ NMLP LXI H,0 ;Start at 1 (1-1) SHLD RECNUM MVI A,10 STA PASS ;Set pass count (used for *'s in xmit) ; Wait for remote to acknowledge file name CALL CMIN CPI ACK JNZ OPNOK1 ; Send program in 128 byte blocks plus CRC SNPGM1: LHLD RECNUM INX H SHLD RECNUM ;Increment record number LXI D,FCB MVI C,20 CALL 5 ;Read one record CPI 0 JZ SNPM2 ;No errors CPI 1 JZ ENDSND ;End program LXI D,FIEMSG CALL PRMSG ;File input error ; Error, tell remote we goofed and exit SNAK: MVI A,NAK CALL CMOUT ;Tell remote we goofed JMP CLSFLE ; One record in, send: ; ; wait for ; 128 data bytes ; CRC ; wait for SNPM2: CALL PRRNM ;Print record number and junk MVI C,11 CALL 5 ;Check for user input ORA A JZ SNPM3 ;No input, continue LXI D,SABMSG CALL PRMSG ;Print abort message MVI C,1 CALL 5 ;Get input CPI ESC PUSH PSW CALL CRLF ;CRLF at any rate POP PSW JNZ SNPM3 ;Continue LXI D,SIEMSG CALL PRMSG ;Print xfer aborted JMP SNAK SNPM3: MVI A,SOH CALL CMOUT ;Send LXI H,80H MVI C,80H ;number of bytes to send per record MVI B,0 ;Clear CRC CALL CMIN SNLP1: MOV A,M CALL CMOUT ;Send program byte ADD B ;Update CRC MOV B,A ;Register B has the CRC INX H DCR C JNZ SNLP1 CALL CLRCOM ;Get rid of any junk we may have recieved MOV A,B CALL CMOUT ;Send CRC MVI B,32 ;He has to stuff on disk, leave 8 seconds CALL TIMOT ;Get the remote sent (hopefully) JNC SNLP2 ;We have something... ; We timed out on a wait for remote acknowledge of this ; record. Continue to send nulls until a is received ; If something else comes in, BOMB OUT! SNWT: XRA A CALL CMOUT ;Send a null MVI B,2 ;He should give a NAK as soon as bad data ;is found, don't wait long CALL TIMOT JC SNWT ;Loop until remote sends us something CPI BEL JZ SNLP3 ;We can recover, remote sent JMP SNAK ;BOMB OUT ; Remote sent us a byte after the record and CRC. ; Check to see what it is and process accordingly. SNLP2: CPI ACK ;See if the character is an JZ SNLP4 ;Last 128 received OK CPI BEL JZ SNLP3 ;Dcr pass count and try again SNAK1: CALL CRLF LXI D,RERMSG CALL PRMSG ;Report hard error JMP CLSFLE ;Close the file SNLP3: LXI H,PASS DCR M ;Decrement pass count JMP SNPM2 ;Go try again SNLP4: MVI A,10 STA PASS ;Reset pass count for next record JMP SNPGM1 ENDSND: MVI A,EOT ;End of transmission CALL CMOUT CALL CMIN CPI ACK ;Acknowledge? JZ CLSFL CALL CRLF JMP OPNOK1 CLSFL: MVI A,ACK STA XERROR ;Signal non error condition CALL CRLF LXI D,EOFMSG CALL PRMSG CLSFLE: LXI D,FCB MVI C,16 CALL 5 ;Close the FCB file RET ;**************************************************************** ;* Compile directory list using ambiguous file name in FCB * ;* Stuff number of files in NFILES, names in Buffer * ;**************************************************************** COMDIR: XRA A STA FCBDN ;We want current disk STA NFILES ;Clear number of files LXI H,Buffer SHLD BPOINT ;Buffer pointer MVI A,3FH STA 68H LXI D,5CH MVI C,11H CALL 5 ;Find first file CPI 0FFH ;Did any files exist? RZ ;Return with NFILES set to 0 CMDR1: LXI H,NFILES INR M ;Increment number of files MVI B,0 ;Convert byte address to pointer to name ANI 3 RRC RRC RRC INR A ;Compensate for disk drive MOV C,A ;Stuff offset into BC LXI H,80H DAD B ;HL now points to name XCHG LHLD BPOINT ;Get address of buffer pointer MVI C,16 ;Number of characters per file name CMDR2: LDAX D MOV M,A ;Transfer a byte INX D INX H ;Knock pointers DCR C JNZ CMDR2 ;Loop thru 16 characters DCX H MVI M,0 ;Zero upper length byte INX H SHLD BPOINT ;Resave our buffer pointer LXI D,5CH MVI C,12H CALL 5 ;Find next file CPI 0FFH JNZ CMDR1 ;There was a file, stuff it ; All files now in memory, add extent lengths and delete them LXI H,Buffer ;Point to start of buffer LDA NFILES MOV C,A ;C has number of files to work on CMDR3: LXI D,11 ;Offset to extent DAD D MOV A,M ;Get extent LXI D,-11 DAD D ;Restore pointer to file name ORA A PUSH B ;Save number of files left to process JZ CMDR7 ; Entry is an extent, find extent 0, add lengths, delete this entry LXI D,14 ;Offset to length DAD D MOV B,M ;Get length LXI D,-14 DAD D ;Restore pointer LXI D,Buffer LDA NFILES MOV C,A ;Number of files to check for match CMDR4: LDAX D CMP M ;Bytes equal? JNZ CMDR5 INX H INX D MOV A,E ANI 0FH ;Mask upper nibble CPI 11 ;Done checking yet? JNZ CMDR4 LDAX D ;Get extent (should be zero) ORA A JNZ CMDR5 ;This isn't extent zero, bomb out MOV A,L ANI 0F0H MOV L,A MVI M,0FFH ;Scratch the extent PUSH H INX D INX D INX D ;Point to # records field PUSH D ;Save pointer to # records XCHG MOV E,M INX H MOV D,M ;DE has length of the 0th extent XCHG ;Transfer to HL MOV E,B MVI D,0 ;Stuff DE with length of extent DAD D ;Add the extent to the base XCHG POP H ;HL has pointer to # records MOV M,E INX H MOV M,D ;Stuff new length POP H ;Recover working file pointer JMP CMDR7 ;Done fixing, next file CMDR5: DCR C ;Bump number of files left to check JZ CMDR8 ;We have checked all files, no extent 0 PUSH H ;Save pointer XCHG ;HL has pointer to test record CALL BUMPHL ;Reset pointer to start of next record XCHG ;DE should have it POP H MOV A,L ANI 0F0H MOV L,A ;Restart at beginning of record JMP CMDR4 CMDR7: MOV A,L ANI 0F0H MOV L,A ;Restore to start of record LXI D,16 DAD D ;Point to next record POP B ;Recover number of files left to work on DCR C JNZ CMDR3 ;Go do next file RET ; Hmmmm - extent 0 not found for this ; extent - someone is wierd. ; Process this extent by itself, make ; it 0, add number of records CMDR8: MOV A,L ANI 0F0H ;Restore to start of record MOV L,A LXI D,11 DAD D MOV A,M ;Get this extent number MVI M,0 ;While we are here, erase extent number INX H INX H INX H ;Bump to length PUSH H ;Save pointer to length LXI H,0 LXI D,80H CMDR9: DAD D DCR A ;Compute number of records for this extent JNZ CMDR9 PUSH H POP B ;BC=#records POP H ;Recover pointer to length PUSH H ;Resave MOV E,M INX H MOV D,M ;DE=leftover records XCHG DAD B ;HL has total number of records XCHG ;To DE POP H ;Recover pointer to length MOV M,E ; INX H ;Stuff actual # of records MOV M,D ; JMP CMDR7 ;**************************************************************** ;* Print DE in decimal in a 5 digit, right justified field * ;* (Adapted from 8080/8085 Software Design, Chris Titus) * ;**************************************************************** PRDE: PUSH H PUSH B ;Save pointers LXI H,UNITS ;Temporary storage area for ASCII string MVI C,5 XRA A STA ZGONFLG ;Leading zero blanking flag PRDE1: MVI M,' ' INX H DCR C ;Blank ASCII field JNZ PRDE1 DCX H ;Point to tens of thousands LXI B,-10000 CALL DIGIT ;Figure tens of thousands LXI B,-1000 CALL DIGIT ;Figure thousands LXI B,-100 CALL DIGIT ;Figure hundreds LXI B,-10 CALL DIGIT ;Figure tens MOV A,E ORI '0' ;Remainder is ones, make ASCII MOV M,A ;and stuff LXI H,UNITS+4 MVI C,5 PRDE2: MOV E,M ;Get character CALL PRCHR DCX H ;Bump pointer DCR C JNZ PRDE2 ;Loop thru digits POP B POP H ;Restore pointer RET DIGIT: PUSH H ;Save pointer to 5 digit area XCHG DAD B ;Subtract by adding 2's complement JNC ADDIT ;NC indicates less than test value XCHG POP H ;Restore pointer INR M ;Increment digit MVI A,0FFH STA ZGONFLG ;Kill leading zeroes flag JMP DIGIT ADDIT: MOV A,C ;Change sign of test value in BC CMA MOV E,A MOV A,B CMA MOV D,A ;DE = ABS(BC) INX D DAD D ;Restore value XCHG ;To DE POP H LDA ZGONFLG ORA A JZ DRET ;Non-zero has been encountered MOV A,M ORI '0' ;Convert to ASCII MOV M,A DRET: DCX H ;Do next digit RET ;**************************************************************** ;* Print the character in the E register * ;**************************************************************** PRCHR: PUSH H PUSH D PUSH B PUSH PSW MOV A,E ;Get character ANI 7FH ;Get rid of 2.0 bits MOV E,A ;Restore LDA VECTOR ORA A ;Check output vector JZ PRCHR1 ;Remote doesn't get this one MOV A,E CALL CMOUT ;Call comout routine PRCHR1: MVI C,2 CALL 5 POP PSW POP B POP D POP H RET ;**************************************************************** ;* Print a space * ;**************************************************************** SPACE: MVI E,20H CALL PRCHR RET ;**************************************************************** ;* Input a character from console with no echo * ;**************************************************************** EKONI: LHLD 1 ;Get warm start address from CBIOS LXI D,6 ;Offset to console input DAD D ;HL has address of console input routine PCHL ;Use routine's RET to get back ;**************************************************************** ;* Print memory at (HL) for the number of bytes in (B) * ;**************************************************************** PRHL: MOV E,M CALL PRCHR INX H DCR B JNZ PRHL RET ;**************************************************************** ;* Print message at DE to $ using CP/M * ;**************************************************************** PRMSG: MVI C,9 CALL 5 ;Go to CP/M and print it RET ;**************************************************************** ;* Print memory at (HL) until DC2 * ;**************************************************************** PRHL0: MOV E,M MOV A,E CPI DC2 RZ CALL PRCHR INX H JMP PRHL0 ;**************************************************************** ;* Print a colon * ;**************************************************************** PRCOL: CALL SPACE MVI E,3AH ;Ascii colon CALL PRCHR CALL SPACE RET ;**************************************************************** ;* Returns zero if buffer at M(DE) equals input buffer * ;**************************************************************** BFCHK: LXI H,INBUF+2 LDA INBUF+1 ;Get the number of characters CPI 2 JNZ NMTCH MOV C,A XCHG ;Move input pointer to DE BFCHK1: LDAX D CPI 61H JM BFCHK2 SUI 20H ;upper case, please! BFCHK2: CMP M JNZ NMTCH DCR C JZ MATCH INX H INX D JMP BFCHK1 NMTCH: XRA A INR A RET MATCH: XRA A RET ;**************************************************************** ;* Reset the file control block for a new file * ;**************************************************************** RSTFCB: MVI C,11 LXI H,FCBFN ;Fill file name and type with blanks RSTFCB1:MVI M,' ' INX H DCR C JNZ RSTFCB1 ; Insert zeroes into the FCB area XRA A STA FCB ;Use disk we are on LXI H,FCBRL ;Start on reel number MVI C,21 INZLP: MOV M,A INX H DCR C JNZ INZLP RET ;**************************************************************** ;* Input a file name, parse into file control block * ;* If name is preceded by disk number (A:), parse that * ;* out and log into that disk. * ;**************************************************************** ; First get a string to the buffer area INPFLN: LXI D,FNMMSG CALL PRMSG ;Prompt for file name LXI D,INBUF MVI C,10 CALL 5 ;Input string to buffer area CALL CRLF ;Next line, please! CALL RSTFCB ;Reset the file control block LXI H,INBUF+1 MOV B,M ;B has length of input string LDA INBUF+3 ;Get second character in string CPI ':' ;Disk specified? LXI H,INBUF+2 JNZ PRSNAM ;No, HL points to start of name MOV A,M CALL LOGIN ;Log in to disk DCR B DCR B ;Compensate for disk name LXI H,INBUF+4 ; HL points to start of file name in buffer ; B has length of input PRSNAM: XRA A STA FCBDN ;Record number = 0 STA WILD ;Reset wildcard LXI D,FCBFN MVI C,9 PSNM1: MOV A,M ;Transfer filename (up to 8 chars) INX H CPI '.' JZ PRSTYP ;It was a '.', parse filetype CPI '?' JZ PSNM3 ;It was a '?', set wildcard and stuff CPI '*' JNZ PSNM4 ;Check for asterisk wildcard option STA WILD ;Wildcard set DCR C ;C has number of characters to stuff MVI A,'?' PSNM5: STAX D INX D DCR C JNZ PSNM5 DCR B JZ PSTP2 ;Didn't specify file type MOV A,M INX H CPI '.' JNZ PSNM2 ;Error in filename, should be a '.' here JMP PRSTYP ;Go parse file type PSNM3: STA WILD ;Stuff wildcard option PSNM4: STAX D INX D DCR B JZ PSTP2 ;Didn't specify file type, leave it blank DCR C JNZ PSNM1 PSNM2: LXI D,NTLMSG ;Error in filename CALL PRMSG MVI A,255 ;Set error return RET PRSTYP: DCR B ;B has number of characters in type MVI C,4 ;# characters in file type (-1) LXI D,FCBFT PSTP1: MOV A,M INX H CPI '?' ;Check for wildcard JZ PSTP3 CPI '*' ;Check for wildcard JNZ PSTP4 DCR C ;C has number of characters to stuff STA WILD MVI A,'?' PSTP5: STAX D ;Finish stuffing filetype with '?' INX D DCR C JNZ PSTP5 DCR B JZ PSTP2 ;* should be last character in string JMP PSNM2 PSTP3: STA WILD PSTP4: STAX D INX D DCR B JNZ PSTP1 PSTP2: XRA A ;Zero error flag RET ;**************************************************************** ;* Input a message terminated by escape into buffer at INBUF * ;* Character count at INBUF+1, message starts at INBUF+2 * ;**************************************************************** MSGIN: LXI H,INBUF+1 ;HL points to length MVI M,0 ;Zero to start LXI D,INBUF+2 ;DE points to message MSGIN1: PUSH H PUSH D MVI C,1 CALL 5 ;Read in a character POP D POP H CPI ESC ;End of string? RZ CPI BS ;Check for each kind of backspace JZ BKMSG CPI DEL JZ BKMSG CPI DEL-20H ;Cap lock delete! JZ BKMSG CPI CR ;If carriage return, add line feed JNZ MSGIN2 STAX D INX D INR M MVI A,LF PUSH H PUSH D PUSH PSW MOV E,A MVI C,2 CALL 5 POP PSW POP D POP H MSGIN2: STAX D INX D INR M JMP MSGIN1 BKMSG: LDA INBUF+1 ;Get present string length ORA A JZ MSGIN1 ;Already zero, start over DCX D DCR M JMP MSGIN1 ;Decrement pointer, counter ;**************************************************************** ;* Wait for input from remote - after timeout, set carry flag=0 * ;* 0 if we got data, carry=1 if time out. * ;* B=1 is about 1/4 second for 2 Mhz... * ;**************************************************************** TIMOT: PUSH H ;Save timing registers PUSH B LHLD Speed## ;Get CPU speed from LINKSBS MOV A,M CPI 2 ;2 Mhz? JZ TIMLUP ;B has correct value MOV A,B RAL ;Double B for 4 Mhz MOV B,A ;Restore B TIMLUP: LXI H,13 ;Timing value for wait loop TMLP1: CALL CMCHK ANA A ;Set flags JNZ TIMED ;We have some input DCR H JNZ TMLP1 ;Loop thru H DCR L JNZ TMLP1 ;Loop thru L DCR B JNZ TIMLUP ;Loop thru B XRA A ;Clear data STC ;Set error byte POP B POP H RET ;Return from timing loop TIMED: POP B ;Restore BC POP H CALL CMIN ;Get the data STC CMC ;Reset error byte RET ;**************************************************************** ;* Print the file name in the FCB * ;**************************************************************** PRFLNM: MVI B,8 LXI H,FCBFN PRFLN1: MOV E,M MOV A,E CPI 20H JZ PRFLN2 CALL PRCHR DCR B INX H JNZ PRFLN1 PRFLN2: MVI E,'.' CALL PRCHR MVI B,3 LXI H,FCBFT ;print file type PRFLN3: MOV E,M CALL PRCHR DCR B INX H JNZ PRFLN3 CALL CRLF RET ;**************************************************************** ;* Clear the communications channel * ;**************************************************************** CLRCOM: PUSH PSW PUSH B PUSH D PUSH H CALL Clrcm1## POP H POP D POP B POP PSW RET ;**************************************************************** ;* Output a byte to the remote computer * ;**************************************************************** CMOUT: PUSH PSW PUSH B PUSH D PUSH H CALL Cmout1## POP H POP D POP B POP PSW RET ;**************************************************************** ;* Check remote input * ;**************************************************************** CMCHK: PUSH B PUSH D PUSH H CALL Cmchk1## POP H POP D POP B RET ;**************************************************************** ;* Input a byte from the remote computer * ;**************************************************************** CMIN: PUSH B PUSH D PUSH H CALL Cmin1## POP H POP D POP B RET ;**************************************************************** ;* CRLF * ;**************************************************************** CRLF: MVI E,0DH CALL PRCHR JUSLF: MVI E,0AH CALL PRCHR RET ;**************************************************************** ;* Login to disk in (A) * ;**************************************************************** LOGIN: PUSH B PUSH D PUSH H LHLD Drives## ;Point to string of correct drive letters MOV C,A ;Put drive letter into C LOGIN2: MOV A,M CMP C JZ LOGIN1 ;We have a good drive letter ORA A INX H JNZ LOGIN2 ;Keep trying LXI D,DSEMSG CALL PRMSG ;Print drive select error STC ;Return error code JMP LOGIN3 LOGIN1: STA DISK ;We have a good drive letter, log into it ANI 01FH ; (Version 1.68 fix.) SBI 1 MOV E,A MVI C,14 CALL 5 STC CMC LOGIN3: POP H POP D POP B RET ;**************************************************************** ;* Clear and zero input buffer * ;**************************************************************** CLRBUF: LXI H,INBUF+1 MVI C,254 XRA A CLR1: MOV M,A INX H DCR C JNZ CLR1 RET ;**************************************************************** ;* Print the record number we are on and an asterisk (*) * ;* for each entry we have had to resend (max is ten stars) * ;**************************************************************** PRRNM: LXI D,RECMSG CALL PRMSG ;Print "Record number" LHLD RECNUM XCHG CALL PRDE ;Print record number CALL SPACE LDA PASS ;Get the pass count MOV B,A MVI A,10 SUB B ;A has number of * to print MOV B,A MVI C,10 ;Number of chars to print PLUP: MOV A,B ORA A JZ PSPC PUSH B MVI E,'*' CALL PRCHR ;Print the star POP B DAST: MOV A,B ORA A JZ DAST1 DCR B DAST1: DCR C JNZ PLUP RET PSPC: PUSH B CALL SPACE POP B JMP DAST ;**************************************************************** ;* Conversational mode for two LINK80 users * ;**************************************************************** SACON: LDA PLXFLG PUSH PSW ;Save duplex LDA AFLG PUSH PSW ;Save auto line-feed toggle MVI A,0FFH STA PLXFLG ;Set conversation to half duplex so we can see it too STA AFLG ;Set auto line-feed toggle to on so cr = crlf CALL CON ;Do the conversation POP PSW STA AFLG ;Restore auto line-feed toggle POP PSW STA PLXFLG ;Restore duplex RET ;**************************************************************** ;* Conversational mode * ;**************************************************************** CON: LXI D,CONMSG ;Print entering conversational mode CALL PRMSG CONV: CALL CMCHK ;Character waiting from remote? JNZ GTCHR LHLD 1 ;Get relative address of CBIOS table LXI D,3 ;Vector to CONST DAD D ;Have to go around CP/M here LXI D,CONV1 ;Fake the return address PUSH D PCHL ;Go check for keyboard input CONV1: ORA A ;Keyboard input? JZ CONV ; Process keyboard input LDA PLXFLG ORA A JNZ CRED ;Half duplex - echo character on screen CALL EKONI ;Full-duplex - get a character JMP CRED2 CRED: MVI C,1 CALL 5 ;Get character from keyboard and echo on screen ;Have character, check for control-A CRED2: CPI SOH JNZ CRED1 ;Check for control-A key LDA TFLG ORA A ;Zero flag set if in conv mode RNZ ;We were in TERM mode, exit and print menu JMP CRED3 ;He wants to send remote control-A (?) ;Check for escape CRED1: CPI ESC JNZ CRED3 ;No escape, send character LDA TFLG ORA A ;Zero flag set if in conv mode MVI A,ESC ;Restore the escape character JNZ CRED3 ;We are in TERM mode, send the escape to remote CALL CMOUT ;Terminate conversational mode RET CRED3: CALL CMOUT ;Output the character CPI CR JNZ CONV ;Not a CR LDA AFLG ORA A CNZ JUSLF ;Auto-linefeed flag set JMP CONV ; Process remote input GTCHR: CALL CMIN MOV E,A CPI ESC JNZ GTCHR1 ;Not an escape, go print character LDA TFLG ORA A RZ ;We were in conv mode, exit routine MVI A,ESC ;Remote computer sent us this ESC GTCHR1: CALL PRCHR CPI CR JNZ CONV ;Not a CR, don't worry about LF LDA TFLG ORA A JZ GTCHR2 ;We are in conversational mode, print LF LDA AFLG ORA A JZ CONV ;Terminal mode didn't want auto-line feed GTCHR2: CALL JUSLF ;Print the linefeed JMP CONV ;**************************************************************** ;* Reset both disks * ;**************************************************************** RESET: MVI C,13 CALL 5 ;Initialize BDOS MVI A,'A' STA DISK ;Current disk is A RET ;**************************************************************** ;* Convert character in A to upper case * ;**************************************************************** CTUC: CPI 'a' RM CPI 'z'+1 RP SUI ' ' RET ;**************************************************************** ;* * ;* LINK80 messages * ;* * ;**************************************************************** CPMSG: DB ':LINK>$' NAKMSG: DB 'Negative acknowledgement of command from remote',CR,LF,'$' NOMSG: DB 'No response from remote',CR,LF DB 'Returning to INITIAL state',CR,LF,'$' CTMSG: DB 'Control transferred to remote',CR,LF,'$' RERMSG: DB 'Remote error, transfer aborted',CR,LF,'$' FNMMSG: DB 'File name: $' CONMSG: DB CR,LF,'Entering conversational mode',CR,LF,LF,'$' FIEMSG: DB 'File access error - Transfer aborted',CR,LF,'$' TIEMSG: DB CR,LF,'',CR,LF,'$' TIMSG: DB CR,LF,'',CR,LF DB '',CR,LF,'$' SABMSG: DB CR,LF,'User break in file transfer',CR,LF DB 'Hit the escape key to abort file transfer',CR,LF,'$' ABMSG: DB CR,LF,'',CR,LF DB '',CR,LF,'$' TABMSG: DB CR,LF,'',CR,LF DB '',CR,LF DB '',CR,LF,'$' TBDMSG: DB CR,LF,'',CR,LF,'$' OVMSG: DB CR,LF,'',CR,LF,'$' TCNTMG: DB CR,LF,'',CR,LF,'$' TIDMSG: DB CR,LF,'',CR,LF,'$' TREMSG: DB '',CR,LF,'$' FEMSG: DB 'File already exists',CR,LF DB 'Delete old file (D) or create new file (N) ? $' CRCMSG: DB 'LINK80 connection unstable',CR,LF SIEMSG: DB 'File transfer aborted',0AH,0DH,'$' EXTMSG: DB 'Error on extending file',CR,LF,'$' EDDMSG: DB 'Disk full',CR,LF,'$' FLERMG: DB 'File error',CR,LF,'$' UFOMSG: DB 'Only unambiguous file names allowed',CR,LF,'$' DSEMSG: DB CR,LF,'Drive select error',CR,LF,'$' PMTMSG: DB CR,LF,'Enter message terminated by "ESC":',CR,LF,LF,'$' DIMSG: DB 'Sending remote directory of logged-on disk',CR,LF,'$' DIRMSG: DB CR,LF,'Requesting remote directory',CR,LF,'$' MWFCMG: DB 'Previous message left has been erased',CR,LF,'$' NOTMSG: DB 'Remote link not established',CR,LF,'$' SRFMSG: DB 'Sending remote file:$' MSWTMS: DB 'Messages waiting',CR,LF,'$' RRMMSG: DB 'Remote requesting message',CR,LF,'$' NMMSG: DB 'No messages waiting',CR,LF RLEMSG: DB 'Remote link established',CR,LF,'$' ERMSG: DB 'What?',CR,LF,'$' BFMSG: DB CR,LF,'',CR,LF,'$' RDDMSG: DB CR,LF,'Remote directory - drive ',DC2 IMMSG: DB 'Incoming message',CR,LF,'$' ERLMSG: DB 'End remote link',CR,LF,'$' FOEMSG: DB 'No file present - $' RSDMSG: DB 'Remote selecting drive $' DFMSG: DB 'Directory full',CR,LF,'$' NTLMSG: DB 'File name error',CR,LF,'$' TDCMSG: DB 'Control not transferred',CR,LF,'$' PGMMSG: DB 'Incoming program - $' FNEMSG: DB 'New file',CR,LF,'$' SNGMSG: DB 'Sending $' DMTMSG: DB 'No file',CR,LF,'$' EOFMSG: DB 'File transfer successful',CR,LF,'$' RLBMSG: DB CR,LF,'Remote link broken',CR,LF,'$' WATMSG: DB 'Entering wait state',CR,LF,'$' TEMSG: DB CR,LF,'Entering TERMINAL mode',CR,LF DB 'Hit "Control-A" for LINK80 attention',CR,LF,LF,'$' ONMSG: DB '(on)$' OFMSG: DB '(off)$' HAFMSG: DB '(Half)$' FULMSG: DB '(Full)$' TAMSG: DB CR,LF,LF,'A - Auto-line feed toggle $' TCMSG: DB CR,LF,'D - Duplex toggle $' TBMSG: DB CR,LF,'M - terminal mode auto-menu toggle (on)',CR,LF DB 'B - Reinitialize serial port',CR,LF DB 'S - Output a file to remote mainframe',CR,LF DB 'R - Reset disks',CR,LF DB 'I - Input a file from remote mainframe',CR,LF DB 'E - Output the "control-A" character to the remote mainframe',CR,LF DB 'Hit escape to return to the INITIAL state',CR,LF DB 'Hit space bar to continue',CR,LF,LF DB 'Command? $' INHEMS: DB CR,LF,'You are in the INITIAL state -',CR,LF DB 'Commands available in this state are:',CR,LF DB ' WAIT - Enter the wait state',CR,LF DB ' MESS - Leave message and enter wait state',CR,LF DB ' INQ - Inquire remote to enter command state',CR,LF DB ' DIR - Print directory of logged-on disk',CR,LF DB ' HELP - Print this menu',CR,LF DB ' TERM - Enter Terminal mode',CR,LF DB ' d: - Log onto disk ',CR,LF DB '$' COHEMS: DB CR,LF,'You are in the COMMAND state -',CR,LF DB 'Commands available in this state are:',CR,LF DB ' INIT - Enter the initial state',CR,LF DB ' MESS - Send message terminated by "ESC" to remote',CR,LF DB ' TR - Transfer control to remote',CR,LF DB ' CO - Enter conversational mode',CR,LF DB ' SEND - Send program to remote',CR,LF DB ' DIR - Print directory of logged-on disk',CR,LF DB ' RDIR - Print remote directory',CR,LF DB ' BYE - End remote link',CR,LF DB ' ? - Get message left by remote',CR,LF DB ' GET - Get program from remote',CR,LF DB 'RESET - Reset disks',CR,LF DB ' d: - Log onto disk ',CR,LF DB ' Rd: - Log onto remote disk ',CR,LF DB '$' RECMSG: DB 0DH,'Record number $' ;**************************************************************** ;* INITIAL state command table * ;**************************************************************** INTBL: DB 3,'INQ' DW INQ ; Inquire remote DB 4,'WAIT' DW WT ; Enter wait state DB 4,'MESS' DW LVMSG ; Leave message and enter wait state DB 4,'HELP' DW INHEP ; Print menu DB 4,'TERM' DW TERM ; Enter TERMINAL mode DB 3,'DIR' DW IDIR ; Print directory DB 0 ; End of table DW STDISK ; Variable disk select command "d:" ;**************************************************************** ;* COMMAND state command table * ;**************************************************************** CMTBL: DB 2,'TR' DW TRCON ;Transfer control to remote DB 4,'MESS' DW SNDMSG ;Send message DB 4,'SEND' DW CSNDPGM ;Send program to remote DB 1,'?' DW INWMSG ;List waiting message DB 2,'CO' DW COGO ;Converse DB 3,'BYE' DW ENLNK1 ;End remote link DB 4,'RDIR' DW GTRMDR ;List remote directory DB 3,'GET' DW GTRMPM ;Get program from remote DB 4,'INIT' DW PRMPT ;Enter initial state DB 4,'HELP' DW COHEP ;Print menu DB 3,'DIR' DW CDIR ;Print directory DB 5,'RESET' DW CRESET ;Reset disks DB 0 ;End of table DW CNDISK ;Variable disk select command "d:" ; STORAGE AREAS XERROR: DB NAK ;Error flag for file transmit routine TMFLG: DB 0FFH ;TERMINAL mode auto-menu toggle AFLG: DB 0 ;Auto-linefeed toggle, initialize at off(0=off, ff=on) WILD: DB 0 ;Wildcard; =ff when wildcard file name entered NFILES: DB 0 ;Number of files indicated by wildcard TFLG: DB 0 ;TERMINAL mode flag PLXFLG: DB 0 ;Duplex flag, initialize at full-duplex (fd=0, hd=ff) VECTOR: DB 0 ;Vector for PRCHR ; If 0, output on screen ; If not, output to screen and remote ZGONFLG:DB 0 ;Leading zero blank flag for PRDE UNITS: DS 5 ;Storage areas for PRDE RECNUM: DW 0 ;Number of records LINK80 has sent DISK: DB 'A' ;Current disk PASS: DB 10 ;Number of passes before file xfer aborts BPOINT: DW Buffer ;Pointer to buffer for TERM mode STAK: DS 2 ;Stack pointer save area NUM: DS 1 ;Number crunching area for DIR routine NUM1: DS 1 NUM2: DS 1 ; INPUT Buffers INBUF: DB 255 ;255 character input buffer DB 0 ;Current length of input buffer DS 255 ;Space for input buffer MFLG: DB ACK ;Message waiting flag DS 80H ;Stack space STACK EQU $ Dirstr EQU 02700H Buffer EQU Dirstr END START