diff options
| author | Nathan Lee <me@nwlee.tech> | 2026-09-25 22:39:01 -0500 |
|---|---|---|
| committer | Nathan Lee <me@nwlee.tech> | 2026-09-25 22:39:01 -0500 |
| commit | 6858c9e7c97f772eb357e3eee0c1fcfb8adcb699 (patch) | |
| tree | 691b3591fa0fc817b88f3a587fa0d613f9d475c1 /website-emu/src/mem.rs | |
scaffold emulator from wrv32em
Diffstat (limited to 'website-emu/src/mem.rs')
| -rw-r--r-- | website-emu/src/mem.rs | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/website-emu/src/mem.rs b/website-emu/src/mem.rs new file mode 100644 index 0000000..c5f1b5c --- /dev/null +++ b/website-emu/src/mem.rs @@ -0,0 +1,105 @@ +use std::ops::Range; + +pub trait MemoryDevice { + fn read(&self, address: u32) -> Result<u8, ()>; + fn write(&mut self, address: u32, value: u8) -> Result<(), ()>; +} + +pub struct CpuMemory { + pub devices: Vec<(Range<u32>, Box<dyn MemoryDevice>)>, +} + +impl CpuMemory { + fn get_device(&self, address: u32) -> Option<&Box<dyn MemoryDevice>> { + self.devices + .iter() + .find(|(range, _)| range.contains(&address)) + .map(|(_, device)| device) + } + fn get_device_mut(&mut self, address: u32) -> Option<&mut Box<dyn MemoryDevice>> { + self.devices + .iter_mut() + .find(|(range, _)| range.contains(&address)) + .map(|(_, device)| device) + } + + pub fn register_device(&mut self, range: Range<u32>, device: Box<dyn MemoryDevice>) { + self.devices.push((range, device)); + } + + pub fn read(&self, address: u32) -> Result<u8, ()> { + 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<u16, ()> { + 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<u32, ()> { + 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<u32, ()> { + 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<u8, ()> { + 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(()) + } + } +} |
