Metropoli BBS
VIEWER: gxdump.s MODE: TEXT (ASCII)
**********************************************************************
*		GX Memory Dump Program
**********************************************************************

**********************************************************************
* This program dumps the entire G/GX memory using xmodem protocol.
* The output file is a direct binary image of ROM, most programs
* using the dump use nibble/byte storage so you may need a converter.
*
* The program can also handle covered memory banks. Since the program
* may reside anywhere it has to use some of the lower RAM area to
* store the covered access subroutines. uart_buffer is not used so that
* area is chosen.
*
* To make the program simple the following subroutines are used:
*
* CopyBlock	- copies next block to be sent to IRAMBUFF
* SendBlock	- sends the block in IRAMBUFF
*
* Special care is taken for the ROM areas handling bankswitching
* and the area not accessible as a bank (memory test code)
*
*		(C) Mika Heiskanen, 1994
*		--> mheiskan@gamma.hut.fi
**********************************************************************

**********************************************************************
*		XMODEM SPECIAL CODES
**********************************************************************
ASSEMBLE
SOH	EQU 1		Not CRC
EOT	EQU 4		End Of Transmission
ACK	EQU 6		Acknowledge block
NAK	EQU 15		Block was not ok
RPL

*******************************************************************************
*	Unsupported entries
*******************************************************************************
ASSEMBLE
=AllowPRLCD	EQU #324C8
=WIPEOUT	EQU #0675C
=xBUFLEN	EQU #22087
=xSRECV		EQU #21E95

=G_XeqInPlace	EQU #7008B	* #026CA doesn't restore bank
=ACCESSD	EQU #726A1	* Access #82000-#8FFFF
=ACCESSE	EQU #72386	* Access #90000-#BFFFF
=ACCESSF	EQU #70B38	* Access #C0000-#FFFFF

=G_IRAMBUFF	EQU #800F5
=G_uart_buffer	EQU #80319
* XeqInPlace moves RAM to #C0000, so:
=U_IRAMBUFF	EQU #C00F5
=U_uart_buffer	EQU #C0319

RPL
*******************************************************************************
::
  CK0NOLASTWD
* Init uart
  AllowPRLCD xBUFLEN DROP xSRECV 2DROP

  CODE

* Register usage:
*
* R0	->address
* R1	( * The ACPTR copy subroutine uses this * )
* R2	block number
* R3	CHK counter
* R4	access routine address

* Initialize variables
		GOSBVL	=SAVPTR
		A=0	A
		R0=A	A		Current address
		A=A+1	A
		R2=A	B		Block number

		ST=0	15		Interrupts off
		GOSUB	InitCopier	Setup the copy subroutine
DumpLoop	GOSUB	CopyBlock	Copy next block to IRAMBUFF
		GOC	DumpLast
		GOSUB	SendBlock
		GOTO	DumpLoop
DumpLast	GOSUB	SendBlock
		ST=1	15
		GOVLNG	=GETPTRLOOP

**********************************************************************
* CopyBlock utility:  Copy a single xmodem block of memory to IRAMBUFF.
* Use proper access methods when applicable.
* Entry:	R0[A]	->address
* Exit:		R0[A]	->tail		CS if set to 0!
*		XMODEM block in IRAMBUFF
* Note:		Assumes bank boundary is not crossed during copy.
*		No worries if using xmodem block size.
**********************************************************************
CopyBlock	A=R0	A
		LC(5)	#82000		Address of first bank
		?A>=C	A
		GOYES	copybank
		LC(5)	#80000
		?A>=C	A
		GOYES	copyhidden
		D1=(5)	=G_IRAMBUFF	->copy to
		LC(5)	#7F000		Prevent bank switching
		?A=C	A
		GOYES	copyzeros
		D0=A			->address
		LC(5)	256		256 nibbles
		A=A+C	A
		R0=A	A
		GOVLNG	=MOVEDOWN	Returns CC
* Copier for area #7F000-#7F0FF = bank switch area
copyzeros	LC(5)	256
		A=A+C	A
		R0=A	A
		GOVLNG	=WIPEOUT	Returns CC
* Copier for area #80000-#81FFF = covered ROM (NOT ACCESSD!)
copyhidden	LC(5)	(=U_uart_buffer)+(RomFetch)-(BankFetch)
		GOSBVL	=G_XeqInPlace
		RTNCC			CC: Not end yet
		
copybank	LC(5)	#90000
		?A<C	A
		GOYES	copybankd
		LC(5)	#C0000
		?A>=C	A
		GOYES	copybankf
