From f61e3f9e65eb59bfd6851cc8267b9cbcae53ed9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com> Date: Mon, 15 May 2023 17:38:13 +0100 Subject: [PATCH] feat: support for speed switching With initial approach for scalling down the speed of other components. --- frontends/sdl/src/main.rs | 9 ++++++--- src/apu.rs | 31 +++++++++++++++++++++++++++++++ src/cpu.rs | 5 +++++ src/gb.rs | 24 ++++++++++++++++++++++-- src/mmu.rs | 11 ++++------- 5 files changed, 68 insertions(+), 12 deletions(-) diff --git a/frontends/sdl/src/main.rs b/frontends/sdl/src/main.rs index e6990a2a..fb789d0a 100644 --- a/frontends/sdl/src/main.rs +++ b/frontends/sdl/src/main.rs @@ -349,9 +349,12 @@ impl Emulator { // calculates the number of cycles that are meant to be the target // for the current "tick" operation this is basically the current - // logic frequency divided by the visual one - let cycle_limit = - (self.logic_frequency as f32 / self.visual_frequency).round() as u32; + // logic frequency divided by the visual one, this operation also + // takes into account the current Game Boy speed multiplier (GBC) + let cycle_limit = (self.logic_frequency as f32 + * self.system.speed().multiplier() as f32 + / self.visual_frequency) + .round() as u32; loop { // limits the number of ticks to the typical number diff --git a/src/apu.rs b/src/apu.rs index c1c41c94..d2b9f657 100644 --- a/src/apu.rs +++ b/src/apu.rs @@ -330,6 +330,24 @@ impl Apu { pub fn read(&mut self, addr: u16) -> u8 { match addr { + // 0xFF11 — NR11: Channel 1 length timer & duty cycle + 0xff11 => (self.ch1_wave_duty & 0x03) << 6, + // 0xFF12 — NR12: Channel 1 volume & envelope + 0xff12 => { + (self.ch1_pace & 0x07) + | ((self.ch1_direction & 0x01) << 3) + | ((self.ch1_volume & 0x0f) << 4) + } + + // 0xFF16 — NR21: Channel 2 length timer & duty cycle + 0xff16 => (self.ch2_wave_duty & 0x03) << 6, + // 0xFF17 — NR22: Channel 2 volume & envelope + 0xff17 => { + (self.ch2_pace & 0x07) + | ((self.ch2_direction & 0x01) << 3) + | ((self.ch2_volume & 0x0f) << 4) + } + // 0xFF1A — NR30: Channel 3 DAC enable 0xff1a => { if self.ch3_dac { @@ -338,6 +356,19 @@ impl Apu { 0x00 } } + // 0xFF1B — NR31: Channel 3 length timer + 0xff1b => 0x00, + // 0xFF1C — NR32: Channel 3 output level + 0xff1c => (self.ch3_output_level & 0x03) << 5, + + // 0xFF20 — NR41: Channel 4 length timer + 0xff20 => 0x00, + // 0xFF21 — NR42: Channel 4 volume & envelope + 0xff21 => { + (self.ch4_pace & 0x07) + | ((self.ch4_direction & 0x01) << 3) + | ((self.ch4_volume & 0x0f) << 4) + } // 0xFF25 — NR51: Sound panning 0xff25 => self.glob_panning, diff --git a/src/cpu.rs b/src/cpu.rs index 440c5995..4c8232dc 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -327,6 +327,11 @@ impl Cpu { self.mmu().ppu() } + #[inline(always)] + pub fn ppu_i(&self) -> &Ppu { + self.mmu_i().ppu_i() + } + #[inline(always)] pub fn apu(&mut self) -> &mut Apu { self.mmu().apu() diff --git a/src/gb.rs b/src/gb.rs index 7339d0e4..f0990106 100644 --- a/src/gb.rs +++ b/src/gb.rs @@ -105,6 +105,13 @@ impl GameBoySpeed { } } + pub fn multiplier(&self) -> u8 { + match self { + GameBoySpeed::Normal => 1, + GameBoySpeed::Double => 2, + } + } + pub fn from_u8(value: u8) -> GameBoySpeed { match value { 0 => GameBoySpeed::Normal, @@ -385,11 +392,12 @@ impl GameBoy { pub fn clock(&mut self) -> u8 { let cycles = self.cpu_clock(); + let cycles_n = cycles / self.mmu().speed.multiplier(); if self.ppu_enabled { - self.ppu_clock(cycles); + self.ppu_clock(cycles_n); } if self.apu_enabled { - self.apu_clock(cycles); + self.apu_clock(cycles_n); } if self.dma_enabled { self.dma_clock(cycles); @@ -628,6 +636,10 @@ impl GameBoy { self.mode == GameBoyMode::Sgb } + pub fn speed(&self) -> GameBoySpeed { + self.mmu_i().speed + } + pub fn mode(&self) -> GameBoyMode { self.mode } @@ -774,10 +786,18 @@ impl GameBoy { self.cpu.mmu() } + pub fn mmu_i(&self) -> &Mmu { + self.cpu.mmu_i() + } + pub fn ppu(&mut self) -> &mut Ppu { self.cpu.ppu() } + pub fn ppu_i(&self) -> &Ppu { + self.cpu.ppu_i() + } + pub fn apu(&mut self) -> &mut Apu { self.cpu.apu() } diff --git a/src/mmu.rs b/src/mmu.rs index bc7f82f3..9b9b792b 100644 --- a/src/mmu.rs +++ b/src/mmu.rs @@ -10,7 +10,6 @@ use crate::{ rom::Cartridge, serial::Serial, timer::Timer, - warnln, }; pub const BOOT_SIZE_DMG: usize = 256; @@ -157,6 +156,10 @@ impl Mmu { &mut self.ppu } + pub fn ppu_i(&self) -> &Ppu { + &self.ppu + } + pub fn apu(&mut self) -> &mut Apu { &mut self.apu } @@ -387,12 +390,6 @@ impl Mmu { // 0xFF4D - KEY1: Speed switching (CGB only) 0x4d => { - warnln!("Switching speed is not yet implemented"); - - // @TODO: The switching of CPU speed is not yet - // implemented and required more work to be done. - // Inclusive the propagation of the speed to the - // controller emulator. self.switching = value & 0x01 == 0x01; } -- GitLab