;KERMIT.MAC	Kermit for the ELZET80
;	28 Sep 86	A.Herrmann [ah]
;	13 Oct 86	switched to SIO interrupt operation
;	16 Oct 86	eliminated all non-ELZET stuff
;	09 Apr 88	Clear-to-end of line at some prompts
;
;KERMIT - (Celtic for "FREE")
;
;	This is the CP/M-80 implementation of the Columbia University
;	KERMIT file transfer protocol.
;
;	Version 3.9A
;
;	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.
;
;See CPMBASE.UPD for detailed update history.

	ASEG			;[ah] Switched these two lines for
	ORG	100H		;[ah] M80 and L80.


TRUE	EQU	-1		;Define the boolean constants.
FALSE	EQU	NOT TRUE	;...

iobyte	EQU	03H	;Location of I/O byte

;Symbolic Definitions for some ASCII characters
;
bell	EQU	07O	;ASCII BEL (Control-G)
ctrlc	EQU	03O	;ASCII ETX (Control-C)
tab	EQU	11O	;ASCII Tab (Control-I)
lf	EQU	12O	;ASCII Line Feed (CTRL-J)
ff	EQU	14O	;ASCII Form Feed (CTRL-L)
cr	EQU	15O	;ASCII Carriage Return (CTRL-M)
xon	EQU	21O	;The ASCII character used for XON
xoff	EQU	23O	;The ASCII character used for XOFF
esc	EQU	33O	;ASCII ESCape
subt	EQU	32O	;ASCII SUB (CTRL-Z)
del	EQU	177O	;ASCII DELete (rubout)
bdos	EQU	0005H	;Call BDOS
npl	EQU	04H	;Number of names per line for dir command.

;BDOS calls
;
;Function Name		Function	Input Parameters Output Parameter
;=============		========	================ ================
;	(ALL Function Numbers are passed in Register C)
conin	EQU	01H	;Read Console	NONE		 ASCII Char in A
conout	EQU	02H	;Write Console	ASCII Char in E  NONE
auxin	EQU	03H	;Auxiliary input
rdrin	EQU	03H	;Read Reader	NONE		 ASCII Char in A
auxout	EQU	04H	;Auxiliary output
punout	EQU	04H	;Write Punch	ASCII Char in E  NONE
lstout	EQU	05H	;Write List	ASCII Char in E  NONE
dconio	EQU	06H	;Direct Con I/O ASCII Char in E  I/O Status in A
			;				 if E=0FEH,
			;				  Input if E=0FFH
auxist	EQU	07H	;Get AUXIN: status		 A=FF is character
			;				 ready, A=0 if none
gtiob	EQU	07H	;Get I/O status NONE		 I/O Status in A
auxost	EQU	08H	;Get AUXOUT: status		 A=FF if ready, A=0
			;				 if not ready
ptiob	EQU	08H	;Put I/O status I/O Status in E  NONE
prstr	EQU	09H	;Print String	String-Address	 NONE
;					in DE (term=$)
rdstr	EQU	0AH	;Read Buffer	Buffer-Address	Read Buffer filled
;					in DE
;	Read Buffer	Byte	Function
;			  1	Maximum Buffer Length
;			  2	Current Buffer Length (returned value)
;			3-n	Data (returned values)
;
consta	EQU	0BH	;Console Stat	NONE		LSB(A)=1 if char ready
inbdos	EQU	0DH	;Init BDOS	NONE		NONE
logdsk	EQU	0EH	;LOG-In disk	Value in E	NONE
;					A=0,B=1,...
openf	EQU	0FH	;Open File	FCB-Addr in DE	Byte Addr.of FCB,
			;				 or 0FFH if not
closf	EQU	10H	;Close File	FCB-Addr in DE	Byte Addr.of FCB,
			;				 or 0FFH if not
sfirst	EQU	11H	;Search File	FCB-Addr in DE	Byte Addr.of FCB(0-3),
			;				 or 0FFH if not
snext	EQU	12H	;Search next	FCB-Addr in DE	Byte Addr.of next FCB,
			;				 or 0FFH if not
delf	EQU	13H	;Delete File	FCB-Addr in DE	Byte Addr.of FCB(0-3),
			;				 or 0FFH if not
readf	EQU	14H	;Read Record	FCB-Addr in DE	0=successful read
;							1=read past EOF
;							2=reading random data
writef	EQU	15H	;Write Record	FCB-Addr in DE	0=successful write
;							1=ERROR extending
;							2=End of disk data
;							255=No more DIR space
makef	EQU	16H
renam	EQU	17H
rdlog	EQU	18H	;Ret. Log Code	NONE		Login Vector in HL
rddrv	EQU	19H	;Read Drive #	NONE		# of logged in drive in
;							(A=0,B=1,C=2....)
setdma	EQU	1AH	;Set DMA Addr.	Addr. of 128	NONE
;					byte buffer in DE
getalv	EQU	1BH	;Get All.Vect.	NONE		All.Vect in HL
wrtprt	EQU	1CH	;Write prot dsk NONE		NONE
getrov	EQU	1DH	;Get R/O Vect.	NONE		HL= R/O Vect. value
setfat	EQU	1EH	;Set File Attr. FCB-Addr.in DE	Dir. code in A
gtdpar	EQU	1FH	;Get DSK par.	NONE		HL=DPB Address
usrcod	EQU	20H	;Get/Set Usr.Cd E=0FFH (get)	A=current code (get)
;					E-code (set)	A=no value (set)
rrand	EQU	21H	;Read  Random	FCB-Addr in DE	A=Return code
wrand	EQU	22H	;Write Random	FCB-Addr in DE	1=read'g unwritten data
;							2=(not used)
;							3=can't close curr. ext
;							4=seek to unwr. ext.
;							5=dir overflow(write)
;							6=seek past End of DSK
cflsz	EQU	23H	;Comp File Sz.	FCB Addr.in DE	Rand.Rec.field set to
			;				 File size
setrar	EQU	24H	;Set Rand. Rec. FCB-Addr.in DE	Rand.Rec.field set

mnport	equ	04h	;Modem data port
mnprts	equ	06h	;Modem status port
output	equ	04h	;Transmit buffer empty
input	equ	01h	;Receive data available
elslen	equ	09h	;length of sio status table
piobc	equ	03h	;PIO-B control port	[ah] This is only for the piggy
piobd	equ	01h	;PIO-B data port	[ah] back rig-up of MY machine!
elintv	equ	0D0h	;interrupt vector low byte
elintt	equ	0FFD0h	;address of interrupt table in BIOS

defesc	EQU	'\'-100O;The default is Control \ -- it's easier B.E.

maxpkt	EQU	'~'-' '+2O;Maximum size of a packet.
maxtry	EQU	05O	;Default number of retries on a packet.
imxtry	EQU	20O	;Default number of retries send initiate.
drpsiz	EQU	5EH	;Default receive packet size.
dspsiz	EQU	20H	;Default send packet size.
dstime	EQU	08H	;Default send time out interval.

drtime	EQU	05H	;Default receive time out interval.

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
parevn	EQU	00H	;Even parity.
parmrk	EQU	03H	;Mark parity.
parnon	EQU	06H	;No parity.
parodd	EQU	09H	;Odd parity.
parspc	EQU	0CH	;Space parity.

defpar	EQU	parnon	;Default parity.
ibmpar	EQU	parmrk	;IBM COMTEN's parity.

soh	EQU	01H	;Start of header char.

fcb	EQU	5CH	;Location of File Control Block.
fcbext	equ	fcb+12
fcbrno	equ	fcb+33
buff	EQU	80H	;Location of file output buffer (DMA).
bufsiz	EQU	80H	;Size of DMA.

diasw	EQU	01H	;Default is diagnostics on.

