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::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<RefCell<dyn Resource>>;
impl<T> 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<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 fn wrap_transmutable<T: Transmutable + 'static>(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<T>(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<dyn Transmutable>> {
self.1.borrow_mut()
}
// impl Device {
// 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> {
self.1.try_borrow_mut()
}
}
// pub fn id(&self) -> DeviceId {
// 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;
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;

View File

@ -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<String, Device>,
pub devices: BTreeMap<DeviceId, Device>,
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 buses: HashMap<String, Rc<RefCell<Bus>>>,
pub interrupt_controller: RefCell<InterruptController>,
}
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<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 {
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<Device, Error> {
pub fn get_device<T: Resource>(&self, device: DeviceId) -> Result<Rc<RefCell<T>>, Error> {
self.devices
.get(name)
.get(&device)
.and_then(|rc| downcast_rc_refc::<T>(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<T: Resource>(&self, name: &str) -> Result<Rc<RefCell<T>>, 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<Device, Error> {
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<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_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<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());
}
Ok(id)
}
pub fn add_named_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()
})
}
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> {
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<Device> {
pub fn get_next_debuggable_device(&self) -> Option<DeviceId> {
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,

View File

@ -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 <device_name> [<device specific arguments>]");
} 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]);
}
}