From 6dc1d5d7983860de92815b85f499386996330afb Mon Sep 17 00:00:00 2001 From: pjht Date: Sat, 18 Mar 2023 17:40:19 -0500 Subject: [PATCH] Add support for interconnects between cards --- src/backplane.rs | 79 +++++++++++++++++++++++++++++++++++++++++++++++- src/card.rs | 19 +++++++++++- src/main.rs | 11 ++++++- 3 files changed, 106 insertions(+), 3 deletions(-) diff --git a/src/backplane.rs b/src/backplane.rs index 1853e0d..e1fac5a 100644 --- a/src/backplane.rs +++ b/src/backplane.rs @@ -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>, + card_no: usize, // used for error message on wrong type passed to build function +} + +impl InterconnectSenderBuilder { + #[allow(dead_code)] + pub fn build(self) -> InterconnectSender { + 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::(), + "Interconnect sender for card {} interconnect {} built with wrong type {}", + self.card_no, + self.interconnect_no, + any::type_name::() + ); + InterconnectSender { + interconnect_no: self.interconnect_no, + card: self.card, + phantom: PhantomData, + } + } +} + +#[allow(dead_code)] +pub struct InterconnectSender { + interconnect_no: usize, + card: Rc>, + phantom: PhantomData, +} + +impl InterconnectSender { + #[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>>, @@ -33,7 +84,10 @@ impl Display for Backplane { } impl Backplane { - pub fn new(card_configs: Vec>) -> anyhow::Result { + pub fn new( + card_configs: Vec>, + interconnects: Vec, + ) -> anyhow::Result { 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, diff --git a/src/card.rs b/src/card.rs index e396e67..39a1be7 100644 --- a/src/card.rs +++ b/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 { + None + } + + fn handle_interconnect_message(&mut self, _interconnect_no: usize, _message: Box) {} } pub trait MMU: Card { diff --git a/src/main.rs b/src/main.rs index 9edc3c3..db199f9 100644 --- a/src/main.rs +++ b/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>, #[serde(borrow)] symbol_tables: Option>, + interconnects: Option>, } 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 {