Skip to content

Commit

Permalink
Cartridge: added support for switchable mirroring
Browse files Browse the repository at this point in the history
- properly handled the mirroring flags in INES header
  • Loading branch information
Amjad50 committed Jul 18, 2020
1 parent bd34dc2 commit 27ab9f9
Show file tree
Hide file tree
Showing 12 changed files with 112 additions and 40 deletions.
26 changes: 22 additions & 4 deletions cartridge/src/cartridge.rs
@@ -1,5 +1,5 @@
use super::{error::CartridgeError, mapper::Mapper, mappers::*};
use common::{Bus, Device};
use common::{Bus, Device, MirroringMode, MirroringProvider};
use std::{
fs::File,
io::{Read, Seek, SeekFrom},
Expand All @@ -13,7 +13,7 @@ pub struct Cartridge {
mirroring_vertical: bool,
contain_sram: bool,
contain_trainer: bool,
ignore_mirroring: bool,
use_4_screen_mirroring: bool,
vs_unisystem: bool, // don't know what is this (flag 7)
_playchoice_10_hint: bool, // not used
is_nes_2: bool,
Expand Down Expand Up @@ -43,7 +43,7 @@ impl Cartridge {
header[6] >>= 1;
let contain_trainer = header[6] & 1 != 0;
header[6] >>= 1;
let ignore_mirroring = header[6] & 1 != 0;
let use_4_screen_mirroring = header[6] & 1 != 0;
header[6] >>= 1;
let lower_mapper = header[6]; // the rest

Expand Down Expand Up @@ -104,7 +104,7 @@ impl Cartridge {
mirroring_vertical,
contain_sram,
contain_trainer,
ignore_mirroring,
use_4_screen_mirroring,
vs_unisystem,
_playchoice_10_hint,
is_nes_2,
Expand Down Expand Up @@ -188,3 +188,21 @@ impl Bus for Cartridge {
}
}
}

impl MirroringProvider for Cartridge {
fn mirroring_mode(&self) -> MirroringMode {
if self.use_4_screen_mirroring {
MirroringMode::FourScreen
} else {
if self.mapper.is_hardwired_mirrored() {
if self.mirroring_vertical {
MirroringMode::Vertical
} else {
MirroringMode::Horizontal
}
} else {
self.mapper.nametable_mirroring()
}
}
}
}
4 changes: 3 additions & 1 deletion cartridge/src/mapper.rs
@@ -1,7 +1,9 @@
use common::Device;
use common::{Device, MirroringMode};

pub trait Mapper {
fn init(&mut self, pgr_count: u8, chr_count: u8);
fn map_read(&self, address: u16, device: Device) -> usize;
fn map_write(&mut self, address: u16, data: u8, device: Device);
fn is_hardwired_mirrored(&self) -> bool;
fn nametable_mirroring(&self) -> MirroringMode;
}
10 changes: 9 additions & 1 deletion cartridge/src/mappers/mapper0.rs
@@ -1,5 +1,5 @@
use crate::mapper::Mapper;
use common::Device;
use common::{Device, MirroringMode};

pub struct Mapper0 {
has_32kb_prg_rom: bool,
Expand Down Expand Up @@ -60,4 +60,12 @@ impl Mapper for Mapper0 {
fn map_write(&mut self, _: u16, _: u8, _: Device) {
// nothing
}

fn is_hardwired_mirrored(&self) -> bool {
true
}

fn nametable_mirroring(&self) -> MirroringMode {
unreachable!()
}
}
16 changes: 14 additions & 2 deletions cartridge/src/mappers/mapper1.rs
@@ -1,5 +1,5 @@
use crate::mapper::Mapper;
use common::Device;
use common::{Device, MirroringMode};

// FIXME: add support for 512kb as now only support 256kb
pub struct Mapper1 {
Expand Down Expand Up @@ -66,7 +66,6 @@ impl Mapper1 {
self.writing_shift_register = 0b10000;
}

// FIXME: handle mirroring from here, and add support to switchable mirroring modes
fn get_mirroring(&self) -> u8 {
self.control_register & 0b00011
}
Expand Down Expand Up @@ -216,4 +215,17 @@ impl Mapper for Mapper1 {
}
}
}

fn is_hardwired_mirrored(&self) -> bool {
false
}

fn nametable_mirroring(&self) -> MirroringMode {
[
MirroringMode::SingleScreenLowBank,
MirroringMode::Horizontal,
MirroringMode::Vertical,
MirroringMode::Horizontal,
][self.get_mirroring() as usize]
}
}
10 changes: 9 additions & 1 deletion cartridge/src/mappers/mapper2.rs
@@ -1,5 +1,5 @@
use crate::mapper::Mapper;
use common::Device;
use common::{Device, MirroringMode};

pub struct Mapper2 {
prg_top_bank: u8,
Expand Down Expand Up @@ -65,4 +65,12 @@ impl Mapper for Mapper2 {
}
}
}

fn is_hardwired_mirrored(&self) -> bool {
true
}

fn nametable_mirroring(&self) -> MirroringMode {
unreachable!()
}
}
10 changes: 9 additions & 1 deletion cartridge/src/mappers/mapper3.rs
@@ -1,5 +1,5 @@
use crate::mapper::Mapper;
use common::Device;
use common::{Device, MirroringMode};

pub struct Mapper3 {
has_32kb_prg_rom: bool,
Expand Down Expand Up @@ -82,4 +82,12 @@ impl Mapper for Mapper3 {
}
}
}

