nes_core/mapper/
m002_uxrom.rs

1//! `UxROM` (Mapper 002)
2//!
3//! <https://wiki.nesdev.com/w/index.php/UxROM>
4
5use crate::{
6    cart::Cart,
7    common::{Clock, Regional, Reset},
8    mapper::{Mapped, MappedRead, MappedWrite, Mapper, MemMap},
9    mem::MemBanks,
10    ppu::Mirroring,
11};
12use serde::{Deserialize, Serialize};
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
15#[must_use]
16pub struct Uxrom {
17    mirroring: Mirroring,
18    prg_rom_banks: MemBanks,
19}
20
21impl Uxrom {
22    const PRG_ROM_WINDOW: usize = 16 * 1024;
23    const CHR_RAM_SIZE: usize = 8 * 1024;
24
25    pub fn load(cart: &mut Cart) -> Mapper {
26        if !cart.has_chr() {
27            cart.add_chr_ram(Self::CHR_RAM_SIZE);
28        };
29        let mut uxrom = Self {
30            mirroring: cart.mirroring(),
31            prg_rom_banks: MemBanks::new(0x8000, 0xFFFF, cart.prg_rom.len(), Self::PRG_ROM_WINDOW),
32        };
33        let last_bank = uxrom.prg_rom_banks.last();
34        uxrom.prg_rom_banks.set(1, last_bank);
35        uxrom.into()
36    }
37}
38
39impl MemMap for Uxrom {
40    // PPU $0000..=$1FFF 8K Fixed CHR-ROM/CHR-RAM Bank
41    // CPU $8000..=$BFFF 16K PRG-ROM Bank Switchable
42    // CPU $C000..=$FFFF 16K PRG-ROM Fixed to Last Bank
43
44    fn map_peek(&self, addr: u16) -> MappedRead {
45        match addr {
46            0x0000..=0x1FFF => MappedRead::Chr(addr.into()),
47            0x8000..=0xFFFF => MappedRead::PrgRom(self.prg_rom_banks.translate(addr)),
48            _ => MappedRead::None,
49        }
50    }
51
52    fn map_write(&mut self, addr: u16, val: u8) -> MappedWrite {
53        match addr {
54            0x0000..=0x1FFF => MappedWrite::Chr(addr.into(), val),
55            0x8000..=0xFFFF => {
56                self.prg_rom_banks.set(0, val.into());
57                MappedWrite::None
58            }
59            _ => MappedWrite::None,
60        }
61    }
62}
63
64impl Mapped for Uxrom {
65    #[inline]
66    fn mirroring(&self) -> Mirroring {
67        self.mirroring
68    }
69
70    #[inline]
71    fn set_mirroring(&mut self, mirroring: Mirroring) {
72        self.mirroring = mirroring;
73    }
74}
75
76impl Clock for Uxrom {}
77impl Regional for Uxrom {}
78impl Reset for Uxrom {}