From 8b902ffdd16f93e6e9f99586ffce7535e440083e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com> Date: Tue, 11 Apr 2023 13:29:33 +0100 Subject: [PATCH] chore: support for clock_freq --- frontends/web/ts/gb.ts | 14 ++++++------ src/apu.rs | 19 +++++++++++---- src/cpu.rs | 8 +++---- src/gb.rs | 40 +++++++++++++++++++++++++------- src/inst.rs | 52 +++++++++++++++++++++--------------------- 5 files changed, 84 insertions(+), 49 deletions(-) diff --git a/frontends/web/ts/gb.ts b/frontends/web/ts/gb.ts index b950b328..41554b48 100644 --- a/frontends/web/ts/gb.ts +++ b/frontends/web/ts/gb.ts @@ -562,22 +562,22 @@ export class GameboyEmulator extends EmulatorBase implements Emulator { get compiler(): Compiler | null { if (!this.gameBoy) return null; return { - name: this.gameBoy.get_compiler(), - version: this.gameBoy.get_compiler_version() + name: this.gameBoy.compiler(), + version: this.gameBoy.compiler_version() }; } get compilation(): Compilation | null { if (!this.gameBoy) return null; return { - date: this.gameBoy.get_compilation_date(), - time: this.gameBoy.get_compilation_time() + date: this.gameBoy.compilation_date(), + time: this.gameBoy.compilation_time() }; } get wasmEngine(): string | null { if (!this.gameBoy) return null; - return this.gameBoy.get_wasm_engine_ws() ?? null; + return this.gameBoy.wasm_engine_ws() ?? null; } get framerate(): number { @@ -672,7 +672,7 @@ export class GameboyEmulator extends EmulatorBase implements Emulator { } getVideoState(): boolean { - return this.gameBoy?.get_ppu_enabled() ?? false; + return this.gameBoy?.ppu_enabled() ?? false; } pauseAudio() { @@ -684,7 +684,7 @@ export class GameboyEmulator extends EmulatorBase implements Emulator { } getAudioState(): boolean { - return this.gameBoy?.get_apu_enabled() ?? false; + return this.gameBoy?.apu_enabled() ?? false; } getTile(index: number): Uint8Array { diff --git a/src/apu.rs b/src/apu.rs index 52554305..0473b30f 100644 --- a/src/apu.rs +++ b/src/apu.rs @@ -1,6 +1,6 @@ use std::collections::VecDeque; -use crate::warnln; +use crate::{gb::GameBoy, warnln}; const DUTY_TABLE: [[u8; 8]; 4] = [ [0, 0, 0, 0, 0, 0, 0, 1], @@ -93,10 +93,12 @@ pub struct Apu { output_timer: i16, audio_buffer: VecDeque<u8>, audio_buffer_max: usize, + + clock_freq: u32, } impl Apu { - pub fn new(sampling_rate: u16, buffer_size: f32) -> Self { + pub fn new(sampling_rate: u16, buffer_size: f32, clock_freq: u32) -> Self { Self { ch1_timer: 0, ch1_sequence: 0, @@ -184,6 +186,7 @@ impl Apu { (sampling_rate as f32 * buffer_size) as usize * 2, ), audio_buffer_max: (sampling_rate as f32 * buffer_size) as usize * 2, + clock_freq: clock_freq, } } @@ -312,7 +315,7 @@ impl Apu { // @TODO the CPU clock is hardcoded here, we must handle situations // where there's some kind of overclock, and for that to happen the // current CPU clock must be propagated here - self.output_timer += (4194304.0 / self.sampling_rate as f32) as i16; + self.output_timer += (self.clock_freq as f32 / self.sampling_rate as f32) as i16; } } @@ -555,6 +558,14 @@ impl Apu { self.audio_buffer.clear(); } + pub fn clock_freq(&self) -> u32 { + self.clock_freq + } + + pub fn set_clock_freq(&mut self, value: u32) { + self.clock_freq = value; + } + #[inline(always)] fn tick_length_all(&mut self) { self.tick_length(Channel::Ch1); @@ -831,6 +842,6 @@ impl Apu { impl Default for Apu { fn default() -> Self { - Self::new(44100, 1.0) + Self::new(44100, 1.0, GameBoy::CPU_FREQ) } } diff --git a/src/cpu.rs b/src/cpu.rs index 8f9b95ff..9be9b169 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -427,7 +427,7 @@ impl Cpu { } #[inline(always)] - pub fn get_zero(&self) -> bool { + pub fn zero(&self) -> bool { self.zero } @@ -437,7 +437,7 @@ impl Cpu { } #[inline(always)] - pub fn get_sub(&self) -> bool { + pub fn sub(&self) -> bool { self.sub } @@ -447,7 +447,7 @@ impl Cpu { } #[inline(always)] - pub fn get_half_carry(&self) -> bool { + pub fn half_carry(&self) -> bool { self.half_carry } @@ -457,7 +457,7 @@ impl Cpu { } #[inline(always)] - pub fn get_carry(&self) -> bool { + pub fn carry(&self) -> bool { self.carry } diff --git a/src/gb.rs b/src/gb.rs index c8a873b8..22a8b606 100644 --- a/src/gb.rs +++ b/src/gb.rs @@ -34,9 +34,23 @@ use std::{ #[cfg_attr(feature = "wasm", wasm_bindgen)] pub struct GameBoy { cpu: Cpu, + + /// If the PPU is enabled, it will be clocked. ppu_enabled: bool, + + /// If the APU is enabled, it will be clocked. apu_enabled: bool, + + /// If the timer is enabled, it will be clocked. timer_enabled: bool, + + /// The current frequency at which the Game Boy + /// emulator is being handled. This is a "hint" that + /// may help components to adjust their internal + /// logic to match the current frequency. For example + /// the APU will adjust its internal clock to match + /// this hint. + clock_freq: u32, } #[cfg_attr(feature = "wasm", wasm_bindgen)] @@ -79,6 +93,7 @@ impl GameBoy { ppu_enabled: true, apu_enabled: true, timer_enabled: true, + clock_freq: GameBoy::CPU_FREQ, } } @@ -270,23 +285,23 @@ impl GameBoy { /// Obtains the name of the compiler that has been /// used in the compilation of the base Boytacean /// library. Can be used for diagnostics. - pub fn get_compiler(&self) -> String { + pub fn compiler(&self) -> String { String::from(COMPILER) } - pub fn get_compiler_version(&self) -> String { + pub fn compiler_version(&self) -> String { String::from(COMPILER_VERSION) } - pub fn get_compilation_date(&self) -> String { + pub fn compilation_date(&self) -> String { String::from(COMPILATION_DATE) } - pub fn get_compilation_time(&self) -> String { + pub fn compilation_time(&self) -> String { String::from(COMPILATION_TIME) } - pub fn get_ppu_enabled(&self) -> bool { + pub fn ppu_enabled(&self) -> bool { self.ppu_enabled } @@ -294,7 +309,7 @@ impl GameBoy { self.ppu_enabled = value; } - pub fn get_apu_enabled(&self) -> bool { + pub fn apu_enabled(&self) -> bool { self.apu_enabled } @@ -302,13 +317,22 @@ impl GameBoy { self.apu_enabled = value; } - pub fn get_timer_enabled(&self) -> bool { + pub fn timer_enabled(&self) -> bool { self.apu_enabled } pub fn set_timer_enabled(&mut self, value: bool) { self.timer_enabled = value; } + + pub fn clock_freq(&self) -> u32 { + self.clock_freq + } + + pub fn set_clock_freq(&mut self, value: u32) { + self.clock_freq = value; + self.apu().set_clock_freq(value); + } } /// Gameboy implementations that are meant with performance @@ -426,7 +450,7 @@ impl GameBoy { self.ppu().set_palette_colors(&palette); } - pub fn get_wasm_engine_ws(&self) -> Option<String> { + pub fn wasm_engine_ws(&self) -> Option<String> { let dependencies = dependencies_map(); if !dependencies.contains_key("wasm-bindgen") { return None; diff --git a/src/inst.rs b/src/inst.rs index b19487d5..8b059a59 100644 --- a/src/inst.rs +++ b/src/inst.rs @@ -711,7 +711,7 @@ fn ld_d_u8(cpu: &mut Cpu) { } fn rla(cpu: &mut Cpu) { - let carry = cpu.get_carry(); + let carry = cpu.carry(); cpu.set_carry(cpu.a & 0x80 == 0x80); @@ -769,7 +769,7 @@ fn ld_e_u8(cpu: &mut Cpu) { } fn rra(cpu: &mut Cpu) { - let carry = cpu.get_carry(); + let carry = cpu.carry(); cpu.set_carry((cpu.a & 0x1) == 0x1); @@ -783,7 +783,7 @@ fn rra(cpu: &mut Cpu) { fn jr_nz_i8(cpu: &mut Cpu) { let byte = cpu.read_u8() as i8; - if cpu.get_zero() { + if cpu.zero() { return; } @@ -836,16 +836,16 @@ fn daa(cpu: &mut Cpu) { let a = cpu.a; let mut adjust = 0; - if cpu.get_half_carry() { + if cpu.half_carry() { adjust |= 0x06; } - if cpu.get_carry() { + if cpu.carry() { // Yes, we have to adjust it. adjust |= 0x60; } - let res = if cpu.get_sub() { + let res = if cpu.sub() { a.wrapping_sub(adjust) } else { if a & 0x0f > 0x09 { @@ -869,7 +869,7 @@ fn daa(cpu: &mut Cpu) { fn jr_z_i8(cpu: &mut Cpu) { let byte = cpu.read_u8() as i8; - if !cpu.get_zero() { + if !cpu.zero() { return; } @@ -933,7 +933,7 @@ fn ld_sp_u16(cpu: &mut Cpu) { fn jr_nc_i8(cpu: &mut Cpu) { let byte = cpu.read_u8() as i8; - if cpu.get_carry() { + if cpu.carry() { return; } @@ -986,7 +986,7 @@ fn scf(cpu: &mut Cpu) { fn jr_c_i8(cpu: &mut Cpu) { let byte = cpu.read_u8() as i8; - if !cpu.get_carry() { + if !cpu.carry() { return; } @@ -1039,7 +1039,7 @@ fn ld_a_u8(cpu: &mut Cpu) { fn ccf(cpu: &mut Cpu) { cpu.set_sub(false); cpu.set_half_carry(false); - cpu.set_carry(!cpu.get_carry()); + cpu.set_carry(!cpu.carry()); } fn ld_b_b(_cpu: &mut Cpu) {} @@ -1676,7 +1676,7 @@ fn cp_a_a(cpu: &mut Cpu) { } fn ret_nz(cpu: &mut Cpu) { - if cpu.get_zero() { + if cpu.zero() { return; } @@ -1692,7 +1692,7 @@ fn pop_bc(cpu: &mut Cpu) { fn jp_nz_u16(cpu: &mut Cpu) { let word = cpu.read_u16(); - if cpu.get_zero() { + if cpu.zero() { return; } @@ -1708,7 +1708,7 @@ fn jp_u16(cpu: &mut Cpu) { fn call_nz_u16(cpu: &mut Cpu) { let word = cpu.read_u16(); - if cpu.get_zero() { + if cpu.zero() { return; } @@ -1731,7 +1731,7 @@ fn rst_00h(cpu: &mut Cpu) { } fn ret_z(cpu: &mut Cpu) { - if !cpu.get_zero() { + if !cpu.zero() { return; } @@ -1746,7 +1746,7 @@ fn ret(cpu: &mut Cpu) { fn jp_z_u16(cpu: &mut Cpu) { let word = cpu.read_u16(); - if !cpu.get_zero() { + if !cpu.zero() { return; } @@ -1757,7 +1757,7 @@ fn jp_z_u16(cpu: &mut Cpu) { fn call_z_u16(cpu: &mut Cpu) { let word = cpu.read_u16(); - if !cpu.get_zero() { + if !cpu.zero() { return; } @@ -1782,7 +1782,7 @@ fn rst_08h(cpu: &mut Cpu) { } fn ret_nc(cpu: &mut Cpu) { - if cpu.get_carry() { + if cpu.carry() { return; } @@ -1798,7 +1798,7 @@ fn pop_de(cpu: &mut Cpu) { fn jp_nc_u16(cpu: &mut Cpu) { let word = cpu.read_u16(); - if cpu.get_carry() { + if cpu.carry() { return; } @@ -1809,7 +1809,7 @@ fn jp_nc_u16(cpu: &mut Cpu) { fn call_nc_u16(cpu: &mut Cpu) { let word = cpu.read_u16(); - if cpu.get_carry() { + if cpu.carry() { return; } @@ -1832,7 +1832,7 @@ fn rst_10h(cpu: &mut Cpu) { } fn ret_c(cpu: &mut Cpu) { - if !cpu.get_carry() { + if !cpu.carry() { return; } @@ -1848,7 +1848,7 @@ fn reti(cpu: &mut Cpu) { fn jp_c_u16(cpu: &mut Cpu) { let word = cpu.read_u16(); - if !cpu.get_carry() { + if !cpu.carry() { return; } @@ -1859,7 +1859,7 @@ fn jp_c_u16(cpu: &mut Cpu) { fn call_c_u16(cpu: &mut Cpu) { let word = cpu.read_u16(); - if !cpu.get_carry() { + if !cpu.carry() { return; } @@ -3132,7 +3132,7 @@ fn res(value: u8, bit: u8) -> u8 { /// byte (probably from a register) and updates the /// proper flag registers. fn rl(cpu: &mut Cpu, value: u8) -> u8 { - let carry = cpu.get_carry(); + let carry = cpu.carry(); cpu.set_carry((value & 0x80) == 0x80); @@ -3161,7 +3161,7 @@ fn rlc(cpu: &mut Cpu, value: u8) -> u8 { /// byte (probably from a register) and updates the /// proper flag registers. fn rr(cpu: &mut Cpu, value: u8) -> u8 { - let carry = cpu.get_carry(); + let carry = cpu.carry(); cpu.set_carry((value & 0x1) == 0x1); @@ -3259,7 +3259,7 @@ fn add_set_flags(cpu: &mut Cpu, first: u8, second: u8) -> u8 { fn add_carry_set_flags(cpu: &mut Cpu, first: u8, second: u8) -> u8 { let first = first as u32; let second = second as u32; - let carry = cpu.get_carry() as u32; + let carry = cpu.carry() as u32; let result = first.wrapping_add(second).wrapping_add(carry); let result_b = result as u8; @@ -3290,7 +3290,7 @@ fn sub_set_flags(cpu: &mut Cpu, first: u8, second: u8) -> u8 { fn sub_carry_set_flags(cpu: &mut Cpu, first: u8, second: u8) -> u8 { let first = first as u32; let second = second as u32; - let carry = cpu.get_carry() as u32; + let carry = cpu.carry() as u32; let result = first.wrapping_sub(second).wrapping_sub(carry); let result_b = result as u8; -- GitLab