Fix memory mapping for MMC1

This commit is contained in:
2026-04-08 21:15:45 -05:00
parent d140f1e122
commit 875e493cd2

View File

@@ -1,8 +1,9 @@
use std::{fmt, sync::Arc}; use std::{fmt, sync::Arc};
use bitfield::bitfield;
use crate::{ use crate::{
CPUMMRegisters, PPU, apu::APU, controllers::Controllers, cpu::DmaState, CPUMMRegisters, PPU, apu::APU, controllers::Controllers, cpu::DmaState, ppu::PPUMMRegisters,
ppu::PPUMMRegisters,
}; };
pub trait Memory { pub trait Memory {
@@ -32,7 +33,7 @@ pub enum Data<R> {
ROM(Arc<[u8]>), ROM(Arc<[u8]>),
Mirror(u16), Mirror(u16),
Reg(R), Reg(R),
Disabled, // Disabled,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -139,8 +140,7 @@ impl<R: Copy> MemoryMap<R> {
self.read(pos + offset) self.read(pos + offset)
// let s = &self.segments[*index]; // let s = &self.segments[*index];
// self.read(s.position + offset % s.size) // self.read(s.position + offset % s.size)
} } // Data::Disabled => todo!(),
Data::Disabled => todo!(),
}; };
} }
} }
@@ -167,8 +167,7 @@ impl<R: Copy> MemoryMap<R> {
// let index = *index; // let index = *index;
// let s = &self.segments[index]; // let s = &self.segments[index];
// self.write(s.position + offset % s.size, val) // self.write(s.position + offset % s.size, val)
} } // Data::Disabled => todo!(),
Data::Disabled => todo!(),
}; };
} }
} }
@@ -177,14 +176,14 @@ impl<R: Copy> MemoryMap<R> {
// todo!("Open bus (${addr:04X})") // todo!("Open bus (${addr:04X})")
} }
pub fn clear(&mut self) { // pub fn clear(&mut self) {
for s in &mut self.segments { // for s in &mut self.segments {
match &mut s.mem { // match &mut s.mem {
Data::RAM(items) => items.fill(0), // Data::RAM(items) => items.fill(0),
_ => (), // _ => (),
} // }
} // }
} // }
pub fn power_cycle(&mut self) -> Self { pub fn power_cycle(&mut self) -> Self {
for seg in &mut self.segments { for seg in &mut self.segments {
@@ -217,8 +216,7 @@ impl<R: Copy> MemoryMap<R> {
Data::Mirror(pos) => { Data::Mirror(pos) => {
let offset = addr - segment.position; let offset = addr - segment.position;
self.peek_val(pos + offset) self.peek_val(pos + offset)
} } // Data::Disabled => Err(None),
Data::Disabled => Err(None),
}; };
} }
} }
@@ -244,13 +242,38 @@ impl<R: Copy> Memory for MemoryMap<R> {
} }
} }
bitfield! {
#[derive(Clone, Copy, PartialEq, Eq)]
struct ShiftPair(u8);
impl Debug;
high, set_high: 7, 4;
low, set_low: 3, 0;
}
impl ShiftPair {
fn low_count(&self) -> usize {
if self.low() == 0 { 0 } else { 64 << self.low() }
}
fn high_count(&self) -> usize {
if self.high() == 0 {
0
} else {
64 << self.high()
}
}
}
#[derive(Clone, Copy, PartialEq, Eq)] #[derive(Clone, Copy, PartialEq, Eq)]
struct Mapper { struct Mapper {
is_nes_2: bool,
horizontal_name_table: bool, horizontal_name_table: bool,
mapper: u16, mapper: u16,
sub_mapper: u8, sub_mapper: u8,
prg_rom_size: u8, prg_rom_size: u8,
chr_rom_size: u8, chr_rom_size: u8,
prg_nv_ram_size: ShiftPair,
chr_nv_ram_size: ShiftPair,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -279,6 +302,8 @@ enum SegmentId {
PrgBank1, PrgBank1,
ChrBank0, ChrBank0,
ChrBank1, ChrBank1,
NVRam,
} }
impl fmt::Display for SegmentId { impl fmt::Display for SegmentId {
@@ -304,10 +329,11 @@ impl Mapped {
// } // }
let mapper = if nes_20 { let mapper = if nes_20 {
assert_eq!(header[9], 0, "No support for larger PRG/CHR roms"); assert_eq!(header[9], 0, "No support for larger PRG/CHR roms");
assert_eq!(header[10], 0, "No support for PRG-RAM/EEPROM"); // assert_eq!(header[10], 0, "No support for PRG-RAM/EEPROM");
assert_eq!(header[11], 0, "No support for CHR-RAM"); // assert_eq!(header[11], 0, "No support for CHR-RAM");
assert!(header[12] == 0 || header[12] == 2, "Only support NTSC NES"); assert!(header[12] == 0 || header[12] == 2, "Only support NTSC NES");
Mapper { Mapper {
is_nes_2: true,
horizontal_name_table: header[6] & (1 << 0) == 1, horizontal_name_table: header[6] & (1 << 0) == 1,
mapper: ((header[6] as u16 & 0xF0) >> 4) mapper: ((header[6] as u16 & 0xF0) >> 4)
| ((header[7] as u16 & 0xF0) >> 0) | ((header[7] as u16 & 0xF0) >> 0)
@@ -315,18 +341,39 @@ impl Mapped {
sub_mapper: (header[8] & 0xF0) >> 4, sub_mapper: (header[8] & 0xF0) >> 4,
prg_rom_size: header[4], prg_rom_size: header[4],
chr_rom_size: header[5], chr_rom_size: header[5],
prg_nv_ram_size: ShiftPair(header[10]),
chr_nv_ram_size: ShiftPair(header[11]),
} }
} else { } else {
Mapper { Mapper {
is_nes_2: false,
horizontal_name_table: header[6] & (1 << 0) == 1, horizontal_name_table: header[6] & (1 << 0) == 1,
mapper: ((header[6] as u16 & 0xF0) >> 4) | ((header[7] as u16 & 0xF0) >> 0), mapper: ((header[6] as u16 & 0xF0) >> 4) | ((header[7] as u16 & 0xF0) >> 0),
sub_mapper: 0, sub_mapper: 0,
prg_rom_size: header[4], prg_rom_size: header[4],
chr_rom_size: header[5], chr_rom_size: header[5],
prg_nv_ram_size: ShiftPair(0),
chr_nv_ram_size: ShiftPair(0),
} }
}; };
let (prg_rom, rom) = rom.split_at(mapper.prg_rom_size as usize * 0x4000); let (prg_rom, rom) = rom.split_at(mapper.prg_rom_size as usize * 0x4000);
let (chr_rom, rom) = rom.split_at(mapper.chr_rom_size as usize * 0x2000); let (chr_rom, _rom) = rom.split_at(mapper.chr_rom_size as usize * 0x2000);
println!("Mapper: {}/{}", mapper.mapper, mapper.sub_mapper);
assert_eq!(
mapper.prg_nv_ram_size.low_count(),
0,
"No support for PRG-RAM"
);
// assert_eq!(
// mapper.chr_nv_ram_size.low_count(),
// 0,
// "No support for CHR-RAM"
// );
assert_eq!(
mapper.chr_nv_ram_size.high_count(),
0,
"No support for CHR-NVRAM"
);
// assert_eq!(rom.len(), 0); // assert_eq!(rom.len(), 0);
// let prg_rom = &file[self.cpu_offset()..self.ppu_offset()]; // let prg_rom = &file[self.cpu_offset()..self.ppu_offset()];
let mut cpu_segments = vec![ let mut cpu_segments = vec![
@@ -340,6 +387,14 @@ impl Mapped {
CPUMMRegisters::APU, CPUMMRegisters::APU,
), ),
]; ];
// CHR-NVRAM
if mapper.prg_nv_ram_size.high_count() > 0 {
cpu_segments.push(Segment::ram(
SegmentId::NVRam,
0x6000,
mapper.prg_nv_ram_size.high_count() as u16,
));
}
let mut ppu_segments = vec![ let mut ppu_segments = vec![
Segment::mirror(SegmentId::VramMirror, 0x3000, 0x0F00, 0x0000), Segment::mirror(SegmentId::VramMirror, 0x3000, 0x0F00, 0x0000),
Segment::reg( Segment::reg(
@@ -387,11 +442,23 @@ impl Mapped {
0x8000 + (0x8000 - prg_rom.len() as u16), 0x8000 + (0x8000 - prg_rom.len() as u16),
prg_rom, prg_rom,
)); ));
if mapper.is_nes_2 {
if mapper.chr_nv_ram_size.low_count() > 0 {
ppu_segments.push(Segment::ram(
SegmentId::PpuRam,
0,
mapper.chr_nv_ram_size.low_count() as u16,
));
} else {
ppu_segments.push(Segment::rom(SegmentId::PpuRom, 0, chr_rom));
}
} else {
if chr_rom.len() == 0 { if chr_rom.len() == 0 {
ppu_segments.push(Segment::ram(SegmentId::PpuRam, 0, 0x2000)); ppu_segments.push(Segment::ram(SegmentId::PpuRam, 0, 0x2000));
} else { } else {
ppu_segments.push(Segment::rom(SegmentId::PpuRom, 0, chr_rom)); ppu_segments.push(Segment::rom(SegmentId::PpuRom, 0, chr_rom));
} }
}
Remapper::None Remapper::None
} else if mapper.mapper == 1 && mapper.sub_mapper == 0 { } else if mapper.mapper == 1 && mapper.sub_mapper == 0 {
let prg_banks: Vec<Arc<[u8]>> = let prg_banks: Vec<Arc<[u8]>> =
@@ -550,7 +617,7 @@ impl<'a> CpuMem<'a> {
*shift_reg = 0; *shift_reg = 0;
*count = 0; *count = 0;
} else if *count == 4 { } else if *count == 4 {
let val = (*shift_reg << 1) | (val & 0x01); let val = (*shift_reg >> 1) | ((val & 0x01) << 4);
if (addr & 0x6000) >> 13 == 0 { if (addr & 0x6000) >> 13 == 0 {
// TODO: fix mem layout if it's changed // TODO: fix mem layout if it's changed
if val & 0b01100 == 0b01000 { if val & 0b01100 == 0b01000 {
@@ -591,6 +658,7 @@ impl<'a> CpuMem<'a> {
} }
} else if (addr & 0x6000) >> 13 == 3 { } else if (addr & 0x6000) >> 13 == 3 {
*cur_prg_bank = (val & 0x0F) as usize; *cur_prg_bank = (val & 0x0F) as usize;
println!("Updating ROM: new {:X}", val);
match mode { match mode {
MMC1Mode::Full => { MMC1Mode::Full => {
let bank0 = self.mem.cpu.find(SegmentId::PrgBank0).unwrap(); let bank0 = self.mem.cpu.find(SegmentId::PrgBank0).unwrap();
@@ -600,11 +668,13 @@ impl<'a> CpuMem<'a> {
} }
MMC1Mode::FirstFixed => { MMC1Mode::FirstFixed => {
let bank1 = self.mem.cpu.find(SegmentId::PrgBank1).unwrap(); let bank1 = self.mem.cpu.find(SegmentId::PrgBank1).unwrap();
bank1.swap_rom(prg_banks[(val & 0x0F) as usize].clone()); // Highest bit is ignored
bank1.swap_rom(prg_banks[(val & 0x07) as usize].clone());
} }
MMC1Mode::LastFixed => { MMC1Mode::LastFixed => {
let bank0 = self.mem.cpu.find(SegmentId::PrgBank0).unwrap(); let bank0 = self.mem.cpu.find(SegmentId::PrgBank0).unwrap();
bank0.swap_rom(prg_banks[(val & 0x0F) as usize].clone()); // Highest bit is ignored
bank0.swap_rom(prg_banks[(val & 0x07) as usize].clone());
} }
} }
// TODO: handle MSB, changes some stuff... // TODO: handle MSB, changes some stuff...
@@ -614,8 +684,9 @@ impl<'a> CpuMem<'a> {
*shift_reg = 0; *shift_reg = 0;
*count = 0; *count = 0;
} else { } else {
*shift_reg = (*shift_reg << 1) | (val & 0x01); *shift_reg = (*shift_reg >> 1) | ((val & 0x01) << 4);
*count += 1; *count += 1;
println!("Mapper SHR {:05b}", *shift_reg);
} }
} }
_ => (), _ => (),