use core::{
marker::PhantomData,
mem::{align_of, size_of, transmute},
slice,
};
use crate::{Bus, BusError};
#[repr(transparent)]
pub struct Memory {
_phantom: PhantomData<*mut u8>,
data: [u8],
}
impl_bus! {
u64 u8,
u64 u16,
u64 u32,
u64 u64,
}
impl Memory {
pub fn new<'d>(data: &'d mut [u64]) -> &'d mut Memory {
let ptr = data.as_mut_ptr() as *mut u8;
let len = data.len() * size_of::<u64>();
drop(data);
let slice = unsafe { slice::from_raw_parts_mut(ptr, len) };
unsafe { transmute::<&'d mut [u8], &'d mut Memory>(slice) }
}
pub const fn size(&self) -> usize {
self.data.len()
}
pub fn data(&mut self) -> &mut [u8] {
&mut self.data
}
#[inline]
fn calculate_destination<T>(&self, address: usize) -> Result<*mut T, BusError> {
let upper = address.wrapping_add(size_of::<T>());
if address < upper && upper <= self.size() {
let ptr = unsafe { self.data.as_ptr().add(address) } as *mut T;
if ptr as usize % align_of::<T>() == 0 {
Ok(ptr)
} else {
Err(BusError::AddressMisaligned)
}
} else {
Err(BusError::AccessFault)
}
}
}
macro_rules! impl_bus {
($($addr:ident $val:ident,)*) => {
$(impl Bus<$addr, $val> for Memory {
fn load(&self, address: $addr) -> Result<$val, BusError> {
if address as usize as u64 == address {
let ptr = self.calculate_destination(address as usize)?;
Ok(unsafe { *ptr })
} else {
Err(BusError::AccessFault)
}
}
fn store(&self, address: $addr, value: $val) -> Result<(), BusError> {
if address as usize as u64 == address {
let ptr = self.calculate_destination(address as usize)?;
Ok(unsafe { *ptr = value })
} else {
Err(BusError::AccessFault)
}
}
})*
};
}
use impl_bus;