Change to locking cards individually and remove now unnecessary traits

This commit is contained in:
pjht 2023-03-15 18:53:03 -05:00
parent 21181fc645
commit d32bcc3a8e
Signed by: pjht
GPG Key ID: 7B5F6AFBEC7EE78E
9 changed files with 178 additions and 300 deletions

1
Cargo.lock generated
View File

@ -521,7 +521,6 @@ dependencies = [
"itertools", "itertools",
"mopa", "mopa",
"nullable-result", "nullable-result",
"parking_lot",
"parse_int", "parse_int",
"reedline-repl-rs", "reedline-repl-rs",
"serde", "serde",

View File

@ -18,7 +18,6 @@ inventory = "0.3.1"
itertools = "0.10.5" itertools = "0.10.5"
mopa = "0.2.2" mopa = "0.2.2"
nullable-result = { version = "0.7.0", features=["try_trait"] } nullable-result = { version = "0.7.0", features=["try_trait"] }
parking_lot = "0.12.1"
parse_int = "0.6.0" parse_int = "0.6.0"
reedline-repl-rs = "1.0.2" reedline-repl-rs = "1.0.2"
serde = { version = "1.0.144", features = ["derive"] } serde = { version = "1.0.144", features = ["derive"] }

View File

@ -1,73 +1,21 @@
use std::fmt::Debug; use std::cell::{Cell, RefCell, RefMut};
use std::fmt::Display; use std::fmt::{Debug, Display};
use std::marker::PhantomData; use std::rc::Rc;
use anyhow::anyhow; use anyhow::anyhow;
use itertools::Itertools; use itertools::Itertools;
use nullable_result::{GeneralIterExt, NullableResult}; use nullable_result::{GeneralIterExt, NullableResult};
use parking_lot::MappedMutexGuard;
use parking_lot::Mutex;
use parking_lot::MutexGuard;
use crate::{ use crate::{
card::{self, Card}, card::{self, Card},
m68k::BusError, m68k::BusError,
}; };
pub trait DMAHandler: Debug {
fn handle<'a>(&mut self, backplane: &'a Backplane, card_accessor: CardAccessorBuilder<'a>);
}
pub trait MMUHandler: Debug {
fn translate_address<'a>(
&mut self,
backplane: &'a Backplane,
card_accessor: CardAccessorBuilder<'a>,
address: u32,
write: bool,
) -> NullableResult<u32, BusError>;
}
#[derive(Copy, Clone, Debug)]
#[allow(dead_code)]
pub struct CardAccessorBuilder<'a> {
backplane: &'a Backplane,
card_no: usize,
}
impl<'a> CardAccessorBuilder<'a> {
#[allow(dead_code)]
pub fn build<T: Card>(self) -> CardAccessor<'a, T> {
CardAccessor {
backplane: self.backplane,
card_no: self.card_no,
card_type: PhantomData,
}
}
}
#[derive(Copy, Clone, Debug)]
#[allow(dead_code)]
pub struct CardAccessor<'a, T> {
backplane: &'a Backplane,
card_no: usize,
card_type: PhantomData<T>,
}
impl<T: Card> CardAccessor<'_, T> {
#[allow(dead_code)]
pub fn get(&self) -> MappedMutexGuard<T> {
MutexGuard::map(self.backplane.cards.lock(), |cards| {
cards[self.card_no].downcast_mut::<T>().unwrap()
})
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct Backplane { pub struct Backplane {
cards: Mutex<Vec<Box<dyn Card>>>, cards: Vec<Rc<RefCell<dyn Card>>>,
dma_handlers: Mutex<Vec<(usize, Box<dyn DMAHandler>)>>, mmu: Option<usize>,
mmu: Mutex<Option<(usize, Box<dyn MMUHandler>)>>, in_dma: Cell<bool>,
} }
impl Display for Backplane { impl Display for Backplane {
@ -75,11 +23,10 @@ impl Display for Backplane {
f.write_fmt(format_args!( f.write_fmt(format_args!(
"{}", "{}",
self.cards self.cards
.lock()
.iter() .iter()
.enumerate() .enumerate()
.format_with("\n", |(i, card), g| { .format_with("\n", |(i, card), g| {
g(&format_args!("Card {i}: {card}")) g(&format_args!("Card {i}: {}", card.borrow_mut()))
}) })
)) ))
} }
@ -90,191 +37,143 @@ impl Backplane {
if card_configs.len() > 255 { if card_configs.len() > 255 {
return Err(anyhow!("A maximum of 255 cards are allowed")); return Err(anyhow!("A maximum of 255 cards are allowed"));
} }
let mut cards = Vec::new(); let cards: Vec<_> = card_configs
let mut dma_handlers = Vec::new(); .into_iter()
let mut mmu = None; .map(|cfg| cfg.into_card())
for item in card_configs.into_iter().map(|cfg| cfg.into_card()) { .try_collect()?;
let (mut card, dma_handler) = item?;
if let Some(dma_handler) = dma_handler { let mmu = cards
dma_handlers.push((cards.len(), dma_handler)); .iter()
} .enumerate()
if let Some(mmu_ret) = card.try_get_mmu() { .filter_map(|(i, card)| card.borrow_mut().try_as_mmu().map(|_| i))
if mmu.is_some() { .at_most_one()
panic!("Can't have two MMU cards!"); .expect("Can't have two MMU cards!");
} else {
mmu = Some((cards.len(), mmu_ret));
}
}
cards.push(card);
}
Ok(Self { Ok(Self {
cards: Mutex::new(cards), cards,
dma_handlers: Mutex::new(dma_handlers), mmu,
mmu: Mutex::new(mmu), in_dma: Cell::new(false),
}) })
} }
pub fn reset(&self) { pub fn reset(&self) {
for card in self.cards.lock().iter_mut() { for card in self.cards.iter() {
card.reset(); card.borrow_mut().reset();
} }
} }
pub fn card_cmd(&self, card_num: u8, cmd: &[&str]) -> anyhow::Result<()> { pub fn card_cmd(&self, card_num: u8, cmd: &[&str]) -> anyhow::Result<()> {
self.cards self.cards
.lock() .get(card_num as usize)
.get_mut(card_num as usize)
.ok_or_else(|| anyhow!("Card {} does not exist", card_num))? .ok_or_else(|| anyhow!("Card {} does not exist", card_num))?
.borrow_mut()
.cmd(cmd) .cmd(cmd)
} }
pub fn read_word(&self, address: u32) -> Result<u16, BusError> { pub fn read_word(&self, address: u32) -> Result<u16, BusError> {
let data = self.mem_helper( self.mem_helper(
address, address,
|card| card.read_word(address), |mut card| card.read_word(address),
|card| card.read_word_io(address as u8), |mut card| card.read_word_io(address as u8),
0,
false, false,
false, false,
)?; )
if !self.dma_handlers.is_locked() {
self.handle_dma()
}
Ok(data)
} }
pub fn read_byte(&self, address: u32) -> Result<u8, BusError> { pub fn read_byte(&self, address: u32) -> Result<u8, BusError> {
let data = self.mem_helper( self.mem_helper(
address, address,
|card| card.read_byte(address), |mut card| card.read_byte(address),
|card| card.read_byte_io(address as u8), |mut card| card.read_byte_io(address as u8),
0,
false, false,
false, false,
)?; )
if !self.dma_handlers.is_locked() {
self.handle_dma()
}
Ok(data)
} }
pub fn write_word(&self, address: u32, data: u16) -> Result<(), BusError> { pub fn write_word(&self, address: u32, data: u16) -> Result<(), BusError> {
self.mem_helper( self.mem_helper(
address, address,
|card| card.write_word(address, data), |mut card| card.write_word(address, data),
|card| card.write_word_io(address as u8, data), |mut card| card.write_word_io(address as u8, data),
(),
false, false,
true, true,
)?; )
if !self.dma_handlers.is_locked() {
self.handle_dma()
}
Ok(())
} }
pub fn write_byte(&self, address: u32, data: u8) -> Result<(), BusError> { pub fn write_byte(&self, address: u32, data: u8) -> Result<(), BusError> {
self.mem_helper( self.mem_helper(
address, address,
|card| card.write_byte(address, data), |mut card| card.write_byte(address, data),
|card| card.write_byte_io(address as u8, data), |mut card| card.write_byte_io(address as u8, data),
(),
false, false,
true, true,
)?; )
if !self.dma_handlers.is_locked() {
self.handle_dma()
}
Ok(())
} }
pub fn read_word_phys(&self, address: u32) -> Result<u16, BusError> { pub fn read_word_phys(&self, address: u32) -> Result<u16, BusError> {
let data = self.mem_helper( self.mem_helper(
address, address,
|card| card.read_word(address), |mut card| card.read_word(address),
|card| card.read_word_io(address as u8), |mut card| card.read_word_io(address as u8),
0,
true, true,
false, false,
)?; )
if !self.dma_handlers.is_locked() {
self.handle_dma()
}
Ok(data)
} }
#[allow(dead_code)]
pub fn read_byte_phys(&self, address: u32) -> Result<u8, BusError> { pub fn read_byte_phys(&self, address: u32) -> Result<u8, BusError> {
let data = self.mem_helper( self.mem_helper(
address, address,
|card| card.read_byte(address), |mut card| card.read_byte(address),
|card| card.read_byte_io(address as u8), |mut card| card.read_byte_io(address as u8),
0,
true, true,
false, false,
)?; )
if !self.dma_handlers.is_locked() {
self.handle_dma()
}
Ok(data)
} }
#[allow(dead_code)]
pub fn write_word_phys(&self, address: u32, data: u16) -> Result<(), BusError> { pub fn write_word_phys(&self, address: u32, data: u16) -> Result<(), BusError> {
self.mem_helper( self.mem_helper(
address, address,
|card| card.write_word(address, data), |mut card| card.write_word(address, data),
|card| card.write_word_io(address as u8, data), |mut card| card.write_word_io(address as u8, data),
(),
true, true,
true, true,
)?; )
if !self.dma_handlers.is_locked() {
self.handle_dma()
}
Ok(())
} }
#[allow(dead_code)]
pub fn write_byte_phys(&self, address: u32, data: u8) -> Result<(), BusError> { pub fn write_byte_phys(&self, address: u32, data: u8) -> Result<(), BusError> {
self.mem_helper( self.mem_helper(
address, address,
|card| card.write_byte(address, data), |mut card| card.write_byte(address, data),
|card| card.write_byte_io(address as u8, data), |mut card| card.write_byte_io(address as u8, data),
(),
true, true,
true, true,
)?; )
if !self.dma_handlers.is_locked() {
self.handle_dma()
}
Ok(())
} }
fn mem_helper<T, M, I>( fn mem_helper<T: Default, M, I>(
&self, &self,
address: u32, address: u32,
mut mem_func: M, mut mem_func: M,
mut io_func: I, mut io_func: I,
io_default: T,
bypass_mmu: bool, bypass_mmu: bool,
write: bool, write: bool,
) -> Result<T, BusError> ) -> Result<T, BusError>
where where
M: FnMut(&mut Box<dyn Card>) -> NullableResult<T, BusError>, M: FnMut(RefMut<'_, dyn Card>) -> NullableResult<T, BusError>,
I: FnMut(&mut Box<dyn Card>) -> NullableResult<T, BusError>, I: FnMut(RefMut<'_, dyn Card>) -> NullableResult<T, BusError>,
T: Copy,
{ {
let address = if bypass_mmu { let address = if bypass_mmu {
address address
} else if let Some((card_no, ref mut mmu)) = *self.mmu.lock() { } else if let Some(card_no) = self.mmu {
match mmu.translate_address( match self.cards[card_no]
self, .borrow_mut()
CardAccessorBuilder { .try_as_mmu()
backplane: self, .unwrap()
card_no, .translate_address(self, address, write)
}, {
address,
write,
) {
NullableResult::Ok(address) => address, NullableResult::Ok(address) => address,
NullableResult::Err(e) => return Err(e), NullableResult::Err(e) => return Err(e),
NullableResult::Null => return Err(BusError), NullableResult::Null => return Err(BusError),
@ -282,33 +181,36 @@ impl Backplane {
} else { } else {
address address
}; };
match address { let res = match address {
(0..=0x00fe_ffff) | (0x0100_0000..=0xffff_ffff) => self (0..=0x00fe_ffff) | (0x0100_0000..=0xffff_ffff) => self
.cards .cards
.lock() .iter()
.iter_mut() .try_find_map(|card| mem_func(card.borrow_mut()))
.try_find_map(&mut mem_func)
.result(BusError), .result(BusError),
(0x00ff_0000..=0x00ff_00ff) => Ok(io_default), (0x00ff_0000..=0x00ff_00ff) => Ok(T::default()),
(0x00ff_0100..=0x00ff_ffff) => self (0x00ff_0100..=0x00ff_ffff) => self
.cards .cards
.lock() .get(((address >> 8) as u8 - 1) as usize)
.get_mut(((address >> 8) as u8 - 1) as usize) .map_or(Ok(T::default()), |card| {
.map_or(Ok(io_default), |card| { io_func(card.borrow_mut())
io_func(card).optional_result().unwrap_or(Ok(io_default)) .optional_result()
.unwrap_or(Ok(T::default()))
}), }),
} };
let val = res?;
self.handle_dma();
Ok(val)
} }
fn handle_dma(&self) { fn handle_dma(&self) {
for handler in self.dma_handlers.lock().iter_mut() { if !self.in_dma.get() {
handler.1.handle( self.in_dma.set(true);
self, for card in self.cards.iter() {
CardAccessorBuilder { if let Ok(mut card) = card.try_borrow_mut() {
backplane: self, card.handle_dma(self)
card_no: handler.0, }
}, }
) self.in_dma.set(false);
} }
} }
} }

View File

@ -1,14 +1,15 @@
#![allow(clippy::transmute_ptr_to_ref)] #![allow(clippy::transmute_ptr_to_ref)]
use crate::{ use crate::{backplane::Backplane, m68k::BusError};
backplane::{DMAHandler, MMUHandler},
m68k::BusError,
};
use anyhow::anyhow; use anyhow::anyhow;
use mopa::mopafy; use mopa::mopafy;
use nullable_result::NullableResult; use nullable_result::NullableResult;
use serde::Deserialize; use serde::Deserialize;
use std::fmt::{Debug, Display}; use std::{
cell::RefCell,
fmt::{Debug, Display},
rc::Rc,
};
use toml::Value; use toml::Value;
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
@ -21,7 +22,7 @@ pub struct Config<'a> {
impl Config<'_> { impl Config<'_> {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn into_card(self) -> anyhow::Result<(Box<dyn Card>, Option<Box<dyn DMAHandler>>)> { pub fn into_card(self) -> anyhow::Result<Rc<RefCell<dyn Card>>> {
inventory::iter::<Type>() inventory::iter::<Type>()
.find(|card_type| card_type.name == self.typ) .find(|card_type| card_type.name == self.typ)
.ok_or_else(|| anyhow!("Invalid card type {}", self.typ))? .ok_or_else(|| anyhow!("Invalid card type {}", self.typ))?
@ -31,8 +32,7 @@ impl Config<'_> {
pub struct Type { pub struct Type {
name: &'static str, name: &'static str,
#[allow(clippy::type_complexity)] new: fn(data: Value) -> anyhow::Result<Rc<RefCell<dyn Card>>>,
new: fn(data: Value) -> anyhow::Result<(Box<dyn Card>, Option<Box<dyn DMAHandler>>)>,
} }
impl Type { impl Type {
@ -43,11 +43,7 @@ impl Type {
} }
} }
#[allow(clippy::type_complexity)] fn new_card(&self, data: Value) -> anyhow::Result<Rc<RefCell<dyn Card>>> {
fn new_card(
&self,
data: Value,
) -> anyhow::Result<(Box<dyn Card>, Option<Box<dyn DMAHandler>>)> {
(self.new)(data) (self.new)(data)
} }
} }
@ -55,19 +51,15 @@ impl Type {
inventory::collect!(Type); inventory::collect!(Type);
pub trait Card: Debug + Display + mopa::Any { pub trait Card: Debug + Display + mopa::Any {
fn new(data: Value) -> anyhow::Result<(Self, Option<Box<dyn DMAHandler + 'static>>)> fn new(data: Value) -> anyhow::Result<Self>
where where
Self: Sized; Self: Sized;
#[allow(clippy::type_complexity)] fn new_dyn(data: Value) -> anyhow::Result<Rc<RefCell<dyn Card>>>
fn new_dyn(
data: Value,
) -> anyhow::Result<(Box<dyn Card>, Option<Box<dyn DMAHandler + 'static>>)>
where where
Self: Sized + 'static, Self: Sized + 'static,
{ {
let (card, handler) = Self::new(data)?; let card = Self::new(data)?;
let card = Box::new(card); Ok(Rc::new(RefCell::new(card)))
Ok((card, handler))
} }
fn display(&self) -> String { fn display(&self) -> String {
String::new() String::new()
@ -122,11 +114,22 @@ pub trait Card: Debug + Display + mopa::Any {
fn reset(&mut self) {} fn reset(&mut self) {}
fn try_get_mmu(&mut self) -> Option<Box<dyn MMUHandler>> { fn handle_dma(&mut self, _backplane: &Backplane) {}
fn try_as_mmu(&mut self) -> Option<&mut dyn MMU> {
None None
} }
} }
pub trait MMU: Card {
fn translate_address(
&mut self,
backplane: &Backplane,
address: u32,
write: bool,
) -> NullableResult<u32, BusError>;
}
mopafy!(Card); mopafy!(Card);
#[allow(dead_code)] #[allow(dead_code)]

View File

@ -3,8 +3,8 @@ use std::fmt::Display;
use nullable_result::NullableResult; use nullable_result::NullableResult;
use crate::{ use crate::{
backplane::{Backplane, CardAccessorBuilder, DMAHandler, MMUHandler}, backplane::Backplane,
card::{u16_get_be_byte, u32_get_be_byte, u32_set_be_byte, Card}, card::{u16_get_be_byte, u32_get_be_byte, u32_set_be_byte, Card, MMU},
m68k::BusError, m68k::BusError,
register, register,
}; };
@ -42,22 +42,19 @@ pub struct MmuCard {
} }
impl Card for MmuCard { impl Card for MmuCard {
fn new(_data: toml::Value) -> anyhow::Result<(Self, Option<Box<dyn DMAHandler>>)> { fn new(_data: toml::Value) -> anyhow::Result<Self> {
Ok(( Ok(Self {
Self { enabled: false,
enabled: false, cache: [None; 4096],
cache: [None; 4096], map_frames: [0; 4],
map_frames: [0; 4], map_frames_enabled: [false; 4],
map_frames_enabled: [false; 4], tlb_clear_entry: 0,
tlb_clear_entry: 0, print_debug: false,
print_debug: false, })
},
None,
))
} }
fn try_get_mmu(&mut self) -> Option<Box<dyn MMUHandler>> { fn try_as_mmu(&mut self) -> Option<&mut dyn MMU> {
Some(Box::new(Mmu)) Some(self)
} }
fn read_byte_io(&mut self, address: u8) -> NullableResult<u8, BusError> { fn read_byte_io(&mut self, address: u8) -> NullableResult<u8, BusError> {
@ -179,21 +176,18 @@ impl Display for MmuCard {
#[derive(Debug)] #[derive(Debug)]
pub struct Mmu; pub struct Mmu;
impl MMUHandler for Mmu { impl MMU for MmuCard {
fn translate_address<'a>( fn translate_address(
&mut self, &mut self,
backplane: &'a Backplane, backplane: &Backplane,
card_accessor: CardAccessorBuilder<'a>,
address: u32, address: u32,
write: bool, write: bool,
) -> NullableResult<u32, BusError> { ) -> NullableResult<u32, BusError> {
let card_accessor = card_accessor.build::<MmuCard>(); let print_debug = self.print_debug;
let card = card_accessor.get(); if self.enabled {
let print_debug = card.print_debug;
if card.enabled {
let page = address >> 12; let page = address >> 12;
let offset = address & 0xFFF; let offset = address & 0xFFF;
let entry = if let Some(entry) = card.cache[page as usize] { let entry = if let Some(entry) = self.cache[page as usize] {
if print_debug { if print_debug {
println!("TLB hit"); println!("TLB hit");
} }
@ -202,24 +196,23 @@ impl MMUHandler for Mmu {
if print_debug { if print_debug {
println!("TLB miss, fetching entry"); println!("TLB miss, fetching entry");
} }
if card.map_frames_enabled[(page >> 10) as usize] == false { if !self.map_frames_enabled[(page >> 10) as usize] {
if print_debug { if print_debug {
println!("No mapping frame for this quarter"); println!("No mapping frame for this quarter");
} }
return NullableResult::Null; return NullableResult::Null;
} }
let map_frame = card.map_frames[(page >> 10) as usize]; let map_frame = self.map_frames[(page >> 10) as usize];
let entry_address = (map_frame) | ((page & 0x3FF) << 2); let entry_address = (map_frame) | ((page & 0x3FF) << 2);
if print_debug { if print_debug {
println!("Entry is at {:#x}", entry_address); println!("Entry is at {entry_address:#x}");
} }
drop(card);
let entry_hi = backplane.read_word_phys(entry_address)?; let entry_hi = backplane.read_word_phys(entry_address)?;
let entry_lo = backplane.read_word_phys(entry_address + 2)?; let entry_lo = backplane.read_word_phys(entry_address + 2)?;
let entry = PagingEntry::from((entry_hi as u32) << 16 | entry_lo as u32); let entry = PagingEntry::from((entry_hi as u32) << 16 | entry_lo as u32);
card_accessor.get().cache[page as usize] = Some(entry); self.cache[page as usize] = Some(entry);
if print_debug { if print_debug {
println!("Fetched entry {:#?}", entry); println!("Fetched entry {entry:#?}");
} }
entry entry
}; };

View File

@ -6,7 +6,6 @@ use serde::Deserialize;
use toml::Value; use toml::Value;
use crate::{ use crate::{
backplane::DMAHandler,
card::{u16_get_be_byte, u32_get_be_byte, Card}, card::{u16_get_be_byte, u32_get_be_byte, Card},
m68k::BusError, m68k::BusError,
register, register,
@ -27,16 +26,13 @@ pub struct Ram {
} }
impl Card for Ram { impl Card for Ram {
fn new(data: Value) -> anyhow::Result<(Self, Option<Box<dyn DMAHandler>>)> { fn new(data: Value) -> anyhow::Result<Self> {
let size = data.try_into::<Config>()?.size; let size = data.try_into::<Config>()?.size;
Ok(( Ok(Self {
Self { data: vec![0; size as usize],
data: vec![0; size as usize], start: 0,
start: 0, enabled: false,
enabled: false, })
},
None,
))
} }
fn read_byte(&mut self, address: u32) -> NullableResult<u8, BusError> { fn read_byte(&mut self, address: u32) -> NullableResult<u8, BusError> {
if !self.enabled { if !self.enabled {

View File

@ -7,7 +7,6 @@ use serde::Deserialize;
use toml::Value; use toml::Value;
use crate::{ use crate::{
backplane::DMAHandler,
card::{u16_get_be_byte, u16_set_be_byte, Card}, card::{u16_get_be_byte, u16_set_be_byte, Card},
m68k::BusError, m68k::BusError,
register, register,
@ -32,7 +31,7 @@ pub struct Rom {
impl Rom {} impl Rom {}
impl Card for Rom { impl Card for Rom {
fn new(data: Value) -> anyhow::Result<(Self, Option<Box<dyn DMAHandler>>)> { fn new(data: Value) -> anyhow::Result<Self> {
let file_name = data.try_into::<Config>()?.image; let file_name = data.try_into::<Config>()?.image;
let mut data = Vec::new(); let mut data = Vec::new();
if let Some(file_name) = file_name.as_ref() { if let Some(file_name) = file_name.as_ref() {
@ -41,16 +40,13 @@ impl Card for Rom {
.read_to_end(&mut data) .read_to_end(&mut data)
.map_err(|e| anyhow!("Failed to read ROM image file {} ({})", file_name, e))?; .map_err(|e| anyhow!("Failed to read ROM image file {} ({})", file_name, e))?;
}; };
Ok(( Ok(Self {
Self { data,
data, enabled: true,
enabled: true, ram: [0; 32 * 1024],
ram: [0; 32 * 1024], file_name,
file_name, start: 0,
start: 0, })
},
None,
))
} }
fn read_byte(&mut self, address: u32) -> NullableResult<u8, BusError> { fn read_byte(&mut self, address: u32) -> NullableResult<u8, BusError> {

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
backplane::{Backplane, CardAccessorBuilder, DMAHandler}, backplane::Backplane,
card::{u16_get_be_byte, u32_get_be_byte, u32_set_be_byte, Card}, card::{u16_get_be_byte, u32_get_be_byte, u32_set_be_byte, Card},
m68k::BusError, m68k::BusError,
register, register,
@ -51,7 +51,7 @@ pub struct Storage {
// 0xC-0x10: Start address for DMA // 0xC-0x10: Start address for DMA
impl Card for Storage { impl Card for Storage {
fn new(data: Value) -> anyhow::Result<(Self, Option<Box<dyn DMAHandler>>)> { fn new(data: Value) -> anyhow::Result<Self> {
let file_name = data.try_into::<Config>()?.image; let file_name = data.try_into::<Config>()?.image;
let file = file_name let file = file_name
.as_ref() .as_ref()
@ -61,18 +61,15 @@ impl Card for Storage {
}) })
.transpose()?; .transpose()?;
Ok(( Ok(Self {
Self { file: file.zip(file_name),
file: file.zip(file_name), transfer: false,
transfer: false, sector: 0,
sector: 0, count: 0,
count: 0, status: Status::empty(),
status: Status::empty(), read_data: VecDeque::new(),
read_data: VecDeque::new(), start_addresss: 0,
start_addresss: 0, })
},
Some(Box::new(Dma)),
))
} }
fn read_byte_io(&mut self, address: u8) -> NullableResult<u8, BusError> { fn read_byte_io(&mut self, address: u8) -> NullableResult<u8, BusError> {
@ -153,6 +150,21 @@ impl Card for Storage {
} }
Ok(()) Ok(())
} }
fn handle_dma(&mut self, backplane: &Backplane) {
if self.transfer {
let mut address = self.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) = (|| self.read_data.pop_front())() {
backplane.write_byte(address, data).unwrap();
address += 1;
}
self.transfer = false;
self.status.set(Status::BUSY, false);
}
}
} }
impl Display for Storage { impl Display for Storage {
@ -171,24 +183,3 @@ impl Display for Storage {
} }
register!(Storage, "storage"); register!(Storage, "storage");
#[derive(Debug)]
struct Dma;
impl DMAHandler for Dma {
fn handle<'a>(&mut self, backplane: &'a Backplane, card_accessor: CardAccessorBuilder<'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);
}
}
}

View File

@ -4,7 +4,6 @@ use nullable_result::NullableResult;
use toml::Value; use toml::Value;
use crate::{ use crate::{
backplane::DMAHandler,
card::{u16_get_be_byte, Card}, card::{u16_get_be_byte, Card},
m68k::BusError, m68k::BusError,
register, register,
@ -22,11 +21,11 @@ impl Display for Term {
} }
impl Card for Term { impl Card for Term {
fn new(_data: Value) -> anyhow::Result<(Self, Option<Box<dyn DMAHandler>>)> fn new(_data: Value) -> anyhow::Result<Self>
where where
Self: Sized, Self: Sized,
{ {
Ok((Self, None)) Ok(Self)
} }
fn read_byte_io(&mut self, address: u8) -> NullableResult<u8, BusError> { fn read_byte_io(&mut self, address: u8) -> NullableResult<u8, BusError> {