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, } impl MemoryBlock { pub fn new(contents: Vec) -> MemoryBlock { MemoryBlock { read_only: false, contents } } pub fn load(filename: &str) -> Result { 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, ignore_unmapped: bool, watchers: Vec
, 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>, } impl BusPort { pub fn new(offset: Address, address_bits: u8, data_bits: u8, bus: Rc>) -> 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); } }