Detection for games that are known to use EEPROM chips, which require knowing how the EEPROM chip is mapped into the cartridge's address space

List of games and metadata from this thread: https://gendev.spritesmind.net/forum/viewtopic.php?f=25&t=206

7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum EepromType {
9    X24C01,
10    X24C02,
11    X24C08,
12    X24C16,
13    X24C64,
14}
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}

Values from https://gendev.spritesmind.net/forum/viewtopic.php?f=25&t=206

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

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];
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}