copybanke	LC(5)	=ACCESSE	* Area #90000-#BFFFF
		GONC	copybankx
copybankd	LC(5)	=ACCESSD	* Area #82000-#8FFFF
		GOC	copybankx
copybankf	LC(5)	=ACCESSF	* Area #C0000-#FFFFF

copybankx	R4=C	A		Set access subroutine
		GOVLNG	=G_uart_buffer	Call the copy subroutine
**********************************************************************
* Init a copier to uart_buffer
**********************************************************************
InitCopier	GOSUB	PassCopy

* This code will go to uart_buffer

BankFetch	P=	0		Uncover bank
		GOSUB	CallAccess
		LC(5)	=G_IRAMBUFF
		R1=C	A		->copy to
		LA(5)	256		256 nibbles
		P=	2		Copy A[A] nibbles from R0[A] to R1[A]
		C=0	S		Copy *to* RAM
		GOSUB	CallAccess
		C=R0	A		->copytail
		?C=0	A		Return CS if copied last block
		RTNYES
		RTNCC
CallAccess	C=R4.F	A		->access subroutine	(Keep R4.F! )
		PC=C

RomFetch	A=R0	A
		D0=A
		D1=(5)	=U_IRAMBUFF
		LC(5)	256
		A=A+C	A
		R0=A	A
		GOVLNG	=MOVEDOWN

* Code ends here

PassCopy	A=PC			Tail address
		C=RSTK			Start address
		D0=C
		C=A-C	A		nibbles
		D1=(5)	=G_uart_buffer
		GOVLNG	=MOVEDOWN

**********************************************************************
* Send block in IRAMBUFF using xmodem protocol.
* Entry:	R2[B] = block number
* Use:		R3[B] = CHK value
**********************************************************************

SendBlock

* Send opening sequence

		LC(2)	SOH
		GOSUB	SendChar
		C=R2	B
		GOSUB	SendChar
		C=R2	B
		C=-C-1	A
		GOSUB	SendChar

		D0=(5)	=G_IRAMBUFF	->chars to send
		C=0	A
		R3=C	A		Init CHK
		LC(2)	128-1		Characters to send
		D=C	A
* Send data itself
SendBlockLp	C=DAT0	B		char
		D0=D0+	2
		A=R3	B		Update CHK
		A=A+C	A
		R3=A	B
		GOSUB	SendChar
		D=D-1	A
		GONC	SendBlockLp
* Send CHK value
		C=R3	B		Send CHK after block
		GOSUB	SendChar
* And wait for ack
		GOSUB	WaitAck
		LC(2)	NAK		Not ok?
		?A=C	B
		GOYES	SendBlock	Yep - try again
		LC(2)	ACK
		?A=C	B
		GOYES	sndgotack
		LC(2)	#18		Abort?
		?A#C	B
		GOYES	SendBlock	Nope - try again then
		GOTO	ExitNow		Abort
* Got ack - update things
sndgotack	A=R2	B
		A=A+1	A		block number++
		R2=A	B
		RTN

*******************************************************************************
* Wait response to send data
**********************************************************************
WaitAck		D1=(5)	=IOC
		LC(2)	#88
		DAT1=C	B
		D1=(2)	=RCS
WaitAckLp	GOSUB	?Exit
		C=DAT1	B
		?CBIT=0	0
		GOYES	WaitAckLp	Wait until RBF
		LCHEX	8
		DAT1=C	1		RX
		D1=(2)	=RBR
		A=DAT1	B
		RTN
**********************************************************************
* Send character in C[B]
**********************************************************************
SendChar	A=C	B
		D1=(5)	=IOC
		LC(2)	#B8
		DAT1=C	B
		D1=(2)	=TCS
SendCharLp	C=DAT1	B
		?CBIT=1	0
		GOYES	SendCharLp	Wait until TBF not set
		D1=(2)	=TBR
		DAT1=A	B
		RTN
**********************************************************************
* Exit if any key has been pressed
**********************************************************************
?Exit		C=0	A
		GOSBVL	=CINRTN
		?C=0	A
		RTNYES
		LC(2)	#18		Let the other side know
		D1=(5)	=TBR
		DAT1=C	B
ExitNow		ST=1	15
		GOVLNG	=GETPTRLOOP		
**********************************************************************
  ENDCODE
  FLUSHRSBUF CLOSEUART
  FLUSH
;
[ RETURN TO DIRECTORY ]