use super::device::Device;
pub struct Mirror<T, const N: u32> {
device: T,
}
impl<T, const N: u32> Default for Mirror<T, N>
where
T: Device + Default,
{
fn default() -> Self {
assert!(N >= 2, "Mirror should have at least N=2");
assert!(
Self::addr_bits_count() <= 16,
"Mirror should be addressable with 16 bit at most"
);
assert_eq!(
N,
2u32.pow(N.ilog2()),
"Mirror should have an N that is power of 2"
);
Self {
device: T::default(),
}
}
}
impl<T, const N: u32> Device for Mirror<T, N>
where
T: Device + Default,
{
fn with_data(data: &[u8]) -> Self {
let mut new_mirror = Self::new();
new_mirror.init_data(data);
new_mirror
}
fn init_data(&mut self, data: &[u8]) {
assert_eq!(
data.len(),
(T::addr_space_size() * N) as usize,
"incorrect sized data for mirror device"
);
let first_instance_of_data = &data[0..(T::addr_space_size() as usize)];
for i in 1..N {
let range_start = (i * T::addr_space_size()) as usize;
let range_end = T::addr_space_size() as usize + range_start;
assert_eq!(
first_instance_of_data,
&data[range_start..range_end],
"data not correctly mirrored"
);
}
self.device.init_data(first_instance_of_data);
}
fn cache_current_read_data(&self, destination: &mut [u8]) {
let inner_size = self.device.addr_space_size_dyn() as usize;
for i in 0..(N as usize) {
let start = i * inner_size;
let end = (i + 1) * inner_size;
self.device
.cache_current_read_data(&mut destination[start..end]);
}
}
fn read(&self, addr: u16) -> u8 {
self.device.read(addr)
}
fn write(&mut self, data: u8, addr: u16) {
self.device.write(data, addr);
}
fn addr_space_size() -> u32 {
T::addr_space_size() * N
}
fn addr_bits_count() -> u8 {
T::addr_bits_count() + (N.ilog2() as u8)
}
fn addr_space_size_dyn(&self) -> u32 {
T::addr_space_size() * N
}
fn addr_bits_count_dyn(&self) -> u8 {
T::addr_bits_count() + (N.ilog2() as u8)
}
fn is_connected(&self) -> bool {
self.device.is_connected()
}
}
impl<T, const N: u32> Mirror<T, N>
where
T: Device + Default,
{
pub fn new() -> Self {
Self::default()
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::Ram;
extern crate alloc;
use alloc::vec;
use alloc::vec::Vec;
#[test]
fn createmirror_writedifferentinstances_allinstancescorrect() {
const N: u16 = 4;
const SIZE: usize = 4;
let mut mirror = Mirror::<Ram<SIZE>, { N as u32 }>::new();
for i in 0..N {
let addr = i + i * N;
mirror.device.write(i as u8, addr);
}
for n in 0..N {
for i in 0..N {
let addr = n * N + i;
assert_eq!(mirror.device.read(addr), i as u8);
}
}
}
#[test]
#[should_panic(expected = "Mirror should have an N that is power of 2")]
fn createmirror_notpowe2n_panics() {
let _ = Mirror::<Ram<16>, 3>::new();
}
#[test]
#[should_panic(expected = "Mirror should have at least N=2")]
fn createmirror_0n_panics() {
let _ = Mirror::<Ram<16>, 0>::new();
}
#[test]
#[should_panic(expected = "Mirror should have at least N=2")]
fn createmirror_1n_panics() {
let _ = Mirror::<Ram<16>, 1>::new();
}
#[test]
fn createmirror_cachereaddata_cachecorrect() {
const N: u16 = 4;
const SIZE: usize = 4;
let mut mirror = Mirror::<Ram<SIZE>, { N as u32 }>::new();
let mut data = vec![1u8, 2, 3, 4];
for (i, data) in data.iter().enumerate() {
mirror.write(*data, i as u16);
}
let data_clone = data.clone();
data.extend_from_slice(&data_clone);
data.extend_from_slice(&data_clone);
data.extend_from_slice(&data_clone);
let mut cache = Vec::with_capacity(16);
cache.resize(16, 0xFE);
mirror.cache_current_read_data(&mut cache);
assert_eq!(cache, data);
}
}