From ce3cbf4e41c5a9333ce4b6908f0a695e45189eaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com> Date: Sun, 8 Sep 2024 18:59:17 +0100 Subject: [PATCH] chore: initial APU state setting --- crates/common/src/data.rs | 39 ++++++++ src/apu.rs | 187 +++++++++++++++++++++++++++++++++++++- src/state.rs | 3 + 3 files changed, 228 insertions(+), 1 deletion(-) diff --git a/crates/common/src/data.rs b/crates/common/src/data.rs index 717c2381..c7b03c62 100644 --- a/crates/common/src/data.rs +++ b/crates/common/src/data.rs @@ -11,18 +11,36 @@ pub fn write_u8<W: Write>(writer: &mut W, value: u8) -> Result<(), Error> { Ok(()) } +#[inline(always)] +pub fn write_i8<W: Write>(writer: &mut W, value: i8) -> Result<(), Error> { + writer.write_all(&value.to_le_bytes())?; + Ok(()) +} + #[inline(always)] pub fn write_u16<W: Write>(writer: &mut W, value: u16) -> Result<(), Error> { writer.write_all(&value.to_le_bytes())?; Ok(()) } +#[inline(always)] +pub fn write_i16<W: Write>(writer: &mut W, value: i16) -> Result<(), Error> { + writer.write_all(&value.to_le_bytes())?; + Ok(()) +} + #[inline(always)] pub fn write_u32<W: Write>(writer: &mut W, value: u32) -> Result<(), Error> { writer.write_all(&value.to_le_bytes())?; Ok(()) } +#[inline(always)] +pub fn write_i32<W: Write>(writer: &mut W, value: i32) -> Result<(), Error> { + writer.write_all(&value.to_le_bytes())?; + Ok(()) +} + #[inline(always)] pub fn read_u8<R: Read>(reader: &mut R) -> Result<u8, Error> { let mut buffer = [0x00; size_of::<u8>()]; @@ -30,6 +48,13 @@ pub fn read_u8<R: Read>(reader: &mut R) -> Result<u8, Error> { Ok(u8::from_le_bytes(buffer)) } +#[inline(always)] +pub fn read_i8<R: Read>(reader: &mut R) -> Result<i8, Error> { + let mut buffer = [0x00; size_of::<i8>()]; + reader.read_exact(&mut buffer)?; + Ok(i8::from_le_bytes(buffer)) +} + #[inline(always)] pub fn read_u16<R: Read>(reader: &mut R) -> Result<u16, Error> { let mut buffer = [0x00; size_of::<u16>()]; @@ -37,6 +62,13 @@ pub fn read_u16<R: Read>(reader: &mut R) -> Result<u16, Error> { Ok(u16::from_le_bytes(buffer)) } +#[inline(always)] +pub fn read_i16<R: Read>(reader: &mut R) -> Result<i16, Error> { + let mut buffer = [0x00; size_of::<i16>()]; + reader.read_exact(&mut buffer)?; + Ok(i16::from_le_bytes(buffer)) +} + #[inline(always)] pub fn read_u32<R: Read>(reader: &mut R) -> Result<u32, Error> { let mut buffer = [0x00; size_of::<u32>()]; @@ -44,6 +76,13 @@ pub fn read_u32<R: Read>(reader: &mut R) -> Result<u32, Error> { Ok(u32::from_le_bytes(buffer)) } +#[inline(always)] +pub fn read_i32<R: Read>(reader: &mut R) -> Result<i32, Error> { + let mut buffer = [0x00; size_of::<i32>()]; + reader.read_exact(&mut buffer)?; + Ok(i32::from_le_bytes(buffer)) +} + #[inline(always)] pub fn read_bytes<R: Read>(reader: &mut R, count: usize) -> Result<Vec<u8>, Error> { let mut buffer = vec![0; count]; diff --git a/src/apu.rs b/src/apu.rs index abd68c30..eb125ffc 100644 --- a/src/apu.rs +++ b/src/apu.rs @@ -1,6 +1,14 @@ //! APU (Audio Processing Unit) functions and structures. -use std::collections::VecDeque; +use std::{ + collections::VecDeque, + io::{Cursor, Read, Write}, +}; + +use boytacean_common::{ + data::{read_i16, read_i32, read_u16, read_u8, write_i16, write_i32, write_u16, write_u8}, + error::Error, +}; use crate::{ consts::{ @@ -10,6 +18,7 @@ use crate::{ }, gb::GameBoy, mmu::BusComponent, + state::StateComponent, warnln, }; @@ -1158,6 +1167,182 @@ impl BusComponent for Apu { } } +impl StateComponent for Apu { + fn state(&self) -> Result<Vec<u8>, Error> { + let mut cursor = Cursor::new(vec![]); + + write_i16(&mut cursor, self.ch1_timer)?; + write_u8(&mut cursor, self.ch1_sequence)?; + write_u8(&mut cursor, self.ch1_envelope_sequence)?; + write_u8(&mut cursor, self.ch1_envelope_enabled as u8)?; + write_u8(&mut cursor, self.ch1_sweep_sequence)?; + write_u8(&mut cursor, self.ch1_output)?; + write_u8(&mut cursor, self.ch1_dac as u8)?; + write_u8(&mut cursor, self.ch1_sweep_slope)?; + write_u8(&mut cursor, self.ch1_sweep_increase as u8)?; + write_u8(&mut cursor, self.ch1_sweep_pace)?; + write_u8(&mut cursor, self.ch1_length_timer)?; + write_u8(&mut cursor, self.ch1_wave_duty)?; + write_u8(&mut cursor, self.ch1_pace)?; + write_u8(&mut cursor, self.ch1_direction)?; + write_u8(&mut cursor, self.ch1_volume)?; + write_u16(&mut cursor, self.ch1_wave_length)?; + write_u8(&mut cursor, self.ch1_length_enabled as u8)?; + write_u8(&mut cursor, self.ch1_enabled as u8)?; + + write_i16(&mut cursor, self.ch2_timer)?; + write_u8(&mut cursor, self.ch2_sequence)?; + write_u8(&mut cursor, self.ch2_envelope_sequence)?; + write_u8(&mut cursor, self.ch2_envelope_enabled as u8)?; + write_u8(&mut cursor, self.ch2_output)?; + write_u8(&mut cursor, self.ch2_dac as u8)?; + write_u8(&mut cursor, self.ch2_length_timer)?; + write_u8(&mut cursor, self.ch2_wave_duty)?; + write_u8(&mut cursor, self.ch2_pace)?; + write_u8(&mut cursor, self.ch2_direction)?; + write_u8(&mut cursor, self.ch2_volume)?; + write_u16(&mut cursor, self.ch2_wave_length)?; + write_u8(&mut cursor, self.ch2_length_enabled as u8)?; + write_u8(&mut cursor, self.ch2_enabled as u8)?; + + write_i16(&mut cursor, self.ch3_timer)?; + write_u8(&mut cursor, self.ch3_position)?; + write_u8(&mut cursor, self.ch3_output)?; + write_u8(&mut cursor, self.ch3_dac as u8)?; + write_u16(&mut cursor, self.ch3_length_timer)?; + write_u8(&mut cursor, self.ch3_output_level)?; + write_u16(&mut cursor, self.ch3_wave_length)?; + write_u8(&mut cursor, self.ch3_length_enabled as u8)?; + write_u8(&mut cursor, self.ch3_enabled as u8)?; + + write_i32(&mut cursor, self.ch4_timer)?; + write_u8(&mut cursor, self.ch4_envelope_sequence)?; + write_u8(&mut cursor, self.ch4_envelope_enabled as u8)?; + write_u8(&mut cursor, self.ch4_output)?; + write_u8(&mut cursor, self.ch4_dac as u8)?; + write_u8(&mut cursor, self.ch4_length_timer)?; + write_u8(&mut cursor, self.ch4_pace)?; + write_u8(&mut cursor, self.ch4_direction)?; + write_u8(&mut cursor, self.ch4_volume)?; + write_u8(&mut cursor, self.ch4_divisor)?; + write_u8(&mut cursor, self.ch4_width_mode as u8)?; + write_u8(&mut cursor, self.ch4_clock_shift)?; + write_u16(&mut cursor, self.ch4_lfsr)?; + write_u8(&mut cursor, self.ch4_length_enabled as u8)?; + write_u8(&mut cursor, self.ch4_enabled as u8)?; + + write_u8(&mut cursor, self.master)?; + write_u8(&mut cursor, self.glob_panning)?; + + write_u8(&mut cursor, self.right_enabled as u8)?; + write_u8(&mut cursor, self.left_enabled as u8)?; + write_u8(&mut cursor, self.sound_enabled as u8)?; + + write_u8(&mut cursor, self.ch1_out_enabled as u8)?; + write_u8(&mut cursor, self.ch2_out_enabled as u8)?; + write_u8(&mut cursor, self.ch3_out_enabled as u8)?; + write_u8(&mut cursor, self.ch4_out_enabled as u8)?; + + cursor.write(&self.wave_ram)?; + + write_u16(&mut cursor, self.sampling_rate)?; + write_u8(&mut cursor, self.channels)?; + + write_u16(&mut cursor, self.sequencer)?; + write_u8(&mut cursor, self.sequencer_step)?; + write_i16(&mut cursor, self.output_timer)?; + + Ok(cursor.into_inner()) + } + + fn set_state(&mut self, data: &[u8]) -> Result<(), Error> { + let mut cursor = Cursor::new(data); + + self.ch1_timer = read_i16(&mut cursor)?; + self.ch1_sequence = read_u8(&mut cursor)?; + self.ch1_envelope_sequence = read_u8(&mut cursor)?; + self.ch1_envelope_enabled = read_u8(&mut cursor)? != 0; + self.ch1_sweep_sequence = read_u8(&mut cursor)?; + self.ch1_output = read_u8(&mut cursor)?; + self.ch1_dac = read_u8(&mut cursor)? != 0; + self.ch1_sweep_slope = read_u8(&mut cursor)?; + self.ch1_sweep_increase = read_u8(&mut cursor)? != 0; + self.ch1_sweep_pace = read_u8(&mut cursor)?; + self.ch1_length_timer = read_u8(&mut cursor)?; + self.ch1_wave_duty = read_u8(&mut cursor)?; + self.ch1_pace = read_u8(&mut cursor)?; + self.ch1_direction = read_u8(&mut cursor)?; + self.ch1_volume = read_u8(&mut cursor)?; + self.ch1_wave_length = read_u16(&mut cursor)?; + self.ch1_length_enabled = read_u8(&mut cursor)? != 0; + self.ch1_enabled = read_u8(&mut cursor)? != 0; + + self.ch2_timer = read_i16(&mut cursor)?; + self.ch2_sequence = read_u8(&mut cursor)?; + self.ch2_envelope_sequence = read_u8(&mut cursor)?; + self.ch2_envelope_enabled = read_u8(&mut cursor)? != 0; + self.ch2_output = read_u8(&mut cursor)?; + self.ch2_dac = read_u8(&mut cursor)? != 0; + self.ch2_length_timer = read_u8(&mut cursor)?; + self.ch2_wave_duty = read_u8(&mut cursor)?; + self.ch2_pace = read_u8(&mut cursor)?; + self.ch2_direction = read_u8(&mut cursor)?; + self.ch2_volume = read_u8(&mut cursor)?; + self.ch2_wave_length = read_u16(&mut cursor)?; + self.ch2_length_enabled = read_u8(&mut cursor)? != 0; + self.ch2_enabled = read_u8(&mut cursor)? != 0; + + self.ch3_timer = read_i16(&mut cursor)?; + self.ch3_position = read_u8(&mut cursor)?; + self.ch3_output = read_u8(&mut cursor)?; + self.ch3_dac = read_u8(&mut cursor)? != 0; + self.ch3_length_timer = read_u16(&mut cursor)?; + self.ch3_output_level = read_u8(&mut cursor)?; + self.ch3_wave_length = read_u16(&mut cursor)?; + self.ch3_length_enabled = read_u8(&mut cursor)? != 0; + self.ch3_enabled = read_u8(&mut cursor)? != 0; + + self.ch4_timer = read_i32(&mut cursor)?; + self.ch4_envelope_sequence = read_u8(&mut cursor)?; + self.ch4_envelope_enabled = read_u8(&mut cursor)? != 0; + self.ch4_output = read_u8(&mut cursor)?; + self.ch4_dac = read_u8(&mut cursor)? != 0; + self.ch4_length_timer = read_u8(&mut cursor)?; + self.ch4_pace = read_u8(&mut cursor)?; + self.ch4_direction = read_u8(&mut cursor)?; + self.ch4_volume = read_u8(&mut cursor)?; + self.ch4_divisor = read_u8(&mut cursor)?; + self.ch4_width_mode = read_u8(&mut cursor)? != 0; + self.ch4_clock_shift = read_u8(&mut cursor)?; + self.ch4_lfsr = read_u16(&mut cursor)?; + self.ch4_length_enabled = read_u8(&mut cursor)? != 0; + self.ch4_enabled = read_u8(&mut cursor)? != 0; + + self.master = read_u8(&mut cursor)?; + self.glob_panning = read_u8(&mut cursor)?; + + self.right_enabled = read_u8(&mut cursor)? != 0; + self.left_enabled = read_u8(&mut cursor)? != 0; + self.sound_enabled = read_u8(&mut cursor)? != 0; + + self.ch1_out_enabled = read_u8(&mut cursor)? != 0; + self.ch2_out_enabled = read_u8(&mut cursor)? != 0; + self.ch3_out_enabled = read_u8(&mut cursor)? != 0; + self.ch4_out_enabled = read_u8(&mut cursor)? != 0; + + cursor.read_exact(&mut self.wave_ram)?; + + self.sampling_rate = read_u16(&mut cursor)?; + self.channels = read_u8(&mut cursor)?; + + self.sequencer = read_u16(&mut cursor)?; + self.sequencer_step = read_u8(&mut cursor)?; + self.output_timer = read_i16(&mut cursor)?; + + Ok(()) + } +} + impl Default for Apu { fn default() -> Self { Self::new(44100, 2, 1.0, GameBoy::CPU_FREQ) diff --git a/src/state.rs b/src/state.rs index 50472ed7..9f87eec8 100644 --- a/src/state.rs +++ b/src/state.rs @@ -514,6 +514,7 @@ impl StateBox for BosState { None }, device_states: vec![ + BosDeviceState::from_gb(gb, GameBoyDevice::Apu)?, BosDeviceState::from_gb(gb, GameBoyDevice::Dma)?, BosDeviceState::from_gb(gb, GameBoyDevice::Timer)?, ], @@ -791,6 +792,7 @@ impl BosDeviceState { fn from_gb(gb: &mut GameBoy, device: GameBoyDevice) -> Result<Self, Error> { match device { + GameBoyDevice::Apu => Ok(Self::new(device, gb.apu_i().state()?)), GameBoyDevice::Dma => Ok(Self::new(device, gb.dma_i().state()?)), GameBoyDevice::Timer => Ok(Self::new(device, gb.timer_i().state()?)), _ => Err(Error::NotImplemented), @@ -799,6 +801,7 @@ impl BosDeviceState { fn to_gb(&self, gb: &mut GameBoy) -> Result<(), Error> { match self.device { + GameBoyDevice::Apu => gb.apu().set_state(&self.state)?, GameBoyDevice::Dma => gb.dma().set_state(&self.state)?, GameBoyDevice::Timer => gb.timer().set_state(&self.state)?, _ => return Err(Error::NotImplemented), -- GitLab