Code for the Namco 175 and Namco 340 boards (iNES mapper 210).

3use crate::bus::cartridge::mappers::{BankSizeKb, ChrType, NametableMirroring, PpuMapResult};
4use crate::bus::cartridge::{HasBasicPpuMapping, MapperImpl};
5use bincode::{Decode, Encode};
6use jgenesis_common::num::GetBit;
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)]
9enum Variant {
10    Namco175,
11    Namco340,
12    Unknown,
13}
14
15#[derive(Debug, Clone, Encode, Decode)]
16pub(crate) struct Namco175 {
17    variant: Variant,
18    chr_type: ChrType,
19    nametable_mirroring: NametableMirroring,
20    prg_banks: [u8; 3],
21    chr_banks: [u8; 8],
22    ram_enabled: bool,
23}
24
25impl Namco175 {
26    pub(crate) fn new(
27        sub_mapper_number: u8,
28        chr_type: ChrType,
29        nametable_mirroring: NametableMirroring,
30    ) -> Self {
31        let variant = match sub_mapper_number {
32            1 => Variant::Namco175,
33            2 => Variant::Namco340,
34            _ => Variant::Unknown,
35        };
36
37        log::info!("Namco 175 variant: {variant:?}");
38
39        Self {
40            variant,
41            chr_type,
42            nametable_mirroring,
43            prg_banks: [0; 3],
44            chr_banks: [0; 8],
45            ram_enabled: false,
46        }
47    }
48}
49
50impl MapperImpl<Namco175> {
51    pub(crate) fn read_cpu_address(&self, address: u16, cpu_open_bus: u8) -> u8 {
52        match address {
53            0x0000..=0x401F => panic!("invalid CPU map address: {address:04X}"),
54            0x4020..=0x5FFF => cpu_open_bus,
55            0x6000..=0x7FFF => {
56                if self.data.ram_enabled && !self.cartridge.prg_ram.is_empty() {
57                    self.cartridge.get_prg_ram((address & 0x1FFF).into())
58                } else {
59                    cpu_open_bus
60                }
61            }
62            0x8000..=0xDFFF => {
63                let bank_index = (address & 0x7FFF) / 0x2000;
64                let bank_number = self.data.prg_banks[bank_index as usize];
65                let prg_rom_addr = BankSizeKb::Eight.to_absolute_address(bank_number, address);
66                self.cartridge.get_prg_rom(prg_rom_addr)
67            }
68            0xE000..=0xFFFF => {
69                let prg_rom_addr = BankSizeKb::Eight
70                    .to_absolute_address_last_bank(self.cartridge.prg_rom.len() as u32, address);
71                self.cartridge.get_prg_rom(prg_rom_addr)
72            }
73        }
74    }
75
76    pub(crate) fn write_cpu_address(&mut self, address: u16, value: u8) {
77        match address {
78            0x0000..=0x401F => panic!("invalid CPU map address: {address:04X}"),
79            0x6000..=0x7FFF if self.data.ram_enabled && !self.cartridge.prg_ram.is_empty() => {
80                self.cartridge.set_prg_ram((address & 0x1FFF).into(), value);
81            }
82            0x8000..=0xBFFF => {
83                let bank_index = (address & 0x7FFF) / 0x0800;
84                self.data.chr_banks[bank_index as usize] = value;
85            }
86            0xC000..=0xC7FF => {
87                if matches!(self.data.variant, Variant::Namco175 | Variant::Unknown) {
88                    self.data.ram_enabled = value.bit(0);
89                }
90            }
91            0xE000..=0xE7FF => {
92                self.data.prg_banks[0] = value & 0x3F;
93
94                if matches!(self.data.variant, Variant::Namco340 | Variant::Unknown) {
95                    self.data.nametable_mirroring = match value & 0xC0 {
96                        0x00 => NametableMirroring::SingleScreenBank0,
97                        0x40 => NametableMirroring::Vertical,
98                        0x80 => NametableMirroring::SingleScreenBank1,
99                        0xC0 => NametableMirroring::Horizontal,
100                        _ => unreachable!("value & 0xC0 should always be 0x00/0x40/0x80/0xC0"),
101                    };
102                }
103            }
104            0xE800..=0xEFFF => {
105                self.data.prg_banks[1] = value & 0x3F;
106            }
107            0xF000..=0xF7FF => {
108                self.data.prg_banks[2] = value & 0x3F;
109            }
110            _ => {}
111        }
112    }
113}
114
115impl HasBasicPpuMapping for MapperImpl<Namco175> {
116    fn map_ppu_address(&self, address: u16) -> PpuMapResult {
117        match address {
118            0x0000..=0x1FFF => {
119                let bank_index = address / 0x0400;
120                let bank_number = self.data.chr_banks[bank_index as usize];
121                let chr_addr = BankSizeKb::One.to_absolute_address(bank_number, address);
122                self.data.chr_type.to_map_result(chr_addr)
123            }
124            0x2000..=0x3EFF => {
125                PpuMapResult::Vram(self.data.nametable_mirroring.map_to_vram(address))
126            }
127            0x3F00..=0xFFFF => panic!("invalid PPU map result: {address:04X}"),
128        }
129    }
130}