*****************************************************************************
;
;  PCPUT - Transfer a file from a Poly-88xx running System-88 (Exec)
;	to a PC using the XMODEM protocol.
;
;       For text files, Exec uses CR as the line terminator, not CR/LF.
;	When PCPUT sends a text file, an LF is inserted after each CR.
;	PCPUT uses the send filename extension to make a best guess as
;  	to whether the file should be sent in text or binary mode. The
;	user is then given the opportunity to confirm or change the
;	setting as desired.
;
;	Rev	 Date	    Desc
;	1.0	01/01/18    M. Douglas, Original
;
;	1.1	01/11/18    M. Douglas
;			    Add '.AS' and '.BS' (assembly source and
;			    BASIC program) to the extension table as
;			    text files.
;
;*****************************************************************************

; Poly PROM equates

USER	equ	3200h		;start of user programs
Ioret	equ	0064h		;exit from interrupt
CONOUT	equ	0C24h		;console output wormhole 1
SRA4	equ	0C16h		;serial port interrupt jump vector
PVEC	equ	2D93h		;contains ctrl-y processing vector
CMPTR	equ	2DC7h		;command line pointer

Dio	equ	0406h		;disk I/O
Msg	equ	040Ch		;display text string
Err	equ	040Fh		;display error from DE and enter Exec
Gover	equ	0415h		;load and execute overlay
R1we	equ	0427h		;prompt then read line from console

; XMODEM equates

PKTLEN	equ	128		;128 byte xmodem packet length
SOH	equ	01h
EOT	equ	04h
ACK	equ	06h
NAK	equ	15h
EOF	equ	1Ah		;ctrl-z character
XMTRIES	equ	10		;number of xmodem retries

; Poly serial port equates

SIODR	equ	00h		;8251 data register
SIOCR	equ	01h		;8251 control register

SIORDA	equ	02h		;8251 receive data available
SIOXCMP	equ	04h		;8251 transmit complete
SIORENA	equ	26h		;8251 receive enabled
SIOXENA	equ	27h		;8251 receive and transmit enabled

SETUP	equ	02ADh		;setup 8251 from table (in Poly PROM)	
ONESEC	equ	24908		;rcvByte loop count for 1 second

; Misc equates

MAXRAM	equ	0F800h		;max RAM address to check (e.g., video) 
CR	equ	0Dh		;ascii for carriage return
LF	equ	0Ah		;ascii for line feed
CTRLZ	equ	1Ah		;ascii for ctrl-z (end of file on PC)
IBLEN	equ	20h		;length of input buffer

;-----------------------------------------------------------------------------
;  Start of code
;-----------------------------------------------------------------------------
	org	USER		;standard Exec program load address

	jmp	start		;first entry jump vector
	jmp	start		;re-entry jump vector (keep this)

start	lxi	h,0		;save stack pointer in savStk
	dad	sp
	shld	savStk

	lhld	PVEC		;save current ctrl-y processor
	shld	savPvec

	lxi	h,pgmExit	;set ctrl-y processor to pgmExit
	shld	PVEC

	call	sizeRam		;get maximum RAM page to use
	call	serInit		;init serial I/O
	call	fOpen		;open filename specified on command line
	call	getType		;set params based on file type
	call	read		;read the file into memory

	lxi	h,mStart	;display "start transfer" prompt
	call	Msg
	call	sndBuf		;send the buffered file		
	lxi	h,mDone		;HL->'File sent' message
	call	Msg
				;fall into program exit

; pgmExit - Exit program. Disable serial interrupts, restore
;    stack, restore ctrl-y processor

pgmExit	xra	a		;disable serial port 
	out	SIOCR		;(prevents further interrupts)

	lhld	savPvec		;restore ctrl-y processor
	shld	PVEC

	lhld	savStk		;restore stack pointer
	sphl
	
	ei			;needed if entered via ctrl-y

	mvi	a,CR		;CR to console
	jmp	CONOUT		;display CR and exit
	
