bus.rsannotatedbus.rssource303 lines · 11.9 KB · raw
1use crate::sa1::mmc::{BwramBitmapBits, BwramMapSource, Sa1Mmc};
2use crate::sa1::registers::{InterruptVectorSource, Sa1Registers};
3use crate::sa1::timer::Sa1Timer;
4use crate::sa1::{Iram, Sa1};
5use jgenesis_common::num::U16Ext;
6use wdc65816_emu::traits::BusInterface;
7
8impl Sa1 {
9    pub fn snes_read(&mut self, address: u32) -> Option<u8> {
10        let bank = (address >> 16) & 0xFF;
11        let offset = address & 0xFFFF;
12        match (bank, offset) {
13            (0x00..=0x3F | 0x80..=0xBF, 0x8000..=0xFFFF) | (0xC0..=0xFF, _) => {
14                // ROM
15
16                // Check for NMI/IRQ vector reads first
17                let nmi_vector_source = self.registers.snes_nmi_vector_source;
18                let irq_vector_source = self.registers.snes_irq_vector_source;
19                match (bank, offset) {
20                    (0x00, 0xFFEA) if nmi_vector_source == InterruptVectorSource::IoPorts => {
21                        Some(self.registers.snes_nmi_vector.lsb())
22                    }
23                    (0x00, 0xFFEB) if nmi_vector_source == InterruptVectorSource::IoPorts => {
24                        Some(self.registers.snes_nmi_vector.msb())
25                    }
26                    (0x00, 0xFFEE) if irq_vector_source == InterruptVectorSource::IoPorts => {
27                        Some(self.registers.snes_irq_vector.lsb())
28                    }
29                    (0x00, 0xFFEF) if irq_vector_source == InterruptVectorSource::IoPorts => {
30                        Some(self.registers.snes_irq_vector.msb())
31                    }
32                    _ => self
33                        .mmc
34                        .map_rom_address(address)
35                        .and_then(|rom_addr| self.rom.get(rom_addr as usize).copied()),
36                }
37            }
38            (0x00..=0x3F | 0x80..=0xBF, 0x2300..=0x230F) => {
39                // SA-1 internal registers
40                self.registers.snes_read(address)
41            }
42            (0x00..=0x3F | 0x80..=0xBF, 0x3000..=0x37FF) => {
43                // I-RAM
44                Some(self.iram[(address & 0x7FF) as usize])
45            }
46            (0x00..=0x3F | 0x80..=0xBF, 0x6000..=0x7FFF) => {
47                // BW-RAM 8KB block
48                let bwram_addr = (self.mmc.snes_bwram_base_addr | (address & 0x1FFF))
49                    & (self.bwram.len() as u32 - 1);
50                Some(self.bwram[bwram_addr as usize])
51            }
52            (0x40..=0x4F, _) => {
53                // BW-RAM in full
54                // If character conversion DMA type 1 is in progress, ignore the address and return
55                // the next CCDMA byte
56                if self.registers.ccdma_transfer_in_progress {
57                    Some(self.registers.next_ccdma_byte(&mut self.iram, &self.bwram))
58                } else {
59                    let bwram_addr = (address as usize) & (self.bwram.len() - 1);
60                    Some(self.bwram[bwram_addr])
61                }
62            }
63            _ => None,
64        }
65    }
66
67    pub fn snes_write(&mut self, address: u32, value: u8) {
68        let bank = (address >> 16) & 0xFF;
69        let offset = address & 0xFFFF;
70        match (bank, offset) {
71            (0x00..=0x3F | 0x80..=0xBF, 0x2200..=0x22FF) => {
72                // SA-1 internal registers
73                self.registers.snes_write(address, value, &mut self.mmc);
74            }
75            (0x00..=0x3F | 0x80..=0xBF, 0x3000..=0x37FF) => {
76                // I-RAM
77                let iram_addr = address & 0x7FF;
78                let write_protect_idx = iram_addr >> 8;
79                if self.registers.snes_iram_writes_enabled[write_protect_idx as usize] {
80                    self.iram[iram_addr as usize] = value;
81                }
82            }
83            (0x00..=0x3F | 0x80..=0xBF, 0x6000..=0x7FFF) => {
84                // BW-RAM 8KB block
85                let bwram_addr = (self.mmc.snes_bwram_base_addr | (address & 0x1FFF))
86                    & (self.bwram.len() as u32 - 1);
87                if self.registers.can_write_bwram(bwram_addr) {
88                    self.bwram[bwram_addr as usize] = value;
89                }
90            }
91            (0x40..=0x4F, _) => {
92                // BW-RAM in full
93                let bwram_addr = (address as usize) & (self.bwram.len() - 1);
94                if self.registers.can_write_bwram(bwram_addr as u32) {
95                    self.bwram[bwram_addr] = value;
96                }
97            }
98            _ => {}
99        }
100    }
101}
102
103pub struct Sa1Bus<'a> {
104    pub rom: &'a [u8],
105    pub iram: &'a mut Iram,
106    pub bwram: &'a mut [u8],
107    pub mmc: &'a mut Sa1Mmc,
108    pub registers: &'a mut Sa1Registers,
109    pub timer: &'a mut Sa1Timer,
110    pub bwram_wait_cycles: u64,
111}
112
113impl BusInterface for Sa1Bus<'_> {
114    #[inline]
115    fn read(&mut self, address: u32) -> u8 {
116        let bank = (address >> 16) & 0xFF;
117        let offset = address & 0xFFFF;
118        match (bank, offset) {
119            (0x00..=0x3F | 0x80..=0xBF, 0x8000..=0xFFFF) | (0xC0..=0xFF, _) => {
120                // ROM
121
122                // Check for NMI/IRQ/RESET vector reads first
123                match (bank, offset) {
124                    (0x00, 0xFFEA) => self.registers.sa1_nmi_vector.lsb(),
125                    (0x00, 0xFFEB) => self.registers.sa1_nmi_vector.msb(),
126                    (0x00, 0xFFEE) => self.registers.sa1_irq_vector.lsb(),
127                    (0x00, 0xFFEF) => self.registers.sa1_irq_vector.msb(),
128                    (0x00, 0xFFFC) => self.registers.sa1_reset_vector.lsb(),
129                    (0x00, 0xFFFD) => self.registers.sa1_reset_vector.msb(),
130                    _ => self
131                        .mmc
132                        .map_rom_address(address)
133                        .and_then(|rom_addr| self.rom.get(rom_addr as usize).copied())
134                        .unwrap_or(0),
135                }
136            }
137            (0x00..=0x3F | 0x80..=0xBF, 0x2300..=0x230F) => {
138                // SA-1 internal registers
139                self.registers.sa1_read(address, self.timer)
140            }
141            (0x00..=0x3F | 0x80..=0xBF, 0x0000..=0x07FF | 0x3000..=0x37FF) => {
142                // I-RAM (mapped to both $0000-$07FF and $3000-$37FF for SA-1 CPU)
143                self.iram[(address & 0x7FF) as usize]
144            }
145            (0x00..=0x3F | 0x80..=0xBF, 0x6000..=0x7FFF) => {
146                // BW-RAM 8KB block
147                self.bwram_wait_cycles += 1;
148
149                match self.mmc.sa1_bwram_source {
150                    BwramMapSource::Normal => {
151                        let bwram_addr = ((self.mmc.sa1_bwram_base_addr & 0x3E000)
152                            | (address & 0x01FFF))
153                            & (self.bwram.len() as u32 - 1);
154                        self.bwram[bwram_addr as usize]
155                    }
156                    BwramMapSource::Bitmap => {
157                        let bitmap_addr = self.mmc.sa1_bwram_base_addr | (address & 0x1FFF);
158                        read_bwram_bitmap(bitmap_addr, self.mmc, self.bwram)
159                    }
160                }
161            }
162            (0x40..=0x4F, _) => {
163                // BW-RAM in full
164                self.bwram_wait_cycles += 1;
165
166                let bwram_addr = (address as usize) & (self.bwram.len() - 1);
167                self.bwram[bwram_addr]
168            }
169            (0x60..=0x6F, _) => {
170                // BW-RAM bitmap view
171                self.bwram_wait_cycles += 1;
172
173                read_bwram_bitmap(address, self.mmc, self.bwram)
174            }
175            _ => 0,
176        }
177    }
178
179    #[inline]
180    fn write(&mut self, address: u32, value: u8) {
181        let bank = (address >> 16) & 0xFF;
182        let offset = address & 0xFFFF;
183        match (bank, offset) {
184            (0x00..=0x3F | 0x80..=0xBF, 0x2200..=0x22FF) => {
185                // SA-1 internal registers
186                self.registers.sa1_write(address, value, self.timer, self.mmc, self.rom, self.iram);
187            }
188            (0x00..=0x3F | 0x80..=0xBF, 0x0000..=0x07FF | 0x3000..=0x37FF) => {
189                // I-RAM (mapped to both $0000-$07FF and $3000-$37FF for SA-1 CPU)
190                let iram_addr = address & 0x7FF;
191                let write_protect_idx = iram_addr >> 8;
192                if self.registers.sa1_iram_writes_enabled[write_protect_idx as usize] {
193                    self.iram[iram_addr as usize] = value;
194                }
195            }
196            (0x00..=0x3F | 0x80..=0xBF, 0x6000..=0x7FFF) => {
197                // BW-RAM 8KB block
198                self.bwram_wait_cycles += 1;
199
200                match self.mmc.sa1_bwram_source {
201                    BwramMapSource::Normal => {
202                        let bwram_addr = ((self.mmc.sa1_bwram_base_addr & 0x3E000)
203                            | (address & 0x01FFF))
204                            & (self.bwram.len() as u32 - 1);
205                        if self.registers.can_write_bwram(bwram_addr) {
206                            self.bwram[bwram_addr as usize] = value;
207                        }
208                    }
209                    BwramMapSource::Bitmap => {
210                        let bitmap_addr = self.mmc.sa1_bwram_base_addr | (address & 0x1FFF);
211                        write_bwram_bitmap(bitmap_addr, value, self.mmc, self.bwram);
212                    }
213                }
214            }
215            (0x40..=0x4F, _) => {
216                // BW-RAM in full (256KB max, mirrored every 4 banks)
217                self.bwram_wait_cycles += 1;
218
219                let bwram_addr = (address as usize) & (self.bwram.len() - 1);
220                if self.registers.can_write_bwram(bwram_addr as u32) {
221                    self.bwram[bwram_addr] = value;
222                }
223            }
224            (0x60..=0x6F, _) => {
225                // BW-RAM bitmap view
226                self.bwram_wait_cycles += 1;
227
228                write_bwram_bitmap(address, value, self.mmc, self.bwram);
229            }
230            _ => {}
231        }
232    }
233
234    #[inline]
235    fn idle(&mut self) {}
236
237    #[inline]
238    fn nmi(&self) -> bool {
239        self.registers.sa1_nmi_enabled && self.registers.sa1_nmi
240    }
241
242    #[inline]
243    fn acknowledge_nmi(&mut self) {}
244
245    #[inline]
246    fn irq(&self) -> bool {
247        (self.registers.sa1_irq_from_snes_enabled && self.registers.sa1_irq_from_snes)
248            || (self.registers.timer_irq_enabled && self.timer.irq_pending)
249            || (self.registers.dma_irq_enabled && self.registers.sa1_dma_irq)
250    }
251
252    #[inline]
253    fn halt(&self) -> bool {
254        self.registers.sa1_wait
255    }
256
257    #[inline]
258    fn reset(&self) -> bool {
259        self.registers.sa1_reset
260    }
261}
262
263fn read_bwram_bitmap(address: u32, mmc: &Sa1Mmc, bwram: &[u8]) -> u8 {
264    match mmc.bwram_bitmap_format {
265        BwramBitmapBits::Two => {
266            let address = address & 0xFFFFF;
267            let bwram_addr = (address >> 2) & (bwram.len() as u32 - 1);
268            let bwram_shift = 2 * (address & 0x03);
269
270            (bwram[bwram_addr as usize] >> bwram_shift) & 0x03
271        }
272        BwramBitmapBits::Four => {
273            let address = address & 0x7FFFF;
274            let bwram_addr = (address >> 1) & (bwram.len() as u32 - 1);
275            let bwram_shift = 4 * (address & 0x01);
276
277            (bwram[bwram_addr as usize] >> bwram_shift) & 0x0F
278        }
279    }
280}
281
282fn write_bwram_bitmap(address: u32, value: u8, mmc: &Sa1Mmc, bwram: &mut [u8]) {
283    match mmc.bwram_bitmap_format {
284        BwramBitmapBits::Two => {
285            let address = address & 0xFFFFF;
286            let bwram_addr = (address >> 2) & (bwram.len() as u32 - 1);
287            let shift = 2 * (address & 0x03);
288
289            let existing_value = bwram[bwram_addr as usize];
290            let new_value = (existing_value & !(0x03 << shift)) | ((value & 0x03) << shift);
291            bwram[bwram_addr as usize] = new_value;
292        }
293        BwramBitmapBits::Four => {
294            let address = address & 0x7FFFF;
295            let bwram_addr = (address >> 1) & (bwram.len() as u32 - 1);
296            let shift = 4 * (address & 0x01);
297
298            let existing_value = bwram[bwram_addr as usize];
299            let new_value = (existing_value & !(0x0F << shift)) | ((value & 0x0F) << shift);
300            bwram[bwram_addr as usize] = new_value;
301        }
302    }
303}