mirror of
https://github.com/transistorfet/moa.git
synced 2024-11-26 22:50:25 +00:00
Added AddressTranslator
This commit is contained in:
parent
f9d613b3b9
commit
2d3463867d
@ -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<u8>,
|
||||
@ -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<dyn Fn(Address) -> Address>,
|
||||
}
|
||||
|
||||
impl AddressTranslator {
|
||||
pub fn new<F>(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<Block>,
|
||||
@ -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(())
|
||||
|
7
todo.txt
7
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
|
||||
|
Loading…
Reference in New Issue
Block a user