;------------------------------------------------------------------
; sizeRam - Determine how much RAM we have for buffering tracks.
;   Sets the lastPg variable which is the last page in RAM.
;------------------------------------------------------------------
sizeRam	lxi	h,fileBuf+100h	;HL->next page after fileBuf

ramLoop	mov	a,m		;a=current RAM content
	inr	m		;change RAM
	cmp	m		;did RAM change?
	mov	m,a		;restore RAM
	jz	ramEnd		;end of RAM found

	inr	h		;next page
	mov	a,h		;reached max allowed address?
	cpi	MAXRAM/256
	jnz	ramLoop		;loop if not

ramEnd	dcr	h		;subtract 256 bytes from end of RAM
	mov	a,h		;save max memory page number
	sta	lastPg

	ret
	
;----------------------------------------------------------------------------
; serInit - initialize serial port and serial interrupt logic
;-----------------------------------------------------------------------------
serInit	call	SETUP		;initialize 8251 from following table 
	db	01Fh		;device 1 (printer port), 9600 baud
	db	0AAh		;fake sync character
	db	040h		;reset gets us to mode level
	db	04Eh		;mode async, 8N1, 16x
	db	000h		;command: idle, also end of table

	xra	a		;A=0		
	sta	rcvFlag		;no receive byte present
	sta	xCount		;zero xmit bytes queued

	lxi	h,xQueue	;HL->transmit queue
	shld	xInPtr		;insert pointer=remove pointer
	shld	xRemPtr
	
	lxi	h,serIsr	;HL->local serial I/O ISR
	shld	SRA4		;use local ISR

	mvi	a,SIORENA	;A=enable receive (not xmit)
	sta	sioSave		;save SIO control register value
	out	SIOCR

	ret
	
;-----------------------------------------------------------------------------
; fOpen - Open the input file specified on command line.
;    If no input file is provided, display program usage information and
;    exit. If the file does not exist, display the error and exit.
;    Otherwise, copy the filename extension, disk start address, and file
;    size to to fnExt, dskAddr, and numSecs.
;-----------------------------------------------------------------------------
fOpen	lhld	CMPTR		;HL->command line parameters
	mov	a,m		;anything entered?
	cpi	CR
	jz	errHelp		;no file specified, exit with help message

	lxi	d,fdeBuf	;DE->buffer for FDE returned by Gfid
	mvi	a,40h		;lookup the file name pointed to by HL
	call	Gover		;call Gfid overlay
	db	'Gfid'
	jc	err0705		;can't find file error

	lxi	h,fdeBuf+1	;HL->1st byte of the FDE
	mov	a,m		;A=byte with filename length
	ani	1Fh		;A=filename length alone

	inx	h		;HL->1st byte of filename
	mvi	d,0		;form DE=offset to filename extension
	mov	e,a		;E=length of filename
	dad	d		;HL->filename extension

	lxi	d,fnExt		;DE->start of local copy of FDE fields
	mvi	b,6		;number of bytes to copy

foLoop	mov	a,m		;copy from FDE to local fields
	stax	d
	inx	h
	inx	d
	dcr	b
	jnz	foLoop
	
	ret

;-----------------------------------------------------------------------------
; getType - Look up the file extension in the extension table and set
;   the txtFile flag. If a match is not found, txtFile is set false.
;-----------------------------------------------------------------------------
getType	xra	a		;init text file flag to false
	sta	txtFile

	lhld	fnExt		;HL=filename extension
	xchg			;DE=filename extension (in E,D)
	lxi	h,extTbl	;HL->extension table
	
gtLoop	mov	a,m		;A=1st byte of extension
	ora	a		;test for zero (end of table)
	jz	gtVfy		;match not found, go to user verify step

	cmp	e		;compare 1st byte of extension
	inx	h
	jnz	gtNext		;no match, check next extension

	mov	a,m		;compare 2nd byte of extension
	sub	d

