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);
+    }
+}