9use crate::cartridge::eeprom::{Eeprom8K, Eeprom512}; 10use crate::cartridge::flashrom::{FlashRom64K, FlashRom128K}; 11use crate::cartridge::gpio::GpioPort; 12use crate::cartridge::rtc::SeikoRealTimeClock; 13use crate::cartridge::solar::SolarSensor; 14use crate::dma::TransferUnit; 15use crate::interrupts::InterruptRegisters; 16use bincode::{Decode, Encode}; 17use crc::Crc; 18use gba_config::GbaSaveMemory; 19use jgenesis_common::boxedarray::BoxedByteArray; 20use jgenesis_common::debug::{DebugBytesView, DebugMemoryView}; 21use jgenesis_common::num::GetBit; 22use jgenesis_proc_macros::{FakeDecode, FakeEncode, PartialClone}; 23use std::mem; 24use std::ops::Deref; 25 26const MAX_ROM_LEN: usize = 32 * 1024 * 1024; 27const SRAM_LEN: usize = 32 * 1024; 28 29const GAME_CODE_ADDRESS: usize = 0x00000AC; 30 31const CRC: Crc<u32> = Crc::<u32>::new(&crc::CRC_32_ISO_HDLC); 32 33#[derive(Debug, Clone, FakeEncode, FakeDecode)] 34struct Rom(Box<[u8]>); 35 36impl Default for Rom { 37 fn default() -> Self { 38 Self(vec![].into_boxed_slice()) 39 } 40} 41 42impl Deref for Rom { 43 type Target = Box<[u8]>; 44 45 fn deref(&self) -> &Self::Target { 46 &self.0 47 } 48} 49 50const AUTO_SAVE_TYPE_OVERRIDES: &[(u32, GbaSaveMemory)] = &[ 51 (0xDD8A7104, GbaSaveMemory::None), // Iridion II (USA) 52 (0x57930C6A, GbaSaveMemory::None), // Iridion II (Europe) 53 (0xDFC88D3E, GbaSaveMemory::None), // Top Gun - Combat Zones (USA) 54]; 55 56#[derive(Debug, Clone, Encode, Decode)] 57enum RwMemory { 58 Unknown, 59 Sram(BoxedByteArray<SRAM_LEN>), 60 EepromUnknownSize, 61 Eeprom512(Eeprom512), 62 Eeprom8K(Eeprom8K), 63 FlashRom64K(FlashRom64K), 64 FlashRom128K(FlashRom128K), 65 None, 66} 67 68impl RwMemory { 69 fn new_sram(initial_save: Option<&Vec<u8>>) -> Self { 70 let mut sram = BoxedByteArray::<SRAM_LEN>::new(); 71 72 if let Some(initial_save) = initial_save 73 && initial_save.len() >= SRAM_LEN 74 { 75 sram.copy_from_slice(&initial_save[..SRAM_LEN]); 76 } else { 77 sram.fill(0xFF); 78 } 79 80 Self::Sram(sram) 81 } 82 83 fn new_flash_rom_64k(initial_save: Option<&Vec<u8>>) -> Self { 84 Self::FlashRom64K(FlashRom64K::new(initial_save)) 85 } 86 87 fn new_flash_rom_128k(initial_save: Option<&Vec<u8>>) -> Self { 88 Self::FlashRom128K(FlashRom128K::new(initial_save)) 89 } 90 91 fn from_forced_type(initial_save: Option<&Vec<u8>>, forced_type: GbaSaveMemory) -> Self { 92 match forced_type { 93 GbaSaveMemory::Sram => Self::new_sram(initial_save), 94 GbaSaveMemory::EepromUnknownSize => Self::EepromUnknownSize, 95 GbaSaveMemory::Eeprom512 => Self::Eeprom512(Eeprom512::new(initial_save)), 96 GbaSaveMemory::Eeprom8K => Self::Eeprom8K(Eeprom8K::new(initial_save)), 97 GbaSaveMemory::FlashRom64K => Self::new_flash_rom_64k(initial_save), 98 GbaSaveMemory::FlashRom128K => Self::new_flash_rom_128k(initial_save), 99 GbaSaveMemory::None => Self::None, 100 } 101 } 102 103 fn initial( 104 rom: &[u8], 105 initial_save: Option<&Vec<u8>>, 106 forced_type: Option<GbaSaveMemory>, 107 ) -> Self { 108 type RwMemoryFn = fn(Option<&Vec<u8>>) -> RwMemory; 109 110 // If the given ASCII string exists in ROM and followed by 3 digits, assume that type 111 // of save memory (e.g. "SRAM_V123" indicates SRAM) 112 const MEMORY_STRINGS: &[(&[u8], &str, RwMemoryFn)] = &[ 113 (b"SRAM_V", "SRAM", RwMemory::new_sram), 114 (b"EEPROM_V", "EEPROM", |_| RwMemory::EepromUnknownSize), 115 (b"FLASH_V", "Flash ROM 64 KB", RwMemory::new_flash_rom_64k), 116 (b"FLASH512_V", "Flash ROM 64 KB", RwMemory::new_flash_rom_64k), 117 (b"FLASH1M_V", "Flash ROM 128 KB", RwMemory::new_flash_rom_128k), 118 ]; 119 120 if let Some(forced_type) = forced_type { 121 log::info!("Forcing save memory type to {}", forced_type.name()); 122 return Self::from_forced_type(initial_save, forced_type); 123 } 124 125 let rom_checksum = CRC.checksum(rom); 126 for &(checksum, forced_type) in AUTO_SAVE_TYPE_OVERRIDES { 127 if checksum == rom_checksum { 128 log::info!( 129 "Forcing save memory type to {} due to checksum match: {checksum:08X}", 130 forced_type.name() 131 ); 132 return Self::from_forced_type(initial_save, forced_type); 133 } 134 } 135 136 for i in 0..rom.len() { 137 for &(string, name, init_fn) in MEMORY_STRINGS { 138 if i + string.len() + 3 > rom.len() { 139 continue; 140 } 141 142 if &rom[i..i + string.len()] != string { 143 continue; 144 } 145 146 if !(i + string.len()..i + string.len() + 3).all(|j| rom[j].is_ascii_digit()) { 147 continue; 148 } 149 150 log::info!( 151 "Auto-detected save memory type {name} from string in ROM at ${i:07X}: {}", 152 str::from_utf8(&rom[i..i + string.len() + 3]).unwrap() 153 ); 154 155 return init_fn(initial_save); 156 } 157 } 158 159 log::info!("No matching save memory string found in ROM; will auto-detect based on usage"); 160 161 Self::Unknown 162 } 163 164 fn min_eeprom_address(&self, rom_len: u32) -> u32 { 165 // EEPROM is at $D000000-$DFFFFFF for ROMs <=16MB, and $DFFFF00-$DFFFFFF for 32MB 166 match self { 167 Self::EepromUnknownSize | Self::Eeprom8K(_) | Self::Eeprom512(_) => { 168 if rom_len <= 16 * 1024 * 1024 { 0xD000000 } else { 0xDFFFF00 } 169 } 170 _ => u32::MAX, 171 } 172 } 173} 174 175fn pad_if_classic_nes_rom(rom: &mut Vec<u8>) { 176 if rom.len() <= GAME_CODE_ADDRESS { 177 return; 178 } 179 180 // Classic NES series games uniquely have a game code of 'F' (uppercase ASCII character) 181 // Most other games have 'A' or 'B', some cartridges with special hardware use other characters 182 if rom[GAME_CODE_ADDRESS] == b'F' { 183 log::info!( 184 "Detected Classic NES Series cartridge; padding to 32 MB to emulate ROM mirroring" 185 ); 186 187 // Manually mirror ROM up to 32 MB 188 while rom.len() < MAX_ROM_LEN { 189 for i in 0..rom.len() { 190 rom.push(rom[i]); 191 } 192 } 193 } 194} 195 196#[derive(Debug, Clone, PartialClone, Encode, Decode)] 197pub struct Cartridge { 198 #[partial_clone(default)] 199 rom: Rom, 200 rom_len: u32, 201 burst_active: bool, 202 burst_address: u32, 203 rw_memory: RwMemory, 204 rw_memory_dirty: bool, 205 min_eeprom_address: u32, 206 gpio: GpioPort, 207 rtc: Option<SeikoRealTimeClock>, 208 solar: Option<SolarSensor>, 209 // Kept here so that they can be copied into R/W memory after auto-detection 210 initial_save: Option<Vec<u8>>, 211 initial_rtc: Option<SeikoRealTimeClock>, 212} 213 214impl Cartridge { 215 pub fn new( 216 mut rom: Vec<u8>, 217 initial_save: Option<Vec<u8>>, 218 initial_rtc: Option<SeikoRealTimeClock>, 219 forced_save_memory_type: Option<GbaSaveMemory>, 220 ) -> Self { 221 jgenesis_common::rom::mirror_to_next_power_of_two(&mut rom); 222 223 // Record ROM length before possibly mirroring; Classic NES Series games depend on this to 224 // map EEPROM correctly 225 let rom_len = rom.len() as u32; 226 pad_if_classic_nes_rom(&mut rom); 227 228 let rw_memory = RwMemory::initial(&rom, initial_save.as_ref(), forced_save_memory_type); 229 let min_eeprom_address = rw_memory.min_eeprom_address(rom_len); 230 231 let has_solar_sensor = rom.get(0xAC).copied() == Some(b'U'); 232 if has_solar_sensor { 233 log::info!("Detected solar sensor peripheral; assuming RTC is also present"); 234 } 235 236 // TODO allow forcing RTC? 237 238 Self { 239 rom: Rom(rom.into_boxed_slice()), 240 rom_len, 241 burst_active: false, 242 burst_address: 0, 243 rw_memory, 244 rw_memory_dirty: false, 245 min_eeprom_address, 246 gpio: GpioPort::new(), 247 rtc: has_solar_sensor 248 .then(|| initial_rtc.clone().unwrap_or_else(SeikoRealTimeClock::new)), 249 solar: has_solar_sensor.then(SolarSensor::new), 250 initial_save, 251 initial_rtc, 252 } 253 } 254 255 pub fn rom_burst_active(&self) -> bool { 256 self.burst_active 257 } 258 259 pub fn end_rom_burst(&mut self) { 260 self.burst_active = false; 261 } 262 263 // Returns address that should be used for the ROM access 264 #[must_use] 265 fn update_burst_state(&mut self, address: u32) -> u32 { 266 if !self.burst_active { 267 // Non-sequential ROM accesses begin a burst and latch A1-16 268 self.burst_active = true; 269 self.burst_address = address & 0x1FFFE; 270 } else if address & 0x1FFFE != self.burst_address { 271 log::debug!( 272 "Cartridge read address does not match burst address! {address:08X} {:05X}", 273 self.burst_address 274 ); 275 } 276 277 let rom_addr = (address & !0x1FFFF) | self.burst_address; 278 self.burst_address = (self.burst_address + 2) & 0x1FFFF; 279 280 if address & 0x1FFFE == 0x1FFFE { 281 // Bursts always end when the final halfword of a 128KB page is requested 282 self.burst_active = false; 283 } 284 285 rom_addr 286 } 287 288 pub fn read_rom(&mut self, address: u32) -> u16 { 289 debug_assert!((0x08000000..0x0E000000).contains(&address)); 290 291 let address = self.update_burst_state(address); 292 293 if address >= self.min_eeprom_address 294 && let Some(bit) = self.try_eeprom_read() 295 { 296 return bit.into(); 297 } 298 299 if (0x080000C4..0x080000CA).contains(&address) 300 && let Some(gpio_value) = self.try_gpio_read(address) 301 { 302 return gpio_value; 303 } 304 305 let rom_addr = (address as usize) & 0x1FFFFFF & !1; 306 if rom_addr >= self.rom.len() { 307 log::debug!( 308 "Out of bounds cartridge ROM read {address:07X}, len {:07X}", 309 self.rom.len() 310 ); 311 let open_bus = rom_addr >> 1; 312 return open_bus as u16; 313 } 314 315 u16::from_le_bytes(self.rom[rom_addr..rom_addr + 2].try_into().unwrap()) 316 } 317 318 fn try_eeprom_read(&mut self) -> Option<bool> { 319 match &mut self.rw_memory { 320 RwMemory::Eeprom512(eeprom) => Some(eeprom.read()), 321 RwMemory::Eeprom8K(eeprom) => Some(eeprom.read()), 322 _ => None, 323 } 324 } 325 326 fn try_gpio_read(&mut self, address: u32) -> Option<u16> { 327 match address { 328 0x080000C4 => self.gpio.read_data(self.rtc.as_ref(), self.solar.as_ref()), 329 0x080000C6 => self.gpio.read_pin_directions(), 330 0x080000C8 => self.gpio.read_mode(), 331 _ => None, 332 } 333 } 334 335 pub fn write_rom(&mut self, address: u32, value: u16) { 336 debug_assert!((0x08000000..0x0E000000).contains(&address)); 337 338 let address = self.update_burst_state(address); 339 340 if (0x080000C4..0x080000CA).contains(&address) { 341 self.gpio_write(address, value); 342 return; 343 } 344 345 if address < self.min_eeprom_address { 346 log::debug!("Ignoring write to ROM address: {address:08X} {value:04X}"); 347 return; 348 } 349 350 self.rw_memory_dirty = true; 351 352 match &mut self.rw_memory { 353 RwMemory::Eeprom512(eeprom) => eeprom.write(value.bit(0)), 354 RwMemory::Eeprom8K(eeprom) => eeprom.write(value.bit(0)), 355 _ => { 356 log::debug!("Ignoring write to ROM address: {address:08X} {value:04X}"); 357 } 358 } 359 } 360 361 fn gpio_write(&mut self, address: u32, value: u16) { 362 self.rtc.get_or_insert_with(|| { 363 log::info!("Auto-detected RTC based on write to ${address:07X}"); 364 self.initial_rtc.clone().unwrap_or_else(SeikoRealTimeClock::new) 365 }); 366 367 match address { 368 0x080000C4 => self.gpio.write_data(value, self.rtc.as_mut(), self.solar.as_mut()), 369 0x080000C6 => self.gpio.write_pin_directions(value), 370 0x080000C8 => self.gpio.write_mode(value), 371 _ => {} 372 } 373 } 374 375 pub fn notify_dma_to_rom(&mut self, address: u32, length: u16, unit: TransferUnit) { 376 if unit != TransferUnit::Halfword { 377 // Word transfers will never be the correct length (and don't make sense for EEPROM anyway) 378 return; 379 } 380 381 if !matches!(self.rw_memory, RwMemory::Unknown | RwMemory::EepromUnknownSize) { 382 return; 383 } 384 385 // Check against original ROM length instead of possibly-padded length (Classic NES Series) 386 let rom_len = self.rom_len; 387 if address < RwMemory::EepromUnknownSize.min_eeprom_address(rom_len) { 388 return; 389 } 390 391 match length { 392 9 => { 393 // 6-bit address; 512 B EEPROM 394 self.rw_memory = RwMemory::Eeprom512(Eeprom512::new(self.initial_save.as_ref())); 395 self.min_eeprom_address = self.rw_memory.min_eeprom_address(rom_len); 396 397 log::info!( 398 "Auto-detected EEPROM size of 512 bytes from DMA of length {length} to ${address:07X}" 399 ); 400 } 401 17 => { 402 // 14-bit address; 8 KB EEPROM 403 self.rw_memory = RwMemory::Eeprom8K(Eeprom8K::new(self.initial_save.as_ref())); 404 self.min_eeprom_address = self.rw_memory.min_eeprom_address(rom_len); 405 406 log::info!( 407 "Auto-detected EEPROM size of 8 KB from DMA of length {length} to ${address:07X}" 408 ); 409 } 410 _ => { 411 log::warn!("Unexpected initial EEPROM DMA length: {length}"); 412 } 413 } 414 } 415 416 pub fn take_rom(&mut self) -> Vec<u8> { 417 mem::take(&mut self.rom.0).into_vec() 418 } 419 420 pub fn take_rom_from(&mut self, other: &mut Self) { 421 self.rom = mem::take(&mut other.rom); 422 } 423 424 pub fn read_sram(&mut self, address: u32) -> u8 { 425 debug_assert!((0x0E000000..0x10000000).contains(&address)); 426 427 if matches!(self.rw_memory, RwMemory::Unknown) { 428 self.rw_memory = RwMemory::new_sram(self.initial_save.as_ref()); 429 log::info!("Auto-detected save memory type as SRAM due to read ${address:08X}"); 430 } 431 432 match &self.rw_memory { 433 RwMemory::Sram(sram) => { 434 let sram_addr = (address as usize) & (SRAM_LEN - 1); 435 sram[sram_addr] 436 } 437 RwMemory::FlashRom64K(flash_rom) => flash_rom.read(address), 438 RwMemory::FlashRom128K(flash_rom) => flash_rom.read(address), 439 _ => { 440 // SRAM area reads always return 0xFF when no SRAM or flash ROM is present 441 // (save/none in jsmolka gba-tests) 442 0xFF 443 } 444 } 445 } 446 447 pub fn write_sram(&mut self, address: u32, value: u8) { 448 debug_assert!((0x0E000000..0x10000000).contains(&address)); 449 450 if matches!(self.rw_memory, RwMemory::Unknown) { 451 if address & 0xFFFF == 0x5555 && value == 0xAA { 452 // Probably Flash ROM 453 // TODO is it possible to auto-detect 64K vs. 128K? 454 self.rw_memory = RwMemory::new_flash_rom_128k(self.initial_save.as_ref()); 455 log::info!( 456 "Auto-detected save memory type as Flash ROM 64 KB due to write ${address:08X} 0x{value:02X}" 457 ); 458 } else { 459 // Probably SRAM 460 self.rw_memory = RwMemory::new_sram(self.initial_save.as_ref()); 461 log::info!( 462 "Auto-detected save memory type as SRAM due to write ${address:08X} 0x{value:02X}" 463 ); 464 } 465 } 466 467 self.rw_memory_dirty = true; 468 469 match &mut self.rw_memory { 470 RwMemory::Sram(sram) => { 471 let sram_addr = (address as usize) & (SRAM_LEN - 1); 472 sram[sram_addr] = value; 473 } 474 RwMemory::FlashRom64K(flash_rom) => flash_rom.write(address, value), 475 RwMemory::FlashRom128K(flash_rom) => flash_rom.write(address, value), 476 _ => { 477 log::debug!("Unexpected SRAM address write {address:08X} {value:02X}"); 478 } 479 } 480 } 481 482 pub fn take_rw_memory_dirty(&mut self) -> bool { 483 mem::take(&mut self.rw_memory_dirty) 484 } 485 486 pub fn rw_memory(&self) -> Option<&[u8]> { 487 match &self.rw_memory { 488 RwMemory::Sram(sram) => Some(sram.as_slice()), 489 RwMemory::Eeprom8K(eeprom) => Some(eeprom.memory()), 490 RwMemory::Eeprom512(eeprom) => Some(eeprom.memory()), 491 RwMemory::FlashRom64K(flash_rom) => Some(flash_rom.memory()), 492 RwMemory::FlashRom128K(flash_rom) => Some(flash_rom.memory()), 493 RwMemory::Unknown | RwMemory::EepromUnknownSize | RwMemory::None => None, 494 } 495 } 496 497 pub fn update_rtc_time(&mut self, cycles: u64, interrupts: &mut InterruptRegisters) { 498 if let Some(rtc) = &mut self.rtc { 499 rtc.update_time(cycles, interrupts); 500 } 501 } 502 503 pub fn rtc(&self) -> Option<impl Encode> { 504 self.rtc.as_ref() 505 } 506 507 pub fn set_solar_brightness(&mut self, brightness: u8) { 508 if let Some(solar) = &mut self.solar { 509 solar.set_brightness(brightness); 510 } 511 } 512 513 pub fn debug_rom_view(&mut self) -> impl DebugMemoryView { 514 DebugBytesView(self.rom.0.as_mut()) 515 } 516}