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};
|
use crate::devices::{Address, Addressable, Transmutable, Device, read_beu16};
|
||||||
|
|
||||||
|
|
||||||
|
/// A contiguous block of `Addressable` memory, backed by a `Vec`
|
||||||
pub struct MemoryBlock {
|
pub struct MemoryBlock {
|
||||||
read_only: bool,
|
read_only: bool,
|
||||||
contents: Vec<u8>,
|
contents: Vec<u8>,
|
||||||
@ -77,42 +78,7 @@ impl Transmutable for MemoryBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub struct AddressRightShifter {
|
/// An address adapter that repeats the address space of the subdevice over the given range
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub struct AddressRepeater {
|
pub struct AddressRepeater {
|
||||||
subdevice: Device,
|
subdevice: Device,
|
||||||
range: Address,
|
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)]
|
#[derive(Clone)]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
pub base: Address,
|
pub base: Address,
|
||||||
@ -157,6 +164,9 @@ pub struct Block {
|
|||||||
pub dev: Device,
|
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)]
|
#[derive(Clone, Default)]
|
||||||
pub struct Bus {
|
pub struct Bus {
|
||||||
blocks: Vec<Block>,
|
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)]
|
#[derive(Clone)]
|
||||||
pub struct BusPort {
|
pub struct BusPort {
|
||||||
offset: Address,
|
offset: Address,
|
||||||
@ -324,7 +336,7 @@ impl Addressable for BusPort {
|
|||||||
let mut subdevice = self.subdevice.borrow_mut();
|
let mut subdevice = self.subdevice.borrow_mut();
|
||||||
for i in (0..data.len()).step_by(self.data_width as usize) {
|
for i in (0..data.len()).step_by(self.data_width as usize) {
|
||||||
let addr_index = (addr + i as Address) & self.address_mask;
|
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])?;
|
subdevice.write(clock, addr_index, &data[i..end])?;
|
||||||
}
|
}
|
||||||
Ok(())
|
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)
|
* 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
|
* 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
|
* 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
|
* fix the m68k timings
|
||||||
* add rust runtime checks for math to look for overflow errors
|
* add rust runtime checks for math to look for overflow errors
|
||||||
|
Loading…
Reference in New Issue
Block a user