*-------------------------------------------------------------------
* BIPNCH - Punch specified sections of RAM to tape in binary for 
*    subsequent load with BILOAD. Multiple disjoint sections of
*    RAM can be specified as shown below. Specify the run address
*    of the payload at $A028. Specify the port number used for
*    output in $A02A.
*
*	$A014, Number of section specifications to follow
*	$A015-16, Start address section #1
*	$A017-18, End address section #1
* 	$A019-1A, Start address section #2
*	$A01B-1C, End address section #2
*	  etc.
*	$A028-29, Run address of loaded program
*	$A02A, I/O port of the punch (0-7)
*
*    Typed in and updated by Mike Douglas, 2/16/20
*-------------------------------------------------------------------

* EQUATES

MAX	EQU	$A014		;NUMBER OF SECTIONS TO PUNCH
BEGA	EQU	$A015
ENDA	EQU	$A017
PCT	EQU	$A028		;ENTRY ADDRESS FOR LOADED PROGRAM
PORTNUM	EQU	$A02A		;PUNCH OUTPUT PORT (0-7)

CONTRL	EQU	$E0E3		;RE-ENTER SWTBUG
TDRE	EQU	$02		;6850 TRANSMIT REGISTER EMPTY

* START OF PROGRAM

	ORG	$2100		;PLACE ABOVE THE PROGRAM BEING SAVED

	LDAA	#$80		;SET MSB OF PORT ADDRESS
	STAA	PORTADR

	LDAA	PORTNUM		;CONVERT PORT NUMBER TO ADDRESS LSB
	ANDA	#7		;LIMIT TO PORTS 0-7
	ASLA			;FOUR BYTES PER PORT
	ASLA
	STAA	PORTADR+1	;LSB OF PORT ADDRESS

	LDX	PORTADR		;X->PUNCH PORT ADDRESS

	CMPA	#$04		;USING CONSOLE PORT?
	BEQ	SKPRES		;YES, SKIP PORT RESET

	LDAA	#3		;RESET THE 6850
	STAA	0,X

SKPRES	LDAA	#$15		;8N1
	STAA	0,X

* MOVE THE ENTRY ADDRESS FOR THE LOADED PROGRAM INTO $A048-$A049
*    AND CREATE A NEW REGION THAT WRITES $A048-$A049 TO THE TAPE

START	LDAA	#1		;INIT CURRENT REGION NUMBER
	STAA	CNTR

	LDX	PCT		;MOVE ENTRY ADDRESS FROM $A028 INTO $A048
	STX	$A048

	LDAA	MAX		;ADD A NEW REGION FOR THE "G" VECTOR
	INC	MAX
		
	LDX	#BEGA		;COMPUTE A POINTER IN TW
	STX	TW
	ASLA			;FOUR BYTES PER ENTRY
	ASLA
	ADDA	#BEGA&$FF	;LSB OF NEW ENTRY
	STAA	TW+1
	LDX	TW		;X->BEG FOR NEW ENTRY

	LDAA	#$A0		;POINT TO $A048-$A048
	STAA	0,X		;START MSB
	STAA	2,X		;END MSB
	
	LDAA	#$48		;START LSB
	STAA	1,X
	INCA			;END LSB
	STAA	3,X

* BIPNCH - OUTER LOOP TO PUNCH A REGION

BIPNCH	JSR	PNON		;TURN ON PUNCH
	JSR	PNLDR		;PUNCH NULL LEADER

BEG	LDX	BEGA		;X->START OF REGION TO PUNCH
	STX	TW		;TW->CURRENT BYTE TO PUNCH

PUND10	LDAB	ENDA+1		;COMPUTE AB=BYTES LEFT IN REGION
	SUBB	TW+1
BEG1	LDAA	ENDA
	SBCA	TW
	BEQ	PUND25		;USE COUNT-1 IN B FOR LAST RECORD

	LDAB	#$FF		;ELSE, PUT 256 BYTES IN THE X1 RECORD

PUND25	LDAA	#'X		;PUNCH "X1" (VS S1)
	JSR	PUNBYTE
	LDAA	#'1
	JSR	PUNBYTE

	PSHB			;BYTE COUNT FOR RECORD ON STACK
	CLRB			;B=CHECKSUM, INIT TO ZERO
	TSX			;X->NUMBER OF BYTES (MINUS 1) IN RECORD
	BSR	PUN		;PUNCH THE BYTE COUNT-1
	
	PULA			;A=NUM BYTES-1 IN RECORD 
	INCA			;A=ACTUAL BYTES IN RECORD
	STAA	TEMP		;TEMP IS THE BYTE COUNTER

	LDX	#TW		;X->CURRENT ADDRESS
	BSR	PUN		;WRITE THE ADDRESS
	BSR	PUN

	LDX	TW		;X->DATA TO PUNCH

