avremu/src/devices/mod.rs

83 lines
2.0 KiB
Rust

// All devices are implemented here.
use slog::Logger;
pub mod oscillator;
pub mod ram;
pub mod usart;
pub trait DeviceImpl {
/// addr relative to the start of the device memory map.
fn read(&mut self, addr: u32) -> u8;
/// addr relative to the start of the device memory map.
fn write(&mut self, addr: u32, value: u8);
}
pub struct Device {
start_addr: u32,
addr_len: u32,
device: Box<dyn DeviceImpl>,
}
impl Device {
pub fn new(device: Box<dyn DeviceImpl>, start_addr: u32, addr_len: u32) -> Self {
Self {
start_addr: start_addr,
addr_len: addr_len,
device: device,
}
}
pub fn handles_addr(&self, addr: u32) -> bool {
addr >= self.start_addr && addr - self.start_addr < self.addr_len
}
pub fn read(&mut self, addr: u32) -> u8 {
self.device.read(addr - self.start_addr)
}
pub fn write(&mut self, addr: u32, val: u8) {
self.device.write(addr - self.start_addr, val)
}
}
pub struct DeviceTree {
log: Logger,
devices: Vec<Device>,
}
impl DeviceTree {
pub fn new(log: Logger) -> Self {
Self {
log: log,
devices: Vec::new(),
}
}
pub fn add_device(&mut self, device: Device) {
self.devices.push(device);
}
fn get_device_for_addr(&mut self, addr: u32) -> Option<&mut Device> {
self.devices.iter_mut().find(|d| d.handles_addr(addr))
}
pub fn read(&mut self, addr: u32) -> u8 {
if let Some(ref mut d) = self.get_device_for_addr(addr) {
return d.read(addr);
}
warn!(self.log, "Trying to read unmapped I/O: {:08X}", addr);
0
}
pub fn write(&mut self, addr: u32, val: u8) {
if let Some(ref mut d) = self.get_device_for_addr(addr) {
return d.write(addr, val);
}
warn!(
self.log,
"Trying to write unmapped I/O: {:08X} <- {:02X}", addr, val
);
}
}