mmc.rsannotatedmmc.rssource186 lines · 6.4 KB · raw
1use bincode::{Decode, Encode};
2use jgenesis_common::num::GetBit;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)]
5pub enum BwramMapSource {
6    #[default]
7    Normal,
8    Bitmap,
9}
10
11impl BwramMapSource {
12    fn from_bit(bit: bool) -> Self {
13        if bit { Self::Bitmap } else { Self::Normal }
14    }
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)]
18pub enum BwramBitmapBits {
19    Two,
20    #[default]
21    Four,
22}
23
24impl BwramBitmapBits {
25    fn from_bit(bit: bool) -> Self {
26        if bit { Self::Two } else { Self::Four }
27    }
28}
29
30const DEFAULT_BANK_C_ADDR: u32 = 0x000000;
31const DEFAULT_BANK_D_ADDR: u32 = 0x100000;
32const DEFAULT_BANK_E_ADDR: u32 = 0x200000;
33const DEFAULT_BANK_F_ADDR: u32 = 0x300000;
34
35#[derive(Debug, Clone, Encode, Decode)]
36pub struct Sa1Mmc {
37    pub bank_c_base_addr: u32,
38    pub bank_c_lorom_mapped: bool,
39    pub lorom_bank_c_addr: u32,
40    pub bank_d_base_addr: u32,
41    pub bank_d_lorom_mapped: bool,
42    pub lorom_bank_d_addr: u32,
43    pub bank_e_base_addr: u32,
44    pub bank_e_lorom_mapped: bool,
45    pub lorom_bank_e_addr: u32,
46    pub bank_f_base_addr: u32,
47    pub bank_f_lorom_mapped: bool,
48    pub lorom_bank_f_addr: u32,
49    pub snes_bwram_base_addr: u32,
50    pub sa1_bwram_base_addr: u32,
51    pub sa1_bwram_source: BwramMapSource,
52    pub bwram_bitmap_format: BwramBitmapBits,
53}
54
55impl Sa1Mmc {
56    pub fn new() -> Self {
57        Self {
58            bank_c_base_addr: DEFAULT_BANK_C_ADDR,
59            bank_c_lorom_mapped: false,
60            lorom_bank_c_addr: DEFAULT_BANK_C_ADDR,
61            bank_d_base_addr: DEFAULT_BANK_D_ADDR,
62            bank_d_lorom_mapped: false,
63            lorom_bank_d_addr: DEFAULT_BANK_D_ADDR,
64            bank_e_base_addr: DEFAULT_BANK_E_ADDR,
65            bank_e_lorom_mapped: false,
66            lorom_bank_e_addr: DEFAULT_BANK_E_ADDR,
67            bank_f_base_addr: DEFAULT_BANK_F_ADDR,
68            bank_f_lorom_mapped: false,
69            lorom_bank_f_addr: DEFAULT_BANK_F_ADDR,
70            snes_bwram_base_addr: 0,
71            sa1_bwram_base_addr: 0,
72            sa1_bwram_source: BwramMapSource::default(),
73            bwram_bitmap_format: BwramBitmapBits::default(),
74        }
75    }
76
77    pub fn map_rom_address(&self, address: u32) -> Option<u32> {
78        let bank = (address >> 16) & 0xFF;
79        let offset = address & 0xFFFF;
80        match (bank, offset) {
81            (0x00..=0x1F, 0x8000..=0xFFFF) => {
82                // LoROM bank C
83                Some(lorom_map_address(self.lorom_bank_c_addr, address))
84            }
85            (0x20..=0x3F, 0x8000..=0xFFFF) => {
86                // LoROM bank D
87                Some(lorom_map_address(self.lorom_bank_d_addr, address))
88            }
89            (0x80..=0x9F, 0x8000..=0xFFFF) => {
90                // LoROM bank E
91                Some(lorom_map_address(self.lorom_bank_e_addr, address))
92            }
93            (0xA0..=0xBF, 0x8000..=0xFFFF) => {
94                // LoROM bank F
95                Some(lorom_map_address(self.lorom_bank_f_addr, address))
96            }
97            (0xC0..=0xCF, _) => {
98                // HiROM bank C
99                Some(self.bank_c_base_addr | (address & 0xFFFFF))
100            }
101            (0xD0..=0xDF, _) => {
102                // HiROM bank D
103                Some(self.bank_d_base_addr | (address & 0xFFFFF))
104            }
105            (0xE0..=0xEF, _) => {
106                // HiROM bank E
107                Some(self.bank_e_base_addr | (address & 0xFFFFF))
108            }
109            (0xF0..=0xFF, _) => {
110                // HiROM bank F
111                Some(self.bank_f_base_addr | (address & 0xFFFFF))
112            }
113            _ => None,
114        }
115    }
116
117    pub fn write_cxb(&mut self, value: u8) {
118        self.bank_c_base_addr = u32::from(value & 0x07) << 20;
119        self.bank_c_lorom_mapped = value.bit(7);
120
121        self.lorom_bank_c_addr =
122            if self.bank_c_lorom_mapped { self.bank_c_base_addr } else { DEFAULT_BANK_C_ADDR };
123
124        log::trace!("  MMC bank C base address: {:06X}", self.bank_c_base_addr);
125        log::trace!("  MMC bank C LoROM mapped: {}", self.bank_c_lorom_mapped);
126    }
127
128    pub fn write_dxb(&mut self, value: u8) {
129        self.bank_d_base_addr = u32::from(value & 0x07) << 20;
130        self.bank_d_lorom_mapped = value.bit(7);
131
132        self.lorom_bank_d_addr =
133            if self.bank_d_lorom_mapped { self.bank_d_base_addr } else { DEFAULT_BANK_D_ADDR };
134
135        log::trace!("  MMC bank D base address: {:06X}", self.bank_d_base_addr);
136        log::trace!("  MMC bank D LoROM mapped: {}", self.bank_d_lorom_mapped);
137    }
138
139    pub fn write_exb(&mut self, value: u8) {
140        self.bank_e_base_addr = u32::from(value & 0x07) << 20;
141        self.bank_e_lorom_mapped = value.bit(7);
142
143        self.lorom_bank_e_addr =
144            if self.bank_e_lorom_mapped { self.bank_e_base_addr } else { DEFAULT_BANK_E_ADDR };
145
146        log::trace!("  MMC bank E base address: {:06X}", self.bank_e_base_addr);
147        log::trace!("  MMC bank E LoROM mapped: {}", self.bank_e_lorom_mapped);
148    }
149
150    pub fn write_fxb(&mut self, value: u8) {
151        self.bank_f_base_addr = u32::from(value & 0x07) << 20;
152        self.bank_f_lorom_mapped = value.bit(7);
153
154        self.lorom_bank_f_addr =
155            if self.bank_f_lorom_mapped { self.bank_f_base_addr } else { DEFAULT_BANK_F_ADDR };
156
157        log::trace!("  MMC bank F base address: {:06X}", self.bank_f_base_addr);
158        log::trace!("  MMC bank F LoROM mapped: {}", self.bank_f_lorom_mapped);
159    }
160
161    pub fn write_bmaps(&mut self, value: u8) {
162        self.snes_bwram_base_addr = u32::from(value & 0x1F) << 13;
163
164        log::trace!("  SNES BW-RAM base address: {:X}", self.snes_bwram_base_addr);
165    }
166
167    pub fn write_bmap(&mut self, value: u8) {
168        self.sa1_bwram_base_addr = u32::from(value & 0x7F) << 13;
169        self.sa1_bwram_source = BwramMapSource::from_bit(value.bit(7));
170
171        log::trace!("  SA-1 BW-RAM base address: {:X}", self.sa1_bwram_base_addr);
172        log::trace!("  SA-1 BW-RAM block source: {:?}", self.sa1_bwram_source);
173    }
174
175    pub fn write_bbf(&mut self, value: u8) {
176        self.bwram_bitmap_format = BwramBitmapBits::from_bit(value.bit(7));
177
178        log::trace!("  SA-1 BW-RAM bitmap format: {:?}", self.bwram_bitmap_format);
179    }
180}
181
182fn lorom_map_address(base_addr: u32, address: u32) -> u32 {
183    // A21-A23 come from MMC base address, but other than that this is standard LoROM mapping
184    // Ignore A15 and shift A16-A20 right by 1
185    base_addr | (address & 0x7FFF) | ((address & 0x1F0000) >> 1)
186}