core: Decouple SysBus from Gpu and re-implement Gpu::update

Former-commit-id: 6ca6989192f0925f4d2eb0e5029a2bcf66869ee9
Former-commit-id: 562d89f627a9e3a9153a7a0db6830fd9b5875967
This commit is contained in:
Michel Heily 2020-05-20 21:22:30 +03:00
parent 96b1e0d844
commit b60ad3114c
4 changed files with 38 additions and 32 deletions

View file

@ -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 { for i in 0..4 {
if self.channels[i].ctrl.is_enabled() && self.channels[i].ctrl.timing() == 1 { if self.channels[i].ctrl.is_enabled() && self.channels[i].ctrl.timing() == timing {
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 {
self.pending_set |= 1 << i; 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! { bitfield! {
#[derive(Serialize, Deserialize, Clone, Default)] #[derive(Serialize, Deserialize, Clone, Default)]
pub struct DmaChannelCtrl(u16); pub struct DmaChannelCtrl(u16);

View file

@ -235,9 +235,9 @@ impl GameBoyAdvance {
io.timers.update(cycles, &mut self.sysbus, &mut irqs); io.timers.update(cycles, &mut self.sysbus, &mut irqs);
io.gpu.update( io.gpu.update(
cycles, cycles,
&mut self.sysbus,
&mut irqs, &mut irqs,
&mut cycles_to_next_event, &mut cycles_to_next_event,
self.sysbus.as_mut(),
&self.video_device, &self.video_device,
); );
io.sound io.sound

View file

@ -4,9 +4,10 @@ use std::rc::Rc;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::dma::{DmaNotifer, TIMING_HBLANK, TIMING_VBLANK};
use super::interrupt::IrqBitmask; use super::interrupt::IrqBitmask;
pub use super::sysbus::consts::*; pub use super::sysbus::consts::*;
use super::sysbus::{BoxedMemory, SysBus}; use super::sysbus::BoxedMemory;
use super::VideoInterface; use super::VideoInterface;
use super::{Addr, Bus}; use super::{Addr, Bus};
@ -434,13 +435,15 @@ impl Gpu {
&self.frame_buffer &self.frame_buffer
} }
pub fn on_state_completed( pub fn on_state_completed<D>(
&mut self, &mut self,
completed: GpuState, completed: GpuState,
sb: &mut SysBus,
irqs: &mut IrqBitmask, irqs: &mut IrqBitmask,
dma_notifier: &mut D,
video_device: &VideoDeviceRcRefCell, video_device: &VideoDeviceRcRefCell,
) { ) where
D: DmaNotifer,
{
match completed { match completed {
HDraw => { HDraw => {
// Transition to HBlank // Transition to HBlank
@ -451,7 +454,7 @@ impl Gpu {
if self.dispstat.hblank_irq_enable() { if self.dispstat.hblank_irq_enable() {
irqs.set_LCD_HBlank(true); irqs.set_LCD_HBlank(true);
}; };
sb.io.dmac.notify_hblank(); dma_notifier.notify(TIMING_HBLANK);
} }
HBlank => { HBlank => {
self.update_vcount(self.vcount + 1, irqs); self.update_vcount(self.vcount + 1, irqs);
@ -479,7 +482,7 @@ impl Gpu {
irqs.set_LCD_VBlank(true); irqs.set_LCD_VBlank(true);
}; };
sb.io.dmac.notify_vblank(); dma_notifier.notify(TIMING_VBLANK);
video_device.borrow_mut().render(&self.frame_buffer); video_device.borrow_mut().render(&self.frame_buffer);
self.obj_buffer_reset(); self.obj_buffer_reset();
self.cycles_left_for_current_state = CYCLES_HDRAW; self.cycles_left_for_current_state = CYCLES_HDRAW;
@ -513,27 +516,24 @@ impl Gpu {
} }
// Returns the new gpu state // Returns the new gpu state
pub fn update( pub fn update<D>(
&mut self, &mut self,
cycles: usize, mut cycles: usize,
sb: &mut SysBus,
irqs: &mut IrqBitmask, irqs: &mut IrqBitmask,
cycles_to_next_event: &mut usize, cycles_to_next_event: &mut usize,
dma_notifier: &mut D,
video_device: &VideoDeviceRcRefCell, video_device: &VideoDeviceRcRefCell,
) { ) where
if self.cycles_left_for_current_state <= cycles { D: DmaNotifer,
let overshoot = cycles - self.cycles_left_for_current_state; {
loop {
self.on_state_completed(self.state, sb, irqs, video_device); if self.cycles_left_for_current_state <= cycles {
cycles -= self.cycles_left_for_current_state;
// handle the overshoot self.on_state_completed(self.state, irqs, dma_notifier, video_device);
if overshoot < self.cycles_left_for_current_state {
self.cycles_left_for_current_state -= overshoot;
} else { } 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 { if self.cycles_left_for_current_state < *cycles_to_next_event {

View file

@ -4,6 +4,7 @@ use std::ops::{Deref, DerefMut};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::cartridge::Cartridge; use super::cartridge::Cartridge;
use super::dma::DmaNotifer;
use super::iodev::{IoDevices, WaitControl}; use super::iodev::{IoDevices, WaitControl};
use super::{Addr, Bus}; use super::{Addr, Bus};
@ -377,3 +378,9 @@ impl Bus for SysBus {
memory_map!(write(self, write_8, addr, value)); 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);
}
}