aboutsummaryrefslogtreecommitdiff
path: root/src/io.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/io.rs')
-rw-r--r--src/io.rs45
1 files changed, 27 insertions, 18 deletions
diff --git a/src/io.rs b/src/io.rs
index 3e7330e..b26533a 100644
--- a/src/io.rs
+++ b/src/io.rs
@@ -1,13 +1,14 @@
use std::time::SystemTime;
use std::{thread, time};
-use crate::state::GBState;
use crate::consts;
+use crate::state::GBState;
pub trait Input {
fn update_events(&mut self, cycles: u128) -> Option<u128>;
fn get_action_gamepad_reg(&self) -> u8;
fn get_direction_gamepad_reg(&self) -> u8;
+ fn save_state(&mut self) -> bool;
}
impl<T: Input + ?Sized> Input for Box<T> {
@@ -20,6 +21,9 @@ impl<T: Input + ?Sized> Input for Box<T> {
fn get_direction_gamepad_reg(&self) -> u8 {
(**self).get_direction_gamepad_reg()
}
+ fn save_state(&mut self) -> bool {
+ (**self).save_state()
+ }
}
pub enum WindowSignal {
@@ -45,21 +49,20 @@ pub trait Audio {
fn new<S: Iterator<Item = f32> + Send + 'static>(wave: S) -> Self;
}
-pub trait LoadSave where Self::Error: std::fmt::Display, Self::Error: std::fmt::Debug {
+pub trait LoadSave
+where
+ Self::Error: std::fmt::Display,
+ Self::Error: std::fmt::Debug,
+{
type Error;
fn load_bootrom(&self, boot_rom: &mut [u8]) -> Result<(), Self::Error>;
fn load_rom(&self, rom: &mut [u8]) -> Result<(), Self::Error>;
fn load_external_ram(&self, external_ram: &mut [u8]) -> Result<(), Self::Error>;
fn save_external_ram(&self, external_ram: &[u8]) -> Result<(), Self::Error>;
+ fn save_state<S: Serial, A: Audio>(&self, state: &GBState<S, A>);
}
-pub struct Gameboy<
- I: Input,
- W: Window,
- S: Serial,
- A: Audio,
- LS: LoadSave,
-> {
+pub struct Gameboy<I: Input, W: Window, S: Serial, A: Audio, LS: LoadSave> {
input: I,
window: W,
speed: f64,
@@ -78,7 +81,6 @@ impl<I: Input, W: Window, S: Serial, A: Audio, LS: LoadSave> Gameboy<I, W, S, A,
}
}
-
pub fn start(self) {
let Self {
mut window,
@@ -88,10 +90,10 @@ impl<I: Input, W: Window, S: Serial, A: Audio, LS: LoadSave> Gameboy<I, W, S, A,
load_save,
} = self;
- load_save.load_bootrom(&mut state.mem.boot_rom).unwrap();
- load_save.load_rom(&mut state.mem.rom).unwrap();
+ load_save.load_bootrom(state.mem.boot_rom.as_mut()).unwrap();
+ load_save.load_rom(state.mem.rom.as_mut()).unwrap();
- if let Err(err) = load_save.load_external_ram(&mut state.mem.external_ram) {
+ if let Err(err) = load_save.load_external_ram(state.mem.external_ram.as_mut()) {
println!(
"Loading save failed ({}). Initializing new external ram.",
err
@@ -130,16 +132,24 @@ impl<I: Input, W: Window, S: Serial, A: Audio, LS: LoadSave> Gameboy<I, W, S, A,
nanos_sleep += c as f64 * (consts::CPU_CYCLE_LENGTH_NANOS as f64 / speed) as f64;
- if nanos_sleep >= 0.0 || next_precise_gamepad_update.map_or(false, |c| (c >= total_cycle_counter)) {
+ if nanos_sleep >= 0.0
+ || next_precise_gamepad_update.map_or(false, |c| (c >= total_cycle_counter))
+ {
next_precise_gamepad_update = input.update_events(total_cycle_counter);
- let (action_button_reg, direction_button_reg) = (
+ let (action_button_reg, direction_button_reg, save_state) = (
input.get_action_gamepad_reg(),
input.get_direction_gamepad_reg(),
+ input.save_state(),
);
+ if save_state {
+ load_save.save_state(&state);
+ }
+
if state.mem.joypad_is_action
- && (action_button_reg & (state.mem.joypad_reg >> 4)) != (state.mem.joypad_reg >> 4)
+ && (action_button_reg & (state.mem.joypad_reg >> 4))
+ != (state.mem.joypad_reg >> 4)
|| (!state.mem.joypad_is_action
&& (direction_button_reg & state.mem.joypad_reg & 0b1111)
!= (state.mem.joypad_reg & 0b1111))
@@ -150,7 +160,6 @@ impl<I: Input, W: Window, S: Serial, A: Audio, LS: LoadSave> Gameboy<I, W, S, A,
state.mem.joypad_reg = direction_button_reg | (action_button_reg << 4);
}
-
if nanos_sleep > 0.0 {
if let Some(fb) = state.mem.display.redraw_request {
if let Some(WindowSignal::Exit) = window.update(&fb) {
@@ -165,7 +174,7 @@ impl<I: Input, W: Window, S: Serial, A: Audio, LS: LoadSave> Gameboy<I, W, S, A,
now = SystemTime::now();
if last_ram_bank_enabled && !state.mem.ram_bank_enabled {
- if let Err(err) = load_save.save_external_ram(&state.mem.external_ram) {
+ if let Err(err) = load_save.save_external_ram(state.mem.external_ram.as_ref()) {
println!("Failed to save external RAM ({})", err);
}
}