This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
blast_corps:eeprom_map [2016/10/14 16:35] queueram created Blast Corps EEPROM Memory Map |
blast_corps:eeprom_map [2017/06/23 10:49] (current) shygoo ↷ Links adapted because of a move operation |
||
---|---|---|---|
Line 27: | Line 27: | ||
| 0x100 | 0xF0 | [[#level_times|Level Times]] | | | 0x100 | 0xF0 | [[#level_times|Level Times]] | | ||
| 0x1F0 | 0x8 | Language \\ 0x1982198219821982 = English \\ 0x1945194519451945 = German | | | 0x1F0 | 0x8 | Language \\ 0x1982198219821982 = English \\ 0x1945194519451945 = German | | ||
- | | 0x1F8 | 0x8 | Footer | | + | | 0x1F8 | 0x8 | Footer \\ 0x2704197125121981 = Before saving rest of EEPROM data \\ 0x87569AB6CD076AEC = After saving rest of EEPROM data | |
===== Level Times ===== | ===== Level Times ===== | ||
- | There is a time recorded for each level as an 4-byte unsigned integer in big endian in units of 1/655360 of a second. To convert these values to seconds, divide the value by 655360. e.g., if the value is 0x00E4554E = 14964046, then 14964046/655360 = 22.8 seconds. | + | 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): |
+ | <code c>record[2] = 0x55 ^ record[0]; | ||
+ | record[3] = 0xFF ^ record[0] ^ record[1] ^ record[2];</code> | ||
+ | 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 ===== | ===== 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. | 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. | ||
- | <code c>u8 ComputeChecksumByte(u8 *data) // 80205760 | + | <code c> |
+ | // helper function for checksum update routine below | ||
+ | static u8 ComputeChecksumByte(u8 *data) // 80205760 | ||
{ | { | ||
u8 cksum = 0; | u8 cksum = 0; | ||
u8 key; | u8 key; | ||
- | for (int i = 0; i < 33; i++) { // 80205760 | + | for (int i = 0; i < 33; i++) { |
- | for (int j = 7; j >= 0; j--) { // 80205760 | + | for (int j = 7; j >= 0; j--) { |
if (cksum & 0x80) { | if (cksum & 0x80) { | ||
key = 0x85; | key = 0x85; | ||
Line 49: | Line 53: | ||
if (i == 0x20) { | if (i == 0x20) { | ||
cksum = cksum & 0xFF; | cksum = cksum & 0xFF; | ||
- | } else { // 80205760 | + | } else { |
u8 mask = data[i] & (1 << j); | u8 mask = data[i] & (1 << j); | ||
u8 bit = mask ? 1 : 0; | u8 bit = mask ? 1 : 0; | ||
Line 60: | Line 64: | ||
} | } | ||
+ | // 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 UpdateChecksum(u8 *eeprom, int length) // 801F2C84 | ||
{ | { | ||
- | u8 buf[4]; // sp28-sp2B | + | u8 cksum[4]; |
int blocks = (length + 0x7F) >> 7; | int blocks = (length + 0x7F) >> 7; | ||
// zero out existing EEPROM checksum and local buffer | // zero out existing EEPROM checksum and local buffer | ||
- | for (int i = 0; i < 4; i++) { // .Lproc_801F2C84_28: 801F2CAC | + | for (int i = 0; i < 4; i++) { |
- | buf[i] = 0; | + | cksum[i] = 0; |
- | eeprom[length + i - 4] = buf[i]; | + | eeprom[length + i - 4] = 0; |
- | } // 801F2CE8 | + | } |
if (blocks > 0) { | if (blocks > 0) { | ||
- | for (int i = 0; i < blocks; i++) { //.Lproc_801F2C84_78: | + | for (int i = 0; i < blocks; i++) { |
- | for (int j = 0; j < 4; j++) { //.Lproc_801F2C84_7C: | + | for (int j = 0; j < 4; j++) { |
int offset = (i << 7) + (j << 5); | int offset = (i << 7) + (j << 5); | ||
if (offset < length) { | if (offset < length) { | ||
- | u8 cksum = ComputeChecksumByte(eeprom + offset); | + | u8 ckbyte = ComputeChecksumByte(eeprom + offset); |
- | buf[j] += (cksum & 0xFF); | + | cksum[j] += (ckbyte & 0xFF); |
} | } | ||
} | } | ||
Line 81: | Line 87: | ||
} | } | ||
// copy the checksum into the EEPROM data | // copy the checksum into the EEPROM data | ||
- | for (int i = 0; i < 4; i++) { // .Lproc_801F2C84_F8: | + | for (int i = 0; i < 4; i++) { // 801F2C84 |
- | eeprom[length + i - 4] = buf[i]; | + | eeprom[length + i - 4] = cksum[i]; |
} | } | ||
return 0; | return 0; | ||
Line 102: | Line 108: | ||
===== Erasing EEPROM ===== | ===== 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" | 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" | ||
- | {{:bc:erase_saved_game.png?direct&200 |}} | + | {{blast_corps:erase_saved_game.png?direct&200 |}} |