use std::collections::VecDeque;
use std::fmt;
use std::str::FromStr;
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum BitValue {
Low,
High,
HighZ,
Invalid,
Overflow,
Undefined,
Filtered,
}
struct NibbleValue([BitValue; 4]);
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ValueFormat {
Hex,
Bin,
}
#[derive(Debug, Clone)]
pub enum SignalValue {
Literal(Vec<BitValue>, ValueFormat),
Symbol(String),
}
impl BitValue {
pub fn from_char(c: char) -> BitValue {
match c {
'0' => BitValue::Low,
'1' => BitValue::High,
'z' => BitValue::HighZ,
'u' => BitValue::Undefined,
'-' => BitValue::Overflow,
'w' => BitValue::Filtered,
_ => BitValue::Invalid,
}
}
pub fn to_char(self) -> char {
match self {
BitValue::Low => '0',
BitValue::High => '1',
BitValue::HighZ => 'z',
BitValue::Undefined => 'u',
BitValue::Overflow => '-',
BitValue::Filtered => 'w',
BitValue::Invalid => 'x',
}
}
}
impl NibbleValue {
fn from_vec(v: &[BitValue]) -> Vec<NibbleValue> {
let mut nibbles = Vec::new();
let mut queue = VecDeque::from(v.to_owned());
while !queue.is_empty() {
nibbles.push(NibbleValue::pop_from(&mut queue))
}
nibbles
}
fn pop_from(q: &mut VecDeque<BitValue>) -> NibbleValue {
let mut nibble = [BitValue::Low; 4];
for i in &mut nibble {
*i = q.pop_front().unwrap_or(BitValue::Low)
}
NibbleValue(nibble)
}
pub fn to_char(&self) -> char {
let mut acc = 0;
for i in self.0.iter().rev() {
acc = (acc << 1) | {
match i {
BitValue::Low => 0,
BitValue::High => 1,
b => return b.to_char(),
}
}
}
"0123456789ABCDEF".chars().nth(acc).unwrap()
}
}
impl FromStr for SignalValue {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut v = Vec::new();
for c in s.chars() {
v.push(BitValue::from_char(c))
}
v.reverse();
Ok(SignalValue::Literal(v, ValueFormat::Hex))
}
}
impl SignalValue {
pub fn new(mut value: u64) -> SignalValue {
let mut v = Vec::new();
while value != 0 {
v.push(match value & 1 {
0 => BitValue::Low,
_ => BitValue::High,
});
value >>= 1;
}
SignalValue::Literal(v, ValueFormat::Hex)
}
pub fn new_default(width: usize, value: BitValue) -> SignalValue {
let mut v = Vec::new();
for _ in 0..width {
v.push(value)
}
SignalValue::Literal(v, ValueFormat::Hex)
}
pub fn from_symbol_str(s: &str) -> SignalValue {
SignalValue::Symbol(s.to_string())
}
pub fn from_hex(s: &str) -> SignalValue {
let mut value = 0;
let chars = "0123456789abcdef";
for (nibble, c) in s.chars().rev().enumerate() {
if let Some(i) = chars.find(&c.to_lowercase().to_string()) {
value |= i << (nibble * 4)
}
}
SignalValue::new(value as u64)
}
pub fn invalid() -> SignalValue {
SignalValue::Literal(vec![BitValue::Undefined], ValueFormat::Hex)
}
pub fn expand(&mut self, width: usize) {
if let SignalValue::Literal(literal, _) = self {
let mut expand_value = *literal.first().unwrap_or(&BitValue::High);
if expand_value == BitValue::High {
expand_value = BitValue::Low
}
for _i in literal.len()..width {
literal.push(expand_value)
}
}
}
pub fn width(&self) -> usize {
match self {
SignalValue::Literal(literal, _) => literal.len(),
SignalValue::Symbol(_) => 2,
}
}
pub fn is_invalid(&self) -> bool {
match self {
SignalValue::Literal(literal, _) => {
for b in literal {
match b {
BitValue::HighZ
| BitValue::Invalid
| BitValue::Overflow
| BitValue::Undefined
| BitValue::Filtered => return true,
_ => {}
}
}
false
}
SignalValue::Symbol(_) => false,
}
}
}
impl fmt::Display for SignalValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SignalValue::Literal(literal, value_format) => {
match value_format {
ValueFormat::Bin => {
write!(f, "b")?;
for b in literal.iter().rev() {
write!(f, "{}", b.to_char())?;
}
}
ValueFormat::Hex => {
write!(f, "h")?;
for nibble in NibbleValue::from_vec(literal).iter().rev() {
write!(f, "{}", nibble.to_char())?
}
}
}
Ok(())
}
SignalValue::Symbol(symbol) => {
write!(f, "{}", symbol)?;
Ok(())
}
}
}
}
impl PartialEq for SignalValue {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(SignalValue::Literal(self_l, _), SignalValue::Literal(other_l, _)) => {
for i in 0.. {
match (self_l.get(i), other_l.get(i)) {
(Some(l), Some(r)) if *l != *r => return false,
(Some(x), None) | (None, Some(x)) if *x != BitValue::Low => return false,
(None, None) => return true,
_ => continue,
}
}
false
}
(SignalValue::Symbol(self_s), SignalValue::Symbol(other_s)) => self_s == other_s,
_ => false,
}
}
}
impl Eq for SignalValue {}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn signal_eq() {
assert_eq!(SignalValue::new(0), SignalValue::from_str("000").unwrap());
assert_eq!(
SignalValue::new(42),
SignalValue::from_str("000000101010").unwrap()
);
}
}