Improve DMA code
Former-commit-id: 8fdb6195ceb323aebd8a26da98fe286d89ef8363
This commit is contained in:
parent
b026ad4ed3
commit
c2ac3c5a10
|
@ -25,6 +25,7 @@ zip = "0.5.3"
|
||||||
ctrlc = "3.1.3"
|
ctrlc = "3.1.3"
|
||||||
cpal="0.10.0"
|
cpal="0.10.0"
|
||||||
spin_sleep="0.3.7"
|
spin_sleep="0.3.7"
|
||||||
|
bit-set = "0.5.1"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "rba-sdl2"
|
name = "rba-sdl2"
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
use std::collections::VecDeque;
|
extern crate bit_set;
|
||||||
|
|
||||||
|
use bit_set::BitSet;
|
||||||
|
|
||||||
use super::arm7tdmi::{Addr, Bus};
|
use super::arm7tdmi::{Addr, Bus};
|
||||||
use super::iodev::consts::{REG_FIFO_A, REG_FIFO_B};
|
use super::iodev::consts::{REG_FIFO_A, REG_FIFO_B};
|
||||||
|
@ -105,6 +107,9 @@ impl DmaChannel {
|
||||||
&& (self.id == 1 || self.id == 2)
|
&& (self.id == 1 || self.id == 2)
|
||||||
&& (self.dst == REG_FIFO_A || self.dst == REG_FIFO_B);
|
&& (self.dst == REG_FIFO_A || self.dst == REG_FIFO_B);
|
||||||
}
|
}
|
||||||
|
if !ctrl.is_enabled() {
|
||||||
|
self.running = false;
|
||||||
|
}
|
||||||
self.ctrl = ctrl;
|
self.ctrl = ctrl;
|
||||||
return start_immediately;
|
return start_immediately;
|
||||||
}
|
}
|
||||||
|
@ -138,20 +143,20 @@ impl DmaChannel {
|
||||||
|
|
||||||
if fifo_mode {
|
if fifo_mode {
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
let v = sb.read_32(self.internal.src_addr);
|
let v = sb.read_32(self.internal.src_addr & !3);
|
||||||
sb.write_32(self.internal.dst_addr, v);
|
sb.write_32(self.internal.dst_addr & !3, v);
|
||||||
self.internal.src_addr += 4;
|
self.internal.src_addr += 4;
|
||||||
}
|
}
|
||||||
} else if word_size == 4 {
|
} else if word_size == 4 {
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
let w = sb.read_32(self.internal.src_addr);
|
let w = sb.read_32(self.internal.src_addr & !3);
|
||||||
sb.write_32(self.internal.dst_addr, w);
|
sb.write_32(self.internal.dst_addr & !3, w);
|
||||||
self.xfer_adj_addrs(word_size);
|
self.xfer_adj_addrs(word_size);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
let hw = sb.read_16(self.internal.src_addr);
|
let hw = sb.read_16(self.internal.src_addr & !1);
|
||||||
sb.write_16(self.internal.dst_addr, hw);
|
sb.write_16(self.internal.dst_addr & !1, hw);
|
||||||
self.xfer_adj_addrs(word_size)
|
self.xfer_adj_addrs(word_size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -174,7 +179,7 @@ impl DmaChannel {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DmaController {
|
pub struct DmaController {
|
||||||
pub channels: [DmaChannel; 4],
|
pub channels: [DmaChannel; 4],
|
||||||
xfers_queue: VecDeque<usize>,
|
pending_bittset: BitSet,
|
||||||
cycles: usize,
|
cycles: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,20 +192,20 @@ impl DmaController {
|
||||||
DmaChannel::new(2),
|
DmaChannel::new(2),
|
||||||
DmaChannel::new(3),
|
DmaChannel::new(3),
|
||||||
],
|
],
|
||||||
xfers_queue: VecDeque::new(),
|
pending_bittset: BitSet::with_capacity(4),
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn perform_work(&mut self, sb: &mut SysBus, irqs: &mut IrqBitmask) -> bool {
|
pub fn has_work(&self) -> bool {
|
||||||
if self.xfers_queue.is_empty() {
|
!self.pending_bittset.is_empty()
|
||||||
false
|
}
|
||||||
} else {
|
|
||||||
while let Some(id) = self.xfers_queue.pop_front() {
|
pub fn perform_work(&mut self, sb: &mut SysBus, irqs: &mut IrqBitmask) {
|
||||||
self.channels[id].xfer(sb, irqs)
|
for id in self.pending_bittset.iter() {
|
||||||
}
|
self.channels[id].xfer(sb, irqs);
|
||||||
true
|
|
||||||
}
|
}
|
||||||
|
self.pending_bittset.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_16(&mut self, channel_id: usize, ofs: u32, value: u16) {
|
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),
|
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.xfers_queue.push_back(channel_id)
|
self.pending_bittset.insert(channel_id);
|
||||||
|
} else {
|
||||||
|
self.pending_bittset.remove(channel_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => panic!("Invalid dma offset"),
|
_ => panic!("Invalid dma offset"),
|
||||||
|
@ -222,7 +229,7 @@ impl DmaController {
|
||||||
pub fn notify_vblank(&mut self) {
|
pub fn notify_vblank(&mut self) {
|
||||||
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() == 1 {
|
||||||
self.xfers_queue.push_back(i);
|
self.pending_bittset.insert(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,7 +237,7 @@ impl DmaController {
|
||||||
pub fn notify_hblank(&mut self) {
|
pub fn notify_hblank(&mut self) {
|
||||||
for i in 0..4 {
|
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() == 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) {
|
pub fn notify_sound_fifo(&mut self, fifo_addr: u32) {
|
||||||
for i in 1..=2 {
|
for i in 1..=2 {
|
||||||
if self.channels[i].ctrl.is_enabled()
|
if self.channels[i].ctrl.is_enabled()
|
||||||
|
&& self.channels[i].running
|
||||||
&& self.channels[i].ctrl.timing() == 3
|
&& self.channels[i].ctrl.timing() == 3
|
||||||
&& self.channels[i].dst == fifo_addr
|
&& self.channels[i].dst == fifo_addr
|
||||||
{
|
{
|
||||||
self.xfers_queue.push_back(i);
|
self.pending_bittset.insert(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ impl GameBoyAdvance {
|
||||||
&mut (*ptr).io as &mut IoDevices
|
&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()
|
if io.intc.irq_pending()
|
||||||
&& self.cpu.last_executed.is_some()
|
&& self.cpu.last_executed.is_some()
|
||||||
&& !self.cpu.did_pipeline_flush()
|
&& !self.cpu.did_pipeline_flush()
|
||||||
|
@ -105,6 +105,7 @@ impl GameBoyAdvance {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
io.dmac.perform_work(&mut self.sysbus, &mut irqs);
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Reference in a new issue