1//! GBA memory map and bus code 2 3use crate::apu; 4use crate::apu::Apu; 5use crate::cartridge::Cartridge; 6use crate::dma::{DmaState, TransferUnit}; 7use crate::input::InputState; 8use crate::interrupts::{InterruptRegisters, InterruptType}; 9use crate::memory::Memory; 10use crate::ppu::Ppu; 11use crate::prefetch::GamePakPrefetcher; 12use crate::scheduler::{Scheduler, SchedulerEvent}; 13use crate::sio::SerialPort; 14use crate::timers::Timers; 15use arm7tdmi_emu::bus::{BusInterface, MemoryCycle, OpSize}; 16use bincode::{Decode, Encode}; 17use jgenesis_common::num::GetBit; 18use jgenesis_proc_macros::PartialClone; 19 20#[derive(Debug, Clone, Copy, Encode, Decode)] 21pub(crate) struct BusState { 22 pub cycles: u64, 23 pub cpu_pc: u32, 24 pub last_bios_read: u32, 25 pub open_bus: u32, 26 pub iwram_open_bus: u32, 27 pub active_dma_channel: Option<u8>, 28 pub locked: bool, 29} 30 31impl BusState { 32 pub fn new() -> Self { 33 Self { 34 cycles: 0, 35 cpu_pc: 0, 36 last_bios_read: 0, 37 open_bus: 0, 38 iwram_open_bus: 0, 39 active_dma_channel: None, 40 locked: false, 41 } 42 } 43} 44 45struct AccessCtx; 46 47impl AccessCtx { 48 const CPU_INSTRUCTION: u8 = 0; 49 const CPU_DATA: u8 = 1; 50 const DMA: u8 = 2; 51} 52 53macro_rules! invalid_size { 54 ($size:expr) => { 55 panic!("Invalid size, must be 0-2: {}", $size) 56 }; 57} 58 59fn word_to_size<const SIZE: u8>(value: u32, address: u32) -> u32 { 60 match SIZE { 61 OpSize::BYTE => (value >> (8 * (address & 3))) & 0xFF, 62 OpSize::HALFWORD => (value >> (8 * (address & 2))) & 0xFFFF, 63 OpSize::WORD => value, 64 _ => invalid_size!(SIZE), 65 } 66} 67 68#[derive(Debug, Clone, PartialClone, Encode, Decode)] 69pub struct Bus { 70 pub ppu: Ppu, 71 pub apu: Apu, 72 pub memory: Memory, 73 #[partial_clone(partial)] 74 pub cartridge: Cartridge, 75 pub prefetch: GamePakPrefetcher, 76 pub dma: DmaState, 77 pub timers: Timers, 78 pub interrupts: InterruptRegisters, 79 pub sio: SerialPort, 80 pub inputs: InputState, 81 pub state: BusState, 82 pub scheduler: Scheduler, 83} 84 85impl Bus { 86 #[inline] 87 fn read_internal<const SIZE: u8, const CTX: u8>( 88 &mut self, 89 address: u32, 90 cycle: MemoryCycle, 91 ) -> u32 { 92 if CTX != AccessCtx::DMA { 93 self.try_progress_dma(); 94 self.end_rom_burst_if_not_accessed(address); 95 self.interrupts.cpu_bus_cycle(self.state.cycles); 96 } 97 98 match address { 99 0x00000000..=0x00003FFF => self.read_bios_rom::<SIZE>(address), 100 0x02000000..=0x02FFFFFF => self.read_ewram::<SIZE>(address), 101 0x03000000..=0x03FFFFFF => self.read_iwram::<SIZE>(address), 102 0x04000000..=0x04FFFFFF => self.read_io_register::<SIZE>(address), 103 0x05000000..=0x05FFFFFF => self.read_palette_ram::<SIZE>(address), 104 0x06000000..=0x06FFFFFF => self.read_vram::<SIZE>(address), 105 0x07000000..=0x07FFFFFF => self.read_oam::<SIZE>(address), 106 0x08000000..=0x0DFFFFFF => self.read_cartridge_rom::<SIZE, CTX>(address, cycle), 107 0x0E000000..=0x0FFFFFFF => self.read_cartridge_sram::<SIZE>(address), 108 0x00004000..=0x01FFFFFF | 0x10000000..=0xFFFFFFFF => self.read_invalid::<SIZE>(address), 109 } 110 } 111 112 #[inline] 113 fn write_internal<const SIZE: u8, const CTX: u8>( 114 &mut self, 115 address: u32, 116 value: u32, 117 cycle: MemoryCycle, 118 ) { 119 if CTX != AccessCtx::DMA { 120 self.try_progress_dma(); 121 self.end_rom_burst_if_not_accessed(address); 122 self.interrupts.cpu_bus_cycle(self.state.cycles); 123 } 124 125 match address { 126 0x02000000..=0x02FFFFFF => self.write_ewram::<SIZE>(address, value), 127 0x03000000..=0x03FFFFFF => self.write_iwram::<SIZE>(address, value), 128 0x04000000..=0x04FFFFFF => self.write_io_register::<SIZE>(address, value), 129 0x05000000..=0x05FFFFFF => self.write_palette_ram::<SIZE>(address, value), 130 0x06000000..=0x06FFFFFF => self.write_vram::<SIZE>(address, value), 131 0x07000000..=0x07FFFFFF => self.write_oam::<SIZE>(address, value), 132 0x08000000..=0x0DFFFFFF => self.write_cartridge_rom::<SIZE>(address, value, cycle), 133 0x0E000000..=0x0FFFFFFF => self.write_cartridge_sram::<SIZE>(address, value), 134 0x00000000..=0x01FFFFFF | 0x10000000..=0xFFFFFFFF => self.write_invalid(), 135 } 136 } 137 138 fn increment_cycles_with_prefetch(&mut self, cycles: u64) { 139 self.state.cycles += cycles; 140 self.advance_prefetch(cycles); 141 } 142 143 fn read_open_bus<const SIZE: u8>(&mut self, address: u32) -> u32 { 144 log::debug!("Open bus read of size {}: {address:08X}", OpSize::display(SIZE)); 145 word_to_size::<SIZE>(self.state.open_bus, address) 146 } 147 148 fn update_open_bus<const SIZE: u8>(&mut self, value: u32) -> u32 { 149 match SIZE { 150 OpSize::BYTE => { 151 self.state.open_bus = u32::from_ne_bytes([value as u8; 4]); 152 } 153 OpSize::HALFWORD => { 154 self.state.open_bus = (value & 0xFFFF) | (value << 16); 155 } 156 OpSize::WORD => { 157 self.state.open_bus = value; 158 } 159 _ => invalid_size!(SIZE), 160 } 161 162 value 163 } 164 165 fn iwram_update_open_bus<const SIZE: u8>(&mut self, value: u32, address: u32) -> u32 { 166 // 8-bit and 16-bit IWRAM accesses only update the accessed bits 167 match SIZE { 168 OpSize::BYTE => { 169 let shift = 8 * (address & 3); 170 self.state.iwram_open_bus &= !(0xFF << shift); 171 self.state.iwram_open_bus |= (value & 0xFF) << shift; 172 } 173 OpSize::HALFWORD => { 174 let shift = 8 * (address & 2); 175 self.state.iwram_open_bus &= !(0xFFFF << shift); 176 self.state.iwram_open_bus |= (value & 0xFFFF) << shift; 177 } 178 OpSize::WORD => { 179 self.state.iwram_open_bus = value; 180 } 181 _ => invalid_size!(SIZE), 182 } 183 184 // Any IWRAM access populates all 32 bits of the data bus (openbuster test ROM) 185 self.state.open_bus = self.state.iwram_open_bus; 186 187 value 188 } 189 190 fn read_bios_rom<const SIZE: u8>(&mut self, address: u32) -> u32 { 191 self.increment_cycles_with_prefetch(1); 192 193 // BIOS ROM is only readable while executing out of BIOS ROM 194 // Reads from other regions return the last value successfully fetched from BIOS ROM 195 if self.state.cpu_pc < 0x00004000 { 196 self.state.last_bios_read = self.memory.read_bios_rom(address); 197 } else { 198 log::debug!("BIOS ROM read {address:08X} while PC is {:08X}", self.state.cpu_pc); 199 } 200 201 let value = word_to_size::<SIZE>(self.state.last_bios_read, address); 202 self.update_open_bus::<SIZE>(value) 203 } 204 205 fn ewram_access_cycles<const SIZE: u8>() -> u64 { 206 // EWRAM only has a 16-bit data bus, so 32-bit accesses take twice as long 207 match SIZE { 208 OpSize::BYTE | OpSize::HALFWORD => 3, 209 OpSize::WORD => 6, 210 _ => invalid_size!(SIZE), 211 } 212 } 213 214 fn read_ewram<const SIZE: u8>(&mut self, address: u32) -> u32 { 215 let cycles = Self::ewram_access_cycles::<SIZE>(); 216 self.increment_cycles_with_prefetch(cycles); 217 218 let value = match SIZE { 219 OpSize::BYTE => self.memory.read_ewram_byte(address).into(), 220 OpSize::HALFWORD => self.memory.read_ewram_halfword(address).into(), 221 OpSize::WORD => self.memory.read_ewram_word(address), 222 _ => invalid_size!(SIZE), 223 }; 224 225 self.update_open_bus::<SIZE>(value) 226 } 227 228 fn write_ewram<const SIZE: u8>(&mut self, address: u32, value: u32) { 229 let cycles = Self::ewram_access_cycles::<SIZE>(); 230 self.increment_cycles_with_prefetch(cycles); 231 self.update_open_bus::<SIZE>(value); 232 233 match SIZE { 234 OpSize::BYTE => self.memory.write_ewram_byte(address, value as u8), 235 OpSize::HALFWORD => self.memory.write_ewram_halfword(address, value as u16), 236 OpSize::WORD => self.memory.write_ewram_word(address, value), 237 _ => invalid_size!(SIZE), 238 } 239 } 240 241 fn read_iwram<const SIZE: u8>(&mut self, address: u32) -> u32 { 242 self.increment_cycles_with_prefetch(1); 243 244 let value = match SIZE { 245 OpSize::BYTE => self.memory.read_iwram_byte(address).into(), 246 OpSize::HALFWORD => self.memory.read_iwram_halfword(address).into(), 247 OpSize::WORD => self.memory.read_iwram_word(address), 248 _ => invalid_size!(SIZE), 249 }; 250 251 self.iwram_update_open_bus::<SIZE>(value, address) 252 } 253 254 fn write_iwram<const SIZE: u8>(&mut self, address: u32, value: u32) { 255 self.increment_cycles_with_prefetch(1); 256 self.iwram_update_open_bus::<SIZE>(value, address); 257 258 match SIZE { 259 OpSize::BYTE => self.memory.write_iwram_byte(address, value as u8), 260 OpSize::HALFWORD => self.memory.write_iwram_halfword(address, value as u16), 261 OpSize::WORD => self.memory.write_iwram_word(address, value), 262 _ => invalid_size!(SIZE), 263 } 264 } 265 266 fn read_io_register<const SIZE: u8>(&mut self, address: u32) -> u32 { 267 self.increment_cycles_with_prefetch(1); 268 269 let Some(value) = self.try_read_io_register::<SIZE>(address) else { 270 return self.read_open_bus::<SIZE>(address); 271 }; 272 273 self.update_open_bus::<SIZE>(value) 274 } 275 276 fn try_read_io_register<const SIZE: u8>(&mut self, address: u32) -> Option<u32> { 277 let value = match SIZE { 278 OpSize::BYTE => { 279 let halfword = self.read_io_register_internal(address & !1)?; 280 halfword.to_le_bytes()[(address & 1) as usize].into() 281 } 282 OpSize::HALFWORD => self.read_io_register_internal(address & !1)?.into(), 283 OpSize::WORD => { 284 let low: u32 = self.read_io_register_internal(address & !3)?.into(); 285 let high: u32 = self.read_io_register_internal((address & !3) | 2)?.into(); 286 low | (high << 16) 287 } 288 _ => invalid_size!(SIZE), 289 }; 290 Some(value) 291 } 292 293 #[allow(clippy::match_same_arms)] 294 fn read_io_register_internal(&mut self, address: u32) -> Option<u16> { 295 match address { 296 0x4000000..=0x4000057 => { 297 // PPU registers 298 self.ppu.read_register( 299 address, 300 self.state.cycles, 301 &mut self.dma, 302 &mut self.scheduler, 303 ) 304 } 305 0x4000060..=0x40000AF => { 306 // APU registers 307 self.apu.step_to(self.state.cycles); 308 self.apu.read_register_halfword(address) 309 } 310 0x40000B0..=0x40000DF => { 311 // DMA registers 312 self.dma.read_register(address) 313 } 314 0x4000100..=0x400010F => { 315 // Timer registers 316 Some(self.timers.read_register( 317 address, 318 self.state.cycles, 319 &mut self.apu, 320 &mut self.dma, 321 &mut self.interrupts, 322 &mut self.scheduler, 323 )) 324 } 325 0x4000120..=0x400012F | 0x4000134..=0x400015F => { 326 // SIO registers 327 Some(self.sio.read_register(address)) 328 } 329 0x4000130 => Some(self.inputs.read_keyinput()), 330 0x4000132 => Some(self.inputs.read_keycnt()), 331 0x4000200 => Some(self.interrupts.read_ie(self.state.cycles)), 332 0x4000202 => Some(self.interrupts.read_if(self.state.cycles)), 333 0x4000204 => Some(self.memory.read_waitcnt()), 334 0x4000206 => Some(0), // High halfword of word-size WAITCNT reads 335 0x4000208 => Some(self.interrupts.read_ime(self.state.cycles)), 336 0x400020A => Some(0), // High halfword of word-size IME reads 337 0x4000300 => Some(self.memory.read_postflg().into()), 338 0x4000302 => Some(0), // High halfword of word-size POSTFLG reads 339 _ => None, 340 } 341 } 342 343 #[allow(clippy::match_same_arms)] 344 fn write_io_register<const SIZE: u8>(&mut self, address: u32, value: u32) { 345 self.increment_cycles_with_prefetch(1); 346 self.update_open_bus::<SIZE>(value); 347 348 if SIZE == OpSize::WORD { 349 if (apu::FIFO_A_ADDRESS..apu::FIFO_B_ADDRESS + 4).contains(&address) { 350 // Special case 32-bit Direct Sound FIFO writes because 16-bit and 32-bit writes behave differently 351 self.apu.write_register_word(address, value); 352 } else { 353 // Other 32-bit writes behave identically to two consecutive 16-bit writes 354 self.write_io_register_internal::<{ OpSize::HALFWORD }>(address & !3, value as u16); 355 self.write_io_register_internal::<{ OpSize::HALFWORD }>( 356 (address & !3) | 2, 357 (value >> 16) as u16, 358 ); 359 } 360 return; 361 } 362 363 self.write_io_register_internal::<SIZE>(address, value as u16); 364 } 365 366 #[allow(clippy::match_same_arms)] 367 fn write_io_register_internal<const SIZE: u8>(&mut self, address: u32, value: u16) { 368 // Registers where an 8-bit write can be implemented as reading the existing 16-bit value, 369 // modifying the target byte, then writing back the modified 16-bit value. 370 // This does not work for all registers because many registers are write-only, or have 371 // different semantics for reads vs. writes (e.g. IF, timer reload/counter registers) 372 const BYTE_READ_THEN_WRITE_ADDRS: &[u32] = &[ 373 0x4000132, // KEYCNT 374 0x4000200, // IE 375 0x4000204, // WAITCNT 376 ]; 377 378 assert_ne!(SIZE, OpSize::WORD); 379 380 if SIZE == OpSize::BYTE && BYTE_READ_THEN_WRITE_ADDRS.contains(&(address & !1)) { 381 let existing = self.read_io_register_internal(address & !1).unwrap_or(0); 382 let mut bytes = existing.to_le_bytes(); 383 bytes[(address & 1) as usize] = value as u8; 384 self.write_io_register_internal::<{ OpSize::HALFWORD }>( 385 address & !1, 386 u16::from_le_bytes(bytes), 387 ); 388 return; 389 } 390 391 match address { 392 0x4000000..=0x4000057 => { 393 // PPU registers 394 match SIZE { 395 OpSize::BYTE => self.ppu.write_register_byte( 396 address, 397 value as u8, 398 self.state.cycles, 399 &mut self.dma, 400 &mut self.interrupts, 401 &mut self.scheduler, 402 ), 403 OpSize::HALFWORD => self.ppu.write_register( 404 address & !1, 405 value, 406 self.state.cycles, 407 &mut self.dma, 408 &mut self.interrupts, 409 &mut self.scheduler, 410 ), 411 _ => invalid_size!(SIZE), 412 } 413 } 414 0x4000058..=0x400005F => {} // Invalid addresses 415 0x4000060..=0x40000AF => { 416 // APU registers 417 match SIZE { 418 OpSize::BYTE => self.apu.write_register(address, value as u8), 419 OpSize::HALFWORD => self.apu.write_register_halfword(address & !1, value), 420 _ => invalid_size!(SIZE), 421 } 422 } 423 0x40000B0..=0x40000DF => { 424 // DMA registers 425 match SIZE { 426 OpSize::BYTE => { 427 self.dma.write_register_byte( 428 address, 429 value as u8, 430 self.state.cycles, 431 &mut self.cartridge, 432 ); 433 } 434 OpSize::HALFWORD => { 435 self.dma.write_register( 436 address & !1, 437 value, 438 self.state.cycles, 439 &mut self.cartridge, 440 ); 441 } 442 _ => invalid_size!(SIZE), 443 } 444 } 445 0x4000100..=0x400010F => { 446 // Timer registers 447 match SIZE { 448 OpSize::BYTE => self.timers.write_register_byte( 449 address, 450 value as u8, 451 self.state.cycles, 452 &mut self.apu, 453 &mut self.dma, 454 &mut self.interrupts, 455 &mut self.scheduler, 456 ), 457 OpSize::HALFWORD => self.timers.write_register( 458 address, 459 value, 460 self.state.cycles, 461 &mut self.apu, 462 &mut self.dma, 463 &mut self.interrupts, 464 &mut self.scheduler, 465 ), 466 _ => invalid_size!(SIZE), 467 } 468 } 469 0x4000120..=0x400012F | 0x4000134..=0x400015A => { 470 // Serial port registers 471 self.sio.write_register(address & !1, value, self.state.cycles); 472 } 473 0x4000132..=0x4000133 => { 474 // KEYCNT 475 self.inputs.write_keycnt(value, self.state.cycles, &mut self.interrupts); 476 } 477 0x4000200..=0x4000201 => { 478 // IE 479 self.interrupts.write_ie(value, self.state.cycles); 480 } 481 0x4000202..=0x4000203 => { 482 // IF 483 let mut value = value; 484 if SIZE == OpSize::BYTE { 485 value = (value & 0xFF) << (8 * (address & 1)); 486 } 487 self.interrupts.write_if(value, self.state.cycles); 488 } 489 0x4000204..=0x4000205 => { 490 // WAITCNT 491 self.memory.write_waitcnt(value); 492 } 493 0x4000208..=0x4000209 => { 494 // IME 495 self.interrupts.write_ime(value, self.state.cycles); 496 } 497 0x4000300..=0x4000301 => { 498 // POSTFLG/HALTCNT 499 match SIZE { 500 OpSize::BYTE => { 501 if !address.bit(0) { 502 self.memory.write_postflg(value as u8); 503 } else { 504 self.write_haltcnt(value as u8); 505 } 506 } 507 OpSize::HALFWORD => { 508 let [lsb, msb] = value.to_le_bytes(); 509 self.memory.write_postflg(lsb); 510 self.write_haltcnt(msb); 511 } 512 _ => invalid_size!(SIZE), 513 } 514 } 515 0x4000410 => {} // Unknown; BIOS writes to this register 516 _ => log::debug!("Unhandled I/O register write {address:08X} {value:04X}"), 517 } 518 } 519 520 fn write_haltcnt(&mut self, value: u8) { 521 if self.state.cpu_pc >= 0x00004000 { 522 // HALTCNT is only writable when executing from BIOS ROM 523 log::debug!("Attempted to write to HALTCNT while PC is {:08X}", self.state.cpu_pc); 524 return; 525 } 526 527 self.interrupts.write_haltcnt(value); 528 } 529 530 fn block_until_palette_ram_free(&mut self) { 531 loop { 532 self.increment_cycles_with_prefetch(1); 533 self.sync_ppu(); 534 if !self.ppu.palette_ram_in_use() { 535 break; 536 } 537 } 538 } 539 540 fn read_palette_ram<const SIZE: u8>(&mut self, address: u32) -> u32 { 541 if SIZE == OpSize::WORD { 542 let low = self.read_palette_ram::<{ OpSize::HALFWORD }>(address & !2); 543 let high = self.read_palette_ram::<{ OpSize::HALFWORD }>(address | 2); 544 let value = (low & 0xFFFF) | (high << 16); 545 return self.update_open_bus::<{ OpSize::WORD }>(value); 546 } 547 548 self.block_until_palette_ram_free(); 549 550 let mut value = self.ppu.read_palette_ram(address); 551 if SIZE == OpSize::BYTE { 552 value = value.to_le_bytes()[(address & 1) as usize].into(); 553 } 554 555 self.update_open_bus::<SIZE>(value.into()) 556 } 557 558 fn write_palette_ram<const SIZE: u8>(&mut self, address: u32, value: u32) { 559 if SIZE == OpSize::WORD { 560 self.write_palette_ram::<{ OpSize::HALFWORD }>(address & !2, value & 0xFFFF); 561 self.write_palette_ram::<{ OpSize::HALFWORD }>(address | 2, value >> 16); 562 self.update_open_bus::<SIZE>(value); 563 return; 564 } 565 566 self.update_open_bus::<SIZE>(value); 567 568 self.block_until_palette_ram_free(); 569 570 match SIZE { 571 OpSize::BYTE => { 572 // 8-bit writes to palette RAM perform a 16-bit write with the byte duplicated 573 self.ppu.write_palette_ram(address, u16::from_ne_bytes([value as u8; 2])); 574 } 575 OpSize::HALFWORD => { 576 self.ppu.write_palette_ram(address, value as u16); 577 } 578 _ => invalid_size!(SIZE), 579 } 580 } 581 582 fn block_until_vram_free(&mut self, address: u32) { 583 loop { 584 self.increment_cycles_with_prefetch(1); 585 self.sync_ppu(); 586 if !self.ppu.vram_in_use(address) { 587 break; 588 } 589 } 590 } 591 592 fn read_vram<const SIZE: u8>(&mut self, address: u32) -> u32 { 593 if SIZE == OpSize::WORD { 594 let low = self.read_vram::<{ OpSize::HALFWORD }>(address & !2); 595 let high = self.read_vram::<{ OpSize::HALFWORD }>(address | 2); 596 let value = (low & 0xFFFF) | (high << 16); 597 return self.update_open_bus::<{ OpSize::WORD }>(value); 598 } 599 600 self.block_until_vram_free(address); 601 602 let mut value = self.ppu.read_vram(address); 603 if SIZE == OpSize::BYTE { 604 value = value.to_le_bytes()[(address & 1) as usize].into(); 605 } 606 607 self.update_open_bus::<SIZE>(value.into()) 608 } 609 610 fn write_vram<const SIZE: u8>(&mut self, address: u32, value: u32) { 611 if SIZE == OpSize::WORD { 612 self.write_vram::<{ OpSize::HALFWORD }>(address & !2, value & 0xFFFF); 613 self.write_vram::<{ OpSize::HALFWORD }>(address | 2, value >> 16); 614 self.update_open_bus::<{ OpSize::WORD }>(value); 615 return; 616 } 617 618 self.update_open_bus::<SIZE>(value); 619 620 self.block_until_vram_free(address); 621 622 match SIZE { 623 OpSize::BYTE => { 624 self.ppu.write_vram_byte(address, value as u8); 625 } 626 OpSize::HALFWORD => { 627 self.ppu.write_vram(address, value as u16); 628 } 629 _ => invalid_size!(SIZE), 630 } 631 } 632 633 fn read_oam<const SIZE: u8>(&mut self, address: u32) -> u32 { 634 self.increment_cycles_with_prefetch(1); 635 // TODO should block if OAM is in use - requires precise tracking of when PPU accesses OAM 636 637 let value = match SIZE { 638 OpSize::BYTE | OpSize::HALFWORD => { 639 let mut value = self.ppu.read_oam(address); 640 if SIZE == OpSize::BYTE { 641 value = value.to_le_bytes()[(address & 1) as usize].into(); 642 } 643 value.into() 644 } 645 OpSize::WORD => { 646 let low: u32 = self.ppu.read_oam(address & !2).into(); 647 let high: u32 = self.ppu.read_oam(address | 2).into(); 648 low | (high << 16) 649 } 650 _ => invalid_size!(SIZE), 651 }; 652 653 // TODO supposedly OAM accesses update open bus differently from other non-IWRAM regions? 654 self.update_open_bus::<SIZE>(value) 655 } 656 657 fn write_oam<const SIZE: u8>(&mut self, address: u32, value: u32) { 658 self.increment_cycles_with_prefetch(1); 659 // TODO should block if OAM is in use - requires precise tracking of when PPU accesses OAM 660 661 // TODO supposedly OAM accesses update open bus differently from other non-IWRAM regions? 662 self.update_open_bus::<SIZE>(value); 663 664 match SIZE { 665 OpSize::BYTE => { 666 // 8-bit writes to OAM are ignored 667 } 668 OpSize::HALFWORD => { 669 self.ppu.write_oam(address, value as u16); 670 } 671 OpSize::WORD => { 672 self.ppu.write_oam(address & !2, value as u16); 673 self.ppu.write_oam(address | 2, (value >> 16) as u16); 674 } 675 _ => invalid_size!(SIZE), 676 } 677 } 678 679 pub fn rom_access_cycles(&self, address: u32) -> u64 { 680 if self.cartridge.rom_burst_active() { 681 self.memory.control().rom_s_cycles(address) 682 } else { 683 self.memory.control().rom_n_cycles(address) 684 } 685 } 686 687 fn read_cartridge_rom<const SIZE: u8, const CTX: u8>( 688 &mut self, 689 mut address: u32, 690 cycle: MemoryCycle, 691 ) -> u32 { 692 if SIZE == OpSize::WORD { 693 address &= !3; 694 } 695 696 let prefetch_enabled = self.memory.control().prefetch_enabled; 697 let value = if CTX == AccessCtx::CPU_INSTRUCTION 698 && (prefetch_enabled || self.prefetch.can_use_for(address)) 699 { 700 assert_ne!(SIZE, OpSize::BYTE); 701 702 if prefetch_enabled { 703 self.prepare_prefetch_read(address); 704 } 705 706 self.state.cycles += 1; 707 self.advance_prefetch(1); 708 let mut opcode: u32 = self.prefetch_read().into(); 709 710 if SIZE == OpSize::WORD { 711 let high: u32 = if prefetch_enabled || self.prefetch.can_use_for(address | 2) { 712 self.prefetch_read().into() 713 } else { 714 self.stop_prefetch(); 715 self.state.cycles += self.rom_access_cycles(address | 2); 716 self.cartridge.read_rom(address | 2).into() 717 }; 718 opcode |= high << 16; 719 } 720 721 opcode 722 } else { 723 self.stop_prefetch(); 724 self.maybe_end_rom_burst_on_access(cycle); 725 726 self.state.cycles += self.rom_access_cycles(address); 727 let mut value: u32 = self.cartridge.read_rom(address).into(); 728 729 match SIZE { 730 OpSize::BYTE => { 731 value = value.to_le_bytes()[(address & 1) as usize].into(); 732 } 733 OpSize::HALFWORD => {} 734 OpSize::WORD => { 735 self.state.cycles += self.rom_access_cycles(address | 2); 736 let high: u32 = self.cartridge.read_rom(address | 2).into(); 737 value |= high << 16; 738 } 739 _ => invalid_size!(SIZE), 740 } 741 742 value 743 }; 744 745 self.update_open_bus::<SIZE>(value) 746 } 747 748 fn write_cartridge_rom<const SIZE: u8>( 749 &mut self, 750 mut address: u32, 751 value: u32, 752 cycle: MemoryCycle, 753 ) { 754 if SIZE == OpSize::WORD { 755 address &= !3; 756 } 757 758 self.stop_prefetch(); 759 self.maybe_end_rom_burst_on_access(cycle); 760 761 self.update_open_bus::<SIZE>(value); 762 763 self.state.cycles += self.rom_access_cycles(address); 764 self.cartridge.write_rom(address, value as u16); 765 766 if SIZE == OpSize::WORD { 767 self.state.cycles += self.rom_access_cycles(address | 2); 768 self.cartridge.write_rom(address | 2, (value >> 16) as u16); 769 } 770 } 771 772 fn read_cartridge_sram<const SIZE: u8>(&mut self, address: u32) -> u32 { 773 self.stop_prefetch(); 774 775 self.state.cycles += self.memory.control().sram_cycles; 776 777 let byte = self.cartridge.read_sram(address); 778 779 // SRAM only has an 8-bit data bus; 16-bit and 32-bit reads duplicate the byte 780 let value = match SIZE { 781 OpSize::BYTE => byte.into(), 782 OpSize::HALFWORD => u16::from_ne_bytes([byte; 2]).into(), 783 OpSize::WORD => u32::from_ne_bytes([byte; 4]), 784 _ => invalid_size!(SIZE), 785 }; 786 787 self.update_open_bus::<SIZE>(value) 788 } 789 790 fn write_cartridge_sram<const SIZE: u8>(&mut self, address: u32, value: u32) { 791 self.stop_prefetch(); 792 793 self.state.cycles += self.memory.control().sram_cycles; 794 self.update_open_bus::<SIZE>(value); 795 796 // SRAM only has an 8-bit data bus; 16-bit and 32-bit writes only update one byte 797 match SIZE { 798 OpSize::BYTE => self.cartridge.write_sram(address, value as u8), 799 OpSize::HALFWORD => { 800 let byte = value.to_le_bytes()[(address & 1) as usize]; 801 self.cartridge.write_sram(address, byte); 802 } 803 OpSize::WORD => { 804 let byte = value.to_le_bytes()[(address & 3) as usize]; 805 self.cartridge.write_sram(address, byte); 806 } 807 _ => invalid_size!(SIZE), 808 } 809 } 810 811 fn read_invalid<const SIZE: u8>(&mut self, address: u32) -> u32 { 812 self.increment_cycles_with_prefetch(1); 813 self.read_open_bus::<SIZE>(address) 814 } 815 816 fn write_invalid(&mut self) { 817 self.increment_cycles_with_prefetch(1); 818 // TODO do writes to invalid addresses update open bus? 819 } 820 821 pub fn try_progress_dma(&mut self) { 822 struct AccessedRom(bool); 823 824 impl AccessedRom { 825 fn check(&mut self, address: u32, end_rom_burst: impl FnOnce()) { 826 if !self.0 && address >= 0x8000000 { 827 end_rom_burst(); 828 self.0 = true; 829 } 830 } 831 } 832 833 if self.state.locked { 834 // DMA cannot run while CPU is locking the bus (SWAP instruction) 835 return; 836 } 837 838 let mut accessed_rom = AccessedRom(false); 839 840 loop { 841 self.process_scheduler_events(); 842 843 let Some(transfer) = self.dma.next_transfer(&mut self.interrupts, self.state.cycles) 844 else { 845 if self.state.active_dma_channel.is_some() { 846 // Idle cycle and end ROM burst when DMA finishes 847 self.increment_cycles_with_prefetch(1); 848 849 if accessed_rom.0 || !self.memory.control().prefetch_enabled { 850 self.cartridge.end_rom_burst(); 851 } 852 } 853 self.state.active_dma_channel = None; 854 855 return; 856 }; 857 858 if self.state.active_dma_channel.is_none() { 859 // Idle cycle and end ROM burst when DMA starts 860 self.increment_cycles_with_prefetch(1); 861 } else if self.state.active_dma_channel != Some(transfer.channel) { 862 // End ROM burst when channel changes if previous channel accessed ROM 863 if accessed_rom.0 { 864 self.cartridge.end_rom_burst(); 865 } 866 accessed_rom.0 = false; 867 } 868 self.state.active_dma_channel = Some(transfer.channel); 869 870 match transfer.unit { 871 TransferUnit::Halfword => { 872 let value = if let Some(address) = transfer.source { 873 accessed_rom.check(address, || self.cartridge.end_rom_burst()); 874 875 let value = self.read_internal::<{ OpSize::HALFWORD }, { AccessCtx::DMA }>( 876 address & !1, 877 MemoryCycle::S, 878 ); 879 self.dma.update_read_latch_halfword(transfer.channel, value as u16); 880 value 881 } else { 882 // Invalid address; reads latched value 883 self.increment_cycles_with_prefetch(1); 884 885 let shift = 8 * (transfer.destination & 2); 886 (transfer.read_latch >> shift) & 0xFFFF 887 }; 888 889 accessed_rom.check(transfer.destination, || self.cartridge.end_rom_burst()); 890 self.write_internal::<{ OpSize::HALFWORD }, { AccessCtx::DMA }>( 891 transfer.destination & !1, 892 value, 893 MemoryCycle::S, 894 ); 895 } 896 TransferUnit::Word => { 897 let value = if let Some(address) = transfer.source { 898 accessed_rom.check(address, || self.cartridge.end_rom_burst()); 899 900 let value = self.read_internal::<{ OpSize::WORD }, { AccessCtx::DMA }>( 901 address & !3, 902 MemoryCycle::S, 903 ); 904 self.dma.update_read_latch_word(transfer.channel, value); 905 value 906 } else { 907 // Invalid address; reads latched value 908 self.increment_cycles_with_prefetch(1); 909 transfer.read_latch 910 }; 911 912 accessed_rom.check(transfer.destination, || self.cartridge.end_rom_burst()); 913 self.write_internal::<{ OpSize::WORD }, { AccessCtx::DMA }>( 914 transfer.destination & !3, 915 value, 916 MemoryCycle::S, 917 ); 918 } 919 } 920 } 921 } 922 923 pub fn sync_ppu(&mut self) { 924 self.ppu.step_to(self.state.cycles, &mut self.dma, &mut self.scheduler); 925 } 926 927 pub fn sync_timers(&mut self) { 928 self.timers.step_to( 929 self.state.cycles, 930 &mut self.apu, 931 &mut self.dma, 932 &mut self.interrupts, 933 &mut self.scheduler, 934 ); 935 } 936 937 pub fn process_scheduler_events(&mut self) { 938 if !self.scheduler.is_event_ready(self.state.cycles) { 939 return; 940 } 941 942 while let Some((event, cycles)) = self.scheduler.pop(self.state.cycles) { 943 match event { 944 SchedulerEvent::VBlankIrq => { 945 self.interrupts.set_flag(InterruptType::VBlank, cycles); 946 self.ppu.schedule_next_vblank_irq(&mut self.scheduler, cycles); 947 } 948 SchedulerEvent::HBlankIrq => { 949 self.interrupts.set_flag(InterruptType::HBlank, cycles); 950 self.ppu.schedule_next_hblank_irq(&mut self.scheduler, cycles); 951 } 952 SchedulerEvent::VCounterIrq => { 953 self.interrupts.set_flag(InterruptType::VCounter, cycles); 954 self.ppu.schedule_next_v_counter_irq(&mut self.scheduler, cycles); 955 } 956 SchedulerEvent::PpuEvent => { 957 self.sync_ppu(); 958 } 959 SchedulerEvent::TimerOverflow => { 960 self.sync_timers(); 961 } 962 SchedulerEvent::Dummy => {} 963 } 964 } 965 } 966 967 fn maybe_end_rom_burst_on_access(&mut self, cycle: MemoryCycle) { 968 // N cycles always end ROM burst when prefetch is disabled 969 if cycle == MemoryCycle::N { 970 self.cartridge.end_rom_burst(); 971 } 972 } 973 974 fn end_rom_burst_if_not_accessed(&mut self, address: u32) { 975 // When prefetch is disabled, cycles that don't access ROM end any in-progress ROM burst 976 // mgba-suite timing tests exercise this (LDMIA that overflows from OAM to ROM) 977 // This does not apply to DMA 978 if !self.memory.control().prefetch_enabled && address < 0x08000000 { 979 self.cartridge.end_rom_burst(); 980 } 981 } 982} 983 984impl BusInterface for Bus { 985 #[inline] 986 fn read<const SIZE: u8>(&mut self, address: u32, cycle: MemoryCycle) -> u32 { 987 self.read_internal::<SIZE, { AccessCtx::CPU_DATA }>(address, cycle) 988 } 989 990 #[inline] 991 fn fetch_opcode<const SIZE: u8>(&mut self, address: u32, cycle: MemoryCycle) -> u32 { 992 self.state.cpu_pc = address; 993 self.read_internal::<SIZE, { AccessCtx::CPU_INSTRUCTION }>(address, cycle) 994 } 995 996 #[inline] 997 fn write<const SIZE: u8>(&mut self, address: u32, value: u32, cycle: MemoryCycle) { 998 self.write_internal::<SIZE, { AccessCtx::CPU_DATA }>(address, value, cycle); 999 } 1000 1001 #[inline] 1002 fn irq(&self) -> bool { 1003 self.interrupts.irq() 1004 } 1005 1006 #[inline] 1007 fn internal_cycles(&mut self, cycles: u32) { 1008 // DMA can run during internal cycles without halting the CPU 1009 let new_cycles = self.state.cycles + u64::from(cycles); 1010 while self.state.cycles < new_cycles { 1011 self.try_progress_dma(); 1012 self.interrupts.cpu_bus_cycle(self.state.cycles); 1013 1014 if self.state.cycles < new_cycles { 1015 self.increment_cycles_with_prefetch(1); 1016 } 1017 } 1018 1019 // "Prefetch disabled bug" 1020 // When the CPU takes an internal cycle while prefetch is disabled, any in-progress ROM burst ends 1021 // This forces the next ROM access to use N-cycle timings 1022 if !self.memory.control().prefetch_enabled { 1023 self.cartridge.end_rom_burst(); 1024 } 1025 } 1026 1027 #[inline] 1028 fn lock(&mut self) { 1029 self.state.locked = true; 1030 } 1031 1032 #[inline] 1033 fn unlock(&mut self) { 1034 self.state.locked = false; 1035 } 1036} 1037 1038#[cfg(test)] 1039mod tests { 1040 use super::*; 1041 use crate::api::{GbaAudioConfig, GbaEmulatorConfig}; 1042 1043 #[test] 1044 fn no_io_addresses_panic() { 1045 let mut bus = Bus { 1046 ppu: Ppu::new(false), 1047 apu: Apu::new(GbaAudioConfig::default()), 1048 memory: Memory::new(vec![0; 16 * 1024], GbaEmulatorConfig::default()).unwrap(), 1049 cartridge: Cartridge::new(vec![0; 4 * 1024 * 1024], None, None, None), 1050 prefetch: GamePakPrefetcher::new(), 1051 dma: DmaState::new(), 1052 timers: Timers::new(), 1053 interrupts: InterruptRegisters::new(), 1054 sio: SerialPort::new(), 1055 inputs: InputState::new(&GbaEmulatorConfig::default()), 1056 state: BusState::new(), 1057 scheduler: Scheduler::new(), 1058 }; 1059 1060 for address in 0x04000000..=0x0400FFFF { 1061 bus.read_byte(address, MemoryCycle::S); 1062 bus.read_halfword(address, MemoryCycle::S); 1063 bus.read_word(address, MemoryCycle::S); 1064 bus.write_byte(address, !0, MemoryCycle::S); 1065 bus.write_halfword(address, !0, MemoryCycle::S); 1066 bus.write_word(address, !0, MemoryCycle::S); 1067 } 1068 } 1069}