====== EEPROM Memory Map ====== Mario Kart 64 uses a 512 byte [[https://en.wikipedia.org/wiki/EEPROM|EEPROM]] unit to save time trial records and the selected sound mode. A mirror of EEPROM data is kept at 8018EB90 in RAM. ===== Top level structure ===== ^ Offset ^ Length ^ Description ^ | 0x000 | 24 | Luigi raceway [[#record_format|record set]] | | 0x018 | 24 | Moo Moo Farm record set | | 0x030 | 24 | Koopa Troopa Beach record set | | 0x048 | 24 | Kalimari Desert record set | | 0x060 | 24 | Toad's Turnpike record set | | 0x078 | 24 | Frappe Snowland record set | | 0x090 | 24 | Choco Mountain record set | | 0x0A8 | 24 | Mario Raceway record set | | 0x0C0 | 24 | Wario Stadium record set | | 0x0D8 | 24 | Sherbet Land record set | | 0x0F0 | 24 | Royal Raceway record set | | 0x108 | 24 | Bowser's Castle record set | | 0x120 | 24 | D.K's Jungle Parkway record set | | 0x138 | 24 | Yoshi Valley record set | | 0x150 | 24 | Banshee Boardwalk record set | | 0x168 | 24 | Rainbow Road record set | | 0x180 | 4 | 50cc trophy information | | 0x181 | 4 | 100cc trophy information | | 0x182 | 4 | 150cc trophy information | | 0x183 | 4 | Extra trophy information | | 0x184 | 1 | Audio setting | | 0x185 | 1 | Unused, padding | | 0x186 | 2 | [[#x186|Checksum of 0x180-0x184]] | | 0x188 | 12 | Copies of Mushroom Cup 1st Record Times | | 0x194 | 12 | Copies of Flower Cup 1st Record Times | | 0x1A0 | 12 | Copies of Mushroom Cup Lap Record Times | | 0x1AC | 12 | Copies of Flower Cup Lap Record Times | | 0x1B8 | 6 | Unknown (Padding?) | | 0x1BE | 2 | [[[#x1BE_and_0x1F6|Checksum of 0x188-0x1BD]] | | 0x1C0 | 12 | Copies of Star Cup 1st Record Times | | 0x1CC | 12 | Copies of Special Cup 1st Record Times | | 0x1D8 | 12 | Copies of Star Cup Lap Record Times | | 0x1E4 | 12 | Copies of Special Cup Lap Record Times | | 0x1F0 | 6 | Unknown (Padding?) | | 0x1F6 | 2 | [[#x1BE_and_0x1F6|Checksum of 0x1C0-0x1F5]] | | 0x1FC | 1 | Copy of audio setting (0x184) | | 0x1FD | 1 | Copy of Unused, padding? (0x185) | | 0x1FE | 2 | Copy of [[#x186|Checksum of 0x180-0x184]] | ===== Course record set ===== For each course, there is a 24 byte structure that contains the five best completion records and the best lap record. There is an additional byte which indicates whether or not any records have been saved for the set, and another byte which could be a checksum. ^ Offset ^ Length ^ Description ^ | 0x000 | 3 | 1st record | | 0x003 | 3 | 2nd record | | 0x006 | 3 | 3rd record | | 0x009 | 3 | 4th record | | 0x00C | 3 | 5th record | | 0x00F | 3 | Best lap record | | 0x012 | 1 | Records exist (00 or 01) | | 0x013 | 4 | Unknown (Unused?) | | 0x017 | 1 | [[#record_checksum|Record Checksum]] | {{mario_kart_64:yjuty.png?200}} ===== Record Format ===== Record entries are 24 bits each and are stored with little endian byte ordering: ''tttttttt tttttttt cccctttt'' Where ''t'' is a 20 bit value for the completion time in centiseconds and ''c'' is a 4 bit ID of the character used in the trial. If a record has a time greater than or equal to 100 minutes, it is not displayed. Valid character IDs for ''c'' are as follows: ^ ID ^ Character ^ | 0 | MARIO | | 1 | LUIGI | | 2 | YOSHI | | 3 | TOAD | | 4 | D.K. | | 5 | WARIO | | 6 | PEACH | | 7 | BOWSER | The default value applied to record entries is ''0xC02709'', which is 100 minutes and Mario as the character selection. ===== Checksums ===== ==== Record Checksum ==== Each record contains a 1-byte checksum at offset 0x17 and is computed as follows: unsigned char RecordChecksum(unsigned char data[], int offset) { int checksum = 0; for (int rec = 0; rec < 7; rec++) { for (int i = 0; i < 3; i++) { unsigned char val = data[offset + rec * 3 + i]; checksum += (val * (i + 1)) + rec; } } return (unsigned char)(checksum & 0xFF); } ==== 0x186 ==== 0x186 is a checksum of offsets 0x180-0x184 and is computed by procedure at 800B492C and 0x187 is computed by procedure at 800B49E4 eeprom[0x186] = (eeprom[0x180] + 1 + ((eeprom[0x181] + 1) * 2) + 1 + ((eeprom[0x182] + 1) * 3) + 2 + ((eeprom[0x183] + 1) * 4) + 3 + ((eeprom[0x184] + 1) * 5) + 4) & 0xFF eeprom[0x187] = (eeprom[0x186] + 0x5A) & 0xFF ==== 0x1BE and 0x1F6 ==== // eeprom: base of EEPROM data // offset: offset in eeprom to checksum (either 0x188 or 0x1C0) void Checksum1BEand1F6(unsigned char eeprom[], int offset) { int checksum = 0; int blockOffset = offset; for (int block = 0; block < 3; block++) { int loopOffset = blockOffset + 1; checksum += (eeprom[blockOffset] + 1) * (block + 1); for (int byteOff = 1; byteOff < 0x11; byteOff += 0x4) { int mult2 = (eeprom[loopOffset] + 1) * (block + 1); checksum += mult2 + byteOff; int mult3 = (eeprom[loopOffset + 1] + 1) * (block + 1); checksum += mult3 + byteOff + 1; int mult4 = (eeprom[loopOffset + 2] + 1) * (block + 1); checksum += mult4 + byteOff + 2; int mult5 = (eeprom[loopOffset + 3] + 1) * (block + 1); checksum += mult5 + byteOff + 3; loopOffset += 4; } blockOffset += 0x11; } eeprom[offset + 0x36] = (unsigned char)(checksum & 0xFF); eeprom[offset + 0x37] = (unsigned char)((data[offset + 0x36] + 0x5A) & 0xFF); } ===== References ===== * http://origami64.net/showthread.php?tid=47&pid=2936#pid2936