core: Decouple SysBus from Gpu and re-implement Gpu::update
Former-commit-id: 6ca6989192f0925f4d2eb0e5029a2bcf66869ee9 Former-commit-id: 562d89f627a9e3a9153a7a0db6830fd9b5875967
This commit is contained in:
parent
96b1e0d844
commit
b60ad3114c
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Reference in a new issue