use std::ops::Range; pub trait MemoryDevice { fn read(&self, address: u32) -> Result; fn write(&mut self, address: u32, value: u8) -> Result<(), ()>; } pub struct CpuMemory { pub devices: Vec<(Range, Box)>, } impl CpuMemory { fn get_device(&self, address: u32) -> Option<&Box> { self.devices .iter() .find(|(range, _)| range.contains(&address)) .map(|(_, device)| device) } fn get_device_mut(&mut self, address: u32) -> Option<&mut Box> { self.devices .iter_mut() .find(|(range, _)| range.contains(&address)) .map(|(_, device)| device) } pub fn register_device(&mut self, range: Range, device: Box) { self.devices.push((range, device)); } pub fn read(&self, address: u32) -> Result { if let Some(device) = self.get_device(address) { device.read(address) } else { Err(()) } } pub fn write(&mut self, address: u32, value: u8) -> Result<(), ()> { if let Some(device) = self.get_device_mut(address) { device.write(address, value) } else { Err(()) } } pub fn read_halfword(&self, address: u32) -> Result { let low = self.read(address)?; let high = self.read(address + 1)?; Ok((high as u16) << 8 | low as u16) } pub fn write_halfword(&mut self, address: u32, value: u16) -> Result<(), ()> { self.write(address + 1, (value >> 8) as u8)?; self.write(address, (value & 0xFF) as u8)?; Ok(()) } pub fn read_word(&self, address: u32) -> Result { let low = self.read_halfword(address)?; let high = self.read_halfword(address + 2)?; Ok((high as u32) << 16 | low as u32) } pub fn write_word(&mut self, address: u32, value: u32) -> Result<(), ()> { self.write_halfword(address + 2, (value >> 16) as u16)?; self.write_halfword(address, (value & 0xFFFF) as u16) } pub fn read_instruction(&self, address: u32) -> Result { if let Some(device) = self.get_device(address) { Ok(u32::from_le_bytes([ device.read(address)?, device.read(address + 1)?, device.read(address + 2)?, device.read(address + 3)?, ])) } else { Err(()) } } } pub struct LogicalMemory { pub base: u32, pub size: u32, pub dram: Box<[u8]>, } impl MemoryDevice for LogicalMemory { fn read(&self, address: u32) -> Result { if address - self.base > self.size { Err(()) } else { Ok(self.dram[(address - self.base) as usize]) } } fn write(&mut self, address: u32, value: u8) -> Result<(), ()> { if address - self.base > self.size { Err(()) } else { self.dram[(address - self.base) as usize] = value; Ok(()) } } }