Add DMA support to storage card
This commit is contained in:
parent
2c6894cc7c
commit
9956962089
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
backplane::DMAHandler,
|
||||
backplane::{Backplane, DMACardAccessorBuilder, DMAHandler},
|
||||
card::{u16_get_be_byte, u32_get_be_byte, u32_set_be_byte, Card},
|
||||
m68k::BusError,
|
||||
register,
|
||||
@ -34,10 +34,12 @@ bitflags! {
|
||||
#[derive(Debug)]
|
||||
pub struct Storage {
|
||||
file: Option<(File, String)>,
|
||||
read_data: VecDeque<u8>,
|
||||
transfer: bool,
|
||||
sector: u32,
|
||||
count: u32,
|
||||
status: Status,
|
||||
read_data: VecDeque<u8>,
|
||||
start_addresss: u32,
|
||||
}
|
||||
|
||||
// Registers
|
||||
@ -45,6 +47,7 @@ pub struct Storage {
|
||||
// 0x4-0x8: Sector count
|
||||
// 0x8-0xA: Command (W) / Status(R)
|
||||
// 0xA-0xC: Data
|
||||
// 0xC-0x11: Start address for DMA
|
||||
|
||||
impl Card for Storage {
|
||||
fn new(data: Value) -> anyhow::Result<(Self, Option<Box<dyn DMAHandler>>)> {
|
||||
@ -60,12 +63,14 @@ impl Card for Storage {
|
||||
Ok((
|
||||
Self {
|
||||
file: file.zip(file_name),
|
||||
read_data: VecDeque::new(),
|
||||
transfer: false,
|
||||
sector: 0,
|
||||
count: 0,
|
||||
status: Status::empty(),
|
||||
read_data: VecDeque::new(),
|
||||
start_addresss: 0,
|
||||
},
|
||||
None,
|
||||
Some(Box::new(Dma)),
|
||||
))
|
||||
}
|
||||
|
||||
@ -80,6 +85,7 @@ impl Card for Storage {
|
||||
}
|
||||
NullableResult::Ok(self.read_data.pop_front().unwrap_or(0))
|
||||
}
|
||||
0xC..=0x10 => NullableResult::Ok(u32_get_be_byte(self.start_addresss, address - 0xD)),
|
||||
0xFF => NullableResult::Ok(4),
|
||||
_ => NullableResult::Null,
|
||||
}
|
||||
@ -107,8 +113,23 @@ impl Card for Storage {
|
||||
self.status.set(Status::DATA_READY, true);
|
||||
}
|
||||
}
|
||||
0x1 => {
|
||||
if let Some((file, _)) = &mut self.file {
|
||||
file.seek(SeekFrom::Start(self.sector as u64 * SECTOR_SIZE))
|
||||
.unwrap();
|
||||
let mut buf = Vec::new();
|
||||
buf.resize(self.count as usize * SECTOR_SIZE as usize, 0);
|
||||
file.read_exact(&mut buf).unwrap();
|
||||
self.read_data.extend(buf);
|
||||
self.status.set(Status::BUSY, true);
|
||||
self.transfer = true;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
0xC..=0x10 => {
|
||||
self.start_addresss = u32_set_be_byte(self.start_addresss, address - 0xC, data);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
NullableResult::Ok(())
|
||||
@ -141,3 +162,23 @@ impl Display for Storage {
|
||||
}
|
||||
|
||||
register!(Storage, "storage");
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Dma;
|
||||
|
||||
impl DMAHandler for Dma {
|
||||
fn handle<'a>(&mut self, backplane: &'a Backplane, card_accessor: DMACardAccessorBuilder<'a>) {
|
||||
let card_accessor = card_accessor.build::<Storage>();
|
||||
if card_accessor.get().transfer {
|
||||
let mut address = card_accessor.get().start_addresss;
|
||||
#[allow(clippy::redundant_closure_call)]
|
||||
// Closure is used to drop the mutex guard between pop calls to prevent deadlock
|
||||
while let Some(data) = (|| card_accessor.get().read_data.pop_front())() {
|
||||
backplane.write_byte(address, data).unwrap();
|
||||
address += 1;
|
||||
}
|
||||
card_accessor.get().transfer = false;
|
||||
card_accessor.get().status.set(Status::BUSY, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user