bus.rsannotatedbus.rssource325 lines · 11.1 KB · raw

SNES memory mapping and bus interface code

3use crate::api::LatchedInterrupts;
4use crate::apu::Apu;
5use crate::memory::{CpuInternalRegisters, Memory, Memory2Speed};
6use crate::ppu::Ppu;
7use wdc65816_emu::core::Wdc65816;
8use wdc65816_emu::traits::BusInterface;

Accesses to address bus B (PPU/APU/WRAM ports) and internal CPU registers are "fast" (no waitstates) Accesses to the cartridge in the higher banks can also be fast depending on register $420D

12const FAST_MASTER_CYCLES: u64 = 6;

Accesses to WRAM and the cartridge are "slow" (+2 master cycles)

15const SLOW_MASTER_CYCLES: u64 = 8;

Accesses to the manual joypad read ports are "extra slow" (+6 master cycles)

18const XSLOW_MASTER_CYCLES: u64 = 12;
20impl Memory2Speed {
21    fn master_cycles(self) -> u64 {
22        match self {
23            Self::Fast => FAST_MASTER_CYCLES,
24            Self::Slow => SLOW_MASTER_CYCLES,
25        }
26    }
27}
28
29pub struct Bus<'a> {
30    pub memory: &'a mut Memory,
31    pub cpu_registers: &'a mut CpuInternalRegisters,
32    pub ppu: &'a mut Ppu,
33    pub apu: &'a mut Apu,
34    pub latched_interrupts: Option<LatchedInterrupts>,
35    pub access_master_cycles: u64,
36    pub pending_write: Option<(u32, u8)>,
37}
38
39impl Bus<'_> {
40    fn read_system_area(&mut self, full_address: u32) -> u8 {
41        let address = full_address & 0x7FFF;
42        match address {
43            0x0000..=0x1FFF => {
44                self.access_master_cycles = SLOW_MASTER_CYCLES;
45
46                // First 8KB of WRAM
47                self.memory.read_wram(address)
48            }
49            0x2100..=0x213F => {
50                self.access_master_cycles = FAST_MASTER_CYCLES;
51
52                // PPU ports
53                self.ppu.read_port(address).unwrap_or(self.memory.cpu_open_bus())
54            }
55            0x2140..=0x217F => {
56                self.access_master_cycles = FAST_MASTER_CYCLES;
57
58                // APU ports
59                self.apu.read_port(address)
60            }
61            0x2180 => {
62                self.access_master_cycles = FAST_MASTER_CYCLES;
63
64                // WMDATA: WRAM port in address bus B
65                self.memory.read_wram_port()
66            }
67            0x4000..=0x41FF => {
68                self.access_master_cycles = XSLOW_MASTER_CYCLES;
69
70                // $4016 and $4017 are CPU I/O ports (manual joypad ports)
71                // The rest of this range is CPU open bus with XSlow memory speed
72                let cpu_open_bus = self.memory.cpu_open_bus();
73                self.cpu_registers.read_register(address, cpu_open_bus).unwrap_or_else(|| {
74                    self.memory.read_cartridge(full_address).unwrap_or(cpu_open_bus)
75                })
76            }
77            0x4200..=0x5FFF => {
78                self.access_master_cycles = FAST_MASTER_CYCLES;
79
80                // CPU I/O ports (everything except manual joypad ports)
81                // $4220-$42FF and $4380-$5FFF are CPU open bus with Fast memory speed
82                let cpu_open_bus = self.memory.cpu_open_bus();
83                self.cpu_registers.read_register(address, cpu_open_bus).unwrap_or_else(|| {
84                    self.memory.read_cartridge(full_address).unwrap_or(cpu_open_bus)
85                })
86            }
87            0x2000..=0x20FF | 0x2181..=0x3FFF => {
88                self.access_master_cycles = FAST_MASTER_CYCLES;
89
90                // Open bus with Fast memory speed
91                // Send to the cartridge first because some cartridges respond to these addresses
92                self.memory.read_cartridge(full_address).unwrap_or(self.memory.cpu_open_bus())
93            }
94            0x6000..=0x7FFF => {
95                self.access_master_cycles = SLOW_MASTER_CYCLES;
96
97                // Open bus with Slow memory speed
98                // Send to the cartridge first because some cartridges respond to these addresses
99                self.memory.read_cartridge(full_address).unwrap_or(self.memory.cpu_open_bus())
100            }
101            _ => panic!("invalid system area address: {full_address:06X}"),
102        }
103    }
104
105    fn write_system_area(&mut self, full_address: u32, value: u8) {
106        let address = full_address & 0x7FFF;
107        match address {
108            0x0000..=0x1FFF => {
109                // First 8KB of WRAM
110                self.memory.write_wram(address, value);
111            }
112            0x2000..=0x20FF | 0x2184..=0x21FF => {
113                // $2000-$2FFF: Open bus; do nothing (no coprocessors use this range)
114                // $2184-$21FF: Open bus in address bus B; do nothing
115            }
116            0x2100..=0x213F => {
117                // PPU ports
118                self.ppu.write_port(address, value);
119            }
120            0x2140..=0x217F => {
121                // APU ports
122                self.apu.write_port(address, value);
123            }
124            0x2180 => {
125                // WMDATA: WRAM port in address bus B
126                self.memory.write_wram_port(value);
127            }
128            0x2181 => {
129                // WMADDL: WRAM port address, low byte
130                self.memory.write_wram_port_address_low(value);
131            }
132            0x2182 => {
133                // WMADDM: WRAM port address, middle byte
134                self.memory.write_wram_port_address_mid(value);
135            }
136            0x2183 => {
137                // WMADDH: WRAM port address, high byte
138                self.memory.write_wram_port_address_high(value);
139            }
140            0x2200..=0x3FFF | 0x4400..=0x7FFF => {
141                // $2200-$3FFF: Normally open bus; some coprocessors map I/O ports or RAM to this range
142                // $4400-$5FFF: Normally open bus; some coprocessors map I/O ports to this range
143                // $6000-$7FFF: Cartridge expansion; some cartridges map RAM to this range
144                self.memory.write_cartridge(full_address, value);
145            }
146            0x4000..=0x41FF => {
147                // CPU I/O ports (manual joypad ports)
148                self.cpu_registers.write_register(address, value);
149            }
150            0x4200..=0x43FF => {
151                // CPU I/O ports (everything except manual joypad ports)
152                self.cpu_registers.write_register(address, value);
153            }
154            _ => unreachable!("value & 0x7FFF is always <= 0x7FFF"),
155        }
156    }
157
158    pub fn apply_write(&mut self, address: u32, value: u8) {
159        log::trace!("Bus write {address:06X} {value:02X}");
160
161        let bank = (address >> 16) as u8;
162        let offset = address as u16;
163        match (bank, offset) {
164            (0x00..=0x3F | 0x80..=0xBF, 0x0000..=0x7FFF) => {
165                // System area
166                self.write_system_area(address, value);
167            }
168            (0x00..=0x3F | 0x80..=0xBF, 0x8000..=0xFFFF) | (0x40..=0x7D | 0xC0..=0xFF, _) => {
169                // Cartridge
170                self.memory.write_cartridge(address, value);
171            }
172            (0x7E..=0x7F, _) => {
173                // WRAM
174                self.memory.write_wram(address, value);
175            }
176        }
177    }
178}
179
180impl BusInterface for Bus<'_> {
181    #[inline]
182    fn read(&mut self, address: u32) -> u8 {
183        log::trace!("Bus read {address:06X}");
184
185        let bank = (address >> 16) as u8;
186        let offset = address as u16;
187        match (bank, offset) {
188            (0x00..=0x3F | 0x80..=0xBF, 0x0000..=0x7FFF) => {
189                // System area
190                self.read_system_area(address)
191            }
192            (0x00..=0x3F, 0x8000..=0xFFFF) | (0x40..=0x7D, _) => {
193                self.access_master_cycles = SLOW_MASTER_CYCLES;
194
195                // Cartridge (Memory-1)
196                self.memory.read_cartridge(address).unwrap_or(self.memory.cpu_open_bus())
197            }
198            (0x80..=0xBF, 0x8000..=0xFFFF) | (0xC0..=0xFF, _) => {
199                self.access_master_cycles = self.cpu_registers.memory_2_speed().master_cycles();
200
201                // Cartridge (Memory-2)
202                self.memory.read_cartridge(address).unwrap_or(self.memory.cpu_open_bus())
203            }
204            (0x7E..=0x7F, _) => {
205                self.access_master_cycles = SLOW_MASTER_CYCLES;
206
207                // WRAM
208                self.memory.read_wram(address)
209            }
210        }
211    }
212
213    #[inline]
214    fn write(&mut self, address: u32, value: u8) {
215        self.pending_write = Some((address, value));
216
217        let bank = (address >> 16) as u8;
218        let offset = address as u16;
219        self.access_master_cycles =
220            address_master_cycles(self.cpu_registers.memory_2_speed(), bank, offset);
221    }
222
223    #[inline]
224    fn idle(&mut self) {
225        self.access_master_cycles = FAST_MASTER_CYCLES;
226    }
227
228    #[inline]
229    fn nmi(&self) -> bool {
230        self.latched_interrupts.map_or(self.cpu_registers.nmi_pending(), |latched| latched.nmi)
231    }
232
233    #[inline]
234    fn acknowledge_nmi(&mut self) {
235        self.cpu_registers.acknowledge_nmi();
236    }
237
238    #[inline]
239    fn irq(&self) -> bool {
240        self.latched_interrupts
241            .map_or(self.cpu_registers.irq_pending() || self.memory.cartridge_irq(), |latched| {
242                latched.irq
243            })
244    }
245
246    #[inline]
247    fn halt(&self) -> bool {
248        false
249    }
250
251    #[inline]
252    fn reset(&self) -> bool {
253        false
254    }
255}
256
257#[inline]
258fn address_master_cycles(memory_2_speed: Memory2Speed, bank: u8, offset: u16) -> u64 {
259    match (bank, offset) {
260        (0x00..=0x3F | 0x80..=0xBF, 0x2000..=0x3FFF | 0x4200..=0x5FFF) => FAST_MASTER_CYCLES,
261        (0x00..=0x3F | 0x80..=0xBF, 0x0000..=0x1FFF | 0x6000..=0x7FFF)
262        | (0x00..=0x3F, 0x8000..=0xFFFF)
263        | (0x40..=0x7F, _) => SLOW_MASTER_CYCLES,
264        (0x00..=0x3F | 0x80..=0xBF, 0x4000..=0x41FF) => XSLOW_MASTER_CYCLES,
265        (0x80..=0xBF, 0x8000..=0xFFFF) | (0xC0..=0xFF, _) => memory_2_speed.master_cycles(),
266    }
267}
268
269pub fn next_cpu_cycle_mclk(cpu: &Wdc65816) -> impl Fn(&Bus<'_>) -> u64 + Copy {
270    struct CapturingBus<'a, 'b>(&'a Bus<'b>, u64);
271
272    impl BusInterface for CapturingBus<'_, '_> {
273        #[inline]
274        fn read(&mut self, address: u32) -> u8 {
275            let bank = (address >> 16) as u8;
276            let offset = address as u16;
277            self.1 = address_master_cycles(self.0.cpu_registers.memory_2_speed(), bank, offset);
278
279            0
280        }
281
282        #[inline]
283        fn write(&mut self, address: u32, _value: u8) {
284            let bank = (address >> 16) as u8;
285            let offset = address as u16;
286            self.1 = address_master_cycles(self.0.cpu_registers.memory_2_speed(), bank, offset);
287        }
288
289        #[inline]
290        fn idle(&mut self) {}
291
292        #[inline]
293        fn nmi(&self) -> bool {
294            self.0.nmi()
295        }
296
297        #[inline]
298        fn acknowledge_nmi(&mut self) {}
299
300        #[inline]
301        fn irq(&self) -> bool {
302            self.0.irq()
303        }
304
305        #[inline]
306        fn halt(&self) -> bool {
307            self.0.halt()
308        }
309
310        #[inline]
311        fn reset(&self) -> bool {
312            self.0.reset()
313        }
314    }
315
316    // Determine the number of mclk cycles for the next CPU cycle by cloning all CPU state and
317    // letting the clone execute 1 cycle against a fake bus implementation that just records which
318    // address was accessed (if any).
319    |bus| {
320        let mut cpu = cpu.clone();
321        let mut bus = CapturingBus(bus, FAST_MASTER_CYCLES);
322        cpu.tick(&mut bus);
323        bus.1
324    }
325}