cmkey	EQU	01H	;Parse a keyword.
cmifi	EQU	02H	;Parse an input file spec (can be wild).
cmofi	EQU	03H	;Parse an output file spec.
cmcfm	EQU	04H	;Parse a confirm.
cmtxt	EQU	05H	;Parse text.
cmifin	equ	10H	;Parse an input file spec (but no
			;Error output

start:	nop		;Make sure we have a zero where
	nop		;DDT will set the stack pointer
	lxi	h,0	;Clear out hl pair
	dad	sp	;and fetch the system stack pointer
	shld	oldsp	;and save for later restoral
reenter:lxi	sp,stack;and move in our own stack.

	mvi	c,rddrv ;Get our logged in drive
	call	BDOS
	inr	a	;relative 1 !
	sta	CURDSK	;and save it for later

	lxi	d,versio	;Print version header
	call	prtstr

	lxi	h,elints	;Load address of interrupt service routine
	shld	elintt		; into BIOS' interrupt table
	lxi	h,02		;Get BIOS start page address 
	mov	a,m		; subtract 1
	dcr	a		; and store it as end of buffer 
	mov	h,a
	mvi	a,0FFH		;0FFH happens to be also the high byte of the 
	mov	l,a		; interrupt table
	shld	elbend		; with which the Z80 I-register is to be loaded
;* LD I,A			;But this is Z80 specific stuff
	db	0EDH,047H	;Op-code for the above Z80 command
;* IM 2				;Select interrupt mode 2
	db	0EDH,05EH	;Op-code for the above Z80 command

	mvi	a,0FH		;Define PIO-B as output
	out	piobc
	lda	piob0		;Set PIO-B bit #0 for baud rate
	out	piobd
	lxi	d,elstbl	;Load the address of the status table
	mvi	c,elslen	;Length of status table
elloop: ;Loop back here for each status word
	ldax	d		;Load the first word into A
	inx	d		;Index the pointer
	out	mnprts		;Send it to the status port
	dcr	c		;Decrement the byte counter
	jnz	elloop		;Jump back for more status bytes
	mvi	a,2		;Load SIO-B WR2
	out	mnprts+1
	mvi	a,elintv	; with low byte of interrupt vector
	out	mnprts+1

	call	kermit		;Start things going.
	call	exit1		;Finish up.

;This is the main KERMIT loop.	It prompts for and gets the users commands.

kermit: lda	curdsk
	adi	'A'-1
	sta	kerm1
	xra	a
	sta	mfflg1		;reset MFNAME
	sta	mfflg2		;ditto
	lxi	d,kerm
	call	prompt		;Prompt the user.
	lxi	d,comtab
	lxi	h,tophlp
	call	keycmd
	lxi	h,kermtb	;Get the address of the jump table.
	mov	c,a
	mvi	b,0
	dad	b
	pchl

kermtb: jmp	telnet
	jmp	exit
	jmp	help
	jmp	log
	jmp	read
	jmp	send
	jmp	setcom		;Set is an assembler keyword!!
	jmp	show
	jmp	status
	jmp	finish
	jmp	logout
	jmp	bye
	jmp	dir		;do directory
	jmp	era		;do "ERA"se file
	jmp	xmit

kermt2: lxi	d,ermes1	;"Unrecognized Command"
	call	prtstr
	jmp	kermit		;Do it again.
kermt3: lxi	d,ermes3	;"Not confirmed"
	call	prtstr
	jmp	kermit		;Do it again.

;	RECEIVE command

read:	lxi	d,data		;Where to put the text (if any.)
	mvi	a,cmtxt
	call	comnd		;Get either some text or a confirm.
	 jmp	kermt3		; Didn't get anything.
	ora	a		;Get any chars?
	jz	read1		;Nope, just a regular send.
	sta	argblk+1	;Store the number of chars.
	xchg			;Get pointer into HL.
	mvi	m,'$'		;Put in a dollar sign for printing.
	call	init		;Clear the line and initialize the buffers.
	lxi	d,scrfln	;Position cursor
	call	prtstr
	lxi	d,data		;Print the file name
	call	prtstr
	mvi	a,'1'		;Start with single character checksum
	sta	curchk		;Save the type
	xra	a		;Start a packet zero.
	sta	argblk
	mvi	a,'R'		;Receive init packet.
	call	spack		;Send the packet.
	 jmp	kermt3		; Die!
	jmp	read12

read1:	call	init		;Clear the line and initialize the buffers.
read12: xra	a
	sta	czseen		;Clear the ^X/^Z flag initially.
	lxi	h,0
	shld	numpkt		;Set the number of packets to zero.
	shld	numrtr		;Set the number of retries to zero.
	sta	pktnum		;Set the packet number to zero.
	sta	numtry		;Set the number of tries to zero.
	lxi	d,scrnrt	;Position cursor
	call	prtstr
	lxi	h,0
	call	nout		;Write the number of retries.
	mvi	a,'R'
	sta	state		;Set the state to receive initiate.
	;...

;RECEIVE state table switcher.

read2:	lxi	d,scrnp 	;Position cursor
	call	prtstr
	lhld	numpkt
	call	nout		;Write the current packet number.
	lda	state		;Get the state.

	cpi	'D'		;Are we in the DATA receive state?
	jnz	read3
	call	rdata
	jmp	read2

read3:	cpi	'F'		;Are we in the FILE receive state?
	jnz	read4
	call	rfile		;Call receive file.
	jmp	read2

read4:	cpi	'R'		;Are we in the Receive-Initiate state?
	jnz	read5
	call	rinit
	lda	state		;[jd] get new state
	cpi	'F'		;[jd] went into receive state?
	jnz	read2		;[jd] no
	lxi	d,inms24	;[jd] yes, get receiving... message
	call	finmes		;[jd] go print it
	jmp	read2

read5:	cpi	'C'		;Are we in the Receive-Complete state?
	jnz	read6
	lxi	d,infms3	;Put in "Complete" message.
	lda	czseen		;Or was it interrupted?
	ora	a		; .  .	.
	jz	read5a		;No.
	xra	a		;Yes, clear flag.
	sta	czseen		; ...
	lxi	d,inms13	;Issue "interrupted" message.
read5a: call	finmes		;Print completion message in right place.
	jmp	kermit

read6:	cpi	'A'		;Are we in the Receive-"Abort" state?
	jnz	read7
read7:	lxi	d,infms4	;Anything else is equivalent to "abort".
	call	finmes
	jmp	kermit

;	Initialize buffers and clear line.

init:	lxi	d,outlin	;Put Banner on screen
	call	prtstr

	lxi	d,outln2	;Put statistics headers on the screen
	call	prtstr		;only for screen-formatting versions.

init1:	mvi	a,bufsiz	;Buffer size.
	sta	chrcnt		;Number of chars left.
	lxi	h,buff		;Addr for beginning.
	shld	bufpnt		;Store addr for beginning.
	ret

;	Receive routines

;	Receive init

rinit:	lda	numtry		;Get the number of tries.
	cpi	imxtry		;Have we reached the maximum number of tries?
	jm	rinit2
	lxi	d,ermes4
	call	error3		;Move cursor and print an error message.
	jmp	abort		;Change the state to abort.
rinit2: inr	a		;Increment it.
	sta	numtry		;Save the updated number of tries.
	mvi	a,'1'		;Reset block check type to single character
	sta	curchk		;Store as current type for initialization
	call	rpack		;Get a packet.
	 jmp	nak		; Trashed packet: nak, retry.
	cpi	'S'		;Is it a send initiate packet?
	jnz	rinit3		;If not see if its an error.
	lda	numtry		;Get the number of tries.
	sta	oldtry		;Save it.
	xra	a
	sta	numtry		;Reset the number of tries.
	lda	argblk		;Returned packet number.  (Synchronize them.)
	call	countp
	lda	argblk+1	;Get the number of arguments received.
	lxi	h,data		;Get a pointer to the data.
	call	spar		;Get the data into the proper variables.
	lxi	h,data		;Get a pointer to our data block.
	call	rpar		;Set up the receive parameters.
	sta	argblk+1	;Store the returned number of arguments.
	mvi	a,'Y'		;Acknowledge packet.
	call	spack		;Send the packet.
	 jmp	abort		; Failed, abort.
	lda	inichk		;Now switch to agreed upon check-type
	sta	curchk		;For all future packets
	mvi	a,'F'		;Set the state to file send.
	sta	state
	ret
rinit3: cpi	'E'		;Is it an error packet.
	jnz	nak0		;If not NAK whatever it is.
	call	error
	jmp	abort

;These are some utility routines.

;	Abort

abort:	mvi	a,'A'		;Otherwise abort.
	sta	state
	ret

;	NAK

nak0:	call	updrtr		;Update number of retries.

nak:	lda	pktnum		;Get the packet number we're waiting for.
	sta	argblk
	xra	a		;No data.
	sta	argblk+1
	mvi	a,'N'		;NAK that packet.
	call	spack
	 jmp	abort		; Give up.
	ret			;Go around again.

updrtr: lxi	d,scrnrt	;Position cursor
	call	prtstr
	lhld	numrtr
	inx	h		;Increment the number of retries
	shld	numrtr
	call	nout		;Write the number of retries.
	ret

;[jd] this routine prints parity warnings.  All registers are
; saved except for a.
parwrn: push	b
	push	d
	push	h
	lxi	d,inms25
	call	error3
	pop	h
	pop	d
	pop	b
	ret
;[jd] end of addition


;	This routine sets up the data for init packet (either the
;	Send_init or ACK packet).

rpar:	lda	rpsiz		;Get the receive packet size.
	adi	' '		;Add a space to make it printable.
	mov	m,a		;Put it in the packet.
	inx	h		;Point to the next char.
	lda	rtime		;Get the receive packet time out.
	adi	' '		;Add a space.
	mov	m,a		;Put it in the packet.
	inx	h
	lda	rpad		;Get the number of padding chars.
	adi	' '
	mov	m,a
	inx	h
	lda	rpadch		;Get the padding char.
	adi	100O		;Uncontrol it.
	ani	7FH
	mov	m,a
	inx	h
	lda	reol		;Get the EOL char.
	adi	' '
	mov	m,a
	inx	h
	lda	rquote		;Get the quote char.
	mov	m,a
	inx	h
	mvi	m,'Y'		;[jd] we know how to do 8-bit quoting
	lda	parity		;[jd]
	cpi	parnon		;[jd] parity none?
	jz	rpar1		;[jd] yes, keep going
	lda	qbchr		;[jd] no, better request 8-bit quoting
	mov	m,a

rpar1:
	inx	h		  ;Advance to next
	lda	inichk		;Get desired block check type
	mov	m,a		;Store it
	inx	h		;Advance pointer
	mvi	a,08H		;Six pieces of data.
	ret


;	This routine reads in all the send_init packet information.

spar:	sta	temp4		;Save the number of arguments.
	mov	a,m		;Get the max packet size.
	sbi	' '		;Subtract a space.
	sta	spsiz		;Save it.
	lda	temp4
	cpi	3		;Fewer than three pieces?
	rm			;If so we are done.
	inx	h
	inx	h		;Increment past the time out info.
	mov	a,m		;Get the number of padding chars.
	sbi	' '
	sta	spad
	lda	temp4
	cpi	4		;Fewer than four pieces?
	rm			;If so we are done.
	inx	h
	mov	a,m		;Get the padding char.
	adi	100O		;Re-controlify it.
	ani	7FH
	sta	spadch
	lda	temp4
	cpi	5		;Fewer than five pieces?
	rm			;If so we are done.
	inx	h
	mov	a,m		;Get the EOL char.
	sbi	' '
	sta	seol
	lda	temp4
	cpi	6		;Fewer than six pieces?
	rm			;If so we are done.
	inx	h
	mov	a,m		;Get the quote char.
	sta	squote
	lda	temp4		;Get the amount of data supplied
	cpi	7		;Have an 8-bit quote?
	rm			;If not there, all done
	inx	h		;Yes, get the character
	mvi	a,0		;[jd]
	sta	quot8		;[jd] assume not quoting
	mov	a,m		;Get	the	supplied character
	cpi	'N'		;[jd] No?
	jz	spar1		;[jd] then don't try to do it
	cpi	' '		;[jd] maybe they don't know about it...
	jz	spar1		;[jd] then don't try to do it.
	cpi	'Y'		;[jd] Yes?
	jnz	spar2		;[jd]
	lda	parity		;[jd] using parity?
	cpi	parnon		;[jd] no, don't need quoting...
	jz	spar1		;[jd]
	mvi	a,0ffh		;[jd] else turn on...
	sta	quot8		;[jd] ...quote flag
	jmp	spar1
spar2:	sta	qbchr		;[jd] use their quote char (should validate)
	mvi	a,0ffh
	sta	quot8		;[jd] turn quote flag and fall thru...

spar1:	lda	temp4		;Determine if block check type given
	cpi	8		;Is the field there?
	rm			;If not, all done
	inx	h		;Point to the character
	mov	a,m		;Get the value
	mov	b,a		;Copy value
	lda	chktyp		;Get our type
	cmp	b		;Is it our desired type?
	jz	spar01		;If so, use it
	mvi	a,'1'		;No, use single character
	sta	inichk		;Store as type desired after init done
	ret			;And return

spar01: sta	inichk		;Store the desired block check type
	ret			;And return

;	Receive file

rfile:	lda	numtry		;Get the number of tries.
	cpi	maxtry		;Have we reached the maximum number of tries?
	jm	rfile1
	lxi	d,ermes5
	call	error3		;Move cursor and print an error message.
	jmp	abort		;Change the state to abort.
rfile1: inr	a		;Increment it.
	sta	numtry		;Save the updated number of tries.
	call	rpack		;Get a packet.
	jmp	nak		; Trashed packet: nak, retry.
	cpi	'S'		;Is it a send initiate packet?
	jnz	rfile2		; No, try next type.
	lda	oldtry		;Get the number of tries.
	cpi	imxtry		;Have we reached the maximum number of tries?
	jm	rfil12		;If not proceed.
	lxi	d,ermes4
	call	error3		;Move cursor and print an error message.
	jmp	abort		;Change the state to abort.
rfil12: inr	a		;Increment it.
	sta	oldtry		;Save the updated number of tries.
	lda	pktnum		;Get the present packet number.
	dcr	a		;Decrement.
	mov	b,a
	lda	argblk		;Get the packet's number
	cmp	b		;Is the packet's number one less than now?
	jnz	nak0		;No, NAK and try again.
	call	updrtr		;Update the retry count.
	xra	a
	sta	numtry		;Reset the number of tries.
	lxi	h, data 	;Get a pointer to our data block.
	call	rpar		;Set up the parameter information.
	sta	argblk+1	;Save the number of arguments.
	mvi	a,'Y'		;Acknowledge packet.
	call	spack		;Send the packet.
	 jmp	abort		; Failed, abort.
	ret
rfile2: cpi	'Z'		;Is it an EOF packet?
	jnz	rfile3		; No, try next type.
	lda	oldtry		;Get the number of tries.
	cpi	maxtry		;Have we reached the maximum number of tries?
	jm	rfil21		;If not proceed.
	lxi	d,ermes6
	call	error3		;Move cursor and print an error message.
	jmp	abort		;Change the state to abort.
rfil21: call	tryagn
	ret
rfile3: cpi	'F'		;Start of file?
	jnz	rfile4
	call	compp
	jnz	nak0		;No, NAK it and try again.
	call	countp
	call	gofil		;Get a file to write to.
	 jmp	abort
	call	init1		;Initialize all the buffers.
	lda	numtry		;Get the number of tries.
	sta	oldtry		;Save it.
	call	ackp
	mvi	a,'D'		;Set the state to data receive.
	sta	state
	lda	czseen		;Check if we punted a file
	cpi	'Z'		;and didn't want any more
	rz			;If that was the request, keep telling other end
	xra	a		;Otherwise, clear flag (Control-X is only for one file)
	sta	czseen		;And store the flag back
	ret

rfile4: cpi	'B'		;End of transmission.
	jnz	rfile5
	call	compp
	jnz	nak0		;No, NAK it and try again.
	xra	a		;No data.  (Packet number already in argblk).
	sta	argblk+1
	mvi	a,'Y'		;Acknowledge packet.
	call	spack		;Send the packet.
	 jmp	abort
	mvi	a,'C'		;Set the state to complete.
	sta	state
	ret
rfile5: cpi	'E'		;Is it an error packet.
	jnz	abort
	call	error
	jmp	abort

;	Receive data

rdata:	lda	numtry		;Get the number of tries.
	cpi	maxtry		;Have we reached the maximum number of tries?
	jm	rdata1
	lxi	d,erms10
	call	error3		;Display error message.
	jmp	abort		;Change the state to abort.
rdata1: inr	a		;Increment it.
	sta	numtry		;Save the updated number of tries.
	call	rpack		;Get a packet.
	 jmp	nak		; Trashed packet: nak, retry.
	cpi	'D'		;Is it a data packet?
	jnz	rdata2		; No, try next type.
rdat11: call	compp
	jz	rdat14
	lda	oldtry		;Get the number of tries.
	cpi	maxtry		;Have we reached the maximum number of tries?
	jm	rdat12		;If not proceed.
	lxi	d,erms10
	call	error3		;Display err msg.
	jmp	abort		;Change the state to abort.
rdat12: call	tryagn
	ret
rdat14: call	countp
	lda	numtry		;Get the number of tries.
	sta	oldtry		;Save it.
	lda	argblk+1	;Get the length of the data.
	call	ptchr
	 jmp	abort		; Unable to write out chars;abort.
	xra	a
	sta	numtry		;Reset the number of tries.
	sta	argblk+1	;No data.  (Packet number still in argblk.)
	mov	c,a		;Assume no data
	lda	czseen		;Check if control-X typed
	ora	a		; .  .	.
	jz	rdat15		;Zero if not typed
	mov	c,a		;Get the type of character typed
	mvi	a,1		;One data character
	sta	argblk+1	;Save the count
	mov	a,c		;Get the possible data character
	sta	data		;Store in data area
rdat15: mvi	a,'Y'		;Acknowledge packet.
	call	spack		;Send the packet.
	 jmp	abort
	ret
rdata2: cpi	'F'		;Start of file?
	jnz	rdata3		; No, try next type.
	lda	oldtry		;Get the number of tries.
	cpi	maxtry		;Have we reached the maximum number of tries?
	jm	rdat21		;If not proceed.
	lxi	d,ermes5
	call	error3		;Display err msg.
	jmp	abort		;Change the state to abort.
rdat21: call	tryagn
	ret
rdata3: cpi	'Z'		;Is it a EOF packet?
	jnz	rdata4		;Try and see if its an error.
	call	compp
	jnz	nak0		;No, NAK it and try again.
	call	countp
	lda	argblk+1	;Get the data length
	cpi	1		;Have one item?
	jnz	rdat33		;If not, ignore data
	lda	data		;Yes, get the character
	cpi	'D'		;Is it a 'D' for discard?
	jz	rdat36		;If so, punt file

rdat33: lhld	bufpnt		;Get the dma pointer.
	lda	chrcnt		;Get the number of chars left in the DMA.
rdat34: dcr	a		;Lower the count.
	ora	a
	jm	rdat35		;If full then stop.
	mvi	m,'Z'-100O	;Put in a ^Z for EOF.
	inx	h		;Point to the next space.
	jmp	rdat34
rdat35: call	outbuf		;Output the last buffer.
	 jmp	abort		; Give up if the disk is full.
	mvi	c,closf 	;Close up the file.
	lxi	d,fcb
	call	bdos
	xra	a		;Since we kept the file,
	sta	czseen		;don't say it was discarded.

rdat36: lda	numtry		;Get the number of tries.
	sta	oldtry		;Save it.
	call	ackp
	mvi	a,'F'
	sta	state
	ret
rdata4: cpi	'E'		;Is it an error packet.
	jnz	abort
	call	error
	jmp	abort

;	Send command

send:	mvi	a,cmifi 	;Parse an input file spec.
	lxi	d,fcb		;Give the address for the FCB.
	call	comnd
	 jmp	kermit		; Give up on bad parse.
send1:	call	cfmcmd
send11: call	mfname		;handle (multi) files
	jnc	send14		;got a valid file-name
	lxi	d,erms15
	call	error3		;Display error msg.
	jmp	kermit
send14: call	init		;Clear the line and initialize the buffers.
	xra	a
	sta	pktnum		;Set the packet number to zero.
	sta	numtry		;Set the number of tries to zero.
	sta	wrn8		;[jd] we haven't sent the 8-bit-lost warning
	lxi	h,0
	shld	numpkt		;Set the number of packets to zero.
	shld	numrtr		;Set the number of retries to zero.
	lxi	d,scrnrt	;Position cursor
	call	prtstr
	lxi	h,0
	call	nout		;Write the number of retries.
	mvi	a,'1'		;Reset to use single character checksum
	sta	curchk		;For startup
	mvi	a,'S'
	sta	state		;Set the state to receive initiate.
	;...

;SEND state table switcher

send2:	lxi	d,scrnp 	;Position cursor
	call	prtstr
	lhld	numpkt
	call	nout		;Write the packet number.
	lda	state		;Get the state.

	cpi	'D'		;Are we in the data send state?
	jnz	send3
	call	sdata
	jmp	send2

send3:	cpi	'F'		;Are we in the file send state?
	jnz	send4
	call	sfile		;Call send file.
	jmp	send2

send4:	cpi	'Z'		;Are we in the EOF state?
	jnz	send5
	call	seof
	jmp	send2

send5:	cpi	'S'		;Are we in the send initiate state?
	jnz	send6
	call	sinit
	lda	state		;[jd] get state back
	cpi	'F'		;[jd] into file send state yet?
	jnz	send2		;[jd] no
	lxi	d,inms23	;[jd] yes, print sending...
	call	finmes		;[jd]
	jmp	send2

send6:	cpi	'B'		;Are we in the eot state?
	jnz	send7
	call	seot
	jmp	send2

send7:	cpi	'C'		;Are we in the send complete state?
	jnz	send8		;No...
	lxi	d,infms3	;Yes, write "Complete" message.
	lda	czseen		;Or was it interrupted?
	ora	a		; .  .	.
	jz	send7a		;No.
	lxi	d,inms13	;Yes, then say "Interrupted" instead.
send7a: call	finmes
	jmp	kermit

send8:	cpi	'A'		;Are we in the send "abort" state?
	jnz	send9
	lxi	d,infms4	;Print	message.
	call	finmes
	jmp	kermit

send9:	lxi	d,infms4	;Anything else is equivalent to "abort".
	call	finmes
	jmp	kermit

;	Send routines

;	Send initiate

sinit:	lda	numtry		;Get the number of tries.
	cpi	imxtry		;Have we reached the maximum number of tries?
	jm	sinit2
	lxi	d,erms14
	call	error3		;Display ermsg
	jmp	abort		;Change the state to abort.
sinit2: inr	a		;Increment it.
	sta	numtry		;Save the updated number of tries.
	mvi	a,'1'		;Reset to use single character checksum
	sta	curchk		;For startup
	lda	chktyp		;Get our desired block check type
	sta	inichk		;Store so we tell other end
	lxi	h, data 	;Get a pointer to our data block.
	call	rpar		;Set up the parameter information.
	sta	argblk+1	;Save the number of arguments.
	lda	numpkt		;Get the packet number.
	sta	argblk
	mvi	a,'S'		;Send initiate packet.
	call	spack		;Send the packet.
	 jmp	abort		; Failed, abort.
	call	rpack		;Get a packet.
	 jmp	r		; Trashed packet don't change state, retry.
	cpi	'Y'		;ACK?
	jnz	sinit3		;If not try next.
	call	compp
	rnz			;If not try again.
	call	countp
	lda	argblk+1	;Get the number of pieces of data.
	lxi	h,data		;Pointer to the data.
	call	spar		;Read in the data.
	lda	numtry		;Get the number of tries.
	sta	oldtry		;Save it.
	xra	a
	sta	numtry		;Reset the number of tries.
	lda	inichk		;Get the agreed upon block check type
	sta	curchk		;Store as type to use for packets now
	mvi	a,'F'		;Set the state to file send.
	sta	state
	call	getfil		;Open the file.
	 jmp	abort		; Something is wrong, die.
	ret
sinit3: cpi	'N'		;NAK?
	jnz	sinit4		;If not see if its an error.
	call	updrtr		;Update the number of retries.
	lda	pktnum		;Get the present packet number.
	inr	a		;Increment.
	mov	b,a
	lda	argblk		;Get the packet's number.
	cmp	b		;Is the packet's number one more than now?
	rnz			;If not assume its for this packet, go again.
	xra	a
	sta	numtry		;Reset number of tries.
	mvi	a,'F'		;Set the state to file send.
	sta	state
	ret
sinit4: cpi	'E'		;Is it an error packet.
	jnz	abort
	call	error
	jmp	abort

;	Send file header

sfile:	lda	numtry		;Get the number of tries.
	cpi	maxtry		;Have we reached the maximum number of tries?
	jm	sfile1
	lxi	d,erms14
	call	error3
	jmp	abort		;Change the state to abort.
sfile1: inr	a		;Increment it.
	sta	numtry		;Save the updated number of tries.
	xra	a		;Clear A
	sta	czseen		;No control-Z or X seen
	lxi	h, data 	;Get a pointer to our data block.
	shld	datptr		;Save it.
	lxi	h,fcb+1 	;Pointer to the file name in the FCB.
	shld	fcbptr		;Save position in FCB.
	mvi	b,0		;No chars yet.
	mvi	c,0
sfil11: mov	a,b
	cpi	8H		;Is this the ninth char?
	jnz	sfil12		;If not proceed.
	mvi	a,'.'		;Get a dot.
	lhld	datptr
	mov	m,a		;Put the char in the data packet.
	inx	h
	shld	datptr		;Save position in data packet.
	inr	c
sfil12: inr	b		;Increment the count.
	mov	a,b
	cpi	0CH		;Twelve?
	jp	sfil13
	lhld	fcbptr
	mov	a,m
	ani	7fH		;Turn off CP/M 2 or 3's high bits.
	inx	h
	shld	fcbptr		;Save position in FCB.
	cpi	'!'		;Is it a good character?
	jm	sfil11		;If not get the next.
	lhld	datptr
	mov	m,a		;Put the char in the data packet.
	inx	h
	shld	datptr		;Save position in data packet.
	inr	c
	jmp	sfil11		;Get another.
sfil13: mov	a,c		;Number of char in file name.
	sta	argblk+1
	lhld	datptr
	mvi	a,'$'
	mov	m,a		;Put in a dollar sign for printing.
	lxi	d,scrfln	;Position cursor
	call	prtstr
	lxi	d,data		;Print the file name
	call	prtstr
	lda	pktnum		;Get the packet number.
	sta	argblk
	mvi	a,'F'		;File header packet.
	call	spack		;Send the packet.
	jmp	abort		; Failed, abort.
	call	rpack		;Get a packet.
	 jmp	r		; Trashed packet don't change state, retry.
	cpi	'Y'		;ACK?
	jnz	sfile2		;If not try next.
	call	compp
	rnz			;If not hold out for the right one.
sfil14: call	countp
	lda	numtry		;Get the number of tries.
	sta	oldtry		;Save it.
	xra	a
	sta	numtry		;Reset the number of tries.
sfil15: xra	a		;Get a zero.
	sta	fcb+20H 	;Set the record number to zero.
	sta	eoflag		;Indicate not EOF.
	mvi	a,0FFH
	sta	filflg		;Indicate file buffer empty.
	call	gtchr
	 jmp	sfil16		;Error go see if its EOF.
	jmp	sfil17		;Got the chars, proceed.
sfil16: cpi	0FFH		;Is it EOF?
	jnz	abort		;If not give up.
	mvi	a,'Z'		;Set the state to EOF.
	sta	state
	ret
sfil17: sta	size		;Save the size of the data gotten.
	mvi	a,'D'		;Set the state to data send.
	sta	state
	ret
sfile2: cpi	'N'		;NAK?
	jnz	sfile3		;Try if error packet.
	call	updrtr		;Update the number of retries.
	lda	pktnum		;Get the present packet number.
	inr	a		;Increment.
	mov	b,a
	lda	argblk		;Get the packet's number.
	cmp	b		;Is the packet's number one more than now?
	rnz			;If not go try again.
	jmp	sfil14		;Just as good as a ACK;go to the ACK code.
sfile3: cpi	'E'		;Is it an error packet.
	jnz	abort
	call	error
	jmp	abort

;	Send data

sdata:	lda	numtry		;Get the number of tries.
	cpi	maxtry		;Have we reached the maximum number of	tries?
	jm	sdata1
	lxi	d,erms14
	call	error3
	jmp	abort		;Change the state to abort.
sdata1: inr	a		;Increment it.
	sta	numtry		;Save the updated number of tries.
	lxi	h, data 	;Get a pointer to our data block.
	shld	datptr		;Save it.
	lxi	h,filbuf	;Pointer to chars to be sent.
	shld	cbfptr		;Save position in char buffer.
	mvi	b,1		;First char.
sdat11: lhld	cbfptr
	mov	a,m
	inx	h
	shld	cbfptr		;Save position in char buffer.
	mov	c,a		;[jd] preserve character temporarily
	lda	quot8		;[jd] doing eighth-bit quoting?
	ora	a		;[jd]
	mov	a,c		;[jd] restore char
	jnz	sdat4		;[jd] using eighth-bit quoting, no warning
	lda	parity		;[jd] get parity
	cpi	parnon		;[jd] none?
	mov	a,c		;[jd] restore character
	jz	sdat4		;[jd] no parity, leave char alone
	lda	wrn8		;[jd] look at warning flat
	ora	a		;[jd] have we already given the warning?
	jnz	sdat5		;[jd] yes, skip this
	mov	a,c		;[jd] restore character...
	ani	80h		;[jd] examine parity
	jz	sdat5		;[jd] no parity, no warning.
	call	parwrn		;[jd] ...print warning - parity lost
	mvi	a,0ffh		;[jd] remember that we sent the message
	sta	wrn8		;[jd]
sdat5:	mov	a,c		;[jd] restore character again
	ani	7fh		;[jd] strip parity so not checksummed
sdat4:	lhld	datptr
	mov	m,a		;Put the char in the data packet.
	inx	h
	shld	datptr		;Save position in data packet.
	inr	b		;Increment the count.
	lda	size		;Get the number of chars in char buffer.
	cmp	b		;Have we transfered that many?
	jp	sdat11		;If not get another.
	lda	size		;Number of char in char buffer.
	sta	argblk+1
	lda	pktnum		;Get the packet number.
	sta	argblk
	mvi	a,'D'		;Data packet.
	call	spack		;Send the packet.
	 jmp	abort		; Failed, abort.
	call	rpack		;Get a packet.
	 jmp	r		; Trashed packet don't change state, retry.
	cpi	'Y'		;ACK?
	jnz	sdata2		;If not try next.
	call	compp
	rnz			;If not hold out for the right one.
	lda	argblk		;Get the packet number back
	call	countp
	lda	numtry		;Get the number of tries.
	sta	oldtry		;Save it.
	xra	a
	sta	numtry		;Reset the number of tries.
	lda	argblk+1	;Get the data length
	cpi	1		;Check if only 1 character?
	jnz	sdat15		;If not, just continue
	lda	data		;Got one character, get it from data
	cpi	'Z'		;Want to abort entire stream?
	jnz	sdat14		;If not, check for just this file
	sta	czseen		;Yes, remember it
sdat14: cpi	'X'		;Desire abort of current file?
	jnz	sdat15		;If not, just continue
	sta	czseen		;Yes, remember that
sdat15: lda	czseen		;Also get control-Z flag
	ora	a		;Check if either given
	jz	sdat12		;If neither given, continue
	mvi	a,'Z'		;Change state to EOF
	sta	state		; .  .	.
	ret			;And return

sdat12: call	gtchr
	 jmp	sdat13		;Error go see if its EOF.
	sta	size		;Save the size of the data gotten.
	ret
sdat13: cpi	0FFH		;Is it EOF?
	jnz	abort		;If not give up.
	mvi	a,'Z'		;Set the state to EOF.
	sta	state
	ret
sdata2: cpi	'N'		;NAK?
	jnz	sdata3		;See if is an error packet.
	call	updrtr		;Update the number of retries.
	lda	pktnum		;Get the present packet number.
	inr	a		;Increment.
	mov	b,a
	lda	argblk		;Get the packet's number.
	cmp	b		;Is the packet's number one more than now?
	rnz			;If not go try again.
	jmp	sdat12		;Just as good as a ACK;go to the ACK code.
sdata3: cpi	'E'		;Is it an error packet.
	jnz	abort
	call	error
	jmp	abort

;	Send EOF

seof:	lda	numtry		;Get the number of tries.
	cpi	maxtry		;Have we reached the maximum number of tries?
	jm	seof1
	lxi	d,erms14
	call	error3
	jmp	abort		;Change the state to abort.
seof1:	inr	a		;Increment it.
	sta	numtry		;Save the updated number of tries.
	lda	pktnum		;Get the packet number.
	sta	argblk
	xra	a
	sta	argblk+1	;No data.
	lda	czseen		;Check if C-Z or C-X typed
	ora	a		; .  .	.
	jz	seof14		;If not aborted, just keep going
	mvi	a,'D'		;Tell other end to discard packet
	sta	data		;Store in data portion
	mvi	a,1		;One character
	sta	argblk+1	;Store the length
seof14: mvi	a,'Z'		;EOF packet.
	call	spack		;Send the packet.
	 jmp	abort		; Failed, abort.
	call	rpack		;Get a packet.
	 jmp	r		; Trashed packet don't change state, retry.
	cpi	'Y'		;ACK?
	jnz	seof2		;If not try next.
	call	compp
	rnz			;If not hold out for the right one.
seof12: call	countp
	lda	numtry		;Get the number of tries.
	sta	oldtry		;Save it.
	xra	a
	sta	numtry		;Reset the number of tries.
	mvi	c,closf 	;Close the file.
	lxi	d,fcb
	call	bdos
;* Check if successful
	lda	czseen		;Desire abort of entire stream?
	cpi	'Z'		;Desire abort of entire stream?
	jz	seof13		;If so, just give up now
	call	mfname		;Get the next file.
	 jc	seof13		; No more.
	call	getfil		;and open it
	 jmp	abort		; Something is wrong, die.
	xra	a		;Clear A
	sta	czseen		;Since we have not aborted this file
	mvi	a,'F'		;Set the state to file send.
	sta	state
	ret
seof13: mvi	a,'B'		;Set the state to EOT.
	sta	state
	ret
seof2:	cpi	'N'		;NAK?
	jnz	seof3		;Try and see if its an error packet.
	call	updrtr		;Update the number of retries.
	lda	pktnum		;Get the present packet number.
	inr	a		;Increment.
	mov	b,a
	lda	argblk		;Get the packet's number.
	cmp	b		;Is the packet's number one more than now?
	rnz			;If not go try again.
	jmp	seof12		;Just as good as a ACK;go to the ACK code.
seof3:	cpi	'E'		;Is it an error packet.
	jnz	abort
	call	error
	jmp	abort

;	Send EOT

seot:	lda	numtry		;Get the number of tries.
	cpi	maxtry		;Have we reached the maximum number of tries?
	jm	seot1
	lxi	d,erms14
	call	error3
	jmp	abort		;Change the state to abort.
seot1:	inr	a		;Increment it.
	sta	numtry		;Save the updated number of tries.
	lda	pktnum		;Get the packet number.
	sta	argblk
	xra	a
	sta	argblk+1	;No data.
	mvi	a,'B'		;EOF packet.
	call	spack		;Send the packet.
	 jmp	abort		; Failed, abort.
	call	rpack		;Get a packet.
	 jmp	r		; Trashed packet don't change state, retry.
	cpi	'Y'		;ACK?
	jnz	seot2		;If not try next.
	call	compp
	rnz			;If not hold out for the right one.
seot12: call	countp
	lda	numtry		;Get the number of tries.
	sta	oldtry		;Save it.
	xra	a
	sta	numtry		;Reset the number of tries.
	mvi	a,'C'		;Set the state to file send.
	sta	state
	ret
seot2:	cpi	'N'		;NAK?
	jnz	seot3		;Is it error.
	call	updrtr		;Update the number of retries.
	lda	pktnum		;Get the present packet number.
	inr	a		;Increment.
	mov	b,a
	lda	argblk		;Get the packet's number.
	cmp	b		;Is the packet's number one more than now?
	rnz			;If not go try again.
	jmp	seot12		;Just as good as a ACK;go to the ACK code.
seot3:	cpi	'E'		;Is it an error packet.
	jnz	abort
	call	error
	jmp	abort

;	File routines

;	Output the chars in a packet.

ptchr:	sta	temp1		;Save the size.
	lxi	h,data		;Beginning of received packet	data.
	shld	outpnt		;Remember where we are.
	lda	rquote
	mov	b,a		;Keep the quote char in b.
	mvi	c,0		;[jd] assume no 8-bit quote char
	lda	quot8		;[jd] doing 8-bit quoting?
	ora	a
	jz	ptchr1		;[jd] no, keep going
	lda	qbchr		;[jd] else get 8-bit quote char
	mov	c,a		;[jd] keep this in c
ptchr1: lxi	h,temp1
	dcr	m		;Decrement # of chars in packet.
	jm	rskp		;Return successfully if done.
	lxi	h,chrcnt	;Number offf chars remaining in dma.
	dcr	m		;Decrement.
	jp	ptchr2		;Continue if space left.
	call	outbuf		;Output it if full.
	 jmp	r		; Error return if disk is full.
ptchr2: lhld	outpnt		;Get position in output buffer.
	mov	a,m		;Grab a char.
	inx	h
	shld	outpnt		;and bump pointer.
	mvi	e,0		;[jd] assume nothing to OR in.
	cmp	c		;[jd] is it the binary quote char?
	jnz	ptch2a		;[jd] no, keep going
	mvi	e,80h		;[jd] include parity bit
	lda	temp1
	dcr	a
	sta	temp1		;[jd] decrement character count
	mov	a,m		;[jd] get next character
	inx	h
	shld	outpnt

ptch2a: cmp	b		;Is it the quote char?
	jnz	ptchr3		;[jd] changed to ptchr3 so includes parity
	mov	a,m		;Get the quoted character
	inx	h
	shld	outpnt		;and bump pointer.
	lxi	h,temp1
	dcr	m		;Decrement # of chars in packet.
	mov	d,a		;Save the char.
	ani	80H		;Turn off all but the parity bit.
	ora	e		;[jd] let parity come from either (???)
	mov	e,a		;Save the parity bit.
	mov	a,d		;Get the char.
	ani	7FH		;Turn off the parity bit.
	cmp	b		;Is it the quote char?
	jz	ptchr3		;If so just go write it out.
	cmp	c		;[jd] maybe it's the 8-bit prefix character?
	jz	ptchr3		;[jd] then don't controllify.
	mov	a,d		;Get the char.
	adi	40H		;Make the character a control char again.
	ani	7FH		;Modulo 128.
ptchr3: ora	e		;Or in the parity bit.
ptchr4: lhld	bufpnt		;Destination buffer.
	mov	m,a		;Store it.
	inx	h
	shld	bufpnt		;Update the pointer
	jmp	ptchr1		;and loop to next char.

	;output the buffer, reset bufpnt and chrcnt

outbuf: push	b
	mvi	c,writef	;The write code.
	lxi	d,fcb
	call	bdos		;Write the record.
	pop	b
	ora	a		;Successful.
	jz	outbf1
	lxi	d,erms11
	call	error3
	ret
outbf1: lxi	h,buff		;Addr for beginning.
	shld	bufpnt		;Store addr for beginning.
	mvi	a,bufsiz-1	;Buffer size.
	sta	chrcnt		;Number of chars left.
	jmp	rskp

;	Get the chars from the file.

gtchr:	lda	squote		;Get the quote char.
	mov	c,a		;Keep quote char in c.
	lda	filflg		;Get the file flag.
	ora	a		;Is there anything in the DMA?
	jz	gtchr0		;Yup, proceed.
	mvi	b,0		;No chars yet.
	call	inbuf
	 jmp	gtceof		;No more chars, go return EOF.
gtchr0: lda	curchk		;Get current block check type
	sui	'1'		;Get the extra overhead
	mov	b,a		;Get a copy
	lda	spsiz		;Get the maximum packet size.
	sui	5		;Subtract the overhead.
	sub	b		;Determine max packet length
	sta	temp1		;This is the number of chars we are to get.
	lxi	h,filbuf	;Where to put the data.
	shld	cbfptr		;Remember where we are.
	mvi	b,0		;No chars.
gtchr1: lda	temp1
	dcr	a		;Decrement the number of chars left.
	jp	gtchr2		;Go on if there is more than one left.
	mov	a,b		;Return the count in A.
	jmp	rskp

gtchr2: sta	temp1
	lda	chrcnt		;Space left in the DMA.
	dcr	a
;* Can improve order here.
	jm	gtchr3
	sta	chrcnt
	jmp	gtchr4

gtchr3: call	inbuf		;Get another buffer full.
	jmp	gtch30		; If no more return what we got.
	jmp	gtchr4		;If we got some, proceed.
gtch30: mov	a,b		;Return the count in A.
	ora	a		;Get any chars?
	jnz	rskp		;If so return them.
	jmp	gtceof		;If not, say we found the end of the file.

gtchr4: lhld	bufpnt		;Position in DMA.
	mov	a,m		;Get a char from the file.
	inx	h
	shld	bufpnt
	mov	d,a		;Save the char.
	ani	80H		;Turn off all but parity.
	mov	e,a		;Save the parity bit.
	jz	gtch4a		;[jd] no parity, skip this check...
	lda	quot8		;[jd] doing eighth-bit quoting?
	ora	a
	jz	gtch4a		;[jd] no, just proceed normally
	lda	temp1		;[jd] get space remaining
	cpi	2		;[jd] 3 chrs left (one cnted already)?
	jm	gtchr9		;[jd] no, skip this
	dcr	a		;[jd] decrement space remaining
	sta	temp1		;[jd] put back.
	lhld	cbfptr		;[jd] Position in character buffer.
	lda	qbchr		;[jd] get quote character
	mov	m,a		;]jd] Put the quote char in the buffer.
	inx	h		;[jd] increment destination buffer pointer
	shld	cbfptr		;[jd] store the pointer back
	inr	b		;[jd] Increment the char count.
	mvi	e,0		;[jd] no parity bit to OR in.
