;*****************************************************************************
;
;  Flop2PC - Transfer floppy image to PC over a serial port
;	    (for Polymorphic hard sector, single density controller)
;
;	This program transmits an image of a Polymorphic single density
;       disk to a PC over the Poly serial port (printer port) using the
;	XMODEM protocol. The disk is copied in raw format (256 bytes per
;	sector, 10 sectors per track, 35 tracks). The disk image is the 
;	linear sequence of the 256 byte sectors from track 0, sector 0 
;	through track 34, sector 9. The leading zeros before the data
;	payload and the checksum are not transferred. This image format
;	is compatible with the Polymorphic 8813 emulator.
;
;	This program runs standalone at 3200h or under Exec. The standard
;	Polymorphic disk PROM set is expected on the CPU board.
;
;	Rev	 Date	    Desc
;	1.0	12/18/17    M. Douglas, Original
;
;*****************************************************************************

; Disk information equates

NUMTRK	equ	35		;number of tracks
NUMSEC	equ	10		;number of sectors per track
SECLEN	equ	256		;sector length (as transmitted)
MINDRV	equ	1		;first drive number
MAXDRV	equ	3		;max drive number 
TRKLEN	equ	(NUMSEC*SECLEN)	;length of track in bytes

; Poly PROM equates

USER	equ	3200h		;start of user programs
CONIN	equ	0C20h		;console input wormhole 0
CONOUT	equ	0C24h		;console output wormhole 1
SRA4	equ	0C16h		;serial port interrupt jump vector
SETUP	equ	02ADh		;setup 8251 from table
Dio	equ	0406h		;disk I/O entry vector
R1we	equ	0427h		;prompt then read line from console
Msg	equ	040Ch		;display message
PVEC	equ	2D93h		;contains ctrl-y processing vector

; 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

ONESEC	equ	24908		;rcvByte loop count for 1 second

; Misc equates

MAXRAM	equ	0F800h		;max RAM address (e.g., protect video)
IBLEN	equ	20		;console input buffer length
CR	equ	13		;ascii for carriage return

	org	3200h		;load address
;-----------------------------------------------------------------------------
;  Start of code
;-----------------------------------------------------------------------------
	org	USER		;standard Exec program load address

cold	jmp	init		;first entry jump vector
warm	jmp	init		;re-entry jump vector

init	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	serInit		;init serial I/O
	call	sizeRam		;determine amount of RAM available

	lxi	h,mWelcom	;display welcome message
	call	Msg

; getDrv - Get drive number or letter from the user.

getDrv	lhld	savStk		;restore stack pointer
	sphl

	lxi	h,inBuf		;HL->user input buffer
	lxi	d,mDrive	;DE->prompt for drive number
	lxi	b,IBLEN		;B=0=echo terminator, C=inBuf length
	call	R1we		;get input from user

	mov	a,b		;A=read length	
	ora	a		;anything typed?
	jz	getDrv		;no, ask again

	lda	inBuf		;A=first character typed
	ori	20h		;upper case letters to lower case
	cpi	'x'		;exit requested?
	jz	pgmExit		;yes

	sui	'0'+MINDRV	;1st drive is now zero
	cpi	MAXDRV-MINDRV+1	;validate <= max drive
	jnc	getDrv		;invalid, prompt again

	adi	MINDRV		;restore offset of 1st drive (if any)
	sta	drvNum		;save the drive number to use

; Prompt the user to start the XMODEM receive operation on the PC. 
;    Wait for a clear receive line for a least one second, then start
;    looking for NAK or 'C' (CRC protocol) from the PC

	lxi	h,mStart	;display start file transfer prompt
	call	Msg

clrRcv1	call	rcvByte		;loop until input clear for 1 second
	jnz	clrRcv1

	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	xra	a		;init track we want to zero
	sta	trkNum

	inr	a		;init xmodem block number to one
	sta	blkNum

	lxi	h,trkBuf	;trkBuf is initial starting point for
	shld	sndPtr		;   XMODEM send

;-----------------------------------------------------------------------------
;  mainLp - Loop through all tracks on the disk buffering as many tracks
;    as will fit in RAM before sending via xmodem, then repeat.
;-----------------------------------------------------------------------------
mainLp	lxi	h,trkBuf	;disk buffering always start at trkBuf
	shld	trkPtr

; Read and buffer bufTrks tracks unless all tracks on drive reached first

bufLoop	call	readTrk		;read into trkBuf

	lda	trkNum		;increment track number (preserve HL)
	inr	a
	sta	trkNum
	cpi	NUMTRK		;done all tracks on the disk?
	jz	sendBuf		;yes, go send the buffered tracks

	xchg			;DE=current track pointer
	lhld	bufEnd		;HL=end of buffering space
	call	cmpDeHl		;compare current-end
	jc	bufLoop		;still room, keep going	

; Track buffer is full or all tracks have been read. Send the buffered
;    tracks via xmodem.