gtNext	inx	h		;HL->next table entry
	jnz	gtLoop		;loop if no match

	dcr	a		;A=0FFh (non-zero for text file)
	sta	txtFile

; gtVfy - Verify the text file parameter with the user

gtVfy	lxi	h,mText		;HL->text mode transfer message
	lda	txtFile		;test text file flag
	ora	a
	jnz	gtVfy2		;using text mode transfer
	
	lxi	h,mBinary	;HL->binary mode message
	
gtVfy2	call	Msg		;display text/binary mode message

gtVfy3	lxi	d,mChange	;prompt for settings change
	call	rdLineA		;display message and get response
	cpi	'n'
	rz			;no changes requested
	
	cpi	'y'
	jnz	gtVfy3		;invalid response, ask again
	
; gtChg - User wants to change the values

gtChg	lxi	d,mNewTxt	;prompt for text or binary mode
	call	rdLineA		;get first character of input from user
	cpi	't'		;text mode?
	jz	gtChg2		;yes
	
	sui	'b'		;binary?
	jnz	gtChg		;invalid response, start over
	
gtChg2	sta	txtFile		;save text file flag
	jmp	gtVfy		;re-verify new value with user
	
;-----------------------------------------------------------------------------
; read - Read the input file into memory
;-----------------------------------------------------------------------------
read	lxi	d,0505h		;DE=file too big error
	lhld	numSecs		;HL=file size in 256 byte sectors
	mov	a,h		;if MSB not zero, file is too big
	ora	a
	jnz	errExit		;exit with error 0505
	
	mov	b,l		;form BC=file length in bytes
	mov	c,a		;C=0
	
	lxi	h,fileBuf	;HL->file buffer
	dad	b		;HL->end of file in RAM
	jc	errExit		;past end of RAM - error

	lda	lastPg		;A=last page of RAM to use
	cmp	h		;file bigger than RAM?
	jc	errExit		;yes, exit with error
	
	shld	fileEnd		;save pointer to EOF in RAM
	
	xra	a		;byte at EOF in RAM must be zero for the...
	mov	m,a		;   text file EOF to work properly

; Use DIO to read the file
	
	lda	fdeBuf		;1st byte contains drive number
	ani	0Fh		;get drive number alone
	mov	c,a		;C=drive to use
	
	lxi	d,fileBuf	;DE->file in memory	
	mvi	b,1		;B=read command
	lhld	dskAddr		;HL=disk address (sector) from the FDE
	lda	numSecs		;A=number of sectors to read
	call	DIO		;issue read command (in PROM)
	jc	errExit		;disk I/O error

	ret

;-----------------------------------------------------------------------------
; sndBuf - Send the file buffer using XMODEM
;-----------------------------------------------------------------------------
sndBuf	call	rcvByte		;loop until input clear for 1 second
	jnz	sndBuf
	
	xra	a		;set CRC flag to false (checksum mode)
	sta	crcFlag

waitNak	call	rcvByte		;wait for a character
	cpi	NAK
	jz	haveNak		;have a NAK, use checksum protocol

	cpi	'C'		;CRC protocol requested?
	jnz	waitNak		;no

	sta	crcFlag		;set crc flag non-zero = CRC mode

;  NAK or 'C' received meaning the XMODEM receive has started. Initialize
;     for the transfer.

haveNak	lhld	fileEnd		;HL->end of file in RAM
	xchg			;DE->end of file
	lxi	h,fileBuf	;HL->start of file in RAM

	mvi	a,1		;init xmodem block number to one
	sta	blkNum
	sta	lastChr		;make sure last char is not CR

sndLoop	push	d		;preserve end of file pointer
	call	sndPkt		;send a packet
	pop	d		;DE->end of file
	
	call	cmpHlDe		;compare packet pointer - disk end
	jc	sndLoop		;more to send, keep going
	
	jmp	sndEot		;send the EOT and exit

