From 5a08ab2d17834296d4aee8df0a01b1267f7a2e78 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com>
Date: Sun, 21 May 2023 22:17:52 +0100
Subject: [PATCH] chore: support for unlimited mode

---
 frontends/sdl/src/main.rs | 43 +++++++++++++++++++++++++++++----------
 1 file changed, 32 insertions(+), 11 deletions(-)

diff --git a/frontends/sdl/src/main.rs b/frontends/sdl/src/main.rs
index b9373fb2..4e29e3ef 100644
--- a/frontends/sdl/src/main.rs
+++ b/frontends/sdl/src/main.rs
@@ -54,13 +54,15 @@ impl Default for Benchmark {
 }
 
 pub struct EmulatorOptions {
-    auto_mode: bool,
+    auto_mode: Option<bool>,
+    unlimited: Option<bool>,
     features: Option<Vec<&'static str>>,
 }
 
 pub struct Emulator {
     system: GameBoy,
     auto_mode: bool,
+    unlimited: bool,
     sdl: Option<SdlSystem>,
     audio: Option<Audio>,
     title: &'static str,
@@ -78,7 +80,8 @@ impl Emulator {
     pub fn new(system: GameBoy, options: EmulatorOptions) -> Self {
         Self {
             system,
-            auto_mode: options.auto_mode,
+            auto_mode: options.auto_mode.unwrap_or(true),
+            unlimited: options.unlimited.unwrap_or(false),
             sdl: None,
             audio: None,
             title: TITLE,
@@ -250,6 +253,10 @@ impl Emulator {
         self.palette_index = (self.palette_index + 1) % self.palettes.len();
     }
 
+    pub fn limited(&self) -> bool {
+        !self.unlimited
+    }
+
     pub fn run(&mut self) {
         // updates the icon of the window to reflect the image
         // and style of the emulator
@@ -455,10 +462,15 @@ impl Emulator {
                     .ceil() as u8;
                 ticks = max(ticks, 1);
 
-                // updates the next update time reference to the current
-                // time so that it can be used from game loop control
-                self.next_tick_time += (1000.0 / self.visual_frequency) * ticks as f32;
-                self.next_tick_time_i = self.next_tick_time.ceil() as u32;
+                // in case the limited (speed) mode is set then we must calculate
+                // a new next tick time reference, this is required to prevent the
+                // machine from running too fast (eg: 50x)
+                if self.limited() {
+                    // updates the next update time reference to the current
+                    // time so that it can be used from game loop control
+                    self.next_tick_time += (1000.0 / self.visual_frequency) * ticks as f32;
+                    self.next_tick_time_i = self.next_tick_time.ceil() as u32;
+                }
             }
 
             let current_time = self.sdl.as_mut().unwrap().timer_subsystem.ticks();
@@ -531,10 +543,15 @@ impl Emulator {
                     .ceil() as u8;
                 ticks = max(ticks, 1);
 
-                // updates the next update time reference to the current
-                // time so that it can be used from game loop control
-                self.next_tick_time += (1000.0 / self.visual_frequency) * ticks as f32;
-                self.next_tick_time_i = self.next_tick_time.ceil() as u32;
+                // in case the limited (speed) mode is set then we must calculate
+                // a new next tick time reference, this is required to prevent the
+                // machine from running too fast (eg: 50x)
+                if self.limited() {
+                    // updates the next update time reference to the current
+                    // time so that it can be used from game loop control
+                    self.next_tick_time += (1000.0 / self.visual_frequency) * ticks as f32;
+                    self.next_tick_time_i = self.next_tick_time.ceil() as u32;
+                }
             }
 
             let current_time = reference.elapsed().as_millis() as u32;
@@ -569,6 +586,9 @@ struct Args {
     #[arg(long, default_value_t = false)]
     headless: bool,
 
+    #[arg(long, default_value_t = false)]
+    unlimited: bool,
+
     #[arg(short, long, default_value_t = String::from("../../res/roms/demo/pocket.gb"))]
     rom_path: String,
 }
@@ -602,7 +622,8 @@ fn main() {
     // both the video and audio sub-systems, loads default
     // ROM file and starts running it
     let options = EmulatorOptions {
-        auto_mode,
+        auto_mode: Some(auto_mode),
+        unlimited: Some(args.unlimited),
         features: if args.headless {
             Some(vec![])
         } else {
-- 
GitLab