tetanes_core/mapper/
m007_axrom.rs

1//! `AxROM` (Mapper 007).
2//!
3//! <https://wiki.nesdev.org/w/index.php/AxROM>
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/// `AxROM` (Mapper 007).
17#[derive(Debug, Clone, Serialize, Deserialize)]
18#[must_use]
19pub struct Axrom {
20    pub mirroring: Mirroring,
21    pub prg_rom_banks: Banks,
22}
23
24impl Axrom {
25    const PRG_ROM_WINDOW: usize = 32 * 1024;
26    const CHR_RAM_SIZE: usize = 8 * 1024;
27    const SINGLE_SCREEN_B: u8 = 0x10; // 0b10000
28
29    pub fn load(cart: &mut Cart) -> Result<Mapper, mapper::Error> {
30        if !cart.has_chr_rom() && cart.chr_ram.is_empty() {
31            cart.add_chr_ram(Self::CHR_RAM_SIZE);
32        }
33        let axrom = Self {
34            mirroring: cart.mirroring(),
35            prg_rom_banks: Banks::new(0x8000, 0xFFFF, cart.prg_rom.len(), Self::PRG_ROM_WINDOW)?,
36        };
37        Ok(axrom.into())
38    }
39}
40
41impl Mirrored for Axrom {
42    fn mirroring(&self) -> Mirroring {
43        self.mirroring
44    }
45
46    fn set_mirroring(&mut self, mirroring: Mirroring) {
47        self.mirroring = mirroring;
48    }
49}
50
51impl MapRead for Axrom {
52    // PPU $0000..=$1FFF 8K CHR-RAM Bank Fixed
53    // CPU $8000..=$FFFF 32K switchable PRG-ROM bank
54
55    fn map_peek(&self, addr: u16) -> MappedRead {
56        match addr {
57            0x0000..=0x1FFF => MappedRead::Chr(addr.into()),
58            0x8000..=0xFFFF => MappedRead::PrgRom(self.prg_rom_banks.translate(addr)),
59            _ => MappedRead::Bus,
60        }
61    }
62}
63
64impl MapWrite for Axrom {
65    fn map_write(&mut self, addr: u16, val: u8) -> MappedWrite {
66        match addr {
67            0x0000..=0x1FFF => MappedWrite::ChrRam(addr.into(), val),
68            0x8000..=0xFFFF => {
69                self.prg_rom_banks.set(0, (val & 0x0F).into());
70                self.mirroring = if val & Self::SINGLE_SCREEN_B == Self::SINGLE_SCREEN_B {
71                    Mirroring::SingleScreenB
72                } else {
73                    Mirroring::SingleScreenA
74                };
75                MappedWrite::Bus
76            }
77            _ => MappedWrite::Bus,
78        }
79    }
80}
81
82impl OnBusRead for Axrom {}
83impl OnBusWrite for Axrom {}
84impl Reset for Axrom {}
85impl Clock for Axrom {}
86impl Regional for Axrom {}
87impl Sram for Axrom {}