bus.rsannotatedbus.rssource1337 lines · 42.2 KB · raw

Code for emulating the bus, and more generally the NES CPU and PPU address spaces.

The NES does not have a unified bus; it has two buses, a 16-bit CPU bus and a 14-bit PPU bus. The CPU can only access the PPU bus through memory-mapped I/O.

CPU address mapping:

  • $0000-$07FF: 2KB internal RAM
  • $0800-$1FFF: Mirrors of internal RAM
  • $2000-$2007: Memory-mapped PPU registers
  • $2008-$3FFF: Mirrors of memory-mapped PPU registers
  • $4000-$4017: Memory-mapped APU and I/O registers
  • $4018-$401F: "Test mode" functionality that is not emulated here
  • $4020-$FFFF: Mapped to the cartridge board

Most cartridge boards map $6000-$7FFF to PRG RAM (if present) and $8000-$FFFF to PRG ROM. Writes to $8000-$FFFF are often mapped to internal cartridge board registers.

PPU address mapping:

  • $0000-$3EFF: Mapped to the cartridge board
  • $3F00-$3F1F: 32 bytes of internal palette RAM
  • $3F20-$3FFF: Mirrors of palette RAM

While almost the entire PPU address space is controlled by the cartridge board, the PPU does expect specific address ranges to hold specific data:

  • $0000-$1FFF: Pattern tables (2x4KB) holding tile data
  • $2000-$2FFF: Nametables (4x1KB) holding background tile maps and background tile attributes
  • $3000-$3EFF: Mirrors of the nametables (not directly used by the PPU but the CPU can read/write here through memory-mapped I/O)

Most cartridge boards contain CHR ROM or CHR RAM that is mapped into $0000-$1FFF for the pattern tables.

The PPU has 2KB of internal VRAM that the cartridge board is free to map into the PPU address space however it wishes. Most boards use this VRAM for nametable data, mapping it into $2000-$2FFF (with some ranges mirrored).

