Files
nesemu/src/native_core/test_support.rs
se.cherkasov bdf23de8db
Some checks failed
CI / rust (push) Has been cancelled
Initial commit: NES emulator with GTK4 desktop frontend
Full NES emulation: CPU, PPU, APU, 47 mappers, iNES/NES 2.0 parsing.
GTK4 desktop client with HeaderBar, pixel-perfect Cairo rendering,
drag-and-drop ROM loading, and keyboard shortcuts.
187 tests covering core emulation, mappers, and runtime.
2026-03-13 11:48:45 +03:00

115 lines
3.0 KiB
Rust

use crate::native_core::cpu::{Cpu6502, CpuBus};
use crate::native_core::ines::{InesHeader, InesRom, Mirroring};
pub(crate) struct TestRamBus(pub [u8; 0x10000]);
impl TestRamBus {
pub(crate) fn new() -> Self {
Self([0; 0x10000])
}
pub(crate) fn load(&mut self, start: u16, bytes: &[u8]) {
for (i, b) in bytes.iter().copied().enumerate() {
self.0[start as usize + i] = b;
}
}
}
impl CpuBus for TestRamBus {
fn read(&mut self, addr: u16) -> u8 {
self.0[addr as usize]
}
fn write(&mut self, addr: u16, value: u8) {
self.0[addr as usize] = value;
}
}
pub(crate) fn cpu_setup_with_reset(prog: &[u8]) -> (Cpu6502, TestRamBus) {
let mut bus = TestRamBus::new();
bus.load(0x8000, prog);
bus.0[0xFFFC] = 0x00;
bus.0[0xFFFD] = 0x80;
let mut cpu = Cpu6502::default();
cpu.reset(&mut bus);
(cpu, bus)
}
pub(crate) struct MapperRomBuilder {
mapper: u16,
submapper: u8,
prg_banks_16k: u16,
chr_banks_8k: u16,
mirroring: Mirroring,
}
impl MapperRomBuilder {
pub(crate) fn new(mapper: u16) -> Self {
Self {
mapper,
submapper: 0,
prg_banks_16k: 1,
chr_banks_8k: 1,
mirroring: Mirroring::Horizontal,
}
}
pub(crate) fn submapper(mut self, submapper: u8) -> Self {
self.submapper = submapper;
self
}
pub(crate) fn prg_banks_16k(mut self, banks: u16) -> Self {
self.prg_banks_16k = banks;
self
}
pub(crate) fn chr_banks_8k(mut self, banks: u16) -> Self {
self.chr_banks_8k = banks;
self
}
pub(crate) fn mirroring(mut self, mirroring: Mirroring) -> Self {
self.mirroring = mirroring;
self
}
pub(crate) fn build(self) -> InesRom {
let prg_rom_len = self.prg_banks_16k as usize * 16 * 1024;
let chr_len = if self.chr_banks_8k == 0 {
8 * 1024
} else {
self.chr_banks_8k as usize * 8 * 1024
};
let chr_data = if self.chr_banks_8k == 0 {
vec![0; chr_len]
} else {
(0..chr_len).map(|v| (v & 0xFF) as u8).collect()
};
InesRom {
header: InesHeader {
mapper: self.mapper,
submapper: self.submapper,
is_nes2: false,
prg_rom_banks_16k: self.prg_banks_16k,
chr_rom_banks_8k: self.chr_banks_8k,
has_trainer: false,
has_battery: false,
mirroring: self.mirroring,
prg_ram_shift: 0,
prg_nvram_shift: 0,
chr_ram_shift: 0,
chr_nvram_shift: 0,
cpu_ppu_timing_mode: 0,
vs_hardware_type: 0,
vs_ppu_type: 0,
misc_rom_count: 0,
default_expansion_device: 0,
},
prg_rom: (0..prg_rom_len).map(|v| (v & 0xFF) as u8).collect(),
chr_data,
chr_is_ram: self.chr_banks_8k == 0,
}
}
}