Skip to main content

Spc7110Board

Struct Spc7110Board 

Source
pub struct Spc7110Board { /* private fields */ }
Expand description

A cartridge carrying an SPC7110 (owns its ROM/RAM mapping directly — see the module doc).

Implementations§

Source§

impl Spc7110Board

Source

pub fn new(prom: Box<[u8]>, drom: Box<[u8]>, sram_size: usize) -> Self

Build an SPC7110 board directly from the cart’s split PROM/DROM + header SRAM size.

Source§

impl Spc7110Board

Source

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

Write every register across the DCU/data-port/ALU/memory-control units, the DCU’s dcu_tile scratch buffer, the decompressor’s mid-stream state, and the paired RTC into an "SP70" section. PROM/DROM/battery-SRAM are never written (System::save_state captures SRAM separately via Board::sram; ROM is never embedded, docs/adr/0003).

Source

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

The inverse of Self::save_state.

§Errors

SaveStateError on truncated/corrupt input, a section with unconsumed trailing bytes, or whatever Decompressor::load_state/EpsonRtc::load_state themselves reject. dcu_offset is masked to & 31: it indexes the fixed 32-byte dcu_tile directly (dcu_tile[self.dcu_offset as usize]), and every normal-operation mutator already masks it to 8 * bpp - 1 (at most 31) before storing, so this applies the engine’s own existing invariant rather than new validation policy. Every register masked/write-limited on a normal write_reg call (r4803/r480b/r4813/r4818/r482e/r4830-r4834) is masked identically on load. dcu_mode is restored verbatim: it’s a raw data-ROM byte with no enforced range even during normal execution (an out-of-range value there is a pre-existing, save-state-independent hazard tracked separately, not something this format can or should paper over).

Trait Implementations§

Source§

impl Board for Spc7110Board

Source§

fn coprocessor_tick(&mut self)

Ares’ SPC7110::main(), called once per master clock (Bus::advance_master, matching the SPC7110’s own real cothread rate — Thread::create(21'477'272, ...), exactly the master clock frequency): consume a pending DCU-begin/multiply/divide trigger from the register write that armed it one tick ago. See dcu_pending’s doc for why this one-tick deferral (not a same-write synchronous completion) is the hardware-accurate timing.

Source§

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

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

fn coprocessor(&self) -> Coprocessor

Which coprocessor this board carries (or Coprocessor::None).
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 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 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).
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. Read more
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. Read more
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 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.
Source§

impl Debug for Spc7110Board

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.