Optimize emulator frame loop

Syncronize to number of cycles performed instead of VCOUNT when
emulating a frame


Former-commit-id: 0f9afe6a95a576dbb7a15cd1bf6bfb7d7ce02fff
This commit is contained in:
Michel Heily 2020-04-10 00:28:59 +03:00
parent ff95b67ae1
commit 8f8204a52b
3 changed files with 23 additions and 10 deletions

View file

@ -24,6 +24,8 @@ pub struct GameBoyAdvance {
pub input_device: Rc<RefCell<dyn InputInterface>>,
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();
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;
}
while self.sysbus.io.gpu.vcount == DISPLAY_HEIGHT {
self.step();
}
self.overshoot_cycles = 0;
}
pub fn add_breakpoint(&mut self, addr: u32) -> Option<usize> {
@ -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.

View file

@ -451,7 +451,7 @@ impl Gpu {
}
// Returns the new gpu state
pub fn step(
pub fn update(
&mut self,
cycles: usize,
sb: &mut SysBus,

View file

@ -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,