core: dma: Delay DMA by 3 cycles

Former-commit-id: 06426b01a3e9e9084c97cd8f3a3de3b3c2b207e6
Former-commit-id: 2dee7bc2a2a3a3e69c7afa878f2d03208f330752
This commit is contained in:
Michel Heily 2020-10-10 10:57:00 -07:00 committed by MishMish
parent 0de8a60006
commit 97101d7bc1
3 changed files with 22 additions and 12 deletions

View file

@ -1,6 +1,7 @@
use super::cartridge::BackupMedia; use super::cartridge::BackupMedia;
use super::interrupt::{self, Interrupt, InterruptConnect, SharedInterruptFlags}; use super::interrupt::{self, Interrupt, InterruptConnect, SharedInterruptFlags};
use super::iodev::consts::{REG_FIFO_A, REG_FIFO_B}; use super::iodev::consts::{REG_FIFO_A, REG_FIFO_B};
use super::sched::{EventType, Scheduler, SharedScheduler};
use super::sysbus::SysBus; use super::sysbus::SysBus;
use super::Bus; use super::Bus;
@ -20,8 +21,6 @@ pub struct DmaChannel {
internal: DmaInternalRegs, internal: DmaInternalRegs,
running: bool, running: bool,
cycles: usize,
start_cycles: usize,
fifo_mode: bool, fifo_mode: bool,
irq: Interrupt, irq: Interrupt,
interrupt_flags: SharedInterruptFlags, interrupt_flags: SharedInterruptFlags,
@ -47,8 +46,7 @@ impl DmaChannel {
dst: 0, dst: 0,
wc: 0, wc: 0,
ctrl: DmaChannelCtrl(0), ctrl: DmaChannelCtrl(0),
cycles: 0,
start_cycles: 0,
fifo_mode: false, fifo_mode: false,
internal: Default::default(), internal: Default::default(),
interrupt_flags, interrupt_flags,
@ -98,7 +96,6 @@ impl DmaChannel {
self.dst, self.dst,
self.wc self.wc
); );
self.start_cycles = self.cycles;
self.running = true; self.running = true;
start_immediately = timing == 0; start_immediately = timing == 0;
self.internal.src_addr = self.src; self.internal.src_addr = self.src;
@ -177,7 +174,6 @@ impl DmaChannel {
interrupt::signal_irq(&self.interrupt_flags, self.irq); interrupt::signal_irq(&self.interrupt_flags, self.irq);
} }
if self.ctrl.repeat() { if self.ctrl.repeat() {
self.start_cycles = self.cycles;
/* reload */ /* reload */
if 3 == self.ctrl.dst_adj() { if 3 == self.ctrl.dst_adj() {
self.internal.dst_addr = self.dst; self.internal.dst_addr = self.dst;
@ -193,7 +189,9 @@ impl DmaChannel {
pub struct DmaController { pub struct DmaController {
pub channels: [DmaChannel; 4], pub channels: [DmaChannel; 4],
pending_set: u8, pending_set: u8,
cycles: usize, #[serde(skip)]
#[serde(default = "Scheduler::new_shared")]
scheduler: SharedScheduler,
} }
impl InterruptConnect for DmaController { impl InterruptConnect for DmaController {
@ -205,7 +203,7 @@ impl InterruptConnect for DmaController {
} }
impl DmaController { impl DmaController {
pub fn new(interrupt_flags: SharedInterruptFlags) -> DmaController { pub fn new(interrupt_flags: SharedInterruptFlags, scheduler: SharedScheduler) -> DmaController {
DmaController { DmaController {
channels: [ channels: [
DmaChannel::new(0, interrupt_flags.clone()), DmaChannel::new(0, interrupt_flags.clone()),
@ -214,7 +212,7 @@ impl DmaController {
DmaChannel::new(3, interrupt_flags.clone()), DmaChannel::new(3, interrupt_flags.clone()),
], ],
pending_set: 0, pending_set: 0,
cycles: 0, scheduler: scheduler,
} }
} }
@ -240,9 +238,11 @@ impl DmaController {
8 => self.channels[channel_id].write_word_count(value), 8 => self.channels[channel_id].write_word_count(value),
10 => { 10 => {
if self.channels[channel_id].write_dma_ctrl(value) { if self.channels[channel_id].write_dma_ctrl(value) {
self.pending_set |= 1 << channel_id; // DMA actually starts after 3 cycles
self.scheduler
.schedule(EventType::DmaActivateChannel(channel_id), 3);
} else { } else {
self.pending_set &= !(1 << channel_id); self.deactivate_channel(channel_id);
} }
} }
_ => panic!("Invalid dma offset {:x}", ofs), _ => panic!("Invalid dma offset {:x}", ofs),
@ -268,6 +268,14 @@ impl DmaController {
} }
} }
} }
pub fn activate_channel(&mut self, channel_id: usize) {
self.pending_set |= 1 << channel_id;
}
pub fn deactivate_channel(&mut self, channel_id: usize) {
self.pending_set &= !(1 << channel_id);
}
} }
pub const TIMING_VBLANK: u16 = 1; pub const TIMING_VBLANK: u16 = 1;

View file

@ -77,7 +77,7 @@ impl GameBoyAdvance {
let intc = InterruptController::new(interrupt_flags.clone()); let intc = InterruptController::new(interrupt_flags.clone());
let gpu = Box::new(Gpu::new(scheduler.clone(), interrupt_flags.clone())); let gpu = Box::new(Gpu::new(scheduler.clone(), interrupt_flags.clone()));
let dmac = DmaController::new(interrupt_flags.clone()); let dmac = DmaController::new(interrupt_flags.clone(), scheduler.clone());
let timers = Timers::new(interrupt_flags.clone()); let timers = Timers::new(interrupt_flags.clone());
let sound_controller = Box::new(SoundController::new( let sound_controller = Box::new(SoundController::new(
scheduler.clone(), scheduler.clone(),
@ -329,6 +329,7 @@ impl EventHandler for GameBoyAdvance {
&mut (*ptr).io as &mut IoDevices &mut (*ptr).io as &mut IoDevices
}; };
match event { match event {
EventType::DmaActivateChannel(channel_id) => io.dmac.activate_channel(channel_id),
EventType::Gpu(event) => io.gpu.on_event( EventType::Gpu(event) => io.gpu.on_event(
event, event,
extra_cycles, extra_cycles,

View file

@ -29,6 +29,7 @@ pub enum ApuEvent {
pub enum EventType { pub enum EventType {
Gpu(GpuEvent), Gpu(GpuEvent),
Apu(ApuEvent), Apu(ApuEvent),
DmaActivateChannel(usize),
} }
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]