Skip to main content

Board

Trait Board 

Source
pub trait Board: Send {
Show 27 methods // Required methods fn name(&self) -> &'static str; fn map(&self, addr24: u32) -> MappedAddr; fn rom(&self) -> &[u8] ; fn sram(&self) -> &[u8] ; fn sram_mut(&mut self) -> &mut [u8] ; // Provided methods fn coprocessor(&self) -> Coprocessor { ... } fn read24(&mut self, addr24: u32) -> u8 { ... } fn write24(&mut self, addr24: u32, val: u8) { ... } fn coprocessor_tick(&mut self) { ... } fn notify_scanline(&mut self) { ... } fn notify_cpu_cycle(&mut self) { ... } fn notify_dma_channel(&mut self, channel: usize, address: u32, count: u16) { ... } fn irq_pending(&self) -> bool { ... } fn debug_gsu_state(&self) -> Option<([u16; 16], u16, u8)> { ... } fn load_firmware(&mut self, _bytes: &[u8]) -> bool { ... } fn firmware_hint(&self) -> Option<&'static str> { ... } fn coprocessor_host_accesses(&self) -> u64 { ... } fn save_state(&self, w: &mut SaveWriter) { ... } fn load_state( &mut self, r: &mut SaveReader<'_>, ) -> Result<(), SaveStateError> { ... } fn has_second_cpu(&self) -> bool { ... } fn second_cpu_read(&mut self, addr24: u32) -> u8 { ... } fn second_cpu_write(&mut self, addr24: u32, val: u8) { ... } fn second_cpu_running(&self) -> bool { ... } fn second_cpu_take_reset(&mut self) -> bool { ... } fn second_cpu_poll_nmi(&mut self) -> bool { ... } fn second_cpu_poll_irq(&self) -> bool { ... } fn second_cpu_tick(&mut self, clocks: u32) { ... }
}
Expand description

A cartridge board: its address mapping + any coprocessor behavior.

The default-no-op hooks are the load-bearing port of RustyNES’s Mapper::notify_*: the CPU/PPU/scheduler call them unconditionally, and only coprocessor boards override them. Keep every board-specific quirk INSIDE its impl Board — never special-case a board from the bus or the PPU.

Required Methods§

Source

fn name(&self) -> &'static str

Human-readable board name (for the debugger + logs), e.g. "LoROM", "HiROM+DSP-1".

Source

fn map(&self, addr24: u32) -> MappedAddr

Decode a 24-bit CPU address (bank << 16) | addr to its backing store. The returned MappedAddr::Rom / MappedAddr::Sram offsets are already folded into range.

Source

fn rom(&self) -> &[u8]

The board’s ROM backing store (for save-states / debugging). Read-only.

Source

fn sram(&self) -> &[u8]

The board’s SRAM backing store (for battery saves / save-states). Read-only.

Source

fn sram_mut(&mut self) -> &mut [u8]

The board’s SRAM backing store, mutable (for battery restore / save-state load).

Provided Methods§

Source

fn coprocessor(&self) -> Coprocessor

Which coprocessor this board carries (or Coprocessor::None).

Source

fn read24(&mut self, addr24: u32) -> u8

Read a byte at a 24-bit CPU address. Default routes through Self::map over the board’s own storage; coprocessor boards override to intercept their register windows.

Source

fn write24(&mut self, addr24: u32, val: u8)

Write a byte at a 24-bit CPU address (SRAM, coprocessor registers, bank latches). Default writes through Self::map to SRAM only — ROM and open bus are read-only.

Source

fn coprocessor_tick(&mut self)

Advance the on-cart coprocessor by one master clock. The Bus calls this from inside its own per-master-tick loop (advance_master, alongside the PPU dot and the APU’s SMP-cycle release) — every single tick, unconditionally, on the coprocessor’s divisor — so a host-driven coprocessor (Super FX/GSU) runs genuinely concurrently with the CPU’s own subsequent instructions instead of draining an entire Go burst to completion “atomically” inside the one bus write that armed it. This mirrors ares’s SuperFX : Thread cothread, which the scheduler interleaves with the main CPU at native master-clock granularity (sfc/coprocessor/superfx/superfx.cpp’s Thread::create + timing.cpp’s Thread::synchronize after every access) — the CPU can do unrelated work, or even service a second Go burst, in between two ticks of the first one, instead of only ever observing the coprocessor’s result after it fully finishes (Gsu::tick doc has the detail on what is, and isn’t, deferred). Default no-op (base LoROM/HiROM/ExHiROM have no coprocessor; DSP-n stays RQM-polled, not tick-driven).

Source

fn notify_scanline(&mut self)

Notify the board that the PPU is starting a new scanline. Default no-op. (Reserved for boards whose coprocessor or IRQ counter is scanline-aligned.)

Source

fn notify_cpu_cycle(&mut self)

