use anyhow::{Context, Result};
#[derive(Debug)]
pub struct MemoryManager {
ram: Vec<u8>,
}
impl MemoryManager {
#[inline] pub fn new() -> Self {
const RAM_SIZE: usize = 24usize * 1024usize * 1024usize; Self {
ram: vec![0u8; RAM_SIZE],
}
}
#[inline(always)] fn translate_address(&self, address: u32) -> Option<usize> {
if address >= 0x80000000u32 && address < 0x81800000u32 {
Some((address.wrapping_sub(0x80000000u32)) as usize)
} else {
None
}
}
#[inline] pub fn read_u8(&self, address: u32) -> Result<u8> {
let offset: usize = self
.translate_address(address)
.context("Invalid memory address")?;
Ok(self.ram[offset])
}
#[inline] pub fn read_u16(&self, address: u32) -> Result<u16> {
let offset: usize = self
.translate_address(address)
.context("Invalid memory address")?;
if offset.wrapping_add(1usize) >= self.ram.len() {
anyhow::bail!("Memory read out of bounds");
}
let bytes: [u8; 2] = [self.ram[offset], self.ram[offset.wrapping_add(1usize)]];
Ok(u16::from_be_bytes(bytes))
}
#[inline] pub fn read_u32(&self, address: u32) -> Result<u32> {
let offset: usize = self
.translate_address(address)
.context("Invalid memory address")?;
if offset.wrapping_add(3usize) >= self.ram.len() {
anyhow::bail!("Memory read out of bounds");
}
let bytes: [u8; 4] = [
self.ram[offset],
self.ram[offset.wrapping_add(1usize)],
self.ram[offset.wrapping_add(2usize)],
self.ram[offset.wrapping_add(3usize)],
];
Ok(u32::from_be_bytes(bytes))
}
#[inline] pub fn read_u64(&self, address: u32) -> Result<u64> {
let offset: usize = self
.translate_address(address)
.context("Invalid memory address")?;
if offset.wrapping_add(7usize) >= self.ram.len() {
anyhow::bail!("Memory read out of bounds");
}
let bytes: [u8; 8] = [
self.ram[offset],
self.ram[offset.wrapping_add(1usize)],
self.ram[offset.wrapping_add(2usize)],
self.ram[offset.wrapping_add(3usize)],
self.ram[offset.wrapping_add(4usize)],
self.ram[offset.wrapping_add(5usize)],
self.ram[offset.wrapping_add(6usize)],
self.ram[offset.wrapping_add(7usize)],
];
Ok(u64::from_be_bytes(bytes))
}
#[inline] pub fn write_u8(&mut self, address: u32, value: u8) -> Result<()> {
let offset: usize = self
.translate_address(address)
.context("Invalid memory address")?;
self.ram[offset] = value;
Ok(())
}
#[inline] pub fn write_u16(&mut self, address: u32, value: u16) -> Result<()> {
let offset: usize = self
.translate_address(address)
.context("Invalid memory address")?;
if offset.wrapping_add(1usize) >= self.ram.len() {
anyhow::bail!("Memory write out of bounds");
}
let bytes: [u8; 2] = value.to_be_bytes();
self.ram[offset] = bytes[0];
self.ram[offset.wrapping_add(1usize)] = bytes[1];
Ok(())
}
#[inline] pub fn write_u32(&mut self, address: u32, value: u32) -> Result<()> {
let offset: usize = self
.translate_address(address)
.context("Invalid memory address")?;
if offset.wrapping_add(3usize) >= self.ram.len() {
anyhow::bail!("Memory write out of bounds");
}
let bytes: [u8; 4] = value.to_be_bytes();
self.ram[offset] = bytes[0];
self.ram[offset.wrapping_add(1usize)] = bytes[1];
self.ram[offset.wrapping_add(2usize)] = bytes[2];
self.ram[offset.wrapping_add(3usize)] = bytes[3];
Ok(())
}
#[inline] pub fn write_u64(&mut self, address: u32, value: u64) -> Result<()> {
let offset: usize = self
.translate_address(address)
.context("Invalid memory address")?;
if offset.wrapping_add(7usize) >= self.ram.len() {
anyhow::bail!("Memory write out of bounds");
}
let bytes: [u8; 8] = value.to_be_bytes();
for (i, byte) in bytes.iter().enumerate() {
self.ram[offset.wrapping_add(i)] = *byte;
}
Ok(())
}
#[inline] pub fn read_bytes(&self, address: u32, len: usize) -> Result<Vec<u8>> {
let offset: usize = self
.translate_address(address)
.context("Invalid memory address")?;
if offset.wrapping_add(len) > self.ram.len() {
anyhow::bail!("Memory read out of bounds");
}
Ok(self.ram[offset..offset.wrapping_add(len)].to_vec())
}
#[inline] pub fn write_bytes(&mut self, address: u32, data: &[u8]) -> Result<()> {
let offset: usize = self
.translate_address(address)
.context("Invalid memory address")?;
if offset.wrapping_add(data.len()) > self.ram.len() {
anyhow::bail!("Memory write out of bounds");
}
self.ram[offset..offset.wrapping_add(data.len())].copy_from_slice(data);
Ok(())
}
#[inline] pub fn load_section(&mut self, address: u32, data: &[u8]) -> Result<()> {
self.write_bytes(address, data)
}
#[inline] pub fn bulk_copy(&mut self, dest: u32, src: u32, len: usize) -> Result<()> {
let dest_offset: usize = self.translate_address(dest)
.context("Invalid destination address")?;
let src_offset: usize = self.translate_address(src)
.context("Invalid source address")?;
if dest_offset.wrapping_add(len) > self.ram.len() || src_offset.wrapping_add(len) > self.ram.len() {
anyhow::bail!("Bulk copy out of bounds");
}
let temp: Vec<u8> = self.ram[src_offset..src_offset.wrapping_add(len)].to_vec();
self.ram[dest_offset..dest_offset.wrapping_add(len)].copy_from_slice(&temp);
Ok(())
}
#[inline] pub fn get_slice(&self, address: u32, len: usize) -> Result<&[u8]> {
let offset: usize = self.translate_address(address)
.context("Invalid memory address")?;
if offset.wrapping_add(len) > self.ram.len() {
anyhow::bail!("Memory slice out of bounds");
}
Ok(&self.ram[offset..offset.wrapping_add(len)])
}
}
impl Default for MemoryManager {
#[inline] fn default() -> Self {
Self::new()
}
}