mod tests;
use crate::isa::{Byte, Long, Word};
use crate::vm::{Exception, Segment};
use std::hint::cold_path;
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 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)?
.shr_exact(1)
.ok_or(Exception::ADDRESS_ERROR)?;
let mut value = unsafe {
self.as_ptr()
.cast::<Word>()
.add(offset)
.read()
};
value = Word::from_be(value);
Ok(value)
}
#[inline]
pub fn load_long(&self, addr: Long) -> Result<Long, Exception> {
let offset = Self::map_addr(addr)?
.shr_exact(2)
.ok_or(Exception::ADDRESS_ERROR)?;
let mut value = unsafe {
self.as_ptr()
.cast::<Long>()
.add(offset)
.read()
};
value = Long::from_be(value);
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_word(&mut self, addr: Long, mut value: Word) -> Result<(), Exception> {
let offset = Self::map_addr(addr)?
.shr_exact(1)
.ok_or(Exception::ADDRESS_ERROR)?;
value = value.to_be();
unsafe {
self.as_mut_ptr()
.cast::<Word>()
.add(offset)
.write(value)
};
Ok(())
}
#[inline]
pub fn store_long(&mut self, addr: Long, mut value: Long) -> Result<(), Exception> {
let offset = Self::map_addr(addr)?
.shr_exact(2)
.ok_or(Exception::ADDRESS_ERROR)?;
value = value.to_be();
unsafe {
self.as_mut_ptr()
.cast::<Long>()
.add(offset)
.write(value)
};
Ok(())
}
#[inline]
#[must_use]
pub fn raw(&self) -> &[u8] {
let data = self.as_ptr().cast::<u8>();
unsafe { slice::from_raw_parts(data, Self::DATA_SIZE) }
}
#[inline]
#[must_use]
pub fn raw_mut(&mut self) -> &mut [u8] {
let data = self.as_mut_ptr().cast::<u8>();
unsafe { slice::from_raw_parts_mut(data, Self::DATA_SIZE) }
}
#[inline]
#[must_use]
pub fn as_bytes(&self) -> &[Byte] {
let data = self.as_ptr().cast::<Byte>();
unsafe { slice::from_raw_parts(data, Self::DATA_SIZE) }
}
#[inline]
#[must_use]
pub fn as_words(&self) -> &[Word] {
const LEN: usize = Mem::DATA_SIZE >> 1;
let data = self.as_ptr().cast::<Word>();
unsafe { slice::from_raw_parts(data, LEN) }
}
#[inline]
#[must_use]
pub fn as_longs(&self) -> &[Long] {
const LEN: usize = Mem::DATA_SIZE >> 2;
let data = self.as_ptr().cast::<Long>();
unsafe { slice::from_raw_parts(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()
}
}