*------------------------------------------------------------------------
* BPATCH.ASM - Patch Altair 680 Cassette BASIC to allow use of a high
*   speed reader/punch connected to the UIO serial port as if it was
*   the cassette interface.
*
*   Mike Douglas, Dec 3, 2023
*------------------------------------------------------------------------

* UIO Equates

UIOSR	EQU	$F006		;UIO SERIAL PORT
UIODR	EQU	$F007
RDRF	EQU	$01		;RECEIVE DATA READY
TDRE	EQU	$02		;TRANSMIT READY

* New patch code loads at the end of BASIC but gets moved to a lower
*   location after BASIC initialization completes.

LOADLOC	EQU	$1C18		;LOAD LOCATION AT END OF BASIC
RUNLOC	EQU	$1A48		;RUN LOCATION AFTER BASIC INIT
OFFSET	EQU	LOADLOC-RUNLOC

*-------------------------------------------------------------------------
* This patch code is loaded at the end of BASIC, initially starting
*   at $1C18. It is moved down to $1A48 for execution after BASIC
*   completes its initialization.
*-------------------------------------------------------------------------
	ORG	LOADLOC

CASWRT	PSHA			;PRESERVE BYTE TO SEND

WAITRDY	LDAA	UIOSR		;WAIT FOR OK TO XMIT
	ANDA	#TDRE
	BEQ	WAITRDY
	
	PULA			;RESTORE AND OUTPUT BYTE
	STAA	UIODR
	RTS

* CSAVE - PUNCH NULL LEADER, THEN $D3 THREE TIMES FOLLWED BY A 
*    GARBAGE "FILE NAME" BYTE (IGNORED). CALL THE ORIGINAL LOOP
*    TO PUNCH PROGRAM MEMORY, THEN PUNCH TRAILING NULLS AND EXIT

CSAVE	BSR	NULL48		;WRITE 48 NULLS

	LDAB	#4		;WRITE THREE $D3 BYTES AND GARBAGE
	LDAA	#$D3		;   FILE NAME BYTE (IGNORED)
	BSR	PUNLOOP

	LDX	$007A		;X=START OF PROGRAM MEMORY
	JSR	$11FC		;PUNCH THE PROGRAM
*				;FALL INTO NULL48
* NULL48 - PUNCH 48 NULLS

NULL48	LDAB	#48		;48 NULLS
	CLRA

PUNLOOP	BSR	CASWRT
	DECB
	BNE	PUNLOOP

	RTS

	FCB	0		;BASIC WANTS ZERO AT 1ST FREE LOCATION
ENDPAT	EQU	*

* MOVPAT - Move patch code from load location to runtime location

MOVPAT	STS	SAVESP		;PRESERVE THE STACK POINTER
	LDS	#CASWRT-1	;SP->SOURCE
	LDX	#CASWRT-OFFSET	;X->DESTINATION

MOVLOOP	PULA			;MOVE BYTE FROM SOURCE TO DESTINATION
	STAA	0,X
	INX
	CPX	#ENDPAT-OFFSET	;DONE?
	BNE	MOVLOOP

	LDX	#ENDPAT-OFFSET  ;END OF PATCH IS START OF BASIC MEMORY
	STX	$007A		;GIVE TO BASIC
	
	LDAA	$007A		;REPLACE INSTRUCTIONS CLOBBERED BY PATCH
	LDAB	$007B

	LDS	SAVESP		;RESTORE STACK AND EXIT
	RTS
	
* Temp data area for MOVPAT

SAVESP	RMB	2

*-------------------------------------------------------------------------
* Hooks into the Assembler/Editor
*-------------------------------------------------------------------------

* Patch the memory size routine to start at $1C48 instad of $1C18 to
*   prevent clobbering our patch code at the end of BASIC

	ORG	$1A79
	LDX	#$1C5B

* Patch the cassette byte save routine to jump to CASWRT

	ORG	$1278
	JMP	CASWRT-OFFSET

* Patch the cassette byte read routine (in place)

	ORG	$1283
CASREAD	LDAA	UIOSR		;UIO 6850 STATUS
	RORA			;LSB IS READ DATA FALG
	BCC	CASREAD

	INX
	LDAA	UIODR		;READ THE NEW BYTE
	RTS

* Patch the CSAVE routine to jump to CSAVE in our patch area

	ORG	$11F0
	JMP	CSAVE-OFFSET

* Patch CLOAD to ignore the filename character

	ORG	$1239
	NOP
	NOP

* When BASIC init has finished, move patch code from load location to
*    the runtime location

	ORG	$1B31
	NOP
	JSR	MOVPAT

	END
