diff --git a/src/storage.rs b/src/storage.rs index c9b6d23..e9c6bb0 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -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, + transfer: bool, sector: u32, count: u32, status: Status, + read_data: VecDeque, + 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>)> { @@ -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::(); + 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); + } + } +}