1//! Detection for games that are known to use EEPROM chips, which require knowing how the EEPROM 2//! chip is mapped into the cartridge's address space 3//! 4//! List of games and metadata from this thread: 5//! <https://gendev.spritesmind.net/forum/viewtopic.php?f=25&t=206> 6 7#[derive(Debug, Clone, Copy, PartialEq, Eq)] 8pub enum EepromType { 9 X24C01, 10 X24C02, 11 X24C08, 12 X24C16, 13 X24C64, 14} 15 16#[derive(Debug, Clone)] 17pub struct EepromMetadata { 18 pub eeprom_type: EepromType, 19 pub sda_in_addr: u32, 20 pub sda_in_bit: u8, 21 pub sda_out_addr: u32, 22 pub sda_out_bit: u8, 23 pub scl_addr: u32, 24 pub scl_bit: u8, 25} 26 27// Values from https://gendev.spritesmind.net/forum/viewtopic.php?f=25&t=206 28 29const NBA_JAM_METADATA: EepromMetadata = EepromMetadata { 30 eeprom_type: EepromType::X24C02, 31 sda_in_addr: 0x200000, 32 sda_in_bit: 0, 33 sda_out_addr: 0x200000, 34 sda_out_bit: 1, 35 scl_addr: 0x200000, 36 scl_bit: 1, 37}; 38 39const ACCLAIM_24C02_METADATA: EepromMetadata = EepromMetadata { 40 eeprom_type: EepromType::X24C02, 41 sda_in_addr: 0x200001, 42 sda_in_bit: 0, 43 sda_out_addr: 0x200001, 44 sda_out_bit: 0, 45 scl_addr: 0x200000, 46 scl_bit: 0, 47}; 48 49const ACCLAIM_24C16_METADATA: EepromMetadata = EepromMetadata { 50 eeprom_type: EepromType::X24C16, 51 sda_in_addr: 0x200001, 52 sda_in_bit: 0, 53 sda_out_addr: 0x200001, 54 sda_out_bit: 0, 55 scl_addr: 0x200000, 56 scl_bit: 0, 57}; 58 59const ACCLAIM_24C64_METADATA: EepromMetadata = EepromMetadata { 60 eeprom_type: EepromType::X24C64, 61 sda_in_addr: 0x200001, 62 sda_in_bit: 0, 63 sda_out_addr: 0x200001, 64 sda_out_bit: 0, 65 scl_addr: 0x200000, 66 scl_bit: 0, 67}; 68 69const SEGA_CAPCOM_METADATA: EepromMetadata = EepromMetadata { 70 eeprom_type: EepromType::X24C01, 71 sda_in_addr: 0x200001, 72 sda_in_bit: 0, 73 sda_out_addr: 0x200001, 74 sda_out_bit: 0, 75 scl_addr: 0x200001, 76 scl_bit: 1, 77}; 78 79const EA_METADATA: EepromMetadata = EepromMetadata { 80 eeprom_type: EepromType::X24C01, 81 sda_in_addr: 0x200000, 82 sda_in_bit: 7, 83 sda_out_addr: 0x200000, 84 sda_out_bit: 7, 85 scl_addr: 0x200000, 86 scl_bit: 6, 87}; 88 89const CODEMASTERS_24C08_METADATA: EepromMetadata = EepromMetadata { 90 eeprom_type: EepromType::X24C08, 91 sda_in_addr: 0x300000, 92 sda_in_bit: 0, 93 sda_out_addr: 0x380001, 94 sda_out_bit: 7, 95 scl_addr: 0x300000, 96 scl_bit: 1, 97}; 98 99const CODEMASTERS_24C16_METADATA: EepromMetadata = EepromMetadata { 100 eeprom_type: EepromType::X24C16, 101 sda_in_addr: 0x300000, 102 sda_in_bit: 0, 103 sda_out_addr: 0x380001, 104 sda_out_bit: 7, 105 scl_addr: 0x300000, 106 scl_bit: 1, 107}; 108 109// Mostly from https://gendev.spritesmind.net/forum/viewtopic.php?p=2485#p2485 110#[rustfmt::skip] 111const SERIAL_NUMBER_TO_METADATA: &[(&[u8], EepromMetadata)] = &[ 112 (b"G-4060 ", SEGA_CAPCOM_METADATA), // Wonder Boy in Monster World (U/E) 113 (b"PR-1993 ", SEGA_CAPCOM_METADATA), // Wonder Boy V: Monster World III (J) 114 (b"T-12046 ", SEGA_CAPCOM_METADATA), // Mega Man: The Wily Wars (E) 115 (b"T-12053 ", SEGA_CAPCOM_METADATA), // Rockman Mega World (J) 116 (b"MK-1215 ", SEGA_CAPCOM_METADATA), // Evander Holyfield's "Real Deal" Boxing (World) 117 (b"MK-1228 ", SEGA_CAPCOM_METADATA), // Greatest Heavyweights (U/E) 118 (b"G-5538 ", SEGA_CAPCOM_METADATA), // Greatest Heavyweights (J) 119 (b"T-081326", NBA_JAM_METADATA), // NBA Jam (U/E) 120 (b"T-81033 ", NBA_JAM_METADATA), // NBA Jam (J) 121 (b"T-81406 ", ACCLAIM_24C02_METADATA), // NBA Jam Tournament Edition (World) 122 (b"T-8104B ", ACCLAIM_24C02_METADATA), // NBA Jam Tournament Edition (32X) (World) 123 (b"T-081276", ACCLAIM_24C02_METADATA), // NFL Quarterback Club (World) 124 (b"T-8102B ", ACCLAIM_24C02_METADATA), // NFL Quarterback Club (32X) (World) 125 (b"T-081586", ACCLAIM_24C16_METADATA), // NFL Quarterback Club 96 (U/E) 126 (b"T-81576 ", ACCLAIM_24C64_METADATA), // College Slam (U) 127 (b"T-81476 ", ACCLAIM_24C64_METADATA), // Frank Thomas Big Hurt Baseball (U/E) 128 (b"T-50176 ", EA_METADATA), // Rings of Power (U/E) 129 (b"T-50396 ", EA_METADATA), // NHLPA Hockey 93 (U/E) 130]; 131 132pub fn eeprom(rom: &[u8], checksum: u32) -> Option<EepromMetadata> { 133 let rom_serial_number = &rom[0x183..0x18B]; 134 for (serial_number, metadata) in SERIAL_NUMBER_TO_METADATA { 135 if rom_serial_number == *serial_number { 136 return Some(metadata.clone()); 137 } 138 } 139 140 // Micro Machines 2: Turbo Tournament (E) 141 if is_micro_machines_2(rom) { 142 return Some(CODEMASTERS_24C08_METADATA); 143 } 144 145 match checksum { 146 // Micro Machines: Military (E) 147 0xB3ABB15E => Some(CODEMASTERS_24C08_METADATA), 148 // Micro Machines: Turbo Tournament 96 (E) 149 0x23319D0D => Some(CODEMASTERS_24C16_METADATA), 150 // Honoo no Toukyuuji - Dodge Danpei (J) 151 0x630F07C6 => Some(SEGA_CAPCOM_METADATA), 152 _ => None, 153 } 154} 155 156pub fn is_micro_machines_2(rom: &[u8]) -> bool { 157 let extended_serial = &rom[0x183..0x18E]; 158 extended_serial == b"T-120096-50" 159}