summaryrefslogtreecommitdiff
path: root/website-emu/src/mem.rs
diff options
context:
space:
mode:
Diffstat (limited to 'website-emu/src/mem.rs')
-rw-r--r--website-emu/src/mem.rs105
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(())
+ }
+ }
+}