From 2d3463867d26f009c60ec3f10a0e241da0a32ad8 Mon Sep 17 00:00:00 2001 From: transistor Date: Sat, 10 Jun 2023 23:19:10 -0700 Subject: [PATCH] Added AddressTranslator --- emulator/core/src/memory.rs | 86 +++++++++++++++++++++---------------- todo.txt | 7 +-- 2 files changed, 51 insertions(+), 42 deletions(-) diff --git a/emulator/core/src/memory.rs b/emulator/core/src/memory.rs index fef5121..f069c0e 100644 --- a/emulator/core/src/memory.rs +++ b/emulator/core/src/memory.rs @@ -11,6 +11,7 @@ use crate::clock::ClockTime; use crate::devices::{Address, Addressable, Transmutable, Device, read_beu16}; +/// A contiguous block of `Addressable` memory, backed by a `Vec` pub struct MemoryBlock { read_only: bool, contents: Vec, @@ -77,42 +78,7 @@ impl Transmutable for MemoryBlock { } -pub struct AddressRightShifter { - subdevice: Device, - shift: u8, -} - -impl AddressRightShifter { - pub fn new(subdevice: Device, shift: u8) -> Self { - Self { - subdevice, - shift, - } - } -} - -impl Addressable for AddressRightShifter { - fn size(&self) -> usize { - let size = self.subdevice.borrow_mut().as_addressable().unwrap().size(); - size << self.shift - } - - fn read(&mut self, clock: ClockTime, addr: Address, data: &mut [u8]) -> Result<(), Error> { - self.subdevice.borrow_mut().as_addressable().unwrap().read(clock, addr >> self.shift, data) - } - - fn write(&mut self, clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> { - self.subdevice.borrow_mut().as_addressable().unwrap().write(clock, addr >> self.shift, data) - } -} - -impl Transmutable for AddressRightShifter { - fn as_addressable(&mut self) -> Option<&mut dyn Addressable> { - Some(self) - } -} - - +/// An address adapter that repeats the address space of the subdevice over the given range pub struct AddressRepeater { subdevice: Device, range: Address, @@ -150,6 +116,47 @@ impl Transmutable for AddressRepeater { } +/// An address adapter that uses a closure to translate the address before accessing the subdevice +pub struct AddressTranslator { + subdevice: Device, + size: usize, + func: Box Address>, +} + +impl AddressTranslator { + pub fn new(subdevice: Device, size: usize, func: F) -> Self + where + F: Fn(Address) -> Address + 'static + { + Self { + subdevice, + size, + func: Box::new(func), + } + } +} + +impl Addressable for AddressTranslator { + fn size(&self) -> usize { + self.size + } + + fn read(&mut self, clock: ClockTime, addr: Address, data: &mut [u8]) -> Result<(), Error> { + self.subdevice.borrow_mut().as_addressable().unwrap().read(clock, (self.func)(addr), data) + } + + fn write(&mut self, clock: ClockTime, addr: Address, data: &[u8]) -> Result<(), Error> { + self.subdevice.borrow_mut().as_addressable().unwrap().write(clock, (self.func)(addr), data) + } +} + +impl Transmutable for AddressTranslator { + fn as_addressable(&mut self) -> Option<&mut dyn Addressable> { + Some(self) + } +} + + #[derive(Clone)] pub struct Block { pub base: Address, @@ -157,6 +164,9 @@ pub struct Block { pub dev: Device, } +/// A bus-like collection of `Addressable` `Device`s mapped to different address ranges +/// +/// This is the fundamental means of connecting devices together to a CPU implementation. #[derive(Clone, Default)] pub struct Bus { blocks: Vec, @@ -270,6 +280,8 @@ impl Addressable for Bus { } } +/// An adapter for limiting the access requests of a device (eg. CPU) on a `Bus` to the address +/// and data widths of the device #[derive(Clone)] pub struct BusPort { offset: Address, @@ -324,7 +336,7 @@ impl Addressable for BusPort { let mut subdevice = self.subdevice.borrow_mut(); for i in (0..data.len()).step_by(self.data_width as usize) { let addr_index = (addr + i as Address) & self.address_mask; - let end = std::cmp::min(i + self.data_width as usize, data.len()); + let end = cmp::min(i + self.data_width as usize, data.len()); subdevice.write(clock, addr_index, &data[i..end])?; } Ok(()) diff --git a/todo.txt b/todo.txt index 3cff115..d13ac5a 100644 --- a/todo.txt +++ b/todo.txt @@ -8,13 +8,10 @@ * can you somehow make devices have two step functions for running things at different times? (I'm thinking ym2612 audio gen vs timers) * the genesis coprocessor stuff will be a good reference point for things that make multiple devices, and how to add them correctly to the system -* address repeater on ym2612 doesn't seem to work the same, when it's on the 68000 device. The Z80 device doesn't have an affect, but maybe it's not being used -* I like making address adapters like this (below) -* you could have busport take a closure or something which translates the address, and returns an error that will be passed up if it occurs - in order to implement the correct behaviour for address exceptions in 68k, transparently - * make Signal directional, by making SignalDriver and SignalInput or SignalReceiver +* address repeater on ym2612 doesn't seem to work the same, when it's on the 68000 device. The Z80 device doesn't have an affect, but maybe it's not being used + * fix the m68k timings * add rust runtime checks for math to look for overflow errors