36pub mod cartridge;
38use crate::api::NesEmulatorConfig;
39use crate::apu::ApuState;
40use crate::bus::cartridge::Mapper;
41use crate::graphics::TimingModeGraphicsExt;
42use crate::input::{LatchedJoypadState, NesInputDevice, NesJoypadStateExt, ZapperState};
43use bincode::{Decode, Encode};
44use jgenesis_common::frontend::TimingMode;
45use jgenesis_common::num::GetBit;
46use jgenesis_proc_macros::PartialClone;
47use mos6502_emu::bus::BusInterface;
48use nes_config::{NesJoypadState, Overscan};
49use std::array;
50
51pub const CPU_RAM_START: u16 = 0x0000;
52pub const CPU_RAM_END: u16 = 0x1FFF;
53pub const CPU_RAM_MASK: u16 = 0x07FF;
54
55pub const CPU_PPU_REGISTERS_START: u16 = 0x2000;
56pub const CPU_PPU_REGISTERS_END: u16 = 0x3FFF;
57pub const CPU_PPU_REGISTERS_MASK: u16 = 0x0007;
58
59pub const CPU_IO_REGISTERS_START: u16 = 0x4000;
60pub const CPU_IO_REGISTERS_END: u16 = 0x4017;
61
62pub const CPU_IO_TEST_MODE_START: u16 = 0x4018;
63pub const CPU_IO_TEST_MODE_END: u16 = 0x401F;
64
65pub const CPU_CARTRIDGE_START: u16 = 0x4020;
66pub const CPU_CARTRIDGE_END: u16 = 0xFFFF;
67
68pub const PALETTE_RAM_MASK: u16 = 0x001F;
69
70#[derive(Debug, Clone, Copy, Default, Encode, Decode)]
71struct PendingCpuWrite {
72    address: u16,
73    value: u8,
74}
75
76#[allow(clippy::upper_case_acronyms)]
77#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78pub enum PpuRegister {
79    PPUCTRL,
80    PPUMASK,
81    PPUSTATUS,
82    OAMADDR,
83    OAMDATA,
84    PPUSCROLL,
85    PPUADDR,
86    PPUDATA,
87}
88
89impl PpuRegister {
90    fn from_relative_address(relative_addr: usize) -> Option<Self> {
91        match relative_addr {
92            0x00 => Some(Self::PPUCTRL),
93            0x01 => Some(Self::PPUMASK),
94            0x02 => Some(Self::PPUSTATUS),
95            0x03 => Some(Self::OAMADDR),
96            0x04 => Some(Self::OAMDATA),
97            0x05 => Some(Self::PPUSCROLL),
98            0x06 => Some(Self::PPUADDR),
99            0x07 => Some(Self::PPUDATA),
100            _ => None,
101        }
102    }
103
104    pub const fn to_address(self) -> u16 {
105        match self {
106            Self::PPUCTRL => 0x2000,
107            Self::PPUMASK => 0x2001,
108            Self::PPUSTATUS => 0x2002,
109            Self::OAMADDR => 0x2003,
110            Self::OAMDATA => 0x2004,
111            Self::PPUSCROLL => 0x2005,
112            Self::PPUADDR => 0x2006,
113            Self::PPUDATA => 0x2007,
114        }
115    }
116}
117
118#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)]
119pub enum PpuWriteToggle {
120    First,
121    Second,
122}
123
124impl PpuWriteToggle {
125    fn toggle(self) -> Self {
126        match self {
127            Self::First => Self::Second,
128            Self::Second => Self::First,
129        }
130    }
131}
132
133#[allow(clippy::upper_case_acronyms)]
134#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)]
135pub enum PpuTrackedRegister {
136    PPUCTRL,
137    PPUSCROLL,
138    PPUADDR,
139    PPUDATA,
140}
141
142#[derive(Debug, Clone, Encode, Decode)]
143pub struct PpuRegisters {
144    ppu_ctrl: u8,
145    ppu_mask: u8,
146    ppu_status: u8,
147    oam_addr: u8,
148    ppu_data_buffer: u8,
149    ppu_status_read: bool,
150    ppu_open_bus: u8,
151    ppu_open_bus_decay_cycles: [u64; 8],
152    total_cycles: u64,
153    oam_open_bus_value: Option<u8>,
154    last_accessed_register: Option<PpuTrackedRegister>,
155    write_toggle: PpuWriteToggle,
156    reset_flag: bool,
157}
158
159impl PpuRegisters {
160    pub fn new() -> Self {
161        Self {
162            ppu_ctrl: 0,
163            ppu_mask: 0,
164            ppu_status: 0xA0,
165            oam_addr: 0,
166            ppu_data_buffer: 0,
167            ppu_status_read: false,
168            ppu_open_bus: 0,
169            ppu_open_bus_decay_cycles: [0; 8],
170            total_cycles: 0,
171            oam_open_bus_value: None,
172            last_accessed_register: None,
173            write_toggle: PpuWriteToggle::First,
174            reset_flag: false,
175        }
176    }
177
178    pub fn ppu_ctrl(&self) -> u8 {
179        self.ppu_ctrl
180    }
181
182    pub fn nmi_enabled(&self) -> bool {
183        self.ppu_ctrl.bit(7)
184    }
185
186    pub fn double_height_sprites(&self) -> bool {
187        self.ppu_ctrl.bit(5)
188    }
189
190    pub fn bg_pattern_table_address(&self) -> u16 {
191        if self.ppu_ctrl.bit(4) { 0x1000 } else { 0x0000 }
192    }
193
194    pub fn sprite_pattern_table_address(&self) -> u16 {
195        if self.ppu_ctrl.bit(3) { 0x1000 } else { 0x0000 }
196    }
197
198    pub fn ppu_data_addr_increment(&self) -> u16 {
199        if self.ppu_ctrl.bit(2) { 32 } else { 1 }
200    }
201
202    pub fn emphasize_blue(&self) -> bool {
203        self.ppu_mask.bit(7)
204    }
205
206    pub fn emphasize_green(&self, timing_mode: TimingMode) -> bool {
207        match timing_mode {
208            TimingMode::Ntsc => self.ppu_mask.bit(6),
209            TimingMode::Pal => self.ppu_mask.bit(5),
210        }
211    }
212
213    pub fn emphasize_red(&self, timing_mode: TimingMode) -> bool {
214        match timing_mode {
215            TimingMode::Ntsc => self.ppu_mask.bit(5),
216            TimingMode::Pal => self.ppu_mask.bit(6),
217        }
218    }
219
220    pub fn greyscale(&self) -> bool {
221        self.ppu_mask.bit(0)
222    }
223
224    pub fn sprites_enabled(&self) -> bool {
225        self.ppu_mask.bit(4)
226    }
227
228    pub fn bg_enabled(&self) -> bool {
229        self.ppu_mask.bit(3)
230    }
231
232    pub fn left_edge_sprites_enabled(&self) -> bool {
233        self.ppu_mask.bit(2)
234    }
235
236    pub fn left_edge_bg_enabled(&self) -> bool {
237        self.ppu_mask.bit(1)
238    }
239
240    pub fn vblank_flag(&self) -> bool {
241        self.ppu_status.bit(7)
242    }
243
244    pub fn set_vblank_flag(&mut self, vblank: bool) {
245        if vblank {
246            self.ppu_status |= 1 << 7;
247        } else {
248            self.ppu_status &= !(1 << 7);
249        }
250    }
251
252    pub fn set_sprite_0_hit(&mut self, sprite_0_hit: bool) {
253        if sprite_0_hit {
254            self.ppu_status |= 1 << 6;
255        } else {
256            self.ppu_status &= !(1 << 6);
257        }
258    }
259
260    pub fn set_sprite_overflow(&mut self, sprite_overflow: bool) {
261        if sprite_overflow {
262            self.ppu_status |= 1 << 5;
263        } else {
264            self.ppu_status &= !(1 << 5);
265        }
266    }
267
268    pub fn clear_reset_flag(&mut self) {
269        self.reset_flag = false;
270    }
271
272    pub fn take_last_accessed_register(&mut self) -> Option<PpuTrackedRegister> {
273        self.last_accessed_register.take()
274    }
275
276    pub fn get_ppu_open_bus_value(&self) -> u8 {
277        self.ppu_open_bus
278    }
279
280    pub fn set_oam_addr(&mut self, oam_addr: u8) {
281        self.oam_addr = oam_addr;
282    }
283
284    pub fn set_oam_open_bus(&mut self, value: Option<u8>) {
285        self.oam_open_bus_value = value;
286    }
287
288    pub fn get_write_toggle(&self) -> PpuWriteToggle {
289        self.write_toggle
290    }
291
292    fn tick(&mut self, interrupt_lines: &mut InterruptLines) {
293        if self.ppu_status_read {
294            self.ppu_status_read = false;
295
296            self.set_vblank_flag(false);
297            self.write_toggle = PpuWriteToggle::First;
298        }
299
300        let nmi_line = if self.vblank_flag() && self.nmi_enabled() {
301            InterruptLine::Low
302        } else {
303            InterruptLine::High
304        };
305        interrupt_lines.ppu_set_nmi_line(nmi_line);
306    }
307}
308
309#[allow(clippy::upper_case_acronyms)]
310#[allow(non_camel_case_types)]
311#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)]
312pub enum IoRegister {
313    #[default]
314    SQ1_VOL,
315    SQ1_SWEEP,
316    SQ1_LO,
317    SQ1_HI,
318    SQ2_VOL,
319    SQ2_SWEEP,
320    SQ2_LO,
321    SQ2_HI,
322    TRI_LINEAR,
323    TRI_LO,
324    TRI_HI,
325    NOISE_VOL,
326    NOISE_LO,
327    NOISE_HI,
328    DMC_FREQ,
329    DMC_RAW,
330    DMC_START,
331    DMC_LEN,
332    OAMDMA,
333    SND_CHN,
334    JOY1,
335    JOY2,
336}
337
338impl IoRegister {
339    const fn to_relative_address(self) -> usize {
340        match self {
341            Self::SQ1_VOL => 0x00,
342            Self::SQ1_SWEEP => 0x01,
343            Self::SQ1_LO => 0x02,
344            Self::SQ1_HI => 0x03,
345            Self::SQ2_VOL => 0x04,
346            Self::SQ2_SWEEP => 0x05,
347            Self::SQ2_LO => 0x06,
348            Self::SQ2_HI => 0x07,
349            Self::TRI_LINEAR => 0x08,
350            Self::TRI_LO => 0x0A,
351            Self::TRI_HI => 0x0B,
352            Self::NOISE_VOL => 0x0C,
353            Self::NOISE_LO => 0x0E,
354            Self::NOISE_HI => 0x0F,
355            Self::DMC_FREQ => 0x10,
356            Self::DMC_RAW => 0x11,
357            Self::DMC_START => 0x12,
358            Self::DMC_LEN => 0x13,
359            Self::OAMDMA => 0x14,
360            Self::SND_CHN => 0x15,
361            Self::JOY1 => 0x16,
362            Self::JOY2 => 0x17,
363        }
364    }
365
366    fn from_relative_address(relative_addr: u16) -> Option<Self> {
367        match relative_addr {
368            0x00 => Some(Self::SQ1_VOL),
369            0x01 => Some(Self::SQ1_SWEEP),
370            0x02 => Some(Self::SQ1_LO),
371            0x03 => Some(Self::SQ1_HI),
372            0x04 => Some(Self::SQ2_VOL),
373            0x05 => Some(Self::SQ2_SWEEP),
374            0x06 => Some(Self::SQ2_LO),
375            0x07 => Some(Self::SQ2_HI),
376            0x08 => Some(Self::TRI_LINEAR),
377            0x0A => Some(Self::TRI_LO),
378            0x0B => Some(Self::TRI_HI),
379            0x0C => Some(Self::NOISE_VOL),
380            0x0E => Some(Self::NOISE_LO),
381            0x0F => Some(Self::NOISE_HI),
382            0x10 => Some(Self::DMC_FREQ),
383            0x11 => Some(Self::DMC_RAW),
384            0x12 => Some(Self::DMC_START),
385            0x13 => Some(Self::DMC_LEN),
386            0x14 => Some(Self::OAMDMA),
387            0x15 => Some(Self::SND_CHN),
388            0x16 => Some(Self::JOY1),
389            0x17 => Some(Self::JOY2),
390            _ => None,
391        }
392    }
393}
394
395#[derive(Debug, Clone, Encode, Decode)]
396struct ZapperBusState {
397    fire_pressed: bool,
398    position: Option<(u16, u16)>,
399    cpu_ticks_until_release: u32,
400    cpu_ticks_until_sensor_off: u32,
401}
402
403impl ZapperBusState {
404    // Roughly two frames' worth of CPU cycles
405    // In actual hardware, the bit transitions from 0 to 1 when either the trigger is full pulled or
406    // roughly 100ms after the half-pull (if the trigger is never full pulled)
407    const HALF_PULLED_CPU_TICKS: u32 = 59_661;
408
409    // Roughly 25 lines' worth of CPU cycles
410    const SENSOR_ON_CPU_TICKS: u32 = 2_841;
411
412    fn new(state: ZapperState) -> Self {
413        Self {
414            fire_pressed: state.fire,
415            position: state.position(),
416            cpu_ticks_until_release: 0,
417            cpu_ticks_until_sensor_off: 0,
418        }
419    }
420
421    fn read(&self) -> u8 {
422        let no_light_sensed_bit = u8::from(self.cpu_ticks_until_sensor_off == 0) << 3;
423        let released_bit = u8::from(self.cpu_ticks_until_release == 0) << 4;
424
425        log::trace!(
426            "Zapper read: light_sensed={} pressed={}",
427            no_light_sensed_bit == 0,
428            released_bit == 0
429        );
430
431        no_light_sensed_bit | released_bit
432    }
433
434    fn tick_cpu(&mut self) {
435        self.cpu_ticks_until_release = self.cpu_ticks_until_release.saturating_sub(1);
436        self.cpu_ticks_until_sensor_off = self.cpu_ticks_until_sensor_off.saturating_sub(1);
437    }
438
439    fn update_buttons(&mut self, state: ZapperState) {
440        self.position = state.position();
441
442        if !self.fire_pressed && state.fire {
443            log::debug!(
444                "Zapper fire button pressed; setting released bit to 0 for {} cycles",
445                Self::HALF_PULLED_CPU_TICKS
446            );
447            self.cpu_ticks_until_release = Self::HALF_PULLED_CPU_TICKS;
448        }
449
450        self.fire_pressed = state.fire;
451    }
452
453    fn handle_pixel_rendered(
454        &mut self,
455        pixel: u8,
456        x: u16,
457        y: u16,
458        display_mode: TimingMode,
459        overscan: Overscan,
460    ) {
461        let Some((x, y)) = Self::adjust_frame_position(x, y, display_mode, overscan) else {
462            return;
463        };
464
465        if self.position == Some((x, y)) {
466            log::debug!("Detected pixel {pixel:02X} at Zapper position of ({x}, {y})");
467
468            if should_trigger_zapper_sensor(pixel) {
469                log::debug!("  Triggered Zapper light sensor");
470                self.cpu_ticks_until_sensor_off = Self::SENSOR_ON_CPU_TICKS;
471            }
472        }
473    }
474
475    fn adjust_frame_position(
476        mut x: u16,
477        mut y: u16,
478        display_mode: TimingMode,
479        overscan: Overscan,
480    ) -> Option<(u16, u16)> {
481        let mut overflowed;
482
483        (y, overflowed) = y.overflowing_sub(display_mode.starting_row());
484        if overflowed {
485            return None;
486        }
487
488        (y, overflowed) = y.overflowing_sub(overscan.top);
489        if overflowed {
490            return None;
491        }
492
493        (x, overflowed) = x.overflowing_sub(overscan.left);
494        if overflowed {
495            return None;
496        }
497
498        Some((x, y))
499    }
500}
501
502fn should_trigger_zapper_sensor(pixel: u8) -> bool {
503    // Fairly arbitrary definition of what constitutes a bright enough pixel to trigger
504    // the sensor. On actual hardware this will vary by TV
505    let pixel = pixel & 0x3F;
506    pixel == 0x00
507        || (0x10..0x1D).contains(&pixel)
508        || (0x20..0x2E).contains(&pixel)
509        || (0x30..0x3E).contains(&pixel)
510}
511
512#[derive(Debug, Clone, Encode, Decode)]
513struct JoypadRegisterState {
514    joypad_state: NesJoypadState,
515    latched_bit: u8,
516    latched_joypad_state: LatchedJoypadState,
517    read_last_cycle: bool,
518    read_this_cycle: bool,
519}
520
521impl JoypadRegisterState {
522    fn new() -> Self {
523        Self {
524            joypad_state: NesJoypadState::default(),
525            latched_bit: 1,
526            latched_joypad_state: LatchedJoypadState::default(),
527            read_last_cycle: false,
528            read_this_cycle: false,
529        }
530    }
531
532    fn handle_read(&mut self) -> u8 {
533        self.read_this_cycle = true;
534
535        if !self.read_last_cycle {
536            self.latched_bit = self.latched_joypad_state.next_bit();
537            self.latched_joypad_state = self.latched_joypad_state.shift();
538        }
539
540        self.latched_bit
541    }
542
543    fn tick_cpu(&mut self) {
544        self.read_last_cycle = self.read_this_cycle;
545        self.read_this_cycle = false;
546    }
547
548    fn strobe(&mut self) {
549        self.latched_joypad_state = self.joypad_state.latch();
550    }
551}
552
553#[derive(Debug, Clone, Encode, Decode)]
554pub struct IoRegisters {
555    data: [u8; 0x18],
556    dma_dirty: bool,
557    dirty_register: Option<IoRegister>,
558    snd_chn_read: bool,
559    p1: JoypadRegisterState,
560    p2: JoypadRegisterState,
561    joypad_strobe: bool,
562    zapper_state: Option<ZapperBusState>,
563    // Needed for zapper positioning
564    overscan: Overscan,
565}
566
567impl IoRegisters {
568    fn new(overscan: Overscan) -> Self {
569        Self {
570            data: [0; 0x18],
571            dma_dirty: false,
572            dirty_register: None,
573            snd_chn_read: false,
574            p1: JoypadRegisterState::new(),
575            p2: JoypadRegisterState::new(),
576            joypad_strobe: false,
577            zapper_state: None,
578            overscan,
579        }
580    }
581
582    fn read_address(&mut self, address: u16, cpu_open_bus: u8) -> Option<u8> {
583        let relative_addr = address - CPU_IO_REGISTERS_START;
584        IoRegister::from_relative_address(relative_addr)
585            .map(|register| self.read_register(register, cpu_open_bus))
586    }
587
588    fn read_register(&mut self, register: IoRegister, cpu_open_bus: u8) -> u8 {
589        // Highest 3 bits of JOY1/JOY2 reads are open bus (normally 0x40 but not necessarily)
590        let joy_open_bus = cpu_open_bus & 0xE0;
591
592        match register {
593            IoRegister::SND_CHN => {
594                self.snd_chn_read = true;
595                // Bit 5 of SND_CHN reads is open bus
596                self.data[register.to_relative_address()] | (cpu_open_bus & (1 << 5))
597            }
598            IoRegister::JOY1 => self.p1.handle_read() | joy_open_bus,
599            IoRegister::JOY2 => match &self.zapper_state {
600                Some(zapper_state) => zapper_state.read() | joy_open_bus,
601                None => self.p2.handle_read() | joy_open_bus,
602            },
603            _ => {
604                // Other I/O registers are write-only
605                cpu_open_bus
606            }
607        }
608    }
609
610    fn write_address(&mut self, address: u16, value: u8) {
611        let relative_addr = address - CPU_IO_REGISTERS_START;
612        let Some(register) = IoRegister::from_relative_address(relative_addr) else {
613            return;
614        };
615
616        self.write_register(register, value);
617    }
618
619    #[allow(clippy::manual_assert)]
620    fn write_register(&mut self, register: IoRegister, value: u8) {
621        self.data[register.to_relative_address()] = value;
622
623        if self.dirty_register.replace(register).is_some() {
624            panic!("Attempted to write an I/O register twice in the same cycle");
625        }
626
627        match register {
628            IoRegister::JOY1 => {
629                self.joypad_strobe = value.bit(0);
630            }
631            IoRegister::OAMDMA => {
632                self.dma_dirty = true;
633            }
634            _ => {}
635        }
636    }
637
638    pub fn take_dirty_register(&mut self) -> Option<(IoRegister, u8)> {
639        self.dirty_register
640            .take()
641            .map(|register| (register, self.data[register.to_relative_address()]))
642    }
643
644    pub fn set_apu_status(&mut self, apu_status: u8) {
645        self.data[IoRegister::SND_CHN.to_relative_address()] = apu_status;
646    }
647
648    pub fn get_and_clear_snd_chn_read(&mut self) -> bool {
649        let snd_chn_read = self.snd_chn_read;
650        self.snd_chn_read = false;
651        snd_chn_read
652    }
653
654    fn tick_cpu(&mut self, apu_odd_cycle: bool) {
655        self.p1.tick_cpu();
656        self.p2.tick_cpu();
657
658        if self.joypad_strobe && apu_odd_cycle {
659            self.p1.strobe();
660            self.p2.strobe();
661        }
662
663        if let Some(zapper_state) = &mut self.zapper_state {
664            zapper_state.tick_cpu();
665        }
666    }
667}
668
669#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)]
670pub enum InterruptLine {
671    High,
672    Low,
673}
674
675#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)]
676pub enum IrqSource {
677    ApuDmc,
678    ApuFrameCounter,
679    Mapper,
680}
681
682impl IrqSource {
683    fn to_low_pull_bit(self) -> u8 {
684        match self {
685            Self::ApuDmc => 0x01,
686            Self::ApuFrameCounter => 0x02,
687            Self::Mapper => 0x04,
688        }
689    }
690}
691
692#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)]
693enum IrqStatus {
694    None,
695    Pending,
696    Triggered,
697}
698
699#[derive(Debug, Clone, Encode, Decode)]
700pub struct InterruptLines {
701    nmi_line: InterruptLine,
702    next_nmi_line: InterruptLine,
703    nmi_triggered: bool,
704    irq_status: IrqStatus,
705    irq_low_pulls: u8,
706}
707
708impl InterruptLines {
709    fn new() -> Self {
710        Self {
711            nmi_line: InterruptLine::High,
712            next_nmi_line: InterruptLine::High,
713            nmi_triggered: false,
714            irq_status: IrqStatus::None,
715            irq_low_pulls: 0x00,
716        }
717    }
718
719    fn tick(&mut self) {
720        if self.nmi_line == InterruptLine::High && self.next_nmi_line == InterruptLine::Low {
721            self.nmi_triggered = true;
722        }
723        self.nmi_line = self.next_nmi_line;
724
725        let irq_line =
726            if self.irq_low_pulls != 0 { InterruptLine::Low } else { InterruptLine::High };
727
728        match (irq_line, self.irq_status) {
729            (InterruptLine::High, _) => {
730                self.irq_status = IrqStatus::None;
731            }
732            (InterruptLine::Low, IrqStatus::None) => {
733                // IRQ interrupts need to be delayed by 1 CPU cycle
734                self.irq_status = IrqStatus::Pending;
735            }
736            (InterruptLine::Low, IrqStatus::Pending) => {
737                self.irq_status = IrqStatus::Triggered;
738            }
739            (InterruptLine::Low, IrqStatus::Triggered) => {}
740        }
741    }
742
743    pub fn nmi_triggered(&self) -> bool {
744        self.nmi_triggered
745    }
746
747    pub fn clear_nmi_triggered(&mut self) {
748        self.nmi_triggered = false;
749    }
750
751    pub fn ppu_set_nmi_line(&mut self, interrupt_line: InterruptLine) {
752        self.next_nmi_line = interrupt_line;
753    }
754
755    pub fn irq_triggered(&self) -> bool {
756        self.irq_status == IrqStatus::Triggered
757    }
758
759    pub fn set_irq_low_pull(&mut self, source: IrqSource, value: bool) {
760        if value {
761            self.irq_low_pulls |= source.to_low_pull_bit();
762        } else {
763            self.irq_low_pulls &= !source.to_low_pull_bit();
764        }
765    }
766}
767
768#[derive(Debug, Clone, Encode, Decode, PartialClone)]
769pub struct Bus {
770    #[partial_clone(partial)]
771    mapper: Mapper,
772    cpu_internal_ram: Box<[u8; 2048]>,
773    cpu_open_bus: u8,
774    ppu_registers: PpuRegisters,
775    io_registers: IoRegisters,
776    ppu_vram: Box<[u8; 2048]>,
777    ppu_palette_ram: [u8; 32],
778    ppu_oam: [u8; 256],
779    ppu_bus_address: u16,
780    interrupt_lines: InterruptLines,
781    pending_write: Option<PendingCpuWrite>,
782}
783
784impl Bus {
785    pub(crate) fn from_cartridge(mapper: Mapper, overscan: Overscan) -> Self {
786        const INITIAL_PALETTE_RAM: [u8; 32] = [
787            0x09, 0x01, 0x00, 0x01, 0x00, 0x02, 0x02, 0x0D, 0x08, 0x10, 0x08, 0x24, 0x00, 0x00,
788            0x04, 0x2C, 0x09, 0x01, 0x34, 0x03, 0x00, 0x04, 0x00, 0x14, 0x08, 0x3A, 0x00, 0x02,
789            0x00, 0x20, 0x2C, 0x08,
790        ];
791
792        Self {
793            mapper,
794            // (Somewhat) randomize initial RAM contents
795            cpu_internal_ram: Box::new(array::from_fn(
796                |_| if rand::random() { 0x00 } else { 0xFF },
797            )),
798            cpu_open_bus: 0,
799            ppu_registers: PpuRegisters::new(),
800            io_registers: IoRegisters::new(overscan),
801            ppu_vram: Box::new(array::from_fn(|_| 0)),
802            ppu_palette_ram: INITIAL_PALETTE_RAM,
803            ppu_oam: [0; 256],
804            ppu_bus_address: 0,
805            interrupt_lines: InterruptLines::new(),
806            pending_write: None,
807        }
808    }
809
810    pub fn cpu(&mut self) -> CpuBus<'_> {
811        CpuBus(self)
812    }
813
814    pub fn ppu(&mut self) -> PpuBus<'_> {
815        PpuBus(self)
816    }
817
818    pub fn update_p1_joypad_state(
819        &mut self,
820        p1_joypad_state: NesJoypadState,
821        allow_opposing_directions: bool,
822    ) {
823        self.io_registers.p1.joypad_state =
824            p1_joypad_state.with_allow_opposing_directions(allow_opposing_directions);
825    }
826
827    pub fn update_p2_joypad_state(
828        &mut self,
829        p2_inputs: NesInputDevice,
830        allow_opposing_directions: bool,
831    ) {
832        match p2_inputs {
833            NesInputDevice::Controller(joypad_state) => {
834                self.io_registers.p2.joypad_state =
835                    joypad_state.with_allow_opposing_directions(allow_opposing_directions);
836                self.io_registers.zapper_state = None;
837            }
838            NesInputDevice::Zapper(zapper_state) => {
839                match &mut self.io_registers.zapper_state {
840                    Some(bus_state) => {
841                        bus_state.update_buttons(zapper_state);
842                    }
843                    None => {
844                        self.io_registers.zapper_state = Some(ZapperBusState::new(zapper_state));
845                    }
846                }
847                self.io_registers.p2.joypad_state = NesJoypadState::default();
848            }
849        }
850    }
851
852    pub fn tick(&mut self) {
853        self.ppu_registers.tick(&mut self.interrupt_lines);
854        self.mapper.tick(self.ppu_bus_address);
855    }
856
857    pub fn tick_cpu(&mut self, apu_state: &ApuState) {
858        if let Some(write) = self.pending_write.take() {
859            self.cpu().apply_write(write.address, write.value);
860        }
861
862        self.mapper.tick_cpu();
863        self.io_registers.tick_cpu(apu_state.is_active_cycle());
864
865        self.ppu_registers.total_cycles += 1;
866    }
867
868    // Poll NMI/IRQ interrupt lines; this should be called once per CPU cycle, between the first
869    // and second PPU ticks
870    pub fn poll_interrupt_lines(&mut self) {
871        self.interrupt_lines.set_irq_low_pull(IrqSource::Mapper, self.mapper.interrupt_flag());
872
873        self.interrupt_lines.tick();
874    }
875
876    pub(crate) fn mapper(&self) -> &Mapper {
877        &self.mapper
878    }
879
880    pub(crate) fn mapper_mut(&mut self) -> &mut Mapper {
881        &mut self.mapper
882    }
883
884    pub(crate) fn move_rom_from(&mut self, other: &mut Self) {
885        self.mapper.move_rom_from(&mut other.mapper);
886    }
887
888    pub(crate) fn reload_config(&mut self, config: &NesEmulatorConfig) {
889        self.io_registers.overscan = config.overscan;
890    }
891}

