core: dma: Delay DMA by 3 cycles
Former-commit-id: 06426b01a3e9e9084c97cd8f3a3de3b3c2b207e6 Former-commit-id: 2dee7bc2a2a3a3e69c7afa878f2d03208f330752
This commit is contained in:
parent
0de8a60006
commit
97101d7bc1
|
@ -1,6 +1,7 @@
|
|||
use super::cartridge::BackupMedia;
|
||||
use super::interrupt::{self, Interrupt, InterruptConnect, SharedInterruptFlags};
|
||||
use super::iodev::consts::{REG_FIFO_A, REG_FIFO_B};
|
||||
use super::sched::{EventType, Scheduler, SharedScheduler};
|
||||
use super::sysbus::SysBus;
|
||||
use super::Bus;
|
||||
|
||||
|
@ -20,8 +21,6 @@ pub struct DmaChannel {
|
|||
internal: DmaInternalRegs,
|
||||
|
||||
running: bool,
|
||||
cycles: usize,
|
||||
start_cycles: usize,
|
||||
fifo_mode: bool,
|
||||
irq: Interrupt,
|
||||
interrupt_flags: SharedInterruptFlags,
|
||||
|
@ -47,8 +46,7 @@ impl DmaChannel {
|
|||
dst: 0,
|
||||
wc: 0,
|
||||
ctrl: DmaChannelCtrl(0),
|
||||
cycles: 0,
|
||||
start_cycles: 0,
|
||||
|
||||
fifo_mode: false,
|
||||
internal: Default::default(),
|
||||
interrupt_flags,
|
||||
|
@ -98,7 +96,6 @@ impl DmaChannel {
|
|||
self.dst,
|
||||
self.wc
|
||||
);
|
||||
self.start_cycles = self.cycles;
|
||||
self.running = true;
|
||||
start_immediately = timing == 0;
|
||||
self.internal.src_addr = self.src;
|
||||
|
@ -177,7 +174,6 @@ impl DmaChannel {
|
|||
interrupt::signal_irq(&self.interrupt_flags, self.irq);
|
||||
}
|
||||
if self.ctrl.repeat() {
|
||||
self.start_cycles = self.cycles;
|
||||
/* reload */
|
||||
if 3 == self.ctrl.dst_adj() {
|
||||
self.internal.dst_addr = self.dst;
|
||||
|
@ -193,7 +189,9 @@ impl DmaChannel {
|
|||
pub struct DmaController {
|
||||
pub channels: [DmaChannel; 4],
|
||||
pending_set: u8,
|
||||
cycles: usize,
|
||||
#[serde(skip)]
|
||||
#[serde(default = "Scheduler::new_shared")]
|
||||
scheduler: SharedScheduler,
|
||||
}
|
||||
|
||||
impl InterruptConnect for DmaController {
|
||||
|
@ -205,7 +203,7 @@ impl InterruptConnect for DmaController {
|
|||
}
|
||||
|
||||
impl DmaController {
|
||||
pub fn new(interrupt_flags: SharedInterruptFlags) -> DmaController {
|
||||
pub fn new(interrupt_flags: SharedInterruptFlags, scheduler: SharedScheduler) -> DmaController {
|
||||
DmaController {
|
||||
channels: [
|
||||
DmaChannel::new(0, interrupt_flags.clone()),
|
||||
|
@ -214,7 +212,7 @@ impl DmaController {
|
|||
DmaChannel::new(3, interrupt_flags.clone()),
|
||||
],
|
||||
pending_set: 0,
|
||||
cycles: 0,
|
||||
scheduler: scheduler,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,9 +238,11 @@ impl DmaController {
|
|||
8 => self.channels[channel_id].write_word_count(value),
|
||||
10 => {
|
||||
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 {
|
||||
self.pending_set &= !(1 << channel_id);
|
||||
self.deactivate_channel(channel_id);
|
||||
}
|
||||
}
|
||||
_ => 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;
|
||||
|
|
|
@ -77,7 +77,7 @@ impl GameBoyAdvance {
|
|||
|
||||
let intc = InterruptController::new(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 sound_controller = Box::new(SoundController::new(
|
||||
scheduler.clone(),
|
||||
|
@ -329,6 +329,7 @@ impl EventHandler for GameBoyAdvance {
|
|||
&mut (*ptr).io as &mut IoDevices
|
||||
};
|
||||
match event {
|
||||
EventType::DmaActivateChannel(channel_id) => io.dmac.activate_channel(channel_id),
|
||||
EventType::Gpu(event) => io.gpu.on_event(
|
||||
event,
|
||||
extra_cycles,
|
||||
|
|
|
@ -29,6 +29,7 @@ pub enum ApuEvent {
|
|||
pub enum EventType {
|
||||
Gpu(GpuEvent),
|
||||
Apu(ApuEvent),
|
||||
DmaActivateChannel(usize),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
|
|
Reference in a new issue