sendBuf	call	sndTrks		;send the buffered tracks via xmodem

	lda	trkNum
	cpi	NUMTRK		;done all tracks?
	jnz	mainLp		;no, not done yet

; The entire disk has been read and (mostly) transmitted. See if there are
;    left over bytes to send. If so, send them.

	mov	a,l		;HL->next packet to send, A=lsb of ptr
	cpi	trkBuf AND 0FFh	;pointing to lsb of address of trkBuf?
	jz	noExtra		;same, no extra bytes to send
	call	sndPkt		;otherwise, send one last packet

; Send EOT and wait for response. Then display the success message and
;    start the program over.

noExtra	call	sndEot		;send and get response for EOT
	lxi	h,mDone		;print the all done message
	call	Msg

	jmp	getDrv		;start over asking for a drive
	
;-----------------------------------------------------------------------------
; readTrk - Read NUMSEC sectors from the current track into a trkBuf as
;   pointed to by trkPtr. After the track is read, trkPtr is updated
;   by the length of a track to point to the next track buffer. This
;   saved value is also returned in HL.
;-----------------------------------------------------------------------------
readTrk	mvi	b,1		;B=read command

	lxi	h,drvNum	;HL->drvNum
	mov	c,m		;C=drive to use
	
	lhld	trkPtr		;HL->next spot in track buffer
	xchg			;DE->next spot in track buffer
	
	mvi	h,0		;init H to zero
	lda	trkNum		;convert track number into disk address
	mov	l,a		;L=track number
	add	a		;A=track*2
	add	a		;A=track*4
	add	l		;A=track*5
	add	a		;A=track*10 (could have carry out)
	mov	l,a		;L=lsb of disk address
	jnc	haveSec		;disk address < 256
	
	inr	h		;disk address >= 256
	
haveSec	mvi	a,NUMSEC	;A=number of sectors to read (10)
	call	Dio		;issue read command (in PROM)
	cc	dskErr		;read failure, display the error

	lhld	trkPtr		;point trkPtr to next track
	lxi	d,TRKLEN	;DE=bytes in a track
	dad	d		;HL=start of next track in trkBuf
	shld	trkPtr
	ret

;-----------------------------------------------------------------------------
; sndTrks - Send the tracks buffered in trkBuf via xmodem. trkPtr points
;    to the end+1 of the data to send
;-----------------------------------------------------------------------------
sndTrks	lhld	trkPtr		;HL=end of buffered data + 1
	xchg			;DE=end of buffered data + 1
	lhld	sndPtr		;HL=start tranmission address

sndLoop	push	d		;save end pointer
	call	sndPkt		;send a packet
	pop	d		;DE=end pointer

; At this point, HL->start of next packet and DE->last byte read from disk+1.
;    If the next XMODEM packet will go past the end of the disk data,
;    we don't want to send it yet.

	lxi	b,PKTLEN	;BC=length of XMODEM packet
	dad	b		;HL=address at end of NEXT packet + 1
	call	cmpDeHl		;compare disk end - end of next packet
	jc	sndDone		;next packet will pass the end, stop

	lxi	b,-PKTLEN	;restore HL
	dad	b
	jmp	sndLoop

; sndDone - All the packets we can send have been sent. Move any bytes
;    left over to just before the start of trkBuf. The next group of
;    xmodem packets will be transmitted starting there.

sndDone	call	subDeHl		;HL=DE-HL = left over byte count - PKTLEN
	mov	a,l		;A=left over count - PKTLEN
	adi	PKTLEN		;A=left over byte count
	mov	b,a		;B=count of bytes to move
	lxi	h,trkBuf	;HL->start of trkBuf
	jz	mvDone		;no bytes to move, we're done
	
; Copy the leftover data backwards to just before the track buffer. The
;   next XMODEM send sequence will start at the beginning of this copied
;   data instead of at the start of trkBuf.

moveLp	dcx	h		;HL->memory just before trkBuf
	dcx	d		;DE->unsent bytes from end of trkBuf
	ldax	d		;move from end of trkBuf to before trkBuf
	mov	m,a	
	dcr	b
	jnz	moveLp

mvDone	shld	sndPtr		;save address from which to send next time
	ret

;-----------------------------------------------------------------------------
; 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	mov	a,m
	call	serOutN		;send next data byte
	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

	pop	h		;restore pointer to the packet
	jmp	reSend		;re-send the packet

;  xmFail - Display failure message then restart program

xmFail	lxi	h,mXmdm		;xmodem failure message
	call	Msg

	lhld	savStk		;restore stack pointer
	sphl

	jmp	getDrv		;start over

;-----------------------------------------------------------------------------
; 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

;-----------------------------------------------------------------------------
; dskErr - Display the disk read error code (in E) and the track number
;    which just had a read error. 
;-----------------------------------------------------------------------------
dskErr	lxi	h,errCode	;HL->where to put ascii error code
	mov	a,e		;A=error code
	call	bin2dec

	lxi	h,errTrk	;HL->where to put ascii track number
	lda	trkNum		;A=track with error on it
	call	bin2dec		;track to ascii

	lxi	h,mDskErr	;display the error message
	call	Msg

	ret

