Add support for interconnects between cards
This commit is contained in:
parent
1cff8b26ce
commit
6dc1d5d798
@ -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,
|
||||
|
19
src/card.rs
19
src/card.rs
@ -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 {
|
||||
|
11
src/main.rs
11
src/main.rs
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user