;[jd] fall thru...

gtch4a: mov	a,d		;Restore the char.
	ani	7FH		;Turn off the parity.
	mov	d,a		;[jd] save here for later...
	cpi	' '		;Compare to a space.
	jm	gtchr5		;If less then its a control char, handle it.
	cpi	del		;Is the char a delete?
	jz	gtchr5		;Go quote it.

;[3.9A] Begin change to fix undesired quoting of ampersands.

	lda	quot8		; Are we doing 8th-bit quoting?
	ora	a
	jz	gtch4c		; if not, skip this test and restore character.
	lda	qbchr		; get 8th-bit quote character
	cmp	d		; same as current character?
	jz	gtch4b		; yes, have to quote it...
gtch4c: mov	a,d		; no. get character back again.

;[3.9A] End Change (Charles Carvalho, ACC)

	cmp	c		;Is it the quote char?
	jnz	gtchr8		;If not proceed.
gtch4b: lxi	h,temp1 	;[jd] point to char count
	dcr	m		;[jd] decrement (know room for at least one)
	lhld	cbfptr		;Position in character buffer.
	mov	m,c		;Put the (quote) char in the buffer.
	inx	h
	shld	cbfptr
	inr	b		;Increment the char count.
	mov	a,d		;[jd] restore character again
	jmp	gtchr8
gtchr5: ora	e		;Turn on the parity bit.
	cpi	('Z'-100O)	;Is it a ^Z?
	jnz	gtchr7		;If not just proceed.
	lda	cpmflg		;Was the file created by CPM?
	cpi	1		;in ASCII-mode ?
	jz	gtch52		;First Control-Z stops text
	lda	eoflag		;EOF flag set?
	ora	a
	jz	gtchr6		;If not just go on.
	lda	cpmflg		;Was the file created by CPM?
	cpi	2		;in BINARY (same as default)
	jz	gtchr6		;Yes (this code currently does the same)
	lhld	bufpnt		;since CHRCNT is ZERO at EOF-time
	lda	chrcnt		;(set by INBUF5 B.G.E)
	mov	d,a		;Get the number of chars left in the DMA.
gtch51: dcr	d
	mov	a,d
	jp	gtch53		;Any chars left?
gtch52: xra	a		;If not, get a zero.
	sta	chrcnt		;Say no more chars in buffer.
	mov	a,b		;Return the count in A.
	jmp	rskp
gtch53: mov	a,m		;Get the next char.
	inx	h		;Move the pointer.
	cpi	('Z'-100O)	;Is it a ^Z?
	jz	gtch51		;If so see if they rest are.

gtchr6: mvi	a,('Z'-100O)	;Restore the ^Z.
gtchr7: sta	temp2		;Save the char.
	lxi	h,temp1 	;Point to the char total remaining.
	dcr	m		;Decrement it.
	lhld	cbfptr		;Position in character buffer.
	mov	m,c		;Put the quote in the buffer.
	inx	h
	shld	cbfptr
	inr	b		;Increment the char count.
	lda	temp2		;Get the control char back.
	adi	40H		;Make the non-control.
	ani	7fH		;Modulo 200 octal.
gtchr8: lhld	cbfptr		;Position in character buffer.
	ora	e		;Or in the parity bit.
	mov	m,a		;Put the char in the buffer.
	inx	h
	shld	cbfptr
	inr	b		;Increment the char count.
	jmp	gtchr1		;Go around again.

gtchr9: ;[jd] not enough room left in buffer...
	lhld	bufpnt
	dcx	h
	shld	bufpnt		;[jd] back up over last character
	lxi	h,chrcnt	;[jd] point to character count
	inr	m		;[jd] increment it
	mov	a,b		;[jd] count of chars transferred
	jmp	rskp		;[jd] return it

gtceof: mvi	a,0FFH		;Get a minus one.
	ret

inbuf:	lda	eoflag		;Have we reached the end?
	ora	a
	jz	inbufa		;no
	mvi	b,0
	rnz			;Return if set.
inbufa: push	b
	push	d
	push	h
	lxi	h,chrcnt	;Reset character count.
	lda	filflg		;Get the file flag.
	ora	a		;Has there ever been anything in the DMA?
	jz	inbuf1		;If so just set it.
	mvi	m,bufsiz	;If not set it the buffer size.
	xra	a		;Zero the flag.
	sta	filflg
	jmp	inbuf2
inbuf1: mvi	m,bufsiz-1	;ELse set it to one less than the buffer size.
inbuf2: lxi	h,buff		;Set the buffer pointer.
	shld	bufpnt
	mvi	c,readf 	;Read a record.
	lxi	d,fcb
	call	bdos
	ora	a		;00H => read O.K
	jz	inbuf4
	jmp	inbuf5		;we either hit EOF or an	ERROR
inbuf3: pop	h
	pop	d
	pop	b
	ret			;Either EOF or ERROR => finish
				;with NON-skip return
inbuf4: pop	h		;more data, restore and rskp
	pop	d
	pop	b
	jmp	rskp
inbuf5: xra	a
	sta	chrcnt		;say no more chars in buffer
	mvi	a,0FFH
	sta	eoflag		;Set the EOF flag.
	jmp	inbuf3		;and return

;Multi-file access subroutine.	Allows processing of multiple files
;(i.e., *.ASM) from disk.  This routine builds the proper name in the
;FCB each time it is called.  This command would be used in such pro-
;grams such as modem transfer, tape save, etc. in which you want to
;process single or multiple files.
;
;The FCB will be set up with the next name, ready to do normal proces-
;sing (OPEN, READ, etc.) when routine is called.
;
;Carry is set if no more names can be found
;
;MFFLG1 is count/switch [0 for first time thru, pos for all others]
;MFFLG2 is counted down for each successive GETNEXT file call
;
;Technique used is to repeat SFIRST/SNEXT sequence N+1 times for each
;successive call, till sequence fails. CP/M does NOT allow disk-handling
;between SFIRST and SNEXT!!
;
mfname: jnc	mfn00
	cmc			;clear carry
mfn00:	push	b		;Save registers
	push	d
	push	h
	mvi	c,setdma	;Init DMA addr, FCB
	lxi	d,80H
	call	bdos
	xra	a		;A = 0
	sta	fcbext		;clear extension
	lda	mfflg1		;find out if "second" call in row
	ora	a
	jnz	mfn01		;Were here before
	sta	mfflg2
	lxi	h,fcb
	lxi	d,mfreq
	lxi	b,12
	call	mover		;.from FCB to MFREQ
	mvi	c,SFIRST	;Search first
	lxi	d,fcb
	call	bdos
	jmp	mfn02		;and check results
;
mfn01:	dcr	a
	sta	mfflg2		;store down-counter
	lxi	h,mfreq 	;SFIRST REQ name
	lxi	d,fcb
	lxi	b,12
	call	mover		;.from MFREQ to FCB
	mvi	c,sfirst	;Search first old one,we got it before
	lxi	d,fcb
	call	bdos		;no error's expected -we got that before
mfn01a:
	mvi	c,snext 	;Search next
	call	bdos
mfn02:	push	psw		;[ah] fixed that from "a"
	lda	mfflg2		;get "repeat file counter"
	ora	a
	jz	mfn02a		;if zero, check if SNEXT had ERROR
	dcr	a		;count down
	sta	mfflg2		;store back
	pop	psw		;no error-check, we got it before  [ah], too.
	jmp	mfn01a		;next SNEXT
mfn02a: pop	psw		;[ah] fixed that, too.
	ora	a
	jm	mffix2		;No (more) found
	call	movfcb		;move data to fcb
	lda	mfreq		;the original disk-designator
	sta	fcb		;back into fcb
	lda	mfflg1		;get file-flag
	inr	a		;increment
	sta	mfflg1		;and store for next go-around
	mvi	a,0		;Setup FCB
	sta	fcbext		;clean up FCB for OPEN etc
	sta	fcbrno
mffix1: pop	h		;restore registers
	pop	d
	pop	b
	ret			;and return
mffix2: stc			;set carry
	jmp	mffix1		;return with CARRY set

;Move subroutine
;from H-pointer to D-pointer B-bytes
;would be nice to use the Z80 Block-move -sigh
;
mover:				;[ah] Well, I did it.
;*	LDIR			;[ah] (DE)<-(HL);INC HL;INC DE;DEC BC 'til BC=0
	db	0EDH,0B0H	;[ah] Op-code for LDIR instruction of Z80
	ret

movfcb: add	a
	add	a
	add	a
	add	a
	add	a		;* 32
	adi	80H
	mov	l,a
	mvi	h,0
	lxi	d,fcb
	lxi	b,12
	call	mover
	ret
getfil: mvi	a,0FFH
	sta	filflg		;Nothing in the DMA.
	xra	a
	sta	eoflag		;Not the end of file.
	sta	fcb+0CH 	;Zero the extent.
	sta	fcb+0EH 	;Must be zero for MAKEF or OPENF.
	sta	fcb+20H 	;Zero the current record.
	mvi	c,openf 	;Open the file.
	lxi	d,fcb
	call	bdos
	jmp	rskp

;	Get the file name (including host to micro translation)

gofil:	lxi	h,data		;Get the address of the file name.
	shld	datptr		;Store the address.
	lxi	h,fcb+1 	;Address of the FCB.
	shld	fcbptr		;Save it.
	xra	a
	sta	temp1		;Initialize the char count.
	sta	temp2
	sta	fcb		;Set the drive to default to current.
	mvi	b,' '
gofil1: mov	m,b		;Blank the FCB.
	inx	h
	inr	a
	cpi	0CH		;Twelve?
	jm	gofil1
gofil2: lhld	datptr		;Get the NAME field.
	mov	a,m
	cpi	'a'		;Force upper case
	jm	gofl2a		;
	ani	5FH		;
gofl2a: inx	h
	cpi	'.'		;Seperator?
	jnz	gofil3
	shld	datptr		;[jd] update ptr (moved from above)
	lxi	h,fcb+9H
	shld	fcbptr
	lda	temp1
	sta	temp2
	mvi	a,9H
	sta	temp1
	jmp	gofil6
gofil3: ora	a		;Trailing null?
	jz	gofil7		;Then we're done.
	shld	datptr		;[jd] no, can update ptr now.
	lhld	fcbptr
	mov	m,a
	inx	h
	shld	fcbptr
	lda	temp1		;Get the char count.
	inr	a
	sta	temp1
	cpi	8H		;Are we finished with this field?
	jm	gofil2
gofil4: sta	temp2
	lhld	datptr
	mov	a,m
	inx	h
	shld	datptr
	ora	a
	jz	gofil7
	cpi	'.'		;Is this the terminator?
	jnz	gofil4		;Go until we find it.
gofil6: lhld	datptr		;Get the TYPE field.
	mov	a,m
	cpi	'a'		;Force upper case
	jm	gofl6a		;
	ani	5FH		;
gofl6a: ora	a		;Trailing null?
	jz	gofil7		;Then we're done.
;[jd] move above two lines so we don't increment pointer if char is null
	inx	h
	shld	datptr
	lhld	fcbptr
	mov	m,a
	inx	h
	shld	fcbptr
	lda	temp1		;Get the char count.
	inr	a
	sta	temp1
	cpi	0CH		;Are we finished with this field?
	jm	gofil6
gofil7: lhld	datptr
	mvi	m,'$'		;Put in a dollar sign for printing.
	lxi	d,scrfln	;Position cursor
	call	prtstr
	lxi	d,data		;Print the file name
	call	prtstr
	lda	flwflg		;Is file warning on?
	ora	a
	jz	gofil9		;If not, just proceed.
	mvi	c,openf 	;See if the file exists.
	lxi	d,fcb
	call	bdos
	cpi	0FFH		;Does it exist?
	jz	gofil9		;If not create it.
	lxi	d,infms5
	call	error3
	lda	temp2		;Get the number of chars in the file name.
	ora	a
	jnz	gofil8
	lda	temp1
	sta	temp2
gofil8: mvi	b,0
	mov	d,b		;Zero d for dad index into filename
	inr	a		;Replace next character after filename
	cpi	9H		;Is the first field full?
	jnz	gofl80
	mvi	b,0FFH		;Set a flag saying so.
	dcr	a
gofl80: mov	e,a		;Keep current, replace index in d,e.
gofl81: lxi	h,fcb		;Get the FCB.
	dad	d		;Add in the character number.
	mvi	m,'&'		;Replace the char with an ampersand.
	push	b
	push	d
	lxi	h,fcb		;Trim off any CP/M 2.2 attribute bits
	mvi	c,1+8+3 	;so they do not affect the new file
gofl82:mov	a,m		;
	ani	7FH		;
	mov	m,a		;
	inx	h		;
	dcr	c		;
	jnz	gofl82		;
	mvi	c,openf 	;See if the file exists.
	lxi	d,fcb
	call	bdos
	pop	d
	pop	b
	cpi	0FFH		;Does it exist?
	jz	gofl89		;If not create it.
	mov	a,b		;Get the field-full flag.
	ora	a		;Incr. or decr. ?
	jz	gofl83		;Jump if increment
	dcr	e		;Decrement the number of chars.
	mov	a,e
	ora	a
	jz	gofl88		;If no more, die.
	jmp	gofl81
gofl83: inr	e		;Increment the number of chars.
	mov	a,e
	cpi	9H		;Are we to the end?
	jm	gofl81		;If not try again.
	lda	temp2		;Get the original size.
	mov	e,a
	mvi	b,0FFH		;Set flag saying field-full, decrement
	jmp	gofl81

gofl88: lxi	d,erms16	;Tell user that we can't rename it.
	call	prtstr
	ret

gofl89: mvi	c,8		;[jd] # of chars in name
	lxi	d,fnbuf 	;[jd] point to destination
	lxi	h,fcb+1 	;[jd] source of name
	mvi	b,0		;[jd] first-time-thru flag
gof89a: mov	a,m		;[jd] get a char from the name
	inx	h		;[jd] pass it
	cpi	' '		;[jd] end of this part of name?
	jz	gof89b		;[jd] yes, skip rest...
	stax	d		;[jd] else drop char off
	inx	d		;[jd] increment dest ptr
	dcr	c		;[jd] decrement count
	jnz	gof89a		;[jd] and continue if more to go
gof89b: mov	a,b		;[jd]
	ora	a		;[jd] first time thru?
	jnz	gof89c		;[jd] no, no period
	mvi	a,'.'		;[jd] period between parts
	stax	d		;[jd]
	inx	d		;[jd]
	mvi	b,0ffh		;[jd] not first time thru anymore
	mvi	c,3		;[jd] length of this part
	lxi	h,fcb+9 	;[jd] start of extension
	jmp	gof89a		;[jd] keep copying
gof89c: mvi	a,'$'
	stax	d		;[jd] end the name string
	lxi	d,fnbuf 	;[jd] Print the file name
	call	prtstr
gofil9: mvi	c,delf		;Delete the file if it exists.
	lxi	d,fcb
	call	bdos
	xra	a
	sta	fcb+0CH 	;Zero the extent.
	sta	fcb+0EH 	;Must be zero for MAKEF or OPENF.
	sta	fcb+20H 	;Zero the current record.
	mvi	c,makef 	;Now create it.
	lxi	d,fcb
	call	bdos
	cpi	0FFH		;Is the disk full?
	jnz	rskp
	lxi	d,erms11
	call	error3
	ret

;	Packet routines

