====== EEPROM Memory Map ======
Blast Corps uses a 512 byte [[https://en.wikipedia.org/wiki/EEPROM|EEPROM]] in the cartridge to save game state of levels unlocked, record times, and tutorials given. A copy of the EEPROM data is stored at 80364A40 in RAM.
===== Top level structure =====
^ Offset ^ Length ^ Description ^
| 0x000 | 0x8 | Name (ASCII name entered during game start) |
| 0x008 | 0x1 | Selected Level |
| 0x009 | 0x1 | Unknown? |
| 0x00A | 0x2 | Points |
| 0x00C | 0x1 | Rank |
| 0x00D | 0x3 | Unknown? |
| 0x010 | 0x4 | Vehicles |
| 0x014 | 0x4 | Total Accumulated Money |
| 0x018 | 0x3C | Level Medals |
| 0x054 | 0x3C | Level Paths |
| 0x090 | 0x1 | Scientists |
| 0x091 | 0x1 | Event |
| 0x092 | 0x3C | Level Vehicles |
| 0x0CE | 0x12 | Tutorials |
| 0x0E0 | 0xE | Unknown? |
| 0x0EE | 0x1 | Cut Scenes |
| 0x0EF | 0x4 | Unknown? |
| 0x0F3 | 0x1 | Control Mode |
| 0x0F4 | 0x8 | Unknown? |
| 0x0FC | 0x4 | [[#checksum|Checksum]]|
| 0x100 | 0xF0 | [[#level_times|Level Times]] |
| 0x1F0 | 0x8 | Language \\ 0x1982198219821982 = English \\ 0x1945194519451945 = German |
| 0x1F8 | 0x8 | Footer \\ 0x2704197125121981 = Before saving rest of EEPROM data \\ 0x87569AB6CD076AEC = After saving rest of EEPROM data |
===== Level Times =====
The record time is stored for each level as a 2-byte integer in big endian in units of hundredths of a second followed by two bytes of checksum. The checksum is computed as follows (where ^ is XOR):
record[2] = 0x55 ^ record[0];
record[3] = 0xFF ^ record[0] ^ record[1] ^ record[2];
For example, if the record value is 0x00E4554E, the time is 0x00E4 = 228 = 22.8 seconds. \\ Checksum verifies because 0x00 ^ 0x55 = 0x55, and 0xFF ^ 0x00 ^ 0xE4 ^ 0x55 = 0x4E
===== Checksum =====
The 4-byte checksum at 0xFC is computed using functions that are stored in the hd_front_end_text.raw gzip file. The UpdateChecksum/801F2C84 function takes a pointer to the start of the EEPROM data in A0 and an offset to compute the checksum over and store result in A1. It uses helper function ComputeChecksumByte/80205760 to compute each round.
// helper function for checksum update routine below
static u8 ComputeChecksumByte(u8 *data) // 80205760
{
u8 cksum = 0;
u8 key;
for (int i = 0; i < 33; i++) {
for (int j = 7; j >= 0; j--) {
if (cksum & 0x80) {
key = 0x85;
} else {
key = 0x00;
}
cksum = cksum << 1;
if (i == 0x20) {
cksum = cksum & 0xFF;
} else {
u8 mask = data[i] & (1 << j);
u8 bit = mask ? 1 : 0;
cksum |= bit;
}
cksum = cksum ^ key;
}
}
return cksum;
}
// usually called with base address of EEPROM data and length = 0x100
// this will update checksum at eeprom[0x100 - 4]
u8 UpdateChecksum(u8 *eeprom, int length) // 801F2C84
{
u8 cksum[4];
int blocks = (length + 0x7F) >> 7;
// zero out existing EEPROM checksum and local buffer
for (int i = 0; i < 4; i++) {
cksum[i] = 0;
eeprom[length + i - 4] = 0;
}
if (blocks > 0) {
for (int i = 0; i < blocks; i++) {
for (int j = 0; j < 4; j++) {
int offset = (i << 7) + (j << 5);
if (offset < length) {
u8 ckbyte = ComputeChecksumByte(eeprom + offset);
cksum[j] += (ckbyte & 0xFF);
}
}
}
}
// copy the checksum into the EEPROM data
for (int i = 0; i < 4; i++) { // 801F2C84
eeprom[length + i - 4] = cksum[i];
}
return 0;
}
===== EEPROM Related Functions =====
The EEPROM functions are all stored in the hd_front_end_text.raw gzip file. In the (U) (1.0) ROM, these are inflated to 0x801E7000.
^ RAM/offset ^ Function ^
| 801F1944/00A944 | int ManageEeprom(u8 block, u8 mode) |
| 801F2C84/00BC84 | u8 UpdateChecksum(u8 *eeprom, int length) |
| 80205760/01E760 | u8 ComputeChecksumByte(u8 *data) |
| 80202850/01B850 | s32 osEepromProbe(OSMesgQueue *mq) |
| 802042A0/01D2A0 | s32 osEepromLongWrite(OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes) |
| 802043E0/01D3E0 | s32 osEepromLongRead(OSMesgQueue *mq, u8 address, u8 *buffer, int nbytes) |
| 80204BE0/01DBE0 | s32 osEepromWrite(OSMesgQueue *mq, u8 address, u8 *buffer) |
| 802050C0/01E0C0 | s32 osEepromRead(OSMesgQueue *mq, u8 address, u8 *buffer) |
===== Erasing EEPROM =====
The EEPROM can be cleared by holding the 'Start' button while the during reset and startup of the game. You will then be prompted to "Erase Saved Game"
{{blast_corps:erase_saved_game.png?direct&200 |}}