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 {
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);

View file

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

View file

@ -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<D>(
&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<D>(
&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 {

View file

@ -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);
}
}