;Send_Packet
;This routine assembles a packet from the arguments given and sends it
;to the host.
;
;Expects the following:
;	A	 - Type of packet (D,Y,N,S,R,E,F,Z,T)
;	ARGBLK	 - Packet sequence number
;	ARGBLK+1 - Number of data characters
;Returns: +1 on failure
;	   +2 on success

spack:	sta	argblk+2
	lxi	h,packet	;Get address of the send packet.
	mvi	a,soh		;Get the start of header char.
	mov	m,a		;Put in the packet.
	inx	h		;Point to next char.
	lda	curchk		;Get current checksum type
	sui	'1'		;Determine extra length of checksum
	mov	b,a		;Copy length
	lda	argblk+1	;Get the number of data chars.
	adi	' '+3		;Real packet character count made printable.
	add	b		;Determine overall length
	mov	m,a		;Put in the packet.
	inx	h		;Point to next char.
	lxi	b,0		;Zero the checksum AC.
	mov	c,a		;Start the checksum.
	lda	argblk		;Get the packet number.
	adi	' '		;Add a space so the number is printable.
	mov	m,a		;Put in the packet.
	inx	h		;Point to next char.
	add	c
	mov	c,a		;Add the packet number to the checksum.
	mvi	a,0		;Clear A (Cannot be XRA A, since we can't touch carry flag)
	adc	b		;Get high order portion of checksum
	mov	b,a		;Copy back to B
	lda	argblk+2	;Get the packet type.
	mov	m,a		;Put in the packet.
	inx	h		;Point to next char.
	add	c
	mov	c,a		;Add the packet number to the checksum.
	mvi	a,0		;Clear A
	adc	b		;Get high order portion of checksum
	mov	b,a		;Copy back to B
spack2: lda	argblk+1	;Get the packet size.
	ora	a		;Are there any chars of data?
	 jz	spack3		; No, finish up.
	dcr	a		;Decrement the char count.
	sta	argblk+1	;Put it back.
	mov	a,m		;Get the next char.
	inx	h		;Point to next char.
	add	c
	mov	c,a		;Add the packet number to the checksum.
	mvi	a,0		;Clear A
	adc	b		;Get high order portion of checksum
	mov	b,a		;Copy back to B
	jmp	spack2		;Go try again.
spack3: lda	curchk		;Get the current checksum type
	cpi	'2'		;Two character?
	jz	spack4		;Yes, go handle it
	jnc	spack5		;No, go handle CRC if '3'
	mov	a,c		;Get the character total.
	ani	0C0H		;Turn off all but the two high order bits.
				;Shift them into the low order position.
	rlc			;Two left rotates same as 6 rights
	rlc			; .  .	.
	add	c		;Add it to the old bits.
	ani	3FH		;Turn off the two high order bits.  (MOD 64)
	adi	' '		;Add a space so the number is printable.
	mov	m,a		;Put in the packet.
	inx	h		;Point to next char.
	jmp	spack7		;Go store eol character

;Here for 3 character CRC-CCITT

spack5: mvi	m,0		;Store a null for current end
	push	h		;Save H
	lxi	h,packet+1	;Point to first checksumed character
	call	crcclc		;Calculate the CRC
	pop	h		;Restore the pointer
	mov	c,e		;Get low order half for later
	mov	b,d		;Copy the high order
	mov	a,d		;Get the high order portion
	rlc			;Shift off low 4 bits
	rlc			; .  .	.
	rlc			; .  .	.
	rlc			; .  .	.
	ani	0FH		;Keep only low 4 bits
	adi	' '		;Put into printing range
	mov	m,a		;Store the character
	inx	h		;Point to next position

;Here for two character checksum

spack4: mov	a,b		;Get high order portion
	ani	0FH		;Only keep last four bits
	rlc			;Shift up two bits
	rlc			; . .  .
	mov	b,a		;Copy back into safe place
	mov	a,c		;Get low order half
	rlc			;Shift	high two bits
	rlc			;to low two bits
	ani	03H		;Keep only two low bits
	ora	b		;Get high order portion in
	adi	' '		;Convert to printing character range
	mov	m,a			;Store the character
	inx	h		;Point to next character
	mov	a,c		;get low order portion
	ani	3FH		;Keep only six bits
	adi	' '		;Convert to printing range
	mov	m,a		;Store it
	inx	h		;Bump the pointer


spack7: lda	seol		;Get the EOL the other host wants.
	mov	m,a		;Put in the packet.
	inx	h		;Point to next char.
	xra	a		;Get a null.
	mov	m,a		;Put in the packet.

	call	outpkt		;Call the system dependent routine.
	 jmp	r
	jmp	rskp

;	Write out a packet.

outpkt:
	lda	spad		;Get the number of padding chars.
	sta	temp1
outpk2: lda	temp1		;Get the count.
	dcr	a
	ora	a
	jm	outpk6		;If none left proceed.
	sta	temp1
	lda	spadch		;Get the padding char.
	mov	e,a			;Put the char in right AC.
	call	outchr		;Output it.
	jmp	outpk2
outpk6:
	lxi	h,packet	;Point to the packet.
outlup: mov	a,m		;Get the next character.
	ora	a		;Is it a null?
	jz	outlud		;If so return success.
	mov	e,a		;Put the char in right AC.
	call	outchr		;Output the character.
	inx	h		;Increment the char pointer.
	jmp	outlup

outlud: jmp	rskp		;Just return


;Set the parity for a character in A.

setpar: push	h		;Save HL.
	push	b
	lxi	h,parity
	mov	c,m		;Get the parity routine.
	mvi	b,0
	lxi	h,parjmp	;Get the first address.
	dad	b
	pchl

parjmp: jmp	even
	jmp	mark
	jmp	none
	jmp	odd
	jmp	space

none:	jmp	parret		;Don't touch the parity bit.

even:	ani	7FH		;Strip parity.
	jpe	parret		;Already even, leave it.
	ori	80H		;Make it even parity.
	jmp	parret

mark:	ori	80H		;Turn on the parity bit.
	jmp	parret

odd:	ani	7FH		;Strip parity.
	jpo	parret		;Already odd, leave it.
	ori	80H		;Make it odd parity.
	jmp	parret

space:	ani	7FH		;Turn off the parity bit.
	jmp	parret

parret: pop	b
	pop	h		;Restore HL.
	ret

;************************System Dependent****************************
;	Put a char in E to the port.

outchr: in	mnprts		;Get the output ready flag.
	ani	output		;Is it set?
	jz	outchr		;If so, loop until it isn't.
	mov	a,e
	call	setpar
	out	mnport		;Output it.
	ret


;************************System Dependent****************************
;
;	Get a char from the port and return in A.

inchr:	lxi	h,0000H 	;Reset fuzzy timer
	shld	timval		;[jd]

inchr0:	lda	elbflg		;Check flag if character in input buffer
	ora	a
	jnz	inchr2		;If so go read it

	mvi	c,consta	;Is a char on the console?
	call	bdos
	ora	a
	jz	inchr6		;If not go look for another char.
	mvi	c,conin 	;Get the char.
	call	bdos
	cpi	cr		;Is it a carriage return?
	rz			;If so return

;Here if not a cr, check other possibilities

inchr4: cpi	('Z'-100O)	;Control-Z?
	jz	inchr5		;Yes, go flag it
	cpi	('C'-100O)	;Control-C?
	jz	reenter 	;re-enter, he wants to get out
	cpi	('X'-100O)	;Control-X?
	jnz	inchr6		;No, try for another character

inchr5: adi	100O		;Convert to printing range
	sta	czseen		;Flag we saw a control-Z
	ret			;And return

inchr6: lda	timflg		;[jd] pick up timer flag
	ora	a		;[jd] are we allowed to use timer?
	jz	inchr0		;[jd] no, don't time out
	lhld	timval		;[jd] Increment fuzzy time-out
	inx	h		;
	shld	timval		;(65,536 * loop time)
	mov	a,h		;(Retry if not time-out)
	ora	l		;
	jnz	inchr0		;
	call	updrtr		;Count as retry
	ret			;and return to do retry

inchr2:	call	elread		;Get next char out of input buffer

	mov	b,a
	lda	parity		;Is the parity none?
	cpi	parnon
	mov	a,b
	jz	rskp		;If so just return.
	ani	7FH		;Turn off the parity bit.
	jmp	rskp

;This is the character read routine. 
; The character is taken from the head of the input buffer queue. 
; If the read pointer catches up to the write pointer both pointers are 
; reinititialized before the start address of the buffer.
; The pointers always point on the most recently written/read character.

elread:	push	d		;Save registers used by this routine
	push	h
	lhld	elrptr		;Increment read pointer
	inx	h
	mov	a,m		;Get char
	push	psw		; and save it
	xchg
	di			;Disable interrupt of further input chars
	lhld	elwptr		; while comparing read and write pointer
	stc			;Clear carry flag
	cmc
;* SBC HL,DE			;Sorry, but I couldn't resist.
	db	0EDH,052H	;Op-code for above Z80 command
	xchg			;Restore read pointer in HL
	jnz	elrea1		;If read has caught up with write 
	lxi	h,elbuff-1	; reset both pointers
	shld	elwptr		; to beginning of buffer
	xra	a		; and clear availability flag
	sta	elbflg
elrea1:	shld	elrptr		;Save new read pointer
	ei			;Enable further interrupts
	pop	psw		;Return with char in accu
	pop	h
	pop	d
	ret

;Interrupt service routine for reading input character from SIO
; and storing it in buffer queue.
elints:	di			;Disable interrupt of further input chars
	push	psw
	push	d
	push	h
	lhld	elwptr		;Increment write pointer
	inx	h
	xchg			;Check against end of buffer
	lhld	elbend
	stc			;Clear
	cmc			; carry flag
;* SBC HL,DE			;Sorry again.
	db	0EDH,052H	;Op-code for above Z80 command
	xchg			;Restore write pointer
	cc	elmove		;If at end of buffer go and reshuffle
	in	mnport		;Read character from SIO
	mov	m,a		;Store it in buffer
	shld	elwptr		;Store new write pointer
	mvi	a,0FFH		;Set availability flag
	sta	elbflg
elintx:	pop	h
	pop	d
	pop	psw
	ei			;Enable further interrupts
;* RETI				;Return from this one
	db	0EDH,04DH	;Op-code for above Z80 command

;If possible move remaining input up to beginning of buffer
elmove:	push	d		;Save write pointer
	lhld	elrptr		;Check if read pointer still at beginning
	xchg
	lxi	h,elbuff-1
	stc			;Clear
	cmc			; carry flag
;* SBC HL,DE			;What can I say?
	db	0EDH,052H	;Op-code for above Z80 command
	pop	h		;Balance stack before beating it
	jz	elfull		;If buffer full go apologize 
	stc			;Else compute length of remaining input
;* SBC HL,DE			;Don't yell at me.
	db	0EDH,052H	;Op-code for above Z80 command
	push	b		;Save BC pair before using it.
	mov	b,h		;Store length in BC
	mov	c,l
	lxi	h,elbuff	;Set up target
	xchg
	lhld	elrptr		; and source address
	inx	hl
	call	mover		; and move it!
	xchg			;Store the new write pointer
	shld	elwptr
	lxi	h,elbuff-1	;Update read pointer
	pop	b		;Restore that one
	ret			; and proceed

elmes1:	db 	'Input buffer overflow. Characters might be lost.',cr,lf,'$'
elfull:	lxi	d,elmes1
	call	prtstr
	pop	h		;Discard return address
	jmp	elintx		;Skip input part


;Receive_Packet
;This routine waits for a packet to arrive from the host.  It reads
;characters until it finds a SOH.  It then reads the packet into packet.
;
;Returns:  +1 failure (if the checksum is wrong or the packet trashed)
;	   +2 success with A	    - message type
;		ARGBLK	 - message number
;		ARGBLK+1 - length of data

rpack:	call	inpkt		;Read up to a carriage return.
	 jmp	r		; Return bad.
rpack0: call	getchr		;Get a character.
	 jmp	rpack		; Hit a CR;null line;just start over.
	cpi	soh		;Is the char the start of header char?
	 jnz	rpack0		; No, go until it is.
rpack1: call	getchr		;Get a character.
	 jmp	r		; Hit the carriage return, return bad.
	cpi	soh		;Is the char the start of header char?
	 jz	rpack1		; Yes, then go start over.
	sta	packet+1	;Store in packet also
	mov	c,a		;Start the checksum.
	lda	curchk		;Get block check type
	sui	'1'		;Determine extra length of block check
	mov	b,a		;Get a copy
	mov	a,c		;Get back length character
	sui	' '+3		;Get the real data count.
	sub	b		;Get total length
	sta	argblk+1
	mvi	b,0		;Clear high order half of checksum
	call	getchr		;Get a character.
	 jmp	r		; Hit the carriage return, return bad.
	cpi	soh		;Is the char the start of header char?
	 jz	rpack1		; Yes, then go start over.
	sta	argblk
	sta	packet+2	;Save also in packet
	add	c
	mov	c,a		;Add the character to the checksum.
	mvi	a,0		;Clear A
	adc	b		;Get high order portion of checksum
	mov	b,a		;Copy back to B
	lda	argblk
	sui	' '		;Get the real packet number.
	sta	argblk
	call	getchr		;Get a character.
	 jmp	r		; Hit the carriage return, return bad.
	cpi	soh		;Is the char the start of header char?
	 jz	rpack1		; Yes, then go start over.
	sta	temp1		;Save the message type.
	sta	packet+3	;Save in packet
	add	c
	mov	c,a		;Add the character to the checksum.
	mvi	a,0		;Clear A
	adc	b		;Get high order portion of checksum
	mov	b,a		;Copy back to B
	lda	argblk+1	;Get the number of data characters.
	sta	temp2
	lxi	h,data		;Point to the data buffer.
	shld	datptr
rpack2: lda	temp2
	sui	1		;Any data characters?
	 jm	rpack3		; If not go get the checksum.
	sta	temp2
	call	getchr		;Get a character.
	 jmp	r		; Hit the carriage return, return bad.
	cpi	soh		;Is the char the start of header char?
	 jz	rpack1		; Yes, then go start over.
	lhld	datptr
	mov	m,a		;Put the char into the packet.
	inx	h		;Point to the next character.
	shld	datptr
	add	c
	mov	c,a		;Add the character to the checksum.
	mvi	a,0		;Clear A
	adc	b		;Get high order portion of checksum
	mov	b,a		;Copy back to B
	jmp	rpack2		;Go get another.
rpack3: call	getchr		;Get a character.
	 jmp	r		; Hit the carriage return, return bad.
	cpi	soh		;Is the char the start of header char?
	 jz	rpack1		; Yes, then go start over.
	sui	' '		;Turn the char back into a number.
	sta	temp3
;Determine type of checksum

	lda	curchk		;Get the current checksum type
	cpi	'2'		;1, 2 or 3 character?
	jz	rpack4		;If zero, 2 character
	jnc	rpack5		;Go handle 3 character
	mov	a,c		;Get the character total.
	ani	0C0H		;Turn off all but the two high order bits.
				;Shift them into the low order position.
	rlc			;Two left rotates same as six rights
	rlc			; .  .	.
	add	c		;Add it to the old bits.
	ani	3FH		;Turn off the two high order bits.  (MOD 64)
	mov	b,a
	lda	temp3		;Get the real received checksum.
	cmp	b		;Are they equal?
	jz	rpack7		;If so, proceed.
rpack9: call	updrtr		;If not, update the number of retries.
	ret			;Return error.

;Here for three character CRC-CCITT

rpack5: lhld	datptr		;Get the address of the data
	mvi	m,0		;Store a zero in the buffer to terminate packet
	lxi	h,packet+1	;Point at start of checksummed region
	call	crcclc		;Calculate the CRC
	mov	c,e		;Save low order half for later
	mov	b,d		;Also copy high order
	mov	a,d		;Get high byte
	rlc			;Want high four bits
	rlc			; .  .	.
	rlc			;And shift two more
	rlc			; .  .	.
	ani	0FH		;Keep only 4 bits
	mov	d,a		;Back into D
	lda	temp3		;Get first value back
	cmp	d		;Correct?
	 jnz	rpack9		;No, punt
	call	getchr		;Get a character.
	 jmp	r		; Hit the carriage return, return bad.
	cpi	soh		;Is the char the start of header char?
	 jz	rpack1		; Yes, then go start over.
	sui	' '		;Remove space offset
	sta	temp3		;Store for later check

;Here for a two character checksum and last two characters of CRC

rpack4: mov	a,b		;Get high order portion
	ani	0FH		;Only four bits
	rlc			;Shift up two bits
	rlc			; .  .	.
	mov	b,a		;Save back in B
	mov	a,c		;Get low order
	rlc			;move two high bits to low bits
	rlc			; .  .	.
	ani	03H		;Save only low two bits
	ora	b		;Get other 4 bits
	mov	b,a		;Save back in B
	lda	temp3		;Get this portion of checksum
	cmp	b		;Check first half
	 jnz	rpack9		;If bad, go give up
	call	getchr		;Get a character.
	 jmp	r		; Hit the carriage return, return bad.
	cpi	soh		;Is the char the start of header char?
	 jz	rpack1		; Yes, then go start over.
	sui	' '		;Remove space offset
	mov	b,a		;Save in safe place
	mov	a,c		;Get low 8 bits of checksum
	ani	3FH		;Keep only 6 bits
	cmp	b		;Correct value
	 jnz	rpack9		;Bad, give up

rpack7: lhld	datptr
	mvi	m,0		;Put a null at the end of the data.
	lda	temp1		;Get the type.
	jmp	rskp

inpkt:	lxi	h,recpkt	;Point to the beginning of the packet.
	shld	pktptr
inpkt1:call	inchr		;Get first character
	jmp	r		;Return failure
	cpi	soh		;is it the beginning of a packet?
	jnz	inpkt1		;if not, ignore leading junk
	jmp	inpkt3		;else go put it in packet
inpkt2: call	inchr		;Get a character.
	 jmp	r		; Return failure.
	cpi	soh		;is it a new beginning of packet?
	jnz	inpkt3		;if not continue
	lxi	h,recpkt	;else throw away what we've got so far
	shld	pktptr		;
inpkt3:lhld	pktptr		;
	mov	m,a		;Put the char in the packet.
	inx	h
	shld	pktptr
	mov	b,a
	lxi	d,-recpkx	;Start over if packet buffer overflow
	dad	d		;
	jc	inpkt		;
	lda	reol		;Get the EOL char.
	cmp	b
	jnz	inpkt2		;If not loop for another.

;Begin IBM change/fdc
;This moved from OUTPK7 -- it appears that waiting until we're
;ready to send a packet before looking for turnaround character
;is long enough for it to get lost.  Better to look now.

inpkt4: lda	ibmflg		;Is this the IBM?
	ora	a
	jz	inpkt6		;If not then proceed.
	lda	state		;Check if this is the Send-Init packet.
	cpi	'S'
	jz	inpkt6		;If so don't wait for the XON.
inpkt5: call	inchr		;Wait for the turn around char.
	 jmp	inpkt6
	cpi	xon		;Is it the IBM turn around character?
	jnz	inpkt5		;If not, go until it is.

inpkt6: lhld	pktptr		;Reload packet pointer
	mvi	m,cr		;Set a carriage-return to stop rpack:
;End IBM change/fdc.

	lxi	h,recpkt
	shld	pktptr		;Save the packet pointer.
	jmp	rskp		;If so we are done.

getchr: lhld	pktptr		;Get the packet pointer.
	mov	a,m		;Get the char.
	inx	h
	shld	pktptr
	cpi	cr		;Is it the carriage return?
	jnz	rskp		;If not return retskp.
	ret			;If so return failure.

;CRCCLC - Routine to calculate a CRC-CCITT for a string.
;
;This routine will calculate a CRC using the CCITT polynomial for
;a string.
;
;Usage:
;	HL/ Address of string
;	A/  Length of string
;	CALL CRCCLC
;
;16-bit CRC value is returned in DE.
;
;Registers BC and HL are preserved.
;

crcclc: push	h		;Save HL
	push	b		;And BC
	lxi	d,0		;Initial CRC value is 0

crccl0: mov	a,m		;Get a character
	ora	a		;Check if zero
	jz	crccl1		;If so, all done
	push	h		;Save the pointer
	xra	e		;Add in with previous value
	mov	e,a		;Get a copy
	ani	0FH		;Get last 4 bits of combined value
	mov	c,a		;Get into C
	mvi	b,0		;And make high order zero
	lxi	h,crctb2	;Point at low order table
	dad	b		;Point to correct entry
	dad	b		; .  .	.
	push	h		;Save the address
	mov	a,e		;Get combined value back again
	rrc			;Shift over to make index
	rrc			; .  .	.
	rrc			; .  .	.
	ani	1EH		;Keep only 4 bits
	mov	c,a		;Set up to offset table
	lxi	h,crctab	;Point at high order table
	dad	b		;Correct entry
	mov	a,m		;Get low order portion of entry
	xra	d		;XOR with previous high order half
	inx	h		;Point to high order byte
	mov	d,m		;Get into D
	pop	h		;Get back pointer to other table entry
	xra	m		;Include with new high order half
	mov	e,a		;Copy new low order portion
	inx	h		;Point to other portion
	mov	a,m		;Get the other portion of the table entry
	xra	d		;Include with other high order portion
	mov	d,a		;Move back into D

	pop	h		;And H
	inx	h		;Point to next character
	jmp	crccl0		;Go get next character

crccl1: pop	b		;Restore B
	pop	h		;And HL

	ret			;And return, DE=CRC-CCITT

CRCTAB: DW	00000H
	DW	01081H
	DW	02102H
	DW	03183H
	DW	04204H
	DW	05285H
	DW	06306H
	DW	07387H
	DW	08408H
	DW	09489H
	DW	0A50AH
	DW	0B58BH
	DW	0C60CH
	DW	0D68DH
	DW	0E70EH
	DW	0F78FH

CRCTB2: DW	00000H
	DW	01189H
	DW	02312H
	DW	0329BH
	DW	04624H
	DW	057ADH
	DW	06536H
	DW	074BFH
	DW	08C48H
	DW	09DC1H
	DW	0AF5AH
	DW	0BED3H
	DW	0CA6CH
	DW	0DBE5H
	DW	0E97EH
	DW	0F8F7H

;This is where we go if we get an error during a protocol communication.
; Call error prints the error packet on line 6 or so.
; Call error1 print CRLF followed by the error packet.
; Call error2 just prints the error packet.
; Call error3 positions cursor and prints error message specified in DE.

error:	call	error9		;Position the cursor.
	mvi	a,'A'		;Set the state to abort.
	sta	state
	jmp	error2

error1: lxi	d,crlf		;Print a CRLF.
	call	prtstr
error2: lda	argblk+1	;Get the length of the data.
	mov	c,a
	mvi	b,0		;Put it into BC
	lxi	h,data		;Get the address of the data.
	dad	b		;Get to the end of the string.
	mvi	a,'$'		;Put a dollar sign at the end.
	mov	m,a
	lxi	d,data		;Print error message
	call	prtstr
	ret
error3: push	d		;Save the pointer to the message.
	call	error9		;Position the cursor.
	lxi	d,clrlin	;Clear the line
	call	prtstr
	pop	d		;Get the pointer back.
	call	prtstr		;Print error message
	ret

error9: lxi	d,screrr	;Position cursor
	call	prtstr
	ret

finmes: push	d		;Save message.
	lxi	d,scrst 	;Position the cursor
	call	prtstr
	pop	d		;Print the termination message
	call	prtstr
	lxi	d,scrend	;Position cursor for prompt
	call	prtstr
	ret


;This is the FINISH command.  It tells the remote KERSRV to exit.

finish: call	cfmcmd
	xra	a
	sta	numtry		;Inititialize count.
	mvi	a,'1'		;Reset block check type to single character
	sta	curchk		; .  .	.

finsh1: lda	numtry		;How many times have we tried?
	cpi	maxtry		;Too many times?
	jm	finsh3		;No, try it.
finsh2: lxi	d,erms18	;Say we couldn't do it.
	call	prtstr
	jmp	kermit		;Go home.
finsh3: inr	a		;Increment the number of tries.
	sta	numtry
	xra	a
	sta	argblk		;Make it packet number zero.
	mvi	a,1
	sta	argblk+1	;One piece of data.
	lxi	h,data
	mvi	m,'F'		;Finish running Kermit.
	mvi	a,'G'		;Generic command packet.
	call	spack
	 jmp	finsh2		; Tell the user and die.
	call	rpack		;Get an acknowledgement.
	 jmp	finsh1		; Go try again.
	cpi	'Y'		;ACK?
	jz	kermit		;Yes, we are done.
	cpi	'E'		;Is it an error packet?
	jnz	finsh1		;Try sending the packet again.
	call	error1		;Print the error message.
	jmp	kermit


;This is the LOGOUT command.  It tells the remote KERSRV to logout.

logout: call	cfmcmd
	call	logo		;Send the logout packet.
	jmp	kermit		;Go get another command
	jmp	kermit		; whether we succeed or not.

logo:	xra	a
	sta	numtry		;Inititialize count.
	mvi	a,'1'		;Reset block check type to single character
	sta	curchk		; .  .	.

logo1:	lda	numtry		;How many times have we tried?
	cpi	maxtry		;Too many times?
	jm	logo3		;No, try it.
logo2:	lxi	d,erms19	;Say we couldn't do it.
	call	prtstr
	ret			;Finished.
logo3:	inr	a		;Increment the number of tries.
	sta	numtry
	xra	a
	sta	argblk		;Make it packet number zero.
	mvi	a,1
	sta	argblk+1	;One piece of data.
	lxi	h,data
	mvi	m,'L'		;Logout the remote host.
	mvi	a,'G'		;Generic command packet.
	call	spack
	 jmp	logo2		; Tell the user and die.
	call	rpack		;Get an acknowledgement
	 jmp	logo1		; Go try again.
	cpi	'Y'		;ACK?
	jz	rskp		;Yes, we are done.
	cpi	'E'		;Is it an error packet?
	jnz	logo1		;Try sending the packet again.
	call	error1		;Print the error message.
	ret			;All done.

;This is the BYE command.  It tells the remote KERSRV to logout and exits.

bye:	call	cfmcmd
	call	logo		;Tell the main frame to logout.
	jmp	kermit		;If it fails, don't exit.

	jmp	exit1		;Exit Kermit.

;This is the 'exit' command.  It leaves KERMIT and returns to CP/M.

exit:	call	cfmcmd

exit1:
	mvi	a,18h		;Reset SIO channel
	out	mnprts
	mvi	a,1		; and disable interrupts in WR 1.
	out	mnprts
	xra	a
	out	mnprts

	lhld	oldsp		;Get back the system stack
	sphl			;and restore it.

	jmp	0		;Then reboot system.

;This is the LOG command.  It logs a session to a file.

log:	mvi	a,cmofi 	;Parse an input file spec.
	lxi	d,fcb
	call	comnd
	 jmp	kermt3
	call	cfmcmd
	lxi	h,logflg
	mvi	m,0FFH		;Set the log flag.
	lxi	h,buff
	shld	bufpnt
	mvi	c,delf		;Delete the file if it exists.
	lxi	d,fcb
	call	bdos
	xra	a
	sta	fcb+0CH 	;Zero the extent.
	sta	fcb+0EH 	;Must be zero for MAKEF or OPENF.
	sta	fcb+20H 	;Zero the current record.
	mvi	c,makef 	;Now create it.
	lxi	d,fcb
	call	bdos
	cpi	0FFH		;Is the disk full?
	jnz	kermit		;
	lxi	d,erms17	;If so tell the user
	call	prtstr
	jmp	kermit

;This is the HELP command.  It gives a list of the commands.

help:	call	cfmcmd
help2:	lxi	d,tophlp	;The address of the help message.
	call	prtstr
	jmp	kermit

;This is the TRANSMIT command.

xmit:	mvi	a,cmofi 	;Parse an input file spec (non-wild).
	lxi	d,fcb		;Give the address for the FCB.
	call	comnd
	 jmp	kermit		;Give up on bad parse.
	call	cfmcmd
	call	getfil		;Open file.
	 jmp	kermit		;Can't happen?
	cpi	0FFH		;Succeed?
	jnz	xmit1
	lxi	d,erms15
	call	error3		;Display error msg.
	jmp	kermit

xmit1:	lxi	d,inms19	;Output start message.
	call	prtstr
	call	escpr		;Print the escape character.
	lxi	d,inms20	;Output 2nd part.
	call	prtstr
	call	escpr		;Print the escape character.
	lxi	d,inms21	;Print the rest.
	call	prtstr
	mvi	a,1		;Start file I/O.
	sta	fileio
	xra	a		;Clear XOFF flag.
	sta	xofflg
	sta	chrcnt		;No chars yet.

xnext:	call	prtchr		;Receive comm. line & display.
	mvi	c,dconio	;Anything at console?
	mvi	e,0FFH
	call	bdos
	ora	a
	jz	xnext		;No.

	lda	eoflag		;EOF encountered?
	ora	a
	jnz	xend1		;Yes, finish.
	lhld	bufpnt		;Get current buffer pointer.
	lda	chrcnt		;Characters remaining in buffer?
	ora	a
	jnz	xmit2		;Yes, proceed.
	call	xbuf		;Get next disk record (if any)
	lda	chrcnt		;Get new character counter

xmit2:	mov	b,a		;Character counter.
	xra	a		;Reset line buffer counter.
	mov	c,a
	sta	cmaflg		;Reset carriage return flag.
	lxi	d,cmdbuf	;Use comnd buffer as line buffer.
xmit30: mov	a,m		;Get a character.
	inx	h
	ani	7FH		;Mask 7 bits.
	cpi	cr		;Carriage return?
	jz	xmit32
	cpi	subt		;CTRL-Z (substitute)?
	jz	xmit38
	cpi	lf		;Line feed?
	jz	xmit39
	stax	d		;Save to buffer.
	inx	d
	lda	cmaflg		;Carriage return seen?
	ora	a
	jnz	xmit31		;Yes, don't count this character.
	inr	c		;Count it.
xmit31: dcr	b		;Any characters in buffer?
	jnz	xmit30		;Yes, loop.
	call	xbuf		;No, get next record.
	lda	chrcnt		;Reset working counter.
	mov	b,a
	jmp	xmit30

xmit32: sta	cmaflg		;Mark return seen.
	jmp	xmit31		  ;And continue.

xmit38: sta	eoflag		;Mark EOF for next line.

xmit39: shld	bufpnt		;Save next buffer pointer.
	dcr	b		;Account for the terminating character.
	mov	a,b		;Save count of remaining characters.
	sta	chrcnt
	mov	a,c		;Save line length.
	sta	filcnt

rexmit: lda	filcnt		;Set up line length.
	sta	cmccnt
	lxi	h,cmdbuf	;Set up line buffer pointer.
	shld	cmcptr

xmit40: call	prtchr		;Receive comm. line & display.
	lda	xofflg		;XOFF received?
	ora	a
	jnz	xmit40		;Yes, wait for XON?
	lda	cmccnt		;Any characters left?
	ora	a
	jz	xmit49		;No, next state.
	dcr	a		;Count this character.
	sta	cmccnt
	lhld	cmcptr		;Get it.
	mov	a,m
	inx	h		;Bump to next character.
	shld	cmcptr
	call	setpar		;Set parity (if any).
	mov	e,a		;Restore character.
	call	prtout		;Output it to the comm. line.
	lda	ecoflg		;Local echo?
	ora	a
	jz	xmit40		;No, continue.
	mov	a,e		;Get the character.
	ani	7FH		;Mask out parity.
	mov	e,a		;Display on console.
	mvi	c,dconio
	call	bdos
	jmp	xmit40		;Continue.

xmit49: xra	a		;Reset last character seen.
	sta	lstchr

xmit50: call	prtchr		;Receive comm. line & display.
	call	conchr		;Read keyboard & send.
	 jmp	xendc		;CLOSE connection.
	lda	lstchr		;Check last keyboard character.
	cpi	cr		;Carriage return?
	jz	xnext		;Yes, prepare to send next line.
	jmp	xmit50		;Continue, until carriage return.

xbuf:	lda	eoflag		;Eof encountered?
	ora	a
	jnz	xend		;Yes, return to normal CONNECT state.
	push	b		;Save registers.
	push	d
	mvi	c,readf 	;Read a record.
	lxi	d,fcb
	call	bdos
	pop	d		;Restore registers.
	pop	b
	mvi	a,bufsiz	;Set up counter.
	sta	chrcnt
	lxi	h,buff		;Set the buffer pointer.
	shld	bufpnt
	lda	filerc		;Get the file record count.
	sui	1		;Decrement it.
	sta	filerc
	ret			;If not the last packet then return.
	lda	fileex		;Any more left?
	cpi	0
	jz	xbuf1
	sui	1
	sta	fileex
	mvi	a,80H		;Get a 128.
	sta	filerc		;Start the record count over.
	ret
xbuf1:	mvi	a,0FFH
	sta	eoflag		;Set the EOF flag.
	ret

xend:	pop	b		;Remove return address (a non-local goto!)
xend1:	call	xmtoff		;Close file, etc.
	lxi	d,inms22	;Tell we're doen with transmission
	jmp	telnt1		;Branch to CONNECT command.

xendc:	call	xmtoff		;Close file, etc.
	jmp	kermit		;Back to command loop.

xmtoff: mvi	c,closf 	;Close file.
	lxi	d,fcb
	call	bdos
	xra	a		;Terminate file I/O.
	sta	fileio
	ret

;This is the CONNECT command.

telnet: call	cfmcmd

	lxi	d,infms7	;Output start of message
telnt1: call	prtstr
	call	escpr		;Print the escape char.
	lxi	d,infms8	;Output the rest of the message
	call	prtstr

chrlup: call	prtchr		;See if char at port (type to cons).
	call	conchr		;See if char at cons (type to port).
	 jmp	kermit		;Go to command loop.
	jmp	chrlup		;Go do it again.


;************************System Dependent****************************

prtchr:	lda	elbflg		;Check flag if character in input buffer
	ora	a
	rz
prtch2:	call	elread		;If so, get the character

	ani	7FH		;Make seven bit.
	mov	e,a		;Set the char aside.

	cpi	xon		;Is it an XON?
	jnz	prtxof		;No
	xra	a		;Yes, reset XOFF flag
	sta	xofflg
	mov	a,e		;Restore character
	jmp	prttst
prtxof: cpi	xoff		;Is it an XOFF?
	jnz	prttst		;No
	sta	xofflg		;Yes, set flag
prttst:
	lda	vtflg		;Get the VT52 emulation flag.
	ora	a		;Is the flag set?
	jz	prtch1		;If not, don't do this stuff.

	lda	escflg		;Get the escape flag.
	ora	a		;Is the flag set?
	jnz	vt52		;If so go translate the sequence.
	mov	a,e		;Get the char for testing.
	cpi	del		;Is the char a delete.
	rz			;If so then forget this foolishness.
	cpi	esc		;Is the char an escape?
	jnz	prtch1		;If not skip on.
	mvi	a,1		;Get a one.
	sta	escflg		;Set the escape flag.
	jmp	prtchr		;Get another char...

prtch1: lda	logflg		;Get the log flag.
	ora	a
	cnz	logit		;Log the char if it is set.
	lda	prnflg		;Get Print parallel flag
	ora	a
	jz	prtch3		;not set

	mvi	c,lstout
	call	bdos		;Char to printer

prtch3:
	mvi	c,dconio	;Console output bdos call.
	call	bdos		;Output the char to the console.
	jmp	prtchr		;Go see if there is another character.

conchr:
	mvi	c,dconio	;Direct console I/O BDOS call.
	mvi	e,0FFH		;Input.
	call	BDOS

	ani	07FH		;Keep only 7 bits
	jz	rskp		;Null means nothing there.
	mov	e,a		;Move the char for comparison.
	sta	lstchr		;Save it
	lda	escchr		;Get the escape char.
	cmp	e		;Is it an escape char?
	jz	intchr		;If so go process it.
	mov	a,e		;Get the char.
	call	setpar		;Set parity (if any).
	mov	e,a		;Restore it.
	push	d		;Save the character
	call	prtout		;Output the char to the port.
	pop	d		;Restore the character
	lda	ecoflg		;Get the echo flag.
	ora	a		;Is it turned on?
	jz	rskp		;If not we're done here.
	mov	a,e		;Get the char.
	ani	7FH		;Turn off the parity bit.

	mov	e,a		;Return it.
	mvi	c,dconio	;Direct console output.
	call	bdos		;Echo the char.

	jmp	rskp

intchr: mvi	c,dconio	;Direct console I/O.
	mvi	e,0FFH		;Input.
	call	bdos		;Get a char.
	ora	a		;Is the char a	null?
	jz	intchr		;If so, go until we get a char.
	mov	b,a		;Save the actual char.
	cpi	ctrlc		;is it Control-C?
	jz	contc		;yes
	ani	137O		;Convert to upper case.
	cpi	'C'		;Is it close?
	jnz	intch0		;If not proceed.
contc:	lxi	d,infms9	;Say we are back.
	call	prtstr

	lda	logflg		;Get the log flag.
	ora	a		;Is it set?
	rz			;Return if it is zero.
	xra	a
	sta	logflg		;Turn off the log flag.
	lxi	d,infms6	;Tell user we are closing file.
	call	prtstr
	lhld	bufpnt
	mvi	m,('Z'-100O)	;Put in a ^Z.
	mvi	c,writef	;Write the last buffer.
	lxi	d,fcb
	call	bdos
	mvi	c,closf 	;Close the file.
	lxi	d,fcb
	call	bdos
	ret

;Here if not an 'S'

intch0:
	cpi	'S'		;Is it status?
	jnz	inch01		;If not, proceed.
	call	stat01		;Print out the status stuff.
	jmp	rskp

inch01: cpi	'R'-100O	;Control-R?
	jz	inch02		;Yes
	cpi	'R'		;(plain) R?
	jnz	inch03		;No
inch02: lda	fileio		;TRANSMIT in progress?
	ora	a
	jz	inch03		;No,ignore
	pop	b		;Remove return address (non-local goto)
	jmp	rexmit		;Retransmit line

inch03: mov	a,b		;Get the char.
	cpi	'?'		;Is it a help request?
	jnz	intch1		;If not, go to the next check.
	lda	fileio		;TRANSMIT in progress?
	ora	a
	jz	inch04		;No
	lxi	d,xmthlp	;Tell about R too
	call	prtstr
inch04: lxi	d,inthlp	;If so, get the address of the help message.
	call	prtstr
	call	escpr		;Print escape character
	lxi	d,inhlp2	;Print the rest
	call	prtstr
	jmp	intchr		;Get another char.

intch1: mov	a,b		;Get the character.
	ani	137O		;Convert to upper case if necessary.
	cpi	'B'		;Send a BREAK?
	jnz	intch2		;No, try next thing.

	lxi	d,inms12	;(Not implemented) Only Robin/dm can send BREAK
	call	prtstr
	jmp	rskp

intch2: mov	a, b		;'0' to send a null.
	cpi	'0'		;Is it?
	jnz	intch3		;No.
	mvi	e,0		;Yes, send an ASCII zero.
	call	prtout
	jmp	rskp

intch3: mov	e,a		;Put the char into another reg.
	lda	escchr		;Get the escape char.
	cmp	e		;Is it the escape char?
	jnz	intchz		;If not, go send a beep to the user.
	mov	a,e		;Get the char.
	call	setpar
	mov	e,a		;Restore it.
	call	prtout		;Output it.
	jmp	rskp		;Return, we are done here.
intchz: mvi	e,'G'-100O	;Otherwise send a beep.
	mvi	c,dconio
	call	bdos
	jmp	rskp

vt52:	mvi	a,00H		;Reset the ol' escape flag.
	sta	escflg
	mov	a,e		;Get the char.

;Those machines which use other than vt52, et.al.'s <esc>'Y'
;	as a cursor lead in need to have that translated to
;	their native cursor lead-in sequences, e.g.: <esc>'=', etc.
;	or they CANNOT do ANY cursor addressing, EVER,	other than that
;	hardwired into KERMIT itself.  We do that here.
;	(Fixed second time, very sigh)

	cpi	'Y'		;if cursor lead-in handle it.
	jnz	vt52a		;if not, go on.
	lxi	d,CURLDN	;point to our cursor lead-in.
	call	prtstr		;have cpm print it.
	ret			;and back for another one.
vt52a:
	cpi	'A'		;Less than an 'A'?
	jm	vtig		;Yes - ignore.
	cpi	'K'+1		;Greater than 'K'?
	jp	vtig		;Yes - ignore.
	sui	'A'		;Else make into index.
	rlc			;Multiply by four.
	rlc			;(Shift left twice.)
	lxi	h,ttab		;Load base addr of table.
	mov	e,a		;Move a into de pair.
	mvi	d,00H		;Zero out high byte.
	dad	d		;Double add index+offset.
	xchg			;Exchange de with hl.
	call	prtstr		;and syscall.
	ret			;Return.

vtig:				;Ignore escape sequence.
	push	psw		;Push the char to be output.
	mvi	e,esc		;Load an escape.
	mvi	c,conout	;The function code
	call	bdos		;and the syscal.
	pop	psw		;Restore the character
	mov	e,a		;and move to output register.
	mvi	c,conout	;The function
	call	bdos		;and the syscall.
	ret			;Return home.

logit:	lhld	bufpnt
	mov	m,e		;Store the char.
	inx	h
	shld	bufpnt
	mov	a,l
	ora	a		;Buffer full?
	rnz
	push	d
	mvi	e,xoff		;^S to stop the
	call	prtout		;host until we
	mvi	c,writef	;write out the buffer.
	lxi	d,fcb
	call	bdos
	ora	a		;Successful.
	jz	logit2
	lxi	d,erms11
	call	prtstr
logit2: mvi	e,xon		;^Q to restart
	call	prtout		;the host.
	lxi	h,buff
	shld	bufpnt		;Reset the buffer pointer.
	pop	d
	ret

;This is the SET command.

setcom: lxi	d,settab	;Parse a keyword from the set table.
	lxi	h,sethlp
	call	keycmd
	lxi	h,setjtb	;Get the address of the jump table.
	mov	c,a
	mvi	b,0
	dad	b
	pchl

setjtb: jmp	escape		;00H SET ESC
	jmp	ibmset		;03H SET IBM
	jmp	locall		;06H SET LOCAL
	jmp	kermt3		;09H SET RECEIVE (not currently used)
	jmp	setsnd		;0CH SET SEND (not currently used)
	jmp	filwar		;0FH SET WARNING
	jmp	setcpm		;12H SET FILE-MODE
	jmp	parset		;15H SET PARITY
	jmp	blkset		;18H SET BLOCK-CHECK-TYPE
	jmp	vt52em		;1BH SET VT52
	jmp	prtset		;1EH SET PORT
	jmp	baud		;21H SET BAUD
	jmp	setdisk 	;24H SET DEFAULT-DISK
	jmp	setprn		;27H SET PRINTER
	jmp	settim		;[jd] 2AH SET TIMER


;SET BLOCK-CHECK-TYPE command.

blkset: lxi	d,blktab	;Get the address of the block-check table
	lxi	h,blkhlp	;And the address of the help text
	call	keycmd
	sta	temp1		;Save the parsed item
	call	cfmcmd
	lda	temp1		;Get the value back
	sta	chktyp		;Save desired checksum type
	jmp	kermit		;Go get another command

;SET DEFAULT DISK command

setdisk:lxi	d,fcb
	mvi	a,cmifin	;get "file-spec" silently
	call	comnd
	 jmp	setdi1
setdi1: lda	fcb
	cpi	0		;In case he didn't type ..
	jnz	setdi2		;he typed a drive-spec
	lda	curdsk		;he didn't - give him default
setdi2: sta	curdsk
	mvi	c,inbdos	;reset disks
	call	bdos
	lda	curdsk
	dcr	a		;LOGDSK is relative 0
	mov	e,a
	mvi	c,logdsk
	call	bdos		;and "LOG" it
	jmp	kermit		;all done

;SET SEND command.

setsnd: lxi	d,stsntb	;Parse a keyword from the set send table.
	lxi	h,stshlp
	call	keycmd
	lxi	h,stsjtb	;Get the address of the jump table.
	mov	c,a
	mvi	b,0
	dad	b
	pchl
stsjtb: jmp	stpdch
	jmp	stpad

stpad:	call	cfmcmd
	jmp	kermit

stpdch: call	cfmcmd
	jmp	kermit

;This is the set speed command 

baud:	lxi	d,spdtab
	lxi	h,spdhlp
	call	keycmd

;This is the SET BAUD command for MY ELZET80 (with piggy pack rig-up)
	xchg			;SIO WR4 byte and PIO-B0 byte in DE
	shld	temp1
	call	cfmcmd
	lhld	temp1		;Get them back into HL
	mov	a,l		;Get combined byte with clock mode and PIO-B0 
	sta	speed		;Store new speed code
	aci	0F0H		;Mask out lower half which is the PIO-B0 value
	mov	l,a		;...and save clock mode
	mvi	a,4		;WR4 of SIO...
	out	mnprts		;...control port
	lda	elstbl+2	;Get old WR4 byte
	aci	0FH		;Mask out old clock mode
	ora	l		;Mask in new one
	out	mnprts		;Write into WR4
	mvi	a,0FH		;Define PIO-B as output
	out	piobc
	mov	a,h		;Get new PIO-B0 byte
	sta	elstbl+elslen	;Store it at bottom of table
	out	piobd		;...and write it out
	jmp	kermit


;This is the ESCAPE character SET subcommand.

escape: call	cfmcmd
	lxi	d,escmes	;Get the address of the escape message.
	call	prtstr
	mvi	c,conin 	;Get the char.
	call	bdos
	sta	escchr		;Store the new escape character.
	jmp	kermit


;	This is the LOCAL echo SET subcommand.

locall:lxi	d,ontab
	lxi	h,onhlp
	call	keycmd
	sta	temp1		;Save the parsed value.
	call	cfmcmd
	lda	temp1		;Get the parsed value.
	sta	ecoflg		;Set the local echo flag.
	jmp	kermit

;	This is the VT52 emulation SET subcommand.

vt52em: lxi	d,ontab
	lxi	h,onhlp
	call	keycmd
	sta	temp1		;Save the parsed value.
	call	cfmcmd
	lda	temp1		;Get the parsed value.
	sta	vtflg		;Set the VT52 emulation flag.
	jmp	kermit

;This is SET PRINTER ON/OFF subcommand

setprn: lxi	d,ontab
	lxi	h,onhlp
	call	keycmd
	sta	temp1		;Save parsed value
	call	cfmcmd
	lda	temp1		;Get the parsed value
	sta	prnflg		;and store
	jmp	kermit

;[jd] This is the SET TIMER ON/OFF subcommand

settim: lxi	d,ontab
	lxi	h,onhlp
	call	keycmd
	sta	temp1		; Save parsed value
	call	cfmcmd		; confirm
	lda	temp1
	sta	timflg		; store flag value
	jmp	kermit

;This is the FILE-WARNING SET subcommand

filwar: lxi	d,ontab
	lxi	h,onhlp
	call	keycmd
	sta	temp1		;Save the parsed value.
	call	cfmcmd
	lda	temp1		;Get the parsed value.
	sta	flwflg		;Set the file-warning flag.
	jmp	kermit

;This is the SET IBM command.

ibmset: lxi	d,ontab
	lxi	h,onhlp
	call	keycmd
	sta	temp1		;Save the parsed value.
	call	cfmcmd
	lda	temp1		;Get the parsed value.
	sta	ibmflg		;Set the IBM flag.
	ora	a		;Is it turned on?
	jz	ibmst1		;If not, set parity to the default.
	mvi	a,ibmpar	;Get the IBM parity.
	mvi	b,1		;Set local echo on.
	jmp	ibmst2
ibmst1: mvi	a,defpar
	mvi	b,0		;Set local echo off.
ibmst2: sta	parity		;Save them.
	mov	a,b
	sta	ecoflg
	sta	timflg		;[jd] timer is same as local echo
	jmp	kermit

;	This is the SET PORT command.

prtset: lxi	d,inms12	;(Not implemented)
	call	prtstr
	jmp	kermit

;	SET FILE-MODE command.

setcpm: lxi	d,typtab
	lxi	h,typhlp
	call	keycmd
	sta	temp1		;Save the parsed value.
	call	cfmcmd
	lda	temp1		;Get the parsed value.
	sta	cpmflg		;Set the CPM flag.
	jmp	kermit

parset: lxi	d,partab
	lxi	h,parhlp
	call	keycmd
	sta	temp1		;Save the parsed value.
	call	cfmcmd
	lda	temp1		;Get the parsed value.
	sta	parity		;Set the CPM flag.
	jmp	kermit

;This is the SHOW command.

show:	call	cfmcmd
;* Reconcile this and status.
	call	stat01		;For now just cop out.
	jmp	kermit


;	This is the STATUS command.

status: call	stat0
	jmp	kermit

stat0:	call	cfmcmd

stat01: lda	fileio		;Are we in transmit?
	ora	a
	jz	sta01b		;No
	lxi	d,xmtst 	;Yes,say so
	call	prtstr

sta01b:lxi	d,locst 	;Get the address of the local echo string.
	call	prtstr
	lda	ecoflg		;Get the local echo flag.
	ora	a		;Is it on?
	jz	stat02		;If not say so.
	lxi	d,onstr 	;Say on.
	jmp	stat03
stat02: lxi	d,offstr	;Say off.
stat03: call	prtstr

	lxi	d,vtemst	;Get the address of the VT52 emulation string.
	call	prtstr
	lda	vtflg		;Get the VT52 emulation flag.
	ora	a		;Is it on?
	jz	stat1		;If not say so.
	lxi	d,onstr 	;Say on.
	jmp	stat11
stat1:	lxi	d,offstr	;Say off.
stat11: call	prtstr

	lxi	d,cpmst 	;Get the address of the CPM created file.
	call	prtstr
	lda	cpmflg		;Get the CPM flag.
	ora	a		;Is it on?
	jz	stat2		;If not say so.
	cpi	1		;ASCII?
	lxi	d,ascstr	;
	jz	stat21		;Say ASCII
	lxi	d,binstr	;Say binary
	jmp	stat21
stat2:	lxi	d,defstr	;Say default.
stat21: call	prtstr

	lxi	d,ibmst 	;IBM string.
	call	prtstr
	lda	ibmflg		;IBM flag.
	ora	a		;Is it on?
	jz	stat3		;If not say	so.
	lxi	d,onstr 	;Say on.
	jmp	stat31
stat3:	lxi	d,offstr	;Say off.
stat31: call	prtstr

	lxi	d,filst 	;File warning string.
	call	prtstr
	lda	flwflg		;File warning flag.
	ora	a		;Is it on?
	jz	stat4		;If not say so.
	lxi	d,onstr 	;Say on.
	jmp	stat41
stat4:	lxi	d,offstr	;Say off.
stat41:call	prtstr

	lxi	d,prst		;Printer copy string
	call	prtstr
	lda	prnflg		;Printer ON/OFF flag
	ora	a
	jz	stat42		;OFF
	lxi	d,onstr
	jmp	stat43
stat42:lxi	d,offstr
stat43:call	prtstr
	lxi	d,parst 	;Parity string.
	call	prtstr
	lda	parity		;Get the parity setting.
	lxi	d,pnonst	;None by default.
	cpi	parmrk		;Is it mark?
	jnz	stat5		;If not say so.
	lxi	d,pmrkst	;Say mark.
	jmp	stat55
stat5:	cpi	parspc		;Is it space?
	jnz	stat51		;If not say so.
	lxi	d,pspcst	;Say space.
	jmp	stat55
stat51: cpi	parodd		;Is it odd?
	jnz	stat52		;If not say so.
	lxi	d,poddst	;Say odd.
	jmp	stat55
stat52: cpi	parevn		;Is it even?
	jnz	stat55		;If not say so.
	lxi	d,pevnst	;Say even.
stat55: call	prtstr

;Print out current BLOCK-CHECK-TYPE

	lxi	d,bckst 	;Get the string
	call	prtstr		;Print "Block check type: "
	lda	chktyp		;Get the type (character 1, 2, or 3)
	mov	e,a		;Put into E
	mvi	c,conout	;Want to print it
	call	BDOS		;Do so
	lxi	d,bckst1	;Get rest of text ("-character")
	call	prtstr		;.  .  .

;Print the current escape character

	lxi	d,escst 	;Escape string.
	call	prtstr
	call	escpr		;Print the escape char.
	lxi	d,crlf		;Get the address of a crlf.
	call	prtstr

;[ah] For ELZET it's two bytes encoded in one
	lxi	d,spdst		;Tell speed if it's set
	call	prtstr
	lda	speed		;Get current speed.
	lxi	h,spdust	;Assume undefined.
	cpi	0FFH		;Is it?
	jz	stat73		;Yes.
	lxi	h,spdtab+1	;Start scanning keyword table.
stat70: mov	b,m		;Get string length.
	inr	b		;Account for $.
	inx	h
	shld	temp1		;Save string pointer.
stat71: inx	h		;Loop over string.
	dcr	b
	jnz	stat71
	mov	c,m		;Get speed value
	cmp	c		;Match?
	jz	stat72		;Yes.
	inx	h		;Bump to next keyword.
	inx	h
	jmp	stat70
stat72: lhld	temp1		;Restore saved string pointer.
stat73: xchg			;Set into DE for display.
	call	prtstr
	lxi	d,crlf		;Terminate.
	call	prtstr

	lxi	d,timmsg	;[jd]
	call	prtstr		;[jd]
	lxi	d,onstr 	;[jd] assume timer on
	lda	timflg
	ora	a
	jnz	stat74		;[jd] is on, keep going
	lxi	d,offstr
stat74: call	prtstr
	lxi	d,crlf
	call	prtstr

	ret


;Display the directory for the requested drive
;
;	Note: This is abstracted from Keith Peterson's DIRF.ASM
;		directory print function.  Thank's again Keith.
;
;
dir:	lxi	d,fcb		;Where to put the data, if any.
	mvi	a,cmifin
	call	comnd		;Plse a full or piece of file-spec
	 jmp	dir2		;Didn't get a FULL file-spec
	jmp	dir4		;lets do it
;
;
;Make FCB all '?' to match any file
dir2:	lda	fcb
	cpi	' '		;CMIFIN leaves that as ' '
	jnz	dir2a		;he typed at least x:
	xra	a
	sta	fcb		;default drive
dir2a:	lxi	h,fcb+1
	mvi	b,11		;FN+FT count.

dir3:	mvi	m,'?'		;Store '?'s in FCB.
	inx	h
	dcr	b
	jnz	dir3
;Print signon message and drive name
dir4:	lda	fcb
	cpi	0		;default?
	jnz	dir4a
	lda	curdsk		;get default
dir4a:	adi	'A'-1		;Asciize it
	sta	dnam14		;Save it in message.
	lxi	d,crlf
	call	prtstr
	lxi	d,inms14	;Point to message
	call	prtstr
;
;Initialize number of names per line counter
	mvi	a,npl		;Nr. names per line.
	sta	nnams		;Init counter.
;
	call	dir26		;Get disk parameters
dir5:	call	mfname		;get some names
	jnc	dir6		;got one
	jmp	dir17		;got none - do summary
;
dir6:				;Check for console break
	mvi	c,consta	;Ck status of kbd.
	call	bdos
	ora	a		;Any key pressed?
	jz	dir6a		;nope, keep going
	mvi	c,conin
	call	bdos		;gobble key
	jmp	dir17		;and print summary only
;
;Print an entry
dir6a:	lxi	h,fcb+1 	;point to Filename
	mvi	b,8		;File name length.
	call	dir11		;Type filename.
	mvi	a,'.'		;Period after FN.
	call	dir10
	mvi	b,3		;Get the filetype.
	call	dir11
	call	dir25		;print size
	lxi	h,nnams 	;Point to names counter.
	dcr	m		;One less on this line.
	push	psw
	cnz	dir7		;No cr-lf needed, do fence.
	pop	psw
	cz	dir12		;Cr-lf needed.
	jmp	dir5
;
;Print	space, fence character, then   space
dir7:	call	dir9
	mvi	a,':'		;Fence character.
	call	dir10
	jmp	dir9
;
;Print two spaces
dir8:	call	dir9
;
;Print one space
dir9:	mvi	a,' '
;
;Type char in A register
dir10:	push	b
	push	d
	push	h
	mov	e,a		;Char to E for CP/M.
	mvi	c,conout	;Write char to console function.
	call	bdos
	pop	h
	pop	d
	pop	b
	ret
;
;Type (B) characters from memory (HL)
dir11:	mov	a,m
	ani	7FH		;Remove CP/M 2.x attributes.
	call	dir10
	inx	h
	dcr	b
	jnz	dir11
	ret
;
;CR-LF routine. HL=NNAMS upon entry
dir12:	mvi	a,CR		;CR.
	call	dir10
	mvi	a,LF		;LF.
	call	dir10
	mvi	m,npl		;Number of names per line.
	ret
;
;	Error exit
dir13:	pop	d		;Get msg.
	call	prtstr
;
;Fall into EXIT
;
;Exit - All done, return via jmp (as for all main commands)
dir16:	lxi	d,crlf
	call	prtstr
	lda	curdsk
	dcr	a		;relative to 0
	mov	e,a
	mvi	c,logdsk
	call	bdos		;back to "logged in" disk
	jmp	kermit		;...and return to kermit.
;
;
;Determines free space remaining
;
dir17:	xra	a
	sta	mfflg1		;clean up MFNAME
	sta	mfflg2
	lda	fcb
	ora	a
	jz	dir18
	dcr	a
	mov	e,a
	mvi	c,logdsk
	call	bdos
dir18:	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
	jz	dir23		;Skip shifts if 1K blocks
dir22:	dad	h		;Multiply blocks by 'K per Block'
	dcr	a
	jnz	dir22
dir23:
	push	h
	lxi	d,inms15	;"Drive "
	call	prtstr
	lda	fcb		;If no drive, get
	ora	a		;logged in drive
	jnz	dir24
	mvi	c,rddrv
	call	bdos
	inr	a
dir24:	adi	'A'-1
	sta	inms16
	lxi	d,inms16	;" has "
	call	Prtstr
	pop	h		;Get number of bytes available
	call	nout
	lxi	d,inms17	;" K bytes free"
	call	prtstr
	jmp	dir16		;all done

;Compute the size of the file

dir25:	mvi	c,cflsz 	;get file-size
	lxi	d,fcb
	call	bdos
	lda	fcbrno		;shift least sign. part
	mov	l,a
	ani	7
	jz	dir250
	adi	8
dir250: add	l
	rrc
	rrc
	rrc
	ani	1fH		;remove crud
	mov	l,a
	mvi	d,0
	lda	fcbrno+1	;shift most sign. part
	rrc
	jnc	dir25a
	mvi	e,20H
	dad	d
	ani	7FH
dir25a: rrc
	jnc	dir25b
	mvi	e,40H
	dad	d
	ani	7FH
dir25b: rrc
	jnc	dir25c
	mvi	e,80H
	dad	d
	ani	7FH
dir25c: mov	h,a
;	LDA	bmask		;Get SECTORS/BLK-1
;	RRC
;	RRC			;Convert to K/BLK
;	RRC
;	ANI	1FH
;	CMA			;Use to finish rounding
;	ANA	L
;	MOV	L,A
	mov	a,l
	cpi	10
	jp	dir25d
	call	dir8
	jmp	dir25e
dir25d: cpi	100
	jp	dir25e
	call	dir9
dir25e: call	dir9		;a space
	CALL	nout		;..go print it
	MVI	A,'k'		;..and follow with K size
	CALL	dir10
	ret

dir26:	mvi	c,gtdpar	;current DISK PARAMETER BLOCK
	call	bdos
	inx	h
	inx	h
	mov	a,m		;Get Block Shift Factor
	sta	bshiftf
	inx	h		;Bump to Block Mask
	mov	a,m		;get it
	sta	bmask
	inx	h
	inx	h
	mov	e,m		;Get Max Block number
	inx	h
	mov	d,m
	xchg
	shld	bmax		;Put it away
	ret

;ERAse a CP/M file

era:	mvi	a,cmifi 	;Parse a file-spec
	lxi	d,fcb		;into FCB
	call	comnd
	 jmp	kermit		;bad parse
	lxi	d,fcb
	mvi	c,sfirst	;check if valid
	call	bdos
	inr	a		;0 if FILE not found
	jnz	era1		;found at least one
	lxi	d,erms15	;"unable to find file"
	call	prtstr
	jmp	kermit
era1:	lxi	d,fcb
	mvi	c,delf
	call	bdos
	lxi	d,inms18	;" File(s) erased"
	call	prtstr
	jmp	kermit

;Print the escape char.

escpr:	lda	escchr		;Get the escape char.
	cpi	' '		;Is it a control char?
	jp	escpr2
	lxi	d,inms10	;Output Control-.
	call	prtstr
	lda	escchr
	ori	100O		;De-controlify.
escpr2: mvi	c,conout	;Output the char
	mov	e,a
	call	bdos
	ret

;************************System Dependent****************************

prtout: in	mnprts		;Get the output ready flag.
	ani	output		;Is it set?
	jz	prtout		;If so, loop until it isn't.
	mov	a,e		;Get the char to output.
prtou2: out	mnport		;Output it.
	ret


;	Utility routines

;Jumping to this location is like retskp.  It assumes the instruction
;after the call is a jmp addr.

rskp:	pop	h		;Get the return address.
	inx	h		;Increment by three.
	inx	h
	inx	h
	pchl

;Jumping here is the same as a ret.

r:	ret

;This routine used to compare packet-Nr
compp:	lda	pktnum		;Get the packet Nr.
	mov	b,a
	lda	argblk
	cmp	b
	ret

;This routine up's the packet Nr. modulo 64
countp: inr	a		;Increment packet Nr.
	ani	3FH		;Turn off the two high order bits
	sta	pktnum		;Save modulo 64 of number
	lhld	numpkt
	inx	h		;Increment Nr. of packets
	shld	numpkt
	ret

;This routine sends an ACK-packet
ackp:	xra	a
	sta	numtry		;Reset number of retries
	sta	argblk+1	;No data. (The packet number is in argblk)
	mvi	a,'Y'		;Acknowledge packet
	call	spack		;Send packet
	 jmp	abort
	ret

tryagn: inr	a		;Increment it.
	sta	oldtry		;Save the updated number of tries.
	lda	pktnum		;Get the present packet number.
	dcr	a		;Decrement.
	mov	b,a
	lda	argblk		;Get the packet's number
	cmp	b		;Is the packet's number one less than now?
	jnz	nak0		;No, NAK it and try again.
	call	updrtr		;Update the number of retries.
	call	ackp
	ret

;This routine fetches keyword
keycmd: mvi	a,cmkey
	call	comnd
	 jmp	kermt2		;"Unrecognized command"
	ret

;This routine fetches confirm
cfmcmd: mvi	a,cmcfm
	call	comnd
	 jmp	kermt3		;"Not confirmed"
	ret


;This routine prints the number in HL on the screen in decimal.
;Saves all ACs.

nout:	push	psw		;Save our ACs.
	push	b
	push	d
	push	h
	lxi	b,-10		;Get some useful constants.
	lxi	d,-1

nout2:	dad	b		;Subtract as many 10s as possible.
	inx	d		;Count them.
	jc	nout2		;If some left keep going.

	lxi	b,10		;Restore the last 10 we took away.
	dad	b
	xchg			;Swap the remainder and the quotient.
	mov	a,h		;Get the number of 10s found.
	ora	l		;* I think this checks if h equals zero.  If
				;* so, this should just be a CPI 0 for clarity.
	cnz	nout		;If non zero, recurse.
	mov	a,e		;Get the remainder.
	adi	'0'		;Make the number printable.
	mov	e,a		;Output the digit.
	mvi	c,conout
	call	bdos

	pop	h		;Restore the ACs.
	pop	d
	pop	b
	pop	psw
	ret

;	This set of routines provides a user oriented way of parsing
;	commands.  It is similar to that of the COMND JSYS in TOPS-20.


;	This routine prints the prompt in DE and specifies the reparse
;	address.

prompt: pop	h		;Get the return address.
	push	h		;Put it on the stack again.
	shld	cmrprs		;Save it as the address to go to on reparse.
	lxi	h,0		;Clear out hl pair.
	dad	sp		;Get the present stack pointer.
	shld	cmostp		;Save for later restoral.
	xchg			;Save the pointer to the prompt.
	shld	cmprmp
	xchg
	lxi	h,cmdbuf
	shld	cmcptr		;Initialize the command pointer.
	shld	cmdptr
	xra	a
	sta	cmaflg		;Zero the flags.
	sta	cmccnt
	mvi	a,0FFH		;Try it this way (Daphne.)
	sta	cmsflg
	lxi	d,cmcrlf
	call	prtstr
	lhld	cmprmp		;Print the prompt.
	xchg
	call	prtstr
	ret

;	This address is jumped to on reparse.

repars: lhld	cmostp		;Get the old stack pointer.
	sphl			;Make it the present one.
	lxi	h,cmdbuf
	shld	cmdptr
	mvi	a,0FFH		;Try it this way (Daphne.)
	sta	cmsflg
	lhld	cmrprs		;Get the reparse address.
	pchl			;Go there.

;	This address can be jumped to on a parsing error.

prserr: lhld	cmostp		;Get the old stack pointer.
	sphl			;Make it the present one.
	lxi	h,cmdbuf
	shld	cmcptr		;Initialize the command pointer.
	shld	cmdptr
	xra	a
	sta	cmaflg		;Zero the flags.
	sta	cmccnt
	mvi	a,0FFH		;Try it this way (Daphne.)
	sta	cmsflg
	lxi	d,cmcrlf
	call	prtstr
	lhld	cmprmp		;Get the prompt.
	xchg
	call	prtstr
;* Instead return to before the prompt call.
	lhld	cmrprs
	pchl

;	This routine parses the specified function in A.  Any additional
;	information is in DE and HL.
;	Returns +1 on success
;		+4 on failure (assumes a JMP follows the call)

comnd:	sta	cmstat		;Save what we are presently parsing.
	call	cminbf		;Get chars until an action or a erase char.
	cpi	cmcfm		;Parse a confirm?
	jz	cmcfrm		;Go get one.
	cpi	cmkey		;Parse a keyword?
	jz	cmkeyw		;Try and get one.
	cpi	cmifi		;Parse an input file spec?
	jz	cmifil		;Go get one.
	cpi	cmifin		;Input file-spec silent?
	jz	 cmifil 	;do as he wishes
	cpi	cmofi		;Output file spec?
	jz	cmofil		;Go get one.
	cpi	cmtxt		;Parse arbitrary text?
	jz	cmtext		;Go do it.
	lxi	d,cmer00	;"?Unrecognized COMND call"
	call	prtstr
	ret

;	This routine parses arbitrary text up to a CR.
;	Accepts DE:	address to put text
;	Returns in A:	number of chars in text (may be 0)
;		  DE:	updated pointer

cmtext: xchg			;Put the pointer to the dest in HL.
	shld	cmptab		;Save the pointer.
	mvi	b,0		;Init the char count
cmtxt1: call	cmgtch		;Get a char.
	ora	a		;Terminator?
	jp	cmtxt5		;No, put in user space.
	ani	7FH		;Turn off minus bit.
	cpi	esc		;An escape?
	jnz	cmtxt2		;No.
	mvi	c,conout
	mvi	e,bell		;Get a bell.
	call	bdos
	xra	a
	sta	cmaflg		;Turn off the action flag.
	lhld	cmcptr		;Move the pointer to before the escape.
	dcx	h
	shld	cmcptr
	shld	cmdptr
	lxi	h,cmccnt	;Get the char count.
	dcr	m		;Decrement it by one.
	jmp	cmtxt1		;Try again.

cmtxt2: cpi	'?'		;Is it a question mark?
	jz	cmtxt3		;If so put it in the text.
	cpi	ff		;Is it a formfeed?
	cz	cmblnk		;If so blank the screen.
	mov	a,b		;Return the count.
	lhld	cmptab		;Return updated pointer in HL.
	xchg
	jmp	rskp		;Return success.

cmtxt3: lxi	h,cmaflg	;Point to the action flag.
	mvi	m,0		;Set it to zero.
cmtxt5: inr	b		;Increment the count.
	lhld	cmptab		;Get the pointer.
	mov	m,a		;Put the char in the array.
	inx	h
	shld	cmptab		;Save the updated pointer.
	jmp	cmtxt1		;Get another char.


;This routine gets a confirm.

cmcfrm: call	cmgtch		;Get a char.
	ora	a		;Is it negative (a terminator;a space or
				;a tab will not be returned here as they
				;will be seen as leading white space.)
	rp			;If not, return failure.
	ani	7FH		;Turn off the minus bit.
	cpi	esc		;Is it an escape?
	jnz	cmcfr2
	mvi	c,conout
	mvi	e,bell		;Get a bell.
	call	bdos
	xra	a
	sta	cmaflg		;Turn off the action flag.
	lhld	cmcptr		;Move the pointer to before the escape.
	dcx	h
	shld	cmcptr
	shld	cmdptr
	lxi	h,cmccnt	;Get the char count.
	dcr	m		;Decrement it by one.
	jmp	cmcfrm		;Try again.
cmcfr2: cpi	'?'		;Curious?
	jnz	cmcfr3
	lxi	d,cmin00	;Print something useful.
	call	prtstr
	lxi	d,cmcrlf	;Print a crlf.


	call	prtstr
	lhld	cmprmp		;Reprint the prompt.
	xchg
	call	prtstr
	lhld	cmdptr		;Get the pointer into the buffer.
	mvi	a,'$'		;Put a $ there for printing.
	mov	m,a
	lhld	cmcptr
	dcx	h		;Decrement and save the buffer pointer.
	shld	cmcptr
	lxi	d,cmdbuf
	call	prtstr
	xra	a		;Turn off the action flag.
	sta	cmaflg
	jmp	repars		;Reparse everything.

cmcfr3: cpi	ff		;Is it a form feed?
	cz	cmblnk		;If so blank the screen.
	jmp	rskp

;	This routine parses a keyword from the table pointed
;	to in DE.  The format of the table is as follows:
;
;	addr:	db	n	;Where n is the # of entries in the table.
;		db	m	;M is the size of the keyword.
;		db	'string$' ;Where string is the keyword.
;		db	a,b	;Where a & b are pieces of data
;				;to be returned.  (Must be two of them.)
;
;	The keywords must be in alphabetical order.
;**** Note:  The data value a is returned in registers A and E.  The
;****	data value b is returned in register D.  This allows the two data
;	bytes to be stored as:
;		dw	xxx
;	and result in a correctly formatted 16-bit value in register pair
;	DE.

cmkeyw: shld	cmhlp		;Save the help.
	xchg			;Get the address of the table.
	shld	cmptab		;Save the beginning of keyword tab for '?'.
	mov	b,m		;Get the number of entries in the table.
	inx	h
	shld	cmkptr
	lhld	cmdptr		;Save the command pointer.
	shld	cmsptr
cmkey2: mov	a,b		;Get the number of entries left.
	ora	a		;Any left?
	rz			;If not we failed.
	lhld	cmkptr
	mov	e,m		;Get the length of the keyword.
	inx	h
cmkey3: dcr	e		;Decrement the number of chars left.
	mov	a,e
	cpi	0FFH		;Have we passed the end?
	jm	cmkey5		;If so go to the next.
	call	cmgtch		;Get a char.
	ora	a		;Is it a terminater?
	jp	cmkey4		;If positive, it is not.
	ani	7FH		;Turn off the minus bit.
	cpi	'?'
	jnz	cmky31
	xra	a
	sta	cmaflg		;Turn off the action flag.
	lxi	h,cmccnt	;Decrement the char count.
	dcr	m
;* Must go through the keyword table and print them.
	lhld	cmhlp		;For now print the help text.
	xchg
	call	prtstr
	lxi	d,cmcrlf	;Print a crlf.
	call	prtstr
	lhld	cmprmp		;Reprint the prompt.
	xchg
	call	prtstr
	lhld	cmdptr		;Get the pointer into the buffer.
	mvi	a,'$'		;Put a $ there for printing.
	mov	m,a
	lhld	cmcptr
	dcx	h		;Decrement and save the buffer pointer.
	shld	cmcptr
	lxi	d,cmdbuf
	call	prtstr
	jmp	repars		;Reparse everything.

cmky31: cpi	esc		;Is it an escape?
	jnz	cmky35
	xra	a
	sta	cmaflg		;Turn off the action flag.
	push	d
	push	b
	push	h
	call	cmambg
	 jmp	cmky32		;Not ambiguous.
	mvi	c,conout
	mvi	e,bell
	call	bdos		;Ring the bell.
	lhld	cmcptr		;Move the pointer to before the escape.
	dcx	h
	shld	cmcptr
	shld	cmdptr
	lxi	h,cmccnt	;Get the char count.
	dcr	m		;Decrement it by one.
	pop	h
	pop	b
	pop	d
	inr	e		;Increment the left to parse char count.
	jmp	cmkey3
cmky32: lhld	cmcptr		;Pointer into buffer.
	dcx	h		;Backup to the escape.
	xchg
	pop	h
	push	h
cmky33: mov	a,m		;Get the next char.
	cpi	'$'		;Finished?
	jz	cmky34
	inx	h
	xchg
	mov	m,a		;Move it into the buffer.
	inx	h
	xchg
	lda	cmccnt		;Increment the char count.
	inr	a
	sta	cmccnt
	jmp	cmky33
cmky34: lda	cmccnt		;Get the character count.
	inr	a		;Increment and save it.
	sta	cmccnt
	xchg			;Put the command buffer pointer in HL.
	mvi	a,' '		;Get a blank.
	mov	m,a		;Put it in the command buffer.
	inx	h		;Increment the pointer
	shld	cmcptr		;Save the updated pointer.
	shld	cmdptr
	pop	h
	push	h
	xchg
	call	prtstr		;Print the rest of the keyword.
	mvi	c,conout
	mvi	e,' '
	call	bdos		;Print a blank.
	pop	h
	pop	b
	pop	d
	jmp	cmky37
cmky35: push	h
	push	d
	call	cmambg
	 jmp	cmky36
	lxi	d,cmer01
	call	prtstr		;Say its ambiguous.
	jmp	prserr		;Give up.
cmky36: pop	d
	pop	h
cmky37: inr	e		;Add one incase it is negative.
	mvi	d,0
	dad	d		;Increment past the keyword.
	inx	h		;Past the $.
	mov	e,m		;Get the data.
	inx	h
	mov	d,m
	mov	a,e
	jmp	rskp
cmkey4: cpi	'a'		;Is it less than	a?
	jm	cmky41		;If so don't capitalize it.
	cpi	'z'+1		;Is it more than z?
	jp	cmky41		;If so don't capitalize it.
	ani	137O		;Capitalize it.
cmky41: mov	d,m		;Get the next char of the keyword.
	inx	h
	cmp	d		;Match?
	jz	cmkey3		;If so get the next letter.

cmkey5: mvi	d,0
	mov	a,e		;Get the number of chars left.
	ora	a		;Is it negative?
	jp	cmky51
	mvi	d,0FFH		;If so, sign extend.
cmky51: dad	d		;Increment past the keyword.
	lxi	d,0003H 	;Plus the $ and data.
	dad	d
	shld	cmkptr
	dcr	b		;Decrement the number of entries left.
	lhld	cmsptr		;Get the old	cmdptr.
	shld	cmdptr		;Restore it.
;* check so we don't pass it.
	jmp	cmkey2		;Go check the next keyword.

cmambg: dcr	b		;Decrement the number of entries left.
	rm			;If none left then it is not ambiguous.
	inr	e		;This is off by one;adjust.
	mov	c,e		;Save the char count.
	mov	a,e
	ora	a		;Any chars left?
	rz			;No, it can't be ambiguous.
	mvi	d,0
	dad	d		;Increment past the keyword.
	mvi	e,3		;Plus the $ and data.
	dad	d
	mov	b,m		;Get the length of the keyword.
	inx	h
	xchg
	lhld	cmkptr		;Get pointer to keyword entry.
	mov	a,m		;Get the length of the keyword.
	sub	c		;Subtract how many left.
	mov	c,a		;Save the count.
	cmp	b
	jz	cmamb0
	rp			;If larger than the new word then not amb.
cmamb0: lhld	cmsptr		;Get the pointer to what parsed.
cmamb1: dcr	c		;Decrement the count.
	jm	rskp		;If we are done then it is ambiguous.
	xchg			;Exchange the pointers.
	mov	b,m		;Get the next char of the keyword
	inx	h
	xchg			;Exchange the pointers.
	mov	a,m		;Get the next parsed char.
	inx	h
	cpi	'a'		;Is it less than a?
	jm	cmamb2		;If so don't capitalize it.
	cpi	'z'+1		;Is it more than z?
	jp	cmamb2		;If so don't capitalize it.
	ani	137O
cmamb2: cmp	b		;Are they equal?
	rnz			;If not then its not ambiguous.
	jmp	cmamb1		;Check the next char.

cmifil: sta	cmfwld		;Set wildcard flag
	xchg			;Get the fcb address.
	shld	cmfcb		;Save it.
	mvi	e,0		;Initialize char count.
	mvi	m,0		;Set the drive to default to current.
	inx	h
	shld	cmfcb2
	xra	a		;Initialize counter.
cmifi0: mvi	m,' '		;Blank the FCB.
	inx	h
	inr	a
	cpi	0CH		;Twelve?
	jm	cmifi0
cmifi1: call	cmgtch		;Get another char.
	ora	a		;Is it an action character.
	jp	cmifi2
	ani	7FH		;Turn off the action bit.
	cpi	'?'		;A question mark?
	jnz	cmif12
	lxi	h,cmaflg	;Blank the action flag.
	mvi	m,0
	lhld	cmcptr		;Increment the buffer pointer.
	inx	h		;(Gets decremented in 'cmgtch')
	shld	cmcptr
	lhld	cmdptr		;[jd] this is actually what is decremented
	inx	h		;[jd]
	shld	cmdptr		;[jd]
	jmp	cmifi8		;Treat like any other character.
cmif12: cpi	esc		;An escape?
	jnz	cmif13
;Try to recognize file-spec a'la TOPS-20
	xra	a
	sta	cmaflg		;Turn off the action flag.
	lhld	cmcptr		;Move the pointer to before the escape.
	dcx	h
	shld	cmcptr
	shld	cmdptr
	lxi	h,cmccnt	;Get the char count.
	dcr	m		;Decrement it by one.
	mov	a,e		;Save character count up to now.
	sta	temp1
	cpi	9		;Past '.'?
	jm	cmfrec		;No.
	dcr	a		;Yes, don't count point.
cmfrec: lhld	cmfcb2		;Fill the rest with CP/M wildcards.
cmfrc1: cpi	11		;Done?
	jp	cmfrc2		;Yes.
	mvi	m,'?'
	inx	h
	inr	a
	jmp	cmfrc1
cmfrc2: mvi	c,sfirst	;Find first matching file?
	lhld	cmfcb
	xchg
	call	bdos
	cpi	0FFH
	jz	cmfrc9		;No, lose.
	lxi	h,fcbblk	;Copy first file spec.
	call	fspcop
	lxi	h,fcbblk+10H	;Get another copy (in case not ambiguous).
	call	fspcop
	mvi	c,snext 	;More matching specs?
	lhld	cmfcb
	xchg
	call	bdos
	cpi	0FFH
	jz	cmfrc3		;Only one.
	lxi	h,fcbblk+10H	;Copy second file spec.
	call	fspcop
cmfrc3: lxi	d,fcbblk	;Start comparing file names.
	lxi	h,fcbblk+10H
	lda	temp1		;Bypass characters typed.
	cpi	9		;Past '.'?
	jm	cmfrc4		;No.
	dcr	a		;Yes, don't count point.
cmfrc4: mvi	c,0
cmfrl1: cmp	c		;Bypassed?
	jz	cmfrl2		;Yes.
	inx	d
	inx	h
	inr	c
	jmp	cmfrl1		;Repeat.
cmfrl2: mov	a,c		;Get file name characters processed.
	cpi	11		;All done?
	jz	cmfrc5		;Yes.
	cpi	8		;End of file name?
	jnz	cmfrl3		;No.
	lda	temp1		;Exactly at point?
	cpi	9
	jz	cmfrl3		;Yes, don't output a second point.
	mvi	a,'.'		;Output separator.
	call	cmfput
cmfrl3: ldax	d		;Get a character from first file spec.
	inx	d
	mov	b,m		;Get from second file spec.
	inx	h
	cmp	b		;Compare.
	jnz	cmfrc5		;Ambiguous.
	inr	c		;Same, count.
	cpi	' '		;Blank?
	jz	cmfrl2		;Yes, don't output.
	call	cmfput		;Put character into buffer.
	jmp	cmfrl2		;Repeat.

cmfrc5: mov	a,c		;Get count of characters processed.
	sta	temp1		;Save it.
	mvi	a,'$'		;Get terminator.
	call	cmfput		;Put it into buffer.
	lhld	cmdptr		;Output recognized characters.
	xchg
	mvi	c,prstr
	call	bdos
	lhld	cmcptr		;Remove terminator from buffer.
	dcx	h
	shld	cmcptr
	lxi	h,cmccnt
	dcr	m
	lda	temp1		;Characters processed.
	cpi	11		;Complete file name.
	jz	repars		;Yes, don't beep.

cmfrc9: mvi c,conout
	mvi e,bell
	call bdos		;Ring the bell.
	jmp repars

;	Continue file spec parsing.

cmif13: mov a,e 		;It must be a terminator.
	cpi 0			;Test the length of the file name.
	jz cmifi9		;If zero complain.
	cpi	0DH
	jp	cmifi9		;If too long complain.
	jmp	rskp		;Otherwise we have succeeded.
cmifi2: cpi	'.'
	jnz	cmifi3
	inr	e
	mov	a,e
	cpi	1H		;Any chars yet?
	jz	cmifi9		;No, give error.
	cpi	0AH		;Tenth char?
	jp	cmifi9		;Past it, give an error.
	mvi	c,9H
	mvi	b,0
	lhld	cmfcb
	dad	b		;Point to file type field.
	shld	cmfcb2
	mvi	e,9H		;Say we've gotten nine.
	jmp	cmifi1		;Get the next char.
cmifi3: cpi	':'
	jnz	cmifi4
	inr	e
	mov	a,e
	cpi	2H		;Is it in the right place for a drive?
	jnz	cmifi9		;If not, complain.
	lhld	cmfcb2
	dcx	h		;Point to previous character.
	mov	a,m		;Get the drive name.
	sui	'@'		;Get the drive number.
	shld	cmfcb2		;Save pointer to beginning of name field.
	dcx	h		;Point to drive number.
	mov	m,a		;Put it in the fcb.
	mvi	e,0		;Start character count over.
	jmp	cmifi1
cmifi4: cpi	'*'
	jnz	cmifi7
	lda	cmfwld		;Wildcards allowed?
	cpi	0
	jz	cmif11		;No,complain
	mov	a,e
	cpi	8H		;Is this in the name or type field?
	jz	cmifi9		;If its where the dot should be give up.
	jp	cmifi5		;Type.
	mvi	b,8H		;Eight chars.
	jmp	cmifi6
cmifi5: mvi	b,0CH		;Three chars.
cmifi6: lhld	cmfcb2		;Get a pointer into the FCB.
	mvi	a,'?'
	mov	m,a		;Put a question mark in.
	inx	h
	shld	cmfcb2
	inr	e
	mov	a,e
	cmp	b
	jm	cmifi6		;Go fill in another.
	jmp	cmifi1		;Get the next char.
cmifi7: cpi	'0'
	jm	cmifi9
	cpi	'z'+1
	jp	cmifi9
	cpi	'A'		;Don't capitalize non-alphabetics.
	jm	cmifi8
	ani	137O		;Capitalize.
cmifi8: lhld	cmfcb2		;Get the pointer into the FCB.
	mov	m,a		;Put the char there.
	inx	h
	shld	cmfcb2
	inr	e
	jmp	cmifi1

cmifi9: lda	cmstat
	cpi	cmifin		;"silent"?
	jz	r		;Yes,let him go w/o check
	lxi	d,cmer02
cmif10: mvi	c,prstr
	call	bdos
	ret

cmif11: lxi	d,cmer03	;Complain about wildcards.
	jmp	cmif10

cmofil: mvi	a,0		;Don't allow wildcards.
	jmp	cmifil		;For now, the same as CMIFI.

fspcop: push	psw		;Save A.
	lxi	d,buff		;Get the right offset in the buffer.
	rlc
	rlc
	rlc
	rlc
	rlc
	add	e
	adi	1		;Bypass drive spec.
	mov	e,a
	mvi	b,11		;Copy file name.
fspcp1: ldax	d
	inx	d
	mov	m,a
	inx	h
	dcr	b
	jnz	fspcp1
	pop	psw		;Restore A.
	ret

cmfput: push	h		;Save H.
	lhld	cmcptr		;Get buffer pointer.
	mov	m,a		;Store in buffer.
	inx	h
	shld	cmcptr
	lxi	h,cmccnt	;Count it.
	inr	m
	pop	h		;Restore H.
	ret

cminbf: push	psw
	push	d
	push	h
	lda	cmaflg		;Is the action char flag set?
	ora	a
	jnz	cminb9		;If so get no more chars.
cminb1: lxi	h,cmccnt	;Increment the char count.
	inr	m
	mvi	c,conin 	;Get a char.
	call	bdos
	lhld	cmcptr		;Get the pointer into the buffer.
	mov	m,a		;Put it in the buffer.
	inx	h
	shld	cmcptr
	cpi	25O		;Is it a ^U?
	jz	cmnb12		;Yes.
	cpi	30O		;Is it a ^X?
	jnz	cminb2
cmnb12: lxi	d,clrlin	;Clear the line.
	call	prtstr
	mvi	c,prstr
	lhld	cmprmp		;Print the prompt.
	xchg
	call	bdos
	lxi	h,cmdbuf
	shld	cmcptr		;Reset the point to the start.
	lxi	h,cmccnt	;Zero the count.
	mvi	m,0
	jmp	repars		;Go start over.
cminb2: cpi	10O		;Or backspace?
	jz	cminb3
	cpi	del		;Delete?
	jnz	cminb4
	lxi	d,delstr	;Print the delete string.
	call	prtstr

cminb3: lda	cmccnt		;Decrement the char count by	two.
	dcr	a
	dcr	a
	ora	a		;Have we gone too far?
	jp	cmnb32		;If not proceed.
	mvi	c,conout	;Ring the bell.
	mvi	e,bell
	call	bdos
	jmp	cmnb12		;Go reprint prompt and reparse.
cmnb32: sta	cmccnt		;Save the new char count.
	lxi	d,clrspc	;Erase the character.
	call	prtstr
	lhld	cmcptr		;Get the pointer into the buffer.
	dcx	h		;Back up in the buffer.
	dcx	h
	shld	cmcptr
	jmp	repars		;Go reparse everything.
cminb4: cpi	'?'		;Is it a question mark.
	jz	cminb6
	cpi	esc		;Is it an escape?
	jz	cminb6
	cpi	cr		;Is it a carriage return?
	jz	cminb5
	cpi	lf		;Is it a line feed?
	jz	cminb5
	cpi	ff		;Is it a formfeed?
	jnz	cminb7
	call	cmblnk
cminb5: lda	cmccnt		;Have we parsed any chars yet?
	cpi	1
	jz	prserr		;If not, just start over.
cminb6: mvi	a,0FFH		;Set the action flag.
	sta	cmaflg
	jmp	cminb9
cminb7: cpi	' '
	jz	cminb1		;Get another char.
	cpi	tab
	jz	cminb1		;Get another char.
	jmp	cminb1		;Get another.

cminb9: pop	h
	pop	d
	pop	psw
	ret

cmgtch: push	h
	push	b
cmgtc1: lda	cmaflg
	ora	a		;Is it set.
	cz	cminbf		;If the action char flag is not set get more.
	lhld	cmdptr		;Get a pointer into the buffer.
	mov	a,m		;Get the next char.
	inx	h
	shld	cmdptr
	cpi	' '		;Is it a space?
	jz	cmgtc2
	cpi	tab		;Or a tab?
	jnz	cmgtc3
cmgtc2: lda	cmsflg		;Get the space flag.
	ora	a		;Was the last char a space?
	jnz	cmgtc1		;Yes, get another char.
	mvi	a,0FFH		;Set the space flag.
	sta	cmsflg
	mvi	a,' '
	pop	b
	pop	h
	jmp	cmgtc5
cmgtc3: push	psw
	xra	a
	sta	cmsflg		;Zero the space flag.
	pop	psw
	pop	b
	pop	h
	cpi	esc
	jz	cmgtc5
	cpi	'?'		;Is the user curious?
	jz	cmgtc4
	cpi	cr
	jz	cmgtc4
	cpi	lf
	jz	cmgtc4
	cpi	ff
	rnz			;Not an action char, just return.
cmgtc4: push	h
	lhld	cmdptr
	dcx	h
	shld	cmdptr
	pop	h
cmgtc5: ori	80H		;Make the char negative to indicate it is
	ret			;a terminator.

;This routine blanks the screen.

cmblnk: lxi	d,clrtop	;Print the string to blank the screen.
	call	prtstr
	ret

;This routine replaces many, many calls to bdos

prtstr:	mvi	c,prstr
	jmp	bdos		;a CALL flwd by a RET becomes a JMP

	;Pure storage.

outln2: db	cr,lf,'Number of packets:'
	db	cr,lf,'Number of retries:'
	db	cr,lf,'File name:$'
kerm:	db	'Kermit-80  '
kerm1:	db	'x:>$'		;'x' filled in at startup with DRIVE name
delpr:	db	'Delete it? $'
crlf:	db	cr,lf,'$'
ermes1: db	cr,lf,'?Unrecognized command$'
ermes2: db	cr,lf,'?Illegal character$'
ermes3: db	cr,lf,'?Not confirmed$'
ermes4: db	'?Unable to receive initiate',cr,lf,'$'
ermes5: db	'?Unable to receive file name',cr,lf,'$'
ermes6: db	'?Unable to receive end of file',cr,lf,'$'
erms10: db	'?Unable to receive data',cr,lf,'$'
erms11: db	'?Disk full',cr,lf,'$'
erms14: db	'?Unable to receive an acknowledgement from the host',cr,lf,'$'
erms15: db	cr,lf,'?Unable to find file',cr,lf,'$'
erms16: db	'?Unable to rename file$'
erms17: db	cr,lf,'?Disk full$'
erms18: db	cr,lf,'?Unable to tell host that the session is finished$'
erms19: db	cr,lf,'?Unable to tell host to logout$'
infms3: db	bell,'Completed$'
infms4: db	bell,'Failed$'
infms5: db	'%Renaming file to $'
infms6: db	cr,lf,'[Closing the log file]$'
infms7: db	cr,lf,'[Connected to remote host, type $'
infms8: db	'C to return]',cr,lf,'$'
infms9: db	cr,lf,'[Connection closed, back at micro]$'
inms10: db	'Control-$'
inms11: db	' (Type Left Arrow to send CTRL-S)',cr,lf,'$'
inms12: db	' (Not implemented)',cr,lf,'$'
inms13: db	bell,'Interrupted$'
inms14: db	TAB,TAB,'    Directory for drive '
dnam14: db	'x:',cr,lf,'$'		;filled in by dir routine.
inms15: DB	CR,LF,TAB,TAB,'Drive $'
inms16: DB	'  has $'	;filled in by summary code with drive letter
inms17: DB	'K bytes free',CR,LF,'$'
inms18: DB	CR,LF,'File(s) erased$',CR,LF
inms19: db	cr,lf,'[Transmitting file to host:'
	db	cr,lf,' 1. Type any character to send a line.'
	db	cr,lf,' 2. Type RETURN to terminate the line '
	db	'and to get the next line (go back to 1.)'
	db	cr,lf,'    (You may send other characters '
	db	'before RETURN.),'
	db	cr,lf,'   or type $'
inms20: db	'R to send the same line again,'
	db	cr,lf,'   or type $'
inms21: db	'C to abort transmission.]',cr,lf,'$'
inms22: db	cr,lf,'[Transmission done. Connected normally '
	db	'to remote host,'
	db	cr,lf,' type $'
inms23: db	'Sending...$'
inms24: db	'Receiving...$'
inms25: db	bell,'Warning: eighth bit cannot be sent$'


baddrv: DB	CR,LF,'++ Bad drive name$',CR,LF
cfrmes: db	' Confirm with carriage return $'
filhlp: db	' Input file spec (possibly wild) $'
escmes: db	cr,lf,'Type the new escape character:  $'
tophlp: db	cr,lf,'BYE to host (LOGOUT) and exit to CP/M'
	db	cr,lf,'CONNECT to host on selected port'
	db	cr,lf,'ERA a CP/M file'
	db	cr,lf,'EXIT to CP/M'
	db	cr,lf,'FINISH running Kermit on the host'
	db	cr,lf,'HELP by giving this message'
	db	cr,lf,'DIR of current used Micro-disk'
	db	cr,lf,'LOG the terminal session to a file'
	db	cr,lf,'LOGOUT the host'
	db	cr,lf,'RECEIVE file from host'
	db	cr,lf,'SEND file to host'
	db	cr,lf,'SET a parameter'
	db	cr,lf,'SHOW the parameters'
	db	cr,lf,'STATUS of Kermit'
	db	cr,lf,'TRANSMIT file to host (in connect state)$'

sethlp: db	cr,lf,'BAud (rate)'
	db	cr,lf,'BLock-check-type (for error detection)'
	db	cr,lf,'Default-disk (to receive data)'
	db	cr,lf,'Escape (character during CONNECT)'
	db	cr,lf,'File-mode (for outgoing files)'
	db	cr,lf,'Ibm (parity and turn around handling)'
	db	cr,lf,'Local-echo (half-duplex)'
	db	cr,lf,'PArity (for communication line)'
	db	cr,lf,'POrt (to communicate on)'
	db	cr,lf,'PRinter copy ( ON / OFF )'
;*	db	cr,lf,'RECEIVE (parameter)'	;Not currently implemented
;*	db	cr,lf,'SEND (parameter)'	;Ditto
	db	cr,lf,'TIMER ( On / OFF )'
	db	cr,lf,'Vt52-emulation'
	db	cr,lf,'Warning (for filename conflicts)'
	db	'$'

stshlp: db	cr,lf,'PAD-CHAR'
	db	cr,lf,'PADDING$'

blkhlp: db	cr,lf,'1-CHARACTER-CHECKSUM'
	db	cr,lf,'2-CHARACTER-CHECKSUM'
	db	cr,lf,'3-CHARACTER-CRC-CCITT$'

parhlp: db	cr,lf,'EVEN	MARK	NONE	ODD	SPACE$'
onhlp:	db	cr,lf,'OFF	ON$'
yeshlp: db	cr,lf,'NO	YES$'
xmthlp: db	cr,lf,'R Send the same line again$'
inthlp: db	cr,lf,'?  This message'
	db	cr,lf,'C  Close the connection'

	db	cr,lf,'0  (zero) Transmit a NULL'

	db	cr,lf,'S  Status of the connection'
	db	cr,lf,'Typing another $'
inhlp2: db	' will send it to the host'
	db	cr,lf,cr,lf,'Command>$'
onstr:	db	' on$'
offstr: db	' off$'
xmtst:	db	cr,lf,'Transmitting a file$'
locst:	db	cr,lf,'Local echo$'

defstr: db	' default$'
ascstr: db	' ASCII$'
binstr: db	' binary$'
typhlp: db	cr,lf,'ASCII	BINARY	DEFAULT$'

vtemst: db	cr,lf,'VT52 emulation$'

cpmst:	db	cr,lf,'File Mode$'
ibmst:	db	cr,lf,'IBM flag$'
filst:	db	cr,lf,'File warning$'
prst:	db	cr,lf,'Printer copy$'
escst:	db	cr,lf,'Escape char: $'
parst:	db	cr,lf,'Parity: $'
bckst:	db	cr,lf,'Block check type: $'
bckst1: db	'-character$'
pnonst: db	'none$'
pmrkst: db	'mark$'
pspcst: db	'space$'
poddst: db	'odd$'
pevnst: db	'even$'

spdst:	db	'Speed $'
spdust: db	'is indeterminate (not SET)$'

timmsg: db	'Timer$'

spdhlp: db	cr,lf,'  300  600  1200  2400  4800  9600$'

;***************************System Dependent**************************

outlin: db	0CH,esc,'V',tab,tab
versio: db	'Kermit-80 V3.9A [ELZET80]',cr,lf,'$'
delstr: db	08H,'$'				;Delete string.
clrspc: db	' ',10O,'$'			;Clear space.
clrlin: db	cr,esc,'Z$'			;Clear line.
clrtop: db	0CH,esc,'V$'			;Clear screen and go home.
scrnp:	db	esc,'F',20H+02H,20H+15H,'$'	;Place for number of packets.
scrnrt: db	esc,'F',20H+03H,20H+15H,'$'	;Place for number of retries.
scrfln: db	esc,'F',20H+03H,20H+0CH,lf,esc,'Z$'	;Place for file name.
screrr: db	esc,'F',20H+05H,20H+00H,esc,'Z$'	;Place for error messages.
scrst:	db	esc,'F',20H+06H,20H+34H,esc,'Z$'	;Place for status ("Complete").
scrend: db	esc,'F',20H+07H,20H+00H,esc,'Z$'	;Place for prompt.
curldn: db	esc,'F$'			;Cursor lead-in

ttab:					;Table start location.
ta:	db	('K'-40H),'$',0,0	;Cursor up.
tb:	db	('J'-40H),'$',0,0	;Cursor down.
tc:	db	('I'-40H),'$',0,0	;Cursor right.
td:	db	('H'-40H),'$',0,0	;Cursor left.
te:	db	0CH,'$',0,0		;Clear screen.
tf:	db	'$',0,0,0		;No translation (Enter graphics mode)
tg:	db	'$',0,0,0		;No translation (Exit graphics mode)
th:	db	('V'-40H),'$',0,0	;Cursor home.
ti:	db	('K'-40H),'$',0,0	;Reverse linefeed. (= Cursor up)
tj:	db	esc,'[$',0		;Clear to end of screen.
tk:	db	esc,'Z$',0		;Clear to end of line.

	;COMND tables
;
;	Structure of command table:
;
;	1) Number of entries.
;	2) Each entry is arranged as follows:
;		a) length of command in bytes.
;		b) 'name of command and $-sign'
;		c) offset into command table at KERMTB:
;		d) offset into command table at KERMTB:
;
;	---> Note this command table is in alphabetic order.
;