A view of the bus containing methods that are appropriate for use by the CPU and APU.

894pub struct CpuBus<'a>(&'a mut Bus);
896impl BusInterface for CpuBus<'_> {
897    #[inline]
898    fn read(&mut self, address: u16) -> u8 {
899        let value = match address {
900            address @ CPU_RAM_START..=CPU_RAM_END => {
901                let ram_address = address & CPU_RAM_MASK;
902                self.0.cpu_internal_ram[ram_address as usize]
903            }
904            address @ CPU_PPU_REGISTERS_START..=CPU_PPU_REGISTERS_END => {
905                let ppu_register_relative_addr =
906                    (address - CPU_PPU_REGISTERS_START) & CPU_PPU_REGISTERS_MASK;
907                self.read_ppu_register_address(ppu_register_relative_addr as usize)
908            }
909            address @ CPU_IO_REGISTERS_START..=CPU_IO_REGISTERS_END => self
910                .0
911                .io_registers
912                .read_address(address, self.0.cpu_open_bus)
913                .unwrap_or(self.0.cpu_open_bus),
914            _address @ CPU_IO_TEST_MODE_START..=CPU_IO_TEST_MODE_END => self.0.cpu_open_bus,
915            address @ CPU_CARTRIDGE_START..=CPU_CARTRIDGE_END => {
916                self.0.mapper.read_cpu_address(address, self.0.cpu_open_bus)
917            }
918        };
919
920        // $4015 reads (SND_CHN) do not update open bus (verified by AccuracyCoin open bus tests)
921        if address != 0x4015 {
922            self.0.cpu_open_bus = value;
923        }
924
925        value
926    }
927
928    #[inline]
929    #[allow(clippy::manual_assert)]
930    fn write(&mut self, address: u16, value: u8) {
931        if self.0.pending_write.replace(PendingCpuWrite { address, value }).is_some() {
932            panic!("Attempted to write twice in the same cycle");
933        }
934    }
935
936    #[inline]
937    fn nmi(&self) -> bool {
938        self.0.interrupt_lines.nmi_triggered()
939    }
940
941    #[inline]
942    fn acknowledge_nmi(&mut self) {
943        self.0.interrupt_lines.clear_nmi_triggered();
944    }
945
946    #[inline]
947    fn irq(&self) -> bool {
948        self.0.interrupt_lines.irq_triggered()
949    }
950}
951
952impl CpuBus<'_> {
953    fn dma_read<const DMC: bool>(
954        &mut self,
955        address: u16,
956        halted_cpu_address: u16,
957        config: &NesEmulatorConfig,
958    ) -> u8 {
959        // 2A03 register activation uses bits 0-4 from the 2A03 address bus and bits 5-15 from the
960        // 6502 address bus.
961        //
962        // For normal CPU reads, the 2A03 and 6502 addresses are obviously always the same.
963        //
964        // For DMA reads, they can be different: the 2A03 address bus is set to the DMA read address,
965        // while the 6502 address bus remains at the address that the CPU was reading from when DMA
966        // halted it.
967        //
968        // This causes bus conflicts if one of the APU registers ($4015-$4017) activates while DMA
969        // is trying to read from a different address.
970        let register_activation_addr = (address & 0x1F) | (halted_cpu_address & !0x1F);
971        if address == register_activation_addr {
972            // Bits 5-15 of the DMA address match the 6502 address
973            // Return early to prevent possible double reads of addresses with read side effects
974            return self.read(address);
975        }
976
977        if (0x4015..=0x4017).contains(&register_activation_addr) {
978            // Bus conflict!
979            if DMC {
980                // For DMC DMA $4015 conflicts, open bus is set to the 8-bit sample, and the frame
981                // counter IRQ flag is cleared (so the $4015 read does happen).
982                //
983                // For DMC DMA $4016/$4017 conflicts, open bus is set to the highest 3 bits of the
984                // sample and the lowest 5 bits from JOY1/JOY2.
985                //
986                // In both cases, give the DMC the actual 8-bit sample to prevent possible audio
987                // corruption, even though this is probably not accurate to hardware.
988                let sample_byte = self.read(address);
989                if config.dma_dummy_joy_reads || register_activation_addr == 0x4015 {
990                    self.read(register_activation_addr);
991                }
992                sample_byte
993            } else if register_activation_addr == 0x4015 {
994                // For OAM DMA $4015 conflicts, the DMA address is read (which can change open bus),
995                // but DMA gets the value from the $4015 read
996                self.read(address);
997                self.read(register_activation_addr)
998            } else {
999                // For OAM DMA $4016/$4017 conflicts, the controller port gets read, but the value
1000                // is only used if the DMA address is open bus
1001                if config.dma_dummy_joy_reads {
1002                    self.read(register_activation_addr);
1003                }
1004                self.read(address)
1005            }
1006        } else if (0x4015..=0x4017).contains(&address) {
1007            // No bus conflict, but DMA tried to read from an APU register that is not activated
1008            self.0.cpu_open_bus
1009        } else {
1010            // No bus conflict and read goes through
1011            self.read(address)
1012        }
1013    }
1014
1015    pub fn oam_dma_read(
1016        &mut self,
1017        address: u16,
1018        halted_cpu_address: u16,
1019        config: &NesEmulatorConfig,
1020    ) -> u8 {
1021        self.dma_read::<false>(address, halted_cpu_address, config)
1022    }
1023
1024    pub fn dmc_dma_read(
1025        &mut self,
1026        address: u16,
1027        halted_cpu_address: u16,
1028        config: &NesEmulatorConfig,
1029    ) -> u8 {
1030        self.dma_read::<true>(address, halted_cpu_address, config)
1031    }
1032
1033    fn apply_write(&mut self, address: u16, value: u8) {
1034        self.0.cpu_open_bus = value;
1035
1036        match address {
1037            address @ CPU_RAM_START..=CPU_RAM_END => {
1038                let ram_address = address & CPU_RAM_MASK;
1039                self.0.cpu_internal_ram[ram_address as usize] = value;
1040            }
1041            address @ CPU_PPU_REGISTERS_START..=CPU_PPU_REGISTERS_END => {
1042                let ppu_register_relative_addr =
1043                    (address - CPU_PPU_REGISTERS_START) & CPU_PPU_REGISTERS_MASK;
1044                self.write_ppu_register_address(ppu_register_relative_addr as usize, value);
1045            }
1046            address @ CPU_IO_REGISTERS_START..=CPU_IO_REGISTERS_END => {
1047                self.0.io_registers.write_address(address, value);
1048            }
1049            _address @ CPU_IO_TEST_MODE_START..=CPU_IO_TEST_MODE_END => {}
1050            address @ CPU_CARTRIDGE_START..=CPU_CARTRIDGE_END => {
1051                self.0.mapper.write_cpu_address(address, value);
1052            }
1053        }
1054    }
1055
1056    fn read_ppu_register_address(&mut self, relative_addr: usize) -> u8 {
1057        let Some(register) = PpuRegister::from_relative_address(relative_addr) else {
1058            panic!("invalid PPU register address: {relative_addr}");
1059        };
1060
1061        self.read_ppu_register(register)
1062    }
1063
1064    fn read_ppu_open_bus(&mut self) -> u8 {
1065        if self.0.ppu_registers.ppu_open_bus == 0 {
1066            return 0;
1067        }
1068
1069        for i in 0..8 {
1070            if self.0.ppu_registers.ppu_open_bus.bit(i)
1071                && self.0.ppu_registers.ppu_open_bus_decay_cycles[i as usize]
1072                    <= self.0.ppu_registers.total_cycles
1073            {
1074                self.0.ppu_registers.ppu_open_bus &= !(1 << i);
1075            }
1076        }
1077
1078        self.0.ppu_registers.ppu_open_bus
1079    }
1080
1081    fn set_ppu_open_bus(&mut self, value: u8, mask: u8) {
1082        let masked = value & mask;
1083        self.0.ppu_registers.ppu_open_bus = (self.0.ppu_registers.ppu_open_bus & !mask) | masked;
1084        for i in 0..8 {
1085            if masked.bit(i) {
1086                // Decay to 0 after slightly more than half a second
1087                // Exact time varies in actual hardware but seems to always be less than a second
1088                self.0.ppu_registers.ppu_open_bus_decay_cycles[i as usize] =
1089                    self.0.ppu_registers.total_cycles + 1000000;
1090            }
1091        }
1092    }
1093
1094    pub fn read_ppu_register(&mut self, register: PpuRegister) -> u8 {
1095        match register {
1096            PpuRegister::PPUCTRL
1097            | PpuRegister::PPUMASK
1098            | PpuRegister::OAMADDR
1099            | PpuRegister::PPUSCROLL
1100            | PpuRegister::PPUADDR => self.read_ppu_open_bus(),
1101            PpuRegister::PPUSTATUS => {
1102                self.0.ppu_registers.ppu_status_read = true;
1103
1104                // PPUSTATUS reads only affect bits 7-5 of open bus, bits 4-0 remain intact
1105                // and are returned as part of the read
1106                let ppu_status_high_bits = self.0.ppu_registers.ppu_status & 0xE0;
1107                let open_bus_lower_bits = self.read_ppu_open_bus() & 0x1F;
1108                self.set_ppu_open_bus(ppu_status_high_bits, 0xE0);
1109
1110                ppu_status_high_bits | open_bus_lower_bits
1111            }
1112            PpuRegister::OAMDATA => {
1113                let mut value = self
1114                    .0
1115                    .ppu_registers
1116                    .oam_open_bus_value
1117                    .unwrap_or(self.0.ppu_oam[self.0.ppu_registers.oam_addr as usize]);
1118                if self.0.ppu_registers.oam_addr & 3 == 2 {
1119                    // Bits 2-4 of the third byte always read 0
1120                    value &= !0x1C;
1121                }
1122
1123                self.set_ppu_open_bus(value, 0xFF);
1124                value
1125            }
1126            PpuRegister::PPUDATA => {
1127                let address = self.0.ppu_bus_address;
1128                let (data, buffer_read_address) = if address < 0x3F00 {
1129                    let data = self.0.ppu_registers.ppu_data_buffer;
1130                    self.set_ppu_open_bus(data, 0xFF);
1131                    (data, address)
1132                } else {
1133                    let palette_address = address & PALETTE_RAM_MASK;
1134                    let palette_data_mask =
1135                        if self.0.ppu_registers.greyscale() { 0x30 } else { 0x3F };
1136
1137                    let palette_byte =
1138                        self.0.ppu_palette_ram[palette_address as usize] & palette_data_mask;
1139                    let open_bus_bits = self.read_ppu_open_bus() & 0xC0;
1140                    self.set_ppu_open_bus(palette_byte, 0x3F);
1141
1142                    // When PPUDATA is used to read palette RAM, buffer reads mirror the nametable
1143                    // data located at $2F00-$2FFF
1144                    (palette_byte | open_bus_bits, address - 0x1000)
1145                };
1146
1147                self.0.mapper.about_to_access_ppu_data();
1148
1149                self.0.ppu_registers.ppu_data_buffer =
1150                    self.0.ppu().read_address(buffer_read_address);
1151                // Reset the bus address in case the buffer read address was different from the
1152                // actual address
1153                self.0.ppu_bus_address = address;
1154
1155                self.0.ppu_registers.last_accessed_register = Some(PpuTrackedRegister::PPUDATA);
1156
1157                data
1158            }
1159        }
1160    }
1161
1162    fn write_ppu_register_address(&mut self, relative_addr: usize, value: u8) {
1163        let Some(register) = PpuRegister::from_relative_address(relative_addr) else {
1164            panic!("invalid PPU register address: {relative_addr}");
1165        };
1166
1167        // Writes to any memory-mapped PPU register put the value on open bus
1168        self.set_ppu_open_bus(value, 0xFF);
1169
1170        if self.0.ppu_registers.reset_flag
1171            && matches!(
1172                register,
1173                PpuRegister::PPUCTRL
1174                    | PpuRegister::PPUMASK
1175                    | PpuRegister::PPUSCROLL
1176                    | PpuRegister::PPUADDR
1177            )
1178        {
1179            // These registers are not writable until the first pre-render scanline after reset
1180            return;
1181        }
1182
1183        match register {
1184            PpuRegister::PPUCTRL => {
1185                self.0.ppu_registers.ppu_ctrl = value;
1186                self.0.ppu_registers.last_accessed_register = Some(PpuTrackedRegister::PPUCTRL);
1187                self.0.mapper.process_ppu_ctrl_update(value);
1188            }
1189            PpuRegister::PPUMASK => {
1190                log::trace!("BUS: PPUMASK set to {value:02X}");
1191                self.0.ppu_registers.ppu_mask = value;
1192                self.0.mapper.process_ppu_mask_update(value);
1193            }
1194            PpuRegister::PPUSTATUS => {}
1195            PpuRegister::OAMADDR => {
1196                self.0.ppu_registers.oam_addr = value;
1197            }
1198            PpuRegister::OAMDATA => {
1199                if self.0.ppu_registers.oam_open_bus_value.is_none() {
1200                    let oam_addr = self.0.ppu_registers.oam_addr;
1201                    self.0.ppu_oam[oam_addr as usize] = value;
1202                    self.0.ppu_registers.oam_addr = self.0.ppu_registers.oam_addr.wrapping_add(1);
1203                }
1204            }
1205            PpuRegister::PPUSCROLL => {
1206                self.0.ppu_registers.last_accessed_register = Some(PpuTrackedRegister::PPUSCROLL);
1207                self.0.ppu_registers.write_toggle = self.0.ppu_registers.write_toggle.toggle();
1208            }
1209            PpuRegister::PPUADDR => {
1210                self.0.ppu_registers.last_accessed_register = Some(PpuTrackedRegister::PPUADDR);
1211                self.0.ppu_registers.write_toggle = self.0.ppu_registers.write_toggle.toggle();
1212            }
1213            PpuRegister::PPUDATA => {
1214                self.0.mapper.about_to_access_ppu_data();
1215
1216                let address = self.0.ppu_bus_address;
1217                self.0.ppu().write_address(address & 0x3FFF, value);
1218
1219                self.0.ppu_registers.last_accessed_register = Some(PpuTrackedRegister::PPUDATA);
1220            }
1221        }
1222    }
1223
1224    pub fn is_oamdma_dirty(&self) -> bool {
1225        self.0.io_registers.dma_dirty
1226    }
1227
1228    pub fn clear_oamdma_dirty(&mut self) {
1229        self.0.io_registers.dma_dirty = false;
1230    }
1231
1232    pub fn read_oamdma_for_transfer(&self) -> u8 {
1233        self.0.io_registers.data[IoRegister::OAMDMA.to_relative_address()]
1234    }
1235
1236    pub fn get_io_registers_mut(&mut self) -> &mut IoRegisters {
1237        &mut self.0.io_registers
1238    }
1239
1240    pub fn interrupt_lines(&mut self) -> &mut InterruptLines {
1241        &mut self.0.interrupt_lines
1242    }
1243}

