///|
/// Convert a VCD scalar character to its classified four-state value.
pub fn logic_bit(value : Char) -> LogicBit {
match value {
'0' => Zero
'1' => One
'x' | 'X' => Unknown
'z' | 'Z' => HighImpedance
_ => Unknown
}
}
///|
/// Convert a classified logic state to canonical VCD spelling.
pub fn LogicBit::to_char(self : LogicBit) -> Char {
match self {
Zero => '0'
One => '1'
Unknown => 'x'
HighImpedance => 'z'
}
}
///|
/// Return a stable human-readable representation of any VCD value.
pub fn Value::display(self : Value) -> String {
match self {
Scalar(value) => value.to_string()
Vector(bits) => "b" + bits
Real(number) => "r" + number.to_string()
}
}
///|
/// Return the number of bits represented by a VCD value.
pub fn Value::width(self : Value) -> Int {
match self {
Scalar(_) => 1
Vector(bits) => bits.length()
Real(_) => 0
}
}
///|
/// Return the scalar character when the value is a scalar.
pub fn Value::as_scalar(self : Value) -> Char? {
match self {
Scalar(value) => Some(value)
_ => None
}
}
///|
/// Return whether a value contains an unknown or high-impedance bit.
pub fn Value::is_unknown(self : Value) -> Bool {
match self {
Scalar(value) =>
match logic_bit(value) {
Unknown | HighImpedance => true
_ => false
}
Vector(bits) => {
for bit in bits {
match logic_bit(bit) {
Unknown | HighImpedance => return true
_ => ()
}
}
false
}
Real(_) => false
}
}
///|
/// Return a canonical lowercase representation without changing numeric data.
pub fn Value::normalized(self : Value) -> Value {
match self {
Scalar(value) => Scalar(logic_bit(value).to_char())
Vector(bits) => Vector(bits.to_lower())
Real(number) => Real(number)
}
}
///|
/// Expand a value into classified bits, preserving vector order.
pub fn Value::bits(self : Value) -> Array[LogicBit] {
match self {
Scalar(value) => [logic_bit(value)]
Vector(text) => text.to_array().map(logic_bit)
Real(_) => []
}
}
///|
/// Convert classified bits to a canonical vector string.
pub fn bits_to_string(bits : Array[LogicBit]) -> String {
bits.map(fn(bit) { bit.to_char().to_string() }).join("")
}
///|
/// Convert a binary VCD value to an integer, returning None for unknown bits.
pub fn Value::to_int(self : Value) -> Int64? {
let bits = self.bits()
if bits.length() == 0 {
return None
}
let mut result : Int64 = 0L
for bit in bits {
match bit {
Zero => result = result * 2L
One => result = result * 2L + 1L
_ => return None
}
}
Some(result)
}
///|
/// Apply a four-state binary operation to two values after width extension.
pub fn value_binary_op(left : Value, right : Value, op : String) -> Value {
let a = left.bits()
let b = right.bits()
let width = Int::max(a.length(), b.length())
if width == 0 {
return Vector("")
}
let result : Array[LogicBit] = []
for i in 0.. Value {
value_binary_op(left, right, "and")
}
///|
/// Four-state bitwise OR.
pub fn value_or(left : Value, right : Value) -> Value {
value_binary_op(left, right, "or")
}
///|
/// Four-state bitwise XOR.
pub fn value_xor(left : Value, right : Value) -> Value {
value_binary_op(left, right, "xor")
}
///|
/// Four-state bitwise NOT.
pub fn value_not(value : Value) -> Value {
let bits = value
.bits()
.map(fn(bit) {
match bit {
Zero => One
One => Zero
_ => Unknown
}
})
if value.width() == 1 {
Scalar(bits[0].to_char())
} else {
Vector(bits_to_string(bits))
}
}
///|
fn aligned_bit(bits : Array[LogicBit], width : Int, index : Int) -> LogicBit {
let offset = width - bits.length()
if index < offset {
Zero
} else {
bits[index - offset]
}
}
///|
fn logic_binary_op(left : LogicBit, right : LogicBit, op : String) -> LogicBit {
match op {
"and" =>
match (left, right) {
(Zero, _) | (_, Zero) => Zero
(One, One) => One
_ => Unknown
}
"or" =>
match (left, right) {
(One, _) | (_, One) => One
(Zero, Zero) => Zero
_ => Unknown
}
_ =>
match (left, right) {
(Zero, Zero) | (One, One) => Zero
(Zero, One) | (One, Zero) => One
_ => Unknown
}
}
}
///|
/// Return the canonical scalar category used by edge analysis.
pub fn edge_kind(before : Char, after : Char) -> EdgeKind {
match (logic_bit(before), logic_bit(after)) {
(Zero, One) => Rising
(One, Zero) => Falling
(_, Unknown) => ToUnknown
(Unknown, _) => FromUnknown
(_, HighImpedance) => ToHighImpedance
(HighImpedance, _) => FromHighImpedance
_ => Other
}
}
///|
/// Return whether a scalar character represents a known driven level.
pub fn is_known_scalar(value : Char) -> Bool {
match logic_bit(value) {
Zero | One => true
_ => false
}
}
///|
/// Return whether two values are equal after VCD case normalization.
pub fn values_equal(
left : Value,
right : Value,
normalize_unknown : Bool,
) -> Bool {
if normalize_unknown {
left.normalized() == right.normalized()
} else {
left == right
}
}