comtab: db	10H			;Number of entries (currently 16.)
	db	03H,'BYE$',21H,21H
	db	07H,'CONNECT$',00H,00H
	db	03H,'DIR$',24H,24H
	db	03H,'ERA$',27H,27H
	db	04H,'EXIT$',03H,03H
	db	06H,'FINISH$',1BH,1BH
	db	03H,'GET$',0CH,0CH	;Same as RECEIVE
	db	04H,'HELP$',06H,06H
	db	03H,'LOG$',09H,09H
	db	06H,'LOGOUT$',1EH,1EH
	db	07H,'RECEIVE$',0CH,0CH
	db	04H,'SEND$',0FH,0FH
	db	03H,'SET$',12H,12H
	db	04H,'SHOW$',15H,15H
	db	06H,'STATUS$',18H,18H
	db	08H,'TRANSMIT$',2AH,2AH

settab: db	13		;[jd] 13 entries
	db	04H,'BAUD$',21H,21H	;Data keys to SETJTB positions.
	db	10H,'BLOCK-CHECK-TYPE$',18H,18H
	db	0CH,'DEFAULT-DISK$',24H,24H
	db	06H,'ESCAPE$',00H,00H
	db	09H,'FILE-MODE$',12H,12H
	db	03H,'IBM$',03H,03H
	db	0AH,'LOCAL-ECHO$',06H,06H
	db	06H,'PARITY$',15H,15H
	db	04H,'PORT$',1EH,1EH
	db	07H,'PRINTER$',27H,27H
