pub struct Nes { /* private fields */ }Expand description
Top-level NES emulator handle.
Owns the CPU, PPU, mapper, RAM, and controller stub. Construct via
Nes::from_rom; drive forward via Nes::run_frame or
Nes::step_instruction. The framebuffer can be sampled at any time via
Nes::framebuffer.
Implementations§
Source§impl Nes
impl Nes
Sourcepub const TRACE_CAP: usize = 50_000
pub const TRACE_CAP: usize = 50_000
Maximum cycle-trace ring depth (oldest records drop past this).
Sourcepub fn sram_mut(&mut self) -> &mut [u8] ⓘ
pub fn sram_mut(&mut self) -> &mut [u8] ⓘ
Returns a mutable reference to the cartridge SRAM (if any).
Sourcepub fn vram_mut(&mut self) -> &mut [u8] ⓘ
pub fn vram_mut(&mut self) -> &mut [u8] ⓘ
Returns a mutable reference to the internal VRAM (nametables).
Sourcepub fn from_rom(bytes: &[u8]) -> Result<Self, RomError>
pub fn from_rom(bytes: &[u8]) -> Result<Self, RomError>
Build a new emulator from raw ROM bytes (iNES 1.0 or NES 2.0).
§Errors
Returns the underlying [RomError] if the bytes don’t parse.
Sourcepub fn from_rom_with_sample_rate(
bytes: &[u8],
sample_rate: u32,
) -> Result<Self, RomError>
pub fn from_rom_with_sample_rate( bytes: &[u8], sample_rate: u32, ) -> Result<Self, RomError>
Build an emulator with an explicit audio sample rate (the rate the CPAL stream is opened at).
§Errors
Returns the underlying [RomError] if the bytes don’t parse.
Sourcepub fn from_disk(disk_bytes: &[u8], bios_bytes: &[u8]) -> Result<Self, RomError>
pub fn from_disk(disk_bytes: &[u8], bios_bytes: &[u8]) -> Result<Self, RomError>
Build an emulator from a Famicom Disk System .fds disk image and a
user-supplied 8 KiB BIOS (disksys.rom).
The BIOS is never committed to this repo (it is Nintendo IP); the caller
supplies it (a frontend BIOS prompt is Stage 2). Construction parses the
disk container, builds the FDS device as the bus’s mapper, and runs the
standard cold-boot reset (the BIOS reset vector at $FFFC drives the
disk-load sequence).
Uses the default 44.1 kHz audio sample rate; use
Nes::from_disk_with_sample_rate to pick the rate.
§Errors
Returns the underlying [RomError] if the disk image is unparseable or
the BIOS is not exactly 8 KiB.
Sourcepub fn from_disk_with_sample_rate(
disk_bytes: &[u8],
bios_bytes: &[u8],
sample_rate: u32,
) -> Result<Self, RomError>
pub fn from_disk_with_sample_rate( disk_bytes: &[u8], bios_bytes: &[u8], sample_rate: u32, ) -> Result<Self, RomError>
Build an FDS emulator with an explicit audio sample rate. See
Nes::from_disk.
The reported rom_sha256 hashes the disk-image bytes (not the BIOS), so
save-states / movies key off the disk the way cartridge builds key off
the ROM.
§Errors
Returns the underlying [RomError] if the disk image is unparseable or
the BIOS is not exactly 8 KiB.
Sourcepub fn from_nsf(nsf_bytes: &[u8]) -> Result<Self, RomError>
pub fn from_nsf(nsf_bytes: &[u8]) -> Result<Self, RomError>
Build an emulator that plays a classic NSF (NESM) music file.
Only the classic NESM\x1a container is supported; NSFe and
expansion-chip audio are documented deferrals.
NSF files carry a ripped NES sound engine plus an init/play address
pair, not a PPU program. Construction parses the file, installs a
[rustynes_mappers::NsfMapper] (a synthetic 6502 driver + the program
image) as the bus’s mapper, and runs the standard cold-boot reset — the
driver’s reset vector calls init for the starting song, enables vblank
NMI, and the ordinary 60 Hz NMI then calls play once per frame. Audio
is produced through the unchanged lockstep loop; there is no video.
Uses the default 44.1 kHz sample rate; see
Nes::from_nsf_with_sample_rate.
§Errors
Returns the underlying [RomError] when the NSF header is malformed.
Sourcepub fn from_nsf_with_sample_rate(
nsf_bytes: &[u8],
sample_rate: u32,
) -> Result<Self, RomError>
pub fn from_nsf_with_sample_rate( nsf_bytes: &[u8], sample_rate: u32, ) -> Result<Self, RomError>
Build an NSF player with an explicit audio sample rate. See
Nes::from_nsf.
§Errors
Returns the underlying [RomError] when the NSF header is malformed.
Sourcepub fn nsf_song_count(&self) -> u8
pub fn nsf_song_count(&self) -> u8
Number of selectable songs in the loaded NSF (0 for a cartridge / disk).
Sourcepub fn nsf_current_song(&self) -> u8
pub fn nsf_current_song(&self) -> u8
The currently-selected 0-based NSF song (0 for a cartridge / disk).
Sourcepub fn nsf_set_song(&mut self, song: u8)
pub fn nsf_set_song(&mut self, song: u8)
Select a 0-based NSF song and restart playback on it (re-runs init via
a warm reset). No-op for a cartridge / disk.
Sourcepub fn from_rom_with_power_on_seed(
bytes: &[u8],
seed: u64,
) -> Result<Self, RomError>
pub fn from_rom_with_power_on_seed( bytes: &[u8], seed: u64, ) -> Result<Self, RomError>
Build an emulator with a randomized power-on RAM state (developer mode; Phase 7 / T-72-005).
Identical to Nes::from_rom except the 2 KiB CPU work RAM and the
open-bus latch are filled from a deterministic xorshift64 PRNG keyed
on seed, modelling the unreliable power-on RAM of real hardware
(nesdev “CPU power up state”). Use this to shake out game/test code
that depends on a particular post-power-on RAM pattern.
The randomization is seeded and deterministic — the same seed
yields the same state, so the same seed + ROM + input ⇒ bit-identical
contract still holds. The default Nes::from_rom (zeroed RAM) is
what CI, the regression oracle, and save-state tests use.
§Errors
Returns the underlying [RomError] if the bytes don’t parse.
Sourcepub fn from_rom_with_power_on_config(
bytes: &[u8],
config: PowerOnConfig,
) -> Result<Self, RomError>
pub fn from_rom_with_power_on_config( bytes: &[u8], config: PowerOnConfig, ) -> Result<Self, RomError>
v2.1.7 P5 — build an emulator with an explicit PowerOnConfig.
Generalizes Nes::from_rom_with_power_on_seed: the caller chooses the
power-on work-RAM fill (PowerOnRam::Zeroed / PowerOnRam::Seeded /
PowerOnRam::Filled). The config is stored on the bus so a subsequent
power-cycle re-applies the same fill (keeping power_cycle == fresh boot). All fills are deterministic, so the same config + ROM + input ⇒ bit-identical contract still holds. PowerOnConfig::default
(PowerOnRam::Zeroed) is byte-identical to Nes::from_rom.
§Errors
Returns the underlying [RomError] if the bytes don’t parse.
Sourcepub fn power_cycle(&mut self)
pub fn power_cycle(&mut self)
Power-cycle (cold boot). Zeroes WRAM, re-rolls phase, reloads vectors.
Sourcepub fn run_frame(&mut self) -> &[u8] ⓘ
pub fn run_frame(&mut self) -> &[u8] ⓘ
Run until the PPU finishes a frame. Returns the framebuffer slice.
§Panics
Panics if the CPU JAMs without producing a frame. Real software shouldn’t JAM; if it does, the caller’s run-loop should catch it before the next frame.
Sourcepub const fn set_rewind_capture(&mut self, enabled: bool)
pub const fn set_rewind_capture(&mut self, enabled: bool)
v2.8.0 Phase 3 — enable/disable the per-frame rewind capture while
the ring stays armed. Run-ahead turns it off around its hidden +
visible frames so only persistent-timeline frames land in the ring.
Default true; with no rewind ring armed this is a no-op.
Sourcepub fn step_instruction(&mut self) -> u8
pub fn step_instruction(&mut self) -> u8
Step exactly one CPU instruction. For debuggers / step-through tools.
Sourcepub fn add_breakpoint(&mut self, addr: u16)
pub fn add_breakpoint(&mut self, addr: u16)
v1.1.0 beta.2 (Workstream C) — add an exec/PC breakpoint at addr.
Nes::run_frame stops the frame the next time the program counter
reaches addr (reportable via Nes::take_break_hit). Idempotent.
debug-hooks only.
Sourcepub fn remove_breakpoint(&mut self, addr: u16)
pub fn remove_breakpoint(&mut self, addr: u16)
Remove a previously-added exec breakpoint (no-op if absent).
Sourcepub fn clear_breakpoints(&mut self)
pub fn clear_breakpoints(&mut self)
Remove all breakpoints.
Sourcepub fn breakpoints(&self) -> &[u16]
pub fn breakpoints(&self) -> &[u16]
The current exec breakpoints (insertion order).
Sourcepub const fn set_breakpoints_enabled(&mut self, enabled: bool)
pub const fn set_breakpoints_enabled(&mut self, enabled: bool)
Arm/disarm breakpoint checking without discarding the list. Default on.
Sourcepub const fn breakpoints_enabled(&self) -> bool
pub const fn breakpoints_enabled(&self) -> bool
Whether breakpoint checking is armed.
Sourcepub const fn take_break_hit(&mut self) -> Option<u16>
pub const fn take_break_hit(&mut self) -> Option<u16>
Take the PC that last hit a breakpoint (cleared on read). The frontend
polls this after Nes::run_frame to pause when a breakpoint fired.
Sourcepub const fn set_event_breakpoints(&mut self, mask: u16)
pub const fn set_event_breakpoints(&mut self, mask: u16)
v1.4.0 Workstream D (D2) — arm the event-driven breakpoint categories
(a bit-OR of crate::EventBpKind::bit). 0 (default) disarms every
category — the per-access taps are then a single cheap mask == 0
early-out. Output-only: a hit pauses + reports but never mutates state.
debug-hooks only.
Sourcepub const fn event_breakpoints(&self) -> u16
pub const fn event_breakpoints(&self) -> u16
The armed event-breakpoint category mask.
Sourcepub const fn take_event_break_hit(&mut self) -> Option<EventBreakHit>
pub const fn take_event_break_hit(&mut self) -> Option<EventBreakHit>
Take the first event-breakpoint hit of the current frame (cleared on
read). The frontend polls this after Nes::run_frame to pause when an
armed hardware event fired, reporting its kind + frame/cycle/scanline/dot.
Sourcepub const fn set_trace_enabled(&mut self, enabled: bool)
pub const fn set_trace_enabled(&mut self, enabled: bool)
v1.1.0 beta.2 (T-110-C2) — start/stop the cycle-trace logger. While on,
each executed instruction’s CPU state is pushed to a ring buffer (capped
at Self::TRACE_CAP). Default off.
Sourcepub const fn trace_enabled(&self) -> bool
pub const fn trace_enabled(&self) -> bool
Whether the cycle-trace logger is recording.
Sourcepub fn clear_trace(&mut self)
pub fn clear_trace(&mut self)
Clear the trace ring.
Sourcepub fn trace_records(&self) -> Vec<TraceRec>
pub fn trace_records(&self) -> Vec<TraceRec>
Copy the trace ring oldest-first (for the trace panel / file export).
Sourcepub fn trace_tail_vec(&self, n: usize) -> Vec<TraceRec>
pub fn trace_tail_vec(&self, n: usize) -> Vec<TraceRec>
Copy the most recent n trace records (oldest-first) — for the live
trace panel’s tail view, cheaper than Self::trace_records on a full
ring.
Sourcepub const fn set_event_logging(&mut self, enabled: bool)
pub const fn set_event_logging(&mut self, enabled: bool)
v1.1.0 beta.2 (T-110-C3) — start/stop the event viewer. While on, the bus
records this frame’s PPU/APU/mapper writes (with their PPU position); the
log is reset at each Self::run_frame. Default off; output-only.
Sourcepub const fn event_logging(&self) -> bool
pub const fn event_logging(&self) -> bool
Whether the event viewer is recording.
Sourcepub fn events(&self) -> &[EventRec]
pub fn events(&self) -> &[EventRec]
The current frame’s captured events (for the event-viewer panel).
Sourcepub const fn set_access_logging(&mut self, enabled: bool)
pub const fn set_access_logging(&mut self, enabled: bool)
v1.1.0 beta.3 (T-110-E2) — start/stop the Lua bus-access log. While on,
the bus records this frame’s CPU reads + writes (with values); the log is
reset at each Self::run_frame. Default off; output-only. Enabled by
the scripting engine only while onRead/onWrite callbacks exist.
Sourcepub const fn access_logging(&self) -> bool
pub const fn access_logging(&self) -> bool
Whether the bus-access log is recording.
Sourcepub fn accesses(&self) -> &[AccessRec]
pub fn accesses(&self) -> &[AccessRec]
The current frame’s captured CPU bus accesses (for the Lua engine).
Sourcepub const fn set_exec_logging(&mut self, enabled: bool)
pub const fn set_exec_logging(&mut self, enabled: bool)
v1.1.0 beta.3 (T-110-E2) — start/stop the per-frame exec-PC log for the
Lua onExec callback. Independent of the Trace Logger (set_trace_enabled),
so enabling it does not disturb the debugger’s trace recording. Cleared
every Self::run_frame; output-only.
Sourcepub const fn exec_logging(&self) -> bool
pub const fn exec_logging(&self) -> bool
Whether the per-frame exec-PC log is recording.
Sourcepub fn exec_log(&self) -> &[u16]
pub fn exec_log(&self) -> &[u16]
This frame’s executed PCs, in execution order (for the Lua engine).
Sourcepub const fn was_input_polled_this_frame(&self) -> bool
pub const fn was_input_polled_this_frame(&self) -> bool
true if the running program read a controller port ($4016/$4017)
during the most recent Self::run_frame — the inverse of a TAStudio
“lag frame” (v1.6.0 Workstream A3). The greenzone / piano-roll lag log
queries this each frame. Output-only; debug-hooks-gated, so the
shipped build is byte-identical and the determinism contract holds.
Sourcepub const fn set_interrupt_logging(&mut self, enabled: bool)
pub const fn set_interrupt_logging(&mut self, enabled: bool)
v1.2.0 (T-110-E1) — start/stop the per-frame interrupt-service log for
the Lua onNmi / onIrq callbacks. The log records this frame’s
committed NMI / IRQ / BRK service entries (captured at the CPU’s
service-vector commit point, NOT the speculative poll sampler); it is
cleared at each Self::run_frame. Default off; output-only. Enabled by
the scripting engine only while onNmi/onIrq callbacks exist. Mirrors
Self::set_exec_logging.
Sourcepub const fn interrupt_logging(&self) -> bool
pub const fn interrupt_logging(&self) -> bool
Whether the per-frame interrupt-service log is recording.
Sourcepub fn interrupt_log(&self) -> &[InterruptRec]
pub fn interrupt_log(&self) -> &[InterruptRec]
This frame’s committed interrupt-service entries, in service order (for
the Lua engine). Mirrors Self::exec_log / Self::accesses.
Sourcepub fn framebuffer(&self) -> &[u8] ⓘ
pub fn framebuffer(&self) -> &[u8] ⓘ
Borrow the framebuffer (RGBA8, 256x240).
Sourcepub fn debug_set_framebuffer(&mut self, rgba: &[u8])
pub fn debug_set_framebuffer(&mut self, rgba: &[u8])
v1.7.0 “Forge” Workstream B (B3) — overwrite the RGBA8 output framebuffer
(the Lua emu:setScreenBuffer(t) paints output only). Output-only; see
[rustynes_ppu::Ppu::debug_set_framebuffer]. Reached only through the
script crate’s gated post-frame path, so the shipped build is
byte-identical and the determinism contract holds. debug-hooks-gated.
Sourcepub fn index_framebuffer(&self) -> &[u16]
pub fn index_framebuffer(&self) -> &[u16]
Borrow the parallel palette-index framebuffer (256x240 u16s, each
(emphasis << 6) | colour) for the NES_NTSC composite filter.
See [rustynes_ppu::Ppu::index_framebuffer].
Sourcepub fn hd_tile_source(&self) -> &[HdTileSource]
pub fn hd_tile_source(&self) -> &[HdTileSource]
v1.2.0 C3 (hd-pack) — borrow the per-pixel HD-pack tile-source buffer
(256x240 [rustynes_ppu::HdTileSource] records). Each entry names the
CHR tile that produced the pixel; the frontend HD-pack loader groups
these by 8x8 cell, hashes the CHR bytes, and substitutes hi-res tiles.
Output-only telemetry; the determinism contract is unaffected. See
[rustynes_ppu::Ppu::hd_tile_source].
Sourcepub const fn hd_bg_scroll(&self) -> (i32, i32)
pub const fn hd_bg_scroll(&self) -> (i32, i32)
The frame’s background scroll (x, y) in NES pixels, for offsetting
parallax HD-pack <background> layers (see
[rustynes_ppu::Ppu::hd_bg_scroll]). Output-only.
Sourcepub const fn ntsc_phase(&self) -> u8
pub const fn ntsc_phase(&self) -> u8
The per-frame NTSC composite colour phase consumed by the NES_NTSC
filter (0..=2 on NTSC; frame parity 0..=1 on PAL/Dendy). See
[rustynes_ppu::Ppu::ntsc_phase].
Sourcepub const fn frame(&self) -> u64
pub const fn frame(&self) -> u64
The completed-frame counter (PPU frames since power-on). A monotonic, deterministic, save-state-restored value — the frontend uses it to phase turbo/autofire so the strobe is reproducible under rollback / TAS replay.
Sourcepub const fn bus(&self) -> &LockstepBus
pub const fn bus(&self) -> &LockstepBus
Borrow the underlying bus (debugger / tests).
Sourcepub const fn bus_mut(&mut self) -> &mut LockstepBus
pub const fn bus_mut(&mut self) -> &mut LockstepBus
Mutably borrow the underlying bus (debugger / tests).
Sourcepub const fn is_jammed(&self) -> bool
pub const fn is_jammed(&self) -> bool
true when the CPU has executed a JAM/KIL/STP and is halted.
(v2.0.0 beta.5: the VsDualSystem soft-lockstep driver guards its
per-instruction stepping — the pre-existing debugger
Self::step_instruction — on this.)
Sourcepub const fn region(&self) -> Region
pub const fn region(&self) -> Region
Cartridge region (NTSC / PAL / Dendy / Multi). Drives wall-clock frame pacing in the frontend and clock dividers in the chip cores.
Sourcepub const fn prg_rom_len(&self) -> usize
pub const fn prg_rom_len(&self) -> usize
Length in bytes of the loaded cartridge’s PRG-ROM (read-only metadata).
Exposed for the Lua scripting cart:prg_size() query (and any other
read-only consumer); does not touch deterministic state.
Sourcepub const fn chr_rom_len(&self) -> usize
pub const fn chr_rom_len(&self) -> usize
Length in bytes of the loaded cartridge’s CHR-ROM (0 when the board uses
CHR-RAM). Read-only metadata; backs the Lua cart:chr_size() query.
Sourcepub fn mapper_id(&self) -> u16
pub fn mapper_id(&self) -> u16
The loaded mapper’s iNES / NES 2.0 mapper id (backs cart:mapper_id()).
Sourcepub const fn frame_duration(&self) -> Duration
pub const fn frame_duration(&self) -> Duration
Wall-clock frame duration for this cartridge’s region. The frontend
uses this to pace emulator advance independently of monitor refresh
rate — without it, Fifo present mode on a 144 Hz monitor would
run the emulator 2.4× too fast.
Sourcepub fn drain_audio(&mut self) -> Vec<f32>
pub fn drain_audio(&mut self) -> Vec<f32>
Drain accumulated audio samples (host sample rate, normalized
[0.0, ~1.0]). Call once per frame from the frontend’s audio thread
or batch driver.
Set the buttons currently held on player port. Ports 0/1 are the
standard controllers ($4016/$4017); ports 2/3 are players 3/4 on
the Four Score adapter (only polled when Self::set_four_score is
on). The change takes effect on the next strobe edge.
§Panics
Panics if port is not in 0..=3.
Get the buttons currently held on player port (0/1 = $4016/$4017;
2/3 = Four Score players 3/4). Read-only; does not advance emulator
state.
Used by the TAS movie recorder (crate::movie) to capture the inputs
applied before each Self::run_frame. (Movies record players 1 & 2;
Four Score players 3/4 are not part of the .rnm stream.)
§Panics
Panics if port is not in 0..=3.
Sourcepub const fn set_four_score(&mut self, enabled: bool)
pub const fn set_four_score(&mut self, enabled: bool)
Enable/disable the Four Score 4-player adapter. Off by default; while
off, controller reads are byte-identical to the standard two-pad
behavior (the determinism contract and save-states are unaffected).
When on, players 3/4 (ports 2/3) are multiplexed onto $4016/$4017
across a 24-read serial sequence.
Sourcepub const fn four_score(&self) -> bool
pub const fn four_score(&self) -> bool
Whether the Four Score adapter is currently enabled.
Sourcepub fn is_vs_system(&self) -> bool
pub fn is_vs_system(&self) -> bool
True when the running cart is Nintendo Vs. System arcade hardware (NES 2.0 console type = Vs. System). The RGB PPU + DIP/coin inputs only take effect on such carts.
Sourcepub const fn is_vs_dual_system(&self) -> bool
pub const fn is_vs_dual_system(&self) -> bool
True when the cart’s header marks a Vs. DualSystem board (two CPUs /
two PPUs; NES 2.0 byte-13 high nibble = Vs. hardware type 5/6).
Detection only: this single-system core cannot boot a DualSystem title
past its attract handshake, so the frontend uses this to surface a clear
note. The two-CPU/two-PPU emulation is a documented v2.0 deferral
(docs/audit/vs-dualsystem-design-2026-06-11.md).
Sourcepub const fn set_vs_dip(&mut self, dip: u8)
pub const fn set_vs_dip(&mut self, dip: u8)
Set the Vs. System 8-bit DIP-switch bank (switch 1 = bit 0 .. switch 8 =
bit 7). Read through the upper bits of $4016/$4017. No effect on
non-Vs. carts; the standard controller read stays byte-identical.
Sourcepub const fn set_vs_ppu_type(&mut self, t: VsPpuType)
pub const fn set_vs_ppu_type(&mut self, t: VsPpuType)
Override the Vs. System PPU type and re-apply the output palette.
iNES-1.0 Vs. dumps default to the 2C03 palette (no NES 2.0 byte-13);
the per-game database (crate::vs_db) supplies the correct
2C04-000x / 2C05 type, which the frontend applies through this setter.
Affects only the colour LUT the PPU emits through, never game logic.
No effect on non-Vs. carts.
Sourcepub const fn insert_coin(&mut self, acceptor: u8)
pub const fn insert_coin(&mut self, acceptor: u8)
Latch a Vs. System coin insertion on the given acceptor (0 = #1, 1 = #2).
Reads true for a real-hardware ~40-70 ms window; the frontend should
clear it (see Self::clear_coin) after a few frames.
Sourcepub const fn clear_coin(&mut self)
pub const fn clear_coin(&mut self)
Clear all latched Vs. System coin-insert signals.
Sourcepub const fn set_vs_service(&mut self, pressed: bool)
pub const fn set_vs_service(&mut self, pressed: bool)
Set / clear the Vs. System service button.
Sourcepub fn disk_side_count(&self) -> usize
pub fn disk_side_count(&self) -> usize
Number of disk sides in the inserted FDS image. Returns 0 for cartridge builds (so a frontend can branch on “is this an FDS game?”).
Sourcepub fn inserted_disk_side(&self) -> Option<usize>
pub fn inserted_disk_side(&self) -> Option<usize>
The currently inserted FDS disk side index, or None when ejected (or
for a cartridge build). A game that prompts “insert side B” is asking the
user to call Self::set_disk_side.
Sourcepub fn set_disk_side(&mut self, side: Option<usize>)
pub fn set_disk_side(&mut self, side: Option<usize>)
Insert FDS side i (Some(i)) or eject the disk (None). Inserting
resets the head and opens a short deterministic “not ready” window (the
BIOS polls $4032 and waits for ready); an out-of-range index is
ignored. No-op on cartridge builds. This is how the user complies with a
game’s “insert side N” prompt.
Sourcepub fn enable_fds_trace(&mut self)
pub fn enable_fds_trace(&mut self)
Start recording the diagnostic FDS read-stream trace (the $4031 disk-byte
stream + $4025 control writes + side changes). Off by default and
observation-only — it never affects emulation, so the determinism contract
holds. Drain it with Self::take_fds_trace. No-op on cartridge builds.
Used by the fds_trace diagnostic harness to debug disk-read / side-swap
failures (e.g. the Kid Icarus side-B ERR.07 stall).
Sourcepub fn take_fds_trace(&mut self) -> Vec<FdsTraceRec>
pub fn take_fds_trace(&mut self) -> Vec<FdsTraceRec>
Drain the accumulated FDS read-stream trace records. Empty for cartridge
builds or when Self::enable_fds_trace was never called.
Sourcepub fn disk_image_bytes(&self) -> Vec<u8> ⓘ
pub fn disk_image_bytes(&self) -> Vec<u8> ⓘ
Re-serialize the (possibly-modified) FDS disk image to the headerless
.fds byte layout so the host can write it to a side-car .fds.sav
(keyed by Self::rom_sha256). Empty for cartridge builds.
Sourcepub fn disk_is_dirty(&self) -> bool
pub fn disk_is_dirty(&self) -> bool
Whether the FDS disk image has unsaved writes since the last
Self::clear_disk_dirty. A frontend checks this on quit / periodically
to decide whether to persist the disk.
Sourcepub fn clear_disk_dirty(&mut self)
pub fn clear_disk_dirty(&mut self)
Clear the FDS disk dirty flag after persisting the image.
Sourcepub fn set_disk_write_protected(&mut self, protected: bool)
pub fn set_disk_write_protected(&mut self, protected: bool)
Mark the inserted FDS disk read-only (true) or writable (false,
the default). Drives the $4032 write-protect flag; a write-protected
disk drops bytes in write mode without modifying the medium.
Sourcepub fn set_expansion_device(&mut self, port: usize, device: Option<InputDevice>)
pub fn set_expansion_device(&mut self, port: usize, device: Option<InputDevice>)
Attach a non-standard overlay input device on port (0 = $4016, 1 =
$4017). Pass None to unplug it and return the port to the standard
controller / Four Score path (byte-identical reads). Devices are
unplugged on power-cycle.
§Panics
Panics if port is not in 0..=1.
Sourcepub const fn expansion_device(&self, port: usize) -> &Option<InputDevice>
pub const fn expansion_device(&self, port: usize) -> &Option<InputDevice>
Borrow the overlay device attached to port (0 = $4016, 1 =
$4017), if any.
§Panics
Panics if port is not in 0..=1.
Sourcepub fn set_paddle(&mut self, port: usize, position: u8, fire: bool)
pub fn set_paddle(&mut self, port: usize, position: u8, fire: bool)
Attach an Arkanoid “Vaus” paddle on port (typically port 1 / $4017)
and set its position + fire state. position is the raw 8-bit
potentiometer value ($00 far-left .. $FF far-right); fire is the
single button. Convenience wrapper that attaches the device if absent
then updates it.
§Panics
Panics if port is not in 0..=1.
Sourcepub fn set_zapper(&mut self, port: usize, x: u16, y: u16, trigger: bool)
pub fn set_zapper(&mut self, port: usize, x: u16, y: u16, trigger: bool)
Attach an NES Zapper light gun on port (typically port 1 / $4017)
and set its aim point + trigger. (x, y) is the screen pixel the gun is
aimed at (0..256, 0..240; out of range = off-screen); trigger is the
trigger state. Convenience wrapper that attaches the device if absent
then updates it.
Light detection is sampled from the framebuffer at the end of each
Self::run_frame; the determinism contract holds because the sample
only runs when a Zapper is attached (the no-device path is unchanged).
§Panics
Panics if port is not in 0..=1.
Sourcepub fn set_power_pad(&mut self, port: usize, buttons: u16)
pub fn set_power_pad(&mut self, port: usize, buttons: u16)
Attach an NES Power Pad / Family Fun Fitness mat on port (typically
port 1 / $4017) and set its live button mask (bit i = mat button
i+1, 0..=11). Convenience wrapper that attaches the device if absent
then updates it. Opt-in: the no-device path stays byte-identical.
§Panics
Panics if port is not in 0..=1.
v1.6.0 B3 — the latched standard-controller button bitmask for port
(0 = P1 / $4016, 1 = P2 / $4017; 2/3 are the Four Score
players), in Buttons bit order (A = bit 0 .. Right =
bit 7). Read-only and side-effect-free — it reads the latched state, not
the shift register, so it never perturbs a controller poll. Exposed for
the Lua joypad.get query.
§Panics
Panics if port is not in 0..=3.
Sourcepub fn set_snes_mouse(
&mut self,
port: usize,
dx: i16,
dy: i16,
left: bool,
right: bool,
sensitivity: u8,
)
pub fn set_snes_mouse( &mut self, port: usize, dx: i16, dy: i16, left: bool, right: bool, sensitivity: u8, )
v1.2.0 Workstream D — attach a SNES-style serial mouse on port (0 =
$4016, 1 = $4017) and set its movement / buttons / sensitivity.
(dx, dy) are the signed per-frame deltas (clamped to +/-127 on latch);
sensitivity is 0 (low) / 1 (medium) / 2 (high). Convenience wrapper
that attaches the device if absent then updates it. Opt-in: the no-device
path stays byte-identical.
§Panics
Panics if port is not in 0..=1.
Sourcepub fn set_family_keyboard(&mut self, port: usize, keys: [u8; 9])
pub fn set_family_keyboard(&mut self, port: usize, keys: [u8; 9])
v1.2.0 Workstream D — attach a Famicom Family BASIC keyboard on port
(typically port 1 / $4017) and set its pressed-key bitmap. keys is
one byte per matrix row (keys[row] bits 0..=3 = column-half 0 keys,
bits 4..=7 = column-half 1 keys); the frontend builds it from host keys.
Convenience wrapper that attaches the device if absent then updates it.
Opt-in: the no-device path stays byte-identical.
§Panics
Panics if port is not in 0..=1.
Sourcepub fn set_family_trainer(&mut self, port: usize, buttons: u16)
pub fn set_family_trainer(&mut self, port: usize, buttons: u16)
v1.3.0 Workstream F1 — attach a Bandai Family Trainer mat on port
and set its 12-button mask (bit i = mat button i+1). The Family
Trainer is layout-equivalent to the Power Pad and reuses its scan; this
attaches the InputDevice::FamilyTrainer variant (distinct from
Self::set_power_pad so the selected device round-trips through a
save-state). Opt-in: the no-device path stays byte-identical.
§Panics
Panics if port is not in 0..=1.
Sourcepub fn set_subor_keyboard(&mut self, port: usize, keys: [u8; 9])
pub fn set_subor_keyboard(&mut self, port: usize, keys: [u8; 9])
v1.3.0 Workstream F1 — attach a Subor keyboard on port and set its
pressed-key bitmap (one byte per matrix row, like
Self::set_family_keyboard). The Subor keyboard reuses the Family
BASIC keyboard matrix scan; this attaches the
InputDevice::SuborKeyboard variant. Opt-in: the no-device path stays
byte-identical.
§Panics
Panics if port is not in 0..=1.
Sourcepub fn set_konami_hyper_shot(&mut self, port: usize, buttons: u8)
pub fn set_konami_hyper_shot(&mut self, port: usize, buttons: u8)
v1.3.0 Workstream F1 — attach a Konami Hyper Shot on port and set
its 4-button mask (bit 0 = P1 Run, 1 = P1 Jump, 2 = P2 Run, 3 = P2 Jump).
Opt-in: the no-device path stays byte-identical.
§Panics
Panics if port is not in 0..=1.
Sourcepub fn set_bandai_hyper_shot(&mut self, port: usize, sensors: u8)
pub fn set_bandai_hyper_shot(&mut self, port: usize, sensors: u8)
v1.3.0 Workstream F1 — attach a Bandai Hyper Shot (Exciting Boxing
punching bag) on port and set its 8-sensor mask (bits 0..=3 = the A=0
group, bits 4..=7 = the A=1 group). Opt-in: the no-device path stays
byte-identical.
§Panics
Panics if port is not in 0..=1.
Sourcepub const fn set_mirroring_override(&mut self, m: Option<Mirroring>)
pub const fn set_mirroring_override(&mut self, m: Option<Mirroring>)
v1.1.0 beta.1 (T-110-B4) — set (Some) or clear (None) a per-game
nametable mirroring override, a load-time correction for ROMs whose
iNES header carries the wrong mirroring flag (supplied by the frontend’s
game database). None (default) defers to the mapper — byte-identical,
so the determinism / AccuracyCoin contract and the core test suites are
unaffected (they never set it). Persisted in the save-state. Does not
affect mappers with on-cart VRAM (4-screen).
Sourcepub fn mapper_has_hardwired_mirroring(&self) -> bool
pub fn mapper_has_hardwired_mirroring(&self) -> bool
Whether the loaded mapper’s nametable mirroring is hardwired by the cartridge (solder pads / header bit) rather than controlled by the mapper’s own registers at runtime.
The frontend consults this before honoring a game-database mirroring
correction: a static override is only valid for a hardwired board, and
force-applying one to a mapper that switches mirroring itself (MMC1/3/5,
AxROM, VRC, …) corrupts its rendering. See
[rustynes_mappers::Mapper::has_hardwired_mirroring].
Sourcepub fn poke_ram(&mut self, addr: u16, value: u8)
pub fn poke_ram(&mut self, addr: u16, value: u8)
Write a byte directly into CPU work RAM ($0000-$1FFF). Used by the
frontend’s raw RAM cheats (GameShark-style); applied after
Self::run_frame, so the deterministic core run loop is unchanged
(the determinism contract holds for the no-cheat path). No-op outside
system RAM.
Sourcepub fn debug_poke_ppu(&mut self, addr: u16, value: u8)
pub fn debug_poke_ppu(&mut self, addr: u16, value: u8)
v1.7.0 “Forge” Workstream A1 — debugger writeback into the PPU bus
($0000-$3FFF): CHR pattern bytes (mapper ppu_write, a no-op on
CHR-ROM), nametable tiles/attributes (mapper-absorbed, else CIRAM via the
active mirroring), and palette RAM. The PPU-bus counterpart of
Self::poke_ram.
Reached only through the frontend’s gated post-frame poke path (the same
caller-side, after-Self::run_frame stage the raw RAM cheats use), so
the deterministic core run loop is unchanged and the no-edit path is
byte-identical. debug-hooks-gated.
Sourcepub const fn poke_oam_byte(&mut self, idx: u8, value: u8)
pub const fn poke_oam_byte(&mut self, idx: u8, value: u8)
v1.7.0 “Forge” Workstream A1 — debugger writeback for one OAM byte
(idx = 0..256: byte 0 = Y, 1 = tile, 2 = attributes, 3 = X per
sprite). debug-hooks-gated; reached only through the gated post-frame
poke path, so the default build is byte-identical.
Sourcepub fn debug_set_cpu_state(
&mut self,
a: u8,
x: u8,
y: u8,
s: u8,
p_bits: u8,
pc: u16,
)
pub fn debug_set_cpu_state( &mut self, a: u8, x: u8, y: u8, s: u8, p_bits: u8, pc: u16, )
v1.7.0 “Forge” Workstream B (Lua API parity) — debugger/scripted
writeback of the CPU register file (a/x/y/s/p bits/pc). The
structured-state counterpart of Self::poke_ram, backing the Lua
emu:setState(t) field map (Mesen2 parity).
Reached only through the frontend / script crate’s gated post-frame poke
path (the same caller-side, after-Self::run_frame stage the raw RAM
cheats + the other debug_poke_* writebacks use), so the deterministic
core run loop is unchanged and the no-edit path is byte-identical.
debug-hooks-gated. p is taken as a raw status-bits byte (truncated to
the defined flags, mirroring a PLP / save-state restore).
Sourcepub fn peek(&mut self, addr: u16) -> u8
pub fn peek(&mut self, addr: u16) -> u8
Read a byte from the CPU address space ($0000-$FFFF) for inspection,
without the register side effects of a real CPU read — reading
$2002 does not clear the VBL flag / address latch and $2007 does not
advance the PPU read buffer. Used by the debugger and the Lua scripting
API (emu.read); it observes state without advancing the emulator,
preserving determinism.
Sourcepub fn peek_ppu(&mut self, addr: u16) -> u8
pub fn peek_ppu(&mut self, addr: u16) -> u8
v1.2.0 C3 (hd-pack) — side-effect-free read of the PPU bus
($0000-$3FFF): CHR pattern data, nametables, palette RAM. Used by the
HD-pack compositor to hash a tile’s 16 CHR bytes. Observes state without
advancing the emulator, preserving determinism.
Sourcepub fn add_genie_code(&mut self, code: &str) -> Result<(), GenieError>
pub fn add_genie_code(&mut self, code: &str) -> Result<(), GenieError>
Add a Game Genie code (6 or 8 characters, case-insensitive) that
substitutes a byte the CPU reads from PRG-ROM ($8000-$FFFF).
Codes are a runtime overlay — they are not part of the save-state and do not perturb the determinism contract when none are active. With codes active, the substituted bytes are part of the deterministic input (record a movie with the same codes to reproduce a run).
§Errors
Returns GenieError if the code string cannot be decoded.
Sourcepub fn remove_genie_code(&mut self, code: &str)
pub fn remove_genie_code(&mut self, code: &str)
Remove the active Game Genie code whose canonical (upper-case) string
matches code. No-op if no such code is active.
Sourcepub fn clear_genie_codes(&mut self)
pub fn clear_genie_codes(&mut self)
Remove all active Game Genie codes.
Sourcepub fn genie_codes(&self) -> impl Iterator<Item = &GenieCode>
pub fn genie_codes(&self) -> impl Iterator<Item = &GenieCode>
Iterate the active Game Genie codes (address-sorted).
Sourcepub fn drain_audio_into(&mut self, out: &mut [f32]) -> usize
pub fn drain_audio_into(&mut self, out: &mut [f32]) -> usize
Drain into a slice; returns the count copied. Excess samples are
dropped if out is smaller than the buffered count.
Sourcepub const fn rom_sha256(&self) -> &[u8; 32]
pub const fn rom_sha256(&self) -> &[u8; 32]
SHA-256 of the ROM bytes this emulator was constructed from.
Used by the frontend’s save-state file layout (one directory per
ROM, keyed by hex-encoded SHA-256). The hash is computed once at
from_rom time; subsequent calls are O(1).
Sourcepub fn rom_hash_tag(&self) -> [u8; 6]
pub fn rom_hash_tag(&self) -> [u8; 6]
Truncated ROM hash tag stored in the save-state header.
Sourcepub fn snapshot(&self) -> Vec<u8> ⓘ
pub fn snapshot(&self) -> Vec<u8> ⓘ
Encode the entire emulator state into a .rns snapshot blob.
Includes a versioned container header and the four chip + bus
sections (CPU , PPU , APU , MAP , BUS ), plus an optional
THM thumbnail section (128x120 RGBA8 nearest-neighbor downsample
of the current framebuffer). The thumbnail is for UI slot pickers
only – per ADR 0003 it is NOT part of the deterministic save-state
contract.
Sourcepub fn snapshot_core_into(&self, out: &mut Vec<u8>)
pub fn snapshot_core_into(&self, out: &mut Vec<u8>)
v2.8.0 Phase 3 — Self::snapshot minus the THM thumbnail
section, encoded into a caller-owned reused buffer. The fast path
for per-frame consumers (run-ahead, the netplay save-state ring):
no allocation in steady state and no 61 KiB thumbnail build. The
output parses with Self::restore / Self::restore_quiet
exactly like a full snapshot (THM is optional by format).
Sourcepub fn thumbnail(&self) -> Vec<u8> ⓘ
pub fn thumbnail(&self) -> Vec<u8> ⓘ
Generate a 128x120 RGBA8 thumbnail of the current framebuffer.
Nearest-neighbor downsample (sample every 2nd pixel of every 2nd row). The 1/4-resolution result is small enough that storing it in slot files is cheap (61,440 bytes uncompressed, ~10-20 KiB after the LZ4 path the rewind ring uses if it is ever wired through there).
Per ADR 0003: NOT part of the deterministic save-state contract. Different builds may produce different pixel-perfect framebuffers at the same cycle if post-pass filters change.
Sourcepub fn extract_thumbnail(data: &[u8]) -> Result<Option<Vec<u8>>, SnapshotError>
pub fn extract_thumbnail(data: &[u8]) -> Result<Option<Vec<u8>>, SnapshotError>
Extract a thumbnail from an .rns save-state blob without restoring
it. Used by frontends to populate slot pickers.
Returns Ok(None) if the blob is well-formed but contains no
thumbnail section (older v0.9.0 slot files).
§Errors
Returns SnapshotError when the container header is malformed.
Sourcepub fn restore(&mut self, data: &[u8]) -> Result<(), SnapshotError>
pub fn restore(&mut self, data: &[u8]) -> Result<(), SnapshotError>
Apply a previously Self::snapshoted blob.
Loading from a different ROM is allowed (the embedded hash tag is only a sanity check), but the result is undefined unless the chip section bodies are appropriate for the running mapper.
§Errors
Returns SnapshotError for malformed inputs.
Sourcepub fn restore_quiet(&mut self, data: &[u8]) -> Result<(), SnapshotError>
pub fn restore_quiet(&mut self, data: &[u8]) -> Result<(), SnapshotError>
v2.8.0 Phase 3 — Self::restore WITHOUT clearing the rewind ring.
For internal, machine-driven restores on the same timeline —
run-ahead’s per-frame rollback and netplay’s rollback-resimulate —
where the buffered rewind history remains exactly as valid as
before. User-driven loads (save-state slots) keep using
Self::restore, which invalidates the ring.
§Errors
Returns SnapshotError for malformed inputs.
Sourcepub fn enable_rewind(&mut self)
pub fn enable_rewind(&mut self)
Enable the rewind ring buffer with default capacity (32 MiB) and keyframe period (60).
Sourcepub fn enable_rewind_with(&mut self, max_bytes: usize, keyframe_period: u32)
pub fn enable_rewind_with(&mut self, max_bytes: usize, keyframe_period: u32)
Enable rewind with explicit byte budget + keyframe period.
Sourcepub fn disable_rewind(&mut self)
pub fn disable_rewind(&mut self)
Disable rewind and free the buffer.
Sourcepub fn rewind_capture(&mut self)
pub fn rewind_capture(&mut self)
Push the current state onto the rewind ring. Frontends call this at the end of each completed frame.
No-op if rewind is disabled.
Sourcepub fn rewind_step_back(&mut self) -> bool
pub fn rewind_step_back(&mut self) -> bool
Pop the most recent rewind entry and restore it. Returns true on
success, false if the ring is empty (or rewind is disabled).
Sourcepub fn rewind_clear(&mut self)
pub fn rewind_clear(&mut self)
Drop every buffered rewind entry. Called when the user releases the rewind key, so subsequent forward play overwrites — there’s nothing to overwrite, but we want forward play to capture into a fresh ring rather than tail-of-old-history.
Sourcepub const fn rewind_enabled(&self) -> bool
pub const fn rewind_enabled(&self) -> bool
true if rewind is enabled.
Sourcepub fn rewind_len(&self) -> usize
pub fn rewind_len(&self) -> usize
Number of buffered rewind entries.
Sourcepub fn rewind_bytes_used(&self) -> usize
pub fn rewind_bytes_used(&self) -> usize
Approximate memory used by the rewind ring, in bytes.
Sourcepub fn cpu_snapshot(&self) -> CpuDebugView
pub fn cpu_snapshot(&self) -> CpuDebugView
Snapshot the CPU register file.
Sourcepub fn ppu_snapshot(&self) -> PpuDebugView
pub fn ppu_snapshot(&self) -> PpuDebugView
Snapshot PPU state for the debugger.
Sourcepub fn apu_snapshot(&self) -> ApuDebugView
pub fn apu_snapshot(&self) -> ApuDebugView
Snapshot APU channel outputs and IRQ flags.
Sourcepub const fn set_apu_channel_mask(&mut self, mask: u8)
pub const fn set_apu_channel_mask(&mut self, mask: u8)
Set the APU per-channel enable mask (a UI playback overlay, NOT NES hardware state). Bit 0 = pulse 1, 1 = pulse 2, 2 = triangle, 3 = noise, 4 = DMC, 5 = external/mapper audio. A cleared bit mutes that channel.
The default ([rustynes_apu::CHANNEL_MASK_ALL]) is byte-identical to
the un-masked mixer — the deterministic per-frame audio is unchanged
unless the frontend explicitly mutes a channel. This is never written
into the save state, so it never affects determinism or round-trips.
Sourcepub const fn apu_channel_mask(&self) -> u8
pub const fn apu_channel_mask(&self) -> u8
Current APU per-channel enable mask. See Self::set_apu_channel_mask.
Sourcepub fn set_apu_channel_gain(&mut self, gain: [f32; 6])
pub fn set_apu_channel_gain(&mut self, gain: [f32; 6])
v1.4.0 Workstream C — set the APU per-channel output gain (a UI mixing
overlay, NOT NES hardware state), generalizing Self::set_apu_channel_mask.
Index 0 = pulse 1, 1 = pulse 2, 2 = triangle, 3 = noise, 4 = DMC,
5 = external/mapper audio. Each gain is clamped to 0.0..=2.0.
The default ([rustynes_apu::CHANNEL_GAIN_UNITY], all 1.0) is
byte-identical to the un-scaled mixer — the deterministic per-frame audio
is unchanged unless the frontend explicitly changes a gain. Never written
into the save state, so it never affects determinism or round-trips.
Sourcepub fn set_apu_filter_model(&mut self, model: FilterModel)
pub fn set_apu_filter_model(&mut self, model: FilterModel)
v2.1.3 — select the APU analog output-filter model (see
[rustynes_apu::FilterModel]). The default
[rustynes_apu::FilterModel::NesRf] (NES front-loader: 90 + 440 Hz HPF +
14 kHz LPF) is byte-identical to the pre-v2.1.3 output; Famicom (37 Hz
HPF) and Clean (~10 Hz DC-block) drop the aggressive 440 Hz high-pass
for a fuller low end. Tonal only — channel content is unchanged, and the
model is never written into the save state (a frontend/config concern,
re-applied at load), so determinism and round-trips are unaffected.
Sourcepub const fn apu_channel_gain(&self) -> [f32; 6]
pub const fn apu_channel_gain(&self) -> [f32; 6]
Current APU per-channel output gain. See Self::set_apu_channel_gain.
Sourcepub fn oam(&self) -> [u8; 256]
pub fn oam(&self) -> [u8; 256]
Borrow OAM (256 bytes = 64 sprites x 4 bytes).
Returns a cloned [u8; 256] so the caller doesn’t have to manage
a borrow lifetime against &self.
Sourcepub fn oam_byte(&self, index: u8) -> u8
pub fn oam_byte(&self, index: u8) -> u8
One OAM byte (index = 0..=255), without copying the whole 256-byte
array — for single-byte readers (e.g. the Lua memory:read_oam) that
would otherwise pay a full oam() copy per access. Read-only.
Sourcepub const fn palette_ram(&self) -> [u8; 32]
pub const fn palette_ram(&self) -> [u8; 32]
Borrow palette RAM (32 bytes).
Sourcepub const fn set_custom_palette(&mut self, base: Option<[[u8; 3]; 64]>)
pub const fn set_custom_palette(&mut self, base: Option<[[u8; 3]; 64]>)
v1.1.0 beta.1 — install (Some) or clear (None) a custom 64-entry base
palette loaded from a .pal file. A frontend presentation override: it
re-tints the displayed RGBA framebuffer via the PPU’s colour LUT but does
not touch any logical core state. None (the default) is byte-identical to
the built-in palette, so AccuracyCoin + the commercial oracle (which never
set one) are unaffected. Not part of the save-state.
Sourcepub const fn set_extra_scanlines(&mut self, lines: u16)
pub const fn set_extra_scanlines(&mut self, lines: u16)
v1.7.0 “Forge” Workstream F3 — set the PPU extra-scanlines overclock: the
number of EXTRA idle vblank scanlines the PPU inserts per frame (at the
existing dot resolution, Mesen2 UpdateTimings). Each extra line is pure
additional CPU run-time — it renders nothing, sets/clears no PPU flag, and
fires no VBL/NMI/A12 event, so the visible image is unchanged. 0 (the
default) is byte-identical to stock NES timing — AccuracyCoin, the
commercial oracle, and nestest (which never set it) are unaffected.
Off by default; a frontend config knob, not part of the save-state.
Distinct from the CPU-multiplier overclock (a v2.0 timebase item).
Sourcepub const fn extra_scanlines(&self) -> u16
pub const fn extra_scanlines(&self) -> u16
v1.7.0 F3 — the configured extra-scanline overclock count (0 = stock).
Sourcepub const fn set_fast_dotloop(&mut self, enabled: bool)
pub const fn set_fast_dotloop(&mut self, enabled: bool)
v2.1.8 A1 — enable or disable the specialized visible-scanline fast dot path (a pure performance optimization for the PPU’s hottest per-dot case).
The PPU dot FSM (Ppu::tick) is the emulator’s single hottest function
(~46% of a representative frame’s self-time). This knob dispatches the
common “clean” visible BG-render dots (visible scanline, dots 1..=256,
rendering stably enabled, no sub-dot disturbance) to a straight-line
handler that runs the identical helper sequence with the statically-dead
event branches pruned. Off by default and byte-identical to a
build without it — proven bit-for-bit by the differential test
(fast_dotloop_diff) and the full AccuracyCoin / visual-regression /
nestest oracle. A frontend/config knob, NOT part of the save-state.
Sourcepub const fn fast_dotloop(&self) -> bool
pub const fn fast_dotloop(&self) -> bool
v2.1.8 A1 — whether the visible-scanline fast dot path is enabled
(false = default, byte-identical to a build without it).
Sourcepub const fn set_oam_decay(&mut self, enabled: bool)
pub const fn set_oam_decay(&mut self, enabled: bool)
v2.1.4 F2.3 — enable or disable the optional OAM-decay accuracy model.
The 2C02’s OAM is dynamic RAM refreshed by sprite evaluation; with rendering
disabled for a while its un-refreshed 8-byte rows decay to a fixed garbage
pattern. This models that (à la Mesen2’s EnableOamDecay): a row un-touched
for > 3000 CPU cycles decays on the next read. Off by default and
byte-identical to a decay-free core when off — AccuracyCoin, the
commercial oracle, and the visual regression suites are unaffected. It is
NTSC/Dendy-only (PAL’s refresh cadence masks decay). Deterministic when on
(driven off the PPU’s monotonic dot counter — no wall-clock / OS RNG), and a
frontend/config knob re-applied on load, NOT part of the save-state (the
in-flight per-row ages are serialized as a relative age so a rollback stays
deterministic; the enable flag is not).
Sourcepub const fn oam_decay_enabled(&self) -> bool
pub const fn oam_decay_enabled(&self) -> bool
v2.1.4 F2.3 — whether the optional OAM-decay model is enabled (false =
default, byte-identical to a decay-free core).
Sourcepub const fn set_ppu_revision(&mut self, revision: PpuRevision)
pub const fn set_ppu_revision(&mut self, revision: PpuRevision)
v2.1.7 P5 — select the emulated 2C02 die revision (see PpuRevision).
The PpuRevision::default (PpuRevision::Rp2c02H) models no extra
quirks, so at the default this is inert and the core is byte-identical
to a build without it — AccuracyCoin, the commercial oracle, and the
visual / audio regression suites are unaffected. Selecting
PpuRevision::Rp2c02G additionally models the OAMADDR ($2003)
write-during-rendering OAM corruption glitch (Huge Insect). The
selection is stored so a power-cycle re-applies it; it is config, not
save-state (the corruption state it can arm already round-trips via the
v6 PPU snapshot tail). Deterministic. A frontend/config knob re-applied on
load, mirroring Nes::set_oam_decay.
Sourcepub const fn ppu_revision(&self) -> PpuRevision
pub const fn ppu_revision(&self) -> PpuRevision
v2.1.7 P5 — the currently-selected 2C02 die revision (default
PpuRevision::Rp2c02H, byte-identical).
Sourcepub const fn set_power_up_palette(&mut self, init: PaletteInit)
pub const fn set_power_up_palette(&mut self, init: PaletteInit)
v2.1.7 P5 — apply a power-up palette-RAM pattern (see PaletteInit).
The 2C02’s palette RAM is not cleared at power-on; this selects the
power-up contents. PaletteInit::default (PaletteInit::Zeroed)
keeps the established all-zero power-up palette, so at the default this is
byte-identical. PaletteInit::Blargg loads the canonical blargg
power-up dump for software that samples uninitialized palette RAM. Writes
only palette RAM (already part of the snapshot), so no snapshot change is
needed; the selection is stored so a power-cycle re-applies it. Best
called at power-on (palette RAM is preserved across a warm reset, like
real hardware).
Sourcepub const fn power_up_palette(&self) -> PaletteInit
pub const fn power_up_palette(&self) -> PaletteInit
v2.1.7 P5 — the currently-selected power-up palette pattern (default
PaletteInit::Zeroed, byte-identical).
Sourcepub fn set_power_on_ram(&mut self, ram: PowerOnRam)
pub fn set_power_on_ram(&mut self, ram: PowerOnRam)
v2.1.7 P5 — select the power-on work-RAM fill (see PowerOnRam).
Applies the fill to the current 2 KiB work RAM (and open-bus latch)
immediately and stores it so a power-cycle re-applies the same fill
(power_cycle == fresh boot). PowerOnRam::default
(PowerOnRam::Zeroed) is the established all-zero power-up state
(byte-identical); the other variants are opt-in and deterministic,
surfacing software that reads uninitialized RAM (Final Fantasy RNG,
River City Ransom, Cybernoid). RAM is not consulted during reset, so
applying it here is safe.
Sourcepub const fn power_on_ram(&self) -> PowerOnRam
pub const fn power_on_ram(&self) -> PowerOnRam
v2.1.7 P5 — the currently-selected power-on work-RAM fill (default
PowerOnRam::Zeroed, byte-identical).
Sourcepub const fn set_cpu_2a03_revision(&mut self, revision: Cpu2A03Revision)
pub const fn set_cpu_2a03_revision(&mut self, revision: Cpu2A03Revision)
v2.1.7 “Hardware Revisions & DMA Frontier” — select the emulated Ricoh 2A03 die revision, which gates the DMA unit’s “unexpected DMA” extra halt-read on the DMC-halt-overlaps-OAM-halt cycle.
Cpu2A03Revision::Rp2A03G is the default and is byte-identical to
the core as it shipped before v2.1.7 (AccuracyCoin 141/141, nestest
0-diff, every committed DMA oracle ROM Passed).
Cpu2A03Revision::Rp2A03H is a purely additive, opt-in accuracy knob
that omits the extra read; its direction is an unverified hypothesis
(no public reference emulator or test ROM models the 2A03 die-revision
DMA difference — see the type docs and ADR 0033). It is deterministic and
a config knob re-applied on load, NOT part of the save-state.
Sourcepub const fn cpu_2a03_revision(&self) -> Cpu2A03Revision
pub const fn cpu_2a03_revision(&self) -> Cpu2A03Revision
v2.1.7 — the configured 2A03 die revision (default
Cpu2A03Revision::Rp2A03G, byte-identical to the pre-v2.1.7 core).
Sourcepub fn mapper_info(&self) -> MapperDebugView
pub fn mapper_info(&self) -> MapperDebugView
Mapper debug info (bank registers, IRQ counters, mirroring, …).
Sourcepub fn expansion_audio_chip(&self) -> Option<&'static str>
pub fn expansion_audio_chip(&self) -> Option<&'static str>
v1.4.0 Workstream C — the loaded mapper’s on-cart expansion-audio chip
name (e.g. "VRC6", "VRC7 (OPLL)", "MMC5", "Namco 163",
"Sunsoft 5B", "FDS"), or None when the board has no expansion audio
(or the mapper-audio feature is compiled out). Used by the frontend to
show the expansion-channel volume slider only when present, with a label.
Discovery is dynamic: it consults the cached [rustynes_mappers::MapperCaps]
audio flag (true only when the mapper overrides mix_audio with the
feature on) and the mapper id to name the chip family.
Sourcepub fn cpu_bus_peek(&mut self, addr: u16) -> u8
pub fn cpu_bus_peek(&mut self, addr: u16) -> u8
Side-effect-free CPU bus peek (for the hex viewer).
Sourcepub fn ppu_bus_peek(&mut self, addr: u16) -> u8
pub fn ppu_bus_peek(&mut self, addr: u16) -> u8
Side-effect-free PPU bus peek (for the hex viewer + visualizers).
Sourcepub fn pattern_table_rgba(&mut self, table: u8) -> Vec<u8> ⓘ
pub fn pattern_table_rgba(&mut self, table: u8) -> Vec<u8> ⓘ
Render the 256 tiles of a CHR pattern table as RGBA8 (128x128).
table selects which of the two pattern tables: 0 -> $0000,
1 -> $1000. Uses BG palette 0 ($3F00-$3F03) for grayscale-ish
rendering. ~80 KiB cloned; only call when the PPU pattern viewer
is open.