; 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 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 (10) 5-Dec-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]

IF cpt85xx
.printx * Assembling CPT-85xx (under CompuPak CP/M) Kermit-80 *
ENDIF

; 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 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
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 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:
	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 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 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

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 <escape>?, after listing all the
;	system-independent escape sequences.
;
sysinh:	
IF apmmdm OR robin OR dmII OR bbII OR kpii OR cpt85xx
	lxi	d,inhlps	; we got options...
	call	prtstr		; print them.
ENDIF;apmmdm OR robin OR dmII OR bbII OR kpii OR cpt85xx
	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 OR cpt85xx
	db	cr,lf,'B  Transmit a BREAK$'
ENDIF;robin OR dmII OR bbII OR kpii OR cpt85xx

;
;	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 OR cpt85xx
	cpi	'B'		; send break?
	jz	sendbr		; yes, go do it.  return nonskip when through.
ENDIF;robin OR dmII OR kpII OR bbII OR cpt85xx
	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.
ENDIF;kpii OR bbII


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 kpii OR bbII or cpt85xx
;
;[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 + call/return overhead.
	ret
ENDIF;kpII OR bbII OR cpt85xx
;
;
;	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: <xon>,<xoff>,<del>, and <nul> 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 or the CPT-85xx
IF kpII OR delphi OR cpt85xx
	mov	a,e		; get the parsed value
	out	baudrt		; Tell the baud rate generator.
	ret
ENDIF;kpII OR delphi OR cpt85xx

; 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 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 NOT (brain OR osbrn1 OR bbII OR kpII OR mikko OR ap6551 OR mdI OR delphi OR cpt85xx)
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 OR cpt85xx)
;
;	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.
outmdm:
IF osi OR apple
	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
	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
	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 |<error>...
;    8 |<status>...
;    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,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	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
; (<esc>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 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
