; CP4SYS.ASM ; KERMIT - (Celtic for "FREE") ; ; This is the CP/M-80 implementation of the Columbia University ; KERMIT file transfer protocol. ; ; Version 4.0 ; ; Copyright June 1981,1982,1983,1984 ; Columbia University ; ; Originally written by Bill Catchings of the Columbia University Center for ; Computing Activities, 612 W. 115th St., New York, NY 10025. ; ; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben, ; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many ; others. ; ; This file contains the system-dependent code and data for KERMIT. ; It will be probably be broken into independent files to generate ; overlays for the various systems, one or more overlay possible ; from each file. For now, we will leave it in one piece. ; ; revision history: ; edit 7: 29 August 1984 by Bdale Garbee @ CMU ; Add support for Digicomp Delphi 100 and Netronics Smartvid terminal. ; ; edit 6: August 21, 1984 ; Add flsmdm, to flush comm line on startup. ; Support multiple-sector buffering (except for osborne 1). ; ; edit 5: August 19, 1984 ; Add missing RET in outlpt: (*sigh*). Also preserve DE in case ; the BIOS destroys it. Add version string (sysedt, since sysver ; was already taken). ; ; edit 4: August 8, 1984 ; Running terminal output through the BDOS didn't work so well for ; the Kaypro. Remove the special check at outcon:. ; ; edit 3: August 3, 1984 ; move "mover" to CP4SYS from CP4UTL, so we can use Z80 block move. ; define Z80 true or false when setting up the rest of the parameters. ; (I'm only defining as Z80's the ones I KNOW are Z80's, because I ; don't want to break anything by guessing wrong). Make the values ; stored by sysinit in "speed" match the 16-bit values found in the ; speed table, so we can find them later. ; ; edit 2: July 27, 1984 (CJC) ; Add break capability for Kaypro II and bbII. ; Merge Toad Hall changes: Allow assembly with LASM, add support for ; Morrow Decision I. ; ; edit 1: May, 1984 ; extracted from CPMBASE.M80 version 3.9; modifications are described ; in the accompanying .UPD file. ; ; Keep module name, edit number, and last revision date in memory. sysedt: db 'CP4SYS.ASM (7) 29-Aug-84$' ; ; Assembly time message to let me know I'm building the right version. ; LASM generates an 'S' error along with the message, which is messy, but ; better than trying to put everything inside a IF m80 OR mac80 conditional, ; because LASM doesn't like nested IF's, either. IF robin .printx * Assembling KERMIT-80 for the DEC VT180 * ENDIF IF brain .printx * Assembling KERMIT-80 for the Intertec Superbrain * ENDIF IF vector .printx * Assembling KERMIT-80 for the Vector Graphics * ENDIF IF osi .printx * Assembling KERMIT-80 for the Ohio Scientific * ENDIF IF heath .printx * Assembling KERMIT-80 for the Heath/Zenith 89 * ENDIF IF z100 .printx * Assembling KERMIT-80 for the Heath/Zenith Z100 * ENDIF IF apple .printx * Assembling KERMIT-80 for the Apple ][ * ENDIF;apple IF apmmdm .printx * with Z80 Softcard & Micromodem II * ENDIF;apmmdm IF ap6551 .printx * with Z80 Softcard & 6551 ACIA * ENDIF;ap6551 IF trs80 .printx * Assembling KERMIT-80 for the TRS-80 II * ENDIF IF osbrn1 .printx * Assembling KERMIT-80 for the Osborne 1 * ENDIF IF telcon .printx * Assembling KERMIT-80 for the Telcon Zorba * ENDIF IF dmII .printx * Assembling KERMIT-80 for the DECmate II * ENDIF IF gener .printx * Assembling Generic KERMIT-80 * ENDIF IF cpm3 .printx * Assembling Generic KERMIT-80 for CP/M 3.0 * ENDIF IF kpii .printx * Assembling Kaypro II KERMIT-80 * ENDIF IF bbII .printx * Assembling BigBoard II KERMIT-80 * ENDIF IF mdI .printx * Assembling for Morrow Decision I * ENDIF ;mdI [Toad Hall] IF mmdI .printx * Assembling for Morrow Micro Decision I * ENDIF ;mmdI IF mikko .printx * Assembling MikroMikko Kermit-80 * ENDIF IF delphi ;[7] .printx * Assembling Digicomp Delphi 100 Kermit-80 * ENDIF ;[7] ; Also tell what kind of terminal, if any, is selected IF crt .printx * generic CRT selected * ENDIF IF adm3a .printx * ADM3A selected * ENDIF IF smrtvd ;[7] .printx * Netronics Smartvid-80 selected * ENDIF ;[7] IF tvi925 .printx * TVI925 selected * ENDIF IF vt52 .printx * VT52 selected * ENDIF IF vt100 .printx * VT100 selected * ENDIF ; ;========================================================================= ; I/O Byte assignments (2-bit fields for 4 devices at loc 3) ; ;bits 6+7 LIST field ; 0 LIST is Teletype device (TTY:) ; 1 LIST is CRT device (CRT:) ; 2 LIST is Lineprinter (LPT:) ; 3 LIST is user defined (UL1:) ; ;bits 4+5 PUNCH field ; 0 PUNCH is Teletype device (TTY:) ; 1 PUNCH is high speed punch (PUN:) ; 2 PUNCH is user defined #1 (UP1:) ; 3 PUNCH is user defined #2 (UP2:) ; ;bits 2+3 READER field ; 0 READER is Teletype device (TTY:) ; 1 READER is high speed reader (RDR:) ; 2 READER is user defined #1 (UR1:) ; 3 READER is user defined #2 (UR2:) ; ;bits 0+1 CONSOLE field ; 0 CONSOLE is console printer (TTY:) ; 1 CONSOLE is CRT device (CRT:) ; 2 CONSOLE is in Batch-mode (BAT:);READER = Input, ; LIST = Output ; 3 CONSOLE is user defined (UC1:) ; ;========================================================================= iobyte EQU 03H ;Location of I/O byte ; the basics... IF robin OR gener batio EQU 056H ;I/O byte CON=BAT,LIST=CRT,READER=RDR,PUNCH=PTP defio EQU 095H ;I/O byte CON=CRT,LIST=LPT,READER=RDR,PUNCH=PTP ENDIF;robin OR gener IF gener crtio equ 01010101B ; use CRT: device ptrio equ 01010110B ; use PTR: device ttyio equ 00000000B ; use TTY: device uc1io equ 01010111B ; use UC1: device ur1io equ 01101010B ; use UR1: device ur2io equ 01111110B ; use UR2: device ENDIF;gener IF robin lptio EQU 054H ;I/O byte CON=TTY,LIST=CRT,READER=PTR,PUNCH=PTP gppio EQU 057H ;I/O byte CON=UC1,LIST=CRT,READER=RDR,PUNCH=PTP ENDIF;robin IF dmII batio EQU 042H ;I/O byte CON=BAT,LIST=CRT,READER=RDR defio EQU 081H ;I/O byte CON=CRT,LIST=LPT,READER=RDR ENDIF;dmII IF mikko batio EQU 10110010B ; I/O byte console => serial line defio EQU 10000001B ; I/O byte console => CRT and Keyboard ENDIF;mikko ; ; ; Protocol parameters. Some of these can be changed with commands. ; drpsiz EQU 5EH ;Default receive packet size. (maximum is 5EH) dspsiz EQU 20H ;Default send packet size. (maximum is 5EH) dstime EQU 08H ;Default send time out interval. IF NOT (apple OR osbrn1) drtime EQU 05H ;Default receive time out interval. ENDIF;NOT (apple OR osbrn1) IF apple OR osbrn1 drtime EQU 0AH ; Use longer receive timeout on apple and osborne. ENDIF;apple OR osbrn1 dspad EQU 00H ;Default send padding. drpad EQU 00H ;Default receive padding. dspadc EQU 00H ;Default send padding char. drpadc EQU 00H ;Default receive padding char. dseol EQU CR ;Default send EOL char. dreol EQU CR ;Default receive EOL char. dsquot EQU '#' ;Default send quote char. drquot EQU '#' ;Default receive quote char. dschkt EQU '1' ;Default checksum type ; IF brain baudst EQU 60H ; baudrt EQU 0EF00H ;Memory location where baud rates are stored. mnport EQU 58H ;Modem data port mnprts EQU 59H ;Modem status port output EQU 01H ;Transmitter empty input EQU 02H ;Input data available z80 EQU FALSE ;I don't know... ENDIF;brain IF osi mnport EQU 0CF01H ;Modem data port mnprts EQU 0CF00H ;Modem status port output EQU 02H ;Transmitter empty input EQU 01H ;Input data available z80 EQU FALSE ;I don't know... ENDIF;osi IF vector mnport EQU 04H ;Modem data port mnprts EQU 05H ;Modem status port output EQU 01H ;Transmitter empty input EQU 02H ;Input data available z80 EQU FALSE ;I don't know... ENDIF;vector IF delphi ;[7] mnport EQU 22H ;[7] Modem data port mnprts EQU 23H ;[7] Modem status port output EQU 01H ;[7] Transmitter empty input EQU 02H ;[7] Input data available baudrt equ 29h ;[7] Baud rate port for channel 2 (default) z80 EQU true ;[7] We're using the z80 side of the dual processor ENDIF;[7] delphi IF heath mnport EQU 330O ;Modem data port mnprts EQU 335O ;Modem status port output EQU 20H ;Transmitter empty input EQU 01H ;Input data available z80 EQU FALSE ;I don't know... ENDIF;heath IF z100 mnport EQU 0ECH ;Modem data port mnprts EQU 0EDH ;Modem status port output EQU 01H ;Transmitter empty input EQU 02H ;Input data available z80 EQU FALSE ;I don't know... ENDIF;z100 IF trs80 ;NEEDS display definition (e.g. trs80lb or trs80pt) mnport EQU 0F4H ;Modem data port (0F5H for port B) mnprts EQU 0F6H ;Modem status port (0F7H for port B) output EQU 04H ;Transmitter empty input EQU 01H ;Input data available z80 EQU FALSE ;I don't know... ENDIF;trs80 IF apmmdm ;APPLE Slot 2 contains Micromodem II. MNPORT EQU 0E0A7H ;Communications Port. mnprts EQU 0E0A6H ;Communications Port Status. mnmodm EQU 0E0A5H ;Modem Control Port. orgmod EQU 8EH ;Modem Originate Mode. OUTPUT EQU 02H ;Output Buffer Empty. INPUT EQU 01H ;Input Register Full. apinc1 EQU 03H ;First Init Character for 6850 ACIA (Reset) apinc2 EQU 11H ;Second Init Character for ACIA (8-bits) apoffh EQU 80H ;Set if OFFHOOK AP300 EQU 1 ;300 Baud z80 EQU TRUE ;Z80 Softcard ENDIF;apmmdm IF ap6551 ;jb mnport EQU 0E088H+(10H*apslot) ;jb Communications Port. mnprts EQU 0E089H+(10H*apslot) ;jb Communications Port Status. mnprtc EQU 0E08BH+(10H*apslot) ;jb Communications Control mnprtm EQU 0E08AH+(10H*apslot) ;jb Communications Master (command) output EQU 10H ;jb Output Buffer Empty. input EQU 08H ;jb Input Register Full. mncinb EQU 18H ;jb Control Port Initialization Byte ;jb (8-bit, no parity, 1-stop, 1200 baud) mnminb EQU 0BH ;jb Master Port Initialization Byte ;jb (DTR, RTS, no interrupts) z80 EQU TRUE ;Z80 Softcard ENDIF;ap6551 IF osbrn1 ;Osborne 1 uses 6850 ACIA, but memory mapped. Derived from Apple. BAUDRT EQU 0EFC1H ;Memory location where baud rates are stored. OSTOP EQU 4000H ;Where we move OSMOVE to at startup OSPORT EQU 2A01H ;Communications Port. OSPRTS EQU 2A00H ;Communications Port Status. OUTPUT EQU 02H ;Output Buffer Empty. INPUT EQU 01H ;Input Register Full. OSBIN1 EQU 57H ;First Init Character for 6850 ACIA (Reset) ;(I would have thought 03, but prom code writes 57 there) OSBI12 EQU 55H ;Second Init Character for ACIA (8-bits, 1200) OSBI03 EQU 56H ;Second init char. for ACIA (8 bits, 300) ;(don't ask.. I don't know why SETUP writes 55 and 56 either) z80 EQU FALSE ;I don't know... ENDIF;osbrn1 IF telcon MNPORT EQU 20H ;Modem data port MNPRTS EQU 21H ;Modem status port OUTPUT EQU 01H ;Transmitter empty INPUT EQU 02H ;Input data available z80 EQU FALSE ;I don't know... ENDIF;telcon IF robin ;Those definitions below that are commented out are just for information ;***** NOT generally found in distributed documentation **** ;pbausl EQU 90H ;The Baud-Rate register. prntst EQU 49H ;Printer ;prndat EQU 48H contst EQU 41H ;Console ;condat EQU 40H gentst EQU 51H ;General port. ;gendat EQU 50H comtst EQU 59H ;COMM-Port ;comdat EQU 58H ;output EQU 01H ;Output ready bit. ;input EQU 02H ;Input ready bit. z80 EQU TRUE ; This one's a Z80. ENDIF;robin IF kpii mnport equ 04h ; Modem data port mnprts equ 06h ; Modem status port output equ 04h ; Transmit buffer empty input equ 01h ; Receive data available baudrt equ 00h ; Baud rate port for channel A z80 EQU TRUE ; This one's a Z80. ENDIF;kpii IF bbII mnport equ 80h ; Modem data port (SIO channel A) mnprts equ 81h ; Modem status port output equ 04h ; Transmit buffer empty input equ 01h ; Receive data available baudrt equ 89h ; Baud rate port for channel A z80 EQU TRUE ; This one's a Z80. ENDIF;bbII IF mmdI ;Morrow MicroDecision - the single-board one mnport EQU 0FEH ;Morrow Printer UART data port mnprts EQU 0FFH ;Morrow Printer UART command/status output EQU 01H ;Output ready bit. input EQU 02H ;Input ready bit. ;Note: Needs terminal definition (vt100, vt52, tvi925, adm3a or crt above) z80 EQU FALSE ;I don't know... ENDIF;mmdI IF mdI ;Morrow Decision I - the big sucker mnport equ 48H ; Modem data port. mnprts equ 4DH ; Modem status port. output equ 20H ; Transmitter empty. input equ 1 ; Input data available. mbase equ 48H ; Base address of Multi I/O port ; selector area. grpsel equ 4FH ; Group select port. rbr equ 48H ; Read Data Buffer. group equ 1 ; Multi I/O Group byte for serial ports. congrp equ 1 ; Serial Port 1 for console mdmgrp equ 3 ; Serial Port 3 for modem. ; Following are needed for baud rate changes...[Toad Hall] dlm equ 49H ; Baud Rate Divisor (Most Sig Bit) dll equ 48H ; Baud Rate Divisor (Least Sig Bit) ier equ 49H ; Interrupt Enable Register lcr equ 4BH ; Line Control Register lsr equ 4DH ; Line Status Register msr equ 4EH ; Modem Status Register dlab equ 80H ; Divisor Latch Access Bit wls0 equ 1 ; Word Length Select Bit 0 wls1 equ 2 ; Word Length Select Bit 1 for 8 bit word stb equ 4 ; Stop bit count - 2 stop bits imask equ 0 ; Interrupt mask (all disabled) z80 EQU TRUE ; This one's a Z80. ENDIF ;mdI NOTE: needs terminal definition. [Toad Hall] IF mikko sioac EQU 0FF12H ;SIO channel A register(s) address sioo3 EQU 01000001B ;SIO Write Reg. 3 original setup (?) ;RX 7 bits,synch mode bits 0,RX enable sion3 EQU 11001111B ;SIO Write Reg. 3 KERMIT setup ;RX 8 bits,synch mode bits 0,RX enable sioo4 EQU 01001111B ;SIO Write Reg. 4 original setup (?) ;X16 clock,8 bit synch(ignored), ;2stop bits,par even(on) sion4 EQU 01000100B ;SIO Write Reg. 4 KERMIT setup ;X16 clock,8 bit synch(ignored), ;1stop bit,par off sioo5 EQU 10101010B ;SIO Write Reg. 5 original setup (?) ;DTR,TX 7 bits,TX enable,RTS sion5 EQU 11101010B ;SIO Write Reg. 5 KERMIT setup ;DTR,TX 8 bits,TX enable,RTS txclk EQU 0FF30H ;Baud rate generator (CTC) for transmitter rxclk EQU 0FF31H ;Baud rate generator (CTC) for receiver chmask EQU 0F1F2H ;Mask byte address for SIO ch. A reception z80 EQU TRUE ;It's got a SIO and a CTC, it must be a Z80 ENDIF;mikko IF robin OR dmII z80 EQU TRUE ; This one's a Z80 ENDIF;robin OR dmII IF gener OR cpm3 ; To be truly generic, we must assume 8080. z80 EQU FALSE ENDIF;gener OR cpm3 ; IF brain OR osi OR apple OR telcon defesc EQU ']'-100O ;The default escape character. ENDIF;brain OR osi OR apple OR telcon IF vector defesc EQU '~' ;Vector can't type ']'. ENDIF;vector IF robin OR dmII OR mikko OR heath OR z100 OR osbrn1 OR kpII defesc EQU '\'-100O ;The default is Control \ -- it's easier B.E. ENDIF;robin OR dmII OR mikko OR heath OR z100 OR osbrn1 OR kpII IF crt OR vt100 OR vt52 OR tvi925 OR adm3a OR smrtvd ;[7] defesc EQU '\'-100O ;Still Control-\ (just ran out of room...) ENDIF;crt OR vt100 OR vt52 OR tvi925 OR adm3a OR smrtvd ;[7] IF trs80 defesc EQU '_'-100O ;CTRL-_ (Down-arrow on TRS-80 keyboard) ENDIF;trs80 ; Select initial setting for VT-52 emulation flag. IF crt ; If dumb or unknown console, vtval EQU 0FFH ; we can't support VT52 emulation ENDIF;crt IF heath OR z100 OR telcon OR vt52 ; If console looks like (or is) VT52 vtval EQU 0 ; we don't need VT52 emulation ENDIF;heath OR z100 OR telcon OR vt52 IF robin OR dmII OR vt100 ; If console looks like VT100 vtval EQU 0 ; we probably don't want VT52 emulation ENDIF;robin OR dmII OR vt100 ; If none of the above, default to VT52-EMULATION ON. IF NOT (crt OR heath OR z100 OR telcon OR vt52 OR robin OR dmII OR vt100) vtval EQU 1 ENDIF;NOT (crt OR heath OR z100 OR telcon OR vt52 OR robin OR dmII OR vt100) ; Set the fuzzy timeout value. Range is 1 (VERY short) through 0ffffH to zero ; (maximum). The actual duration is a function of the loop length and the ; processor speed. For now, we'll make it zero for everybody, but feel free ; to change it for your system. fuzval EQU 0 ; ; ; System-dependent initialization ; Called once at program start. sysinit: lxi d,cfgmsg ; "configured for " call prtstr lxi d,sysver ; get configuration we're configured for call prtstr ; print it. ; ; If we're set up to do special terminal handling, say what kind ; of terminal we expect... (unless it's the generic 'crt') IF adm3a OR tvi925 OR vt52 OR vt100 OR smrtvd ;[7] lxi d,witmsg ; " with " call prtstr lxi d,ttytyp ; terminal type call prtstr ENDIF;adm3a OR tvi925 OR vt52 OR vt100 OR smrtvd ;[7] call prcrlf ; print CR/LF ; ; now, to work... ; IF NOT osbrn1 ; locate large buffer for multi-sector I/O ; What we want to do here is find the ccp. Space between ovlend and the ccp ; is available for buffering, except we don't want to use more than maxsec ; buffers (if we use too many, the remote end could time out while we're ; writing to disk). maxsec is system-dependent, but for now we'll just ; use 16Kbytes. The only reason for using less (besides not having 16K ; available) is to limit the amount of time spent transferring data into ; the buffer before discovering there is no room on disk to store it. ; (16Kbytes @ 30 bytes per sec is 9 minutes; probably close to 15 minutes ; when protocol overhead and delays for acknowledges are considered) ; I'm excluding the Osborne 1 for now because it needs code up at 4000H, ; so we'd have to start the buffer after that. maxsec EQU (16*1024)/bufsiz ; 16K / number of bytes per sector lxi h,ovlend ; get start of buffer shld bufadr ; store in linkage section mvi a,maxsec ; get size of buffer, in sectors sta bufsec ; store that, too. ENDIF;NOT osbrn1 IF iobyt ; (actually, we ought to do this for everybody) call iniadr ;Initialize the BIOS addresses mvi c,gtiob ;Get current I/O byte call bdos ;From CP/M sta coniob ;Remember where console is ENDIF;iobyt IF osbrn1 lxi d,ostop ;where we're moving it to lxi h,osmove ;what we're moving mvi b,osmct ;How many bytes we're moving call mover lda baudrt ; Find out what speed is current ani 1 mvi a,osbi03 ; assume 300 baud jz osstr1 mvi a,osbi12 ; nope, it's 1200. osstr1: sta speed ; save initial speed sta speed+1 ; as 16 bits, to match speed table entries mov d,a mov e,a ; get initial speed in DE call sysspd ;set up parity etc. ENDIF;osbrn1 IF kpii OR bbII lxi d,siotbl ; Load the address of the status able mvi c,siolen ; Length of status table siolup: ;Loop back here for each command byte ldax d ; Load the first byte into A inx d ; Index the pointer out mnprts ; Send it to the status port dcr c ; Decrement the byte counter jnz siolup ; Jump back for more commands ENDIF;kpii or bbII IF mikko lxi d,mintbl ;Address of KERMIT Reg values (what) mvi c,minlen ;Length of table (how many) lxi h,sioac ;Send data to ch. A SIO registers (to where) call movmik mvi a,0FFH ;Set ch. A mask to use all bits sta chmask ENDIF;mikko IF brain lda baudrt ; fetch current baud rate ani 0F0H ; extract left nibble rrc ; shift right 4 places rrc rrc rrc sta speed ; store as comm port speed sta speed+1 ; (16 bits, to match speed table entries) ENDIF;brain IF mdI lxi h,96 ;Default 1200 baud modem port speed shld speed ;Store as modem port speed call sysspd ;Initialize the port ENDIF;mdI [Toad Hall] IF ap6551 lda mnprtc ; read control port ani 0fH ; extract low order nybble sta speed ; store as comm line speed sta speed+1 ; (16 bits, to match speed table entries) mvi a,mnminb ;jb initialization routine sta mnprts ;jb sta mnprtm ;jb initialize master (command) port mvi a,mncinb ;jb sta mnprtc ;jb initialize control port ENDIF;ap6551 IF delphi ;[7] ; ; shove the default baud rate (1200) in to the Delphi port address ; for the baud rate generator on port 2, the default port; save this ; value so we can tell what speed is selected. ; mvi a,07h ;[7] get value for 1200 baud out baudrt ;[7] set it for port 2 sta speed ;[7] save for status display sta speed+1 ENDIF;[7] delphi ret ; IF iobyt ; This one is hopefully the last "improvement" in view of GENERIC ;Kermit. It uses for Character-I/O the BIOS-routines ( instead of the ;"normal" BDOS routines. What does it give us (hopefully) : More speed, ;higher chance of success ( I/O byte implemented in BIOS [if at all]), ;but no "extra" device handling - that's done by BDOS. ; ; How do we "get" the call-adresses? Location 0 has a JMP Warm-Boot ;in CP/M which points into the second location of the BIOS JMP-Vector. The ;next three locations of the JMP-Vector point to the CONSTAT,CONIN,CONOUT ;BIOS-routines. CONOUT wants the character in C. ; ;- Bernie Eiben iniadr: lhld 1 ;get BIOS Warmstart-address lxi d,3 ;next adress is CONSTAT in BIOS dad d shld bconst+1 ;stuff it into the call-instruction lxi d,3 ;next adress is CONIN in BIOS dad d shld bconin+1 ; lxi d,3 ;next adress is CONOUT in BIOS dad d shld bcnout+1 lxi d,3 ;next address is LIST in BIOS dad d shld blsout+1 ret ;And return bconst: jmp $-$ ;Call BIOS directly (filled in by iniadr) bconin: jmp $-$ ;Call BIOS directly (filled in by iniadr) bcnout: jmp $-$ ;Call BIOS directly (filled in by iniadr) blsout: jmp $-$ ; .... ENDIF;iobyt IF mikko ;currently for MIKROMIKKO only ; copy command block into memory-mapped SIO. movmik: di ;disable interrupts movmk1: ldax d ;Get a register value mov m,a ;Output it inx d ;Next value dcr c ;Decrement counter jnz movmk1 ;Repeat until done ei ret ENDIF;mikko ; IF osbrn1 osmove: osflag equ 0EF08H ;Osborne 1 Bank-2 flag ; ; return modem status in A ; OSLDST EQU ostop-osmove+$ DI OUT 0 LDA osprts ;Read the status port OUT 1 EI ret ; ; set modem status from A ; OSSTST equ ostop-osmove+$ DI OUT 0 STA osprts ;Write the control port jmp osstex ; ; read character from modem into A ; OSLDDA equ ostop-osmove+$ DI OUT 0 LDA osport OUT 1 EI ret ; ; output character in A to modem ; OSSTDA equ ostop-osmove+$ DI OUT 0 STA osport osstex equ ostop-osmove+$ OUT 1 mvi a,1 sta osflag EI ret osmct equ $-osmove ENDIF;osbrn1 IF kpii OR bbII ; List of commands to set up SIO channel A for asynchronous operation. siotbl: DB 18H ; Channel reset DB 18H ; another, in case register 0 wasn't selected DB 04H ; Select register 4 DB 44H ; 1 stop bit, clock*16 DB 01H ; Select register 1 DB 00H ; No interrupts enabled DB 03H ; Select register 3 DB 0C1H ; Rx enable, 8 bit Rx character DB 05H ; Select register 5 DB 0EAH ; Tx enable, 8 bit Tx character, ; raise DTR and RTS siolen equ $-siotbl ; length of command list ENDIF;kpii or bbII IF mikko ; command list to set SIO chip back to normal state miotbl: db 3 ;reg. 3 db sioo3 db 5 ;reg. 5 db sioo5 db 4 ;reg. 4 db sioo4 db 0 ;reselect reg. 0 miolen equ $-miotbl ;MikroMikko SIO table length (original values) ; command list to set up SIO chip for operation with Kermit mintbl: db 3 ;reg. 3 db sion3 db 5 ;reg. 5 db sion5 db 4 ;reg. 4 db sion4 db 0 ;reselect reg. 0 minlen equ $-mintbl ;MikroMikko SIO table length (KERMIT values) ENDIF;mikko ; ; ; system-dependent termination processing ; If we've changed anything, this is our last chance to put it back. sysexit: IF mikko lxi d,miotbl ;Load the adress of original reg values mvi c,miolen ;Length of table lxi h,sioac ;Send data to ch A SIO registers call movmik mvi a,07FH ;Set ch A mask to use just 7 bits sta chmask ENDIF;mikko ret ; ; system-dependent processing for start of CONNECT command ; syscon: IF apmmdm call ckdial ;See if dialing is required. jmp kermit ;Go to command loop if aborted. ENDIF;apmmdm IF robin OR trs80 ;For Robin and TRS80, add some more info lxi d,conmsg ; about obscure key combinations call prtstr ENDIF;robin OR trs80 IF osbrn1 ;*** This is Software dependent *** lhld 1 ;Modify back-arrow code to DELETE mvi l,0 ;Get BIOS-start address lxi d,85H ;Adress for key-code = XX85H dad d mov e,m ;Get it in DE inx h mov d,m xchg ;Memory pointer to HL mvi m,del ;modify the code ENDIF;osbrn1 ret conmsg: ; Messages printed when entering transparent (CONNECT) mode: IF robin ; for Robin, control-S key is hidden db ' (Type Left Arrow to send CTRL-S)',cr,lf,'$' ENDIF;robin IF trs80 ; for TRS-80, the preferred escape key is hidden db ' (Control-_ is the Down-Arrow key on the TRS-80 keyboard)' db cr,lf,'$' ENDIF;trs80 ; IF apmmdm ;This code was mostly taken from ; APMODEM.ASM V2.1 ; Based on MODEM.ASM by Ward Christensen ; Modified for the Apple ][ by Gordon Banks 1-Jan-81 ; Micromodem ][ dialer option by Dav Holle 2-Feb-81 ; Code modified for KERMIT by Scott Robinson 14-Oct-82 ; ;Come here to see if we need to dial a number. ; ckdial: lda mnport ;access the data port lda mnprts ;check status ani 4 ;do we already have carrier? jz rskp ;Yes, just continue xra a ;Hangup Phone for starters sta mnmodm lxi b,1000 ;Delay for a second call delay mvi a,8FH ;orgmod+ap300+apoffh sta holdd ;storing mode for after dialing mvi A,8DH ;Go Offhook to start dialing sequence sta mnmodm mvi a,apinc1 ;Init ACIA sta mnport mvi a,apinc2 ;Set ACIA bits per character sta mnport lxi b,2500 ;wait 2.5 seconds for dial tone call delay lxi d,dialms ;Ask the user for the number call prtstr ; gtdial: mvi c,conin ;Get a character call bdos push psw ;save it cpi 30H ;is it big enough to dial? jc dialed ;no cpi 3AH ;is it too big to dial? jnc dialed ;yes ani 0FH ;ok, it's a digit, get its value jnz dialnz ;dial nonzero digits as-is mvi A,10 ;dial zero as ten ; dialnz: mov e,a ;count pulses in E-reg dopuls: mvi a,0DH ;put it on-hook sta mnmodm lxi b,61 ;61-millisec pulse call delay mvi a,8DH ;take it off-hook again... sta mnmodm lxi b,39 ;39-millisec delay between pulses call delay dcr e ;any more pulses to do? jnz dopuls ;yep, do 'em lxi b,600 ;delay 600 msecs between digits call delay ; dialed: pop psw ;get back the char cpi cr ;do we have a CR (done dialing)? jnz gtdial ;no, keep on dialin' lxi d,dialm2 call prtstr tictoc: mvi c,dconio ;Direct console input. mvi e,0FFH call bdos ora a ;Have a charcter? jnz nodial ;If so we abort lda mnport ;access the data port lda mnprts ;get modem status ani 4 ;carrier? jnz tictoc ;No ; lda holdd ;get the old modem control byte sta mnmodm ;turn our carrier on lxi d,dialm3 call prtstr jmp rskp nodial: xra a ;Hangup the modem. sta mnmodm ret ;Return to abort the command. ; holdd: db 0 ;Modem setup code dialms: DB 'Number to Dial: $' dialm2: DB CR,LF,'Awaiting Carrier....(any key aborts)$' dialm3: DB cr,lf,'Connected.',CR,LF,'$' ; ;DELAY wait for the number of millisecs in B,C ; delay: push b ;save B,C push d ;save D,E inr b ;bump B for later DCR ; delay1: mvi e,126 ;delay count for 1 millisec (Apple Z80 ;clock=2.041MHz) ; delay2: dcr e ;count jnz delay2 ;down ; dcr c ;more millisecs? jnz delay1 ;yes dcr b ;no - more in hi byte? jnz delay1 ;yes pop d ;no, restore D,E pop b ; restore B,C ret ENDIF;apmmdm ; ; ; syscls - system-dependent close routine ; called when exiting transparent session. ; syscls: IF osbrn1 lhld 1 ;Modify back-arrow code to BACKSPACE mvi l,0 ;Get BIOS address lxi d,85H ;Address for key-code =XX85H dad d mov e,m ;Get it in DE inx h mov d,m xchg ;Address to HL mvi m,bs ;Modify code ENDIF;osbrn1 ret ; ; ; sysinh - help for system-dependent special functions. ; called in response to ?, after listing all the ; system-independent escape sequences. ; sysinh: IF apmmdm OR robin OR dmII OR bbII OR kpii lxi d,inhlps ; we got options... call prtstr ; print them. ENDIF;apmmdm OR robin OR dmII OR bbII OR kpii ret ;additional, system-dependent help for transparent mode ; (two-character escape sequences) inhlps: IF apmmdm db cr,lf,'D Close and disconnect the connection$' ENDIF;apmmdm IF robin OR dmII OR bbII OR kpii db cr,lf,'B Transmit a BREAK$' ENDIF;robin OR dmII OR bbII OR kpii ; ; sysint - system dependent special functions ; called when transparent escape character has been typed; ; the second character of the sequence is in A (and in B). ; returns: ; non-skip: sequence has been processed ; skip: sequence was not recognized sysint: ani 137O ; convert lower case to upper, for testing... IF apmmdm cpi 'D' ;Disconnect Modem? jnz intc00 ;No. xra a ;Yes, hangup the modem sta mnmodm ret ; command has been executed intc00: ENDIF;apmmdm IF robin OR dmII OR kpII OR bbII cpi 'B' ; send break? jz sendbr ; yes, go do it. return nonskip when through. ENDIF;robin OR dmII OR kpII OR bbII jmp rskp ; take skip return - command not recognized. ; IF robin ;Definitions & code to send a BREAK (ungenerically, no other way). comctl equ 59h ;VT180 communications port crtctl equ 41h ;VT180 crt port ;VT180 serial port command bits txe equ 1 ;transmit enable dtr equ 2 ;dtr on rxe equ 4 ;rx enable sndbrk equ 8 rerr equ 10h ;reset error rts equ 20h ;RTS on reset equ 40h ;port reset ;Send a break to the communications port. ; sendbr: lxi h,38500 ;250 ms(?) lda prtadr ;Get address of selected port mov c,a ;Into C mvi a,sndbrk+dtr ; OUT C,A ;Want to send to port addressed by C db 0EDH,079H ;Op code for above instruction sndbr1: dcx h ;timing loop... mov a,l ora h jnz sndbr1 ;...until over lda prtadr ;Get the address for the port mov c,a ;Into C mvi a,txe+dtr+rxe+rerr+rts ;enable tr/rc, dtr, reset error ; out c,a ;Z-80 only instruction db 0EDH,079H ;Op code for above instruction out contst ;reset ports ret ENDIF;robin ; IF dmII ;[jd] this added to send break on DECmate ; DECmate command codes for 6120 I/O processor oboff equ 3fh ; offset of outbyt routine for 6120 prtctl equ 02h ; port control brdat equ 06h ; data to tell 6120 to send a break brdur equ 30 ; duration, 30 = 300 ms. sendbr: lxi b,(brdat * 100h) + prtctl ; c/prtctl, b/brdat call outbyt lxi b,brdur*100h ; b/duration, c/0 ; fall through into outbyt outbyt: lhld 1 ; get warm boot address lxi d,oboff ; offset of outbyt routine dad d ; compute address pchl ; branch there (a callret) ENDIF;dmII ; IF kpII OR bbII ;[cjc] send break on Kaypro and bbII ; Officially, a "break" is 300 milliseconds of "space" (idle line is ; "mark"). (or maybe 200 milliseconds; I forget.) The timing isn't ; usually that critical, but we'll make an attempt, at least. Sending ; too long a break can cause some modems to hang up. sendbr: ; First, make sure the transmitter is really empty. (The SIO sets ; "transmitter buffer empty" when it can accept another character; ; the previous character is still being shifted onto the line. ; Another status bit, "all done", is set to indicate that the ; transmitter is really idle. sndbr1: mvi a,1 ; select Read Register 1 out mnprts in mnprts ; read the contents ani 1 ; test "all done" flag jz sndbr1 ; loop until it's nonzero. ; ; Next, set the "send break" bit to start the transmitter spacing. mvi a,5 ; select Write Register 5 out mnprts mvi a,0FAH ; Tx enable, 8 bit Tx character, Send Break, out mnprts ; DTR and RTS on. ; ; Now, delay for 30 hundredths of a second mvi a,30 ; delay count call delay ; ; Time's up. Put transmitter back in normal state (data byte is the ; same as the one in siotbl: for Write Register 5) and return. mvi a,5 ; select Write Register 5 out mnprts mvi a,0EAH ; Tx enable, 8 bit Tx character, out mnprts ; DTR and RTS on. ret ; done. ; ; Delay routine. Called with time (hundredths of seconds) in A. ; The inner loop delays 1001 T-states, assuming no wait states are ; inserted; this is repeated CPUSPD times, for a total delay of just ; over 0.01 second. (CPUSPD should be set to the system clock rate, ; in units of 100KHz: for an unmodified Kaypro II, that's 25 for ; 2.5 MHz. Some enterprising soul could determine whether or not the ; Kaypro actually inserts a wait state on instruction fetch (a common ; practice); if so, the magic number at delay2 needs to be decreased. ; (We also neglect to consider time spent at interrupt level). ; ; called by: sendbr ; destroys BC delay: mvi c,cpuspd ; Number of times to wait 1000 T-states to ; make .01 second delay delay2: mvi b,70 ; Number of times to execute inner loop to ; make 1000 T-state delay delay3: dcr b ; 4 T-states (* 70 * cpuspd) jnz delay3 ; 10 T-states (* 70 * cpuspd) dcr c ; 4 T-states (* cpuspd) jnz delay2 ; 10 T-states (* cpuspd) ; total delay: ((14 * 70) + 14) * cpuspd ; = 1001 * cpuspd + call/return overhead. ret ENDIF;kpII OR bbII ; ; ; sysflt - system-dependent filter ; called with character in E. ; if this character should not be printed, return with A = zero. ; preserves bc, de, hl. ; note: ,,, and are always discarded. sysflt: mov a,e ; get character for testing IF mikko cpi 'O'-100O ;Control-O's lock keyboard rnz ; if not control-O, it's ok. xra a ; don't allow control-O out. ENDIF;mikko ret ; ; ; system-dependent processing for BYE command. ; for apmmdm, hang up the phone. sysbye: IF apmmdm xra a ;Hangup our end, too. sta mnmodm ENDIF;apmmdm ret ; ; This is the system-dependent command to change the baud rate. ; DE contains the two-byte value from the baud rate table; this ; value is also stored in 'speed'. sysspd: ; Set the speed for the Brain IF brain lda baudrt ;Get the present baud rates. ani 0fH ;turn off the left mov d,a ;Set it aside. mov a,e ;Get the new baud rate. rlc ;Shift left 4 places. rlc rlc rlc ora d ; combine with the old baud rate sta baudrt ;Store the new baud rates. out baudst ;Set the baud rates. ret ENDIF;brain ; Set the speed for the Osborne I IF osbrn1 mvi a,osbin1 ;Reset the ACIA call osstst ;Write the control port osbs1: inr c ;Waiting loop jnz osbs1 mov a,e ; get the specified speed jmp osstst ;Write the control reg. ENDIF;osbrn1 ; Set the speed for bigboard II IF bbII di ; don't let anything between the data bytes mvi a,01000111b ; get the command byte (load time constant) out baudrt ; output it to CTC mov a,e ; Get the parsed value. out baudrt ; Tell the baud rate generator. ei ; end of critical section ret ENDIF;bbII ; Set the speed for kaypro II or the delphi IF kpII OR delphi ; [7] mov a,e ; get the parsed value out baudrt ; Tell the baud rate generator. ret ENDIF;kpII OR delphi ; [7] ; Set the speed for MicroMikko. DE is baud rate multiplier IF mikko di lxi h,txclk mov m,d ;LSB first (swapped in memory) mov m,e ;MSB last lxi h,rxclk mov m,d mov m,e mvi b,0 ;"modifier" for 1 stop bit mvi a,2 ;Test MSB of speed >2 (110 bps or less) cmp e jp miksp1 mvi b,00001000B ;"modifier" for 2 stop bits miksp1: mvi a,4 ;Select SIO Reg 4 lxi h,sioac mov m,a mvi a,sion4 ;Get values ora b ;Add modifier mov m,a ;Set value (stop bits) ei ret ENDIF;mikko ; Set the speed for Apple with 6551 ACIA IF ap6551 lda mnprtc ;jb read control port ani 0F0H ;jb zap low order nybble ora e ;jb put rate in low order nybble sta mnprtc ;jb send to control port ret ENDIF;ap6551 ; Set the speed for the Decision I IF mdI call selmdm ;Let's be absolutely sure, huh? mvi a,dlab+wls1+wls0+stb ;Set data latch access bit out lcr ;Out to Line Control Register lhld speed ;Load baudrate multiplier xchg mov a,d ;Get low order byte for baud rate out dlm ;Out to the MSB divisor port mov a,e ;...and the high order byte out dll ;Out to the LSB divisor port mvi a,wls1+wls0+stb ;Enable Divisor Access Latch out lcr ;Out to ACE Line Control Register xra a ;Clear A out ier ;Set no interrupts out lsr ;Clear status in msr ;Clear Modem Status Register in lsr ;Clear Line Status Register in rbr ;Clear Receiver Buffers in rbr ret ENDIF ;mdI [Toad Hall] ; Speed tables ; (Note that speed tables MUST be in alphabetical order for later ; lookup procedures, and must begin with a value showing the total ; number of entries. The speed help tables are just for us poor ; humans. ; db string length,string,divisor (2 identical bytes or 1 word) ; [Toad Hall] IF kpii OR brain OR delphi ; [7] spdtbl: db 10h ;16 entries db 03h,'110$', 02h,02h db 04h,'1200$', 07h,07h db 05h,'134.5$', 03h,03h db 03h,'150$', 04h,04h db 04h,'1800$', 08h,08h db 05h,'19200$', 0fh,0fh db 04h,'2000$', 09h,09h db 04h,'2400$', 0ah,0ah db 03h,'300$', 05h,05h db 04h,'3600$', 0bh,0bh db 04h,'4800$', 0ch,0ch db 02h,'50$', 00h,00h db 03h,'600$', 06h,06h db 04h,'7200$', 0dh,0dh db 02h,'75$', 01h,01h db 04h,'9600$', 0eh,0eh sphtbl: db cr,lf,' 50 75 110 134.5 150 300 600 1200' db cr,lf,' 1800 2000 2400 3600 4800 7200 9600 19200$' ENDIF;kpii OR brain OR delphi ; [7] IF bbII spdtbl: db 8 ; 8 entries db 04h,'1200$', 20h,20h db 05h,'19200$', 02h,02h db 04h,'2400$', 10h,10h db 03h,'300$', 80h,80h db 05h,'38400$', 01h,01h db 04h,'4800$', 08h,08h db 03h,'600$', 40h,40h db 04h,'9600$', 04h,04h sphtbl: db cr,lf,' 300 600 1200 2400 4800 9600 19200 38400$' ENDIF;bbII IF mikko spdtbl: db 9h ;9 entries db 03h,'110$' dw 0369h db 04h,'1200$' dw 0050h db 03h,'150$' dw 0280h db 04h,'2400$' dw 0028h db 03h,'300$' dw 0140h db 04h,'4800$' dw 0014h db 03h,'600$' dw 00A0H db 02h,'75$' dw 0500h db 04h,'9600$' dw 000ah sphtbl: db cr,lf,' 75 110 150 300 600 1200 2400 4800 9600$' ENDIF;mikko IF osbrn1 spdtbl: db 02h ;2 entries db 04h,'1200$', OSBI12,OSBI12 db 03h,'300$', OSBI03,OSBI03 sphtbl: db cr,lf,' 300',cr,lf,' 1200$' ENDIF;osbrn1 IF ap6551 ;jb spdtbl: db 0DH ;jb 13 entries db 03H,'110$', 03H,03H ;jb db 04H,'1200$', 08H,08H ;jb db 05H,'134.5$', 04H,04H ;jb db 03H,'150$', 05H,05H ;jb db 04H,'1800$', 09H,09H ;jb db 05H,'19200$', 0FH,0FH ;jb db 04H,'2400$', 0AH,0AH ;jb db 03H,'300$', 06H,06H ;jb db 04H,'3600$', 0BH,0BH ;jb db 04H,'4800$', 0CH,0CH ;jb db 03H,'600$', 07H,07H ;jb db 04H,'7200$', 0DH,0DH ;jb db 04H,'9600$', 0EH,0EH ;jb sphtbl: db cr,lf,' 110 134.5 150 300 600 1200 1800' db cr,lf,' 2400 3600 4800 7200 9600 19200$' ENDIF;ap6551 IF mdI spdtbl: db 0dh ; 13 entries db 03h, '110$' dw 1047 db 04h, '1200$' dw 96 db 03h, '150$' dw 768 db 05h,'19200$' dw 6 db 04h, '2400$' dw 48 db 03h, '300$' dw 384 db 05h,'38400$' dw 3 db 03h, '450$' dw 288 db 04h, '4800$' dw 24 db 05h,'56000$' dw 2 db 03h, '600$' dw 192 db 02h, '75$' dw 1536 db 04h, '9600$' dw 12 sphtbl: db cr,lf,' 75 110 150 300 450 600 1200' db cr,lf,' 2400 4800 9600 19200 38400 56000$' ;(Lord knows what you'll be communicating with at 56000 baud, but the ;Multi-I/O board literature says it'll do it, so what the heck.... ;might as well throw it in here just to show off...sure hope the ;port don't melt...) ENDIF ;mdI [Toad Hall] IF NOT (brain OR osbrn1 OR bbII OR kpII OR mikko OR ap6551 OR mdI OR delphi) spdtbl equ 0 ; SET BAUD not supported. sphtbl equ 0 ENDIF;NOT (brain OR osbrn1 OR bbII OR kpII OR mikko OR ap6551 OR mdI OR delphi) ; ; This is the system-dependent SET PORT command. ; HL contains the argument from the command table. sysprt: IF iobyt mov a,m ;Get the I/O byte sta prtiob ;Save the desired IO byte for this port inx h ;Point at next entry mov a,m ;Get the output function sta prtfun ;Save it ENDIF;iobyt IF iobyt AND robin inx h ;Point at next entry mov a,m ;Get the hardware address for the port sta prtadr ;Store it ENDIF;iobyt AND robin ret ; ; ; Port tables for GENERIC CPM 2.2 IF gener ; help text prhtbl: db cr,lf,'CRT device' db cr,lf,'PTR device' db cr,lf,'TTY device' db cr,lf,'UC1 device' db cr,lf,'UR1 device' db cr,lf,'UR2 device$' ; command table prttbl: db 06H ;Six devices to choose from db 03H,'CRT$' dw crtptb db 03H,'PTR$' dw ptrptb db 03H,'TTY$' dw ttyptb db 03H,'UC1$' dw uc1ptb db 03H,'UR1$' dw ur1ptb db 03H,'UR2$' dw ur2ptb ; port entry table ; table entries are: ; db iobyte-value, BDOS output function, reserved crtptb: db crtio,conout,0 ptrptb: db ptrio,punout,0 ttyptb: db ttyio,conout,0 uc1ptb: db uc1io,conout,0 ur1ptb: db ur1io,punout,0 ur2ptb: db ur2io,punout,0 ENDIF;gener ; ; ; Port tables for DECmate II or MicroMikko ; IF dmII OR mikko ; help text prhtbl: db cr,lf,'COMMUNICATIONS port$' ; command table prttbl: db 01H ;Only one port known at this point db 0EH,'COMMUNICATIONS$' dw comptb ;address of info ; port entry table ; table entries are: ; db iobyte-value, BDOS output function, reserved comptb: db batio,punout,0 ENDIF;dmII OR mikko ; ; ; Port tables for Robin ; IF robin ; help text prhtbl: db cr,lf,'COMMUNICATIONS port' db cr,lf,'GENERAL purpose port' db cr,lf,'PRINTER port$' ; command table prttbl: db 03H ;Three entries db 0EH,'COMMUNICATIONS$' dw comptb db 07H,'GENERAL$' dw gppptb db 07H,'PRINTER$' dw prnptb ; port entry table ; table entries are: ; db iobyte-value, BDOS output function, hardware port address ; (control/status) ; ;At present, the hardware port address is only used for sending a break. comptb: db batio,punout,comtst gppptb: db gppio,conout,gentst prnptb: db lptio,conout,prntst prtadr: db comtst ;space for current hardware port address ENDIF;robin IF iobyt prtfun: db punout ;Function to use for output to comm port prtiob: db batio ;I/O byte to use for communicating coniob: db defio ;I/O byte to use for console ENDIF;iobyt IF NOT iobyt prttbl equ 0 ; SET PORT is not supported prhtbl equ 0 ENDIF;NOT iobyt ; ; ; Set up screen display for file transfer ; called with kermit version in DE ; sysscr: push d ; save version for a bit lxi d,outlin ; clear screen, position cursor call prtstr ; do it pop d ; get Kermit's version IF NOT (osi OR crt) ; got cursor control? call prtstr ; print it mvi e,'[' ; open bracket call outcon ; print it (close bracket is in outln2) lxi d,sysver ; get name and version of system module call prtstr lxi d,outln2 ; yes, print field names call prtstr lda dbgflg ; is debugging enabled? ora a rz ; finished if no debugging lxi d,outln3 ; set up debugging fields call prtstr ENDIF;NOT (osi OR crt) ret ; ; Calculate free space for current drive ; returns value in HL sysspc: IF cpm3 ;cpm3's alloc vect may be in another bank lda fcb ;If no drive, get ora a ; logged in drive jz dir180 dcr a ;FCB drive A=1 normalize to be A=0 jmp dir18a dir180: mvi c,rddrv call bdos dir18a: mov e,a ;drive in e mvi c,getfs ;get free space BDOS funct call bdos ;returns free recs (3 bytes in buff..buff+2) mvi b,3 ;conv recs to K by 3 bit shift dir18b: xra a ;clear carry mvi c,3 ;for 3 bytes lxi h,buff+3 ;point to addr + 1 dir18c: dcx h ;point to less sig. byte mov a,m ;get byte rar ;carry -> A -> carry mov m,a ;put back byte dcr c ;for all bytes (carry not mod) jnz dir18c dcr b ;shift 1 bit 3 times jnz dir18b mov e,m ;get least sig byte inx h mov d,m ;get most sig byte xchg ;get K free in HL ENDIF;cpm3 IF NOT cpm3 ; the rest are CP/M 2.2 systems, so use the alloc vector mvi c,getalv ;Address of CP/M Allocation Vector call bdos xchg ;Get its length lhld bmax inx h lxi b,0 ;Initialize Block count to zero dir19: push d ;Save allocation address ldax d mvi e,8 ;set to process 8 blocks dir20: ral ;Test bit jc dir20a inx b dir20a: mov d,a ;Save bits dcx h mov a,l ora h jz dir21 ;Quit if out of blocks mov a,d ;Restore bits dcr e ;count down 8 bits jnz dir20 ;do another bit pop d ;Bump to next count of Allocation Vector inx d jmp dir19 ;process it dir21: pop d ;Clear Allocation vector from stack mov l,c ;Copy block to 'HL' mov h,b lda bshiftf ;Get Block Shift Factor sui 3 ;Convert from records to thousands rz ;Skip shifts if 1K blocks dir22: dad h ;Multiply blocks by 'K per Block' dcr a jnz dir22 ret ENDIF;NOT cpm3 [Toad Hall] ; ; ; selmdm - select modem port ; selcon - select console port ; selmdm is called before using inpmdm or outmdm; selcon is called before ; using inpcon or outcon. ; For iobyt systems, diddle the I/O byte to select console or comm port; ; For Decision I, switches Multi I/O board to console or modem serial ; port. [Toad Hall] ; For the rest, does nothing. ; preserves bc, de, hl. selmdm: IF iobyt lda prtiob ;Set up for output to go to the comm port sta iobyte ;Switch byte directly ENDIF;iobyt IF mdI lda group ori mdmgrp ;Mask modem serial port out grpsel ENDIF;mdI [Toad Hall] ret selcon: IF iobyt lda coniob ;Set up for output to go to the console port sta iobyte ;Switch directly ENDIF;iobyt IF mdI lda group ori congrp ;Mask console serial port (1) out grpsel ENDIF;mdI [Toad Hall] ret ; ; Get character from console, or return zero. ; result is returned in A. destroys bc, de, hl. ; inpcon: IF NOT iobyt mvi c,dconio ;Direct console I/O BDOS call. mvi e,0FFH ;Input. call BDOS ENDIF;NOT iobyt IF iobyt call bconst ;Get the status ora a ;Anything there? rz ;No, forget it call bconin ;Yes, get the character ENDIF;iobyt ret ; ; ; Output character in E to the console. ; destroys bc, de, hl ; outcon: IF NOT iobyt mvi c,dconio ;Console output bdos call. call bdos ;Output the char to the console. ENDIF;NOT iobyt IF iobyt mov c,e ;Character call bcnout ;to Console ENDIF;iobyt ret ; ; ; outmdm - output a char from E to the modem. ; the parity bit has been set as necessary. ; returns nonskip; bc, de, hl preserved. IF osi OR apple outmdm: push h lxi h,mnprts ;address of the port status register outmd2: mov a,m ; get port status in A ani output ;Loop till ready. jz outmd2 lxi h,mnport ;address of port data register mov m,e ; write the character pop h ret ENDIF;osi OR apple IF osbrn1 outmdm: call osldst ;Read the status port ani output ;Loop till ready. jz outmdm mov a,e jmp osstda ;Write to the data port ENDIF;osbrn1 IF inout outmdm: in mnprts ;Get the output done flag. ani output ;Is it set? jz outmdm ;If not, loop until it is. mov a,e out mnport ;Output it. ret ENDIF;inout IF iobyt ;****Note that we enter from outpkt with the I/O byte already set up for ;output to go to the comm port outmdm: push h push b lda prtfun ;Get the output function mov c,a ;Into C call bdos ;And output the character pop b pop h ret ENDIF;iobyt IF cpm3 outmdm: push h push b mvi c,auxout ;Output to the aux output device call bdos pop b pop h ret ENDIF;cpm3 ; ; ; get character from modem; return zero if none available. ; for IOBYT systems, the modem port has already been selected. ; destroys bc, de, hl. inpmdm: IF iobyt call bconst ;Is Char at COMM-Port? ora a ;something there? rz ; return if nothing there call bconin ; data present. read data. ENDIF;iobyt IF cpm3 mvi c,auxist call bdos ;is char at auxin? ora a ;something there? rz ;no mvi c,auxin call bdos ;read char from auxin ENDIF;cpm3 IF osi OR apple lda mnprts ;Get the port status into A. ani input ;See if the input ready bit is on. rz ;If not then return. lda mnport ;If so, get the char. ENDIF;osi OR apple IF osbrn1 call osldst ;Read the status port ani input ;Something there? rz ;Nope call osldda ;Read the data port ENDIF;osbrn1 IF inout ;Note: modem port should already be selected for mdI. [Toad Hall] in mnprts ;Get the port status into A. ani input ;See if the input ready bit is on. rz ;If not then return. in mnport ;If so, get the char. ENDIF;inout ret ; return with character in A ; ; flsmdm - flush comm line. ; Modem is selected. ; Currently, just gets characters until none are available. flsmdm: call inpmdm ; Try to get a character ora a ; Got one? jnz flsmdm ; If so, try for another ret ; Receiver is drained. Return. ; ; ; outlpt - output character in E to printer ; console is selected. ; preserves de. outlpt: push d ; save DE in either case IF NOT iobyt mvi c,lstout call bdos ;Char to printer ENDIF;NOT iobyt IF iobyt mov c,e call blsout ENDIF;iobyt pop d ; restore saved register pair ret ; ; ; Screen manipulation routines ; csrpos - move to row B, column C ; ; csrpos for terminals that use a leadin sequence followed ; by (row + 31.) and (column + 31.) ; IF NOT (robin OR dmII OR vt100 OR osi OR crt OR vector) csrpos: push b ; save coordinates lxi d,curldn ; get cursor leadin sequence call prtstr ; print it pop h ; restore coordinates mov a,h ; get row adi (' '-1) ; space is row one mov e,a push h call outcon ; output row pop h mov a,l ; get column adi (' '-1) ; space is column one mov e,a jmp outcon ; output it and return ENDIF;NOT (robin OR dmII OR vt100 OR osi OR crt OR vector) ; ; csrpos for ANSI terminals ; IF robin OR dmII OR vt100 csrpos: push b ; save coordinates lxi d,curldn ; get cursor leadin sequence call prtstr ; print it pop h ; peek at coordinates push h ; then save away again mov l,h ; l = row mvi h,0 ; hl = row call nout ; output in decimal mvi e,';' ; follow with semicolon call outcon ; print it pop h ; restore column mvi h,0 ; hl = column call nout mvi e,'H' ; terminate with 'move cursor' command jmp outcon ; output it and return ENDIF;robin OR dmII OR vt100 ; ; csrpos for the Vector General. It's weird. ; IF vector csrpos: dcr b ; vector uses zero-based addressing? dcr c push b ; save coordinates mvi e,esc ; print an escape call outcon pop d ; peek at coordinates push d call outcon ; output column pop d mov e,d ; get row jmp outcon ; output and return ENDIF;vector IF osi OR crt ; systems without cursor positioning csrpos: ret ; dummy routine referenced by linkage section ENDIF;osi OR crt ; ; position to various fields: ; for the Kermits with cursor positioning, the display looks like this: ; 5 10 15 20 25 30 35 ; +----|----|----|----|----|----|----|... ; 1 | ; 2 | Kermit-80 v4.0 [system] ; 3 | ; 4 |Number of packets: ____ ; 5 |Number of retries: ____ ; 6 |File name: ____________ ; 7 |... ; 8 |... ; 9 |RPack: ___(if debugging)... ; 10 | ; 11 |SPack: ___(if debugging)... ; 12 | ; 13 |Kermit-80 A:> (when finished) ; IF NOT (osi OR crt) scrnp: lxi b,4*100H+20 jmp csrpos scrnrt: lxi b,5*100H+20 jmp csrpos scrfln: lxi b,6*100H+12 call csrpos clreol: lxi d,tk jmp prtstr screrr: lxi b,7*100H+1 call csrpos jmp clreol scrst: lxi b,8*100H+1 call csrpos jmp clreol rppos: lxi b,9*100H+8 call csrpos jmp clreol sppos: lxi b,11*100H+8 call csrpos jmp clreol scrend: lxi b,13*100H+1 call csrpos clreos: lxi d,tj jmp prtstr ENDIF;NOT (osi OR crt) IF osi OR crt ; no cursor control scrnp: mvi e,' ' jmp outcon scrnrt: mvi e,' ' call outcon mvi e,'%' jmp outcon scrfln: screrr: scrst: scrend: jmp prcrlf ;Print CR/LF [Toad Hall] rppos: lxi d,prpack jmp prtstr sppos: lxi d,pspack jmp prtstr ENDIF;osi OR crt ; ; delchr - make delete look like a backspace. Unless delete is a printing ; character, we just need to print a backspace. (we'll output clrspc ; afterwards) ; For Kaypro and Vector General, delete puts a blotch on the screen. ; For Apple and Osborne 1, delete moves but doesn't print. delchr: IF kpII OR vector OR apple OR osbrn1 lxi d,delstr jmp prtstr ENDIF;kpII OR vector OR apple OR osbrn1 IF NOT (kpII OR vector OR apple OR osbrn1) mvi e,bs ;get a backspace jmp outcon ENDIF;NOT (kpII OR vector OR apple OR osbrn1) ; erase the character at the current cursor position clrspc: mvi e,' ' call outcon mvi e,bs ;get a backspace jmp outcon ; erase the current line clrlin: lxi d,eralin jmp prtstr ; erase the whole screen, and go home. preserves b (but not c) clrtop: lxi d,erascr jmp prtstr ; Some frequently-used routines (duplicates of those in CP4MIT): ; prcrlf - output a CR/LF ; prtstr - output string in DE ; rskp - return, skipping over error return prcrlf: lxi d,crlf prtstr: mvi c,prstr jmp bdos rskp: pop h ; Get the return address inx h ; Increment by three inx h inx h pchl ; Copy block of data ; source in HL, destination in DE, byte count in BC ; called by: cp4sys, mfname ; mover: IF NOT z80 ; 8080's have to do it the hard way mov a,m stax d inx h inx d dcx b mov a,b ora c jnz mover ENDIF;NOT z80 IF z80 db 0EDh,0B0h ; Z80 LDIR instruction ENDIF;z80 ret ; ; ; Miscellaneous messages ; crlf: db cr,lf,'$' cfgmsg: db 'configured for $' IF adm3a OR tvi925 OR vt52 OR vt100 OR smrtvd ; [7] witmsg: db ' with $' ENDIF;adm3a OR tvi925 OR vt52 OR vt100 OR smrtvd ; [7] ;**************************Terminal tables**************************** IF NOT (osi OR crt) ; got cursor control? outln2: db ']',cr,lf,cr,lf,'Number of packets:' db cr,lf,'Number of retries:' db cr,lf,'File name:$' outln3: db cr,lf,cr,lf ; debugging messages db cr,lf,'RPack:' db cr,lf ; blank line in case of long packet db cr,lf,'SPack:$' ENDIF;NOT (osi OR crt) IF brain sysver: db 'Intertec SuperBrain$' outlin: db ('A'-100O),esc,'~k',cr,lf,tab,tab,'$' erascr: db ('A'-100O),esc,'~k$' ;Clear screen and go home. eralin: db cr,esc,'~K$' ;Clear line. curldn: db esc,'Y$' ; leadin for cursor positioning ttab: ;Table start location. ta: db ('K'-100O),'$',0,0 ;Cursor up. tb: db 12O,'$',0,0 ;Cursor down. tc: db ('F'-100O),'$',0,0 ;Cursor right. td: db '$',0,0,0 ;(can't) Cursor left te: db '$',0,0,0 ;(can't) Clear display tf: db '$',0,0,0 ;(can't) Enter graphics mode tg: db '$',0,0,0 ;(can't) Exit graphics mode th: db ('A'-100O),'$',0,0 ;Cursor home. ti: db ('K'-100O),'$',0,0 ;Reverse linefeed. tj: db esc,'~k$',0 ;Clear to end of screen. tk: db esc,'~K$',0 ;Clear to end of line. ENDIF;brain ; IF osbrn1 sysver: db 'Osborne 1$' outlin: db 1AH,tab,'$' ;(Clear screen, home cursor) erascr: db 1AH,'$' ;Clear screen and go home. eralin: db cr,esc,'T$' ;Clear line. delstr: db bs,bs,'$' ; Adjust for delete curldn: db esc,'=$' ;Cursor lead-in ttab: ;Table start location. ta: db ('K'-100O),'$',0,0 ;Cursor up. tb: db 12O,'$',0,0 ;Cursor down. tc: db ('L'-100O),'$',0,0 ;Cursor right. td: db bs,'$',0,0 ;Cursor left. te: db subt,'$',0,0 ;Clear screen. tf: db '$',0,0,0 ;(can't) Enter graphics mode tg: db '$',0,0,0 ;(can't) Exit graphics mode th: db ('^'-100O),'$',0,0 ;Cursor home. ti: db ('K'-100O),'$',0,0 ;Reverse linefeed. tj: db esc,'T$',0 ;(can't) Clear to end of screen. tk: db esc,'T$',0 ;Clear to end of line. ENDIF;osbrn1 ; IF apple sysver: db 'Apple II CP/M$' outlin: db ('^'-100O),esc,'Y',cr,lf,' $' erascr: db ('^'-100O),esc,'Y$' ;Clear screen and go home. eralin: db cr,esc,'T$' ;Clear line. delstr: db bs,bs,'$' ; Adjust for delete curldn: db esc,'=$' ;Cursor lead-in ttab: ;Table start location. ta: db ('K'-100O),'$',0,0 ;Cursor up. tb: db 12O,'$',0,0 ;Cursor down. tc: db ('F'-100O),'$',0,0 ;Cursor right. td: db '$',0,0,0 ;(can't) Cursor left te: db '$',0,0,0 ;(can't) Clear display tf: db '$',0,0,0 ;(can't) Enter graphics mode tg: db '$',0,0,0 ;(can't) Exit graphics mode th: db ('^'-100O),'$',0,0 ;Cursor home. ti: db ('K'-100O),'$',0,0 ;Reverse linefeed. tj: db esc,'Y$',0 ;Clear to end of screen. tk: db esc,'T$',0 ;Clear to end of line. ENDIF;apple ; IF vector sysver: db 'Vector Graphics$' outlin: db ('D'-100O),cr,lf,tab,tab,'$' erascr: db ('D'-100O),'$' ;Clear screen and go home. eralin: db cr,('Q'-100O),'$' ;Clear line. delstr: db bs,' ',bs,bs,'$' ; adjust for echoing delete character ttab: ;Table start location. ta: db ('U'-100O),'$',0,0 ;Cursor up. tb: db 12O,'$',0,0 ;Cursor down. tc: db ('Z'-100O),'$',0,0 ;Cursor right. td: db '$',0,0,0 ;(can't) Cursor left te: db '$',0,0,0 ;(can't) Clear display tf: db '$',0,0,0 ;(can't) Enter graphics mode tg: db '$',0,0,0 ;(can't) Exit graphics mode th: db ('B'-100O),'$',0,0 ;Cursor home. ti: db ('U'-100O),'$',0,0 ;Reverse linefeed. tj: db ('P'-100O),'$',0,0 ;Clear to end of screen. tk: db ('Q'-100O),'$',0,0 ;Clear to end of line. ENDIF;vector ; IF telcon sysver: db 'Telcon Zorba$' ENDIF;telcon IF heath sysver: db 'Heath/Zenith 89$' ENDIF;heath IF z100 sysver: db 'Heath/Zenith Z-100 CP/M$' ENDIF;z100 IF vt52 ; DEC VT52 ttytyp: db 'VT52$' ENDIF;vt52 IF heath OR z100 OR telcon OR vt52 outlin: db esc,'H',esc,'J',cr,lf,tab,tab,'$' erascr: db esc,'H',esc,'J$' ;Clear screen and go home. eralin: db cr,esc,'K$' ;Clear line. curldn: db esc,'Y$' ;cursor leadin ttab: ;Table start location. ta: db esc,'A$',0 ;Cursor up. tb: db esc,'B$',0 ;Cursor down. tc: db esc,'C$',0 ;Cursor right. td: db esc,'D$',0 ;Cursor left te: db esc,'E$',0 ;Clear display tf: db esc,'F$',0 ;Enter Graphics Mode tg: db esc,'G$',0 ;Exit Graphics mode th: db esc,'H$',0 ;Cursor home. ti: db esc,'I$',0 ;Reverse linefeed. tj: db esc,'J$',0 ;Clear to end of screen. tk: db esc,'K$',0 ;Clear to end of line. ENDIF;heath OR z100 OR telcon OR vt52 ; IF trs80lb sysver: db 'TRS-80 II Lifeboat CP/M$' outlin: db esc,':',cr,lf,tab,tab,'$' erascr: db esc,':$' ;Clear screen and go home. eralin: db cr,esc,'T$' ;Clear line. curldn: db esc,'=$' ;Cursor lead-in ttab: ;Table start location. ta: db 0BH,'$',0,0 ;Cursor up. tb: db 0AH,'$',0,0 ;Cursor down. tc: db 0CH,'$',0,0 ;Cursor right. td: db bs,'$',0,0 ;Cursor left te: db esc,':$',0 ;Clear display tf: db '$',0,0,0 ;(can't) Enter Graphics Mode tg: db '$',0,0,0 ;(can't) Exit Graphics mode th: db 1EH,'$',0,0 ;Cursor home. ti: db 0BH,'$',0,0 ;Reverse linefeed. tj: db esc,'Y$',0 ;Clear to end of screen. tk: db esc,'T$',0 ;Clear to end of line. ENDIF;trs80lb ; IF trs80pt sysver: db 'TRS-80 II P+T CP/M$' outlin: db 0CH,cr,lf,tab,tab,'$' erascr: db 0CH,'$' ;Clear screen and go home. eralin: db cr,01H,'$' ;Clear line. curldn: db esc,'Y$' ;Cursor lead-in ttab: ;Table start location ;Must be 4 bytes each ta: db 1EH,'$',0,0 ;Cursor up. tb: db 1FH,'$',0,0 ;Cursor down. tc: db 1DH,'$',0,0 ;Cursor right. td: db 1CH,'$',0,0 ;Cursor left te: db 0CH,'$',0,0 ;Clear display tf: db 11H,'$',0,0 ;Enter Graphics Mode tg: db 14H,'$',0,0 ;Exit Graphics mode th: db 06H,'$',0,0 ;Cursor home. ti: db 1EH,'$',0,0 ;Reverse linefeed. tj: db 02H,'$',0,0 ;Clear to end of screen. tk: db 01H,'$',0,0 ;Clear to end of line. ENDIF;trs80pt ; IF robin sysver: db 'VT180 "Robin"$' ENDIF;robin IF dmII sysver: db 'DECmate II CP/M-80$' ENDIF;dmII IF vt100 ttytyp: db 'VT100$' ENDIF;vt100 IF robin OR dmII or vt100 ; Note that we cannot support Graphics Mode or the H19 erase-screen command ; (E), because the sequences are more than three bytes. outlin: db esc,3CH,esc,'[H',esc,'[J',cr,lf,tab,tab,'$' erascr: db esc,'[H',esc,'[J$' ;Clear screen and go home. eralin: db cr,esc,'[K$' ;Clear line. curldn: db esc,'[$' ; Cursor leadin ttab: ta: db esc,'[A$' ; Cursor up. tb: db esc,'[B$' ; Cursor down. tc: db esc,'[C$' ; Cursor right. td: db esc,'[D$' ; Cursor left te: db '$',0,0,0 ; (can't) Clear display tf: db '$',0,0,0 ; (don't) Enter Graphics Mode tg: db '$',0,0,0 ; (don't) Exit Graphics mode th: db esc,'[H$' ; Cursor home. ti: db esc,'M$',0 ; Reverse linefeed. tj: db esc,'[J$' ; Clear to end of screen. tk: db esc,'[K$' ; Clear to end of line. ENDIF;robin OR dmII or vt100 ; IF kpii sysver: db 'Kaypro II$' outlin: db subt,cr,lf,tab,tab,'$' erascr: db subt,'$' ;Clear screen and home. eralin: db cr,18H,'$' ;Clear line. curldn: db esc,'=$' ;Cursor lead-in delstr: db bs,' ',bs,bs,'$' ; adjust for echoing delete character ttab: ;Table start location. ta: db 0BH,'$',0,0 ;Cursor up. tb: db 0AH,'$',0,0 ;Cursor down. tc: db 0CH,'$',0,0 ;Cursor right. td: db bs,'$',0,0 ;Cursor left te: db subt,'$',0,0 ;Clear display tf: db esc,'G$',0 ; Enter Graphics Mode (select Greek) tg: db esc,'A$',0 ; Exit Graphics mode (select ASCII) th: db 1EH,'$',0,0 ; Cursor home. [UTK016] ti: db esc,'E','$',0 ; Reverse linefeed. (insert line) tj: db 'W'-100O,'$',0,0 ; Clear to end of screen. tk: db 'X'-100O,'$',0,0 ; Clear to end of line. ENDIF ; kpii ; IF mikko sysver: db 'MikroMikko$' outlin: db subt,cr,lf,tab,'$' erascr: db subt,'$' ;Clear screen and go home. eralin: db cr,1CH,'$' ;Clear line. curldn: db esc,'=$' ;cursor leadin ttab: ;Table start location. ta: db 0BH,'$',0,0 ;Cursor up. tb: db 0AH,'$',0,0 ;Cursor down. tc: db 0CH,'$',0,0 ;Cursor right. td: db bs,'$',0,0 ;Cursor left te: db subt,'$',0,0 ;Clear display tf: db '$',0,0,0 ;(can't) Enter Graphics Mode tg: db '$',0,0,0 ;(can't) Exit Graphics mode th: db 1EH,'$',0,0 ;Cursor home. ti: db '$',0,0,0 ;(can't) Reverse linefeed. tj: db 1cH,'$',0,0 ;Clear to end of screen. tk: db 1cH,'$',0,0 ;Clear to end of line. ENDIF;mikko ; IF gener or cpm3 sysver: db 'Generic CP/M-80$' ENDIF;gener or cpm3 IF bbII sysver: db 'Big Board II$' ENDIF;bbII IF mdI sysver: db 'Morrow Decision I$' ENDIF;mdI [Toad Hall] IF mmdI sysver: db 'MicroDecision I$' ENDIF;mmdI IF osi sysver: db 'Ohio Scientific$' ENDIF;osi IF osi OR crt outlin: db cr,lf,'Starting ...$' erascr equ crlf ;"Home & clear" (best we can do). eralin: db '^U',cr,lf,'$' ;Clear line. prpack: db cr,lf,'RPack: $' pspack: db cr,lf,'SPack: $' ttab equ 0 ; no VT52 table ENDIF;osi OR crt IF tvi925 ;(incidentally, works fine for Freedom 100 also [Toad Hall]) ;adm3a entry and tvi925 entry separated to remove warning message. ttytyp: db 'TVI925$' outlin: db 'Z'-64,0,0,cr,lf,'$' erascr: db 'Z'-64,0,0,'$' ;Clear screen and home eralin: db esc,'Y$',0 ;Clear to end of sreen curldn: db cr,esc,'=$' ;Cursor lead-in ttab: ;Table start location ;(MUST be 4 bytes each) ta: db 'K'-64,'$',0,0 ;Cursor up, stop at top tb: db 'V'-64,'$',0,0 ;Cursor down, stop at bottom tc: db 'L'-64,'$',0,0 ;Cursor right, stop at right td: db 'H'-64,'$',0,0 ;Cursor left, stop at left te: db 'Z'-64,0,0,'$' ;Clear display (2 pad nulls) tf: db '$',0,0,0 ;(can't) Enter Graphics mode tg: db '$',0,0,0 ;(can't) Exit Graphics mode th: db 1EH,'$',0,0 ;Cursor home ti: db esc,'j$',0 ;Reverse linefeed, scroll tj: db esc,'Y$',0 ;Clear to end of sreen tk: db esc,'T$',0 ;Clear to end of line ENDIF;tvi925 IF adm3a ttytyp: db 'ADM3A$' outlin: db 'Z'-64,0,0,cr,lf,'$' erascr: db 'Z'-64,0,0,'$' ;Clear screen and home eralin: db esc,'Y$',0 ;Clear to end of sreen curldn: db cr,esc,'=$' ;Cursor lead-in ttab: ;Table start location ;(MUST be 4 bytes each) ta: db 'K'-64,'$',0,0 ;Cursor up, stop at top tb: db 'J'-64,'$',0,0 ;Cursor down CTRL-J tc: db 'L'-64,'$',0,0 ;Cursor right, stop at right td: db 'H'-64,'$',0,0 ;Cursor left, stop at left te: db 'Z'-64,0,0,'$' ;Clear display (2 pad nulls) tf: db '$',0,0,0 ;(can't) Enter Graphics mode tg: db '$',0,0,0 ;(can't) Exit Graphics mode th: db 1EH,'$',0,0 ;Cursor home ti: db 'K'-64,'$',0,0 ;Reverse linefeed tj: db '$',0,0,0 ;(can't) Clear to end of screen tk: db '$',0,0,0 ;(can't) Clear to end of line ENDIF;adm3a IF delphi ; [7] new system sysver: db 'Digicomp Delphi 100$' endif;delphi IF smrtvd ; [7] new terminal ttytyp: db 'Smartvid-80$' outlin: db esc,'+',cr,lf,tab,tab,'$' eralin: db cr,esc,'T$' ;Clear to end of line. erascr: db esc,'+$' ;Clear screen and go home. curldn: db esc,'=$' ;Cursor lead-in ttab: ;Table start location. ta: db ('K'-100O),'$',0,0 ;Cursor up. tb: db 12O,'$',0,0 ;Cursor down. tc: db ('A'-100O),'$',0,0 ;Cursor right. td: db ('H'-100O),'$',0,0 ;Cursor left. te: db ('L'-100O),'$',0,0 ;Clear screen and home cursor tf: db '$',0,0,0 ;(can't) Enter Graphics mode tg: db '$',0,0,0 ;(can't) Exit Graphics mode th: db ('Z'-100O),'$',0,0 ;Cursor home. ti: db ('K'-100O),'$',0,0 ;Reverse linefeed. tj: db esc,'Y$',0 ;Clear to end of screen. tk: db esc,'T$',0 ;Clear to end of line. ENDIF;smrtvd ovlend equ $ ; End of overlay END