fn is_hardwired_mirrored(&self) -> bool {
true
}

fn nametable_mirroring(&self) -> MirroringMode {
unreachable!()
}
}
14 changes: 13 additions & 1 deletion cartridge/src/mappers/mapper4.rs
@@ -1,5 +1,5 @@
use crate::mapper::Mapper;
use common::Device;
use common::{Device, MirroringMode};

pub struct Mapper4 {
/// ($8000-$9FFE, even)
Expand Down Expand Up @@ -239,4 +239,16 @@ impl Mapper for Mapper4 {
}
}
}

fn is_hardwired_mirrored(&self) -> bool {
false
}

fn nametable_mirroring(&self) -> MirroringMode {
if self.mirroring_vertical {
MirroringMode::Vertical
} else {
MirroringMode::Horizontal
}
}
}
3 changes: 3 additions & 0 deletions common/src/lib.rs
@@ -1,4 +1,7 @@
mod bus;
mod mirroring;

pub mod interconnection;

pub use bus::{Bus, Device};
pub use mirroring::{MirroringMode, MirroringProvider};
12 changes: 12 additions & 0 deletions common/src/mirroring.rs
@@ -0,0 +1,12 @@
#[derive(Debug, Copy, Clone)]
pub enum MirroringMode {
Vertical,
Horizontal,
SingleScreenLowBank,
SingleScreenHighBank,
FourScreen,
}

pub trait MirroringProvider {
fn mirroring_mode(&self) -> MirroringMode;
}
11 changes: 4 additions & 7 deletions nes_test/src/nes.rs
Expand Up @@ -56,10 +56,10 @@ impl CPUBus {
}

impl PPUBus {
pub fn new(cartridge: Rc<RefCell<Cartridge>>, is_vertical_mirroring: bool) -> Self {
pub fn new(cartridge: Rc<RefCell<Cartridge>>) -> Self {
PPUBus {
cartridge,
vram: VRam::new(is_vertical_mirroring),
cartridge: cartridge.clone(),
vram: VRam::new(cartridge.clone()),
palettes: Palette::new(),
}
}
Expand Down Expand Up @@ -137,10 +137,7 @@ impl NES {
pub fn new(filename: &str) -> Result<Self, CartridgeError> {
let cartridge = Cartridge::from_file(File::open(filename)?)?;
let cartridge = Rc::new(RefCell::new(cartridge));
let ppubus = PPUBus::new(
cartridge.clone(),
cartridge.borrow().is_vertical_mirroring(),
);
let ppubus = PPUBus::new(cartridge.clone());

let tv = TV::new(TV_WIDTH, TV_HEIGHT);
let image = tv.get_image_clone();
Expand Down
11 changes: 4 additions & 7 deletions ppu2c02/src/tests.rs
Expand Up @@ -77,10 +77,10 @@ mod ppu_tests {
}

impl PPUBus {
pub fn new(cartridge: Rc<RefCell<Cartridge>>, is_vertical_mirroring: bool) -> Self {
pub fn new(cartridge: Rc<RefCell<Cartridge>>) -> Self {
PPUBus {
cartridge,
vram: VRam::new(is_vertical_mirroring),
cartridge: cartridge.clone(),
vram: VRam::new(cartridge.clone()),
palettes: Palette::new(),
}
}
Expand Down Expand Up @@ -153,10 +153,7 @@ mod ppu_tests {
fn new(filename: &str) -> Result<Self, CartridgeError> {
let cartridge = Rc::new(RefCell::new(Cartridge::from_file(File::open(filename)?)?));

let ppubus = PPUBus::new(
cartridge.clone(),
cartridge.borrow().is_vertical_mirroring(),
);
let ppubus = PPUBus::new(cartridge.clone());

let tv = TV::new(TV_WIDTH, TV_HEIGHT);
let tv_image = tv.get_image_clone();
Expand Down
25 changes: 10 additions & 15 deletions ppu2c02/src/vram.rs
@@ -1,26 +1,17 @@
use common::{Bus, Device};

enum MirroringMode {
Vertical,
Horizontal,
// TODO: add other strange mirroring modes
}
use common::{Bus, Device, MirroringMode, MirroringProvider};
use std::{cell::RefCell, rc::Rc};

pub struct VRam {
// half of this memory (or depending on mirroring mode) is unused
vram_data: [u8; 0x1000],
mirroring_mode: MirroringMode,
mirroring_provider: Rc<RefCell<dyn MirroringProvider>>,
}

impl VRam {
pub fn new(is_vertical_mirroring: bool) -> Self {
pub fn new(mirroring_provider: Rc<RefCell<dyn MirroringProvider>>) -> Self {
Self {
vram_data: [0; 0x1000],
mirroring_mode: if is_vertical_mirroring {
MirroringMode::Vertical
} else {
MirroringMode::Horizontal
},
mirroring_provider,
}
}

Expand All @@ -40,9 +31,13 @@ impl VRam {
fn map_address(&self, address: u16) -> u16 {
assert!(address >= 0x2000 && address < 0x3000);

match self.mirroring_mode {
match self.mirroring_provider.borrow().mirroring_mode() {
MirroringMode::Vertical => address & 0x7FF,
MirroringMode::Horizontal => address & 0xBFF,
_ => unimplemented!(
"mirroring mode {:?}",
self.mirroring_provider.borrow().mirroring_mode()
),
}
}
}
Expand Down

0 comments on commit 27ab9f9

Please sign in to comment.