;-----------------------------------------------------------------------------
; sndPkt - Send an xmodem format 128 byte packet. HL points to the 128 byte
;    buffer to send. On exit, HL points to the next 128 byte boundary.
;-----------------------------------------------------------------------------
sndPkt	mvi	a,XMTRIES	;init retry counter
	sta	xmRetry

; First, send header bytes

reSend	push	h		;save hl for possible re-send

	mvi	a,SOH		;1st byte is SOH
	call	serOutN

	lda	blkNum		;2nd byte is the block number
	call	serOutN

	cma			;2nd complement of block number
	call	serOutN

; Init checksum and CRC and packet length for transmission of data portion

	xra	a		;init crc
	sta	crc16
	sta	crc16+1
	lxi	d,PKTLEN*256	;D=byte counter, E=0 (checksum)

; Loop sending the data bytes and updating checksum and CRC

pktLoop	lda	txtFile		;text file?
	ora	a
	jz	notText		;not a text file, just send next byte

	lda	lastChr		;was previous character a CR?
	cpi	CR
	jz	sendLf		;yes, send a line feed 

	mov	a,m		;A=next character to send
	ora	a		;is next byte zero? (marks EOF)
	jnz	sendA		;not EOF, go send the byte

	lhld	fileEnd		;force HL to end of file in RAM
	dcx	h		;account for increment at end of loop

	mvi	a,EOF		;send XMODEM EOF character (ctrl-z) instead of zero
	jmp	sendA

sendLf	mvi	a,LF		;stuff a LF after each CR
	dcx	h		;undo pointer increment for stuffed LF
	jmp	sendA		;go send the LF

notText	mov	a,m		;A=next byte to send

sendA	sta	lastChr		;save last character sent
	call	serOutN		;send the byte in A
	call	calCrc		;update the checksum and CRC
	inx	h		;point to next byte
	dcr	d		;decrement bytes remaining
	jnz	pktLoop

; Send checksum or CRC based on crcFlag

	lda	crcFlag		;crc or checksum?
	ora	a
	jz	sndCsum		;flag clear = checksum

	lda	crc16+1		;A=high byte of CRC
	call	serOutN		;send it
	lda	crc16		;A=low byte of crc
	jmp	sndCrc		;send the low byte

sndCsum	mov	a,e		;send the checksum byte from E

sndCrc	call	serOutN

; All bytes sent. Wait for the response.

	call	rcvByte		;get the response character
	jz	sndFail		;timeout on response

	cpi	ACK		;ack received?
	jnz	sndFail		;no, send failed

	lda	blkNum		;increment block number
	inr	a
	sta	blkNum

	pop	b		;remove pushed hl, but don't clobber hl
	ret

; sndFail - ACK not received, decrement retry and try again.

sndFail	lxi	h,xmRetry	;point to retry counter
	dcr	m
	jz	xmFail		;retries used up, failed xmodem transfer

; If we've had 3 NAKs on the 1st packet and CRC is selected, assume
;   we took so long to send the 1st packet due to disk retries that
;   the receiver has since timed out and switched to checksum

	lda	crcFlag		;are we in CRC mode
	jz	clrRcv2		;no, ignore the rest of this

	lda	blkNum		;on block 1?
	dcr	a
	jnz	clrRcv2		;no, go on

	lda	xmRetry		;failed three times in a row on block 1?
	sui	XMTRIES-3
	jnz	clrRcv2		;no

	sta	crcFlag		;clear crcFlag to force checksum

;  clrRcv2 - Wait for one second of line clear time and send packet again.

clrRcv2	call	rcvByte		;wait for 1 second of clear line
	jnz	clrRcv2

	sta	lastChr		;clear possible CR flag (A=0)
	pop	h		;restore pointer to the packet
	jmp	reSend		;re-send the packet

;  xmFail - Display failure message and exit

xmFail	lxi	h,mXmdm		;xmodem failure message
	call	Msg
	jmp	pgmExit		;exit

