Improve DMA code

Former-commit-id: 8fdb6195ceb323aebd8a26da98fe286d89ef8363
This commit is contained in:
Michel Heily 2019-12-27 12:37:32 +02:00
parent b026ad4ed3
commit c2ac3c5a10
3 changed files with 32 additions and 22 deletions

View file

@ -25,6 +25,7 @@ zip = "0.5.3"
ctrlc = "3.1.3"
cpal="0.10.0"
spin_sleep="0.3.7"
bit-set = "0.5.1"
[[bin]]
name = "rba-sdl2"

View file

@ -1,4 +1,6 @@
use std::collections::VecDeque;
extern crate bit_set;
use bit_set::BitSet;
use super::arm7tdmi::{Addr, Bus};
use super::iodev::consts::{REG_FIFO_A, REG_FIFO_B};
@ -105,6 +107,9 @@ impl DmaChannel {
&& (self.id == 1 || self.id == 2)
&& (self.dst == REG_FIFO_A || self.dst == REG_FIFO_B);
}
if !ctrl.is_enabled() {
self.running = false;
}
self.ctrl = ctrl;
return start_immediately;
}
@ -138,20 +143,20 @@ impl DmaChannel {
if fifo_mode {
for _ in 0..4 {
let v = sb.read_32(self.internal.src_addr);
sb.write_32(self.internal.dst_addr, v);
let v = sb.read_32(self.internal.src_addr & !3);
sb.write_32(self.internal.dst_addr & !3, v);
self.internal.src_addr += 4;
}
} else if word_size == 4 {
for _ in 0..count {
let w = sb.read_32(self.internal.src_addr);
sb.write_32(self.internal.dst_addr, w);
let w = sb.read_32(self.internal.src_addr & !3);
sb.write_32(self.internal.dst_addr & !3, w);
self.xfer_adj_addrs(word_size);
}
} else {
for _ in 0..count {
let hw = sb.read_16(self.internal.src_addr);
sb.write_16(self.internal.dst_addr, hw);
let hw = sb.read_16(self.internal.src_addr & !1);
sb.write_16(self.internal.dst_addr & !1, hw);
self.xfer_adj_addrs(word_size)
}
}
@ -174,7 +179,7 @@ impl DmaChannel {
#[derive(Debug)]
pub struct DmaController {
pub channels: [DmaChannel; 4],
xfers_queue: VecDeque<usize>,
pending_bittset: BitSet,
cycles: usize,
}
@ -187,20 +192,20 @@ impl DmaController {
DmaChannel::new(2),
DmaChannel::new(3),
],
xfers_queue: VecDeque::new(),
pending_bittset: BitSet::with_capacity(4),
cycles: 0,
}
}
pub fn perform_work(&mut self, sb: &mut SysBus, irqs: &mut IrqBitmask) -> bool {
if self.xfers_queue.is_empty() {
false
} else {
while let Some(id) = self.xfers_queue.pop_front() {
self.channels[id].xfer(sb, irqs)
pub fn has_work(&self) -> bool {
!self.pending_bittset.is_empty()
}
true
pub fn perform_work(&mut self, sb: &mut SysBus, irqs: &mut IrqBitmask) {
for id in self.pending_bittset.iter() {
self.channels[id].xfer(sb, irqs);
}
self.pending_bittset.clear();
}
pub fn write_16(&mut self, channel_id: usize, ofs: u32, value: u16) {
@ -212,7 +217,9 @@ impl DmaController {
8 => self.channels[channel_id].write_word_count(value),
10 => {
if self.channels[channel_id].write_dma_ctrl(value) {
self.xfers_queue.push_back(channel_id)
self.pending_bittset.insert(channel_id);
} else {
self.pending_bittset.remove(channel_id);
}
}
_ => panic!("Invalid dma offset"),
@ -222,7 +229,7 @@ impl DmaController {
pub fn notify_vblank(&mut self) {
for i in 0..4 {
if self.channels[i].ctrl.is_enabled() && self.channels[i].ctrl.timing() == 1 {
self.xfers_queue.push_back(i);
self.pending_bittset.insert(i);
}
}
}
@ -230,7 +237,7 @@ impl DmaController {
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.xfers_queue.push_back(i);
self.pending_bittset.insert(i);
}
}
}
@ -238,10 +245,11 @@ impl DmaController {
pub fn notify_sound_fifo(&mut self, fifo_addr: u32) {
for i in 1..=2 {
if self.channels[i].ctrl.is_enabled()
&& self.channels[i].running
&& self.channels[i].ctrl.timing() == 3
&& self.channels[i].dst == fifo_addr
{
self.xfers_queue.push_back(i);
self.pending_bittset.insert(i);
}
}
}

View file

@ -89,7 +89,7 @@ impl GameBoyAdvance {
&mut (*ptr).io as &mut IoDevices
};
let cycles = if !io.dmac.perform_work(&mut self.sysbus, &mut irqs) {
let cycles = if !io.dmac.has_work() {
if io.intc.irq_pending()
&& self.cpu.last_executed.is_some()
&& !self.cpu.did_pipeline_flush()
@ -105,6 +105,7 @@ impl GameBoyAdvance {
1
}
} else {
io.dmac.perform_work(&mut self.sysbus, &mut irqs);
0
};