1pub(crate) mod action52; 2pub(crate) mod bandai; 3pub(crate) mod konami; 4pub(crate) mod mmc1; 5pub(crate) mod mmc2; 6pub(crate) mod mmc3; 7pub(crate) mod mmc5; 8pub(crate) mod namco163; 9pub(crate) mod namco175; 10pub(crate) mod nrom; 11pub(crate) mod sunsoft; 12pub(crate) mod unrom512; 13 14use crate::bus::cartridge::Cartridge; 15use bincode::{Decode, Encode}; 16 17#[allow(clippy::upper_case_acronyms)] 18#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)] 19pub(crate) enum ChrType { 20 ROM, 21 RAM, 22} 23 24impl ChrType { 25 fn to_map_result(self, address: u32) -> PpuMapResult { 26 match self { 27 Self::ROM => PpuMapResult::ChrROM(address), 28 Self::RAM => PpuMapResult::ChrRAM(address), 29 } 30 } 31} 32 33#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)] 34pub(crate) enum NametableMirroring { 35 Horizontal, 36 Vertical, 37 SingleScreenBank0, 38 SingleScreenBank1, 39} 40 41impl NametableMirroring { 42 fn map_to_vram(self, address: u16) -> u16 { 43 assert!((0x2000..=0x3EFF).contains(&address)); 44 45 let relative_addr = address & 0x0FFF; 46 47 match self { 48 Self::Horizontal => ((relative_addr & 0x0800) >> 1) | (relative_addr & 0x03FF), 49 Self::Vertical => relative_addr & 0x07FF, 50 Self::SingleScreenBank0 => relative_addr & 0x03FF, 51 Self::SingleScreenBank1 => 0x0400 | (relative_addr & 0x03FF), 52 } 53 } 54} 55 56#[derive(Debug, Clone, Copy)] 57pub(crate) enum CpuMapResult { 58 PrgROM(u32), 59 PrgRAM(u32), 60 None, 61} 62 63impl CpuMapResult { 64 fn read(self, cartridge: &Cartridge) -> Option<u8> { 65 match self { 66 Self::PrgROM(address) => Some(cartridge.get_prg_rom(address)), 67 Self::PrgRAM(address) => Some(cartridge.get_prg_ram(address)), 68 Self::None => None, 69 } 70 } 71 72 fn write(self, value: u8, cartridge: &mut Cartridge) { 73 if let Self::PrgRAM(address) = self { 74 cartridge.set_prg_ram(address, value); 75 } 76 } 77} 78 79#[derive(Debug, Clone, Copy)] 80pub(crate) enum PpuMapResult { 81 ChrROM(u32), 82 ChrRAM(u32), 83 Vram(u16), 84} 85 86impl PpuMapResult { 87 pub(super) fn read(self, cartridge: &Cartridge, vram: &[u8; 2048]) -> u8 { 88 match self { 89 Self::ChrROM(address) => cartridge.get_chr_rom(address), 90 Self::ChrRAM(address) => cartridge.get_chr_ram(address), 91 Self::Vram(address) => vram[address as usize], 92 } 93 } 94 95 pub(super) fn write(self, value: u8, cartridge: &mut Cartridge, vram: &mut [u8; 2048]) { 96 match self { 97 Self::ChrROM(_) => {} 98 Self::ChrRAM(address) => { 99 cartridge.set_chr_ram(address, value); 100 } 101 Self::Vram(address) => { 102 vram[address as usize] = value; 103 } 104 } 105 } 106} 107 108#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)] 109enum BankSizeKb { 110 One, 111 Two, 112 Four, 113 Eight, 114 Sixteen, 115 ThirtyTwo, 116} 117 118impl BankSizeKb { 119 fn shift(self) -> u32 { 120 match self { 121 Self::One => 10, 122 Self::Two => 11, 123 Self::Four => 12, 124 Self::Eight => 13, 125 Self::Sixteen => 14, 126 Self::ThirtyTwo => 15, 127 } 128 } 129 130 fn address_mask(self) -> u16 { 131 match self { 132 Self::One => 0x03FF, 133 Self::Two => 0x07FF, 134 Self::Four => 0x0FFF, 135 Self::Eight => 0x1FFF, 136 Self::Sixteen => 0x3FFF, 137 Self::ThirtyTwo => 0x7FFF, 138 } 139 } 140 141 fn to_absolute_address<N: Into<u32>>(self, bank_number: N, address: u16) -> u32 { 142 (bank_number.into() << self.shift()) | u32::from(address & self.address_mask()) 143 } 144 145 fn to_absolute_address_from_end<N: Into<u32>>( 146 self, 147 inverse_bank_number: N, 148 memory_len: u32, 149 address: u16, 150 ) -> u32 { 151 (((memory_len >> self.shift()) - inverse_bank_number.into()) << self.shift()) 152 | u32::from(address & self.address_mask()) 153 } 154 155 fn to_absolute_address_last_bank(self, memory_len: u32, address: u16) -> u32 { 156 self.to_absolute_address_from_end(1_u32, memory_len, address) 157 } 158} 159 160#[cfg(test)] 161pub(crate) fn new_mmc1(prg_rom: Vec<u8>) -> super::Mapper { 162 use super::mappers::mmc1::Mmc1; 163 use super::{Mapper, MapperImpl, TimingMode}; 164 165 Mapper::Mmc1(MapperImpl { 166 cartridge: Cartridge { 167 timing_mode: TimingMode::Ntsc, 168 prg_rom, 169 prg_ram: vec![0; 8192], 170 has_ram_battery: false, 171 prg_ram_dirty_bit: false, 172 chr_rom: vec![0; 8192], 173 chr_ram: Vec::new(), 174 }, 175 data: Mmc1::new(ChrType::ROM), 176 }) 177}