use anyhow::Result;
#[derive(Debug)]
pub struct Ram {
data: Vec<u8>,
}
impl Ram {
#[inline] pub fn new() -> Self {
const RAM_SIZE: usize = 24usize * 1024usize * 1024usize; Self {
data: vec![0u8; RAM_SIZE],
}
}
#[inline(always)] pub fn read_u8(&self, address: u32) -> Result<u8> {
let addr: usize = (address & 0x00FFFFFFu32) as usize; if addr < self.data.len() {
Ok(self.data[addr])
} else {
anyhow::bail!("RAM read out of bounds: 0x{:08X}", address);
}
}
#[inline] pub fn read_u16(&self, address: u32) -> Result<u16> {
let low: u8 = self.read_u8(address)?;
let high: u8 = self.read_u8(address.wrapping_add(1u32))?;
Ok(u16::from_be_bytes([high, low]))
}
#[inline] pub fn read_u32(&self, address: u32) -> Result<u32> {
let bytes: [u8; 4] = [
self.read_u8(address)?,
self.read_u8(address.wrapping_add(1u32))?,
self.read_u8(address.wrapping_add(2u32))?,
self.read_u8(address.wrapping_add(3u32))?,
];
Ok(u32::from_be_bytes(bytes))
}
#[inline(always)] pub fn write_u8(&mut self, address: u32, value: u8) -> Result<()> {
let addr: usize = (address & 0x00FFFFFFu32) as usize;
if addr < self.data.len() {
self.data[addr] = value;
Ok(())
} else {
anyhow::bail!("RAM write out of bounds: 0x{:08X}", address);
}
}
#[inline] pub fn write_u16(&mut self, address: u32, value: u16) -> Result<()> {
let bytes: [u8; 2] = value.to_be_bytes();
self.write_u8(address, bytes[0])?;
self.write_u8(address.wrapping_add(1u32), bytes[1])?;
Ok(())
}
#[inline] pub fn write_u32(&mut self, address: u32, value: u32) -> Result<()> {
let bytes: [u8; 4] = value.to_be_bytes();
self.write_u8(address, bytes[0])?;
self.write_u8(address.wrapping_add(1u32), bytes[1])?;
self.write_u8(address.wrapping_add(2u32), bytes[2])?;
self.write_u8(address.wrapping_add(3u32), bytes[3])?;
Ok(())
}
#[inline] pub fn read_bytes(&self, address: u32, len: usize) -> Result<Vec<u8>> {
let addr: usize = (address & 0x00FFFFFFu32) as usize;
if addr.wrapping_add(len) <= self.data.len() {
Ok(self.data[addr..addr.wrapping_add(len)].to_vec())
} else {
anyhow::bail!("RAM read out of bounds: 0x{:08X} len {}", address, len);
}
}
#[inline] pub fn write_bytes(&mut self, address: u32, data: &[u8]) -> Result<()> {
let addr: usize = (address & 0x00FFFFFFu32) as usize;
if addr.wrapping_add(data.len()) <= self.data.len() {
self.data[addr..addr.wrapping_add(data.len())].copy_from_slice(data);
Ok(())
} else {
anyhow::bail!(
"RAM write out of bounds: 0x{:08X} len {}",
address,
data.len()
);
}
}
}
impl Default for Ram {
#[inline] fn default() -> Self {
Self::new()
}
}