Skip to content

Commit

Permalink
simplified logicvector
Browse files Browse the repository at this point in the history
  • Loading branch information
hellow554 committed Dec 3, 2018
1 parent 7eddf1c commit 90bb3c8
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 49 deletions.
27 changes: 27 additions & 0 deletions src/logicbit/logicvector/masks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,25 @@ pub struct Masks {
}

impl Masks {
pub fn get(&self, index: u8) -> Ieee1164 {
for m in self.iter() {
if m.1 >> index & 1 == 1 {
return m.0;
}
}
panic!("No bit set on {}", index)
}

pub fn set(&mut self, index: u8, value: Ieee1164) {
for m in self.iter_mut() {
if m.0 == value {
*m.1 |= 1 << index;
} else {
*m.1 &= !(1 << index);
}
}
}

pub fn sanity_check(&self, width: u8) -> Result<(), SanityChecked> {
for d in 0..128 {
let mut has_one = false;
Expand All @@ -44,6 +63,14 @@ impl Masks {

Ok(())
}

pub fn iter(&self) -> Iter {
self.into_iter()
}

pub fn iter_mut(&mut self) -> IterMut {
self.into_iter()
}
}

impl Index<Ieee1164> for Masks {
Expand Down
115 changes: 66 additions & 49 deletions src/logicbit/logicvector/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::fmt;
use std::ops::{Add, BitAnd, BitOr, BitXor};
use std::str::FromStr;

use crate::{Ieee1164, Ieee1164Value, Resolve};
use crate::{Ieee1164, Resolve};

#[allow(unused)]
macro_rules! expand_op_logicvector {
Expand Down Expand Up @@ -38,18 +38,7 @@ macro_rules! unsafe_version_logicvector {
}

#[inline(always)]
fn build_mask(old: u8, new: u8) -> u128 {
use std::u128::MAX;
match (old, new) {
(a, b) if a >= b => panic!("`old` cannot be greater/equal than `new`!"),
(128, 128) => MAX,
(a, 128) => MAX & !((1 << a) - 1),
(a, b) => ((1 << b) - 1) & !((1 << a) - 1),
}
}

#[inline(always)]
fn gen_mask_from_width(width: u8) -> u128 {
fn mask_from_width(width: u8) -> u128 {
if width != 128 {
((1 << width) - 1)
} else {
Expand All @@ -73,9 +62,9 @@ impl LogicVector {
assert!(assert_width(width));
let mut s = Self {
masks: Masks::default(),
width: width as u8,
width,
};
s.masks[value] = std::u128::MAX & gen_mask_from_width(width);
s.masks[value] = std::u128::MAX & mask_from_width(width);
debug_assert_eq!(Ok(()), s.sanity_check());
s
}
Expand All @@ -85,11 +74,10 @@ impl LogicVector {
if assert_width(width) && width >= (128 - zeros) {
let mut masks = Masks::default();
masks[Ieee1164::_1] = value;
masks[Ieee1164::_0] = (!value) & gen_mask_from_width(width);
masks[Ieee1164::_0] = (!value) & mask_from_width(width);

let s = Self { masks, width };
debug_assert_eq!(Ok(()), s.sanity_check());
Some(s)
debug_assert_eq!(Ok(()), masks.sanity_check(width));
Some(Self { masks, width })
} else {
None
}
Expand All @@ -111,36 +99,65 @@ impl LogicVector {
debug_assert_eq!(Ok(()), self.sanity_check());
}

pub fn resize(&mut self, new_width: u8, value: Ieee1164) {
pub fn resize(&mut self, new_width: u8, value: Ieee1164) -> Option<LogicVector> {
fn resize_mask(old: u8, new: u8) -> u128 {
match (old, new) {
(a, b) if a >= b => unreachable!("`old` cannot be greater/equal than `new`!"),
(128, 128) => std::u128::MAX,
(a, 128) => std::u128::MAX & !((1 << a) - 1),
(a, b) => ((1 << b) - 1) & !((1 << a) - 1),
}
}

assert!(assert_width(new_width));
let old_width = self.width();
self.width = new_width as u8;

match old_width.cmp(&new_width) {
Ordering::Equal => {}
let res = match old_width.cmp(&new_width) {
Ordering::Equal => None,
Ordering::Less => {
let mask = build_mask(old_width, new_width);
let mask = resize_mask(old_width, new_width);

for masks in &mut self.masks {
if masks.0 == value {
*masks.1 |= std::u128::MAX & mask;
for m in &mut self.masks {
if m.0 == value {
*m.1 |= std::u128::MAX & mask;
} else {
*masks.1 &= !(std::u128::MAX & mask);
*m.1 &= !(std::u128::MAX & mask);
}
}
None
}
Ordering::Greater => {
for mask in &mut self.masks {
*mask.1 &= std::u128::MAX & gen_mask_from_width(new_width);
let mut nv = Masks::default();

let mask_nv = resize_mask(new_width, old_width);
let mask_ov = mask_from_width(new_width);
for (m_new, m_old) in nv.iter_mut().zip(self.masks.iter_mut()) {
assert_eq!(m_new.0, m_old.0);
*m_new.1 = (*m_old.1 & mask_nv) >> new_width;
*m_old.1 &= std::u128::MAX & mask_ov;
}

Some(LogicVector {
masks: nv,
width: old_width - new_width,
})
}
};
if let Some(ref nv) = res {
debug_assert_eq!(Ok(()), nv.sanity_check());
}
debug_assert_eq!(Ok(()), self.sanity_check());
res
}

pub fn set_all_to(&mut self, value: Ieee1164) {
for mask in &mut self.masks {
*mask.1 = if value == mask.0 { std::u128::MAX } else { 0 }
*mask.1 = if value == mask.0 {
mask_from_width(self.width)
} else {
0
}
}
debug_assert_eq!(Ok(()), self.sanity_check());
}
Expand All @@ -159,6 +176,22 @@ impl LogicVector {
Some(self.masks[Ieee1164::_1])
}
}

pub fn get(&self, idx: u8) -> Option<Ieee1164> {
assert!(idx < 128);
if idx < self.width() {
Some(self.masks.get(idx))
} else {
None
}
}

pub fn set(&mut self, idx: u8, value: Ieee1164) {
assert!(idx < 128);
if idx < self.width() {
self.masks.set(idx, value)
}
}
}

impl LogicVector {
Expand Down Expand Up @@ -254,7 +287,7 @@ impl LogicVector {
}
let width = self.width();
if let (Some(a), Some(b)) = (self.as_u128(), rhs.as_u128()) {
LogicVector::from_int_value((a + b) & gen_mask_from_width(width), width)
LogicVector::from_int_value((a + b) & mask_from_width(width), width)
} else {
Some(LogicVector::with_width(width))
}
Expand All @@ -271,7 +304,7 @@ fn add(lhs: &LogicVector, rhs: &LogicVector) -> LogicVector {
assert_eq!(width, rhs.width());

LogicVector::from_int_value(
(lhs.as_u128().unwrap() + rhs.as_u128().unwrap()) & gen_mask_from_width(width),
(lhs.as_u128().unwrap() + rhs.as_u128().unwrap()) & mask_from_width(width),
width,
)
.unwrap()
Expand All @@ -285,11 +318,7 @@ expand_op!(resolve, Resolve, resolve, LogicVector, LogicVector, LogicVector);

impl PartialEq for LogicVector {
fn eq(&self, other: &LogicVector) -> bool {
if let (Some(a), Some(b)) = (self.as_u128(), other.as_u128()) {
a == b
} else {
false
}
self.masks == other.masks
}
}

Expand Down Expand Up @@ -453,18 +482,6 @@ mod tests {
prop_assert_eq!(v, value as u128);
}

#[test]
fn atm_gen_mask(old in 0u8..129, new in 0u8..129) {
prop_assume!(old < new);
prop_assume!(old != 0);
prop_assume!(new != 0);
let mask = build_mask(old, new);
prop_assert_eq!(mask.trailing_zeros() as u8, old);
prop_assert_eq!(mask.leading_zeros() as u8, 128 - new);
prop_assert_eq!(mask.count_ones() as u8, new - old);
prop_assert_eq!(mask.count_zeros() as u8, 128 - new + old);
}

#[test]
fn atm_as_u128(val in 0u64..) {
let v = LogicVector::from_int_value(val as u128, 64);
Expand Down

0 comments on commit 90bb3c8

Please sign in to comment.