diff --git a/frontends/sdl/src/main.rs b/frontends/sdl/src/main.rs
index 6e51071513fc53e243cea2930d2bb01bde721cc7..62b394779ec564aba4822170c7e7e555d43643fe 100644
--- a/frontends/sdl/src/main.rs
+++ b/frontends/sdl/src/main.rs
@@ -13,6 +13,7 @@ use boytacean::{
     ppu::{PaletteInfo, PpuMode},
     rom::Cartridge,
     serial::{NullDevice, SerialDevice},
+    util::{replace_ext, write_file},
 };
 use chrono::Utc;
 use clap::Parser;
@@ -38,6 +39,10 @@ const TITLE: &str = "Boytacean";
 /// amplification level of the volume
 const VOLUME: f32 = 64.0;
 
+/// The rate (in seconds) at which the current battery
+/// backed RAM is going to be stored into the file system.
+const STORE_RATE: u8 = 5;
+
 pub struct Benchmark {
     count: usize,
     cpu_only: Option<bool>,
@@ -69,6 +74,7 @@ pub struct Emulator {
     audio: Option<Audio>,
     title: &'static str,
     rom_path: String,
+    ram_path: String,
     logic_frequency: u32,
     visual_frequency: f32,
     next_tick_time: f32,
@@ -88,6 +94,7 @@ impl Emulator {
             audio: None,
             title: TITLE,
             rom_path: String::from("invalid"),
+            ram_path: String::from("invalid"),
             logic_frequency: GameBoy::CPU_FREQ,
             visual_frequency: GameBoy::VISUAL_FREQ,
             next_tick_time: 0.0,
@@ -202,8 +209,16 @@ impl Emulator {
     }
 
     pub fn load_rom(&mut self, path: Option<&str>) {
-        let path_res = path.unwrap_or(&self.rom_path);
-        let rom = self.system.load_rom_file(path_res);
+        let rom_path: &str = path.unwrap_or(&self.rom_path);
+        let ram_path = replace_ext(rom_path, "sav").unwrap_or("invalid".to_string());
+        let rom = self.system.load_rom_file(
+            rom_path,
+            if Path::new(&ram_path).exists() {
+                Some(&ram_path)
+            } else {
+                None
+            },
+        );
         println!(
             "========= Cartridge =========\n{}\n=============================",
             rom
@@ -213,7 +228,8 @@ impl Emulator {
                 .set_title(format!("{} [{}]", self.title, rom.title()).as_str())
                 .unwrap();
         }
-        self.rom_path = String::from(path_res);
+        self.rom_path = String::from(rom_path);
+        self.ram_path = ram_path;
     }
 
     pub fn reset(&mut self) {
@@ -305,6 +321,10 @@ impl Emulator {
             .create_texture_streaming(PixelFormatEnum::RGB24, width as u32, height as u32)
             .unwrap();
 
+        // calculates the rate as visual cycles that will take from
+        // the current visual frequency to re-save the battery backed RAM
+        let store_count = (self.visual_frequency * STORE_RATE as f32).round() as u32;
+
         // starts the variable that will control the number of cycles that
         // are going to move (because of overflow) from one tick to another
         let mut pending_cycles = 0u32;
@@ -320,6 +340,14 @@ impl Emulator {
             // on the number of visual ticks since beginning
             counter = counter.wrapping_add(1);
 
+            // in case the current counter is a multiple of the store rate
+            // then we've reached the time to re-save the battery backed RAM
+            // into a *.sav file in the file system
+            if counter % store_count == 0 && self.system.rom().has_battery() {
+                let ram_data = self.system.ram_data_eager();
+                write_file(&self.ram_path, ram_data);
+            }
+
             // obtains an event from the SDL sub-system to be
             // processed under the current emulation context
             while let Some(event) = self.sdl.as_mut().unwrap().event_pump.poll_event() {
diff --git a/src/gb.rs b/src/gb.rs
index 87b2379fa0412c2186a5e3b463fc3c05904f5778..84191d0f22d2fcb27ed1b48a688687f5ea97e22d 100644
--- a/src/gb.rs
+++ b/src/gb.rs
@@ -642,7 +642,7 @@ impl GameBoy {
     }
 
     pub fn set_ram_data(&mut self, ram_data: Vec<u8>) {
-        self.mmu().rom().set_ram_data(ram_data)
+        self.mmu().rom().set_ram_data(&ram_data)
     }
 
     pub fn registers(&mut self) -> Registers {
@@ -974,15 +974,24 @@ impl GameBoy {
         self.load_boot_file(BootRom::Cgb);
     }
 
-    pub fn load_rom(&mut self, data: &[u8]) -> &mut Cartridge {
-        let rom = Cartridge::from_data(data);
+    pub fn load_rom(&mut self, data: &[u8], ram_data: Option<&[u8]>) -> &mut Cartridge {
+        let mut rom = Cartridge::from_data(data);
+        if let Some(ram_data) = ram_data {
+            rom.set_ram_data(ram_data)
+        }
         self.mmu().set_rom(rom);
         self.mmu().rom()
     }
 
-    pub fn load_rom_file(&mut self, path: &str) -> &mut Cartridge {
+    pub fn load_rom_file(&mut self, path: &str, ram_path: Option<&str>) -> &mut Cartridge {
         let data = read_file(path);
-        self.load_rom(&data)
+        match ram_path {
+            Some(ram_path) => {
+                let ram_data = read_file(ram_path);
+                self.load_rom(&data, Some(&ram_data))
+            }
+            None => self.load_rom(&data, None),
+        }
     }
 
     pub fn attach_serial(&mut self, device: Box<dyn SerialDevice>) {
@@ -1006,7 +1015,7 @@ impl GameBoy {
     }
 
     pub fn load_rom_ws(&mut self, data: &[u8]) -> Cartridge {
-        let rom = self.load_rom(data);
+        let rom = self.load_rom(data, None);
         rom.set_rumble_cb(|active| {
             rumble_callback(active);
         });
diff --git a/src/rom.rs b/src/rom.rs
index 90d0545d79e229ef11f8b7771710a8d63082443b..f793667fa3d84c9f5c63627effbd6ae50f3a08e6 100644
--- a/src/rom.rs
+++ b/src/rom.rs
@@ -587,12 +587,16 @@ impl Cartridge {
         )
     }
 
+    pub fn rom_data_eager(&self) -> Vec<u8> {
+        self.rom_data.clone()
+    }
+
     pub fn ram_data_eager(&self) -> Vec<u8> {
         self.ram_data.clone()
     }
 
-    pub fn set_ram_data(&mut self, ram_data: Vec<u8>) {
-        self.ram_data = ram_data;
+    pub fn set_ram_data(&mut self, data: &[u8]) {
+        self.ram_data = data.to_vec();
     }
 
     pub fn description(&self, column_length: usize) -> String {
diff --git a/src/test.rs b/src/test.rs
index 43f4ab89ff59b349ed930df205036c2ff9dfe67e..ff38d784b70cb9379c89a7adf2e09d2b0b844ab0 100644
--- a/src/test.rs
+++ b/src/test.rs
@@ -30,7 +30,7 @@ pub fn run_test(rom_path: &str, max_cycles: Option<u64>, options: TestOptions) -
     let max_cycles = max_cycles.unwrap_or(u64::MAX);
 
     let mut game_boy = build_test(options);
-    game_boy.load_rom_file(rom_path);
+    game_boy.load_rom_file(rom_path, None);
 
     loop {
         cycles += game_boy.clock() as u64;
diff --git a/src/util.rs b/src/util.rs
index 96776eecc5b692c096fae2dabd603f119a988465..c73eff41fd7821316ab0e5e1e46bcccb98fe1559 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -1,4 +1,10 @@
-use std::{cell::RefCell, fs::File, io::Read, rc::Rc};
+use std::{
+    cell::RefCell,
+    fs::File,
+    io::{Read, Write},
+    path::Path,
+    rc::Rc,
+};
 
 pub type SharedMut<T> = Rc<RefCell<T>>;
 
@@ -11,3 +17,61 @@ pub fn read_file(path: &str) -> Vec<u8> {
     file.read_to_end(&mut data).unwrap();
     data
 }
+
+pub fn write_file(path: &str, data: Vec<u8>) {
+    let mut file = match File::create(path) {
+        Ok(file) => file,
+        Err(_) => panic!("Failed to open file: {}", path),
+    };
+    file.write_all(&data).unwrap()
+}
+
+/// Replaces the extension in the given path with the provided extension.
+/// This function allows for simple associated file discovery.
+pub fn replace_ext(path: &str, new_extension: &str) -> Option<String> {
+    let file_path = Path::new(path);
+    let parent_dir = file_path.parent()?;
+    let file_stem = file_path.file_stem()?;
+    let file_extension = file_path.extension()?;
+    if file_stem == file_extension {
+        return None;
+    }
+    let new_file_name = format!("{}.{}", file_stem.to_str()?, new_extension);
+    let new_file_path = parent_dir.join(new_file_name);
+    Some(String::from(new_file_path.to_str()?))
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_change_extension() {
+        let new_path = replace_ext("/path/to/file.txt", "dat").unwrap();
+        assert_eq!(
+            new_path,
+            Path::new("/path/to").join("file.dat").to_str().unwrap()
+        );
+
+        let new_path = replace_ext("/path/to/file.with.multiple.dots.txt", "dat").unwrap();
+        assert_eq!(
+            new_path,
+            Path::new("/path/to")
+                .join("file.with.multiple.dots.dat")
+                .to_str()
+                .unwrap()
+        );
+
+        let new_path = replace_ext("/path/to/file.without.extension", "dat").unwrap();
+        assert_eq!(
+            new_path,
+            Path::new("/path/to")
+                .join("file.without.dat")
+                .to_str()
+                .unwrap()
+        );
+
+        let new_path = replace_ext("/path/to/directory/", "dat");
+        assert_eq!(new_path, None);
+    }
+}