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
impl Spc7110Board
Source§impl Spc7110Board
impl Spc7110Board
Sourcepub fn save_state(&self, w: &mut SaveWriter)
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).
Sourcepub fn load_state(
&mut self,
r: &mut SaveReader<'_>,
) -> Result<(), SaveStateError>
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
impl Board for Spc7110Board
Source§fn coprocessor_tick(&mut self)
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
fn name(&self) -> &'static str
"LoROM", "HiROM+DSP-1".Source§fn coprocessor(&self) -> Coprocessor
fn coprocessor(&self) -> Coprocessor
Coprocessor::None).Source§fn map(&self, addr24: u32) -> MappedAddr
fn map(&self, addr24: u32) -> MappedAddr
(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
fn read24(&mut self, addr24: u32) -> u8
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)
fn write24(&mut self, addr24: u32, val: u8)
Self::map to SRAM only — ROM and open bus are read-only.Source§fn rom(&self) -> &[u8] ⓘ
fn rom(&self) -> &[u8] ⓘ
Source§fn sram(&self) -> &[u8] ⓘ
fn sram(&self) -> &[u8] ⓘ
Source§fn sram_mut(&mut self) -> &mut [u8] ⓘ
fn sram_mut(&mut self) -> &mut [u8] ⓘ
Source§fn save_state(&self, w: &mut SaveWriter)
fn save_state(&self, w: &mut SaveWriter)
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>
fn load_state(&mut self, r: &mut SaveReader<'_>) -> Result<(), SaveStateError>
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 moreSource§fn notify_scanline(&mut self)
fn notify_scanline(&mut self)
Source§fn notify_cpu_cycle(&mut self)
fn notify_cpu_cycle(&mut self)
Source§fn notify_dma_channel(&mut self, channel: usize, address: u32, count: u16)
fn notify_dma_channel(&mut self, channel: usize, address: u32, count: u16)
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
fn irq_pending(&self) -> bool
false. The bus ORs this with the other IRQ sources.Source§fn debug_gsu_state(&self) -> Option<([u16; 16], u16, u8)>
fn debug_gsu_state(&self) -> Option<([u16; 16], u16, u8)>
Source§fn load_firmware(&mut self, _bytes: &[u8]) -> bool
fn load_firmware(&mut self, _bytes: &[u8]) -> bool
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>
fn firmware_hint(&self) -> Option<&'static str>
"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
fn coprocessor_host_accesses(&self) -> u64
0 — base boards have no coprocessor.Source§fn has_second_cpu(&self) -> bool
fn has_second_cpu(&self) -> bool
false.Source§fn second_cpu_read(&mut self, addr24: u32) -> u8
fn second_cpu_read(&mut self, addr24: u32) -> u8
Source§fn second_cpu_write(&mut self, addr24: u32, val: u8)
fn second_cpu_write(&mut self, addr24: u32, val: u8)
Source§fn second_cpu_running(&self) -> bool
fn second_cpu_running(&self) -> bool
false.Source§fn second_cpu_take_reset(&mut self) -> bool
fn second_cpu_take_reset(&mut self) -> bool
true exactly once per
edge; core then resets the second CPU. Default false.Source§fn second_cpu_poll_nmi(&mut self) -> bool
fn second_cpu_poll_nmi(&mut self) -> bool
true return). Default false.Source§fn second_cpu_poll_irq(&self) -> bool
fn second_cpu_poll_irq(&self) -> bool
I flag is clear). Default false.Source§fn second_cpu_tick(&mut self, clocks: u32)
fn second_cpu_tick(&mut self, clocks: u32)
clocks of its own master clock.
Default no-op.