;*	db	07H,'RECEIVE$',09H,09H	;Not implemented yet.
;*	db	04H,'SEND$',0CH,0CH	;Ditto
	db	005,'TIMER$',2AH,2AH	;[jd] set timer...
	db	0EH,'VT52-EMULATION$',1BH,1BH
	db	07H,'WARNING$',0FH,0FH

stsntb: db	02H
	db	08H,'PAD-CHAR$',00H,00H
	db	07H,'PADDING$',03H,03H

blktab: db	03H
	db	14H,'1-CHARACTER-CHECKSUM$','1','1'
	db	14H,'2-CHARACTER-CHECKSUM$','2','2'
	db	15H,'3-CHARACTER-CRC-CCITT$','3','3'

partab: db	05H		;Five entries.
	db	04H,'EVEN$',parevn,parevn
	db	04H,'MARK$',parmrk,parmrk
	db	04H,'NONE$',parnon,parnon
	db	03H,'ODD$',parodd,parodd
	db	05H,'SPACE$',parspc,parspc

ontab:	db	02H		;Two entries.
	db	02H,'ON$',01H,01H
	db	03H,'OFF$',00H,00H

typtab: db	03H		;Three entries
	db	05H,'ASCII$',01H,01H
	db	06H,'BINARY$',02H,02H
	db	07H,'DEFAULT$',00H,00H

