e01b- go_verifyFlash
e024- go_writeFlashOS
e027- go_readFlash
All three of these functions can access anywhere in memory -- in the game file, the FAT, the directory, and other files.
The verifyFlash and readFlash are similar and look like this:
**
** verifyFlash
** This call verifies 128 bytes of data into the FLASH ROM at a specified
location.
** It is unrestricted.
**
** Input variables (bank 1):
** 17D FL_ADDR_MSB Flash
read/write start address (24 bits big endian)
** 17E FL_ADDR_MED
** 17F FL_ADDR_LSB
** 180-1FF
Data to write
**
** Returns: 00=data verified
** else=data
didn't verify
Note that the variable addresses are in the $100-$1ff range, meaning that they are in the user's RAM bank.
The write is called with this:
**
** WriteflashOS code
** This call writes 128 bytes of data into the FLASH ROM at a specified
location.
** It is unrestricted.
**
** Input variables (bank 1):
** 17C FL_FINAL
1=wait for last byte to finalize writing [exact usage unknown, I'd recommend
use a 1]
** 17D FL_ADDR_MSB Flash
read/write start address (24 bits big endian)
** 17E FL_ADDR_MED
** 17F FL_ADDR_LSB
** 180-1FF
Data to write
**
Now, if you recall, the verify and read functions are made accessible to the game developer through the use of entrypoints at $110 (verify) and $120 (read).
The actual code at these locations in the other bank looks somewhat
like this:
0110- CALLF go_verifyFlash ;do the bulk of the routine
at $E01B
0113- NOT1 EXT, 0
;prepare to execute code in the user's bank
0115- JMPF L0115
;exit to user code at $115
We can use this to our advantage - since we know where there is a NOT1 EXT,0 and a JMPF to our code, we can pretend to call from this routine. The basic idea is that we simulate the CALLF at $110 (OS bank) with some of our magic code (in our bank). A CALLF isn't anything really special -- it basically pushes the return address on the stack (lower byte first, then upper byte) and jumps to the desired place. We'll just (manually) push a return address of $113 onto the stack and then jump to $E024 in the OS code.
== WARNING: I HAVEN'T TESTED THIS CODE: ==
.org $110
; entry to verify memory routine
0110- b8 0d | verifyFlash: NOT1 EXT,
0 ; prepare to execute code in
other bank
0112- 21 01 10 |
JMPF verifyFlash ; call the routine above
0115- a0 | L0115:
RET
; return
.org somewhere-in-your-normal-code
wrflash: LD #<$0113
;get LSB of return address
PUSH ACC
LD #>$0113 ;get MSB of return
address
PUSH ACC
NOT1 EXT, 0 ; prepare to execute code
in other bank
JMPF $E024 ; call writeFlashOS,
return to the RET instruction at $115.
To use this function, just call wrflash and it will return. The sequence of execution is:
your program calls wrflash
wrflash jumps to $e024 in OS memory
$e024 does its thing and then performs a RET to $113 (also in OS code)
$113 switches execution banks and jumps to the user code at $115 (in
the user bank)
$115 has a RET and returns to your code.
Again, this is all untested, but should work. And, of course, you could
lose a lot of data by using this function.
- john