;-----------------------------------------------------------------------------
; calCrc - update the 8 bit checksum and 16-bit CRC with one more byte. 
;    (CRC routine copied from M. Eberhard)
; On Entry:
;   A has the new byte
;   E has checksum
;   crc16 is current except this byte
; On Exit:
;   E contains updated checksum
;   crc16 has been updated
;   Trashes A,B,C
;-----------------------------------------------------------------------------
calCrc	mov	b,a		;save byte in B
	add	e		;update checksum in E
	mov	e,a
	mov	a,b		;restore A with original byte

	push	d		;save registers
	push	h

	lhld	crc16		;get CRC so far
	xra	h		;XOR into CRC top byte
	mov	h,a
	lxi	b,1021h		;BC=CRC16 polynomial
	mvi	d,8		;prepare to rotate 8 bits

; Do 8 bit shift/divide by CRC polynomial

cRotLp	dad	h		;16-bit shift
	jnc	cClr		;skip if bit 15 was 0

	mov	a,h		;CRC=CRC xor 1021H
	xra	b
	mov	h,a
	mov	a,l
	xra	c
	mov	l,a

cClr	dcr	d
	jnz	cRotLp		;rotate 8 times

; Save the updated CRC and exit

	shld	crc16		;save updated CRC
	pop	h
	pop	d
	ret

;-----------------------------------------------------------------------------
;  sndEot - Send EOT character and wait for ACK response
;-----------------------------------------------------------------------------
sndEot	mvi	a,XMTRIES	;init retry counter
	sta	xmRetry

reEot	mvi	a,EOT		;send the EOT
	call	serOut1
	call	rcvByte		;wait for response
	jz	eotFail		;timeout

	cpi	ACK		;ack received?
	jnz	eotFail		;no, EOT send failed

	ret			;otherwise, we're done.

; Timeout waiting for ACK to EOT. Decrement retry counter and try again

eotFail	lxi	h,xmRetry	;point to retry counter
	dcr	m
	rz			;just give up - xfer was probably good

clrRcv3	call	rcvByte		;wait for 1 second of clear line
	jnz	clrRcv3
	jmp	reEot		;try again

;-----------------------------------------------------------------------------
; Error processing
;-----------------------------------------------------------------------------
; errHelp - Display program info and usage, exit to Exec

errHelp	lxi	h,mHelp		;HL->help message 
 	call	Msg		;display it
 	jmp	pgmExit		;exit
 	
; err0705 - Display file not found error, exit to Exec

err0705	lxi	d,0705h		;error=file not found

errExit	xra	a		;disable serial port
	out	SIOCR		;(prevents further interrupts)

	jmp	Err		;display error and exit to Exec

;-----------------------------------------------------------------------------
; rdLineA - Display prompt message pointed to by DE, then read a line of
;    input from the console. The input line is read into inBuf using
;    R1we. Return the 1st character in A forced to lower case. If nothing
;    is typed in, zero is returned in A.
;-----------------------------------------------------------------------------
rdLineA	lxi	h,inBuf		;HL->user input buffer
	lxi	b,100h+IBLEN	;B=1=don't echo terminator, C=inBuf length
	call	R1we		;get input from user

	mov	a,b		;A=read length	
	ora	a		;anything typed?
	rz			;nothing typed, return zero

	lda	inBuf		;A=first character typed
	ori	20h		;upper case letters to lower case
	ret

;-----------------------------------------------------------------------------
; rcvByte - Receive a byte from the serial port with a one second
;     timeout. If a timeout occurs, zero is returned in a and the zero 
;     flag is true. Otherwise, the character is returned in a (could be
;     zero) and zero flag is false. ONESEC must be set based on processor
;     speed and the number of cycles in the serIn call + 46.
;     Clobbers B and C
;-----------------------------------------------------------------------------
rcvByte	lxi	b,ONESEC	;BC=cycles through this loop for 1s

rcvWait	call	serIn		;(17+cycles in serIn) look for a byte
	rnz			;(5)byte received

	dcx	b		;(5)otherwise, decrement timer
	mov	a,b		;(5)one second expire?
	ora	c		;(4)
	jnz	rcvWait		;(10)no, keep waiting

	ret			;return with timeout (zero true and in A)

