*******************************************************************
*
*  BINSAVE.ASM
*    Binary save through the UIO serial port. Uses the same
*    data record sync and jump record sync bytes as the 8800
*    format tapes.
*
*    Mike Douglas, Dec 3, 2023
*
*******************************************************************
SIOSR	equ	$F006		;UIO 6850 status register
SIODR	equ	$F007		;data register
MONITR	equ	$FFAB		;re-enter monitor

DATAREC	equ	$3C		;flag that a data record follows
JUMPREC	equ	$78		;flag that a jump record follows

*--------------------------------------------------------------------
*  Set the address range to save as shown below. Jump to $3E00
*  to execute the save operation.
*    $3E02-$3E03 First address to write  (BASIC $0000, ASM/EDT $0000)
*    $3E04-$3E05 Last address to write   (BASIC $1C5B, ASM/EDT $1CCC)
*    $3E06-$3E07 Jump-to (start) address (BASIC $0000, ASM/EDT $0107)
*--------------------------------------------------------------------
	org	$3E00		;loader near top of 1st 16K

	bra	start
curAddr	rmb	2		;start/current address
endAddr	rmb	2		;last address to write+1
jmpAddr	rmb	2		;execute address for loaded code
moreFlg	rmb	1		;non-zero = more data record to write
byteCnt	rmb	1		;count of bytes in a record

* Loop through the specified range of memory writing out 256 byte blocks
*    until finished (last block can be < 256 bytes)

start	ldaa	#3		;reset the UIO 6850
	staa	SIOSR
	ldaa	#$15		;8N1
	staa	SIOSR

	ldx	endAddr		;convert last location to last+1
	inx
	stx	endAddr

wrtRec	ldaa	endAddr+1	;compute endAddr-curAddr
	suba	curAddr+1	;A=LSB
	ldab	endAddr
	sbcb	curAddr		;B=MSB
	beq	haveCnt		;last write <= 256 bytes
	clra			;else, write 256 bytes

haveCnt	staa	byteCnt		;byteCnt = number of bytes to write
	stab	moreFlg		;non-zero if more data to write
	
	ldab	#DATAREC	;write data record flag byte
	bsr	uioWrt

	ldab	curAddr		;write address for loading
	bsr	uioWrt
	ldab	curAddr+1
	bsr	uioWrt

	ldab	byteCnt		;write count of bytes
	bsr	uioWrt

	ldx	curAddr		;X->data to write
	clra			;A=checksum

dataLp	ldab	0,x		;get next byte to write
	aba			;update checksum
	inx
	bsr	uioWrt
	dec	byteCnt
	bne	dataLp
	
	tab			;write checksum
	bsr	uioWrt

	stx	curAddr		;save the current address
	ldab	moreFlg		;more data to write?
	bne	wrtRec		;yes

* Data records all written. Write the jump record.

	ldab	#JUMPREC	;write jump record flag byte
	bsr	uioWrt

	ldab	jmpAddr		;write the jump-to address
	bsr	uioWrt
	ldab	jmpAddr+1
	bsr	uioWrt

	jmp	MONITR		;exit to monitor

* uioWrt - Write byte from B to the UIO serial port

uioWrt	pshb			;preserve byte to send

xmtWait ldab	SIOSR		;wait for xmit ready
	andb	#$02
	beq	xmtWait

	pulb			;get back byte to send
	stab	SIODR		;and send ti
	rts

	end
