mod tests;
use crate::vm::{
Byte,
Exception,
Long,
Segment,
Word,
};
use std::hint::{cold_path, unlikely};
use std::slice;
#[derive(Clone, Debug)]
pub struct Mem {
data: Box<[Long]>,
}
const _: () = assert!(
Mem::IMG_SIZE.is_multiple_of(size_of::<Long>()),
"erroneous image size is not a multiple of long-words",
);
const _: () = assert!(
Mem::DATA_SIZE.is_multiple_of(size_of::<Long>()),
"erroneous data size is not a multiple of long-words",
);
impl Mem {
pub const IMG_SIZE: usize = {
let mut size = 0;
size += Segment::IMG0.size;
size += Segment::IMG1.size;
size += Segment::IMG2.size;
size += Segment::IMG3.size;
size += Segment::IMG4.size;
size += Segment::IMG5.size;
size += Segment::IMG6.size;
size += Segment::IMG7.size;
size
};
pub const DATA_SIZE: usize = Self::IMG_SIZE + Segment::WRAM.size + Segment::IO.size;
#[inline]
#[must_use]
pub fn new() -> Self {
const DATA_LEN: usize = Mem::DATA_SIZE >> 2;
let data = vec![Default::default(); DATA_LEN].into();
Self { data }
}
#[inline]
pub fn clear(&mut self) {
self.data.fill(Default::default());
}
#[inline]
pub const fn map_addr(addr: Long) -> Result<usize, Exception> {
let segment = Segment::from_v_addr(addr);
let mut addr = addr.as_usize() - segment.v_origin;
if addr >= segment.size {
cold_path();
return Err(Exception::ACCESS_FAULT);
}
addr += segment.p_origin;
Ok(addr)
}
#[inline]
pub fn load_byte(&self, addr: Long) -> Result<Byte, Exception> {
let offset = Self::map_addr(addr)?;
let value = unsafe {
self.as_ptr()
.cast::<Byte>()
.add(offset)
.read()
};
Ok(value)
}
#[inline]
pub fn load_word(&self, addr: Long) -> Result<Word, Exception> {
let offset = Self::map_addr(addr)?;
if unlikely(!offset.is_multiple_of(2)) {
return Err(Exception::ADDRESS_ERROR);
}
let value = unsafe {
self.as_ptr()
.cast::<Word>()
.add(offset)
.read()
};
Ok(value)
}
#[inline]
pub fn load_long(&self, addr: Long) -> Result<Long, Exception> {
let offset = Self::map_addr(addr)?;
if unlikely(!offset.is_multiple_of(4)) {
return Err(Exception::ADDRESS_ERROR);
}
let value = unsafe {
self.as_ptr()
.cast::<Long>()
.add(offset)
.read()
};
Ok(value)
}
#[inline]
pub fn store_byte(&mut self, addr: Long, value: Byte) -> Result<(), Exception> {
let offset = Self::map_addr(addr)?;
unsafe {
self.as_mut_ptr()
.cast::<Byte>()
.add(offset)
.write(value)
};
Ok(())
}
#[inline]
pub fn store_long(&mut self, addr: Long, value: Long) -> Result<(), Exception> {
let mut offset = Self::map_addr(addr)?;
offset = offset.shr_exact(2).ok_or(Exception::ADDRESS_ERROR)?;
unsafe {
self.as_mut_ptr()
.cast::<Long>()
.add(offset)
.write(value)
};
Ok(())
}
#[inline]
#[must_use]
pub fn raw(&self) -> &[u8] {
let len = Self::DATA_SIZE;
let data = self.as_ptr().cast::<u8>();
unsafe { slice::from_raw_parts(data, len) }
}
#[inline]
#[must_use]
pub fn raw_mut(&mut self) -> &mut [u8] {
let len = Self::DATA_SIZE;
let data = self.as_mut_ptr().cast::<u8>();
unsafe { slice::from_raw_parts_mut(data, len) }
}
#[inline]
#[must_use]
pub fn as_ptr(&self) -> *const () {
self.data.as_ptr().cast::<()>()
}
#[inline]
#[must_use]
pub fn as_mut_ptr(&mut self) -> *mut () {
self.data.as_mut_ptr().cast::<()>()
}
}
impl Default for Mem {
#[inline]
fn default() -> Self {
Self::new()
}
}