Add support for interconnects between cards

This commit is contained in:
pjht 2023-03-18 17:40:19 -05:00
parent 1cff8b26ce
commit 6dc1d5d798
Signed by: pjht
GPG Key ID: 7B5F6AFBEC7EE78E
3 changed files with 106 additions and 3 deletions

View File

@ -1,16 +1,67 @@
use std::any::{self, TypeId};
use std::cell::{Cell, RefCell, RefMut};
use std::fmt::{Debug, Display};
use std::marker::PhantomData;
use std::rc::Rc;
use anyhow::anyhow;
use itertools::Itertools;
use nullable_result::{GeneralIterExt, NullableResult};
use crate::InterconnectConfig;
use crate::{
card::{self, Card},
m68k::BusError,
};
#[allow(dead_code)]
pub struct InterconnectSenderBuilder {
interconnect_no: usize,
card: Rc<RefCell<dyn Card>>,
card_no: usize, // used for error message on wrong type passed to build function
}
impl InterconnectSenderBuilder {
#[allow(dead_code)]
pub fn build<T>(self) -> InterconnectSender<T> {
assert!(
self.card
.borrow_mut()
.get_interconnect_typeid(self.interconnect_no)
.unwrap_or_else(|| panic!(
"Card {} interconnect {} does not exist",
self.card_no, self.interconnect_no
))
== TypeId::of::<T>(),
"Interconnect sender for card {} interconnect {} built with wrong type {}",
self.card_no,
self.interconnect_no,
any::type_name::<T>()
);
InterconnectSender {
interconnect_no: self.interconnect_no,
card: self.card,
phantom: PhantomData,
}
}
}
#[allow(dead_code)]
pub struct InterconnectSender<T: 'static> {
interconnect_no: usize,
card: Rc<RefCell<dyn Card>>,
phantom: PhantomData<T>,
}
impl<T> InterconnectSender<T> {
#[allow(dead_code)]
pub fn send(&mut self, message: T) {
self.card
.borrow_mut()
.handle_interconnect_message(self.interconnect_no, Box::new(message));
}
}
#[derive(Debug)]
pub struct Backplane {
cards: Vec<Rc<RefCell<dyn Card>>>,
@ -33,7 +84,10 @@ impl Display for Backplane {
}
impl Backplane {
pub fn new(card_configs: Vec<card::Config<'_>>) -> anyhow::Result<Self> {
pub fn new(
card_configs: Vec<card::Config<'_>>,
interconnects: Vec<InterconnectConfig>,
) -> anyhow::Result<Self> {
if card_configs.len() > 255 {
return Err(anyhow!("A maximum of 255 cards are allowed"));
}
@ -49,6 +103,29 @@ impl Backplane {
.at_most_one()
.expect("Can't have two MMU cards!");
for interconnect in interconnects {
cards[interconnect.a_index]
.borrow_mut()
.set_interconnect_sender(
interconnect.a_interconnect_no,
InterconnectSenderBuilder {
interconnect_no: interconnect.b_interconnect_no,
card: Rc::clone(&cards[interconnect.b_index]),
card_no: interconnect.b_index,
},
);
cards[interconnect.b_index]
.borrow_mut()
.set_interconnect_sender(
interconnect.b_interconnect_no,
InterconnectSenderBuilder {
interconnect_no: interconnect.a_interconnect_no,
card: Rc::clone(&cards[interconnect.a_index]),
card_no: interconnect.a_index,
},
)
}
Ok(Self {
cards,
mmu,

View File

@ -1,11 +1,15 @@
#![allow(clippy::transmute_ptr_to_ref)]
use crate::{backplane::Backplane, m68k::BusError};
use crate::{
backplane::{Backplane, InterconnectSenderBuilder},
m68k::BusError,
};
use anyhow::anyhow;
use mopa::mopafy;
use nullable_result::NullableResult;
use serde::Deserialize;
use std::{
any::{Any, TypeId},
cell::RefCell,
fmt::{Debug, Display},
rc::Rc,
@ -119,6 +123,19 @@ pub trait Card: Debug + Display + mopa::Any {
fn try_as_mmu(&mut self) -> Option<&mut dyn MMU> {
None
}
fn set_interconnect_sender(
&mut self,
_interconnect_no: usize,
_sender: InterconnectSenderBuilder,
) {
}
fn get_interconnect_typeid(&mut self, _interconnect_no: usize) -> Option<TypeId> {
None
}
fn handle_interconnect_message(&mut self, _interconnect_no: usize, _message: Box<dyn Any>) {}
}
pub trait MMU: Card {

View File

@ -34,12 +34,21 @@ use serde::Deserialize;
use std::{fs, path::Path, process};
use symbol_tables::SymbolTables;
#[derive(Deserialize, Debug)]
pub struct InterconnectConfig {
a_index: usize,
a_interconnect_no: usize,
b_index: usize,
b_interconnect_no: usize,
}
#[derive(Deserialize, Debug)]
struct EmuConfig<'a> {
#[serde(borrow)]
cards: Vec<card::Config<'a>>,
#[serde(borrow)]
symbol_tables: Option<Vec<&'a str>>,
interconnects: Option<Vec<InterconnectConfig>>,
}
struct EmuState {
@ -65,7 +74,7 @@ fn main() -> Result<(), anyhow::Error> {
.map_err(|e| anyhow!("Could not read config file ({})", e))?;
let config: EmuConfig =
toml::from_str(&config_str).map_err(|e| anyhow!("Could not parse config file ({})", e))?;
let backplane = Backplane::new(config.cards)?;
let backplane = Backplane::new(config.cards, config.interconnects.unwrap_or_default())?;
let mut symbol_tables = SymbolTables::new();
if let Some(initial_tables) = config.symbol_tables {
for path in initial_tables {