Change to locking cards individually and remove now unnecessary traits
This commit is contained in:
parent
21181fc645
commit
d32bcc3a8e
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -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",
|
||||||
|
@ -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"] }
|
||||||
|
272
src/backplane.rs
272
src/backplane.rs
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
47
src/card.rs
47
src/card.rs
@ -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)]
|
||||||
|
55
src/mmu.rs
55
src/mmu.rs
@ -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
|
||||||
};
|
};
|
||||||
|
16
src/ram.rs
16
src/ram.rs
@ -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 {
|
||||||
|
20
src/rom.rs
20
src/rom.rs
@ -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> {
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -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> {
|
||||||
|
Loading…
Reference in New Issue
Block a user