* PUND30 - PUNCH A FULL X1 RECORD OF BYTES (TYPICALLY 256)

PUND30	BSR	PUN		;PUNCH A BYTE
	DEC	TEMP		;DECREMENT BYTE COUNT
	BNE	PUND30		;PUNCH ALL BYTES IN X1 RECORD

	STX	TW		;SAVE CURRENT PUNCH LOCATION
	
	COMB			;FINISH CHECKSUM
	PSHB			;PUT ON STACK	
	TSX			;X->CHECKSUM IN MEMORY	
	BSR	PUN		;PUNCH CHECKSUM
	PULB			;CLEAN UP STACK

	LDX	TW		;X->NEXT BYTE TO PUNCH
	DEX			;X->LAST BYTE PUNCHED
	
CP1	CPX	ENDA		;LAST BYTE OF REGUON PUNCHED?
	BNE	PUND10		;NO, CONTINUE

* COMPLETE REGION PUNCHED. MOVE TO NEXT REGION. SELF-MODIFY CODE
*    TO USE THE NEXT REGION'S POINTERS

	LDAA	CNTR		;ANY MORE REGIONS TO PUNCH?
	CMPA	MAX
	BEQ	EXIT		;NO

	INC	CNTR		;INCREMENT REGION COUNTER

	LDAA	BEG+2		;MODIFY CODE TO POINT TO
	ADDA	#4		;...NEXT REGION'S POINTERS
	STAA	BEG+2

	LDAA	BEG1+2
	ADDA	#4
	STAA	BEG1+2
	STAA	CP1+2

	INCA	
	STAA	PUND10+2

	BRA	BIPNCH

* PNON - PUNCH ON
* PNLDR - PUNCH NULL LEADER

PNLDR	LDAB	#5		;PUNCH 5 NULL LEADER BYTES

PNULL	CLRA	
	JSR	PUNBYTE
	DECB	
	BNE	PNULL

	RTS	

* PUN - PUNCH THE BYTE POINTED TO BY X. UPDATE THE CHECKSUM AND INCREMENT
*    THE POINTER IN X. IF THE BYTE PUNCHED TURNED OFF THE PUNCH, TURN
*    THE PUNCH BACK ON.

PUN	LDAA	0,X		;PUNCH BYTE AT (X)
	JSR	PUNBYTE

	ADDB	0,X		;UPDATE CHECKSUM
	LDAA	0,X
	INX		

*	CMPA	#$14		;DID PUNCH GET TURNED OFF?
*	BEQ	PNON		;YES, TURN IT BACK ON

*	CMPA	#$94		;IN CASE $94=$14
*	BEQ	PNON

	RTS

* EXIT - ALL REGIONS PUNCHED. WRITE AN X9 RECORD AND EXIT TO SWTBUG

EXIT	LDAA	#'X		;WRITE X9 TO SIGNAL END
	JSR	PUNBYTE
	LDAA	#'9
	JSR	PUNBYTE
	JMP	CONTRL		;EXIT TO SWTBUG

PNON	LDAA	#$12		;DC2 - PUNCH ON
	JSR	PUNBYTE
	RTS	

* PUNBYTE - PUNCH BYTE THROUGH PORT AT THE ADDRESS IN PORTADR

PUNBYTE	STX	SAVEX		;PRESERVE X
	PSHA			;PRESERVE BYTE TO PUNCH
	LDX	PORTADR		;X->PUNCH PORT

PUNWAIT	LDAA	0,X		;WAIT FOR PORT TO BE READY
	ANDA	#TDRE
	BEQ	PUNWAIT

	PULA			;A=BYTE TO SEND
	STAA	1,X		;SEND IT

	LDX	SAVEX		;RESTORE X
	RTS			;AND EXIT

* DATA AREA

CNTR	RMB	1
TW	RMB	2		;BUFFER POINTER
SAVEX	RMB	2		;REGISTER X SAVE
PORTADR	RMB	2		;PUNCH PORT ADDRESS
TEMP	RMB	1

	END		
