====== 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 |}}