Skip to main content

rustysnes_ppu/
bus.rs

1//! The PPU-side narrow bus trait — the SNES port of RustyNES's `PpuBus`.
2//!
3//! The PPU owns its 64 KiB VRAM, CGRAM, and OAM directly; those are NOT on this trait. This
4//! trait is ONLY for what the PPU must reach through the cartridge: extended Mode 7 / coprocessor
5//! reads on enhancement boards, and the board IRQ/scanline notify hooks (the `notify_a12`
6//! analogues). In production, `rustysnes-core` implements [`VideoBus`] over the cart's
7//! [`rustysnes_cart::Board`]; in unit tests a tiny in-memory impl suffices.
8
9/// The narrow bus interface the PPU sees. Every method has a default so a minimal test impl
10/// (`struct DummyBus; impl VideoBus for DummyBus {}`) compiles.
11pub trait VideoBus {
12    /// Cartridge-mediated read for the PPU (Mode 7 extended-bank fetches on coprocessor
13    /// boards route here; plain boards return open bus). Default `0`.
14    fn cart_read(&mut self, _addr24: u32) -> u8 {
15        0
16    }
17
18    /// Notify the board that the PPU is starting a new scanline (for scanline-aligned
19    /// coprocessor / IRQ logic). Default no-op.
20    fn notify_scanline(&mut self) {}
21
22    /// Notify the board that the PPU has entered vertical blank. Default no-op.
23    fn notify_vblank(&mut self) {}
24}
25
26/// A no-op [`VideoBus`] for unit-testing the PPU in isolation (the one-directional graph is
27/// what makes per-chip testing possible).
28#[derive(Debug, Default)]
29pub struct NullVideoBus;
30
31impl VideoBus for NullVideoBus {}
32
33#[cfg(test)]
34mod tests {
35    use super::*;
36
37    #[test]
38    fn null_bus_reads_open() {
39        let mut bus = NullVideoBus;
40        assert_eq!(bus.cart_read(0x00_8000), 0);
41        bus.notify_scanline();
42        bus.notify_vblank();
43    }
44}