use super::device::Device;
use super::size_const::*;
#[derive(Copy, Clone)]
pub struct Ram<const SIZE: usize> {
data: [u8; SIZE],
}
impl<const SIZE: usize> Ram<SIZE> {
pub fn new() -> Self {
Self::default()
}
pub const fn bits_count() -> u8 {
SIZE.ilog2() as u8
}
pub const fn size() -> u32 {
SIZE as u32
}
pub fn as_slice(&self) -> &[u8] {
self.data.as_slice()
}
}
impl<const SIZE: usize> Default for Ram<SIZE> {
fn default() -> Self {
assert!(Self::size() > 0, "Ram size must be at least 1 byte");
assert!(
(Self::size() as usize) <= SIZE_64K,
"Ram size must be addressable with at most 16 bit"
);
assert_eq!(
2usize.pow(Self::addr_bits_count() as u32),
Self::size() as usize,
"Ram size must be a power of 2"
);
Self { data: [0; SIZE] }
}
}
impl<const SIZE: usize> Device for Ram<SIZE> {
fn with_data(data: &[u8]) -> Self {
let mut new_ram = Self::default();
new_ram.init_data(data);
new_ram
}
fn init_data(&mut self, data: &[u8]) {
self.data.copy_from_slice(data);
}
fn cache_current_read_data(&self, destination: &mut [u8]) {
destination.copy_from_slice(&self.data);
}
fn read(&self, addr: u16) -> u8 {
let index = Self::wrap_addr(addr);
self.data[index as usize]
}
fn write(&mut self, data: u8, addr: u16) {
let index = Self::wrap_addr(addr);
self.data[index as usize] = data;
}
fn addr_space_size() -> u32 {
Ram::<SIZE>::size()
}
fn addr_bits_count() -> u8 {
Ram::<SIZE>::bits_count()
}
fn addr_space_size_dyn(&self) -> u32 {
Ram::<SIZE>::size()
}
fn addr_bits_count_dyn(&self) -> u8 {
Ram::<SIZE>::bits_count()
}
}
#[cfg(test)]
mod tests {
use super::*;
extern crate alloc;
use alloc::vec::Vec;
#[test]
fn createnewram_allzeros() {
let ram = Ram::<{ SIZE_64K }>::new();
for x in ram.data {
assert_eq!(x, 0);
}
}
#[test]
fn createnewram_initdata_datacorrect() {
let mut ram = Ram::<{ SIZE_64K }>::new();
let data: Vec<_> = (0usize..SIZE_64K).map(|x| x as u8).collect();
ram.init_data(&data[..]);
for i in 0..u16::MAX {
assert_eq!(ram.read(i), i as u8, "\nerroneous data at {}", i);
}
let mut ram = Ram::<32>::new();
ram.init_data(&data[..32]);
for i in 0..32 {
assert_eq!(ram.read(i), i as u8, "\nerroneous data at {}", i);
}
}
#[test]
fn createnewram_fillwithdata_datacorrect() {
let mut ram = Ram::<{ SIZE_64K }>::new();
for i in 0..u16::MAX {
ram.write(i as u8, i);
}
for i in 0..u16::MAX {
assert_eq!(ram.read(i), i as u8, "\nerroneous data at {}", i);
}
let mut ram = Ram::<32>::new();
for i in 0..u16::MAX {
ram.write(i as u8, i);
}
for i in (u16::MAX - 32)..u16::MAX {
assert_eq!(ram.read(i), i as u8, "\nerroneous data at {}", i);
}
}
#[test]
fn createnewsmallram_readwrite_nooutofbounds() {
let ram = Ram::<16>::new();
for i in 0..u16::MAX {
let index = Ram::<16>::wrap_addr(i);
assert_eq!(ram.data[index as usize], 0);
}
let ram = Ram::<32>::new();
for i in 0..u16::MAX {
let index = Ram::<32>::wrap_addr(i);
assert_eq!(ram.data[index as usize], 0);
}
}
#[test]
#[should_panic(expected = "Ram size must be at least 1 byte")]
fn createemptyram_panics() {
let _ = Ram::<0>::new();
}
#[test]
#[should_panic(expected = "Ram size must be addressable with at most 16 bit")]
fn createtoobigram_panics() {
let _ = Ram::<{ 2usize.pow(16) + 1 }>::new();
}
#[test]
#[should_panic(expected = "Ram size must be a power of 2")]
fn createnotpowe2ram_panics() {
let _ = Ram::<{ SIZE_64K - 1 }>::new();
}
}