///|
/// Canonical encoding class for a VCD value.
pub enum ValueKind {
ScalarKind
VectorKind
RealKind
} derive(Debug, Eq)
///|
/// Return a value's encoding class.
pub fn value_kind(value : Value) -> ValueKind {
match value {
Scalar(_) => ScalarKind
Vector(_) => VectorKind
Real(_) => RealKind
}
}
///|
/// Encode a value exactly as a VCD assignment token, excluding the id.
pub fn value_token(value : Value) -> String {
match value {
Scalar(value) => value.to_string()
Vector(bits) => "b" + bits
Real(number) => "r" + number.to_string()
}
}
///|
/// Decode a value token together with its identifier.
pub fn decode_value_token(
token : String,
signal_id : String,
time : Int64,
) -> Result[Change, ParseError] {
if token == "" {
return Err(InvalidValue(token))
}
let prefix = token.get_char(0).unwrap()
if prefix == '0' ||
prefix == '1' ||
prefix == 'x' ||
prefix == 'X' ||
prefix == 'z' ||
prefix == 'Z' {
if token.length() != 1 {
return Err(InvalidValue(token))
}
Ok({ time, id: signal_id, value: Scalar(prefix) })
} else if prefix == 'b' || prefix == 'B' {
if token.length() <= 1 {
return Err(UnsupportedValue(token))
}
let bits = token.get_view(start=1).unwrap().to_owned()
if !bits.to_array().all(fn(bit) { is_logic_char(bit) }) {
return Err(InvalidValue(token))
}
Ok({ time, id: signal_id, value: Vector(bits) })
} else if prefix == 'r' || prefix == 'R' {
if token.length() <= 1 {
return Err(UnsupportedValue(token))
}
match parse_real(token.get_view(start=1).unwrap().to_owned()) {
Some(number) => Ok({ time, id: signal_id, value: Real(number) })
None => Err(InvalidValue(token))
}
} else {
Err(UnsupportedValue(token))
}
}
///|
/// Return whether a character is a legal four-state VCD bit.
pub fn is_logic_char(value : Char) -> Bool {
value == '0' ||
value == '1' ||
value == 'x' ||
value == 'X' ||
value == 'z' ||
value == 'Z'
}
///|
/// Replace all unknown vector bits with a chosen stable value.
pub fn replace_unknown(value : Value, replacement : LogicBit) -> Value {
let bits = value
.bits()
.map(fn(bit) {
match bit {
Unknown | HighImpedance => replacement
_ => bit
}
})
bits_value(bits)
}
///|
/// Coerce a vector to a fixed width by truncating the most significant bits.
pub fn truncate_value(value : Value, width : Int) -> Value {
let bits = value.bits()
let target = Int::max(1, width)
if bits.length() <= target {
value_zero_extend(value, target)
} else {
bits_value(bits[bits.length() - target:].to_owned())
}
}
///|
/// Convert a value to a fixed-width binary string.
pub fn value_binary_string(value : Value, width : Int) -> String {
bits_to_string(truncate_value(value, width).bits())
}
///|
/// Convert a known binary value to hexadecimal text.
pub fn value_hex(value : Value) -> String? {
if value.is_unknown() || value.bits().length() == 0 {
return None
}
let bits = value.bits()
let padding = (4 - bits.length() % 4) % 4
let padded : Array[LogicBit] = []
for _ in 0.. 1
_ => 0
}
total * 2 + bit_value
})
out.push(hex_digit(number))
}
Some(out.join(""))
}
///|
/// Return a VCD-compatible string with lower-case state markers.
pub fn canonical_value_text(value : Value) -> String {
value.normalized().display()
}
///|
fn hex_digit(value : Int) -> String {
match value {
0 => "0"
1 => "1"
2 => "2"
3 => "3"
4 => "4"
5 => "5"
6 => "6"
7 => "7"
8 => "8"
9 => "9"
10 => "a"
11 => "b"
12 => "c"
13 => "d"
14 => "e"
15 => "f"
_ => "?"
}
}