moa/emulator/core/src/memory.rs
transistor 7c279613cc Moved AddressRepeater to core, and renamed AddressAdapter
AddressRepeater now takes the range it should repeat over, which only
really affects its reported size.

AddressAdapter is now AddressRightShifter, which is literally the operation
it performs, where the input is still the bits to shift the address right by
2022-10-01 21:01:56 -07:00

362 lines
10 KiB
Rust

use std::fs;
use std::rc::Rc;
use std::cell::RefCell;
use crate::error::Error;
use crate::devices::{Address, Addressable, Transmutable, TransmutableBox, read_beu16};
pub struct MemoryBlock {
read_only: bool,
contents: Vec<u8>,
}
impl MemoryBlock {
pub fn new(contents: Vec<u8>) -> MemoryBlock {
MemoryBlock {
read_only: false,
contents
}
}
pub fn load(filename: &str) -> Result<MemoryBlock, Error> {
match fs::read(filename) {
Ok(contents) => Ok(MemoryBlock::new(contents)),
Err(_) => Err(Error::new(&format!("Error reading contents of {}", filename))),
}
}
pub fn load_at(&mut self, addr: Address, filename: &str) -> Result<(), Error> {
match fs::read(filename) {
Ok(contents) => {
for i in 0..contents.len() {
self.contents[(addr as usize) + i] = contents[i];
}
Ok(())
},
Err(_) => Err(Error::new(&format!("Error reading contents of {}", filename))),
}
}
pub fn read_only(&mut self) {
self.read_only = true;
}
pub fn resize(&mut self, new_size: usize) {
self.contents.resize(new_size, 0);
}
}
impl Addressable for MemoryBlock {
fn len(&self) -> usize {
self.contents.len()
}
fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> {
for i in 0..data.len() {
data[i] = self.contents[(addr as usize) + i];
}
Ok(())
}
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> {
if self.read_only {
return Err(Error::breakpoint(&format!("Attempt to write to read-only memory at {:x} with data {:?}", addr, data)));
}
for i in 0..data.len() {
self.contents[(addr as usize) + i] = data[i];
}
Ok(())
}
}
impl Transmutable for MemoryBlock {
fn as_addressable(&mut self) -> Option<&mut dyn Addressable> {
Some(self)
}
}
pub struct AddressRightShifter {
subdevice: TransmutableBox,
shift: u8,
}
impl AddressRightShifter {
pub fn new(subdevice: TransmutableBox, shift: u8) -> Self {
Self {
subdevice,
shift,
}
}
}
impl Addressable for AddressRightShifter {
fn len(&self) -> usize {
let len = self.subdevice.borrow_mut().as_addressable().unwrap().len();
len << self.shift
}
fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> {
self.subdevice.borrow_mut().as_addressable().unwrap().read(addr >> self.shift, data)
}
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> {
self.subdevice.borrow_mut().as_addressable().unwrap().write(addr >> self.shift, data)
}
}
impl Transmutable for AddressRightShifter {
fn as_addressable(&mut self) -> Option<&mut dyn Addressable> {
Some(self)
}
}
pub struct AddressRepeater {
subdevice: TransmutableBox,
range: Address,
}
impl AddressRepeater {
pub fn new(subdevice: TransmutableBox, range: Address) -> Self {
Self {
subdevice,
range,
}
}
}
impl Addressable for AddressRepeater {
fn len(&self) -> usize {
self.range as usize
}
fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> {
let len = self.subdevice.borrow_mut().as_addressable().unwrap().len() as Address;
self.subdevice.borrow_mut().as_addressable().unwrap().read(addr % len, data)
}
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> {
let len = self.subdevice.borrow_mut().as_addressable().unwrap().len() as Address;
self.subdevice.borrow_mut().as_addressable().unwrap().write(addr % len, data)
}
}
impl Transmutable for AddressRepeater {
fn as_addressable(&mut self) -> Option<&mut dyn Addressable> {
Some(self)
}
}
#[derive(Clone)]
pub struct Block {
pub base: Address,
pub length: usize,
pub dev: TransmutableBox,
}
#[derive(Clone)]
pub struct Bus {
blocks: Vec<Block>,
ignore_unmapped: bool,
watchers: Vec<Address>,
watcher_modified: bool,
}
impl Bus {
pub fn new() -> Bus {
Bus {
ignore_unmapped: false,
blocks: vec!(),
watchers: vec!(),
watcher_modified: false,
}
}
pub fn set_ignore_unmapped(&mut self, ignore_unmapped: bool) {
self.ignore_unmapped = ignore_unmapped;
}
pub fn clear_all_bus_devices(&mut self) {
self.blocks.clear();
}
pub fn insert(&mut self, base: Address, dev: TransmutableBox) {
let length = dev.borrow_mut().as_addressable().unwrap().len();
let block = Block { base, length, dev };
let i = self.blocks.iter().position(|cur| cur.base > block.base).unwrap_or(self.blocks.len());
self.blocks.insert(i, block);
}
pub fn get_device_at(&self, addr: Address, count: usize) -> Result<(TransmutableBox, Address), Error> {
for block in &self.blocks {
if addr >= block.base && addr < (block.base + block.length as Address) {
let relative_addr = addr - block.base;
if relative_addr as usize + count <= block.length {
return Ok((block.dev.clone(), relative_addr));
} else {
return Err(Error::new(&format!("Error reading address {:#010x}", addr)));
}
}
}
return Err(Error::new(&format!("No segment found at {:#010x}", addr)));
}
pub fn dump_memory(&mut self, mut addr: Address, mut count: Address) {
while count > 0 {
let mut line = format!("{:#010x}: ", addr);
let to = if count < 16 { count / 2 } else { 8 };
for _ in 0..to {
let word = self.read_beu16(addr);
if word.is_err() {
println!("{}", line);
return;
}
line += &format!("{:#06x} ", word.unwrap());
addr += 2;
count -= 2;
}
println!("{}", line);
}
}
pub fn add_watcher(&mut self, addr: Address) {
self.watchers.push(addr);
}
pub fn remove_watcher(&mut self, addr: Address) {
self.watchers.push(addr);
if let Some(index) = self.watchers.iter().position(|a| *a == addr) {
self.watchers.remove(index);
}
}
pub fn check_and_reset_watcher_modified(&mut self) -> bool {
let result = self.watcher_modified;
self.watcher_modified = false;
result
}
}
impl Addressable for Bus {
fn len(&self) -> usize {
let block = &self.blocks[self.blocks.len() - 1];
(block.base as usize) + block.length
}
fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> {
let (dev, relative_addr) = match self.get_device_at(addr, data.len()) {
Ok(result) => result,
Err(err) if self.ignore_unmapped => {
info!("{:?}", err);
return Ok(())
},
Err(err) => return Err(err),
};
let result = dev.borrow_mut().as_addressable().unwrap().read(relative_addr, data);
result
}
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> {
if let Some(_) = self.watchers.iter().position(|a| *a == addr) {
println!("watch: writing to address {:#06x} with {:?}", addr, data);
self.watcher_modified = true;
}
let (dev, relative_addr) = match self.get_device_at(addr, data.len()) {
Ok(result) => result,
Err(err) if self.ignore_unmapped => {
info!("{:?}", err);
return Ok(())
},
Err(err) => return Err(err),
};
let result = dev.borrow_mut().as_addressable().unwrap().write(relative_addr, data);
result
}
}
#[derive(Clone)]
pub struct BusPort {
offset: Address,
address_mask: Address,
data_width: u8,
subdevice: Rc<RefCell<Bus>>,
}
impl BusPort {
pub fn new(offset: Address, address_bits: u8, data_bits: u8, bus: Rc<RefCell<Bus>>) -> Self {
let mut address_mask = 0;
for _ in 0..address_bits {
address_mask = (address_mask << 1) | 0x01;
}
Self {
offset,
address_mask,
data_width: data_bits / 8,
subdevice: bus,
}
}
pub fn dump_memory(&mut self, addr: Address, count: Address) {
self.subdevice.borrow_mut().dump_memory(self.offset + (addr & self.address_mask), count)
}
pub fn address_mask(&self) -> Address {
self.address_mask
}
pub fn data_width(&self) -> u8 {
self.data_width
}
}
impl Addressable for BusPort {
fn len(&self) -> usize {
self.subdevice.borrow().len()
}
fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> {
let addr = self.offset + (addr & self.address_mask);
let mut subdevice = self.subdevice.borrow_mut();
for i in (0..data.len()).step_by(self.data_width as usize) {
let end = std::cmp::min(i + self.data_width as usize, data.len());
subdevice.read(addr + i as Address, &mut data[i..end])?;
}
Ok(())
}
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> {
let addr = self.offset + (addr & self.address_mask);
let mut subdevice = self.subdevice.borrow_mut();
for i in (0..data.len()).step_by(self.data_width as usize) {
let end = std::cmp::min(i + self.data_width as usize, data.len());
subdevice.write(addr + i as Address, &data[i..end])?;
}
Ok(())
}
}
pub fn dump_slice(data: &[u8], mut count: usize) {
let mut addr = 0;
while count > 0 {
let mut line = format!("{:#010x}: ", addr);
let to = if count < 16 { count / 2 } else { 8 };
for _ in 0..to {
let word = read_beu16(&data[addr..]);
line += &format!("{:#06x} ", word);
addr += 2;
count -= 2;
}
println!("{}", line);
}
}