///|
/// Concatenate two VCD values without losing vector width.
pub fn value_concat(left : Value, right : Value) -> Value {
let bits = left.bits() + right.bits()
if bits.length() == 1 {
Scalar(bits[0].to_char())
} else {
Vector(bits_to_string(bits))
}
}
///|
/// Reduce a vector with four-state AND semantics.
pub fn value_reduce_and(value : Value) -> Value {
reduce_value(value, "and")
}
///|
/// Reduce a vector with four-state OR semantics.
pub fn value_reduce_or(value : Value) -> Value {
reduce_value(value, "or")
}
///|
/// Reduce a vector with four-state XOR semantics.
pub fn value_reduce_xor(value : Value) -> Value {
reduce_value(value, "xor")
}
///|
/// Add two binary values, returning unknown for any unknown input bit.
pub fn value_add(left : Value, right : Value) -> Value {
let left_bits = left.bits()
let right_bits = right.bits()
let width = Int::max(left_bits.length(), right_bits.length())
let result : Array[LogicBit] = []
let mut carry = Zero
let mut i = width - 1
while i >= 0 {
let (sum, next_carry) = logic_add_three(
aligned_bit(left_bits, width, i),
aligned_bit(right_bits, width, i),
carry,
)
result.insert(0, sum)
carry = next_carry
i -= 1
}
if carry is One {
result.insert(0, One)
}
bits_value(result)
}
///|
/// Subtract two binary values with a fixed-width result.
pub fn value_sub(left : Value, right : Value) -> Value {
let width = Int::max(left.width(), right.width())
let a = value_zero_extend(left, width)
let b = value_zero_extend(right, width)
if a.is_unknown() || b.is_unknown() {
return Vector("x".repeat(width))
}
match (a.to_int(), b.to_int()) {
(Some(left_number), Some(right_number)) => {
let modulus = pow2(width)
let raw = if left_number >= right_number {
left_number - right_number
} else {
modulus - (right_number - left_number)
}
value_from_int(raw, width)
}
_ => Vector("x".repeat(width))
}
}
///|
/// Compare two known binary values as unsigned integers.
pub fn value_compare_unsigned(left : Value, right : Value) -> Int? {
if left.is_unknown() || right.is_unknown() {
return None
}
let a = left.bits()
let b = right.bits()
let width = Int::max(a.length(), b.length())
for i in 0.. Some(-1)
(One, Zero) => Some(1)
_ => None
}
}
}
Some(0)
}
///|
/// Shift a value left and fill vacated bits with zero.
pub fn value_shift_left(value : Value, amount : Int) -> Value {
let bits = value.bits()
let width = bits.length()
if width == 0 {
return value
}
let shift = Int::max(0, amount)
let result : Array[LogicBit] = []
for i in 0..= width {
result.push(Zero)
} else {
result.push(bits[source])
}
}
bits_value(result)
}
///|
/// Shift a value right and fill vacated bits with zero.
pub fn value_shift_right(value : Value, amount : Int) -> Value {
let bits = value.bits()
let width = bits.length()
if width == 0 {
return value
}
let shift = Int::max(0, amount)
let result : Array[LogicBit] = []
for i in 0.. Value {
let bits = value.bits()
let width = bits.length()
if width == 0 {
return value
}
let shift = (amount % width + width) % width
let result : Array[LogicBit] = []
for i in 0.. Value {
let bits = value.bits()
let width = bits.length()
if width == 0 {
return value
}
let shift = (amount % width + width) % width
let result : Array[LogicBit] = []
for i in 0.. Int {
value.bits().count(One)
}
///|
/// Count unknown and high-impedance bits in a value.
pub fn value_count_unknown(value : Value) -> Int {
value
.bits()
.count_if(fn(bit) {
match bit {
Unknown | HighImpedance => true
_ => false
}
})
}
///|
/// Return whether every bit is logically zero.
pub fn value_is_zero(value : Value) -> Bool {
let bits = value.bits()
bits.length() > 0 && bits.all(fn(bit) { bit is Zero })
}
///|
/// Return whether a vector contains at least one known one bit.
pub fn value_has_one(value : Value) -> Bool {
value.bits().any(fn(bit) { bit is One })
}
///|
/// Construct a value from a non-negative integer and a fixed width.
pub fn value_from_int(number : Int64, width : Int) -> Value {
let safe_width = Int::max(1, width)
let result : Array[LogicBit] = []
let mut current = Int64::max(0L, number)
for _ in 0.. Value {
let bits = value.bits()
if bits.length() == 0 {
return Scalar('x')
}
let mut result = bits[0]
for i in 1.. Value {
if bits.length() == 1 {
Scalar(bits[0].to_char())
} else {
Vector(bits_to_string(bits))
}
}
///|
fn logic_add_three(
left : LogicBit,
right : LogicBit,
carry : LogicBit,
) -> (LogicBit, LogicBit) {
match (left, right, carry) {
(Zero, Zero, Zero) => (Zero, Zero)
(Zero, Zero, One) => (One, Zero)
(Zero, One, Zero) | (One, Zero, Zero) => (One, Zero)
(Zero, One, One) | (One, Zero, One) => (Zero, One)
(One, One, Zero) => (Zero, One)
(One, One, One) => (One, One)
_ => (Unknown, Unknown)
}
}
///|
fn pow2(width : Int) -> Int64 {
let mut result : Int64 = 1L
for _ in 0.. Value {
let bits = value.bits()
let target = Int::max(width, bits.length())
let sign = match bits.get(0) {
Some(One) => One
_ => Zero
}
let result : Array[LogicBit] = []
for _ in 0..<(target - bits.length()) {
result.push(sign)
}
result.append(bits)
bits_value(result)
}