tetanes_core/mapper/
m066_gxrom.rs

1//! `GxROM` (Mapper 066).
2//!
3//! <https://wiki.nesdev.org/w/index.php?title=GxROM>
4
5use crate::{
6    cart::Cart,
7    common::{Clock, Regional, Reset, Sram},
8    mapper::{
9        self, MapRead, MapWrite, MappedRead, MappedWrite, Mapper, Mirrored, OnBusRead, OnBusWrite,
10    },
11    mem::Banks,
12    ppu::Mirroring,
13};
14use serde::{Deserialize, Serialize};
15
16/// `GxROM` (Mapper 066).
17#[derive(Debug, Clone, Serialize, Deserialize)]
18#[must_use]
19pub struct Gxrom {
20    pub mirroring: Mirroring,
21    pub chr_banks: Banks,
22    pub prg_rom_banks: Banks,
23}
24
25impl Gxrom {
26    const PRG_ROM_WINDOW: usize = 32 * 1024;
27    const CHR_WINDOW: usize = 8 * 1024;
28
29    const CHR_BANK_MASK: u8 = 0x0F; // 0b1111
30    const PRG_BANK_MASK: u8 = 0x30; // 0b110000
31
32    pub fn load(cart: &mut Cart) -> Result<Mapper, mapper::Error> {
33        let gxrom = Self {
34            mirroring: cart.mirroring(),
35            chr_banks: Banks::new(0x0000, 0x1FFF, cart.chr_rom.len(), Self::CHR_WINDOW)?,
36            prg_rom_banks: Banks::new(0x8000, 0xFFFF, cart.prg_rom.len(), Self::PRG_ROM_WINDOW)?,
37        };
38        Ok(gxrom.into())
39    }
40}
41
42impl Mirrored for Gxrom {
43    fn mirroring(&self) -> Mirroring {
44        self.mirroring
45    }
46
47    fn set_mirroring(&mut self, mirroring: Mirroring) {
48        self.mirroring = mirroring;
49    }
50}
51
52impl MapRead for Gxrom {
53    // PPU $0000..=$1FFF 8K CHR-ROM Bank Switchable
54    // CPU $8000..=$FFFF 32K PRG-ROM Bank Switchable
55
56    fn map_peek(&self, addr: u16) -> MappedRead {
57        match addr {
58            0x0000..=0x1FFF => MappedRead::Chr(self.chr_banks.translate(addr)),
59            0x8000..=0xFFFF => MappedRead::PrgRom(self.prg_rom_banks.translate(addr)),
60            _ => MappedRead::Bus,
61        }
62    }
63}
64
65impl MapWrite for Gxrom {
66    fn map_write(&mut self, addr: u16, val: u8) -> MappedWrite {
67        if matches!(addr, 0x8000..=0xFFFF) {
68            self.chr_banks.set(0, (val & Self::CHR_BANK_MASK).into());
69            self.prg_rom_banks
70                .set(0, ((val & Self::PRG_BANK_MASK) >> 4).into());
71        }
72        MappedWrite::Bus
73    }
74}
75
76impl OnBusRead for Gxrom {}
77impl OnBusWrite for Gxrom {}
78impl Reset for Gxrom {}
79impl Clock for Gxrom {}
80impl Regional for Gxrom {}
81impl Sram for Gxrom {}