From 709e351832bb94037a373787cf0ee1cf42299d0b Mon Sep 17 00:00:00 2001 From: Theron Date: Thu, 9 Jan 2020 22:04:10 -0600 Subject: [PATCH] nrom refactor --- src/cartridge/mmc1.rs | 18 ++++++++-- src/cartridge/mod.rs | 36 +++++++++++++++----- src/cartridge/nrom.rs | 76 +++++++++++++++++++++++++++++-------------- src/cpu/mod.rs | 12 ++++--- src/main.rs | 10 +++--- src/memory_model.rs | 2 +- src/ppu/memory.rs | 26 ++++++++------- 7 files changed, 124 insertions(+), 56 deletions(-) diff --git a/src/cartridge/mmc1.rs b/src/cartridge/mmc1.rs index 5a2cd4f..0c632cd 100644 --- a/src/cartridge/mmc1.rs +++ b/src/cartridge/mmc1.rs @@ -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 + } } diff --git a/src/cartridge/mod.rs b/src/cartridge/mod.rs index d2a8e68..3dee02e 100644 --- a/src/cartridge/mod.rs +++ b/src/cartridge/mod.rs @@ -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> { + 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>, // 8 KiB chunks for PPU all_data: Vec, - 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 diff --git a/src/cartridge/nrom.rs b/src/cartridge/nrom.rs index 9834311..d515ac1 100644 --- a/src/cartridge/nrom.rs +++ b/src/cartridge/nrom.rs @@ -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 } } diff --git a/src/cpu/mod.rs b/src/cpu/mod.rs index 7cfcf47..9bc6e9e 100644 --- a/src/cpu/mod.rs +++ b/src/cpu/mod.rs @@ -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), } diff --git a/src/main.rs b/src/main.rs index c08b23a..41a63f0 100644 --- a/src/main.rs +++ b/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(); diff --git a/src/memory_model.rs b/src/memory_model.rs index ca54bd0..d055b3f 100644 --- a/src/memory_model.rs +++ b/src/memory_model.rs @@ -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()}; diff --git a/src/ppu/memory.rs b/src/ppu/memory.rs index 68b8b19..651d016 100644 --- a/src/ppu/memory.rs +++ b/src/ppu/memory.rs @@ -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;