2021-10-09 06:11:52 +00:00
|
|
|
|
|
|
|
use std::rc::Rc;
|
2021-10-18 19:05:10 +00:00
|
|
|
use std::cell::RefCell;
|
2021-10-09 06:11:52 +00:00
|
|
|
|
|
|
|
use crate::error::Error;
|
|
|
|
use crate::system::System;
|
|
|
|
|
|
|
|
|
2021-10-17 03:30:50 +00:00
|
|
|
pub const MAX_READ: usize = 4;
|
|
|
|
|
2021-10-24 05:22:02 +00:00
|
|
|
/// The time in nanoseconds that have elapsed since the start of the simulation
|
2021-10-09 06:11:52 +00:00
|
|
|
pub type Clock = u64;
|
2021-10-24 05:22:02 +00:00
|
|
|
|
|
|
|
/// The time in nanoseconds until the `step()` method should be called again
|
|
|
|
pub type ClockElapsed = u64;
|
|
|
|
|
|
|
|
/// A universal memory address used by the Addressable trait
|
2021-10-17 03:30:50 +00:00
|
|
|
pub type Address = u64;
|
2021-10-09 06:11:52 +00:00
|
|
|
|
2021-10-17 17:39:43 +00:00
|
|
|
|
2021-10-11 22:04:39 +00:00
|
|
|
/// A device that can change state over time. The `step()` method will be called
|
|
|
|
/// by the containing `System` when the system clock advances. If an error occurs
|
|
|
|
/// with any device, the `on_error()` method will be called to display any state
|
|
|
|
/// information that might be helpful for debugging.
|
2021-10-09 06:11:52 +00:00
|
|
|
pub trait Steppable {
|
2021-10-24 05:22:02 +00:00
|
|
|
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error>;
|
2021-10-09 06:11:52 +00:00
|
|
|
fn on_error(&mut self, _system: &System) { }
|
2021-10-15 04:16:31 +00:00
|
|
|
fn on_debug(&mut self) { }
|
2021-10-09 06:11:52 +00:00
|
|
|
}
|
|
|
|
|
2021-10-17 17:39:43 +00:00
|
|
|
|
2021-10-11 22:04:39 +00:00
|
|
|
/// A device that can receive an interrupt. The `interrupt_state_change()` method
|
|
|
|
/// will be called whenever an interrupt signal changes goes high or low.
|
2021-10-09 06:11:52 +00:00
|
|
|
pub trait Interruptable {
|
2021-10-09 18:00:32 +00:00
|
|
|
fn interrupt_state_change(&mut self, state: bool, priority: u8, number: u8) -> Result<(), Error>;
|
2021-10-09 06:11:52 +00:00
|
|
|
}
|
|
|
|
|
2021-10-17 17:39:43 +00:00
|
|
|
|
2021-10-17 03:30:50 +00:00
|
|
|
/// A device that can be addressed to read data from or write data to the device.
|
|
|
|
pub trait Addressable {
|
|
|
|
fn len(&self) -> usize;
|
2021-10-27 00:33:23 +00:00
|
|
|
fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error>;
|
2021-10-17 03:30:50 +00:00
|
|
|
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error>;
|
|
|
|
|
|
|
|
fn read_u8(&mut self, addr: Address) -> Result<u8, Error> {
|
2021-10-27 00:33:23 +00:00
|
|
|
let mut data = [0; 1];
|
|
|
|
self.read(addr, &mut data)?;
|
|
|
|
Ok(data[0])
|
2021-10-17 03:30:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn read_beu16(&mut self, addr: Address) -> Result<u16, Error> {
|
2021-10-27 00:33:23 +00:00
|
|
|
let mut data = [0; 2];
|
|
|
|
self.read(addr, &mut data)?;
|
|
|
|
Ok(read_beu16(&data))
|
2021-10-17 03:30:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn read_beu32(&mut self, addr: Address) -> Result<u32, Error> {
|
2021-10-27 00:33:23 +00:00
|
|
|
let mut data = [0; 4];
|
|
|
|
self.read(addr, &mut data)?;
|
|
|
|
Ok(read_beu32(&data))
|
2021-10-17 03:30:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn write_u8(&mut self, addr: Address, value: u8) -> Result<(), Error> {
|
|
|
|
let data = [value];
|
|
|
|
self.write(addr, &data)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write_beu16(&mut self, addr: Address, value: u16) -> Result<(), Error> {
|
|
|
|
let data = write_beu16(value);
|
|
|
|
self.write(addr, &data)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn write_beu32(&mut self, addr: Address, value: u32) -> Result<(), Error> {
|
|
|
|
let data = write_beu32(value);
|
|
|
|
self.write(addr, &data)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn read_beu16(data: &[u8]) -> u16 {
|
|
|
|
(data[0] as u16) << 8 |
|
|
|
|
(data[1] as u16)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn read_beu32(data: &[u8]) -> u32 {
|
|
|
|
(data[0] as u32) << 24 |
|
|
|
|
(data[1] as u32) << 16 |
|
|
|
|
(data[2] as u32) << 8 |
|
|
|
|
(data[3] as u32)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn write_beu16(value: u16) -> [u8; 2] {
|
|
|
|
[
|
|
|
|
(value >> 8) as u8,
|
|
|
|
value as u8,
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn write_beu32(value: u32) -> [u8; 4] {
|
|
|
|
[
|
|
|
|
(value >> 24) as u8,
|
|
|
|
(value >> 16) as u8,
|
|
|
|
(value >> 8) as u8,
|
|
|
|
value as u8,
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
2021-10-26 19:17:59 +00:00
|
|
|
/// A device that can debugged by putting it into debug mode, or setting breakpoints
|
|
|
|
pub trait Debuggable {
|
|
|
|
fn enable_debugging(&mut self);
|
|
|
|
fn add_breakpoint(&mut self, addr: Address);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-10-17 17:39:43 +00:00
|
|
|
pub trait Transmutable {
|
|
|
|
fn as_steppable(&mut self) -> Option<&mut dyn Steppable> {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
fn as_addressable(&mut self) -> Option<&mut dyn Addressable> {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
fn as_interruptable(&mut self) -> Option<&mut dyn Interruptable> {
|
|
|
|
None
|
|
|
|
}
|
2021-10-26 19:17:59 +00:00
|
|
|
|
|
|
|
fn as_debuggable(&mut self) -> Option<&mut dyn Debuggable> {
|
|
|
|
None
|
|
|
|
}
|
2021-10-17 17:39:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)))
|
|
|
|
}
|
|
|
|
|