*------------------------------------------------------------------------
* BPATCH.ASM - Patch Altair 680 Cassette BASIC to allow use of a separate
*   high speed reader/punch connected to the console port through an A/B
*   switch. The CLOAD and CSAVE commands are patched. The CLOAD patch
*   simply uses the console port instead of the casstte port. The CSAVE
*   patch provides a 3 second delay before punching starts to allow the
*   operator to flip an A/B port selection switch. During the punch 
*   operation, a per-character delay is used to reduce the output rate 
*   to about 49 cps.
*
*   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	CPS49

* 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

SAVEX	RMB	2		;SAVE AREA FOR X
		
* PACEPUN - Delay to punch at about 49 CPS

PACEPUN	STX	SAVEX-OFFSET	;PRESERVE X
	LDX	#CPSRATE	;49 CPS, 69 CPS, or no delay
PUNWAIT	DEX			;8US
	BNE	PUNWAIT		;8US
	LDX	SAVEX-OFFSET	;RESTORE X AND EXIT
	RTS

* CSAVE - DELAY 3 SECONDS, THEN 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	LDAA	#3		;DELAY 3 SECONDS
ONESEC	LDX	#62500		;1S = 62500*16US
LOOP	DEX			;8US
	BNE	LOOP		;8US
	DECA
	BNE	ONESEC

	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	JSR	CASWRT
	DECB
	BNE	PUNLOOP

	RTS

	FCB	0		;BASIC WANTS ZERO AT 1ST FREE LOCATION
ENDPAT	EQU	*

* MOVEPAT - Move patch code from load location to runtime location

MOVEPAT	STS	SAVESP		;PRESERVE THE STACK POINTER
	LDS	#PACEPUN-1	;SP->SOURCE
	LDX	#PACEPUN-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 MEM
	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 MOVEPAT

SAVESP	RMB	2		;SAVE AREA FOR STACK POINTER

*-------------------------------------------------------------------------
* Hooks into the Assembler/Editor
*-------------------------------------------------------------------------

* Patch the memory size routine to start at $1C68 instad of $1C18 to
*   prevent clobbering our patch code at the end of BASIC

	ORG	$1A79
	LDX	#$1C68

* Patch the cassette byte read routine (in place)

	ORG	$1283
CASREAD	LDAA	$F000		;CONSOLE STATUS
	RORA			;LSB IS READ DATA FALG
	BCC	CASREAD
	INX
	LDAA	$F001		;READ THE NEW BYTE
	RTS

* Patch the cassette byte save routine

	ORG	$1278
CASWRT	PSHB			;PRESERVE B
	TAB			;MONITOR WANTS BYTE IN B
	JSR	$FF81		;CALL MONITOR FOR CONSOLE OUTPUT
	PULB			;RESTORE B
	JMP	PACEPUN-OFFSET	;DELAY TO PACE AT 49CPS

* Patch 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	MOVEPAT

	END
