Rewrite system device storage

This commit is contained in:
Jomer.Dev 2024-06-16 01:17:39 +02:00
parent 6e7e315808
commit 64571e45b8
4 changed files with 204 additions and 102 deletions

View File

@ -1,6 +1,8 @@
use std::any::{Any, TypeId};
use std::ops::Deref;
use std::rc::Rc; use std::rc::Rc;
use std::cell::{RefCell, RefMut, BorrowMutError}; use std::cell::RefCell;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicU32, Ordering};
use femtos::{Duration, Instant}; use femtos::{Duration, Instant};
use crate::{Error, System}; 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<RefCell<dyn Resource>>;
impl<T> Resource for T where T: Transmutable + 'static {}
pub trait Transmutable { pub trait Transmutable {
#[inline] #[inline]
fn as_steppable(&mut self) -> Option<&mut dyn Steppable> { fn as_steppable(&mut self) -> Option<&mut dyn Steppable> {
@ -199,54 +208,76 @@ pub trait Transmutable {
} }
} }
// Taken from deno_core
fn is<T: Resource>(field: &dyn Resource) -> bool {
field.type_id() == TypeId::of::<T>()
}
// Taken from deno_core
pub fn downcast_rc_refc<'a, T: Resource>(field: &'a Device) -> Option<&'a Rc<RefCell<T>>> {
if is::<T>(field.borrow().deref()) {
let ptr = field as *const Rc<RefCell<_>> as *const Rc<RefCell<T>>;
#[allow(clippy::undocumented_unsafe_blocks)]
Some(unsafe { &*ptr })
} else {
None
}
}
pub type TransmutableBox = Rc<RefCell<Box<dyn Transmutable>>>; pub type TransmutableBox = Rc<RefCell<Box<dyn Transmutable>>>;
pub fn wrap_transmutable<T: Transmutable + 'static>(value: T) -> TransmutableBox { pub fn wrap_transmutable<T: Transmutable + 'static>(value: T) -> TransmutableBox {
Rc::new(RefCell::new(Box::new(value))) 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 fn get_next_id() -> u32 {
pub struct DeviceId(usize);
impl DeviceId {
pub fn new() -> Self {
let next = NEXT_ID.load(Ordering::Acquire); let next = NEXT_ID.load(Ordering::Acquire);
NEXT_ID.store(next + 1, Ordering::Release); NEXT_ID.store(next + 1, Ordering::Release);
Self(next) next
}
} }
impl Default for DeviceId { // #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
fn default() -> Self { // pub struct DeviceId(usize);
Self::new()
}
}
#[derive(Clone)] // impl DeviceId {
pub struct Device(DeviceId, TransmutableBox); // pub fn new() -> Self {
// let next = NEXT_ID.load(Ordering::Acquire);
// NEXT_ID.store(next + 1, Ordering::Release);
// Self(next)
// }
// }
impl Device { // impl Default for DeviceId {
pub fn new<T>(value: T) -> Self // fn default() -> Self {
where // Self::new()
T: Transmutable + 'static, // }
{ // }
Self(DeviceId::new(), wrap_transmutable(value))
}
pub fn id(&self) -> DeviceId { // #[derive(Clone)]
self.0 // pub struct Device(DeviceId, TransmutableBox);
}
pub fn borrow_mut(&self) -> RefMut<'_, Box<dyn Transmutable>> { // impl Device {
self.1.borrow_mut() // pub fn new<T>(value: T) -> Self
} // where
// T: Transmutable + 'static,
// {
// Self(DeviceId::new(), wrap_transmutable(value))
// }
pub fn try_borrow_mut(&self) -> Result<RefMut<'_, Box<dyn Transmutable>>, BorrowMutError> { // pub fn id(&self) -> DeviceId {
self.1.try_borrow_mut() // self.0
} // }
}
// pub fn borrow_mut(&self) -> RefMut<'_, Box<dyn Transmutable>> {
// self.1.borrow_mut()
// }
// pub fn try_borrow_mut(&self) -> Result<RefMut<'_, Box<dyn Transmutable>>, BorrowMutError> {
// self.1.try_borrow_mut()
// }
// }
/* /*

View File

@ -7,7 +7,7 @@ mod memory;
mod system; mod system;
pub use crate::devices::{ 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::{ pub use crate::devices::{
read_beu16, read_beu32, read_leu16, read_leu32, write_beu16, write_beu32, write_leu16, write_leu32, wrap_transmutable, 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::error::Error;
pub use crate::interrupts::InterruptController; pub use crate::interrupts::InterruptController;
pub use crate::memory::{MemoryBlock, AddressTranslator, AddressRepeater, Bus, BusPort, dump_slice, dump_memory}; 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;

View File

@ -1,29 +1,33 @@
use std::rc::Rc; use std::rc::Rc;
use std::cell::{RefCell, RefMut}; use std::cell::{RefCell, RefMut};
use std::collections::HashMap; use std::collections::{BTreeMap, HashMap};
use femtos::{Instant, Duration}; 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 struct System {
pub clock: Instant, pub clock: Instant,
pub devices: HashMap<String, Device>, pub devices: BTreeMap<DeviceId, Device>,
pub event_queue: Vec<NextStep>, pub event_queue: Vec<NextStep>,
pub id_to_name: HashMap<DeviceId, String>,
pub debuggables: Vec<Device>, pub debuggables: Vec<DeviceId>,
pub bus: Rc<RefCell<Bus>>, pub bus: Rc<RefCell<Bus>>,
pub buses: HashMap<String, Rc<RefCell<Bus>>>, pub buses: HashMap<String, Rc<RefCell<Bus>>>,
pub interrupt_controller: RefCell<InterruptController>, pub interrupt_controller: RefCell<InterruptController>,
} }
impl Default for System { impl Default for System {
fn default() -> Self { fn default() -> Self {
Self { Self {
clock: Instant::START, clock: Instant::START,
devices: HashMap::new(), devices: BTreeMap::new(),
event_queue: vec![], event_queue: vec![],
id_to_name: HashMap::new(),
debuggables: Vec::new(), debuggables: Vec::new(),
@ -34,6 +38,24 @@ impl Default for System {
} }
} }
pub struct DeviceSettings {
pub name: Option<String>,
pub address: Option<Address>,
pub debuggable: bool,
pub queue: bool,
}
impl Default for DeviceSettings {
fn default() -> Self {
Self {
name: None,
address: None,
debuggable: false,
queue: false,
}
}
}
impl System { impl System {
pub fn get_bus(&self) -> RefMut<'_, Bus> { pub fn get_bus(&self) -> RefMut<'_, Bus> {
self.bus.borrow_mut() self.bus.borrow_mut()
@ -43,43 +65,104 @@ impl System {
self.interrupt_controller.borrow_mut() self.interrupt_controller.borrow_mut()
} }
pub fn get_device(&self, name: &str) -> Result<Device, Error> { pub fn get_device<T: Resource>(&self, device: DeviceId) -> Result<Rc<RefCell<T>>, Error> {
self.devices self.devices
.get(name) .get(&device)
.and_then(|rc| downcast_rc_refc::<T>(rc))
.cloned() .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> { pub fn get_device_by_name<T: Resource>(&self, name: &str) -> Result<Rc<RefCell<T>>, Error> {
self.try_add_debuggable(device.clone()); let id = self.id_to_name.iter().find_map(|(key, &ref val)| if val == name { Some(key)} else { None });
self.try_queue_device(device.clone()); if let Some(id) = id {
self.devices.insert(name.to_string(), device); self.get_device(*id)
Ok(()) } else {
Err(Error::new(format!("system: could not find device {}", name)))
}
} }
pub fn add_addressable_device(&mut self, addr: Address, device: Device) -> Result<(), Error> { pub fn get_dyn_device(&self, device: DeviceId) -> Result<Device, Error> {
self.add_peripheral(&format!("mem{:x}", addr), addr, device) 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> { pub fn get_dyn_device_by_name(&self, name: &str) -> Result<Device, 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_dyn_device(*id)
} else {
Err(Error::new(format!("system: could not find device {}", name)))
}
}
pub fn add_device<T: Resource>(&mut self, device: T, settings: DeviceSettings) -> Result<DeviceId, Error> {
self.add_device_rc_ref(Rc::new(RefCell::new(device)), settings)
}
pub fn add_device_rc_ref<T: Resource>(&mut self, device: Rc<RefCell<T>>, settings: DeviceSettings) -> Result<DeviceId, Error> {
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<DeviceId, Error> {
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()); self.bus.borrow_mut().insert(addr, device.clone());
self.try_add_debuggable(device.clone()); }
self.try_queue_device(device.clone()); Ok(id)
self.devices.insert(name.to_string(), device);
Ok(())
} }
pub fn add_interruptable_device(&mut self, name: &str, device: Device) -> Result<(), Error> { pub fn add_named_device<T: Resource>(&mut self, name: &str, device: T) -> Result<DeviceId, Error> {
self.try_add_debuggable(device.clone()); self.add_device(device, DeviceSettings {
self.try_queue_device(device.clone()); name: Some(name.to_owned()),
self.devices.insert(name.to_string(), device); queue: true,
Ok(()) ..Default::default()
})
}
pub fn add_addressable_device<T: Resource>(&mut self, addr: Address, device: T) -> Result<DeviceId, Error> {
self.add_device(device, DeviceSettings {
name: Some(format!("mem{:x}", addr)),
address: Some(addr),
queue: true,
..Default::default()
})
}
pub fn add_peripheral<T: Resource>(&mut self, name: &str, addr: Address, device: T) -> Result<DeviceId, Error> {
self.add_device(device, DeviceSettings {
name: Some(name.to_owned()),
address: Some(addr),
queue: true,
..Default::default()
})
}
pub fn add_interruptable_device<T: Resource>(&mut self, name: &str, device: T) -> Result<DeviceId, Error> {
self.add_device(device, DeviceSettings {
name: Some(name.to_owned()),
queue: true,
..Default::default()
})
} }
fn process_one_event(&mut self) -> Result<(), Error> { fn process_one_event(&mut self) -> Result<(), Error> {
let mut event_device = self.event_queue.pop().unwrap(); let mut event_device = self.event_queue.pop().unwrap();
self.clock = event_device.next_clock; 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) => { Ok(diff) => {
event_device.next_clock = self.clock.checked_add(diff).unwrap(); event_device.next_clock = self.clock.checked_add(diff).unwrap();
Ok(()) Ok(())
@ -107,11 +190,11 @@ impl System {
} }
/// Step through the simulation until the next event is for the given device /// 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 { loop {
self.step()?; self.step()?;
if self.get_next_event_device().id() == device.id() { if self.get_next_event_device() == device {
break; break;
} }
} }
@ -123,7 +206,7 @@ impl System {
loop { loop {
self.step()?; 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; break;
} }
} }
@ -161,31 +244,19 @@ impl System {
} }
} }
pub fn get_next_event_device(&self) -> Device { pub fn get_next_event_device(&self) -> DeviceId {
self.event_queue[self.event_queue.len() - 1].device.clone() self.event_queue[self.event_queue.len() - 1].device
} }
pub fn get_next_debuggable_device(&self) -> Option<Device> { pub fn get_next_debuggable_device(&self) -> Option<DeviceId> {
for event in self.event_queue.iter().rev() { for event in self.event_queue.iter().rev() {
if event.device.borrow_mut().as_debuggable().is_some() { if self.get_dyn_device(event.device).unwrap().borrow_mut().as_debuggable().is_some() {
return Some(event.device.clone()); return Some(event.device);
} }
} }
None 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) { fn queue_device(&mut self, device_step: NextStep) {
for (i, event) in self.event_queue.iter().enumerate().rev() { for (i, event) in self.event_queue.iter().enumerate().rev() {
if event.next_clock > device_step.next_clock { if event.next_clock > device_step.next_clock {
@ -200,11 +271,11 @@ impl System {
pub struct NextStep { pub struct NextStep {
pub next_clock: Instant, pub next_clock: Instant,
pub device: Device, pub device: DeviceId,
} }
impl NextStep { impl NextStep {
pub fn new(device: Device) -> Self { pub fn new(device: DeviceId) -> Self {
Self { Self {
next_clock: Instant::START, next_clock: Instant::START,
device, device,

View File

@ -27,7 +27,7 @@ impl Debugger {
pub fn print_step(&mut self, system: &mut System) -> Result<(), Error> { pub fn print_step(&mut self, system: &mut System) -> Result<(), Error> {
println!("@ {} ns", system.clock.as_duration().as_nanos()); println!("@ {} ns", system.clock.as_duration().as_nanos());
if let Some(device) = system.get_next_debuggable_device() { 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(()) Ok(())
} }
@ -65,13 +65,13 @@ impl Debugger {
let (name, addr) = parse_address(args[1])?; let (name, addr) = parse_address(args[1])?;
match name { match name {
Some(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); target.borrow_mut().as_debuggable().unwrap().add_breakpoint(addr);
println!("Breakpoint set for devices {:?} at {:08x}", name, addr); println!("Breakpoint set for devices {:?} at {:08x}", name, addr);
}, },
None => { None => {
if let Some(device) = system.get_next_debuggable_device() { 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); println!("Breakpoint set for {:08x}", addr);
} }
}, },
@ -85,13 +85,13 @@ impl Debugger {
let (name, addr) = parse_address(args[1])?; let (name, addr) = parse_address(args[1])?;
match name { match name {
Some(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); target.borrow_mut().as_debuggable().unwrap().remove_breakpoint(addr);
println!("Breakpoint removed for devices {:?} at {:08x}", name, addr); println!("Breakpoint removed for devices {:?} at {:08x}", name, addr);
}, },
None => { None => {
if let Some(device) = system.get_next_debuggable_device() { 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); println!("Breakpoint removed for {:08x}", addr);
} }
}, },
@ -132,13 +132,13 @@ impl Debugger {
if args.len() < 2 { if args.len() < 2 {
println!("Usage: inspect <device_name> [<device specific arguments>]"); println!("Usage: inspect <device_name> [<device specific arguments>]");
} else { } else {
let device = system.get_device(args[1])?; // let device = system.get_dyn_device(args[1])?;
let subargs = if args.len() > 2 { &args[2..] } else { &[""] }; // let subargs = if args.len() > 2 { &args[2..] } else { &[""] };
device // device
.borrow_mut() // .borrow_mut()
.as_inspectable() // .as_inspectable()
.ok_or_else(|| Error::new("That device is not inspectable"))? // .ok_or_else(|| Error::new("That device is not inspectable"))?
.inspect(system, subargs)?; // .inspect(system, subargs)?;
} }
}, },
"dis" | "disassemble" => { "dis" | "disassemble" => {
@ -155,7 +155,7 @@ impl Debugger {
}; };
if let Some(device) = system.get_next_debuggable_device() { if let Some(device) = system.get_next_debuggable_device() {
device system.get_dyn_device(device).unwrap()
.borrow_mut() .borrow_mut()
.as_debuggable() .as_debuggable()
.unwrap() .unwrap()
@ -202,7 +202,7 @@ impl Debugger {
//}, //},
_ => { _ => {
if let Some(device) = system.get_next_debuggable_device() { 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]); println!("Error: unknown command {}", args[0]);
} }
} }