yestab: db	02H		;Two entries.
	db	02H,'NO$',00H,00H
	db	03H,'YES$',01H,01H

cmer00: db	cr,lf,'?Program error:	Invalid COMND call$'
cmer01: db	cr,lf,'?Ambiguous$'
cmer02: db	cr,lf,'?Illegal CP/M file specification$'
cmer03: db	cr,lf,'?"*" not allowed in file specification$'
cmin00: db	' Confirm with carriage return$'
cmcrlf: db	cr,lf,'$'

spdtab:	db	06H			;6 entries
	db	03H,'300$',0C0H+01H,01H	;Lo byte: Clock mode & PIO-B0 value
	db	03H,'600$',080H+01H,01H	;Hi byte: PIO-B0 value
	db	04H,'1200$',040H+01H,01H
	db	04H,'2400$',0C0H+00H,00H
	db	04H,'4800$',080H+00H,00H
	db	04H,'9600$',040H+00H,00H

;	Impure data

;COMND storage

cmstat: ds	1		;What is presently being parsed.
cmaflg: ds	1		;Non-zero when an action char has been found.
cmccnt: ds	1		;Non-zero if a significant char is found.
cmsflg: ds	1		;Non-zero when the last char was a space.
cmostp: ds	2		;Old stack pointer for reparse.
cmrprs: ds	2		;Address to go to on reparse.
cmprmp: ds	2		;Address of prompt.
cmptab: ds	2		;Address of present keyword table.
cmhlp:	ds	2		;Address of present help.
cmdbuf: ds	80H		;Buffer for command parsing.
cmfcb:	ds	2		;Pointer to FCB.
cmfcb2: ds	2		;Pointer to position in FCB.
cmfwld: ds	1		;Wildcard flag
cmcptr: ds	2		;Pointer for next char input.
cmdptr: ds	2		;Pointer into the command buffer.
cmkptr: ds	2		;Pointer to keyword.
cmsptr: ds	2		;Place to save a pointer.

