nrom refactor
This commit is contained in:
parent
9e9f4b6c51
commit
709e351832
|
@ -12,8 +12,18 @@ pub struct Mmc1 {
|
|||
}
|
||||
|
||||
impl Mmc1 {
|
||||
fn new(cart: Cartridge) -> Self {
|
||||
Mmc1
|
||||
pub fn new(cart: Cartridge) -> Self {
|
||||
let m = cart.mirroring;
|
||||
Mmc1 {
|
||||
cart: cart,
|
||||
step: 0,
|
||||
shift_register: 0,
|
||||
prg_low_bank: 0,
|
||||
prg_high_bank: 0,
|
||||
chr_low_bank: 0,
|
||||
chr_high_bank: 0,
|
||||
mirroring: m,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,4 +35,8 @@ impl Mapper for Mmc1 {
|
|||
fn write(&mut self, address: usize, value: u8) {
|
||||
|
||||
}
|
||||
|
||||
fn get_mirroring(&mut self) -> Mirror {
|
||||
self.mirroring
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,20 @@
|
|||
mod nrom;
|
||||
mod mmc1;
|
||||
|
||||
use nrom::Nrom;
|
||||
use mmc1::Mmc1;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use std::io::Read;
|
||||
|
||||
pub trait Mapper {
|
||||
fn read(&mut self, address: usize) -> u8;
|
||||
fn write(&mut self, address: usize, value: u8);
|
||||
fn get_mirroring(&mut self) -> Mirror;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum Mirror {
|
||||
LowBank,
|
||||
HighBank,
|
||||
|
@ -19,10 +27,20 @@ pub enum Mirror {
|
|||
pub type CpuMapperFunc = fn(&mut crate::cpu::Cpu, usize, bool) -> Option<&mut u8>;
|
||||
pub type PpuMapperFunc = fn(&mut crate::ppu::Ppu, usize, bool) -> Option<&mut u8>;
|
||||
|
||||
pub fn get_mapper() -> Rc<RefCell<dyn Mapper>> {
|
||||
let cart = Cartridge::new();
|
||||
let num = cart.mapper_num;
|
||||
match num {
|
||||
0 => Rc::new(RefCell::new(Nrom::new(cart))),
|
||||
1 => Rc::new(RefCell::new(Mmc1::new(cart))),
|
||||
_ => panic!("unimplemented mapper: {}", num),
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Cartridge {
|
||||
prg_rom_size: usize,
|
||||
chr_rom_size: usize,
|
||||
pub mirroring: u8, // 0 horizontal, 1 vertical
|
||||
pub mirroring: Mirror, // 0 horizontal, 1 vertical
|
||||
_bb_prg_ram_present: u8, // 1: Cartridge contains battery-backed PRG RAM ($6000-7FFF) or other persistent memory
|
||||
trainer_present: u8, // 1: 512-byte trainer at $7000-$71FF (stored before PRG data)
|
||||
_four_screen_vram: u8, // 1: Ignore mirroring control or above mirroring bit; instead provide four-screen VRAM
|
||||
|
@ -32,8 +50,9 @@ pub struct Cartridge {
|
|||
pub chr_rom: Vec<Vec<u8>>, // 8 KiB chunks for PPU
|
||||
|
||||
all_data: Vec<u8>,
|
||||
pub cpu_mapper_func: CpuMapperFunc,
|
||||
pub ppu_mapper_func: PpuMapperFunc,
|
||||
mapper_num: u8,
|
||||
// pub cpu_mapper_func: CpuMapperFunc,
|
||||
// pub ppu_mapper_func: PpuMapperFunc,
|
||||
}
|
||||
|
||||
impl Cartridge {
|
||||
|
@ -45,20 +64,21 @@ impl Cartridge {
|
|||
let mut data = vec![];
|
||||
f.read_to_end(&mut data).unwrap();
|
||||
assert!(data[0..4] == [0x4E, 0x45, 0x53, 0x1A], "signature mismatch, not an iNES file");
|
||||
let mapper = ((data[7] >> 4) << 4) + (data[6] >> 4);
|
||||
let (cpu_mapper_func, ppu_mapper_func) = get_mapper_funcs(mapper);
|
||||
let mapper_num = ((data[7] >> 4) << 4) + (data[6] >> 4);
|
||||
// let (cpu_mapper_func, ppu_mapper_func) = get_mapper_funcs(mapper);
|
||||
let mut cart = Cartridge {
|
||||
prg_rom_size: data[4] as usize,
|
||||
chr_rom_size: data[5] as usize,
|
||||
mirroring: (data[6] & (1 << 0) != 0) as u8,
|
||||
mirroring: if data[6] & (1 << 0) == 0 {Mirror::Horizontal} else {Mirror::Vertical},
|
||||
_bb_prg_ram_present: (data[6] & (1 << 1) != 0) as u8,
|
||||
trainer_present: (data[6] & (1 << 2) != 0) as u8,
|
||||
_four_screen_vram: (data[6] & (1 << 3) != 0) as u8,
|
||||
prg_rom: Vec::new(),
|
||||
chr_rom: Vec::new(),
|
||||
all_data: data,
|
||||
cpu_mapper_func: cpu_mapper_func,
|
||||
ppu_mapper_func: ppu_mapper_func,
|
||||
mapper_num: mapper_num,
|
||||
// cpu_mapper_func: cpu_mapper_func,
|
||||
// ppu_mapper_func: ppu_mapper_func,
|
||||
};
|
||||
cart.fill();
|
||||
cart
|
||||
|
|
|
@ -1,37 +1,63 @@
|
|||
use super::Cartridge;
|
||||
use super::{Cartridge, Mapper, Mirror};
|
||||
|
||||
pub struct Nrom {
|
||||
cart: Cartridge,
|
||||
// mirroring: Mirror,
|
||||
}
|
||||
|
||||
|
||||
pub fn nrom_cpu(cpu: &mut crate::cpu::Cpu, address: usize, writing: bool) -> Option<&mut u8> {
|
||||
// PRG-ROM, not -RAM
|
||||
if writing { return None };
|
||||
|
||||
// CPU $8000-$BFFF: First 16 KB of ROM.
|
||||
// CPU $C000-$FFFF: Last 16 KB of ROM (NROM-256) or mirror of $8000-$BFFF (NROM-128).
|
||||
let l = cpu.prg_rom.len();
|
||||
match address {
|
||||
0x8000..=0xBFFF => Some(&mut cpu.prg_rom[0][address % 0x4000]),
|
||||
0xC000..=0xFFFF => Some(&mut cpu.prg_rom[l - 1][address % 0x4000]),
|
||||
_ => panic!("bad cpu address passed to nrom mapper: 0x{:04x}", address),
|
||||
impl Nrom {
|
||||
pub fn new(cart: Cartridge) -> Self {
|
||||
Nrom{
|
||||
cart: cart,
|
||||
// mirroring: cart.mirroring,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nrom_ppu(ppu: &mut crate::ppu::Ppu, address: usize, writing: bool) -> Option<&mut u8> {
|
||||
let l = ppu.pattern_tables.len();
|
||||
// NROM/mapper 0 doesn't allow writes to CHR-ROM
|
||||
if writing || l == 0 { return None };
|
||||
match address {
|
||||
0x0000..=0x1FFF => Some(&mut ppu.pattern_tables[l-1][address]),
|
||||
_ => panic!("bad ppu address passed to nrom mapper: 0x{:04x}", address),
|
||||
impl Mapper for Nrom {
|
||||
fn read(&mut self, address: usize) -> u8 {
|
||||
let cl = self.cart.chr_rom.len();
|
||||
let pl = self.cart.prg_rom.len();
|
||||
let addr = address % 0x4000;
|
||||
match address {
|
||||
0x0000..=0x1FFF => {
|
||||
if cl > 0 {
|
||||
self.cart.chr_rom[cl-1][address]
|
||||
} else {
|
||||
0
|
||||
}
|
||||
},
|
||||
0x8000..=0xBFFF => {
|
||||
self.cart.prg_rom[0][addr]
|
||||
},
|
||||
0xC000..=0xFFFF => {
|
||||
self.cart.prg_rom[pl-1][addr]
|
||||
},
|
||||
_ => panic!("bad address sent to NROM mapper: 0x{:X}", address),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_mapper_funcs(mapper: u8) -> (super::CpuMapperFunc, super::PpuMapperFunc) {
|
||||
match mapper {
|
||||
0 => (nrom_cpu, nrom_ppu),
|
||||
_ => panic!("unimplemented mapper: {}", mapper),
|
||||
fn write(&mut self, address: usize, value: u8) {
|
||||
let cl = self.cart.chr_rom.len();
|
||||
let pl = self.cart.prg_rom.len();
|
||||
let addr = address % 0x4000;
|
||||
match address {
|
||||
0x0000..=0x1FFF => {
|
||||
if cl > 0 {
|
||||
self.cart.chr_rom[cl-1][address] = value;
|
||||
}
|
||||
},
|
||||
0x8000..=0xBFFF => {
|
||||
self.cart.prg_rom[0][addr] = value;
|
||||
},
|
||||
0xC000..=0xFFFF => {
|
||||
self.cart.prg_rom[pl-1][addr] = value;
|
||||
},
|
||||
_ => panic!("bad address sent to NROM mapper: 0x{:X}", address),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_mirroring(&mut self) -> Mirror {
|
||||
self.cart.mirroring
|
||||
}
|
||||
}
|
||||
|
|
|
@ -198,7 +198,8 @@ impl Cpu {
|
|||
0x4000..=0x4017 => 0, // can't read from these APU registers
|
||||
0x4018..=0x401F => 0, // APU and I/O functionality that is normally disabled. See CPU Test Mode.
|
||||
0x4020..=0xFFFF => { // Cartridge space: PRG ROM, PRG RAM, and mapper registers
|
||||
*(self.mapper_func)(self, address, false).unwrap() // unwrapping because mapper funcs won't return None for reads.
|
||||
// *(self.mapper_func)(self, address, false).unwrap() // unwrapping because mapper funcs won't return None for reads.
|
||||
self.mapper.borrow_mut().read(address)
|
||||
},
|
||||
_ => panic!("invalid read from 0x{:02x}", address),
|
||||
};
|
||||
|
@ -215,10 +216,11 @@ impl Cpu {
|
|||
0x4000..=0x4017 => self.apu.write_reg(address, val), // APU stuff
|
||||
0x4018..=0x401F => (), // APU and I/O functionality that is normally disabled. See CPU Test Mode.
|
||||
0x4020..=0xFFFF => { // Cartridge space: PRG ROM, PRG RAM, and mapper registers
|
||||
match (self.mapper_func)(self, address, true) {
|
||||
Some(loc) => *loc = val,
|
||||
None => (),
|
||||
};
|
||||
self.mapper.borrow_mut().write(address, val)
|
||||
// match (self.mapper_func)(self, address, true) {
|
||||
// Some(loc) => *loc = val,
|
||||
// None => (),
|
||||
// };
|
||||
},
|
||||
_ => panic!("invalid write to {:02x}", address),
|
||||
}
|
||||
|
|
10
src/main.rs
10
src/main.rs
|
@ -11,10 +11,12 @@ mod audio;
|
|||
use cpu::Cpu;
|
||||
use ppu::Ppu;
|
||||
use apu::Apu;
|
||||
use cartridge::Cartridge;
|
||||
use cartridge::{get_mapper, Cartridge, Mapper};
|
||||
use input::poll_buttons;
|
||||
use screen::{init_window, draw_pixel, draw_to_window};
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use sdl2::keyboard::Keycode;
|
||||
use sdl2::event::Event;
|
||||
use sdl2::pixels::PixelFormatEnum;
|
||||
|
@ -39,10 +41,10 @@ fn main() -> Result<(), String> {
|
|||
audio_device.resume();
|
||||
|
||||
// Initialize hardware components
|
||||
let cart = Cartridge::new();
|
||||
let ppu = Ppu::new(&cart);
|
||||
let mapper = get_mapper();
|
||||
let ppu = Ppu::new(mapper.clone());
|
||||
let apu = Apu::new();
|
||||
let mut cpu = Cpu::new(&cart, ppu, apu);
|
||||
let mut cpu = Cpu::new(mapper.clone(), ppu, apu);
|
||||
|
||||
// For throttling to 60 FPS
|
||||
let mut timer = Instant::now();
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::rc::Rc;
|
|||
use std::cell::RefCell;
|
||||
|
||||
fn main() {
|
||||
let mapper = Rc::new(RefCell::new(Mmc1{a:32}));
|
||||
let mapper = Rc::new(RefCell::new(Box::new(Mmc1{a:32})));
|
||||
|
||||
let ppu = Ppu{mapper: mapper.clone()};
|
||||
let cpu = Cpu{mapper: mapper.clone()};
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
use crate::cartridge::Mirror;
|
||||
|
||||
impl super::Ppu {
|
||||
|
||||
pub fn read(&mut self, addr: usize) -> u8 {
|
||||
let address = addr % 0x4000;
|
||||
match addr {
|
||||
0x0000..=0x1FFF => {
|
||||
if self.pattern_tables.len() > 0 {
|
||||
*(self.mapper_func)(self, address, false).unwrap() // unwrapping because mapper funcs won't return None for reads
|
||||
} else {
|
||||
0
|
||||
}
|
||||
self.mapper.borrow_mut().read(address)
|
||||
// if self.pattern_tables.len() > 0 {
|
||||
// *(self.mapper_func)(self, address, false).unwrap() // unwrapping because mapper funcs won't return None for reads
|
||||
// } else {
|
||||
// 0
|
||||
// }
|
||||
},
|
||||
0x2000..=0x3EFF => self.read_nametable(address),
|
||||
0x3F00..=0x3FFF => {
|
||||
|
@ -24,10 +27,11 @@ impl super::Ppu {
|
|||
let address = addr % 0x4000;
|
||||
match addr {
|
||||
0x0000..=0x1FFF => {
|
||||
match (self.mapper_func)(self, address, true) {
|
||||
Some(loc) => *loc = value,
|
||||
None => (),
|
||||
}
|
||||
self.mapper.borrow_mut().write(address, value);
|
||||
// match (self.mapper_func)(self, address, true) {
|
||||
// Some(loc) => *loc = value,
|
||||
// None => (),
|
||||
// }
|
||||
},
|
||||
0x2000..=0x3EFF => self.write_nametable(address, value),
|
||||
0x3F00..=0x3FFF => {
|
||||
|
@ -63,7 +67,7 @@ impl super::Ppu {
|
|||
fn read_nametable(&mut self, address: usize) -> u8 {
|
||||
let base = address % 0x1000;
|
||||
let offset = base % 0x0400;
|
||||
if self.mirroring == 0 { // horizontal
|
||||
if self.mapper.borrow_mut().get_mirroring() == Mirror::Horizontal {
|
||||
match base {
|
||||
0x0000..=0x07FF => {
|
||||
self.nametable_0[offset]
|
||||
|
@ -89,7 +93,7 @@ impl super::Ppu {
|
|||
fn write_nametable(&mut self, address: usize, value: u8) {
|
||||
let base = address % 0x1000;
|
||||
let offset = base % 0x0400;
|
||||
if self.mirroring == 0 { // horizontal
|
||||
if self.mapper.borrow_mut().get_mirroring() == Mirror::Horizontal { // horizontal
|
||||
match base {
|
||||
0x0000..=0x07FF => {
|
||||
self.nametable_0[offset] = value;
|
||||
|
|
Loading…
Reference in New Issue