From 8f8204a52b7b395a0cc1adc3942ab69bd1b3a5b7 Mon Sep 17 00:00:00 2001 From: Michel Heily Date: Fri, 10 Apr 2020 00:28:59 +0300 Subject: [PATCH] Optimize emulator frame loop Syncronize to number of cycles performed instead of VCOUNT when emulating a frame Former-commit-id: 0f9afe6a95a576dbb7a15cd1bf6bfb7d7ce02fff --- src/core/gba.rs | 29 +++++++++++++++++++++-------- src/core/gpu/mod.rs | 2 +- src/gdb.rs | 2 +- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/core/gba.rs b/src/core/gba.rs index b887799..488c777 100644 --- a/src/core/gba.rs +++ b/src/core/gba.rs @@ -24,6 +24,8 @@ pub struct GameBoyAdvance { pub input_device: Rc>, pub cycles_to_next_event: usize, + + overshoot_cycles: usize, } #[derive(Serialize, Deserialize)] @@ -58,6 +60,7 @@ impl GameBoyAdvance { input_device: input_device, cycles_to_next_event: 1, + overshoot_cycles: 0, }; gba.sysbus.created(); @@ -93,12 +96,20 @@ impl GameBoyAdvance { pub fn frame(&mut self) { self.key_poll(); - while self.sysbus.io.gpu.vcount != DISPLAY_HEIGHT { - self.step(); - } - while self.sysbus.io.gpu.vcount == DISPLAY_HEIGHT { - self.step(); + + let mut remaining_cycles = 280896 - self.overshoot_cycles; + + while remaining_cycles > 0 { + let cycles = self.step(); + if remaining_cycles >= cycles { + remaining_cycles -= cycles; + } else { + self.overshoot_cycles = cycles - remaining_cycles; + return; + } } + + self.overshoot_cycles = 0; } pub fn add_breakpoint(&mut self, addr: u32) -> Option { @@ -137,7 +148,7 @@ impl GameBoyAdvance { self.cpu.cycles - previous_cycles } - pub fn step(&mut self) { + pub fn step(&mut self) -> usize { // I hate myself for doing this, but rust left me no choice. let io = unsafe { let ptr = &mut *self.sysbus as *mut SysBus; @@ -162,7 +173,7 @@ impl GameBoyAdvance { } else { io.dmac.perform_work(&mut self.sysbus, &mut irqs); io.intc.request_irqs(irqs); - return; + return cycles; }; cycles += _cycles; @@ -174,7 +185,7 @@ impl GameBoyAdvance { // update gpu & sound io.timers.update(cycles, &mut self.sysbus, &mut irqs); - io.gpu.step( + io.gpu.update( cycles, &mut self.sysbus, &mut irqs, @@ -185,6 +196,8 @@ impl GameBoyAdvance { .update(cycles, &mut cycles_to_next_event, &self.audio_device); self.cycles_to_next_event = cycles_to_next_event; io.intc.request_irqs(irqs); + + cycles } /// Query the emulator for the recently drawn framebuffer. diff --git a/src/core/gpu/mod.rs b/src/core/gpu/mod.rs index e750b20..835b64c 100644 --- a/src/core/gpu/mod.rs +++ b/src/core/gpu/mod.rs @@ -451,7 +451,7 @@ impl Gpu { } // Returns the new gpu state - pub fn step( + pub fn update( &mut self, cycles: usize, sb: &mut SysBus, diff --git a/src/gdb.rs b/src/gdb.rs index 9e86337..7525f5c 100644 --- a/src/gdb.rs +++ b/src/gdb.rs @@ -42,7 +42,7 @@ impl Target for GameBoyAdvance { if self.cycles_to_next_event <= unsafe { S_TOTAL_CYCLES } { let mut cycles_to_next_event = std::usize::MAX; - io.gpu.step( + io.gpu.update( unsafe { S_TOTAL_CYCLES }, &mut self.sysbus, &mut irqs,