;--------------------------------------------------------------
; bin2dec - Binary byte in A to 2 ASCII digits at (HL)
;   HL is preserved
;--------------------------------------------------------------
bin2dec	mvi	m,' '		;assume zero supression
	sui	10		;value less than 10?
	jc	do1s		;yes, leading blank
	mvi	m,'1'		;have one ten already

loop10	sui	10		;count 10s
	jc	do1s		;done with 10s, do 1s
	inr	m
	jmp	loop10

do1s	adi	'0'+10		;form ASCII 1s digit
	inx	h		;move to 1s position
	mov	m,a
	dcx	h		;restore hl
	ret

;------------------------------------------------------------------
; sizeRam - Determine how much RAM we have for buffering tracks.
;   Sets the bufEnd variable which points to end address of 
;   the last possible track buffer + 1
;------------------------------------------------------------------
sizeRam	lxi	h,(trkBuf+0FFh) AND 0FF00h   ;next 256 byte boundary

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 RAM address?
	cpi	MAXRAM/256
	jnz	ramLoop		;loop if not

; ramEnd - End of RAM found. Subtract 256 bytes from this to make room
;   for xmodem packet overflow at the end. Determine the end address + 1
;   of the last track buffer that will fit in RAM. Store in bufEnd

ramEnd	xchg			;DE=end of RAM + 1
	dcr	d		;subtract 256 bytes from end of RAM
	lxi	h,trkBuf	;HL=start of track buffer
	lxi	b,TRKLEN	;BC=length of track in bytes

; Loop increasing HL by TRKLEN until HL > end of RAM.

bfEndLp	dad	b		;HL=HL+track length
	call	cmpHlDe		;compare HL-DE
	jc	bfEndLp		;still more room, keep going

; Subtract one track length from HL, this will be the end address + 1 of
;   the the last track buffer that will fit in RAM

	lxi	b,-TRKLEN	;subtract one track length
	dad	b		;HL = end address of last track + 1
	shld	bufEnd		;save as bufEnd

	ret

;--------------------------------------------------------------
; 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

;--------------------------------------------------------------------
; 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

;--------------------------------------------------------------------
; cmDeHl - Compare DE-HL. Carry set if DE<HL, carry clear if DE>=HL
;--------------------------------------------------------------------
cmpDeHl	mov	a,e		;compare DE-HL, do lsbs first
	sub	l
	mov	a,d		;do msbs
	sbb	h
	ret			;carry set DE<HL, clear DE>=HL

;--------------------------------------------------------------------
; subDeHl - HL=DE-HL
;--------------------------------------------------------------------
subDeHl	mov	a,e		;subtract DE-HL, do lsbs first
	sub	l
	mov	l,a		;lsb result in l
	mov	a,d		;do msbs
	sbb	h
	mov	h,a		;msb result in h	
	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		;store local ISR

	mvi	a,SIORENA	;A=enable receive (not xmit)
	sta	sioSave		;save SIO control register value
	out	SIOCR

	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

;---------------------------------------------------------------------
; Message constants
;---------------------------------------------------------------------
mWelcom	db	CR
	db	'===== Floppy to PC Image Transfer, Version 1.0 ====='
	db	CR
	db	'    (Poly-88xx with Poly Hard Sector Controller)'
	db	CR,CR
	db	'This program transfers an image of a Polymorphic single'
	db	CR
	db	'density disk to a PC through the serial port using the'
	db	CR
	db	'XMODEM protocol (checksum or CRC).',CR,0

mDrive	db	CR,'Insert and specify source disk (1-3)',cr
	db	'  or X to exit: ',0

mStart	db	CR,'Start XMODEM receive operation on the PC now...',0

mDone	db	CR,CR,'Transfer complete!',CR,0

mXmdm	db	CR,CR,'XMODEM communication failure',CR,0

mDskErr	db	CR,'Read failure '
errCode	db	'xx on track '
errTrk	db	'xx',0

;**************************************************************************
; 
;  Data area
;
;**************************************************************************

; disk variables

drvNum	ds	1		;drive number to use
trkNum	ds	1		;track number to read
trkPtr	ds	2		;pointer into trkBuf at track boundaries
bufEnd	ds	2		;end address + 1 of last track spot in RAM

; xmodem variables

xmRetry	ds	1		;xmodem retry counter
blkNum	ds	1		;current xmodem block number
crcFlag	ds	1		;non zero if using CRC instead of checksum
crc16	ds	2		;crc-16 result
sndPtr	ds	2		;pointer for start of XMODEM send

; 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

; misc variables

savStk	ds	2		;saved entry stack pointer
savPvec	ds	2		;saved entry PVEC pointer

; track buffer runs from here to the end of memory

	ds	PKTLEN		;space for pre-pended unsent data
trkBuf	equ	$
inBuf	equ	$		;use for console input as well

	end