;----------------------------------------------------------------------------
; serIn - Input character from serial port and return in A
;    Inputs:
;    Outputs: Z true if no character present
;	      Z false if character returned in A
;    clobbers none
;    28 cycles with no character 
;-----------------------------------------------------------------------------
serIn	lda	rcvFlag		;(13) serial data available ?
	ora	a		;(4)
	rz			;(11) no

	mvi	a,0		;A=0, preserve non-zero status
	sta	rcvFlag		;clear data present flag

	lda	rcvData		;A=byte received
	ret			;return with Z false

;-----------------------------------------------------------------------------
; serOut1 - Output byte to serial for a one byte transmission. The 
;	transmitter is immediately enabled so the byte is sent.
; serOutN - Output byte to serial for a multi-byte transmission. The
;	transmitter is not enabled until at least two bytes are queued
;	to improve transmission efficiency
;    Inputs: A = character to send
;    Output: A,B = character sent
;    clobbers B,C
;-----------------------------------------------------------------------------
serOut1	mvi	c,1		;enable interrupts with >= 1 byte in queue
	jmp	soInit		;continue

serOutN	mvi	c,2		;enable interrupts with >= 2 bytes in queue

soInit	mov	b,a		;save byte to send in B
	push	h		;preserve HL

soWait	lda	xCount		;A=bytes in xmit queue
	cpi	XMTQLEN		;room for another byte?
	jnc	soWait		;loop if no room

	lhld	xInPtr		;HL=insert pointer
	mov	m,b		;insert byte to xmit
	
	inr	l		;increment and wrap, assumes the xmit queue
	mvi	a,XMTQLEN XOR 0FFh	;...is on XMTQLEN*2 boundary
	ana	l		;wrap
	sta	xInPtr		;MSB doesn't change

	lxi	h,xCount	;HL->count of bytes in queue
	inr	m		;increment byte count (atomic)

	lda	sioSave		;see if transmitter enabled
	rrc			;LSB is transmit enable
	jc	soExit		;transmitter already on, exit

	mov	a,m		;A=bytes in queue
	cmp	c		;enough bytes to enable transmitter?
	jc	soExit		;no, exit

	mvi	a,SIOXENA	;enable transmitter (and receiver)
	sta	sioSave		;save latest control register value
	out	SIOCR

soExit	pop	h		;restore HL
	mov	a,b		;return with output byte in A
	ret

;--------------------------------------------------------------------------
; serIsr - Serial port interrupt service routine
;--------------------------------------------------------------------------
serIsr	in	SIOCR		;A=serial status register
	ani	SIORDA		;data received?
	jz	isrXmt		;no, must be a transmit interrupt

	sta	rcvFlag		;set received data flag true (non-zero)
	in	SIODR		;A=byte received
	sta	rcvData		;rcvByte = byte received

	jmp	isrExit		;restore registers and exit

; Transmit ready interrupt. Send the next character from the transmit
;    queue. If no characters left, wait for the current transmission
;    to complete then shut down the transmitter (only way to turn off
;    transmit interrupts).

isrXmt	lda	xCount		;A=number of bytes in xmit queue
	ora	a		;anything there?
	jz	isrCmp		;no, wait for last transmission to complete

	dcr	a		;decrement the count of bytes in the queue 
	sta	xCount

	lhld	xRemPtr		;HL=remove pointer
	mov	a,m		;A=next byte to send
	out	SIODR		;send it

	inr	l		;increment and wrap, assumes the xmit queue
	mvi	a,XMTQLEN XOR 0FFh	;...is on XMTQLEN*2 boundary
	ana	l		;wrap
	sta	xRemPtr		;MSB doesn't change

	jmp	isrExit		;exit

