use rand::rngs::StdRng;
use rand::Rng;
use crate::ast::Reg;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Word {
data: u16,
init: u16
}
const NO_BITS: u16 = 0;
const ALL_BITS: u16 = 1u16.wrapping_neg();
impl Word {
pub fn new_uninit<F: WordFiller + ?Sized>(fill: &mut F) -> Self {
Self {
data: fill.generate(),
init: NO_BITS,
}
}
pub fn new_init(data: u16) -> Self {
Self {
data,
init: ALL_BITS,
}
}
pub fn get(&self) -> u16 {
self.data
}
pub fn get_if_init<E>(&self, strict: bool, err: E) -> Result<u16, E> {
match !strict || self.is_init() {
true => Ok(self.data),
false => Err(err)
}
}
pub fn set(&mut self, data: u16) {
self.data = data;
self.init = ALL_BITS;
}
pub fn set_if_init<E>(&mut self, data: Word, strict: bool, err: E) -> Result<(), E> {
match !strict || data.is_init() {
true => {
*self = data;
Ok(())
},
false => Err(err)
}
}
pub fn is_init(&self) -> bool {
self.init == ALL_BITS
}
pub fn clear_init(&mut self) {
self.init = NO_BITS;
}
}
impl From<u16> for Word {
fn from(value: u16) -> Self {
Word::new_init(value)
}
}
impl From<i16> for Word {
fn from(value: i16) -> Self {
Word::new_init(value as u16)
}
}
impl std::ops::Not for Word {
type Output = Word;
fn not(self) -> Self::Output {
let Self { data, init } = self;
Self { data: !data, init }
}
}
impl std::ops::Add for Word {
type Output = Word;
fn add(self, rhs: Self) -> Self::Output {
let Self { data: ldata, init: linit } = self;
let Self { data: rdata, init: rinit } = rhs;
if rdata == 0 && rinit == ALL_BITS { return self; }
if ldata == 0 && linit == ALL_BITS { return rhs; }
let data = ldata.wrapping_add(rdata);
let init = match linit == ALL_BITS && rinit == ALL_BITS {
true => ALL_BITS,
false => NO_BITS,
};
Self { data, init }
}
}
impl std::ops::AddAssign for Word {
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs;
}
}
impl std::ops::AddAssign<u16> for Word {
fn add_assign(&mut self, rhs: u16) {
*self = *self + Word::from(rhs);
}
}
impl std::ops::AddAssign<i16> for Word {
fn add_assign(&mut self, rhs: i16) {
*self = *self + Word::from(rhs);
}
}
impl std::ops::Sub for Word {
type Output = Word;
fn sub(self, rhs: Self) -> Self::Output {
let Self { data: ldata, init: linit } = self;
let Self { data: rdata, init: rinit } = rhs;
if rdata == 0 && rinit == ALL_BITS { return self; }
let data = ldata.wrapping_sub(rdata);
let init = match linit == ALL_BITS && rinit == ALL_BITS {
true => ALL_BITS,
false => NO_BITS,
};
Self { data, init }
}
}
impl std::ops::SubAssign for Word {
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs;
}
}
impl std::ops::SubAssign<u16> for Word {
fn sub_assign(&mut self, rhs: u16) {
*self = *self - Word::new_init(rhs);
}
}
impl std::ops::SubAssign<i16> for Word {
fn sub_assign(&mut self, rhs: i16) {
*self = *self - Word::new_init(rhs as _);
}
}
impl std::ops::BitAnd for Word {
type Output = Word;
fn bitand(self, rhs: Self) -> Self::Output {
let Self { data: ldata, init: linit } = self;
let Self { data: rdata, init: rinit } = rhs;
let data = ldata & rdata;
let init = (linit & rinit) | (!ldata & linit) | (!rdata & rinit);
Self { data, init }
}
}
impl std::ops::BitAndAssign for Word {
fn bitand_assign(&mut self, rhs: Self) {
*self = *self & rhs;
}
}
pub trait WordFiller {
fn generate(&mut self) -> u16;
fn generate_array<const N: usize>(&mut self) -> [Word; N] {
std::array::from_fn(|_| Word::new_uninit(self))
}
fn generate_boxed_array<const N: usize>(&mut self) -> Box<[Word; N]> {
std::iter::repeat_with(|| Word::new_uninit(self))
.take(N)
.collect::<Box<_>>()
.try_into()
.unwrap_or_else(|_| unreachable!("iterator should have had {N} elements"))
}
}
impl WordFiller for () {
fn generate(&mut self) -> u16 {
rand::random()
}
}
impl WordFiller for u16 {
fn generate(&mut self) -> u16 {
*self
}
}
impl WordFiller for StdRng {
fn generate(&mut self) -> u16 {
self.random()
}
}
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
pub enum MachineInitStrategy {
#[default]
Unseeded,
Seeded {
seed: u64
},
Known {
value: u16
}
}
impl MachineInitStrategy {
pub(super) fn generator(&self) -> impl WordFiller {
use rand::SeedableRng;
match self {
MachineInitStrategy::Unseeded => WCGenerator::Unseeded,
MachineInitStrategy::Seeded { seed } => WCGenerator::Seeded(Box::new(StdRng::seed_from_u64(*seed))),
MachineInitStrategy::Known { value } => WCGenerator::Known(*value),
}
}
}
enum WCGenerator {
Unseeded,
Seeded(Box<rand::rngs::StdRng>),
Known(u16)
}
impl WordFiller for WCGenerator {
fn generate(&mut self) -> u16 {
match self {
WCGenerator::Unseeded => ().generate(),
WCGenerator::Seeded(r) => r.generate(),
WCGenerator::Known(k) => k.generate(),
}
}
}
#[derive(Debug)]
pub struct MemArray(Box<[Word; 1 << 16]>);
impl MemArray {
pub fn new(filler: &mut impl WordFiller) -> Self {
Self(filler.generate_boxed_array())
}
pub(super) fn copy_obj_block(&mut self, mut start: u16, data: &[Option<u16>]) {
let mem = &mut self.0;
for chunk in data.chunk_by(|a, b| a.is_some() == b.is_some()) {
let end = start.wrapping_add(chunk.len() as u16);
let si = usize::from(start);
let ei = usize::from(end);
let block_is_contiguous = start <= end;
if chunk[0].is_some() { let ch: Vec<_> = chunk.iter()
.map(|&opt| opt.unwrap())
.map(Word::new_init)
.collect();
if block_is_contiguous {
mem[si..ei].copy_from_slice(&ch);
} else {
let (left, right) = ch.split_at(start.wrapping_neg() as usize);
mem[si..].copy_from_slice(left);
mem[..ei].copy_from_slice(right)
}
} else { if block_is_contiguous {
for word in &mut mem[si..ei] {
word.clear_init();
}
} else {
for word in &mut mem[si..] {
word.clear_init();
}
for word in &mut mem[..ei] {
word.clear_init();
}
}
}
start = end;
}
}
pub(super) fn as_slice_mut(&mut self) -> &mut [Word] {
&mut *self.0
}
}
impl std::ops::Index<u16> for MemArray {
type Output = Word;
fn index(&self, index: u16) -> &Self::Output {
&self.0[index as usize]
}
}
impl std::ops::IndexMut<u16> for MemArray {
fn index_mut(&mut self, index: u16) -> &mut Self::Output {
&mut self.0[index as usize]
}
}
#[derive(Debug, Clone)]
pub struct RegFile([Word; Reg::REG_SIZE]);
impl RegFile {
pub fn new(filler: &mut impl WordFiller) -> Self {
Self(filler.generate_array())
}
}
impl std::ops::Index<Reg> for RegFile {
type Output = Word;
fn index(&self, index: Reg) -> &Self::Output {
&self.0[usize::from(index)]
}
}
impl std::ops::IndexMut<Reg> for RegFile {
fn index_mut(&mut self, index: Reg) -> &mut Self::Output {
&mut self.0[usize::from(index)]
}
}