bus.rsannotatedbus.rssource1069 lines · 38.2 KB · raw
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}