A view of the bus containing methods that are appropriate for use by the PPU.

1246pub struct PpuBus<'a>(&'a mut Bus);
1248impl PpuBus<'_> {
1249    pub fn read_address(&mut self, address: u16) -> u8 {
1250        // PPU bus only has 14-bit addressing
1251        let address = address & 0x3FFF;
1252
1253        self.0.ppu_bus_address = address;
1254
1255        match address {
1256            0x0000..=0x3EFF => self.0.mapper.read_ppu_address(address, &self.0.ppu_vram),
1257            0x3F00..=0x3FFF => self.0.ppu_palette_ram[(address & PALETTE_RAM_MASK) as usize],
1258            0x4000..=0xFFFF => {
1259                unreachable!("{address} should be <= 0x3FFF after masking with 0x3FFF")
1260            }
1261        }
1262    }
1263
1264    pub fn write_address(&mut self, address: u16, value: u8) {
1265        let address = address & 0x3FFF;
1266        match address {
1267            0x0000..=0x3EFF => {
1268                self.0.mapper.write_ppu_address(address, value, &mut self.0.ppu_vram);
1269            }
1270            0x3F00..=0x3FFF => {
1271                let palette_ram_addr = (address & PALETTE_RAM_MASK) as usize;
1272                self.0.ppu_palette_ram[palette_ram_addr] = value;
1273
1274                // Sprite backdrop colors ($3F10, $3F14, $3F18, $3F1C) mirror BG backdrop colors ($3F00, $3F04, $3F08, $3F0C)
1275                // Emulate this by writing to both locations whenever either is written to.
1276                // Super Mario Bros. and Micro Machines depend on this for correct colors
1277                if palette_ram_addr & 3 == 0 {
1278                    self.0.ppu_palette_ram[palette_ram_addr ^ 0x10] = value;
1279                }
1280            }
1281            0x4000..=0xFFFF => {
1282                unreachable!("{address} should be <= 0x3FFF after masking with 0x3FFF")
1283            }
1284        }
1285    }
1286
1287    pub fn get_ppu_registers(&self) -> &PpuRegisters {
1288        &self.0.ppu_registers
1289    }
1290
1291    pub fn get_ppu_registers_mut(&mut self) -> &mut PpuRegisters {
1292        &mut self.0.ppu_registers
1293    }
1294
1295    pub fn get_oam(&self) -> &[u8; 256] {
1296        &self.0.ppu_oam
1297    }
1298
1299    pub fn get_palette_ram(&self) -> &[u8; 32] {
1300        &self.0.ppu_palette_ram
1301    }
1302
1303    pub fn set_bus_address(&mut self, address: u16) {
1304        self.0.ppu_bus_address = address;
1305    }
1306
1307    pub fn handle_pixel_rendered(&mut self, pixel: u8, x: u16, y: u16, display_mode: TimingMode) {
1308        if let Some(zapper_state) = &mut self.0.io_registers.zapper_state {
1309            let overscan = self.0.io_registers.overscan;
1310            zapper_state.handle_pixel_rendered(pixel, x, y, display_mode, overscan);
1311        }
1312    }
1313
1314    pub fn reset(&mut self) {
1315        self.0.ppu_registers.ppu_ctrl = 0x00;
1316        self.0.ppu_registers.ppu_mask = 0x00;
1317        self.0.ppu_registers.write_toggle = PpuWriteToggle::First;
1318        self.0.ppu_registers.ppu_data_buffer = 0x00;
1319        self.0.ppu_registers.ppu_open_bus = 0x00;
1320        self.0.ppu_registers.reset_flag = true;
1321        self.0.mapper.reset();
1322    }
1323}
1324
1325#[cfg(test)]
1326mod tests {
1327    use super::*;
1328
1329    #[test]
1330    fn randomized_ram_on_startup() {
1331        let mapper = cartridge::new_mmc1(vec![0; 32768]);
1332        let bus1 = Bus::from_cartridge(mapper.clone(), Overscan::default());
1333        let bus2 = Bus::from_cartridge(mapper, Overscan::default());
1334
1335        assert_ne!(bus1.cpu_internal_ram, bus2.cpu_internal_ram);
1336    }
1337}