From 64571e45b8539a83eacaa0f7204439b1d6962771 Mon Sep 17 00:00:00 2001 From: "Jomer.Dev" Date: Sun, 16 Jun 2024 01:17:39 +0200 Subject: [PATCH] Rewrite system device storage --- emulator/core/src/devices.rs | 103 +++++++++------ emulator/core/src/lib.rs | 6 +- emulator/core/src/system.rs | 169 ++++++++++++++++++------- emulator/libraries/debugger/src/lib.rs | 28 ++-- 4 files changed, 204 insertions(+), 102 deletions(-) diff --git a/emulator/core/src/devices.rs b/emulator/core/src/devices.rs index 6ffae86..018d1b4 100644 --- a/emulator/core/src/devices.rs +++ b/emulator/core/src/devices.rs @@ -1,6 +1,8 @@ +use std::any::{Any, TypeId}; +use std::ops::Deref; use std::rc::Rc; -use std::cell::{RefCell, RefMut, BorrowMutError}; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::cell::RefCell; +use std::sync::atomic::{AtomicU32, Ordering}; use femtos::{Duration, Instant}; use crate::{Error, System}; @@ -172,6 +174,13 @@ pub trait Inspectable { } +pub type DeviceId = u32; +pub trait Resource: Any + 'static + Transmutable {} + +pub type Device = Rc>; + +impl Resource for T where T: Transmutable + 'static {} + pub trait Transmutable { #[inline] fn as_steppable(&mut self) -> Option<&mut dyn Steppable> { @@ -199,54 +208,76 @@ pub trait Transmutable { } } +// Taken from deno_core +fn is(field: &dyn Resource) -> bool { + field.type_id() == TypeId::of::() +} + +// Taken from deno_core +pub fn downcast_rc_refc<'a, T: Resource>(field: &'a Device) -> Option<&'a Rc>> { + if is::(field.borrow().deref()) { + let ptr = field as *const Rc> as *const Rc>; + #[allow(clippy::undocumented_unsafe_blocks)] + Some(unsafe { &*ptr }) + } else { + None + } +} + pub type TransmutableBox = Rc>>; pub fn wrap_transmutable(value: T) -> TransmutableBox { Rc::new(RefCell::new(Box::new(value))) } -static NEXT_ID: AtomicUsize = AtomicUsize::new(1); +static NEXT_ID: AtomicU32 = AtomicU32::new(1); -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub struct DeviceId(usize); - -impl DeviceId { - pub fn new() -> Self { - let next = NEXT_ID.load(Ordering::Acquire); - NEXT_ID.store(next + 1, Ordering::Release); - Self(next) - } +pub fn get_next_id() -> u32 { + let next = NEXT_ID.load(Ordering::Acquire); + NEXT_ID.store(next + 1, Ordering::Release); + next } -impl Default for DeviceId { - fn default() -> Self { - Self::new() - } -} +// #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +// pub struct DeviceId(usize); -#[derive(Clone)] -pub struct Device(DeviceId, TransmutableBox); +// impl DeviceId { +// pub fn new() -> Self { +// let next = NEXT_ID.load(Ordering::Acquire); +// NEXT_ID.store(next + 1, Ordering::Release); +// Self(next) +// } +// } -impl Device { - pub fn new(value: T) -> Self - where - T: Transmutable + 'static, - { - Self(DeviceId::new(), wrap_transmutable(value)) - } +// impl Default for DeviceId { +// fn default() -> Self { +// Self::new() +// } +// } - pub fn id(&self) -> DeviceId { - self.0 - } +// #[derive(Clone)] +// pub struct Device(DeviceId, TransmutableBox); - pub fn borrow_mut(&self) -> RefMut<'_, Box> { - self.1.borrow_mut() - } +// impl Device { +// pub fn new(value: T) -> Self +// where +// T: Transmutable + 'static, +// { +// Self(DeviceId::new(), wrap_transmutable(value)) +// } - pub fn try_borrow_mut(&self) -> Result>, BorrowMutError> { - self.1.try_borrow_mut() - } -} +// pub fn id(&self) -> DeviceId { +// self.0 +// } + +// pub fn borrow_mut(&self) -> RefMut<'_, Box> { +// self.1.borrow_mut() +// } + +// pub fn try_borrow_mut(&self) -> Result>, BorrowMutError> { +// self.1.try_borrow_mut() +// } +// } /* diff --git a/emulator/core/src/lib.rs b/emulator/core/src/lib.rs index c0c332f..0f4e6ae 100644 --- a/emulator/core/src/lib.rs +++ b/emulator/core/src/lib.rs @@ -7,7 +7,7 @@ mod memory; mod system; pub use crate::devices::{ - Address, Addressable, Steppable, Interruptable, Debuggable, Inspectable, Transmutable, TransmutableBox, Device, + Address, Addressable, Steppable, Interruptable, Debuggable, Inspectable, Transmutable, TransmutableBox, Resource }; pub use crate::devices::{ read_beu16, read_beu32, read_leu16, read_leu32, write_beu16, write_beu32, write_leu16, write_leu32, wrap_transmutable, @@ -15,6 +15,6 @@ pub use crate::devices::{ pub use crate::error::Error; pub use crate::interrupts::InterruptController; pub use crate::memory::{MemoryBlock, AddressTranslator, AddressRepeater, Bus, BusPort, dump_slice, dump_memory}; -pub use crate::system::System; +pub use crate::system::{System, DeviceSettings}; -pub use emulator_hal::bus::{BusAccess}; +pub use emulator_hal::bus::BusAccess; diff --git a/emulator/core/src/system.rs b/emulator/core/src/system.rs index 60eff8b..f4f2070 100644 --- a/emulator/core/src/system.rs +++ b/emulator/core/src/system.rs @@ -1,29 +1,33 @@ use std::rc::Rc; use std::cell::{RefCell, RefMut}; -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use femtos::{Instant, Duration}; -use crate::{Bus, Error, InterruptController, Address, Device}; +use crate::devices::{downcast_rc_refc, get_next_id, Device, DeviceId, Resource}; +use crate::{Address, Bus, Error, InterruptController}; pub struct System { pub clock: Instant, - pub devices: HashMap, + pub devices: BTreeMap, pub event_queue: Vec, + pub id_to_name: HashMap, - pub debuggables: Vec, + pub debuggables: Vec, pub bus: Rc>, pub buses: HashMap>>, pub interrupt_controller: RefCell, } + impl Default for System { fn default() -> Self { Self { clock: Instant::START, - devices: HashMap::new(), + devices: BTreeMap::new(), event_queue: vec![], + id_to_name: HashMap::new(), debuggables: Vec::new(), @@ -34,6 +38,24 @@ impl Default for System { } } +pub struct DeviceSettings { + pub name: Option, + pub address: Option
, + pub debuggable: bool, + pub queue: bool, +} + +impl Default for DeviceSettings { + fn default() -> Self { + Self { + name: None, + address: None, + debuggable: false, + queue: false, + } + } +} + impl System { pub fn get_bus(&self) -> RefMut<'_, Bus> { self.bus.borrow_mut() @@ -43,43 +65,104 @@ impl System { self.interrupt_controller.borrow_mut() } - pub fn get_device(&self, name: &str) -> Result { + pub fn get_device(&self, device: DeviceId) -> Result>, Error> { self.devices - .get(name) + .get(&device) + .and_then(|rc| downcast_rc_refc::(rc)) .cloned() - .ok_or_else(|| Error::new(format!("system: no device named {}", name))) + .ok_or_else(|| Error::new(format!("system: bad device id {}", device))) } - pub fn add_device(&mut self, name: &str, device: Device) -> Result<(), Error> { - self.try_add_debuggable(device.clone()); - self.try_queue_device(device.clone()); - self.devices.insert(name.to_string(), device); - Ok(()) + pub fn get_device_by_name(&self, name: &str) -> Result>, Error> { + let id = self.id_to_name.iter().find_map(|(key, &ref val)| if val == name { Some(key)} else { None }); + if let Some(id) = id { + self.get_device(*id) + } else { + Err(Error::new(format!("system: could not find device {}", name))) + } } - pub fn add_addressable_device(&mut self, addr: Address, device: Device) -> Result<(), Error> { - self.add_peripheral(&format!("mem{:x}", addr), addr, device) + pub fn get_dyn_device(&self, device: DeviceId) -> Result { + self.devices + .get(&device) + .cloned() + .ok_or_else(|| Error::new(format!("system: bad device id {}", device))) } - pub fn add_peripheral(&mut self, name: &str, addr: Address, device: Device) -> Result<(), Error> { - self.bus.borrow_mut().insert(addr, device.clone()); - self.try_add_debuggable(device.clone()); - self.try_queue_device(device.clone()); - self.devices.insert(name.to_string(), device); - Ok(()) + pub fn get_dyn_device_by_name(&self, name: &str) -> Result { + let id = self.id_to_name.iter().find_map(|(key, &ref val)| if val == name { Some(key)} else { None }); + if let Some(id) = id { + self.get_dyn_device(*id) + } else { + Err(Error::new(format!("system: could not find device {}", name))) + } } - pub fn add_interruptable_device(&mut self, name: &str, device: Device) -> Result<(), Error> { - self.try_add_debuggable(device.clone()); - self.try_queue_device(device.clone()); - self.devices.insert(name.to_string(), device); - Ok(()) + pub fn add_device(&mut self, device: T, settings: DeviceSettings) -> Result { + self.add_device_rc_ref(Rc::new(RefCell::new(device)), settings) + } + + pub fn add_device_rc_ref(&mut self, device: Rc>, settings: DeviceSettings) -> Result { + let device = device as Device; + self.add_device_rc_dyn(device, settings) + } + + pub fn add_device_rc_dyn(&mut self, device: Device, settings: DeviceSettings) -> Result { + let id = get_next_id(); + self.id_to_name.insert(id, settings.name.unwrap_or_default()); + + self.devices.insert(id, device.clone()); + + if settings.debuggable && device.borrow_mut().as_debuggable().is_some() { + self.debuggables.push(id); + } + if settings.queue && device.borrow_mut().as_steppable().is_some() { + self.queue_device(NextStep::new(id)); + } + if let Some(addr) = settings.address { + self.bus.borrow_mut().insert(addr, device.clone()); + } + Ok(id) + } + + pub fn add_named_device(&mut self, name: &str, device: T) -> Result { + self.add_device(device, DeviceSettings { + name: Some(name.to_owned()), + queue: true, + ..Default::default() + }) + } + + pub fn add_addressable_device(&mut self, addr: Address, device: T) -> Result { + self.add_device(device, DeviceSettings { + name: Some(format!("mem{:x}", addr)), + address: Some(addr), + queue: true, + ..Default::default() + }) + } + + pub fn add_peripheral(&mut self, name: &str, addr: Address, device: T) -> Result { + self.add_device(device, DeviceSettings { + name: Some(name.to_owned()), + address: Some(addr), + queue: true, + ..Default::default() + }) + } + + pub fn add_interruptable_device(&mut self, name: &str, device: T) -> Result { + self.add_device(device, DeviceSettings { + name: Some(name.to_owned()), + queue: true, + ..Default::default() + }) } fn process_one_event(&mut self) -> Result<(), Error> { let mut event_device = self.event_queue.pop().unwrap(); self.clock = event_device.next_clock; - let result = match event_device.device.borrow_mut().as_steppable().unwrap().step(self) { + let result = match self.get_dyn_device(event_device.device).unwrap().borrow_mut().as_steppable().unwrap().step(self) { Ok(diff) => { event_device.next_clock = self.clock.checked_add(diff).unwrap(); Ok(()) @@ -107,11 +190,11 @@ impl System { } /// Step through the simulation until the next event is for the given device - pub fn step_until_device(&mut self, device: Device) -> Result<(), Error> { + pub fn step_until_device(&mut self, device: DeviceId) -> Result<(), Error> { loop { self.step()?; - if self.get_next_event_device().id() == device.id() { + if self.get_next_event_device() == device { break; } } @@ -123,7 +206,7 @@ impl System { loop { self.step()?; - if self.get_next_event_device().borrow_mut().as_debuggable().is_some() { + if self.get_dyn_device(self.get_next_event_device()).unwrap().borrow_mut().as_debuggable().is_some() { break; } } @@ -161,31 +244,19 @@ impl System { } } - pub fn get_next_event_device(&self) -> Device { - self.event_queue[self.event_queue.len() - 1].device.clone() + pub fn get_next_event_device(&self) -> DeviceId { + self.event_queue[self.event_queue.len() - 1].device } - pub fn get_next_debuggable_device(&self) -> Option { + pub fn get_next_debuggable_device(&self) -> Option { for event in self.event_queue.iter().rev() { - if event.device.borrow_mut().as_debuggable().is_some() { - return Some(event.device.clone()); + if self.get_dyn_device(event.device).unwrap().borrow_mut().as_debuggable().is_some() { + return Some(event.device); } } None } - fn try_add_debuggable(&mut self, device: Device) { - if device.borrow_mut().as_debuggable().is_some() { - self.debuggables.push(device); - } - } - - fn try_queue_device(&mut self, device: Device) { - if device.borrow_mut().as_steppable().is_some() { - self.queue_device(NextStep::new(device)); - } - } - fn queue_device(&mut self, device_step: NextStep) { for (i, event) in self.event_queue.iter().enumerate().rev() { if event.next_clock > device_step.next_clock { @@ -200,11 +271,11 @@ impl System { pub struct NextStep { pub next_clock: Instant, - pub device: Device, + pub device: DeviceId, } impl NextStep { - pub fn new(device: Device) -> Self { + pub fn new(device: DeviceId) -> Self { Self { next_clock: Instant::START, device, diff --git a/emulator/libraries/debugger/src/lib.rs b/emulator/libraries/debugger/src/lib.rs index 9b7fd31..0666289 100644 --- a/emulator/libraries/debugger/src/lib.rs +++ b/emulator/libraries/debugger/src/lib.rs @@ -27,7 +27,7 @@ impl Debugger { pub fn print_step(&mut self, system: &mut System) -> Result<(), Error> { println!("@ {} ns", system.clock.as_duration().as_nanos()); if let Some(device) = system.get_next_debuggable_device() { - device.borrow_mut().as_debuggable().unwrap().print_current_step(system)?; + system.get_dyn_device(device).unwrap().borrow_mut().as_debuggable().unwrap().print_current_step(system)?; } Ok(()) } @@ -65,13 +65,13 @@ impl Debugger { let (name, addr) = parse_address(args[1])?; match name { Some(name) => { - let target = system.get_device(name)?; + let target = system.get_dyn_device_by_name(name)?; target.borrow_mut().as_debuggable().unwrap().add_breakpoint(addr); println!("Breakpoint set for devices {:?} at {:08x}", name, addr); }, None => { if let Some(device) = system.get_next_debuggable_device() { - device.borrow_mut().as_debuggable().unwrap().add_breakpoint(addr); + system.get_dyn_device(device).unwrap().borrow_mut().as_debuggable().unwrap().add_breakpoint(addr); println!("Breakpoint set for {:08x}", addr); } }, @@ -85,13 +85,13 @@ impl Debugger { let (name, addr) = parse_address(args[1])?; match name { Some(name) => { - let target = system.get_device(name)?; + let target = system.get_dyn_device_by_name(name)?; target.borrow_mut().as_debuggable().unwrap().remove_breakpoint(addr); println!("Breakpoint removed for devices {:?} at {:08x}", name, addr); }, None => { if let Some(device) = system.get_next_debuggable_device() { - device.borrow_mut().as_debuggable().unwrap().remove_breakpoint(addr); + system.get_dyn_device(device).unwrap().borrow_mut().as_debuggable().unwrap().remove_breakpoint(addr); println!("Breakpoint removed for {:08x}", addr); } }, @@ -132,13 +132,13 @@ impl Debugger { if args.len() < 2 { println!("Usage: inspect []"); } else { - let device = system.get_device(args[1])?; - let subargs = if args.len() > 2 { &args[2..] } else { &[""] }; - device - .borrow_mut() - .as_inspectable() - .ok_or_else(|| Error::new("That device is not inspectable"))? - .inspect(system, subargs)?; + // let device = system.get_dyn_device(args[1])?; + // let subargs = if args.len() > 2 { &args[2..] } else { &[""] }; + // device + // .borrow_mut() + // .as_inspectable() + // .ok_or_else(|| Error::new("That device is not inspectable"))? + // .inspect(system, subargs)?; } }, "dis" | "disassemble" => { @@ -155,7 +155,7 @@ impl Debugger { }; if let Some(device) = system.get_next_debuggable_device() { - device + system.get_dyn_device(device).unwrap() .borrow_mut() .as_debuggable() .unwrap() @@ -202,7 +202,7 @@ impl Debugger { //}, _ => { if let Some(device) = system.get_next_debuggable_device() { - if device.borrow_mut().as_debuggable().unwrap().run_command(system, &args)? { + if system.get_dyn_device(device).unwrap().borrow_mut().as_debuggable().unwrap().run_command(system, &args)? { println!("Error: unknown command {}", args[0]); } }