-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
99 changed files
with
4,977 additions
and
1,585 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
[package] | ||
name = "device_debug" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] | ||
peripheral_bus = { path = "../peripheral-bus" } | ||
log = "0.4.20" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
use std::any::Any; | ||
|
||
use log::debug; | ||
use peripheral_bus::{ | ||
device::BusAssertions, device::Device, memory_mapped_device::MemoryMappedDevice, | ||
}; | ||
|
||
/// | ||
/// A device that just exists to do integration tests on the VM | ||
/// Allows programs to assert interrupts etc. when they need to | ||
/// | ||
pub struct DebugDevice { | ||
pub trigger_bus_error: bool, | ||
pub trigger_interrupt: u8, | ||
} | ||
|
||
#[must_use] | ||
pub fn new_debug_device() -> DebugDevice { | ||
DebugDevice { | ||
trigger_bus_error: false, | ||
trigger_interrupt: 0, | ||
} | ||
} | ||
|
||
impl Device for DebugDevice { | ||
fn poll(&mut self, bus_assertions: BusAssertions, selected: bool) -> BusAssertions { | ||
let io_assertions = self.perform_bus_io(bus_assertions, selected); | ||
// TODO: Bus error should be edge triggered I think so we don't get double faults | ||
// if devices are slow to stop asserting | ||
if self.trigger_bus_error { | ||
debug!("Bus error triggered!"); | ||
|
||
self.trigger_bus_error = false; | ||
return BusAssertions { | ||
bus_error: true, | ||
..io_assertions | ||
}; | ||
} | ||
if self.trigger_interrupt > 0 { | ||
debug!("Interrupt L{} error triggered!", self.trigger_interrupt); | ||
|
||
let interrupt_level = self.trigger_interrupt; | ||
self.trigger_interrupt = 0; | ||
return BusAssertions { | ||
interrupt_assertion: 0x1 << (interrupt_level - 1), | ||
..io_assertions | ||
}; | ||
} | ||
io_assertions | ||
} | ||
fn as_any(&mut self) -> &mut dyn Any { | ||
self | ||
} | ||
} | ||
|
||
impl MemoryMappedDevice for DebugDevice { | ||
fn read_address(&self, address: u32) -> u16 { | ||
debug!("Reading from address 0x{address:X}"); | ||
match address { | ||
0x0 => { | ||
if self.trigger_bus_error { | ||
0x1 | ||
} else { | ||
0x0 | ||
} | ||
} | ||
0x1..=0x5 => { | ||
if (address as u8) == self.trigger_interrupt { | ||
0x1 | ||
} else { | ||
0x0 | ||
} | ||
} | ||
_ => 0x0, | ||
} | ||
} | ||
|
||
fn write_address(&mut self, address: u32, value: u16) { | ||
debug!("Writing 0x{value:X} to address 0x{address:X}"); | ||
|
||
match address { | ||
0x0 => self.trigger_bus_error = value == 0x1, | ||
0x1..=0x5 => { | ||
if value == 0x1 { | ||
self.trigger_interrupt = address as u8 | ||
} | ||
} | ||
_ => {} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
[package] | ||
name = "device_ram" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
memmap = "0.7.0" | ||
peripheral_bus = { path = "../peripheral-bus" } | ||
log = "0.4.20" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
use std::{ | ||
any::Any, | ||
cell::RefCell, | ||
fs::{File, OpenOptions}, | ||
path::PathBuf, | ||
}; | ||
|
||
use memmap::{MmapMut, MmapOptions}; | ||
use peripheral_bus::{ | ||
device::BusAssertions, device::Device, memory_mapped_device::MemoryMappedDevice, | ||
}; | ||
|
||
pub enum SegmentMemCell { | ||
// At the moment, all raw segments get the maximum allowable of memory allocated | ||
// for a single segment (16 bit address). This is wasteful but not a huge issue | ||
// at the moment running on a machine with GBs of memory | ||
RawMemory(Box<[u8; (0xFFFF * 2) + 2]>), | ||
FileMapped(Box<File>, Box<MmapMut>), | ||
} | ||
|
||
pub struct RamDevice { | ||
// TODO: Does this still need to be RefCell? | ||
pub mem_cell: RefCell<SegmentMemCell>, | ||
} | ||
|
||
#[must_use] | ||
pub fn new_ram_device_standard() -> RamDevice { | ||
RamDevice { | ||
mem_cell: RefCell::new(SegmentMemCell::RawMemory(Box::new([0; (0xFFFF * 2) + 2]))), | ||
} | ||
} | ||
|
||
pub fn new_ram_device_file_mapped(file_path: PathBuf) -> RamDevice { | ||
// TODO: Proper error handling? | ||
let file = OpenOptions::new() | ||
.read(true) | ||
.write(true) | ||
.open(file_path) | ||
.unwrap(); | ||
// TODO: Proper error handling here too? | ||
let mmap = unsafe { MmapOptions::new().map_mut(&file).unwrap() }; | ||
|
||
RamDevice { | ||
mem_cell: RefCell::new(SegmentMemCell::FileMapped(Box::new(file), Box::new(mmap))), | ||
} | ||
} | ||
impl Device for RamDevice { | ||
fn poll(&mut self, bus_assertions: BusAssertions, selected: bool) -> BusAssertions { | ||
self.perform_bus_io(bus_assertions, selected) | ||
} | ||
fn as_any(&mut self) -> &mut dyn Any { | ||
self | ||
} | ||
} | ||
|
||
impl MemoryMappedDevice for RamDevice { | ||
fn read_address(&self, address: u32) -> u16 { | ||
let address_pointer = address as usize * 2; | ||
|
||
// Range check? | ||
let cell = self.mem_cell.borrow(); | ||
|
||
let raw_memory: &[u8] = match *cell { | ||
SegmentMemCell::RawMemory(ref mem) => &mem[..], | ||
SegmentMemCell::FileMapped(_, ref mmap) => &mmap[..], | ||
}; | ||
let byte_pair: [u8; 2] = raw_memory[address_pointer..=address_pointer + 1] | ||
.try_into() | ||
.unwrap(); | ||
u16::from_be_bytes(byte_pair) | ||
} | ||
fn write_address(&mut self, address: u32, value: u16) { | ||
let address_pointer = address as usize * 2; | ||
let byte_pair: [u8; 2] = u16::to_be_bytes(value); | ||
|
||
let mut cell = self.mem_cell.borrow_mut(); | ||
|
||
let raw_memory: &mut [u8] = match *cell { | ||
SegmentMemCell::RawMemory(ref mut mem) => &mut mem[..], | ||
SegmentMemCell::FileMapped(_, ref mut mmap) => &mut mmap[..], | ||
}; | ||
raw_memory[address_pointer] = byte_pair[0]; | ||
raw_memory[address_pointer + 1] = byte_pair[1]; | ||
} | ||
|
||
fn read_raw_bytes(&self, limit: u32) -> Vec<u8> { | ||
let cell = self.mem_cell.borrow(); | ||
|
||
let raw_memory: &[u8] = match *cell { | ||
SegmentMemCell::RawMemory(ref mem) => &mem[..], | ||
SegmentMemCell::FileMapped(_, ref mmap) => &mmap[..], | ||
}; | ||
|
||
// TODO: Is this efficient in rust? Does it get optimised? | ||
raw_memory | ||
.iter() | ||
.take(limit as usize * 2) | ||
.copied() | ||
.collect() | ||
} | ||
fn write_raw_bytes(&mut self, binary_data: &[u8]) { | ||
let mut cell = self.mem_cell.borrow_mut(); | ||
let raw_memory: &mut [u8] = match *cell { | ||
SegmentMemCell::RawMemory(ref mut mem) => &mut mem[..], | ||
SegmentMemCell::FileMapped(_, ref mut mmap) => &mut mmap[..], | ||
}; | ||
|
||
raw_memory[0..binary_data.len()].copy_from_slice(binary_data); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
[package] | ||
name = "device_terminal" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
peripheral_bus = { path = "../peripheral-bus" } | ||
log = "0.4.20" |
Oops, something went wrong.