; m4add/asm ; ; Input a line from a take file ; DOTAKE EQU $ LD HL,CMDBUF ;WHERE TO PUT THE TEXT LD B,0 ;CHARACTER COUNTER CALL CONIN IFA 128,TAKERR ;Jump if break was pressed TAKLOP LD DE,TFCB ;FCB FOR TAKE FILE CALL XGET ;Call @GET svc JR NZ,TAKERR ;QUIT ON AN ERROR LD (HL),A ;SAVE THE CHARACTER INC HL ;POINT TO THE NEXT INC B ;ADD TO CHARACTER COUNT IFA CR,TAK020 ;Go if at the end of string LD C,A LD A,(TAKLOG) ;IS DISPLAY OF TAKE FILES ON? OR A LD A,C CALL NZ,CONOUT JR TAKLOP TAK020 RET ;RETURN WITH THE STRING TAKERR LD DE,TFCB ;GET READY TO CLOSE THE FILE CALL XCLOSE ;Close the file XOR A ;TURN THE TAKE FLAG OFF LD (TAKFLG),A ;RESET IT LD A,29 CALL CONOUT SCF ;SET CARRY FOR A PARSE ERROR RET ; ; This routine is used by the command parser routines to input a ; string from the keyboard. It recognizes the TAKFLG which tells ; it to input a string from the active take file. ; Input to the routine is HL which points to the string buffer, ; and B which has an initial count of the number of characters ; already in the buffer. ; GETSTR LD A,(TAKFLG) ;Is there a TAKE file active OR A JP NZ,DOTAKE ;If so than go fill buffer from file. LD IY,(FLAGS) ;Get the flags address. BIT 5,(IY+18) ;Check if JCL active. JR Z,SKIP_JCL ;Jump if JCL not active. LD HL,CMDBUF ;Get the input buffer. LD BC,5000H ;Set B to max count, and C to zero. JP XKEYIN ;Get a line from JCL and return. ; SKIP_JCL PUSH HL ;Save the registers PUSH DE LD A,B ;Save the number of character already in LD (TEMP4),A ;the buffer for later GET010 CALL XKEY ;Get a character from the keyboard JP NZ,GETEXT ;Humm, what do we do on an error IFANOT 8,GET030 ;Go if not backspace LD E,A ;Save the KEY we got LD A,B ;Get the number of characters IFZ GET010 ;Go if no place to backspace over DEC B ;At least one space left DEC HL ;Back up the buffer pointer LD A,E ;Get the character CALL CONOUT ;Display it JR GET010 ;Go get a new key GET030 IFA CR,GET040 ;Go if enter pressed IFANOT 24,GET036 ;Jump if not SHIFT <- GET035 LD A,B ;NUMBER LEFT IFZ GET010 ;Go if all were erased LD A,8 ;BACKSPACE CALL CONOUT ;PRINT IT DEC B ;ONE MORE LEFT DEC HL ;BACKUP IN THE BUFFER JR GET035 ;KEEP LOOPING GET036 IFA ESC,GET040 ;Go if it was escape IFANOT 129,GET038 ;Go if not F1 (Also escape) LD A,ESC ;GET AN ESCAPE JR GET040 ;JOIN THE CODE FOR EXIT GET038 IFA 128,GET040 ;Go it it was a break IFALT 20H,GET010 ;Ignore other control keys GET040 INC B ;ONE LESS CHARACTER LEFT LD (HL),A ;PUT THE CHARACTER IN THE BUFFER JR NZ,GET050 ;WHEN nZ IS SET, NO MORE CHARS LEFT DEC B ;SAY WE STILL HAVE ONE JR GET060 ;MIGHT BE '?' WHICH IS IGNORED AS LAST GET050 IFA CR,GETEXT ;Finish up if CR pressed IFA ESC,GETEXT ;Same for escape IFA 128,GETEXT ;Same for break INC HL ;ONE MORE IN THE BUFFER CALL CONOUT ;PRINT WHAT WAS TYPED GET060 CP '?' ;WAS IT A '?' ? JP NZ,GET010 ;GET A NEW KEY IF NOT LD A,8 ;GET A BACKSPACE CALL CONOUT ;PRINT IT TO REMOVE THE '?' DEC HL ;POINT AT THE '?' PUSH HL ;HL -> IY POP IY LD A,' ' ;LOOK FOR A PREVIOUS SPACE IFA (IY-1),GETEXT ;Look for a previous space LD A,B ;ARE WE AT THE START OF THE LINE DEC A ;IF Z IS SET THAN THE CURSOR IS AT HOME ON THE LINE. NO SPACE WILL ;BE ADDED IN THIS CASE. LD A,' ' ;PUT A SPACE ON THE DISPLAY CALL NZ,CONOUT ;PRINT IT GETEXT LD A,B ;GET NUMBER ON THE LINE DEC A JR NZ,GET110 ;AT LEAST ONE CHAR ON THE LINE PUSH AF ;PUT AF INTO BC POP BC LD A,(HL) ;WAS '?' THE TERMINATOR? CP '?' LD A,B ;GET THE LENGTH IN A JR NZ,GET120 GET110 INC A ;COUNT THE TERMINATOR IF IT IS '?' GET120 LD B,A ;SAVE THE LENGTH LD A,(HL) ;GET THE TERMINATOR IFA ESC,GET130 ;Skip normal return if escape SLA A ;CHECK FOR BREAK (128 IS NEGATIVE) JR C,GET130 ;ALSO GIVES C STATUS LIKE @KEYIN SRL A ;FIX IT BACK OR 10H ;MAKE CR, CHR$(29), '?' IS UNDISTURBED CALL CONOUT ;PRINT THE CHARACTER GET130 POP DE ;RESTORE THE REGS POP HL RET ;RETURN TO THE CALLER ; STDOUT LD A,16 ;REVERSE VIDEO ON JP CONOUT ;USE THE RETURN ON THE STACK STDEND LD A,17 ;REVERSE VIDEO OFF JP CONOUT ;USE THE RETURN ON THE STACK ; ;ENTRY POINT FOR INTERUPT DRIVEN RECEIVE CHARACTER ROUTINE. ; GETINT JR NZ,GTIN10 ;NO CHARACTER AVAILABLE LD HL,(CURCHR) ;CURRENT POS IN BUFFER LD (HL),C ;CHARACTER IS IN C, STORE IT INC L ;POINT TO NEXT WRITE POSITION LD A,(NXTCHR) ;CHECK FOR OVERFLOW IFA L,GTIN10 LD (CURCHR),HL ;SAVE ADDRESS OF NEXT STORE LD A,(MAXCNT) LD E,A LD HL,INCNT ;Get the address of the count INC (HL) ;Add one to the count LD A,(HL) ;Get the count IFALT E,GTIN10 ;Jump if below count LD A,(FLOFLG) ;ARE WE DOING FLOW CONTROL? IFZ GTIN10 ;Go if not doing flow control LD A,C ;GET THE CHARACTER JUST RECEIVED IFA XOFF,GTIN06 ;Jump if XOFF received IFANOT XON,GTIN07 ;Jump if not time for XON XOR A GTIN06 LD (XOFREC),A ;Store the new flag value GTIN07 LD A,(XFFLG) ;SEE IF WE ALREADY SENT IT IFNZ GTIN10 ;Go if XOFF already sent INC A ;MAKE IT NON-ZERO LD (XFFLG),A ;SET IT LD E,XOFF ;Get an XOFF character CALL OUTCHR ;SENT IT OUT GTIN10 RET ; ;LOG THE CHARACTER IN THE LOG FILE ; LOGIT PUSH AF ;Save the character to log LD A,(LOGFLG) ;Check if logging active IFANOT 2,LOGITO ;Go if logging not on, or file not open POP AF ;Get the character back PUSH AF ;Put the character back IFANOT LF,LOGT0 ;Is it LINE FEED? Jump if not LD A,(PREVLCHR) ;Check if previous character was IFA CR,LOGITO ;Throw out if previous was LD A,LF ;Get a line feed character back LOGT0 PUSH DE ;Save the registers LD (PREVLCHR),A ;Save the previous character LD DE,LFCB ;Get the FCB address LOGT1 CALL XPUT ;@PUT the character to the file JR Z,LOGEXT ;Exit if no errors on output LOGT2 CALL XERROR0 ;Print the system message given in A LD DE,LFCB ;Get the FCB back CALL XCLOSE ;Make sure that the file is closed STROUT ERMS20 ;Say that the file was closed XOR A ;Reset the logging flag LD (LOGFLG),A ;Store the new value LOGEXT POP DE ;Restore DE LOGITO POP AF ;Restore the character RET ;Back to caller ; ; These are the TRSDOS 6.x SVC definitions ; XPARAM DOSVC 17 ;@PARAM SVC (Parse ()'d argument list). XFSPEC DOSVC 78 ;@FSPEC SVC (Convert filename to TRSDOS) XINIT DOSVC 58 ;@INIT SVC (Create a file on disk device) XOPEN DOSVC 59 ;@OPEN SVC (Open a file) XREAD DOSVC 67 ;@READ SVC (Read a record) XSKIP DOSVC 72 ;@SKIP SVC (Skip a logical record) XCLOSE DOSVC 60 ;@CLOSE SVC (Close a file) XVER DOSVC 73 ;@VER SVC (Write with verification) XCTL DOSVC 5 ;@CTL SVC, perform control operation XPRT PUSH BC ;Send character to printer PUSH AF LD C,A LD A,6 JR SVCSAV XVDCTL DOSVC 15 ;@VDCTL SVC (Perform video operations) XGET DOSVC 3 ;@GET SVC (Get a character from a file) ; ; SVC'S that require the character passed in A to be in C should ; look like this. ; XPUT PUSH BC ;SAVE BC PUSH AF ;SAVE AF LD C,A LD A,4 ;@PUT SVC SVCSAV RST 28H ;CALL AN SVC POP BC ;POPPING BC DOES NOT AFFECT THE FLAGS LD (XERRNO),A ;Store last error number LD A,B ;B HAS OLD A SO RESTORE POP BC ;GET OLD BC RET ;RETURN TO THE CALLER XKEYIN DOSVC 9 ;Get a string from *DO (@KEYIN SVC) XHIGH DOSVC 100 ;@HIGH$ SVC XLOAD DOSVC 76 ;@LOAD SVC (Load an executable) XCHKDRV DOSVC 33 ;@CHKDRV SVC (Check if drive is ready) XTIME DOSVC 19 ;@TIME SVC (Get current system time) XADTSK DOSVC 29 ;@ADTSK SVC (Add a task to the table) XCKTSK DOSVC 28 ;@CKTSK SVC (Check if task slot available) XRMTSK DOSVC 30 ;@RMTSK SVC (Remove task from table) XKLTSK DOSVC 32 ;@KLTSK SVC (Kill current exec task) XPAUSE DOSVC 16 ;@PAUSE SVC (Delay for count in BC) XFLAGS DOSVC 101 ;@FLAGS SVC (Get system flags address) XREMOVE DOSVC 57 ;@REMOV SVC (Remove opened file) XKILL EQU XREMOVE XDECHEX DOSVC 96 ;@DECHEX SVC (Convert ASCII to binary) XHEXDEC DOSVC 97 ;@HEXDEC SVC (Convert binary to ASCII) XKBD DOSVC 8 ;@KBD SVC (Get a keyboard char, no wait) XKEY DOSVC 1 ;@KEY SVC (Get a keyboard char, wait) XCMNDR DOSVC 25 ;@CMNDR SVC (Execute system command) XMUL16 DOSVC 91 ;@MUL16 SVC (Multiply 8 bit by 16 bi&t) XDSP PUSH BC ;SAVE BC PUSH AF ;SAVE AF LD C,A LD A,2 ;@DSP SVC JP SVCSAV XGTDCB DOSVC 82 ;@GTDCB SVC (Get the DCB for given device) XEXIT LD L,A ;A HAS OUR RETURN CODE LD H,0 ;MAKE HL THE RETURN CODE DOSVC 22 ;Do @EXIT SVC XERROR0 LD A,0 ;Get the last error number XERRNO EQU $-1 XERROR PUSH BC ;SAVE BC AND AF PUSH AF LD IY,(FLAGS) ;GET @FLAGS ADDRESS RES 6,(IY+2) ;RESET ALL SPECIAL BITS RES 7,(IY+2) RES 6,(IY+18) OR 0C0H ;MAKE SIMPLE MESSAGES LD C,A ;C NEEDS THE ERROR NUMBER CALL NEWLIN ;Get a new line for the messages LD A,26 ;@ERROR SVC (ISSUE A SYSTEM MESSAGE) JP SVCSAV ;GO CALL IT ; ; Set up interrupt and device information ; SETINT EQU $ ; ; This code sets up the interrupt driven receiver. It calls @CTL ; to pass the address of the "GETINT" routine, which is called ; each time a character is received by the UART ; LD IY,GETINT ;Where to transfer control to LD DE,(CLDCB) ;Which device to get LD C,4 ;Ctl function 4 CALL XCTL ;Do @CTL ; ; Install *FO and *FI devices ; LD DE,0 ;Find a new DCB for this device CALL XGTDCB JR NZ,NODCB ;Abort if an error occured LD (FOTDCB),HL ;Save the pointer to the DCB PUSH HL ;Move it to IX to do indexing POP IX LD (IX+6),'F' ;Store the name in the DCB LD (IX+7),'O' LD A,2 ;Select @PUT capabilities only LD (IX),A LD HL,FILOUT ;Get the entry point LD (IX+1),L ;Store it LD (IX+2),H LD DE,0 ;Get a new DCB for the input device CALL XGTDCB JR NZ,NODCB ;Abort if an error occurs LD (FINDCB),HL ;Save the address of the DCB PUSH HL ;Put the address in IX for indexing POP IX LD (IX+6),'F' ;Store the device name in the DCB LD (IX+7),'I' LD A,1 ;Select @GET capabilites only LD (IX),A LD HL,FILIN ;Get the entry point LD (IX+1),L ;Store the address LD (IX+2),H RET ;Done! ; ; Print no DCB's available message ; NODCB STROUT NONDCB ;Print NO NEW DCB's message JP EXIT1 ;Exit from KERMIT ; ; Get a new line to print on ; NEWLIN PUSH AF ;Save the acumulator LD A,CR ;Get a equivilent CALL CONOUT ;Output it to the screen POP AF ;Restore A RET ;Return to caller ; ; Set the default disk drive command ; SETDSK EQU $ LD A,CMNUM ;PARSE A NUMBER CALL COMND JP KERMT3 OR A ;If no number than say bad command JP Z,KERMT2 LD A,D ;Check for number above 255 IFNZ SETDRV_2 ;Jump if number bigger than 255 LD C,E ;Get the lower order byte CALL XCHKDRV ;Check the disk drive JR NZ,SETDRV_2 ;Jump if TRSDOS doesn't like it PUSH BC ;Save the binary number JR NC,SETDRV_1 ;If carry set the drive is write protected STROUT WRTPROT ;Say drive is write protected SETDRV_1 STROUT DSKOK ;Say default drive changed POP BC ;Get the drive number back LD A,C ;Get the binary value into a ADD A,48 ;Make it and ASCII digit LD (DEFDSK),A ;Save it as the new default JP KERMIT ;Get a new command ; ; Print bad drive message ; SETDRV_2 LD A,32 ;Get the illegal drive message number CALL XERROR ;Have TRSDOS print the message JP KERMIT ;Go get a new command ; ; Clear any buffered characters from input buffer ; CLRPRT PUSH AF LD A,(NXTCHR) ;Set the next, and current positions LD (CURCHR),A ;within the buffer to be the same XOR A ;Set buffered character count to zero LD (INCNT),A LD (XOFREC),A ;Reset XOFF'd state LD (XFFLG),A ;Haven't sent XOFF either POP AF RET ; ; Display the directory ; ;This code makes an educated guess as to whether it is running on a ;6.1 or a 6.2 TRSDOS machine. This is to determine if we should ;issue the DIR command for 6.1 or the CAT command for 6.2 ; DIR EQU $ LD A,CMTXT ;Get text for DIR/CAT command LD DE,DIRBUF CALL COMND JP KERMT3 IFNZ DIR1C ;Jump if some text given DIR1B LD A,(DEFDSK) ;Otherwise, use default drive LD (DIRBUF),A ;Put in the text LD A,CR ;Put in the terminator LD (DIRBUF+1),A DIR1C CALL NEWLIN ;Get new lines CALL NEWLIN LD IY,(FLAGS) ;Check if using 6.1, or 6.2 TRSDOS LD A,(IY+27) ;Get the version number AND 0FH ;KEEP JUST THE X OF 6.X LD HL,DO62DR ;Get 6.2 command (CAT) IFA 2,DIR1E ;Jump if 6.2 LD HL,DO61DR ;Get 6.1 command (DIR) DIR1E LD DE,DIRCMD ;Where to put the text LD BC,4 ;How much to move PUSH DE ;Save the start LDIR ;Move the command POP HL ;Restore the start CALL XCMNDR ;Let TRSDOS do it for us DIR1D JP KERMIT ;Get a new command ; ; Erase a file from the system ; ERA EQU $ LD A,CMTXT ;Get some text LD DE,MFNBUF PUSH DE ;Save the buffer address CALL COMND JP KERMT3 IFZ ERA3 ;Jump if no text given CALL NEWLIN ;Get a newline POP HL ;Get the address back LD (MFNPTR),HL XOR A LD (LOGNAMES),A ;Reset the log names flag CALL BUILDF ;Do wild carding LD A,(FILECNT) ;Check if anything found IFZ ERA3 LD (MFNPTR),HL ;Save the start of the list ERA2 CALL MFNAME ;Get one filename from the buffer JR C,ERA3 ;Jump if no more LD DE,MFREQ ;Get the name LD B,0 ;Select 256 LRL LD HL,DATA ;Get the address of a temp buffer CALL XOPEN ;Try to open it JR Z,ERA1 ;Jump if opened CP 42 ;Was it an LRL error message? JR Z,ERA1 ;Jump if it was ERA0 CALL XERROR0 ;Issue the message indicated in A JR ERA3 ;Get a new command ; ; Print the removing message, then remove it ; ERA1 LD HL,FCB ;Convert ETX to EOS in FCB LD BC,32 ;Max distance LD A,3 ;What to find CPIR ;Look DEC HL ;Ignore errors LD (HL),EOS ;Change it STROUT REMOVSTR ;Output 'Removing: ' message STROUT FCB ;Output the filename CALL NEWLIN ;Get a newline LD DE,MFREQ ;Get the FCB CALL XKILL ;Remove the file JR Z,ERA2 ;Abort if error occurs JR ERA0 ;Get the next one ; ERA3 JP KERMIT ;Get a new command ; ; This routine sets up KERMIT/INI as initialization. The trick ; is to just make it look like the user typed 'TAKE KERMIT/INI'. ; CHKTAK CALL XFLAGS ;Get the flags area into IY LD A,(IY+10) ;Get the KFLAG$ AND 0F8H ;Reset the , and LD (IY+10),A ;the bits, and store it LD B,46 ;Pause for a good deal of time CALL XPAUSE LD A,(IY+10) ;Get the KFLAG$ mask back AND 7 ;Any of the keys pressed? RET NZ ;Stop if BREAK, ENTER, or PAUSE LD DE,TFCB ;LOAD THE FCB ADDRESS LD HL,TKNAME ;NAME OF THE FILE LD BC,TKLEN ;LENGTH OF THE STRING LDIR LD DE,TFCB ;GET IT AGAIN LD HL,TBUF ;GET THE INPUT BUFFER LD B,0 ;256 BYTE LRL CALL XOPEN ;OPEN THE FILE JR Z,CHKT_1 ;Jump if everything OK CP 42 RET NZ ;Return if NOT LRL error CHKT_1 LD A,1 ;SET THE TAKE COMMAND ACTIVE FLAG LD (TAKFLG),A RET ;GO DO IT. ; ; Print ESCAPE character sequence as CONTROL-? ; ESCPR LD A,(ESCCHR) ;GET THE ESCAPE CHAR. ESCPR1 IFAGE ' ',ESCPR2 ;IS IT A CONTROL CHAR? PUSH AF STROUT INMS10 ;Output CONTROL- POP AF ;GET THE CHAR BACK OR 100O ;DE-CONTROLIFY. ESCPR2 CALL CONOUT RET ; ; Swap screens between connect mode, and KERMIT command modes ; SWAPIN LD A,15 ;cursor off CALL CONOUT ;Tell *DO to turn it off LD HL,2600H ;Get the destination LD B,6 CALL XVDCTL ;Move screen image to temp space LD HL,SWTBUF ;Move the buffer to the screen LD B,5 CALL XVDCTL ;Move it LD HL,2600H ;Now move temp buffer to swap buffer LD DE,SWTBUF LD BC,1920 LDIR ;Move it LD A,14 ;cursor back on CALL CONOUT RET ;Return to the caller ; ; Put connect command screen in view ; SCRCON EQU $ CALL SWAPIN ;Swap screens LD B,4 ;Select get cursor position option CALL XVDCTL ;SVC @VDCTL to get position LD (CMDCRS),HL ;Save the cursor LD HL,(CONCRS) ;Get the connect cursor postion LD B,3 ;Select SET cursor position CALL XVDCTL ;SVC @VDCTL to set it LD A,14 ;Make sure that the cursor is ON CALL CONOUT RET ;Return to caller ; ; Swap in Kermit command screen ; SCRCMD EQU $ CALL SWAPIN ;Swap screens LD B,4 ;Get the current cursor position CALL XVDCTL ;SVC @VDCTL to get it LD (CONCRS),HL ;Save it LD HL,(CMDCRS) ;Get the Kermit command cursor position LD B,3 ;Set the current cursor position CALL XVDCTL ;SVC @VDCTL to set it LD A,14 ;Make sure the cursor is on CALL CONOUT RET ;Return ; ; *FI Device driver is here ; ; Valid memory module headers are used here, but are not necessary ; since the drivers are not in the High or Low memory chain of ; modules. ; FILIN JR INPFIL ;Jump to code DW ENDIN ;End of module DB 4 ;Module name length DB 'INP$' FINDCB DW 0 ;Pointer to our DCB DW 0 PRECHR DB 0 ;Previous character received INPFIL CALL INPORT ;Get an input character JR Z,INP04 ;Jump if successful CALL CONIN ;Failed, read the keyboard IFZ INPFIL ;Jump if no key pressed IFANOT 128,INP03 ;Jump if not break LD A,28 ;Return at EOF indicator OR A ;Set NZ status RET ;return to caller INP03 LD E,A ;Get the keyboard character CALL OUTCHR ;Output it to the port JR INPFIL ;Read the port again INP04 LD C,A ;Get the input character LD A,(FLOFLG) ;Are we doing flow control? IFNZ INP05 ;Jump if not doing flow control LD A,C ;Get the character back IFA XON,INPFIL ;Ignore XON if sent IFA XOFF,INPFIL ;Ignore that also INP05 LD A,(PRECHR) ;Get the previous character CP CR ;Was it CR? LD A,C ;Get the current character JR NZ,INP09 ;Jump if not CR LD A,(FILTYPE) ;Check if should convert OR A ;Is it binary mode? LD A,C JR NZ,INP09 ;It is, so do not translate CP LF ;Is the current character LF? LD (PRECHR),A ;Store new previous JR Z,INPFIL ;Ignore LF after CR INP09 CP A ;Set Z status RET ;Return byte to caller in A ENDIN EQU $ ; ; *FO Device driver is here ; FILOUT JR FIOUT ;Jump to code DW OUTEND-1 ;Normal header DB 4 DB 'OUT$' FOTDCB DW 0 DW 0 FIOUT LD E,C ;Get the character to send FIOUT1 CALL OUTCHR ;Output it. We will hang till output LD A,C ;Get the character sent CP A ;Set the Z flag RET ;Return the byte sent out, and Z status OUTEND EQU $ ; end of file