From d32bcc3a8e0f4156115e52cbd5c79300c50bc538 Mon Sep 17 00:00:00 2001 From: pjht Date: Wed, 15 Mar 2023 18:53:03 -0500 Subject: [PATCH] Change to locking cards individually and remove now unnecessary traits --- Cargo.lock | 1 - Cargo.toml | 1 - src/backplane.rs | 272 +++++++++++++++-------------------------------- src/card.rs | 47 ++++---- src/mmu.rs | 55 +++++----- src/ram.rs | 16 ++- src/rom.rs | 20 ++-- src/storage.rs | 61 +++++------ src/term.rs | 5 +- 9 files changed, 178 insertions(+), 300 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c4eb6c9..6f367f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -521,7 +521,6 @@ dependencies = [ "itertools", "mopa", "nullable-result", - "parking_lot", "parse_int", "reedline-repl-rs", "serde", diff --git a/Cargo.toml b/Cargo.toml index 8415e5b..9656947 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,6 @@ inventory = "0.3.1" itertools = "0.10.5" mopa = "0.2.2" nullable-result = { version = "0.7.0", features=["try_trait"] } -parking_lot = "0.12.1" parse_int = "0.6.0" reedline-repl-rs = "1.0.2" serde = { version = "1.0.144", features = ["derive"] } diff --git a/src/backplane.rs b/src/backplane.rs index 70d1662..1853e0d 100644 --- a/src/backplane.rs +++ b/src/backplane.rs @@ -1,73 +1,21 @@ -use std::fmt::Debug; -use std::fmt::Display; -use std::marker::PhantomData; +use std::cell::{Cell, RefCell, RefMut}; +use std::fmt::{Debug, Display}; +use std::rc::Rc; use anyhow::anyhow; use itertools::Itertools; use nullable_result::{GeneralIterExt, NullableResult}; -use parking_lot::MappedMutexGuard; -use parking_lot::Mutex; -use parking_lot::MutexGuard; use crate::{ card::{self, Card}, 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; -} - -#[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(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, -} - -impl CardAccessor<'_, T> { - #[allow(dead_code)] - pub fn get(&self) -> MappedMutexGuard { - MutexGuard::map(self.backplane.cards.lock(), |cards| { - cards[self.card_no].downcast_mut::().unwrap() - }) - } -} - #[derive(Debug)] pub struct Backplane { - cards: Mutex>>, - dma_handlers: Mutex)>>, - mmu: Mutex)>>, + cards: Vec>>, + mmu: Option, + in_dma: Cell, } impl Display for Backplane { @@ -75,11 +23,10 @@ impl Display for Backplane { f.write_fmt(format_args!( "{}", self.cards - .lock() .iter() .enumerate() .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 { return Err(anyhow!("A maximum of 255 cards are allowed")); } - let mut cards = Vec::new(); - let mut dma_handlers = Vec::new(); - let mut mmu = None; - for item in card_configs.into_iter().map(|cfg| cfg.into_card()) { - let (mut card, dma_handler) = item?; - if let Some(dma_handler) = dma_handler { - dma_handlers.push((cards.len(), dma_handler)); - } - if let Some(mmu_ret) = card.try_get_mmu() { - if mmu.is_some() { - panic!("Can't have two MMU cards!"); - } else { - mmu = Some((cards.len(), mmu_ret)); - } - } - cards.push(card); - } + let cards: Vec<_> = card_configs + .into_iter() + .map(|cfg| cfg.into_card()) + .try_collect()?; + + let mmu = cards + .iter() + .enumerate() + .filter_map(|(i, card)| card.borrow_mut().try_as_mmu().map(|_| i)) + .at_most_one() + .expect("Can't have two MMU cards!"); Ok(Self { - cards: Mutex::new(cards), - dma_handlers: Mutex::new(dma_handlers), - mmu: Mutex::new(mmu), + cards, + mmu, + in_dma: Cell::new(false), }) } pub fn reset(&self) { - for card in self.cards.lock().iter_mut() { - card.reset(); + for card in self.cards.iter() { + card.borrow_mut().reset(); } } pub fn card_cmd(&self, card_num: u8, cmd: &[&str]) -> anyhow::Result<()> { self.cards - .lock() - .get_mut(card_num as usize) + .get(card_num as usize) .ok_or_else(|| anyhow!("Card {} does not exist", card_num))? + .borrow_mut() .cmd(cmd) } pub fn read_word(&self, address: u32) -> Result { - let data = self.mem_helper( + self.mem_helper( address, - |card| card.read_word(address), - |card| card.read_word_io(address as u8), - 0, + |mut card| card.read_word(address), + |mut card| card.read_word_io(address as u8), false, false, - )?; - if !self.dma_handlers.is_locked() { - self.handle_dma() - } - Ok(data) + ) } pub fn read_byte(&self, address: u32) -> Result { - let data = self.mem_helper( + self.mem_helper( address, - |card| card.read_byte(address), - |card| card.read_byte_io(address as u8), - 0, + |mut card| card.read_byte(address), + |mut card| card.read_byte_io(address as u8), false, false, - )?; - if !self.dma_handlers.is_locked() { - self.handle_dma() - } - Ok(data) + ) } pub fn write_word(&self, address: u32, data: u16) -> Result<(), BusError> { self.mem_helper( address, - |card| card.write_word(address, data), - |card| card.write_word_io(address as u8, data), - (), + |mut card| card.write_word(address, data), + |mut card| card.write_word_io(address as u8, data), false, true, - )?; - if !self.dma_handlers.is_locked() { - self.handle_dma() - } - Ok(()) + ) } pub fn write_byte(&self, address: u32, data: u8) -> Result<(), BusError> { self.mem_helper( address, - |card| card.write_byte(address, data), - |card| card.write_byte_io(address as u8, data), - (), + |mut card| card.write_byte(address, data), + |mut card| card.write_byte_io(address as u8, data), false, true, - )?; - if !self.dma_handlers.is_locked() { - self.handle_dma() - } - Ok(()) + ) } pub fn read_word_phys(&self, address: u32) -> Result { - let data = self.mem_helper( + self.mem_helper( address, - |card| card.read_word(address), - |card| card.read_word_io(address as u8), - 0, + |mut card| card.read_word(address), + |mut card| card.read_word_io(address as u8), true, false, - )?; - if !self.dma_handlers.is_locked() { - self.handle_dma() - } - Ok(data) + ) } + #[allow(dead_code)] pub fn read_byte_phys(&self, address: u32) -> Result { - let data = self.mem_helper( + self.mem_helper( address, - |card| card.read_byte(address), - |card| card.read_byte_io(address as u8), - 0, + |mut card| card.read_byte(address), + |mut card| card.read_byte_io(address as u8), true, 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> { self.mem_helper( address, - |card| card.write_word(address, data), - |card| card.write_word_io(address as u8, data), - (), + |mut card| card.write_word(address, data), + |mut card| card.write_word_io(address as u8, data), 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> { self.mem_helper( address, - |card| card.write_byte(address, data), - |card| card.write_byte_io(address as u8, data), - (), + |mut card| card.write_byte(address, data), + |mut card| card.write_byte_io(address as u8, data), true, true, - )?; - if !self.dma_handlers.is_locked() { - self.handle_dma() - } - Ok(()) + ) } - fn mem_helper( + fn mem_helper( &self, address: u32, mut mem_func: M, mut io_func: I, - io_default: T, bypass_mmu: bool, write: bool, ) -> Result where - M: FnMut(&mut Box) -> NullableResult, - I: FnMut(&mut Box) -> NullableResult, - T: Copy, + M: FnMut(RefMut<'_, dyn Card>) -> NullableResult, + I: FnMut(RefMut<'_, dyn Card>) -> NullableResult, { let address = if bypass_mmu { address - } else if let Some((card_no, ref mut mmu)) = *self.mmu.lock() { - match mmu.translate_address( - self, - CardAccessorBuilder { - backplane: self, - card_no, - }, - address, - write, - ) { + } else if let Some(card_no) = self.mmu { + match self.cards[card_no] + .borrow_mut() + .try_as_mmu() + .unwrap() + .translate_address(self, address, write) + { NullableResult::Ok(address) => address, NullableResult::Err(e) => return Err(e), NullableResult::Null => return Err(BusError), @@ -282,33 +181,36 @@ impl Backplane { } else { address }; - match address { + let res = match address { (0..=0x00fe_ffff) | (0x0100_0000..=0xffff_ffff) => self .cards - .lock() - .iter_mut() - .try_find_map(&mut mem_func) + .iter() + .try_find_map(|card| mem_func(card.borrow_mut())) .result(BusError), - (0x00ff_0000..=0x00ff_00ff) => Ok(io_default), + (0x00ff_0000..=0x00ff_00ff) => Ok(T::default()), (0x00ff_0100..=0x00ff_ffff) => self .cards - .lock() - .get_mut(((address >> 8) as u8 - 1) as usize) - .map_or(Ok(io_default), |card| { - io_func(card).optional_result().unwrap_or(Ok(io_default)) + .get(((address >> 8) as u8 - 1) as usize) + .map_or(Ok(T::default()), |card| { + io_func(card.borrow_mut()) + .optional_result() + .unwrap_or(Ok(T::default())) }), - } + }; + let val = res?; + self.handle_dma(); + Ok(val) } fn handle_dma(&self) { - for handler in self.dma_handlers.lock().iter_mut() { - handler.1.handle( - self, - CardAccessorBuilder { - backplane: self, - card_no: handler.0, - }, - ) + if !self.in_dma.get() { + self.in_dma.set(true); + for card in self.cards.iter() { + if let Ok(mut card) = card.try_borrow_mut() { + card.handle_dma(self) + } + } + self.in_dma.set(false); } } } diff --git a/src/card.rs b/src/card.rs index da97cee..e396e67 100644 --- a/src/card.rs +++ b/src/card.rs @@ -1,14 +1,15 @@ #![allow(clippy::transmute_ptr_to_ref)] -use crate::{ - backplane::{DMAHandler, MMUHandler}, - m68k::BusError, -}; +use crate::{backplane::Backplane, m68k::BusError}; use anyhow::anyhow; use mopa::mopafy; use nullable_result::NullableResult; use serde::Deserialize; -use std::fmt::{Debug, Display}; +use std::{ + cell::RefCell, + fmt::{Debug, Display}, + rc::Rc, +}; use toml::Value; #[derive(Deserialize, Debug)] @@ -21,7 +22,7 @@ pub struct Config<'a> { impl Config<'_> { #[allow(clippy::type_complexity)] - pub fn into_card(self) -> anyhow::Result<(Box, Option>)> { + pub fn into_card(self) -> anyhow::Result>> { inventory::iter::() .find(|card_type| card_type.name == self.typ) .ok_or_else(|| anyhow!("Invalid card type {}", self.typ))? @@ -31,8 +32,7 @@ impl Config<'_> { pub struct Type { name: &'static str, - #[allow(clippy::type_complexity)] - new: fn(data: Value) -> anyhow::Result<(Box, Option>)>, + new: fn(data: Value) -> anyhow::Result>>, } impl Type { @@ -43,11 +43,7 @@ impl Type { } } - #[allow(clippy::type_complexity)] - fn new_card( - &self, - data: Value, - ) -> anyhow::Result<(Box, Option>)> { + fn new_card(&self, data: Value) -> anyhow::Result>> { (self.new)(data) } } @@ -55,19 +51,15 @@ impl Type { inventory::collect!(Type); pub trait Card: Debug + Display + mopa::Any { - fn new(data: Value) -> anyhow::Result<(Self, Option>)> + fn new(data: Value) -> anyhow::Result where Self: Sized; - #[allow(clippy::type_complexity)] - fn new_dyn( - data: Value, - ) -> anyhow::Result<(Box, Option>)> + fn new_dyn(data: Value) -> anyhow::Result>> where Self: Sized + 'static, { - let (card, handler) = Self::new(data)?; - let card = Box::new(card); - Ok((card, handler)) + let card = Self::new(data)?; + Ok(Rc::new(RefCell::new(card))) } fn display(&self) -> String { String::new() @@ -122,11 +114,22 @@ pub trait Card: Debug + Display + mopa::Any { fn reset(&mut self) {} - fn try_get_mmu(&mut self) -> Option> { + fn handle_dma(&mut self, _backplane: &Backplane) {} + + fn try_as_mmu(&mut self) -> Option<&mut dyn MMU> { None } } +pub trait MMU: Card { + fn translate_address( + &mut self, + backplane: &Backplane, + address: u32, + write: bool, + ) -> NullableResult; +} + mopafy!(Card); #[allow(dead_code)] diff --git a/src/mmu.rs b/src/mmu.rs index 6ab88ae..1402119 100644 --- a/src/mmu.rs +++ b/src/mmu.rs @@ -3,8 +3,8 @@ use std::fmt::Display; use nullable_result::NullableResult; use crate::{ - backplane::{Backplane, CardAccessorBuilder, DMAHandler, MMUHandler}, - card::{u16_get_be_byte, u32_get_be_byte, u32_set_be_byte, Card}, + backplane::Backplane, + card::{u16_get_be_byte, u32_get_be_byte, u32_set_be_byte, Card, MMU}, m68k::BusError, register, }; @@ -42,22 +42,19 @@ pub struct MmuCard { } impl Card for MmuCard { - fn new(_data: toml::Value) -> anyhow::Result<(Self, Option>)> { - Ok(( - Self { - enabled: false, - cache: [None; 4096], - map_frames: [0; 4], - map_frames_enabled: [false; 4], - tlb_clear_entry: 0, - print_debug: false, - }, - None, - )) + fn new(_data: toml::Value) -> anyhow::Result { + Ok(Self { + enabled: false, + cache: [None; 4096], + map_frames: [0; 4], + map_frames_enabled: [false; 4], + tlb_clear_entry: 0, + print_debug: false, + }) } - fn try_get_mmu(&mut self) -> Option> { - Some(Box::new(Mmu)) + fn try_as_mmu(&mut self) -> Option<&mut dyn MMU> { + Some(self) } fn read_byte_io(&mut self, address: u8) -> NullableResult { @@ -179,21 +176,18 @@ impl Display for MmuCard { #[derive(Debug)] pub struct Mmu; -impl MMUHandler for Mmu { - fn translate_address<'a>( +impl MMU for MmuCard { + fn translate_address( &mut self, - backplane: &'a Backplane, - card_accessor: CardAccessorBuilder<'a>, + backplane: &Backplane, address: u32, write: bool, ) -> NullableResult { - let card_accessor = card_accessor.build::(); - let card = card_accessor.get(); - let print_debug = card.print_debug; - if card.enabled { + let print_debug = self.print_debug; + if self.enabled { let page = address >> 12; 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 { println!("TLB hit"); } @@ -202,24 +196,23 @@ impl MMUHandler for Mmu { if print_debug { 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 { println!("No mapping frame for this quarter"); } 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); 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_lo = backplane.read_word_phys(entry_address + 2)?; 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 { - println!("Fetched entry {:#?}", entry); + println!("Fetched entry {entry:#?}"); } entry }; diff --git a/src/ram.rs b/src/ram.rs index ffe8dd9..ca8dd94 100644 --- a/src/ram.rs +++ b/src/ram.rs @@ -6,7 +6,6 @@ use serde::Deserialize; use toml::Value; use crate::{ - backplane::DMAHandler, card::{u16_get_be_byte, u32_get_be_byte, Card}, m68k::BusError, register, @@ -27,16 +26,13 @@ pub struct Ram { } impl Card for Ram { - fn new(data: Value) -> anyhow::Result<(Self, Option>)> { + fn new(data: Value) -> anyhow::Result { let size = data.try_into::()?.size; - Ok(( - Self { - data: vec![0; size as usize], - start: 0, - enabled: false, - }, - None, - )) + Ok(Self { + data: vec![0; size as usize], + start: 0, + enabled: false, + }) } fn read_byte(&mut self, address: u32) -> NullableResult { if !self.enabled { diff --git a/src/rom.rs b/src/rom.rs index 9a7f3fe..c92c980 100644 --- a/src/rom.rs +++ b/src/rom.rs @@ -7,7 +7,6 @@ use serde::Deserialize; use toml::Value; use crate::{ - backplane::DMAHandler, card::{u16_get_be_byte, u16_set_be_byte, Card}, m68k::BusError, register, @@ -32,7 +31,7 @@ pub struct Rom { impl Rom {} impl Card for Rom { - fn new(data: Value) -> anyhow::Result<(Self, Option>)> { + fn new(data: Value) -> anyhow::Result { let file_name = data.try_into::()?.image; let mut data = Vec::new(); if let Some(file_name) = file_name.as_ref() { @@ -41,16 +40,13 @@ impl Card for Rom { .read_to_end(&mut data) .map_err(|e| anyhow!("Failed to read ROM image file {} ({})", file_name, e))?; }; - Ok(( - Self { - data, - enabled: true, - ram: [0; 32 * 1024], - file_name, - start: 0, - }, - None, - )) + Ok(Self { + data, + enabled: true, + ram: [0; 32 * 1024], + file_name, + start: 0, + }) } fn read_byte(&mut self, address: u32) -> NullableResult { diff --git a/src/storage.rs b/src/storage.rs index 9193ba8..1b7158a 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -1,5 +1,5 @@ use crate::{ - backplane::{Backplane, CardAccessorBuilder, DMAHandler}, + backplane::Backplane, card::{u16_get_be_byte, u32_get_be_byte, u32_set_be_byte, Card}, m68k::BusError, register, @@ -51,7 +51,7 @@ pub struct Storage { // 0xC-0x10: Start address for DMA impl Card for Storage { - fn new(data: Value) -> anyhow::Result<(Self, Option>)> { + fn new(data: Value) -> anyhow::Result { let file_name = data.try_into::()?.image; let file = file_name .as_ref() @@ -61,18 +61,15 @@ impl Card for Storage { }) .transpose()?; - Ok(( - Self { - file: file.zip(file_name), - transfer: false, - sector: 0, - count: 0, - status: Status::empty(), - read_data: VecDeque::new(), - start_addresss: 0, - }, - Some(Box::new(Dma)), - )) + Ok(Self { + file: file.zip(file_name), + transfer: false, + sector: 0, + count: 0, + status: Status::empty(), + read_data: VecDeque::new(), + start_addresss: 0, + }) } fn read_byte_io(&mut self, address: u8) -> NullableResult { @@ -153,6 +150,21 @@ impl Card for Storage { } 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 { @@ -171,24 +183,3 @@ 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: CardAccessorBuilder<'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); - } - } -} diff --git a/src/term.rs b/src/term.rs index 7b5633c..728e3f4 100644 --- a/src/term.rs +++ b/src/term.rs @@ -4,7 +4,6 @@ use nullable_result::NullableResult; use toml::Value; use crate::{ - backplane::DMAHandler, card::{u16_get_be_byte, Card}, m68k::BusError, register, @@ -22,11 +21,11 @@ impl Display for Term { } impl Card for Term { - fn new(_data: Value) -> anyhow::Result<(Self, Option>)> + fn new(_data: Value) -> anyhow::Result where Self: Sized, { - Ok((Self, None)) + Ok(Self) } fn read_byte_io(&mut self, address: u8) -> NullableResult {