oldsp:	ds	2		;Room for old system stack.
	ds	100H		;Room for 256 (instead of 32 [ah]) calls. 
stack:	ds	2
eoflag: ds	1		;EOF flag;non-zero on EOF.
filflg: ds	1		;Non-zero when nothing in DMA buffer.
curdsk: db	0		;holds "logged" disk
prnflg: db	0		;Flag copy to printer
timflg: db	0		;[jd] timer flag: 0 -> no timer
timval: dw	0		;[jd] timer value
wrn8:	db	0		;[jd] non-zero if 8-bit-lost warning sent
qbchr:	db	'&'		;[jd] binary quote character.
quot8:	db	0		;[jd] non-zero if doing 8-bit quoting
logflg: db	0		;Flag for a log file.
ecoflg: db	0		;Local echo flag (default off).
escflg: db	0		;Escape flag (start off).

vtflg:	db	1		;VT52 emulation flag (default on).

flwflg: db	1		;File warning flag (default on).
ibmflg: db	0		;IBM flag (default off).
cpmflg: db	1		;[jd] File was created by CPM.
parity: db	defpar		;Parity.
escchr: db	defesc		;Storage for the escape character.
fileio: db	0		;Line-by-line from file (default off).
xofflg: db	0		;X-OFF (=^S) received from COMM-line
;				;X-ON (=^Q) received resets this
chrcnt: ds	1		;Number of chars in the file buffer.
filcnt: ds	1		;Number of chars left to fill.
outpnt: ds	2		;Position in packet.
bufpnt: ds	2		;Position in file buffer.
filerc: ds	1		;File record count
fileex: ds	1		;File extent
fcbptr: ds	2		;Position in FCB.
datptr: ds	2		;Position in packet data buffer.
cbfptr: ds	2		;Position in character buffer.
pktptr: ds	2		;Poistion in receive packet.
size:	ds	1		;Size of data from gtchr.
spsiz:	db	dspsiz		;Send packet size.
rpsiz:	db	drpsiz		;Receive packet size.
stime:	db	dstime		;Send time out.
rtime:	db	drtime		;Receive time out.
spad:	db	dspad		;Send padding.
rpad:	db	drpad		;Receive padding.
spadch: db	dspadc		;Send padding char.
rpadch: db	drpadc		;Receive padding char.
seol:	db	dseol		;Send EOL char.
reol:	db	dreol		;Receive EOL char.
squote: db	dsquot		;Send quote char.
rquote: db	drquot		;Receive quote char.
chktyp: db	dschkt		;Checksum type desired
curchk: db	dschkt		;Current checksum type
inichk: db	dschkt		;Agreed upon checksum type
czseen: ds	1		;Flag that control-Z was typed
pktnum: ds	1		;Packet number.
numpkt: ds	2		;Total number of packets sent.
numrtr: ds	2		;Total number of retries.
numtry: ds	1		;Number of tries on this packet.
oldtry: ds	1		;Number of tries on previous packet.
state:	ds	1		;Present state of the automaton.
packet: ds	4		;Packet (data is part of it).
data:	ds	5AH		;Data and checksum field of packet.
recpkt: ds	65H		;Receive packet storage (use the following).
recpkx: db	cr,'$'		;=	=	= buffer limit
filbuf: ds	65H		;Character buffer.
fnbuf:	ds	20h		;[jd] file name buffer
;** Temp 1 & 2 must be in order
temp1:	ds	1		;Temporary storage.
lstchr	EQU	temp1		;Last console input character.
temp2:	ds	1
temp3:	ds	1
temp4:	ds	1

argblk: ds	20H		;Used for subroutine arguments
fcbnum: ds	1		;Number of FCB's left in the list
maxfil	EQU	20H
fcbblk: ds	maxfil*10H	;Used for a list of FCB's

speed:	db	040H+01H	;initial speed 1200bd

;Unitialized storage for DIRLST
BMAX:	  DS	2		;HIGHEST BLOCK NUMBER ON DRIVE
BMASK:	  DS	1		;(RECORDS/BLOCK)-1
BSHIFTF:  DS	1		;NUMBER OF SHIFTS TO MULTIPLY BY REC/BLOCK
nnams:	ds	1		;Dir - names per line counter.
;	Data storage for MFNAME (multi-file access)
mfreq:		DS	12		;Requested name
mfflg1: DB	0		;First time thru flag for MFNAME
mfflg2: DB	0		;Down counter for MFNAME
;
elstbl: ;Status table for SIO
	DB	18H		;Channel reset
	DB	04H		;Write Register 4
	DB	44H		;x16 clock, 1 stop bit, no parity
	DB	01H		;Write Register 1
	DB	18H		;Interrupts on all Rx chars
	DB	03H		;Write Register 3
	DB	0C1H		;Rx enable, 8 bit Rx character
	DB	05H		;Write Register 5
	DB	068H		;No DTR, 8 bit Tx character
				;Tx enable, No RTS
				;Remember: CTS-check in BIOS at 0F390-99 !
piob0:	db	01H		;Initial value of PIO-B0

elbflg:	dw	0		;Flag for characters in input buffer
elwptr:	dw	elbuff-1	;Write pointer
elrptr:	dw	elbuff-1	;Read pointer
elbend:	dw	0		;End of input buffer
elbuff:	db	0		;Interrupt input buffer starts here

	END	START
