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 {
|
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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
D: DmaNotifer,
|
||||||
|
{
|
||||||
|
loop {
|
||||||
if self.cycles_left_for_current_state <= cycles {
|
if self.cycles_left_for_current_state <= cycles {
|
||||||
let overshoot = cycles - self.cycles_left_for_current_state;
|
cycles -= self.cycles_left_for_current_state;
|
||||||
|
self.on_state_completed(self.state, irqs, dma_notifier, video_device);
|
||||||
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;
|
|
||||||
} else {
|
|
||||||
panic!("OH SHIT");
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
self.cycles_left_for_current_state -= cycles;
|
self.cycles_left_for_current_state -= cycles;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.cycles_left_for_current_state < *cycles_to_next_event {
|
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 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Reference in a new issue