isrCmp	in	SIOCR		;A=serial status register
	ani	SIOXCMP		;transmission complete?
	jz	isrCmp		;no, keep waiting

	mvi	a,SIORENA	;disable xmit (rcv still enabled)
	sta	sioSave		;save latest control register value
	out	SIOCR		;xmit off disables xmit interrupt
				;fall through to exit
isrExit	pop	h		;restore registers
	pop	d
	pop	b
	pop	psw
	ei			;enable interrupts
	ret

;--------------------------------------------------------------------
; cmHlDe - Compare HL-DE. Carry set if HL<DE, carry clear if HL>=DE
;--------------------------------------------------------------------
cmpHlDe	mov	a,l		;compare HL-DE, do lsbs first
	sub	e
	mov	a,h		;do msbs
	sbb	d
	ret			;carry set HL<DE, clear HL>=DE

;-----------------------------------------------------------------------------
;   Data Area
;-----------------------------------------------------------------------------
mHelp	db	CR
	db	'PCPUT Ver 1.1 for System-88 (Exec)',CR
	db	'  Sends a file to a PC through the Poly serial',CR
	db	'  port using the XMODEM protocol.',CR
	db	CR
	db	'Usage: PCPUT file.ext',CR,0
	
mText	db	CR,'Transferring as TEXT file.',CR,0
mBinary	db	CR,'Transferring as BINARY file.',CR,0
mChange	db	CR,'Change this setting? ',0

mNewTxt	db	CR,CR,'Text or binary transfer? ',0

mStart	db	CR,CR,'Start XMODEM receive on PC now...',CR,0
mDone	db	'File transfer complete',CR,0
mRam	db	CR,'File too big, out of RAM',CR,0
mXmdm	db	CR,'XMODEM communication failure',CR,0


;**************************************************************************
; 
;  Data area
;
;**************************************************************************

; extTbl - Table of file extensions used to determine whether a file
;    is a text file or not. If an extension is not in this table,
;    txtFile is set to false. 

extTbl	db	'TX'		;text file
	db	'ED'		;editor definitions
	db	'HF'		;help file
	db	'BS'		;BASIC program
	db	'AS'		;assembly language source
	db	0		;mark end of table

txtFile	ds	1		;non-zero for text file, zero for binary

; Xmodem data

xmRetry	ds	1		;xmodem retry counter
blkNum	ds	1		;current xmodem block number
rcvBlk	ds	1		;block number received
rcvNBlk	ds	1		;"not" block number received
crcFlag	ds	1		;non zero if using CRC instead of checksum
crc16	ds	2		;crc-16 result
lastChr	ds	1		;last character sent

; Serial I/O data

rcvFlag	ds	1		;non-zero = received byte available
rcvData	ds	1		;byte received from serial port
xCount	ds	1		;count of bytes in xmit queue
xInPtr	ds	2		;transmit queue insert pointer
xRemPtr	ds	2		;transmit queue remove pointer
sioSave	ds	1		;saved 8251 command register value

; Transmit queue aligned on an XMTQLEN*2 boundary. This allows
;     ANDing to wrap.

XMTQLEN	equ	4		;transmit queue length (power of 2)
	org	($+(XMTQLEN*2-1)) AND -(XMTQLEN*2)   ;force XMTQLEN*2 boundary
xQueue	ds	XMTQLEN		;transmit queue

; File data

fdeBuf	ds	44		;FDE as returned by Gfid

; Copy of data from the FDE. These fields MUST REMAIN IN THIS ORDER

fnExt	ds	2		;filename extension 
dskAddr	ds	2		;starting disk address of file (FDA)
numSecs	ds	2		;number of sectors in file (DNS)

; Misc data

savStk	ds	2		;saved entry stack pointer
savPvec	ds	2		;saved entry PVEC pointer
lastPg	ds	1		;last useable RAM page
fileEnd	ds	2		;pointer to end of file in RAM

; Receive buffer runs from here to the end of memory

	org	($+0FFh) AND 0FF00h	;align to next page boundary

fileBuf	equ	$
inBuf	equ	$		;console input buffer uses this area too

	end
