use crate::nes::cartridge::bandai::bandai_fcg::{BandaiFcgMapper, BandaiFcgVariant};
use crate::nes::cartridge::base_mapper::BaseMapper;
use crate::nes::cartridge::mapper::{Mapper, MapperCapabilities, MapperContext};
const MAPPER_NUMBER: u16 = 157;
pub struct Mapper157 {
inner: BandaiFcgMapper,
}
impl Mapper157 {
pub fn new(ctx: MapperContext) -> Self {
Self {
inner: BandaiFcgMapper::new_with_variant(ctx, BandaiFcgVariant::Lz93d50),
}
}
}
impl Mapper for Mapper157 {
fn base(&self) -> &BaseMapper {
self.inner.base()
}
fn base_mut(&mut self) -> &mut BaseMapper {
self.inner.base_mut()
}
fn mapper_number(&self) -> u16 {
MAPPER_NUMBER
}
fn read_prg(&self, addr: u16) -> u8 {
self.inner.read_prg(addr)
}
fn write_prg(&mut self, addr: u16, value: u8) {
self.inner.write_prg(addr, value);
}
fn read_chr(&mut self, addr: u16) -> u8 {
self.inner.read_chr(addr)
}
fn write_chr(&mut self, addr: u16, value: u8) {
self.inner.write_chr(addr, value);
}
fn cpu_cycle(&mut self) {
self.inner.cpu_cycle();
}
fn irq_pending(&self) -> bool {
self.inner.irq_pending()
}
fn capabilities(&self) -> MapperCapabilities {
self.inner.capabilities()
}
fn wram_size(&self) -> usize {
self.inner.wram_size()
}
fn wram_snapshot(&self) -> Vec<u8> {
self.inner.wram_snapshot()
}
fn load_wram_snapshot(&mut self, data: &[u8]) {
self.inner.load_wram_snapshot(data);
}
fn registers_snapshot(&self) -> Vec<u8> {
self.inner.registers_snapshot()
}
fn restore_registers(&mut self, data: &[u8]) {
self.inner.restore_registers(data);
}
fn initialize_ram(&mut self, mode: crate::nes::console::RamInitMode) {
self.inner.initialize_ram(mode);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::nes::cartridge::NametableLayout;
use crate::nes::cartridge::mapper::{MapperContext, create_mapper};
use crate::nes::cartridge::test_helpers::banked_data;
const PRG_BANKS_16K: usize = 8;
fn make_mapper() -> Mapper157 {
Mapper157::new(MapperContext::new_for_test(
MAPPER_NUMBER,
banked_data(16 * 1024, PRG_BANKS_16K),
vec![], NametableLayout::Horizontal,
))
}
#[test]
fn mapper_157_is_registered_in_factory() {
let result = create_mapper(MapperContext::new_for_test(
MAPPER_NUMBER,
banked_data(16 * 1024, PRG_BANKS_16K),
vec![],
NametableLayout::Horizontal,
));
assert!(result.is_ok(), "Mapper 157 must be creatable via factory");
}
#[test]
fn power_on_prg_bank_0_at_8000_last_bank_fixed_at_c000() {
let mapper = make_mapper();
assert_eq!(mapper.read_prg(0x8000), 0, "bank 0 at $8000 on power-on");
assert_eq!(
mapper.read_prg(0xC000),
PRG_BANKS_16K as u8 - 1,
"last bank fixed at $C000"
);
}
#[test]
fn register_8008_switches_prg_bank_at_8000() {
let mut mapper = make_mapper();
mapper.write_prg(0x8008, 3);
assert_eq!(
mapper.read_prg(0x8000),
3,
"bank 3 at $8000 after writing $8008"
);
assert_eq!(
mapper.read_prg(0xC000),
PRG_BANKS_16K as u8 - 1,
"last bank at $C000 unchanged"
);
}
#[test]
fn register_8009_controls_mirroring() {
let mut mapper = make_mapper();
mapper.write_prg(0x8009, 0); assert_eq!(mapper.get_mirroring(), NametableLayout::Vertical);
mapper.write_prg(0x8009, 1); assert_eq!(mapper.get_mirroring(), NametableLayout::Horizontal);
}
#[test]
fn chr_ram_is_writable() {
let mut mapper = make_mapper();
mapper.write_chr(0x0000, 0xAB);
assert_eq!(mapper.read_chr(0x0000), 0xAB, "CHR-RAM write/read at $0000");
mapper.write_chr(0x1FFF, 0x42);
assert_eq!(mapper.read_chr(0x1FFF), 0x42, "CHR-RAM write/read at $1FFF");
}
#[test]
fn irq_not_pending_at_startup() {
let mapper = make_mapper();
assert!(!mapper.irq_pending(), "no IRQ at power-on");
}
#[test]
fn irq_fires_after_countdown() {
let mut mapper = make_mapper();
mapper.write_prg(0x800B, 3); mapper.write_prg(0x800C, 0); mapper.write_prg(0x800A, 1);
assert!(!mapper.irq_pending(), "IRQ not yet pending");
mapper.cpu_cycle();
mapper.cpu_cycle();
mapper.cpu_cycle();
assert!(mapper.irq_pending(), "IRQ should fire after 3 cycles");
}
#[test]
fn capabilities_include_irq_and_chr_banking() {
let mapper = make_mapper();
let caps = mapper.capabilities();
assert!(caps.has_irq, "mapper 157 has IRQ");
assert!(!caps.has_expansion_audio, "no expansion audio");
assert_eq!(caps.prg_bank_size_kb, 16, "16 KiB PRG bank size");
}
#[test]
fn snapshot_restore_round_trips_prg_bank() {
let mut mapper = make_mapper();
mapper.write_prg(0x8008, 5);
let snap = mapper.registers_snapshot();
let mut restored = make_mapper();
restored.restore_registers(&snap);
assert_eq!(
restored.read_prg(0x8000),
5,
"PRG bank must be restored to 5"
);
}
}