*******************************************************************
*
*  BINSAVE.ASM
*    Binary save through the console serial port. Uses the same
*    data record sync and jump record sync bytes as the 8800
*    format tapes. Provides a 3 second delay at the start to
*    allow switching to a high speed punch. Dies in a loop at
*    the end to prevent the terminal prompt from punching to
*    tape.
*
*    Mike Douglas, Nov 23, 2023
*
*******************************************************************

* Set CPSRATE for the desired punch rate

CPS49	EQU	1276		;49 CPS RATE
CPS69	EQU	893		;69 CPS RATE
NODLY	EQU	1		;NO DELAY

CPSRATE	EQU	NODLY

* Equates

SIOSR	equ	$F000		;UART status register
SIODR	equ	$F001		;data register
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 $1C69, ASM/EDT $1CD8)
*    $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	bsr	delay3		;delay 3 seconds for port A/B switch
	ldx	endAddr		;convert last 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	conWrt

	ldab	curAddr		;write address for loading
	bsr	conWrt
	ldab	curAddr+1
	bsr	conWrt

	ldab	byteCnt		;write count of bytes
	bsr	conWrt

	ldx	curAddr		;X->data to write
	clra			;A=checksum

dataLp	ldab	0,x		;get next byte to write
	aba			;update checksum
	inx
	bsr	conWrt
	dec	byteCnt
	bne	dataLp
	
	tab			;write checksum
	bsr	conWrt

	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	conWrt

	ldab	jmpAddr		;write the jump-to address
	bsr	conWrt
	ldab	jmpAddr+1
	bsr	conWrt

die	bra	die		;die here to let tape finish

* conWrt - Write byte from B to the console UART

conWrt	pshb			;preserve byte to send

wrWait	ldab	SIOSR		;wait for xmit ready
	andb	#$02
	beq	wrWait
	pulb			;get back byte to send
	stab	SIODR		;and send ti

	stx	saveX		;preserve X
	ldx	#CPSRATE	;delay for proper xmit rate
wrDly	dex			;8us
	bne	wrDly		;8us
	ldx	saveX		;restore X
	rts

* delay3 - Three second delay

delay3	ldaa	#3		;delay 3 seconds
oneSec	ldx	#62500		;1s = 62500*16us
delay	dex			;8us
	bne	delay		;8us
	deca
	bne	oneSec
	rts

* Data

saveX	rmb	2
	end
