From b60ad3114c482b1519879a3eb23cc6a83c0c7fe1 Mon Sep 17 00:00:00 2001 From: Michel Heily Date: Wed, 20 May 2020 21:22:30 +0300 Subject: [PATCH] core: Decouple SysBus from Gpu and re-implement Gpu::update Former-commit-id: 6ca6989192f0925f4d2eb0e5029a2bcf66869ee9 Former-commit-id: 562d89f627a9e3a9153a7a0db6830fd9b5875967 --- rustboyadvance-core/src/dma.rs | 19 +++++++------- rustboyadvance-core/src/gba.rs | 2 +- rustboyadvance-core/src/gpu/mod.rs | 42 +++++++++++++++--------------- rustboyadvance-core/src/sysbus.rs | 7 +++++ 4 files changed, 38 insertions(+), 32 deletions(-) diff --git a/rustboyadvance-core/src/dma.rs b/rustboyadvance-core/src/dma.rs index 2dbfa72..42814d8 100644 --- a/rustboyadvance-core/src/dma.rs +++ b/rustboyadvance-core/src/dma.rs @@ -238,17 +238,9 @@ impl DmaController { } } - pub fn notify_vblank(&mut self) { + pub fn notify_from_gpu(&mut self, timing: u16) { for i in 0..4 { - if self.channels[i].ctrl.is_enabled() && self.channels[i].ctrl.timing() == 1 { - self.pending_set |= 1 << i; - } - } - } - - pub fn notify_hblank(&mut self) { - for i in 0..4 { - if self.channels[i].ctrl.is_enabled() && self.channels[i].ctrl.timing() == 2 { + if self.channels[i].ctrl.is_enabled() && self.channels[i].ctrl.timing() == timing { self.pending_set |= 1 << i; } } @@ -267,6 +259,13 @@ impl DmaController { } } +pub const TIMING_VBLANK: u16 = 1; +pub const TIMING_HBLANK: u16 = 2; + +pub trait DmaNotifer { + fn notify(&mut self, timing: u16); +} + bitfield! { #[derive(Serialize, Deserialize, Clone, Default)] pub struct DmaChannelCtrl(u16); diff --git a/rustboyadvance-core/src/gba.rs b/rustboyadvance-core/src/gba.rs index 0193efb..b1c31a7 100644 --- a/rustboyadvance-core/src/gba.rs +++ b/rustboyadvance-core/src/gba.rs @@ -235,9 +235,9 @@ impl GameBoyAdvance { io.timers.update(cycles, &mut self.sysbus, &mut irqs); io.gpu.update( cycles, - &mut self.sysbus, &mut irqs, &mut cycles_to_next_event, + self.sysbus.as_mut(), &self.video_device, ); io.sound diff --git a/rustboyadvance-core/src/gpu/mod.rs b/rustboyadvance-core/src/gpu/mod.rs index be0c762..453306a 100644 --- a/rustboyadvance-core/src/gpu/mod.rs +++ b/rustboyadvance-core/src/gpu/mod.rs @@ -4,9 +4,10 @@ use std::rc::Rc; use serde::{Deserialize, Serialize}; +use super::dma::{DmaNotifer, TIMING_HBLANK, TIMING_VBLANK}; use super::interrupt::IrqBitmask; pub use super::sysbus::consts::*; -use super::sysbus::{BoxedMemory, SysBus}; +use super::sysbus::BoxedMemory; use super::VideoInterface; use super::{Addr, Bus}; @@ -434,13 +435,15 @@ impl Gpu { &self.frame_buffer } - pub fn on_state_completed( + pub fn on_state_completed( &mut self, completed: GpuState, - sb: &mut SysBus, irqs: &mut IrqBitmask, + dma_notifier: &mut D, video_device: &VideoDeviceRcRefCell, - ) { + ) where + D: DmaNotifer, + { match completed { HDraw => { // Transition to HBlank @@ -451,7 +454,7 @@ impl Gpu { if self.dispstat.hblank_irq_enable() { irqs.set_LCD_HBlank(true); }; - sb.io.dmac.notify_hblank(); + dma_notifier.notify(TIMING_HBLANK); } HBlank => { self.update_vcount(self.vcount + 1, irqs); @@ -479,7 +482,7 @@ impl Gpu { irqs.set_LCD_VBlank(true); }; - sb.io.dmac.notify_vblank(); + dma_notifier.notify(TIMING_VBLANK); video_device.borrow_mut().render(&self.frame_buffer); self.obj_buffer_reset(); self.cycles_left_for_current_state = CYCLES_HDRAW; @@ -513,27 +516,24 @@ impl Gpu { } // Returns the new gpu state - pub fn update( + pub fn update( &mut self, - cycles: usize, - sb: &mut SysBus, + mut cycles: usize, irqs: &mut IrqBitmask, cycles_to_next_event: &mut usize, + dma_notifier: &mut D, video_device: &VideoDeviceRcRefCell, - ) { - if self.cycles_left_for_current_state <= cycles { - let overshoot = cycles - self.cycles_left_for_current_state; - - self.on_state_completed(self.state, sb, irqs, video_device); - - // handle the overshoot - if overshoot < self.cycles_left_for_current_state { - self.cycles_left_for_current_state -= overshoot; + ) where + D: DmaNotifer, + { + loop { + if self.cycles_left_for_current_state <= cycles { + cycles -= self.cycles_left_for_current_state; + self.on_state_completed(self.state, irqs, dma_notifier, video_device); } else { - panic!("OH SHIT"); + self.cycles_left_for_current_state -= cycles; + break; } - } else { - self.cycles_left_for_current_state -= cycles; } if self.cycles_left_for_current_state < *cycles_to_next_event { diff --git a/rustboyadvance-core/src/sysbus.rs b/rustboyadvance-core/src/sysbus.rs index 787366e..b3c0ea7 100644 --- a/rustboyadvance-core/src/sysbus.rs +++ b/rustboyadvance-core/src/sysbus.rs @@ -4,6 +4,7 @@ use std::ops::{Deref, DerefMut}; use serde::{Deserialize, Serialize}; use super::cartridge::Cartridge; +use super::dma::DmaNotifer; use super::iodev::{IoDevices, WaitControl}; use super::{Addr, Bus}; @@ -377,3 +378,9 @@ impl Bus for SysBus { memory_map!(write(self, write_8, addr, value)); } } + +impl DmaNotifer for SysBus { + fn notify(&mut self, timing: u16) { + self.io.dmac.notify_from_gpu(timing); + } +}