diff --git a/crates/common/src/data.rs b/crates/common/src/data.rs new file mode 100644 index 0000000000000000000000000000000000000000..1f3973d0254ade14341a8bcbc5f03e31911d5da9 --- /dev/null +++ b/crates/common/src/data.rs @@ -0,0 +1,24 @@ +use std::io::{Cursor, Read}; + +use crate::error::Error; + +#[inline(always)] +pub fn read_u8(data: &mut Cursor<&[u8]>) -> Result<u8, Error> { + let mut buffer = [0x00; size_of::<u8>()]; + data.read_exact(&mut buffer)?; + Ok(u8::from_le_bytes(buffer)) +} + +#[inline(always)] +pub fn read_u16(data: &mut Cursor<&[u8]>) -> Result<u16, Error> { + let mut buffer = [0x00; size_of::<u16>()]; + data.read_exact(&mut buffer)?; + Ok(u16::from_le_bytes(buffer)) +} + +#[inline(always)] +pub fn read_u32(data: &mut Cursor<&[u8]>) -> Result<u32, Error> { + let mut buffer = [0x00; size_of::<u32>()]; + data.read_exact(&mut buffer)?; + Ok(u32::from_le_bytes(buffer)) +} diff --git a/crates/common/src/lib.rs b/crates/common/src/lib.rs index 797c52e5250c248771e5477d0b4921dbe1914dfc..80b89fc55323c46655947f8263ed41119e2c736d 100644 --- a/crates/common/src/lib.rs +++ b/crates/common/src/lib.rs @@ -1,4 +1,5 @@ pub mod bench; +pub mod data; pub mod error; pub mod util; diff --git a/src/timer.rs b/src/timer.rs index 2fe4038f74142aad62afa6be2b8d9f8bd4a02724..e902ea850b618d346b1fca35f259ca015c038604 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -1,9 +1,18 @@ //! Timer functions and structures. +use std::io::{Cursor, Write}; + +use boytacean_common::{ + data::{read_u16, read_u8}, + error::Error, +}; + use crate::{ consts::{DIV_ADDR, TAC_ADDR, TIMA_ADDR, TMA_ADDR}, mmu::BusComponent, - panic_gb, warnln, + panic_gb, + state::StateComponent, + warnln, }; pub struct Timer { @@ -161,8 +170,75 @@ impl BusComponent for Timer { } } +impl StateComponent for Timer { + fn state(&self) -> Result<Vec<u8>, Error> { + let mut cursor = Cursor::new(vec![]); + cursor.write(&self.div.to_le_bytes())?; + cursor.write(&self.tima.to_le_bytes())?; + cursor.write(&self.tma.to_le_bytes())?; + cursor.write(&self.tac.to_le_bytes())?; + cursor.write(&self.div_clock.to_le_bytes())?; + cursor.write(&self.tima_clock.to_le_bytes())?; + cursor.write(&(self.tima_enabled as u8).to_le_bytes())?; + cursor.write(&self.tima_ratio.to_le_bytes())?; + cursor.write(&(self.int_tima as u8).to_le_bytes())?; + Ok(cursor.into_inner()) + } + + fn set_state(&mut self, data: &[u8]) -> Result<(), boytacean_common::error::Error> { + let mut cursor = Cursor::new(data); + self.div = read_u8(&mut cursor)?; + self.tima = read_u8(&mut cursor)?; + self.tma = read_u8(&mut cursor)?; + self.tac = read_u8(&mut cursor)?; + self.div_clock = read_u16(&mut cursor)?; + self.tima_clock = read_u16(&mut cursor)?; + self.tima_enabled = read_u8(&mut cursor)? == 1; + self.tima_ratio = read_u16(&mut cursor)?; + self.int_tima = read_u8(&mut cursor)? == 1; + Ok(()) + } +} + impl Default for Timer { fn default() -> Self { Self::new() } } + +#[cfg(test)] +mod tests { + use super::Timer; + + use crate::state::StateComponent; + + #[test] + fn test_state_and_set_state() { + let mut timer = Timer::new(); + timer.div = 0x12; + timer.tima = 0x34; + timer.tma = 0x56; + timer.tac = 0x78; + timer.div_clock = 0x9abc; + timer.tima_clock = 0xdef0; + timer.tima_enabled = true; + timer.tima_ratio = 0x1234; + timer.int_tima = true; + + let state = timer.state().unwrap(); + assert_eq!(state.len(), 12); + + let mut new_timer = Timer::new(); + new_timer.set_state(&state).unwrap(); + + assert_eq!(timer.div, new_timer.div); + assert_eq!(timer.tima, new_timer.tima); + assert_eq!(timer.tma, new_timer.tma); + assert_eq!(timer.tac, new_timer.tac); + assert_eq!(timer.div_clock, new_timer.div_clock); + assert_eq!(timer.tima_clock, new_timer.tima_clock); + assert_eq!(timer.tima_enabled, new_timer.tima_enabled); + assert_eq!(timer.tima_ratio, new_timer.tima_ratio); + assert_eq!(timer.int_tima, new_timer.int_tima); + } +}