*******************************************************************
*
*  BINSAVE.ASM
*    Binary save for the Altair 680 cassette interface board.
*    Uses the same data record sync and jump record sync bytes
*    as the 8800 format tapes.
*
*    Mike Douglas, July 24, 2022
*
*******************************************************************
OUTCH	equ	$FF81		;display char from B (in monitor)
OUT2H	equ	$FF6D		;output A in hex
SIOSR	equ	$F010		;cassette UART status register
SIODR	equ	$F011		;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, EDT-ASM $0000)
*    $3E04-$3E05 Last address to write   (BASIC $1C18, EDT-ASM $1CD8)
*    $3E06-$3E07 Jump-to (start) address (BASIC $0000, EDT-ASM $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	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	casWrt

	ldab	curAddr		;write address for loading
	bsr	casWrt
	ldab	curAddr+1
	bsr	casWrt
	
	ldab	#$0D		;display the address we're on
	jsr	OUTCH
	ldab	#$0A
	jsr	OUTCH
	ldaa	curAddr
	jsr	OUT2H
	ldaa	curAddr+1
	jsr	OUT2H

	ldab	byteCnt		;write count of bytes
	bsr	casWrt

	ldx	curAddr		;X->data to write
	clra			;A=checksum

dataLp	ldab	0,x		;get next byte to write
	aba			;update checksum
	inx
	bsr	casWrt
	dec	byteCnt
	bne	dataLp
	
	tab			;write checksum
	bsr	casWrt

	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	casWrt

	ldab	jmpAddr		;write the jump-to address
	bsr	casWrt
	ldab	jmpAddr+1
	bsr	casWrt

	jmp	MONITR		;exit to monitor

* casWrt - Write byte from B to the cassette UART

casWrt	pshb
wrWait	ldab	SIOSR
	bmi	wrWait

	pulb
	stab	SIODR
	rts

	end
