pub struct Sachen150 { /* private fields */ }Expand description
Sachen SA-020A eight-register ASIC (iNES mappers 150 and 243).
A fake-“74LS374N”-marked part with eight three-bit registers reached through
an index/data pair at $4100/$4101 (mask $C101), driving one switchable
32 KiB PRG bank, one switchable 8 KiB CHR bank, and four mirroring modes –
one of which is the non-standard S0-S0-S0-S1 layout.
The type is named for mapper 150 for historical reasons but backs both PCBs
the ASIC shipped on; see Sa020aBoard. Construct via Sachen150::new
for the SA-150 or Sachen150::new_on_board to pick explicitly.
Implementations§
Source§impl Sachen150
impl Sachen150
Sourcepub fn new(prg_rom: Box<[u8]>, chr_rom: Box<[u8]>) -> Result<Self, MapperError>
pub fn new(prg_rom: Box<[u8]>, chr_rom: Box<[u8]>) -> Result<Self, MapperError>
Construct a new mapper 150 board.
§Errors
Returns MapperError::Invalid when PRG is not a non-zero multiple of
32 KiB, or CHR-ROM (when present) is not a multiple of 8 KiB.
Sourcepub fn new_on_board(
prg_rom: Box<[u8]>,
chr_rom: Box<[u8]>,
board: Sa020aBoard,
) -> Result<Self, MapperError>
pub fn new_on_board( prg_rom: Box<[u8]>, chr_rom: Box<[u8]>, board: Sa020aBoard, ) -> Result<Self, MapperError>
Construct the SA-020A ASIC on an explicit PCB.
§Errors
Returns MapperError::Invalid when PRG is not a non-zero multiple of
32 KiB, or CHR-ROM (when present) is not a multiple of 8 KiB.
Trait Implementations§
Source§impl Mapper for Sachen150
impl Mapper for Sachen150
Source§fn cpu_read_driven_mask(&self, addr: u16) -> u8
fn cpu_read_driven_mask(&self, addr: u16) -> u8
The data register drives D2-D0 only; D7-D3 float
(nesdev_wiki/INES_Mapper_150.xhtml: “Register data … …. .RRR”).
Source§fn caps(&self) -> MapperCaps
fn caps(&self) -> MapperCaps
Source§fn cpu_read_unmapped(&self, addr: u16) -> bool
fn cpu_read_unmapped(&self, addr: u16) -> bool
true when addr is not wired to mapper-resident
memory — i.e. when cpu_read(addr) returns junk and the bus
should fall through to the open-bus latch instead of overwriting
it. The CPU databus is left floating in this case, so the most
recently driven byte stays visible to the next read. Read moreSource§fn cpu_write(&mut self, addr: u16, value: u8)
fn cpu_write(&mut self, addr: u16, value: u8)
$4020-$FFFF.Source§fn ppu_read(&mut self, addr: u16) -> u8
fn ppu_read(&mut self, addr: u16) -> u8
$0000-$3FFF (pattern table Read moreSource§fn ppu_write(&mut self, addr: u16, value: u8)
fn ppu_write(&mut self, addr: u16, value: u8)
$0000-$3FFF.Source§fn current_mirroring(&self) -> Mirroring
fn current_mirroring(&self) -> Mirroring
Source§fn nametable_address(&self, addr: u16) -> u16
fn nametable_address(&self, addr: u16) -> u16
$2000-$3EFF to a CIRAM offset in
0..0x800. The PPU owns the 2 KiB CIRAM and uses this hook to apply
per-mapper mirroring without giving the mapper direct access to the
console-side VRAM. Read moreSource§fn save_state(&self) -> Vec<u8> ⓘ
fn save_state(&self) -> Vec<u8> ⓘ
Source§fn load_state(&mut self, data: &[u8]) -> Result<(), MapperError>
fn load_state(&mut self, data: &[u8]) -> Result<(), MapperError>
Mapper::save_state blob back into the mapper. Read moreSource§fn notify_floating_read(&mut self, _addr: u16, _value: u8)
fn notify_floating_read(&mut self, _addr: u16, _value: u8)
Self::cpu_read_unmapped) has just
completed, and value is what floated on the bus. Read moreSource§fn notify_ppu_register_write(&mut self, _addr: u16, _value: u8)
fn notify_ppu_register_write(&mut self, _addr: u16, _value: u8)
value to the PPU register window ($2000-$3FFF), at
the undecoded address addr. Read moreSource§fn nametable_unfolded(&self) -> bool
fn nametable_unfolded(&self) -> bool
$3000-$3EFF is independent RAM on this cartridge rather
than a mirror of $2000-$2EFF. Read moreSource§fn ppu_read_sprite(&mut self, addr: u16) -> u8
fn ppu_read_sprite(&mut self, addr: u16) -> u8
$0000-$1FFF) on
behalf of a sprite tile fetch. MMC5 in 8x16 sprite mode uses a
separate set of CHR bank registers ($5120-$5127) for sprite
fetches; other mappers default to forwarding to Mapper::ppu_read.Source§fn chr_phys(&self, _addr: u16) -> Option<u32>
fn chr_phys(&self, _addr: u16) -> Option<u32>
$0000-$1FFF (Some(offset)), or None for CHR-RAM
(content-hashed instead). tile_index = offset / 16 is the key Mesen uses
for CHR-ROM <tile> replacements. Default None so an unported mapper
falls back to the content-hash path (no worse than before); the common
CHR-ROM mappers override it by exposing their internal CHR mapping.Source§fn chr_reads_are_pure(&self) -> bool
fn chr_reads_are_pure(&self) -> bool
T-SPRITE-LIMIT) — whether Self::ppu_read and
Self::ppu_read_sprite on $0000-$1FFF change nothing but return a
byte. true (the default) lets the PPU’s “disable sprite limit” option
make extra, display-only pattern reads on this board. Read moreSource§fn set_mmc3_revision_override(
&mut self,
_revision: Option<Mmc3Revision>,
) -> bool
fn set_mmc3_revision_override( &mut self, _revision: Option<Mmc3Revision>, ) -> bool
T-MMC3-NEC-OVERRIDE, ACC-13) — force an MMC3’s IRQ revision
(Some), or return to the one its header selected (None). Returns
whether this board is an MMC3 that applied it; every other board
ignores it (the default). Lets an iNES 1.0 dump, which cannot name its
MMC3 revision, run under the alternate (Nec) behaviour.Source§fn nametable_fetch(&mut self, _addr: u16) -> Option<u8>
fn nametable_fetch(&mut self, _addr: u16) -> Option<u8>
addr ($2000-$3EFF). Read moreSource§fn nametable_write(&mut self, _addr: u16, _value: u8) -> bool
fn nametable_write(&mut self, _addr: u16, _value: u8) -> bool
addr ($2000-$3EFF) directly
into mapper-resident storage. Read moreSource§fn peek_ex_attribute(&mut self, _v: u16) -> Option<ExAttribute>
fn peek_ex_attribute(&mut self, _v: u16) -> Option<ExAttribute>
Source§fn bg_split_state(
&mut self,
_scanline_y: u16,
_coarse_x: u16,
) -> Option<BgSplitState>
fn bg_split_state( &mut self, _scanline_y: u16, _coarse_x: u16, ) -> Option<BgSplitState>
Source§fn notify_a12(&mut self, _level: bool)
fn notify_a12(&mut self, _level: bool)
Source§fn notify_a12_at_sub_dot(&mut self, level: bool, _sub_dot: u8)
fn notify_a12_at_sub_dot(&mut self, level: bool, _sub_dot: u8)
Self::notify_a12 so existing
mappers compile unchanged; MMC3 overrides this for the
M2-phase-aware IRQ-output propagation delay required by
mmc3_test_2/4-scanline_timing sub-test #3 (C1 step B4 successor).Source§fn notify_cpu_cycle(&mut self)
fn notify_cpu_cycle(&mut self)
Source§fn notify_frame_event(&mut self, _events: MapperFrameEvents)
fn notify_frame_event(&mut self, _events: MapperFrameEvents)
Source§fn notify_scanline_start(&mut self)
fn notify_scanline_start(&mut self)
Source§fn notify_vblank(&mut self)
fn notify_vblank(&mut self)
Source§fn enable_vs_dual_wram(&mut self)
fn enable_vs_dual_wram(&mut self)
DualSystem): provision the board’s shared 2 KiB
work RAM at $6000-$7FFF (mirrored across the 8 KiB window — MAME
vsnes.cpp: map(0x6000, 0x67ff).mirror(0x1800).ram()). Only the
Vs. System board (mapper 99) implements this — the DualSystem
cabinets carry a 2 KiB RAM shared between the two consoles, absent
on UniSystem carts (whose $6000 window stays open bus,
byte-identically). Called by the VsDualSystem wrapper at
construction on both consoles: each console holds its own COPY, and
the wrapper converges the copies by draining the write log (below)
after every stepped instruction — MAME’s fully-shared
.share("nvram") model at soft-lockstep granularity. Default no-op.Source§fn set_vs_dual_sub(&mut self)
fn set_vs_dual_sub(&mut self)
DualSystem): mark this mapper instance as the
cabinet’s SUB console — it banks the second 32 KiB PRG half and the
upper CHR pages (the two CPUs run DIFFERENT programs; MAME
balonfgt loads distinct sub-region ROMs, Mesen2 uses
prgOuter = IsVsMainConsole() ? 0 : 4). Applied by the
VsDualSystem wrapper at construction, like the bus’s sub
identity. Default no-op.Source§fn drain_vs_dual_wram_writes(&mut self, dst: &mut Vec<(u16, u8)>)
fn drain_vs_dual_wram_writes(&mut self, dst: &mut Vec<(u16, u8)>)
DualSystem): drain this console’s shared-WRAM
write log — every (offset, value) the CPU wrote to the window
since the last drain, in order — by APPENDING into dst (never
clearing it first). The wrapper replays them into the partner’s
copy (Self::apply_vs_dual_wram_write), which is what makes the
RAM behave as ONE simultaneously-shared memory (MAME’s model;
nesdev also documents a $4016-bit-1 access mux, but MAME — where
the four DualSystem games verifiably run — shares the RAM
unconditionally, and Balloon Fight’s boot handshake requires the
partner to see writes made while the mux would deny it access). Read moreSource§fn take_vs_dual_wram_writes(&mut self) -> Vec<(u16, u8)>
fn take_vs_dual_wram_writes(&mut self) -> Vec<(u16, u8)>
Self::drain_vs_dual_wram_writes for
callers that don’t already hold a reusable buffer (diagnostics,
tests) — NOT used by the hot pump_comms path, which owns and
reuses its own scratch buffer instead.Source§fn apply_vs_dual_wram_write(&mut self, offset: u16, value: u8)
fn apply_vs_dual_wram_write(&mut self, offset: u16, value: u8)
DualSystem): replay one partner-console write
into this console’s copy of the shared WRAM (see
Self::take_vs_dual_wram_writes). Does NOT re-log the write (no
echo loop). Default no-op.Source§fn take_vs_dual_wram(&mut self) -> Option<Box<[u8]>>
fn take_vs_dual_wram(&mut self) -> Option<Box<[u8]>>
DualSystem): take the console’s shared-WRAM copy
(used by the wrapper’s snapshot-restore normalization — the two
copies are re-converged from one buffer after a restore). Returns
None on boards without the dual WRAM. Default None.Source§fn set_vs_dual_wram(&mut self, wram: Box<[u8]>)
fn set_vs_dual_wram(&mut self, wram: Box<[u8]>)
DualSystem): install a shared-WRAM copy (the
other half of the restore normalization). Default no-op.Source§fn irq_pending(&self) -> bool
fn irq_pending(&self) -> bool
true if the mapper is currently asserting an IRQ.Source§fn irq_acknowledge(&mut self)
fn irq_acknowledge(&mut self)
Source§fn mix_audio(&mut self) -> i32
fn mix_audio(&mut self) -> i32
Source§fn has_hardwired_mirroring(&self) -> bool
fn has_hardwired_mirroring(&self) -> bool
Source§fn disk_side_count(&self) -> usize
fn disk_side_count(&self) -> usize
Source§fn inserted_disk_side(&self) -> Option<usize>
fn inserted_disk_side(&self) -> Option<usize>
None when ejected (or for
non-FDS mappers).Source§fn set_disk_side(&mut self, _side: Option<usize>)
fn set_disk_side(&mut self, _side: Option<usize>)
i (Some) or eject the disk (None). No-op for
non-FDS mappers; an out-of-range index is ignored by the FDS device.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_data(&self) -> &[u8] ⓘ
fn save_data(&self) -> &[u8] ⓘ
Self::sram, and the default says so. Read moreSource§fn save_data_mut(&mut self) -> &mut [u8] ⓘ
fn save_data_mut(&mut self) -> &mut [u8] ⓘ
Self::save_data, for loading a save.Source§fn clear_save_data(&mut self)
fn clear_save_data(&mut self)
power_on_for_movie).Source§fn enable_fds_trace(&mut self)
fn enable_fds_trace(&mut self)
crate::FdsTraceRec.Source§fn take_fds_trace(&mut self) -> Vec<FdsTraceRec>
fn take_fds_trace(&mut self) -> Vec<FdsTraceRec>
Source§fn disk_image_bytes(&self) -> Vec<u8> ⓘ
fn disk_image_bytes(&self) -> Vec<u8> ⓘ
Source§fn disk_is_dirty(&self) -> bool
fn disk_is_dirty(&self) -> bool
false for non-FDS
mappers.Source§fn clear_disk_dirty(&mut self)
fn clear_disk_dirty(&mut self)
Source§fn set_disk_write_protected(&mut self, _protected: bool)
fn set_disk_write_protected(&mut self, _protected: bool)
true) or writable (false). No-op
for non-FDS mappers.Source§fn nsf_song_count(&self) -> u8
fn nsf_song_count(&self) -> u8
Source§fn nsf_current_song(&self) -> u8
fn nsf_current_song(&self) -> u8
Source§fn nsf_set_song(&mut self, _song: u8) -> bool
fn nsf_set_song(&mut self, _song: u8) -> bool
true if this is an NSF mapper (so the
caller knows to re-run the reset that re-vectors into the driver’s
init). Default no-op returning false.