; 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,1985 ; 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 12: February 6, 1985 ; Add extended H89 support (by Paul Milazzo, Rice University), ; support for Northstar Horizon with Northstar CP/M and SIO-4 board ; (by Joe Smith, Colorodo School of Mines), and support for Lobo ; MAX-80 computer (from Hal Hostetler) ; ; edit 11: 13-Jan-85 by Vanya J.Cooper Pima Commun. College Tel: 602-884-6809 ; ;pcc001 27-Dec-84 vjc modules: cp4sys,cp4typ ; Add conditional for Xerox 820. I thought at first I could ; live with the kaypro conditional, but it's enough of a pain ; that I added it back in. The clear-to-end-of-screen char ; is different, breaking many programs in VT52 mode, and the ; default escape char control-\, is not at all obvious how ; to type on the 820 keyboard. If you muddle through the ; key translation table, it turns out to be control-comma. ; Rather than OR xer820 all the occurances of kpII conditionals ; I added a bbI conditional for all common code for the big ; board I based machines that is automatically turned on by ; either kpII or xer820. This will also make it easier in ; the future if another flavor of bigboard is added. ; ; edit 10: 5 December 1984 by CJC ; Add missing ENDIF (tsk, tsk) ; ; edit 9: 4 December 1984 by CJC ; Add two osborne fixes: missing crlf in outlin:, incorrect opcode in ; initialization. ; ; edit 8: 13 October 1984 by L M Jones, JCC, for New York Botanical Garden ; Add support for CPT-85xx series word processors when running CP/M-80. ; ; 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 (12) 6-Feb-85$' ; ; 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 xer820 ;[pcc001] .printx * Assembling Xerox 820 KERMIT-80 * ENDIF ;[pcc001] 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] IF cpt85xx .printx * Assembling CPT-85xx (under CompuPak CP/M) Kermit-80 * ENDIF IF norths .printx * Assembling for NorthStar Horizon with HSIO-4 board * ENDIF;norths IF lobo ;[hh] .printx * Assembling Kermit-80 for the Lobo MAX-80 * ENDIF;lobo [hh] ; 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 lobo ;[hh] mnport EQU 0F7E4H ;Modem data port A mnprts EQU 0F7E5H ;Modem status/conrtol port A baudrt EQU 0F7D0H ;Baud rate port A output EQU 04H ;Transmit buffer empty input EQU 01H ;Receive data available z80 EQU TRUE ;a good z80, here ENDIF;lobo 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 ; Definitions for the 8250 ACE acerbr EQU 0 ; ACE Receiver Buffer Register offset (R/O) (DLAB = 0) acethr EQU 0 ; ACE Transmitter Holding Register offset (W/O) acedll EQU 0 ; ACE Divisor Latch (Low) (DLAB = 1) acedlh EQU 1 ; ACE Divisor Latch (High) (DLAB = 1) aceier EQU 1 ; ACE Interrupt Enable Register (DLAB = 0) aceiir EQU 2 ; ACE Interrupt Identification Register acelcr EQU 3 ; ACE Line Control Register acemcr EQU 4 ; ACE Modem Control Register acelsr EQU 5 ; ACE Line Status Register offset acemsr EQU 6 ; ACE Modem Status Register ace8bw EQU 00000011b ; 8 bit words acesb EQU 01000000b ; set break acedla EQU 10000000b ; divisor latch access acedtr EQU 00000001b ; data terminal ready aceloo EQU 00010000b ; loopback mode acedr EQU 00000001b ; data ready acethe EQU 00100000b ; transmitter holding register empty mnport EQU 330O ;Modem data port mnprts EQU mnport+acelsr ;Modem status port output EQU acethe ;Transmitter empty input EQU acedr ;Input data available z80 EQU TRUE ;H89 uses the Z80 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 ;[hh] this one's an 8085. 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 TRUE ;[hh] All TRS-80's but the CoCo 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 TRUE ;[hh] a z80 here, also 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 bbI 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;bbI IF norths ;The basic Northstar Horizon BIOS does not access ports 2-5 port0d equ 02h ;Port 0 data (console) port0s equ 03h ;Port 0 status port1d equ 04h ;Port 1 data (printer) port1s equ 05h ;Port 1 status port2b equ 10h ;Port 2 baud port2i equ 11h ;Port 2 interrupt mask port2d equ 12h ;Port 2 data port2s equ 13h ;Port 2 status port3b equ 14h ;Port 3 baud port3i equ 15h ;Port 3 interrupt mask port3d equ 16h ;Port 3 data port3s equ 17h ;Port 3 status port4b equ 18h ;Port 4 baud port4i equ 19h ;Port 4 interrupt mask port4d equ 1Ah ;Port 4 data port4s equ 1Bh ;Port 4 status port5b equ 1Ch ;Port 5 baud port5i equ 1Dh ;Port 5 interrupt mask port5d equ 1Eh ;Port 5 data port5s equ 1Fh ;Port 5 status NS19K2 EQU 00H ;19.2 kilobaud NS9600 EQU 01H ;9600 baud NS4800 EQU 02H ;4800 baud NS2400 EQU 03H ;2400 baud NS1200 EQU 04H ;1200 baud NS0600 EQU 05H ; 600 baud NS0300 EQU 06H ; 300 baud NS0110 EQU 07H ; 110 baud ;; Set to use port 5 at 1200 baud ***** mnport equ port5d ;Data port mnprts equ port5s ;Status port baudrt equ port5b ;Baud rate port baudini equ ns1200 ;Initial baud rate output EQU 1 ;Bit of UART status for transmitter ready input EQU 2 ;Bit of UART status for receiver ready z80 equ FALSE ENDIF;norths 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 cpt85xx baudrt EQU 4Ch ; Baud rate generater (National MM5307) mnport EQU 4Bh ; Comm port data register (Intel 8251) mnprts EQU 4Ah ; Comm port command/status register output EQU 01h ; Transmitter buffer empty flag input EQU 02h ; Reciver buffer full flag TxEmpty EQU 04h ; Transmitter empty flag z80 EQU FALSE ; It's really an 8080 [or 8085 ... same thing] ENDIF;cpt85xx 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 OR xer820 defesc EQU ']'-100O ;The default escape character. ENDIF;brain OR osi OR apple OR telcon OR xer820 IF vector defesc EQU '~' ;Vector can't type ']'. ENDIF;vector IF robin OR dmII OR mikko OR heath OR z100 OR osbrn1 OR kpII OR lobo 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 OR lobo IF crt OR vt100 OR vt52 OR tvi925 OR adm3a OR smrtvd OR cpt85xx defesc EQU '\'-100O ;Still Control-\ (just ran out of room...) ENDIF;crt OR vt100 OR vt52 OR tvi925 OR adm3a OR smrtvd OR cpt85xx 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: mvi c,getvnm ; get the BDOS version number (e.g. 22H, 31H) call bdos mov a,l sta bdosvr ; and store it away for future reference ; 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 8Kbytes. If you get retransmissions and other protocol errors after ; transferring the first maxsec sectors, lower maxsec. ; 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 (8*1024)/bufsiz ; 8K / 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 bbI 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;bbI or bbII IF cpt85xx mvi a,80h ; Send UART reset [force idle] by setting out baudrt ; bit 7 of baud rate I/O port mvi a,0Fh ; Clear reset bit and default to 9600 baud out baudrt mvi a,4Eh ; Set UART mode to async 16x clock, 8 data out mnprts ; bits, no parity, and 1 stop bit mvi a,37h ; Set command to Tx enable, DTR on, Rx enable, out mnprts ; break off, error reset, and RTS on ENDIF;cpt85xx IF lobo ;[hh] lxi d,siotbl ;[hh] address of status table mvi c,siolen ;[hh] length of the table siolup: ;[hh] loop here for each command byte ldax d ;[hh] load first byte into A inx d ;[hh] index pointer to next bute sta mnprts ;[hh] send it to status port A sta mnprts+2 ;[hh] and to status port B dcr c ;[hh] decrement the counter jnz siolup ;[hh] loop back for more commands mvi a,05H ;[hh] value for 300 baud sta baudrt ;[hh] starting default for port A sta baudrt+4 ;[hh] and for port B sta speed ;[hh] tell program they're set mvi a,0E4H ;[hh] value for port A sta port ;[hh] tell program we've set this, too mvi a,0D0H ;[hh] port A baud rate value sta port+1 ;[hh] save this as well, for consistancy ENDIF ;lobo 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 norths mvi a,baudini ;Get initial speed out baudrt sta speed ;save for status display sta speed+1 ENDIF;norths 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 ; IF heath ; ; System dependent startup for H89 ; call mdmofl ; keep the line safe from garbage ; First, tell Kermit the modem port's current speed in mnport+acelcr ori acedla out mnport+acelcr ; access the ACE's divisor latch in mnport+acedll ; get the low byte sta speed in mnport+acedlh ; and the high byte sta speed+1 ; Now set up the port for Kermit mvi a,ace8bw ; 8 data bits, 1 stop bit, no parity out mnport+acelcr in mnport+acemcr ori acedtr ; raise DTR (just in case) out mnport+acemcr call mdmonl ; and put the ACE back on line ret ; Take the ACE off line before modifying its state mdmofl: in mnport+aceier ; save the ACE's interrupt state sta iersav xra a out mnport+aceier ; and disable ACE interrupts in mnport+acemcr ; now put the ACE in loopback mode ori aceloo out mnport+acemcr ret ; Put the ACE back on line mdmonl: in mnport ; flush left-over garbage in the receive buffer mvi a,7 ; wait about 2 300-baud character times call delay in mnport ; and flush more garbage in mnport+acemcr ; take the ACE out of loopback mode ani 0FFH-aceloo out mnport+acemcr lda iersav out mnport+aceier ; and restore the ACE's interrupt state ret iersav: ds 1 ENDIF;heath ret ; return from system-dependent routine bdosvr: ds 1 ; space to save the BDOS version number ; 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 bbI OR bbII OR lobo ; 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;bbI or bbII OR lobo 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 IF cpt85xx mvi a,80h ; Reset (force idle) the 8251 UART via bit 7 out baudrt ; of the baud rate generater port mvi a,00h ; and turn off the baud rate generater out baudrt ENDIF;cpt85xx 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 OR cpt85xx ;For Robin/TRS80/CPT-85xx, add some more info lxi d,conmsg ; about obscure key combinations call prtstr ENDIF;robin OR trs80 OR cpt85xx 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 cpt85xx ; for CPT-85xx, some graphics map "funny" to keyboard in CP/M db ' (Use CODE + SHIFT + 1/2 key to generate a Control-\)' db cr,lf,'$' ENDIF;cpt85xx ; 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 bbI OR cpt85xx OR heath OR lobo lxi d,inhlps ; we got options... call prtstr ; print them. ENDIF;apmmdm OR robin OR dmII OR bbII OR bbI OR cpt85xx OR heath OR lobo ret ;additional, system-dependent help for transparent mode ; (two-character escape sequences) inhlps: IF robin OR dmII OR bbII OR bbI OR cpt85xx OR heath OR lobo db cr,lf,'B Transmit a BREAK' ENDIF;robin OR dmII OR bbII OR bbI OR cpt85xx OR heath OR lobo IF apmmdm OR heath OR lobo db cr,lf,'D Drop the line' ENDIF;apmmdm OR heath OR lobo db '$' ;[hh] table terminator ; ; 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 heath cpi 'D' ; drop line? jnz intc00 ; no: try next function character mdmdrp: in mnport+acemcr ; (we also get here from sysbye) ani 0FFH-acedtr out mnport+acemcr ; yes: drop DTR mvi a,50 ; for half a second call delay in mnport+acemcr ori acedtr out mnport+acemcr ; and then restore it ret intc00: ENDIF;heath IF robin OR dmII OR bbI OR bbII OR cpt85xx OR heath OR lobo cpi 'B' ; send break? jz sendbr ; yes, go do it. return nonskip when through. ENDIF;robin OR dmII OR bbI OR bbII OR cpt85xx OR heath OR lobo IF lobo ;[hh] cpi 'D' ;[hh] disconnect? jz discon ;[hh] yes, go do it. nonskip return when done. ENDIF ;lobo 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 bbI 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. ENDIF;bbI OR bbII IF lobo ;[hh] This routine sends a break tone or disconnects a modem ; (those that respond to it) by setting the DTR line low ; for 300 ms. ; sendbr: mvi a,05H ;[hh] write register 5 call outctl ;[hh] send it to control port mvi a,0FAH ;[hh] value to send break tone jmp sndbr1 ;[hh] ; discon: mvi a,05H ;[hh] write register 5 call outctl ;[hh] send it to the control port mvi a,06AH ;[hh] DTR off and break tone on sndbr1: call outctl ;[hh] send to control port mvi a,30 ;[hh] delay count for 300 ms. call delay ;[hh] wait a while... mvi a,05H ;[hh] write register 5 call outctl ;[hh] get it's attention mvi a,0EAH ;[hh] normal 8 bits, DTR on, RTS on, etc. call outctl ;[hh] restore SIO ret ; outctl: sta mnprts ;[hh] ret ENDIF ;lobo ; IF cpt85xx ;[lmj] send break on cpt85xx sendbr: ; ; Ensure that the transmitter has finished sending buffered chars sndbr1: in mnprts ; get UART status ani TxEmpty ; everything sent? jz sndbr1 ; no, wait a bit more ; ; Begin sending a break by setting bit in UART command register mvi a,3Fh ; Set TxEna, DTR, RxEna, SBreak, ErrRst, RTS out mnprts ; ; Wait for 250 milliseconds (using hundredths second dealy routine) mvi a,25 call delay ; ; Resume normal operation by clearing the SendBreak command bit mvi a,37h ;Set TxEna, DTR, RxEna, ErrRst, RTS out mnprts ; ret ;done ENDIF;cpt85xx ; IF heath ; ; Send BREAK on H89 ; sendbr: in mnport+acelcr ori acesb out mnport+acelcr ; set ACE break condition mvi a,30 call delay ; wait 300 milliseconds in mnport+acelcr ani 0FFH-acesb out mnport+acelcr ; and clear ACE break condition ret ENDIF;heath IF bbI OR bbII OR cpt85xx OR heath OR lobo ; ;[cjc] 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 dcr a ; 4 T-states jnz delay ; 10 T-states ret ; grand total: ((1001 * cpuspd) + 14) * a ENDIF;bbI OR bbII OR cpt85xx OR heath OR lobo ; ; ; 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, heath, and lobo, hang up the phone. sysbye: IF apmmdm xra a ;Hangup our end, too. sta mnmodm ENDIF;apmmdm IF heath call mdmdrp ; Sleazy but effective ENDIF;heath IF lobo ;[hh] call discon ;[hh] force modem to hang up ENDIF;lobo 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 ;[hh] set the speed for a lobo MAX-80 IF lobo mov a,e ;[hh] get the parsed value setbd: sta baudrt ;[hh] and send it to the baud rate port ret ;[hh] ENDIF;lobo ; Set the speed for bigboard I or the delphi or the CPT-85xx or Northstar IF bbI OR delphi OR cpt85xx mov a,e ; get the parsed value out baudrt ; Tell the baud rate generator. ret ENDIF;bbI OR delphi OR cpt85xx OR norths ; 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] IF heath ; ; Set speed for H89 ; call mdmofl ; keep the line safe from garbage in mnport+acelcr ori acedla out mnport+acelcr ; access the ACE's divisor latch mov a,e ; low byte of speed is in E out mnport+acedll ; set the low byte mov a,d ; high byte of speed is in D out mnport+acedlh ; set the high byte in mnport+acelcr ani 0FFH-acedla out mnport+acelcr ; de-access the ACE's divisor latch call mdmonl ; and put the ACE back on line ret ENDIF;heath ; ; 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 bbI OR brain OR delphi OR lobo ;[hh] 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;bbI OR brain OR delphi OR lobo ;[hh] 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 cpt85xx spdtbl: db 15 ; 15 entries db 03,'110$', 03h,03h db 04,'1200$', 09h,09h db 05,'134.5$', 04h,04h db 03,'150$', 05h,05h db 04,'1800$', 0Ah,0Ah db 04,'2400$', 0Bh,0Bh db 03,'300$', 06h,06h db 04,'3600$', 0Ch,0Ch db 04,'4800$', 0Dh,0Dh db 02,'50$', 01h,01h db 03,'600$', 07h,07h db 04,'7200$', 0Eh,0Eh db 02,'75$', 02h,02h db 03,'900$', 08h,08h db 04,'9600$', 0Fh,0Fh sphtbl: db cr,lf,' 50 75 110 134.5 150 300 600 900' db cr,lf,' 1200 1800 2400 3600 4800 7200 9600$' ENDIF;cpt85xx 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 heath ; ; Speed selection table for H89 (OK, so I got a little carried away...) ; spdtbl: db 19 ; 19 entries db 3,'110$' dw 1047 db 4,'1200$' dw 96 db 5,'134.5$' dw 857 db 4,'1800$' dw 64 db 5,'19200$' dw 6 db 3,'200$' dw 576 db 4,'2400$' dw 48 db 3,'300$' dw 384 db 4,'3600$' dw 32 db 5,'38400$' dw 3 db 3,'450$' dw 256 db 4,'4800$' dw 24 db 2,'50$' dw 2304 db 5,'56000$' dw 2 db 3,'600$' dw 192 db 4,'7200$' dw 16 db 2,'75$' dw 1536 db 3,'900$' dw 128 db 4,'9600$' dw 12 sphtbl: db cr,lf db ' 50 75 110 134.5 200 300 450 600 900 1200' db cr,lf,' 1800 2400 3600 4800 7200 9600 19200 38400 56000$' ENDIF;heath IF norths spdtbl: db 8 ; 8 entries db 3,'110$', 07H,07H db 4,'1200$', 04H,04H db 5,'19200$', 00H,00H db 4,'2400$', 03H,03H db 3,'300$', 06H,06H db 4,'4800$', 02H,02H db 3,'600$', 05H,05H db 4,'9600$', 01H,01H sphtbl: db cr,lf db ' 110 300 600 1200 2400 4800 9600 19200$' ENDIF;norths ; The following conditionals were once a huge if not statement. There ; wasn't enough room to add the lobo to the list, so it had to be broken ; into 2, which you can't do with an if not. I redid it as two ifs and ; applied them to those that wouldn't set baud. [Hal Hostetler] IF robin OR gener OR dmII OR vector OR z100 OR trs80 OR telcon spdtbl equ 0 ; SET BAUD not supported. sphtbl equ 0 ENDIF;robin OR gener OR dmII OR vector OR z100 OR trs80 OR telcon ; IF mmdI OR osi OR cpm3 OR apmmdm spdtbl EQU 0 ;[hh] SET BAUD not supported. sphtbl EQU 0 ;[hh] ran out of room above... ENDIF;mmdI OR osi OR cpm3 OR apmmdm ; ; This is the system-dependent SET PORT command. ; HL contains the argument from the command table. sysprt: IF lobo ;[hh] mov a,e ;[hh] get the data port value and store at sta outmd3+1 ;[hh] the two places we use... sta inpmd2+1 ;[hh] MNPORT in the overlay sta port ;[hh] inform program of the change in ports inr a ;[hh] status port = data port + 1 in the Lobo sta outmd1+1 ;[hh] store it at the three places... sta inpmd1+1 ;[hh] we use MNPRTS... sta outctl+1 ;[hh] in the overlay mov a,d ;[hh] now get the baud rate port value sta getbd+1 ;[hh] store it in the two places we use... sta setbd+1 ;[hh] BAUDRT in the overlay sta port+1 ;[hh] don't need to, but keeps it consistant getbd: lda baudrt ;[hh] get baud rate value from port sta speed ;[hh] tell STAT. baud rate for each port ;[hh] is independant of the other ENDIF ;lobo 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 Lobo MAX-80 IF lobo ;[hh] ; help text prhtbl: db cr,lf,'RS-232 port A or B$' ; ; command table prttbl: db 02H ;[hh] two entries db 01H,'A$',0E4H,0D0H db 01H,'B$',0E6H,0D4H ENDIF ;lobo ; ; ; 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 OR lobo) ;[hh] prttbl equ 0 ; SET PORT is not supported prhtbl equ 0 ENDIF;NOT iobyt OR lobo ; ; ; 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: lda bdosvr ;cpm3's alloc vect may be in another bank cpi 30H ;cpm3 or later? jm cp2spc ;no: use cp/m 2 algorithm 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 ret ; the rest are CP/M 2.2 systems, so use the alloc vector cp2spc: 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 ; ; ; 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. outmdm: IF osi OR apple OR lobo ;[hh] push h outmd1: 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 outmd3: lxi h,mnport ;address of port data register mov m,e ; write the character pop h ret ENDIF;osi OR apple OR lobo IF osbrn1 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 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 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 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 OR lobo ;[hh] inpmd1: lda mnprts ;Get the port status into A. ani input ;See if the input ready bit is on. rz ;If not then return. inpmd2: 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 bbI OR vector OR apple OR osbrn1 OR lobo lxi d,delstr jmp prtstr ENDIF;bbI OR vector OR apple OR osbrn1 OR lobo IF NOT (bbI OR vector OR apple OR osbrn1) mvi e,bs ;get a backspace jmp outcon ENDIF;NOT (bbI 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 lobo ;[hh] sysver: db 'Lobo MAX-80$' outlin: db esc,'*',cr,lf,tab,tab,'$' erascr: db esc,'*$' ;[hh] clear screen and home cursor eralin: db cr,esc,'R$' ;[hh] clear line curldn: db esc,'=$' ;[hh] cursor lead-in string delstr: db bs,' ',bs,bs,'$' ;[hh] ??adjust for echoing delete ttab: ;[hh] table start location ta: db 0BH,'$',0,0 ;[hh] cursor up tb: db 0AH,'$',0,0 ;[hh] cursor down tc: db 0CH,'$',0,0 ;[hh] cursor right td: db 08H,'$',0,0 ;[hh] cursor left te: db esc,'*$',0 ;[hh] clear display (homes cursor) tf: db '$',0,0,0 ;[hh] (can't) enter graphics mode tg: db '$',0,0,0 ;[hh] (can't) exit graphics mode th: db 01EH,'$',0,0 ;[hh] home cursor ti: db esc,'E$',0 ;[hh] reverse linefeed (insert line) tj: db esc,'Y$',0 ;[hh] clear to end of screen tk: db esc,'T$',0 ;[hh] clear to end of line ENDIF ;lobo ; 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,cr,lf,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 e sc,'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 norths sysver: db 'Northstar Horizon$' ENDIF;norths 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 xer820 sysver: db 'Xerox 820$' 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 '$',0,0,0 ; Enter Graphics Mode (can't) tg: db '$',0,0,0 ; Exit Graphics mode (can't) th: db 1EH,'$',0,0 ; Cursor home. [UTK016] ti: db 0BH,'$',0,0 ; Reverse linefeed. (cursor up) tj: db 11H,'$',0,0 ; Clear to end of screen. tk: db 18H,'$',0,0 ; Clear to end of line. ENDIF ; xer820 ; 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 cpt85xx sysver: db 'CPT-85xx under CompuPak CP/M$' ENDIF;cpt85xx 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