Notify the board of one elapsed CPU cycle. Default no-op. Coprocessors with a CPU-cycle-driven IRQ/refresh counter override this.

Source

fn notify_dma_channel(&mut self, channel: usize, address: u32, count: u16)

Notify the board that DMA channel channel’s $43n2-$43n6 source-address/byte-count registers were just written, reporting the channel’s CURRENT full 24-bit source address and 16-bit count. Default no-op. The $4300-$437F DMA register file lives in rustysnes-core::Bus (not routed through Board::read24/write24 at all under normal SNES addressing), so a board that needs to observe DMA setup — S-DD1’s decompression- during-DMA hook, which snoops these exact registers on real hardware (ares sfc/coprocessor/sdd1/sdd1.cpp dmaWrite) — has no other way to see it; this hook is rustysnes-core’s side of that snoop, called after every relevant register write regardless of board (cheap no-op for the other 99% of carts).

Source

fn irq_pending(&self) -> bool

Whether the board is currently asserting its IRQ line (SA-1, Super FX, SPC7110 RTC). Default false. The bus ORs this with the other IRQ sources.

Source

fn debug_gsu_state(&self) -> Option<([u16; 16], u16, u8)>

The GSU register file (R0-R15 + SFR + PBR), for a Super FX board’s debugger Cart panel.

Default None — only crate::coproc::superfx::SuperFxBoard overrides this. A read-only debug accessor, not a control surface (docs/frontend.md §Debugger overlay).

Source

fn load_firmware(&mut self, _bytes: &[u8]) -> bool

Supply a coprocessor firmware dump (e.g. the DSP-1 dsp1.rom). Default false — a base board has no firmware to load. A chip-ROM-dump coprocessor returns true once the dump is accepted; without it the board is non-functional, never silently degraded (docs/adr/0003).

Source

fn firmware_hint(&self) -> Option<&'static str>

The specific firmware file name this board expects (e.g. "dsp2.rom"), if the board knows exactly which chip dump it needs. Default None — most chip-ROM-dump coprocessors accept any same-family, same-size dump (DSP-1 accepts either dsp1.rom or dsp1b.rom), so callers searching a firmware directory should try this exact name FIRST when present: several NEC DSP chips share an identical firmware byte size (docs/cart.md §“the shared NEC core”), so trying a same-sized-but-wrong-chip’s dump would silently load the wrong lookup tables/ program into the engine — this hint is what stops that ambiguity for the single-game variants (DSP-2/4, ST010) that DO need one exact file, not a same-family candidate list.

Source

fn coprocessor_host_accesses(&self) -> u64

Count of host accesses to the coprocessor’s data ports since power-on (debugger / diagnostics). Default 0 — base boards have no coprocessor.

Source

fn save_state(&self, w: &mut SaveWriter)

Write this board’s coprocessor state (registers, cursors, sub-engine state — NOT ROM/SRAM, see above). Default no-op: the base LoROM/HiROM/ExHiROM boards and any coprocessor board that hasn’t opted in yet carry no extra state beyond what System::save_state already captures directly, so writing nothing is correct, not merely convenient — restoring such a board’s post-load state is already exact.

Source

fn load_state(&mut self, r: &mut SaveReader<'_>) -> Result<(), SaveStateError>

The inverse of Self::save_state — restore state a matching save_state call wrote. Default no-op, matching that default. A board overriding one MUST override the other; an asymmetric pair would silently desync a restored coprocessor from its own register file, which is exactly the honesty-gate failure mode docs/adr/0003/docs/adr/0006 forbid.

§Errors

A board rejects malformed/truncated bytes via SaveStateError rather than partially applying them — never a panic on untrusted (user-supplied, possibly hand-edited or corrupted) save-state data.

Source

fn has_second_cpu(&self) -> bool

Whether this board carries a second CPU that core must instantiate + step. Default false.

Source

fn second_cpu_read(&mut self, addr24: u32) -> u8

Read a byte through the second CPU’s memory view (its own address decode). Default open bus.

Source

fn second_cpu_write(&mut self, addr24: u32, val: u8)

Write a byte through the second CPU’s memory view. Default no-op.

Source

fn second_cpu_running(&self) -> bool

Whether the second CPU is currently allowed to execute (not held in reset / sleep). Default false.

Source

fn second_cpu_take_reset(&mut self) -> bool

Take a pending second-CPU reset edge (e.g. SA-1 RESB 1→0). Returns true exactly once per edge; core then resets the second CPU. Default false.

Source

fn second_cpu_poll_nmi(&mut self) -> bool

Edge-triggered NMI to the second CPU (acknowledges on a true return). Default false.

Source

fn second_cpu_poll_irq(&self) -> bool

Level-sensitive IRQ to the second CPU (honored when its I flag is clear). Default false.

Source

fn second_cpu_tick(&mut self, clocks: u32)

Advance the second CPU’s internal timer/counters by clocks of its own master clock. Default no-op.

Implementors§