use celox::{BigUint, SimulatorBuilder};
#[path = "test_utils/mod.rs"]
#[macro_use]
#[allow(unused_macros)]
mod test_utils;
all_backends! {
fn test_four_state_and_or(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic,
b: input logic,
y_and: output logic,
y_or: output logic
) {
assign y_and = a & b;
assign y_or = a | b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y_and = sim.signal("y_and");
let id_y_or = sim.signal("y_or");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0u32), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(1u32), BigUint::from(1u32));
})
.unwrap();
let (v_and, m_and) = sim.get_four_state(id_y_and);
assert_eq!(m_and, BigUint::from(0u32), "0 & X should have mask 0");
assert_eq!(v_and, BigUint::from(0u32), "0 & X should have value 0");
let (v_or, m_or) = sim.get_four_state(id_y_or);
assert_eq!(m_or, BigUint::from(1u32), "0 | X should have mask 1 (X)");
assert_eq!(
v_or,
BigUint::from(1u32),
"0 | X should have value 1 (X encoding)"
);
}
fn test_four_state_initial_and_set(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
b: input bit<8>
) {}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let (v_init_a, m_init_a) = sim.get_four_state(id_a);
assert_eq!(v_init_a, BigUint::from(0xFFu32));
assert_eq!(m_init_a, BigUint::from(0xFFu32));
let (v_init_b, m_init_b) = sim.get_four_state(id_b);
assert_eq!(v_init_b, BigUint::from(0u32));
assert_eq!(
m_init_b,
BigUint::from(0u32),
"bit type should not be initialized to X"
);
sim.modify(|io| {
io.set(id_a, 42u8);
})
.unwrap();
let (v_set, m_set) = sim.get_four_state(id_a);
assert_eq!(v_set, BigUint::from(42u32));
assert_eq!(m_set, BigUint::from(0u32));
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0xA5u32), BigUint::from(0x0Fu32));
})
.unwrap();
let (v_four_set, m_four_set) = sim.get_four_state(id_a);
assert_eq!(v_four_set, BigUint::from(0xA5u32));
assert_eq!(m_four_set, BigUint::from(0x0Fu32));
sim.modify(|io| {
io.set(id_a, 100u8);
})
.unwrap();
let (v_set2, m_set2) = sim.get_four_state(id_a);
assert_eq!(v_set2, BigUint::from(100u32));
assert_eq!(
m_set2,
BigUint::from(0u32),
"Mask should be cleared by set()"
);
}
fn test_ff_struct_logic_to_bit_coercion_clears_mask(sim) {
@ignore_on(veryl, sv);
@setup {
let code = r#"
module Top (
clk: input clock,
in_logic: input logic<8>,
out_bit: output bit<8>
) {
struct S {
x: bit<8>,
}
var r: S;
always_ff (clk) {
r = S'{x: in_logic};
}
assign out_bit = r.x;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let clk = sim.event("clk");
let in_logic = sim.signal("in_logic");
let out_bit = sim.signal("out_bit");
sim.modify(|io| {
io.set_four_state(in_logic, BigUint::from(0xA5u32), BigUint::from(0x0Fu32));
})
.unwrap();
sim.tick(clk).unwrap();
let (_value, mask) = sim.get_four_state(out_bit);
assert_eq!(mask, BigUint::from(0u32), "logic -> bit coercion must clear X/Z mask");
}
fn test_four_state_mixing(sim) {
@ignore_on(veryl, sv);
@setup {
let code = r#"
module Top (
a_logic: input logic<8>,
b_bit: input bit<8>,
y_logic_from_bit: output logic<8>,
y_bit_from_logic: output bit<8>
) {
// Assigning a logic (4-state) to a bit (2-state) should drop the X state.
assign y_bit_from_logic = a_logic as u8;
// Assigning a bit (2-state) to a logic (4-state) should have mask 0.
assign y_logic_from_bit = b_bit;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a_logic = sim.signal("a_logic");
let id_b_bit = sim.signal("b_bit");
let id_y_logic_from_bit = sim.signal("y_logic_from_bit");
let id_y_bit_from_logic = sim.signal("y_bit_from_logic");
sim.modify(|io| {
io.set_four_state(id_a_logic, BigUint::from(0u32), BigUint::from(0xFFu32));
io.set_four_state(id_b_bit, BigUint::from(0xAAu32), BigUint::from(0u32));
})
.unwrap();
let (v_y_logic, m_y_logic) = sim.get_four_state(id_y_logic_from_bit);
assert_eq!(v_y_logic, BigUint::from(0xAAu32));
assert_eq!(
m_y_logic,
BigUint::from(0u32),
"bit to logic assignment should have 0 mask"
);
let (_v_y_bit, m_y_bit) = sim.get_four_state(id_y_bit_from_logic);
assert_eq!(
m_y_bit,
BigUint::from(0u32),
"logic to bit assignment should drop X mask"
);
}
fn test_four_state_mixing_propagation(sim) {
@ignore_on(veryl, sv);
@setup {
let code = r#"
module Top (
a_logic: input logic<8>,
y_logic: output logic<8>
) {
var temp_bit: bit<8>;
assign temp_bit = a_logic as u8;
assign y_logic = temp_bit;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a_logic = sim.signal("a_logic");
let id_y_logic = sim.signal("y_logic");
sim.modify(|io| {
io.set_four_state(id_a_logic, BigUint::from(0u32), BigUint::from(0xFFu32));
})
.unwrap();
let (_, m_y_logic) = sim.get_four_state(id_y_logic);
assert_eq!(
m_y_logic,
BigUint::from(0u32),
"X should be stripped when propagating through a bit intermediate variable"
);
}
fn test_read_a(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>
) {}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0xA5u32), BigUint::from(0x0Fu32));
})
.unwrap();
let (_v, m) = sim.get_four_state(id_a);
assert_eq!(m, BigUint::from(0x0Fu32), "mask of A should be 15, not 255");
}
fn test_four_state_arithmetic_ops(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
b: input logic<8>,
y_add: output logic<8>
) {
assign y_add = a + b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y_add = sim.signal("y_add");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(10u32), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(1u32), BigUint::from(1u32));
})
.unwrap();
let (v_add, m_add) = sim.get_four_state(id_y_add);
assert_eq!(
m_add,
BigUint::from(0xFFu32),
"Arithmetic addition with X input should yield all X mask"
);
assert_eq!(
v_add,
BigUint::from(0xFFu32),
"Value is normalized at X positions (v |= m)"
);
}
fn test_four_state_unary_ops(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
y_bitnot: output logic<8>,
y_redor: output logic
) {
assign y_bitnot = ~a;
assign y_redor = |a;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_y_bitnot = sim.signal("y_bitnot");
let id_y_redor = sim.signal("y_redor");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0xA5u32), BigUint::from(0x0Fu32));
})
.unwrap();
let (_v_bitnot, m_bitnot) = sim.get_four_state(id_y_bitnot);
assert_eq!(
m_bitnot,
BigUint::from(0x0Fu32),
"Bitwise NOT should preserve mask bits"
);
let (_, _m_redor) = sim.get_four_state(id_y_redor);
}
fn test_four_state_xor_partial_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
b: input logic<8>,
y: output logic<8>
) {
assign y = a ^ b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0xFFu32), BigUint::from(0x0Fu32));
io.set_four_state(id_b, BigUint::from(0x00u32), BigUint::from(0x00u32));
})
.unwrap();
let (_, m_y) = sim.get_four_state(id_y);
assert_eq!(
m_y,
BigUint::from(0x0Fu32),
"XOR mask should be union of input masks"
);
}
fn test_four_state_concat(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<4>,
b: input logic<4>,
y: output logic<8>
) {
assign y = {a, b};
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0xAu32), BigUint::from(0xFu32));
io.set_four_state(id_b, BigUint::from(0x5u32), BigUint::from(0x0u32));
})
.unwrap();
let (v_y, m_y) = sim.get_four_state(id_y);
assert_eq!(
m_y,
BigUint::from(0xF0u32),
"Concat: upper nibble should be X (from a), lower nibble defined (from b)"
);
assert_eq!(v_y & BigUint::from(0x0Fu32), BigUint::from(0x05u32));
}
fn test_four_state_shift_by_constant(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
y_shr: output logic<8>,
y_shl: output logic<8>
) {
assign y_shr = a >> 4;
assign y_shl = a << 4;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_y_shr = sim.signal("y_shr");
let id_y_shl = sim.signal("y_shl");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0xA5u32), BigUint::from(0x0Fu32));
})
.unwrap();
let (_, m_shr) = sim.get_four_state(id_y_shr);
assert_eq!(
m_shr,
BigUint::from(0x00u32),
"Right shift by 4 should shift X mask out"
);
let (_, m_shl) = sim.get_four_state(id_y_shl);
assert_eq!(
m_shl,
BigUint::from(0xF0u32),
"Left shift by 4 should shift X mask to upper nibble"
);
}
fn test_four_state_shift_by_x_amount(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
b: input logic<8>,
y: output logic<8>
) {
assign y = a >> b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0xFFu32), BigUint::from(0x00u32));
io.set_four_state(id_b, BigUint::from(0x00u32), BigUint::from(0xFFu32));
})
.unwrap();
let (_, m_y) = sim.get_four_state(id_y);
assert_eq!(
m_y,
BigUint::from(0xFFu32),
"Shift by X amount should produce all-X mask"
);
}
fn test_four_state_comparison_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
b: input logic<8>,
y_eq: output logic,
y_lt: output logic
) {
assign y_eq = a == b;
assign y_lt = a <: b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y_eq = sim.signal("y_eq");
let id_y_lt = sim.signal("y_lt");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(10u32), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(0u32), BigUint::from(1u32));
})
.unwrap();
let (_, m_eq) = sim.get_four_state(id_y_eq);
let (_, m_lt) = sim.get_four_state(id_y_lt);
assert_eq!(
m_eq,
BigUint::from(1u32),
"Equality comparison with X input should yield X"
);
assert_eq!(
m_lt,
BigUint::from(1u32),
"Less-than comparison with X input should yield X"
);
}
fn test_four_state_mux_x_condition(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
sel: input logic,
a: input logic<8>,
b: input logic<8>,
y: output logic<8>
) {
assign y = if sel ? a : b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_sel = sim.signal("sel");
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_sel, BigUint::from(1u32), BigUint::from(1u32));
io.set_four_state(id_a, BigUint::from(0xAAu32), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(0xBBu32), BigUint::from(0u32));
})
.unwrap();
let (v_y, m_y) = sim.get_four_state(id_y);
assert_eq!(v_y, BigUint::from(0xBBu32));
assert_eq!(
m_y,
BigUint::from(0x11u32),
"Mux with X condition must merge branch bits"
);
}
fn test_four_state_mux_x_in_branch(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
sel: input logic,
a: input logic<8>,
b: input logic<8>,
y: output logic<8>
) {
assign y = if sel ? a : b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_sel = sim.signal("sel");
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_sel, BigUint::from(1u32), BigUint::from(0u32));
io.set_four_state(id_a, BigUint::from(0u32), BigUint::from(0xFFu32));
io.set_four_state(id_b, BigUint::from(0xBBu32), BigUint::from(0u32));
})
.unwrap();
let (_, m_y) = sim.get_four_state(id_y);
assert_eq!(
m_y,
BigUint::from(0xFFu32),
"Mux sel=1 selecting X branch should propagate X"
);
sim.modify(|io| {
io.set_four_state(id_sel, BigUint::from(0u32), BigUint::from(0u32));
})
.unwrap();
let (v_y, m_y) = sim.get_four_state(id_y);
assert_eq!(
m_y,
BigUint::from(0u32),
"Mux sel=0 selecting defined branch should have mask=0"
);
assert_eq!(v_y, BigUint::from(0xBBu32));
}
fn test_four_state_wide_128bit(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<128>,
b: input logic<128>,
y_and: output logic<128>,
y_or: output logic<128>
) {
assign y_and = a & b;
assign y_or = a | b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y_and = sim.signal("y_and");
let id_y_or = sim.signal("y_or");
let val_a: BigUint = (BigUint::from(u64::MAX) << 64) | BigUint::from(u64::MAX);
let mask_a: BigUint = BigUint::from(0u32);
let val_b: BigUint = BigUint::from(0u32);
let mask_b: BigUint = BigUint::from(u64::MAX) << 64;
sim.modify(|io| {
io.set_four_state(id_a, val_a, mask_a);
io.set_four_state(id_b, val_b, mask_b);
})
.unwrap();
let (_, m_and) = sim.get_four_state(id_y_and);
let expected_mask_upper = BigUint::from(u64::MAX) << 64;
assert_eq!(
m_and, expected_mask_upper,
"128-bit AND: upper 64 bits should be X, lower should be 0"
);
let (_, m_or) = sim.get_four_state(id_y_or);
assert_eq!(
m_or,
BigUint::from(0u32),
"128-bit OR: 1|X = 1, so mask should be 0"
);
}
fn test_four_state_always_comb_chain(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
b: input logic<8>,
y: output logic<8>
) {
var tmp: logic<8>;
always_comb {
tmp = a & b;
y = tmp | 8'hF0;
}
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0xFFu32), BigUint::from(0x00u32));
io.set_four_state(id_b, BigUint::from(0xFFu32), BigUint::from(0x01u32));
})
.unwrap();
let (_, m_y) = sim.get_four_state(id_y);
assert_eq!(
m_y,
BigUint::from(0x01u32),
"always_comb chain should propagate X through AND then OR correctly"
);
}
fn test_four_state_ff_capture_and_reset(sim) {
@ignore_on(veryl, sv);
@setup {
let code = r#"
module Top (
clk: input clock,
rst: input reset,
d: input logic<8>,
q: output logic<8>
) {
always_ff {
if_reset {
q = 8'd0;
} else {
q = d;
}
}
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let clk = sim.event("clk");
let id_rst = sim.signal("rst");
let id_d = sim.signal("d");
let id_q = sim.signal("q");
sim.modify(|io| {
io.set_four_state(id_rst, BigUint::from(0u32), BigUint::from(0u32));
io.set_four_state(id_d, BigUint::from(0u32), BigUint::from(0xFFu32));
io.set_four_state(id_q, BigUint::from(0u32), BigUint::from(0u32));
})
.unwrap();
sim.tick(clk).unwrap();
let (v_q, m_q) = sim.get_four_state(id_q);
assert_eq!(v_q, BigUint::from(0u32), "After reset, q value should be 0");
assert_eq!(
m_q,
BigUint::from(0u32),
"After reset, q mask should be 0 (constant reset value)"
);
sim.modify(|io| {
io.set_four_state(id_rst, BigUint::from(1u32), BigUint::from(0u32));
io.set_four_state(id_d, BigUint::from(0xA5u32), BigUint::from(0x0Fu32));
})
.unwrap();
sim.tick(clk).unwrap();
let (_v_q, m_q) = sim.get_four_state(id_q);
assert_eq!(
m_q,
BigUint::from(0x0Fu32),
"FF should capture X mask from d"
);
sim.modify(|io| {
io.set_four_state(id_rst, BigUint::from(0u32), BigUint::from(0u32));
})
.unwrap();
sim.tick(clk).unwrap();
let (v_q, m_q) = sim.get_four_state(id_q);
assert_eq!(v_q, BigUint::from(0u32));
assert_eq!(m_q, BigUint::from(0u32), "Reset should clear X mask in FF");
}
fn test_four_state_all_defined(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
b: input logic<8>,
y_add: output logic<8>,
y_and: output logic<8>,
y_xor: output logic<8>
) {
assign y_add = a + b;
assign y_and = a & b;
assign y_xor = a ^ b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y_add = sim.signal("y_add");
let id_y_and = sim.signal("y_and");
let id_y_xor = sim.signal("y_xor");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0xA5u32), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(0x5Au32), BigUint::from(0u32));
})
.unwrap();
let (v_add, m_add) = sim.get_four_state(id_y_add);
assert_eq!(v_add, BigUint::from(0xFFu32));
assert_eq!(
m_add,
BigUint::from(0u32),
"All defined: add mask should be 0"
);
let (v_and, m_and) = sim.get_four_state(id_y_and);
assert_eq!(v_and, BigUint::from(0x00u32));
assert_eq!(
m_and,
BigUint::from(0u32),
"All defined: and mask should be 0"
);
let (v_xor, m_xor) = sim.get_four_state(id_y_xor);
assert_eq!(v_xor, BigUint::from(0xFFu32));
assert_eq!(
m_xor,
BigUint::from(0u32),
"All defined: xor mask should be 0"
);
}
fn test_four_state_wide_128bit_simple(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<128>,
b: input logic<128>,
y: output logic<128>
) {
assign y = a & b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y");
let val_a: BigUint = (BigUint::from(0x12345678u32) << 64) | BigUint::from(0x9abcdef0u32);
let val_b: BigUint = (BigUint::from(0xFFFFFFFFu32) << 64) | BigUint::from(0u32);
let mask_zero = BigUint::from(0u32);
sim.modify(|io| {
io.set_four_state(id_a, val_a.clone(), mask_zero.clone());
io.set_four_state(id_b, val_b.clone(), mask_zero.clone());
})
.unwrap();
let (v_y, m_y) = sim.get_four_state(id_y);
let expected_v = val_a & val_b;
assert_eq!(v_y, expected_v, "128-bit simple AND value");
assert_eq!(
m_y,
BigUint::from(0u32),
"128-bit simple AND mask should be 0"
);
}
fn test_four_state_wide_shifts(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<128>,
sh: input logic<8>,
y_shr: output logic<128>,
y_shl: output logic<128>
) {
assign y_shr = a >> sh;
assign y_shl = a << sh;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_sh = sim.signal("sh");
let id_y_shr = sim.signal("y_shr");
let val_a: BigUint = (BigUint::from(0xAAu64) << 64) | BigUint::from(0x55u64);
let mask_a: BigUint = BigUint::from(0xFFu64) << 64; sim.modify(|io| {
io.set_four_state(id_a, val_a.clone(), mask_a.clone());
io.set_four_state(id_sh, BigUint::from(0u32), BigUint::from(0u32));
})
.unwrap();
let (v_shr, m_shr) = sim.get_four_state(id_y_shr);
let raw_shr = (BigUint::from(0xAAu64) << 64) | BigUint::from(0x55u64);
assert_eq!(v_shr, raw_shr | &m_shr);
assert_eq!(m_shr, mask_a);
sim.modify(|io| {
io.set_four_state(id_sh, BigUint::from(64u32), BigUint::from(0u32));
})
.unwrap();
let (v_shr, m_shr) = sim.get_four_state(id_y_shr);
assert_eq!(v_shr, BigUint::from(0xFFu64));
assert_eq!(m_shr, BigUint::from(0xFFu64));
sim.modify(|io| {
io.set_four_state(id_sh, BigUint::from(1u32), BigUint::from(1u32));
})
.unwrap();
let (_, m_shr) = sim.get_four_state(id_y_shr);
let all_x = (BigUint::from(u64::MAX) << 64) | BigUint::from(u64::MAX);
assert_eq!(m_shr, all_x, "Shift by X should result in all-X mask");
}
fn test_four_state_wide_arith(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<128>,
b: input logic<128>,
y_add: output logic<128>,
y_sub: output logic<128>
) {
assign y_add = a + b;
assign y_sub = a - b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y_add = sim.signal("y_add");
let val_a = BigUint::from(1u32);
let mask_a = BigUint::from(u64::MAX) << 64;
let val_b = BigUint::from(1u32);
let mask_b = BigUint::from(0u32);
sim.modify(|io| {
io.set_four_state(id_a, val_a, mask_a);
io.set_four_state(id_b, val_b, mask_b);
})
.unwrap();
let (_, m_add) = sim.get_four_state(id_y_add);
let all_x = (BigUint::from(u64::MAX) << 64) | BigUint::from(u64::MAX);
assert_eq!(
m_add, all_x,
"Arithmetic with partial X should result in all-X for multi-word"
);
}
fn test_four_state_wide_signed(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input signed logic<128>,
b: input signed logic<128>,
y_sar: output signed logic<128>,
y_lts: output logic
) {
assign y_sar = a >>> 64;
assign y_lts = a <: b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y_sar = sim.signal("y_sar");
let id_y_lts = sim.signal("y_lts");
let val_a = (BigUint::from(u64::MAX) << 64) | BigUint::from(u64::MAX);
let mask_a = BigUint::from(u64::MAX) << 64;
sim.modify(|io| {
io.set_four_state(id_a, val_a, mask_a);
})
.unwrap();
let (_, m_sar) = sim.get_four_state(id_y_sar);
let expected_m_sar = (BigUint::from(u64::MAX) << 64) | BigUint::from(u64::MAX);
assert_eq!(
m_sar, expected_m_sar,
"SAR sign extension should propagate X"
);
let val_b = BigUint::from(0u32);
let mask_b = BigUint::from(0u32);
sim.modify(|io| {
io.set_four_state(id_b, val_b, mask_b);
})
.unwrap();
let (_, m_lts) = sim.get_four_state(id_y_lts);
assert_eq!(
m_lts,
BigUint::from(1u32),
"Comparison with X should result in X (conservative)"
);
}
fn test_four_state_wide_concat_mixed(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<64>,
b: input bit<64>,
y_concat: output logic<128>
) {
assign y_concat = {a, b}; // a (4-state) high, b (2-state) low
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y_concat = sim.signal("y_concat");
let val_a = BigUint::from(0xAAu64);
let mask_a = BigUint::from(0xFFu64);
let val_b = BigUint::from(0x55u64);
sim.modify(|io| {
io.set_four_state(id_a, val_a, mask_a);
io.set_wide(id_b, val_b);
})
.unwrap();
let (v_c, m_c) = sim.get_four_state(id_y_concat);
let expected_m = BigUint::from(0xFFu64) << 64;
let expected_v = (BigUint::from(0xAAu64) << 64) | BigUint::from(0x55u64);
assert_eq!(v_c, expected_v);
assert_eq!(m_c, expected_m);
}
fn test_four_state_mul_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
b: input logic<8>,
y_mul: output logic<8>
) {
assign y_mul = a * b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y_mul");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(3u32), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(7u32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(v, BigUint::from(21u32), "3 * 7 = 21");
assert_eq!(m, BigUint::from(0u32), "No X when both defined");
sim.modify(|io| {
io.set_four_state(id_b, BigUint::from(0u32), BigUint::from(1u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0xFFu32),
"MUL with X should yield all-X mask"
);
assert_eq!(
v,
BigUint::from(0xFFu32),
"Value normalized at X positions (v |= m)"
);
}
fn test_four_state_div_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
b: input logic<8>,
y_div: output logic<8>
) {
assign y_div = a / b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y_div");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(20u32), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(4u32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(v, BigUint::from(5u32), "20 / 4 = 5");
assert_eq!(m, BigUint::from(0u32));
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0u32), BigUint::from(0x80u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0xFFu32),
"DIV with X dividend should yield all-X"
);
assert_eq!(
v,
BigUint::from(0xFFu32),
"Value normalized at X positions (v |= m)"
);
}
fn test_four_state_mod_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
b: input logic<8>,
y_mod: output logic<8>
) {
assign y_mod = a % b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y_mod");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(17u32), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(5u32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(v, BigUint::from(2u32), "17 % 5 = 2");
assert_eq!(m, BigUint::from(0u32));
sim.modify(|io| {
io.set_four_state(id_b, BigUint::from(0u32), BigUint::from(1u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0xFFu32),
"MOD with X divisor should yield all-X"
);
assert_eq!(
v,
BigUint::from(0xFFu32),
"Value normalized at X positions (v |= m)"
);
}
fn test_four_state_ne_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
b: input logic<8>,
y_ne: output logic
) {
assign y_ne = a != b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y_ne");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(10u32), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(20u32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(v, BigUint::from(1u32), "10 != 20 should be true");
assert_eq!(m, BigUint::from(0u32));
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0u32), BigUint::from(1u32));
})
.unwrap();
let (_, m) = sim.get_four_state(id_y);
assert_eq!(m, BigUint::from(1u32), "NE with X should yield X result");
}
fn test_four_state_gt_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
b: input logic<8>,
y_gt: output logic
) {
assign y_gt = a >: b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y_gt");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(20u32), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(10u32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(v, BigUint::from(1u32), "20 > 10 should be true");
assert_eq!(m, BigUint::from(0u32));
sim.modify(|io| {
io.set_four_state(id_b, BigUint::from(0u32), BigUint::from(1u32));
})
.unwrap();
let (_, m) = sim.get_four_state(id_y);
assert_eq!(m, BigUint::from(1u32), "GT with X should yield X result");
}
fn test_four_state_ge_le_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
b: input logic<8>,
y_ge: output logic,
y_le: output logic
) {
assign y_ge = a >= b;
assign y_le = a <= b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y_ge = sim.signal("y_ge");
let id_y_le = sim.signal("y_le");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(10u32), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(10u32), BigUint::from(0u32));
})
.unwrap();
let (v_ge, m_ge) = sim.get_four_state(id_y_ge);
let (v_le, m_le) = sim.get_four_state(id_y_le);
assert_eq!(v_ge, BigUint::from(1u32), "10 >= 10");
assert_eq!(m_ge, BigUint::from(0u32));
assert_eq!(v_le, BigUint::from(1u32), "10 <= 10");
assert_eq!(m_le, BigUint::from(0u32));
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0u32), BigUint::from(1u32));
})
.unwrap();
let (_, m_ge) = sim.get_four_state(id_y_ge);
let (_, m_le) = sim.get_four_state(id_y_le);
assert_eq!(m_ge, BigUint::from(1u32), "GE with X should yield X");
assert_eq!(m_le, BigUint::from(1u32), "LE with X should yield X");
}
fn test_four_state_signed_comparison_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input signed logic<8>,
b: input signed logic<8>,
y_lt_s: output logic,
y_gt_s: output logic,
y_le_s: output logic,
y_ge_s: output logic
) {
assign y_lt_s = a <: b;
assign y_gt_s = a >: b;
assign y_le_s = a <= b;
assign y_ge_s = a >= b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_lt = sim.signal("y_lt_s");
let id_gt = sim.signal("y_gt_s");
let id_le = sim.signal("y_le_s");
let id_ge = sim.signal("y_ge_s");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0xFFu32), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(1u32), BigUint::from(0u32));
})
.unwrap();
let (v_lt, m_lt) = sim.get_four_state(id_lt);
let (v_gt, m_gt) = sim.get_four_state(id_gt);
assert_eq!(v_lt, BigUint::from(1u32), "signed: -1 < 1 should be true");
assert_eq!(m_lt, BigUint::from(0u32));
assert_eq!(v_gt, BigUint::from(0u32), "signed: -1 > 1 should be false");
assert_eq!(m_gt, BigUint::from(0u32));
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0u32), BigUint::from(1u32));
})
.unwrap();
let (_, m_lt) = sim.get_four_state(id_lt);
let (_, m_gt) = sim.get_four_state(id_gt);
let (_, m_le) = sim.get_four_state(id_le);
let (_, m_ge) = sim.get_four_state(id_ge);
assert_eq!(m_lt, BigUint::from(1u32), "Signed LT with X should yield X");
assert_eq!(m_gt, BigUint::from(1u32), "Signed GT with X should yield X");
assert_eq!(m_le, BigUint::from(1u32), "Signed LE with X should yield X");
assert_eq!(m_ge, BigUint::from(1u32), "Signed GE with X should yield X");
}
fn test_four_state_reduction_xor_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
y_rxor: output logic
) {
assign y_rxor = ^a;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_y = sim.signal("y_rxor");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0xA5u32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(m, BigUint::from(0u32), "No X when all bits defined");
assert_eq!(v, BigUint::from(0u32), "^0xA5 = 0 (even parity)");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0xA5u32), BigUint::from(1u32));
})
.unwrap();
let (_, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(1u32),
"Reduction XOR with any X bit should yield X"
);
}
fn test_four_state_65bit_boundary(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<65>,
b: input logic<65>,
y_and: output logic<65>,
y_add: output logic<65>
) {
assign y_and = a & b;
assign y_add = a + b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y_and = sim.signal("y_and");
let id_y_add = sim.signal("y_add");
let val_a = BigUint::from(1u64) << 64 | BigUint::from(0xFFu64);
let mask_a: BigUint = BigUint::from(1u64) << 64; let val_b = BigUint::from(1u64) << 64 | BigUint::from(0x0Fu64);
sim.modify(|io| {
io.set_four_state(id_a, val_a, mask_a.clone());
io.set_four_state(id_b, val_b, BigUint::from(0u32));
})
.unwrap();
let (v_and, m_and) = sim.get_four_state(id_y_and);
assert_eq!(
m_and,
BigUint::from(1u64) << 64,
"AND: X bit should propagate at bit 64"
);
assert_eq!(v_and, (BigUint::from(1u64) << 64) | BigUint::from(0x0Fu64));
let (v_add, m_add) = sim.get_four_state(id_y_add);
let all_x_65 = (BigUint::from(1u64) << 65) - BigUint::from(1u64);
assert_eq!(
m_add, all_x_65,
"ADD with X should yield all-X mask for 65 bits"
);
assert_eq!(v_add, m_add.clone());
}
fn test_four_state_negation_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
y_neg: output logic<8>
) {
assign y_neg = -a;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_y = sim.signal("y_neg");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(5u32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(v, BigUint::from(0xFBu32), "-5 = 0xFB in 8-bit");
assert_eq!(m, BigUint::from(0u32));
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0u32), BigUint::from(1u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0xFFu32),
"Negation with X should yield all-X"
);
assert_eq!(v, BigUint::from(0xFFu32));
}
fn test_four_state_logical_not_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
y_lnot: output logic
) {
assign y_lnot = !(|a);
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_y = sim.signal("y_lnot");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0x0Au32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(v, BigUint::from(0u32), "!nonzero = 0");
assert_eq!(m, BigUint::from(0u32));
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0u32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(v, BigUint::from(1u32), "!0 = 1");
assert_eq!(m, BigUint::from(0u32));
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0u32), BigUint::from(1u32));
})
.unwrap();
let (_, m) = sim.get_four_state(id_y);
assert_eq!(m, BigUint::from(1u32), "Logical NOT with X should yield X");
}
fn test_four_state_sar_x_shift_amount(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input signed logic<8>,
sh: input logic<8>,
y_sar: output signed logic<8>
) {
assign y_sar = a >>> sh;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_sh = sim.signal("sh");
let id_y = sim.signal("y_sar");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0x80u32), BigUint::from(0u32));
io.set_four_state(id_sh, BigUint::from(2u32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(v, BigUint::from(0xE0u32), "0x80 >>> 2 = 0xE0 (sign extend)");
assert_eq!(m, BigUint::from(0u32));
sim.modify(|io| {
io.set_four_state(id_sh, BigUint::from(1u32), BigUint::from(1u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0xFFu32),
"SAR by X amount should yield all-X"
);
assert_eq!(v, BigUint::from(0xFFu32));
}
fn test_four_state_concat_three_elements(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<4>,
b: input logic<4>,
c: input logic<4>,
y: output logic<12>
) {
assign y = {a, b, c};
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_c = sim.signal("c");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0xAu32), BigUint::from(0xFu32)); io.set_four_state(id_b, BigUint::from(0x5u32), BigUint::from(0u32)); io.set_four_state(id_c, BigUint::from(0x3u32), BigUint::from(0u32)); })
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(m, BigUint::from(0xF00u32), "Only high nibble should be X");
assert_eq!(
v,
BigUint::from(0xA53u32),
"Defined parts: b=5, c=3; X positions preserve input value"
);
}
fn test_four_state_wide_comparison_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<128>,
b: input logic<128>,
y_eq: output logic,
y_lt: output logic
) {
assign y_eq = a == b;
assign y_lt = a <: b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y_eq = sim.signal("y_eq");
let id_y_lt = sim.signal("y_lt");
let val: BigUint = (BigUint::from(0xAAu64) << 64) | BigUint::from(0x55u64);
sim.modify(|io| {
io.set_four_state(id_a, val.clone(), BigUint::from(0u32));
io.set_four_state(id_b, val.clone(), BigUint::from(0u32));
})
.unwrap();
let (v_eq, m_eq) = sim.get_four_state(id_y_eq);
assert_eq!(v_eq, BigUint::from(1u32), "Equal values should be EQ=1");
assert_eq!(m_eq, BigUint::from(0u32));
let mask_a = BigUint::from(0xFFu64) << 64;
sim.modify(|io| {
io.set_four_state(id_a, val.clone(), mask_a);
})
.unwrap();
let (_, m_eq) = sim.get_four_state(id_y_eq);
let (_, m_lt) = sim.get_four_state(id_y_lt);
assert_eq!(m_eq, BigUint::from(1u32), "Wide EQ with X should yield X");
assert_eq!(m_lt, BigUint::from(1u32), "Wide LT with X should yield X");
}
fn test_four_state_multibit_mux_with_x(sim) {
@ignore_on(veryl, sv);
@setup {
let code = r#"
module Top (
sel: input logic<2>,
a: input logic<8>,
b: input logic<8>,
c: input logic<8>,
y: output logic<8>
) {
always_comb {
if sel == 2'd0 {
y = a;
} else if sel == 2'd1 {
y = b;
} else {
y = c;
}
}
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_sel = sim.signal("sel");
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_c = sim.signal("c");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0xAAu32), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(0xBBu32), BigUint::from(0u32));
io.set_four_state(id_c, BigUint::from(0xCCu32), BigUint::from(0u32));
})
.unwrap();
sim.modify(|io| {
io.set_four_state(id_sel, BigUint::from(0u32), BigUint::from(1u32)); })
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(m, BigUint::from(0u32));
assert_eq!(v, BigUint::from(0xCCu32));
}
fn test_four_state_procedural_case_x_uses_default(sim) {
@ignore_on(veryl, sv);
@setup {
let code = r#"
module Top (
sel: input logic<2>,
y: output logic<8>
) {
always_comb {
case sel {
2'd0: y = 8'd10;
2'd1: y = 8'd20;
default: y = 8'd99;
}
}
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let sel = sim.signal("sel");
let y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(sel, BigUint::from(1u32), BigUint::from(1u32));
})
.unwrap();
let (value, mask) = sim.get_four_state(y);
assert_eq!(mask, BigUint::from(0u32));
assert_eq!(value, BigUint::from(99u32));
}
fn test_four_state_procedural_if_known_nonzero_with_x_is_true(sim) {
@ignore_on(veryl, sv);
@setup {
let code = r#"
module Top (
cond: input logic<2>,
y: output logic<8>
) {
always_comb {
if cond {
y = 8'hA5;
} else {
y = 8'h5A;
}
}
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let cond = sim.signal("cond");
let y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(cond, BigUint::from(2u32), BigUint::from(1u32));
})
.unwrap();
let (value, mask) = sim.get_four_state(y);
assert_eq!(mask, BigUint::from(0u32));
assert_eq!(value, BigUint::from(0xA5u32));
}
fn test_four_state_width_narrowing_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<16>,
y: output logic<8>
) {
assign y = a[7:0];
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0x12ABu32), BigUint::from(0xFF00u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(v, BigUint::from(0xABu32), "Lower byte should be 0xAB");
assert_eq!(m, BigUint::from(0u32), "Lower byte should have no X");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0x1200u32), BigUint::from(0x000Fu32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(m, BigUint::from(0x0Fu32), "Lower nibble X should propagate");
assert_eq!(v, BigUint::from(0u32), "X bits normalized to 0");
}
fn test_four_state_width_widening_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
y: output logic<16>
) {
assign y = a;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0xA5u32), BigUint::from(0x0Fu32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0x0Fu32),
"Only lower nibble X should propagate"
);
assert_eq!(
v,
BigUint::from(0xA5u32),
"Widening preserves input value at X positions"
);
}
fn test_four_state_ff_conditional_with_x(sim) {
@ignore_on(veryl, sv);
@setup {
let code = r#"
module Top (
clk: input clock,
rst: input reset,
en: input logic,
d: input logic<8>,
q: output logic<8>
) {
always_ff {
if_reset {
q = 8'd0;
} else if en {
q = d;
}
}
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let clk = sim.event("clk");
let id_rst = sim.signal("rst");
let id_en = sim.signal("en");
let id_d = sim.signal("d");
let id_q = sim.signal("q");
sim.modify(|io| {
io.set_four_state(id_rst, BigUint::from(0u32), BigUint::from(0u32));
io.set_four_state(id_en, BigUint::from(0u32), BigUint::from(0u32));
io.set_four_state(id_d, BigUint::from(0u32), BigUint::from(0u32));
io.set_four_state(id_q, BigUint::from(0u32), BigUint::from(0u32));
})
.unwrap();
sim.tick(clk).unwrap();
let (v_q, m_q) = sim.get_four_state(id_q);
assert_eq!(v_q, BigUint::from(0u32));
assert_eq!(m_q, BigUint::from(0u32), "Reset should clear X");
sim.modify(|io| {
io.set_four_state(id_rst, BigUint::from(1u32), BigUint::from(0u32));
io.set_four_state(id_en, BigUint::from(1u32), BigUint::from(0u32));
io.set_four_state(id_d, BigUint::from(0xABu32), BigUint::from(0x0Fu32));
})
.unwrap();
sim.tick(clk).unwrap();
let (_, m_q) = sim.get_four_state(id_q);
assert_eq!(
m_q,
BigUint::from(0x0Fu32),
"en=1: X from d should propagate to q"
);
sim.modify(|io| {
io.set_four_state(id_en, BigUint::from(0u32), BigUint::from(0u32));
io.set_four_state(id_d, BigUint::from(0xFFu32), BigUint::from(0u32));
})
.unwrap();
sim.tick(clk).unwrap();
let (_, m_q) = sim.get_four_state(id_q);
assert_eq!(
m_q,
BigUint::from(0x0Fu32),
"en=0: q should hold previous X mask"
);
}
fn test_four_state_concat_odd_width(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<3>,
b: input logic<5>,
y: output logic<8>
) {
assign y = {a, b};
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0x5u32), BigUint::from(0b010u32));
io.set_four_state(id_b, BigUint::from(0x13u32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(m, BigUint::from(0x40u32), "X in a[1] should appear at y[6]");
assert_eq!(
v,
BigUint::from(0xB3u32),
"Concat preserves input value at X positions"
);
}
fn test_four_state_127bit(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<127>,
b: input logic<127>,
y_and: output logic<127>
) {
assign y_and = a & b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y_and");
let val_a: BigUint = (BigUint::from(1u64) << 126) | BigUint::from(0xFFu64);
let mask_a: BigUint = BigUint::from(1u64) << 126;
let val_b: BigUint = (BigUint::from(u64::MAX) << 63) | BigUint::from(u64::MAX);
sim.modify(|io| {
io.set_four_state(id_a, val_a, mask_a.clone());
io.set_four_state(id_b, val_b, BigUint::from(0u32));
})
.unwrap();
let (_, m) = sim.get_four_state(id_y);
assert_eq!(m, mask_a, "127-bit AND: X at MSB should propagate");
}
fn test_four_state_wide_unary_not_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<128>,
y: output logic<128>
) {
assign y = ~a;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_y = sim.signal("y");
let val_a: BigUint = (BigUint::from(0xAAu64) << 64) | BigUint::from(u64::MAX);
let mask_a: BigUint = BigUint::from(0xFFu64) << 64;
sim.modify(|io| {
io.set_four_state(id_a, val_a, mask_a.clone());
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(m, mask_a, "Wide NOT should preserve mask");
assert_eq!(
v & BigUint::from(u64::MAX),
BigUint::from(0u64),
"Lower word: ~0xFFFFFFFFFFFFFFFF = 0"
);
}
fn test_four_state_wide_negation_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<128>,
y: output logic<128>
) {
assign y = -a;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_y = sim.signal("y");
let mask_a: BigUint = BigUint::from(1u64) << 64;
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(5u32), mask_a);
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
let all_x: BigUint = (BigUint::from(u64::MAX) << 64) | BigUint::from(u64::MAX);
assert_eq!(m, all_x, "Wide negation with X should yield all-X");
assert_eq!(v, all_x);
}
fn test_four_state_wide_reduction_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<128>,
y_rand: output logic,
y_ror: output logic,
y_rxor: output logic
) {
assign y_rand = &a;
assign y_ror = |a;
assign y_rxor = ^a;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_rand = sim.signal("y_rand");
let id_ror = sim.signal("y_ror");
let id_rxor = sim.signal("y_rxor");
let val_a: BigUint = (BigUint::from(0xAAu64) << 64) | BigUint::from(u64::MAX);
let mask_a: BigUint = BigUint::from(0xFFu64) << 64;
sim.modify(|io| {
io.set_four_state(id_a, val_a, mask_a);
})
.unwrap();
let (_, m_rand) = sim.get_four_state(id_rand);
assert_eq!(
m_rand,
BigUint::from(0u32),
"Wide &a with definite 0 bits should be defined (dominant-value)"
);
let (_, m_ror) = sim.get_four_state(id_ror);
assert_eq!(
m_ror,
BigUint::from(0u32),
"Wide |a with definite 1 bits should be defined (dominant-value)"
);
let (_, m_rxor) = sim.get_four_state(id_rxor);
assert_eq!(
m_rxor,
BigUint::from(1u32),
"Wide ^a with any X should be X"
);
}
fn test_four_state_mux_both_branches_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
sel: input logic,
a: input logic<8>,
b: input logic<8>,
y: output logic<8>
) {
assign y = if sel ? a : b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_sel = sim.signal("sel");
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_sel, BigUint::from(1u32), BigUint::from(0u32));
io.set_four_state(id_a, BigUint::from(0xFFu32), BigUint::from(0xFFu32));
io.set_four_state(id_b, BigUint::from(0xFFu32), BigUint::from(0xFFu32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0xFFu32),
"sel=1 selecting X branch → all-X"
);
assert_eq!(
v,
BigUint::from(0xFFu32),
"X encoding: v=1, m=1"
);
sim.modify(|io| {
io.set_four_state(id_sel, BigUint::from(0u32), BigUint::from(0u32));
})
.unwrap();
let (_, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0xFFu32),
"sel=0 selecting X branch → all-X"
);
sim.modify(|io| {
io.set_four_state(id_sel, BigUint::from(0u32), BigUint::from(1u32));
})
.unwrap();
let (_, m) = sim.get_four_state(id_y);
assert_eq!(m, BigUint::from(0xFFu32), "sel=X, both branches X → all-X");
}
fn test_four_state_cascaded_mux_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
sel1: input logic,
sel2: input logic,
a: input logic<8>,
b: input logic<8>,
c: input logic<8>,
y: output logic<8>
) {
assign y = if sel1 ? (if sel2 ? a : b) : c;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_sel1 = sim.signal("sel1");
let id_sel2 = sim.signal("sel2");
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_c = sim.signal("c");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0xAAu32), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(0xBBu32), BigUint::from(0u32));
io.set_four_state(id_c, BigUint::from(0xCCu32), BigUint::from(0u32));
})
.unwrap();
sim.modify(|io| {
io.set_four_state(id_sel1, BigUint::from(1u32), BigUint::from(0u32));
io.set_four_state(id_sel2, BigUint::from(1u32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(v, BigUint::from(0xAAu32), "sel1=1,sel2=1 → a");
assert_eq!(m, BigUint::from(0u32));
sim.modify(|io| {
io.set_four_state(id_sel2, BigUint::from(0u32), BigUint::from(1u32));
})
.unwrap();
let (_, m) = sim.get_four_state(id_y);
assert_ne!(
m,
BigUint::from(0u32),
"sel1=1,sel2=X → inner mux X propagates"
);
sim.modify(|io| {
io.set_four_state(id_sel1, BigUint::from(0u32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(v, BigUint::from(0xCCu32), "sel1=0 → c regardless of sel2");
assert_eq!(m, BigUint::from(0u32));
}
fn test_four_state_shift_both_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
sh: input logic<8>,
y: output logic<8>
) {
assign y = a >> sh;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_sh = sim.signal("sh");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0xFFu32), BigUint::from(0x0Fu32));
io.set_four_state(id_sh, BigUint::from(3u32), BigUint::from(1u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0xFFu32),
"Shift with X in both data and amount → all-X"
);
assert_eq!(v, BigUint::from(0xFFu32));
}
fn test_four_state_case_defined_selector(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
sel: input logic<2>,
y: output logic<8>
) {
assign y = case sel {
2'd0: 8'd10,
2'd1: 8'd20,
2'd2: 8'd30,
default: 8'd99,
};
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_sel = sim.signal("sel");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_sel, BigUint::from(1u32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0u32),
"Defined selector should produce defined result"
);
assert_eq!(v, BigUint::from(20u32), "sel=1 should select value 20");
}
fn test_four_state_case_x_in_selector(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
sel: input logic<2>,
y: output logic<8>
) {
assign y = case sel {
2'd0: 8'd10,
2'd1: 8'd20,
default: 8'd99,
};
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_sel = sim.signal("sel");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_sel, BigUint::from(1u32), BigUint::from(1u32)); })
.unwrap();
let (_, m) = sim.get_four_state(id_y);
assert_ne!(
m,
BigUint::from(0u32),
"Case with X selector should produce X in output (conservative mux)"
);
}
fn test_four_state_reduction_or_dominant_one(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
y: output logic
) {
assign y = |a;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0x01u32), BigUint::from(0xF0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0u32),
"Reduction OR with definite 1 should yield defined result"
);
assert_eq!(
v,
BigUint::from(1u32),
"Reduction OR with definite 1 should yield 1"
);
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0x00u32), BigUint::from(0x0Fu32));
})
.unwrap();
let (_, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(1u32),
"Reduction OR with no definite 1 but X bits should yield X"
);
}
fn test_four_state_reduction_and_dominant_zero(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
y: output logic
) {
assign y = &a;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0x0Eu32), BigUint::from(0xF0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0u32),
"Reduction AND with definite 0 should yield defined result"
);
assert_eq!(
v,
BigUint::from(0u32),
"Reduction AND with definite 0 should yield 0"
);
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0xF0u32), BigUint::from(0x0Fu32));
})
.unwrap();
let (_, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(1u32),
"Reduction AND with no definite 0 but X bits should yield X"
);
}
fn test_four_state_wide_reduction_or_dominant(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<128>,
y: output logic
) {
assign y = |a;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_y = sim.signal("y");
let val = BigUint::from(1u32); let mask = BigUint::from(0u32) | (BigUint::from(u64::MAX) << 64); sim.modify(|io| {
io.set_four_state(id_a, val, mask);
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0u32),
"Wide reduction OR: definite 1 in any chunk → defined result"
);
assert_eq!(
v,
BigUint::from(1u32),
"Wide reduction OR: definite 1 in any chunk → 1"
);
}
fn test_four_state_wide_reduction_and_dominant(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<128>,
y: output logic
) {
assign y = &a;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_y = sim.signal("y");
let val = BigUint::from(0xFFFFFFFFFFFFFFFEu64); let mask = BigUint::from(0u32) | (BigUint::from(u64::MAX) << 64); sim.modify(|io| {
io.set_four_state(id_a, val, mask);
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0u32),
"Wide reduction AND: definite 0 in any chunk → defined result"
);
assert_eq!(
v,
BigUint::from(0u32),
"Wide reduction AND: definite 0 in any chunk → 0"
);
}
fn test_four_state_logic_and_dominant_zero(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
b: input logic<8>,
y: output logic
) {
assign y = (|a) && (|b);
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0u32), BigUint::from(0u32)); io.set_four_state(id_b, BigUint::from(0u32), BigUint::from(0xFFu32)); })
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(m, BigUint::from(0u32), "0 && X should be definite (mask=0)");
assert_eq!(v, BigUint::from(0u32), "0 && X = 0");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0u32), BigUint::from(0xFFu32)); io.set_four_state(id_b, BigUint::from(0u32), BigUint::from(0u32)); })
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(m, BigUint::from(0u32), "X && 0 should be definite (mask=0)");
assert_eq!(v, BigUint::from(0u32), "X && 0 = 0");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(1u32), BigUint::from(0u32)); io.set_four_state(id_b, BigUint::from(0u32), BigUint::from(0xFFu32)); })
.unwrap();
let (_, m) = sim.get_four_state(id_y);
assert_ne!(m, BigUint::from(0u32), "1 && X should be X (mask!=0)");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0u32), BigUint::from(0xFFu32)); io.set_four_state(id_b, BigUint::from(1u32), BigUint::from(0u32)); })
.unwrap();
let (_, m) = sim.get_four_state(id_y);
assert_ne!(m, BigUint::from(0u32), "X && 1 should be X (mask!=0)");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(1u32), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(1u32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(m, BigUint::from(0u32), "1 && 1 should be definite");
assert_eq!(v, BigUint::from(1u32), "1 && 1 = 1");
}
fn test_four_state_logic_or_dominant_one(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<8>,
b: input logic<8>,
y: output logic
) {
assign y = (|a) || (|b);
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(1u32), BigUint::from(0u32)); io.set_four_state(id_b, BigUint::from(0u32), BigUint::from(0xFFu32)); })
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(m, BigUint::from(0u32), "1 || X should be definite (mask=0)");
assert_eq!(v, BigUint::from(1u32), "1 || X = 1");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0u32), BigUint::from(0xFFu32)); io.set_four_state(id_b, BigUint::from(1u32), BigUint::from(0u32)); })
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(m, BigUint::from(0u32), "X || 1 should be definite (mask=0)");
assert_eq!(v, BigUint::from(1u32), "X || 1 = 1");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0u32), BigUint::from(0u32)); io.set_four_state(id_b, BigUint::from(0u32), BigUint::from(0xFFu32)); })
.unwrap();
let (_, m) = sim.get_four_state(id_y);
assert_ne!(m, BigUint::from(0u32), "0 || X should be X (mask!=0)");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0u32), BigUint::from(0xFFu32)); io.set_four_state(id_b, BigUint::from(0u32), BigUint::from(0u32)); })
.unwrap();
let (_, m) = sim.get_four_state(id_y);
assert_ne!(m, BigUint::from(0u32), "X || 0 should be X (mask!=0)");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0u32), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(0u32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(m, BigUint::from(0u32), "0 || 0 should be definite");
assert_eq!(v, BigUint::from(0u32), "0 || 0 = 0");
}
fn test_four_state_eq_wildcard_value_at_wildcard_pos(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<4>,
b: input logic<4>,
y: output logic
) {
assign y = a ==? b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0b1110u32), BigUint::from(0u32)); io.set_four_state(id_b, BigUint::from(0b1010u32), BigUint::from(0b0101u32)); })
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0u32),
"==? with matching non-wildcard bits should be definite"
);
assert_eq!(
v,
BigUint::from(1u32),
"==? with matching non-wildcard bits should be 1"
);
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0b1100u32), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(0b1010u32), BigUint::from(0b0101u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0u32),
"==? with definite mismatch should be definite"
);
assert_eq!(
v,
BigUint::from(0u32),
"==? with mismatch at non-wildcard should be 0"
);
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0b0010u32), BigUint::from(0b1100u32)); io.set_four_state(id_b, BigUint::from(0b1010u32), BigUint::from(0b0101u32)); })
.unwrap();
let (_, m) = sim.get_four_state(id_y);
assert_ne!(
m,
BigUint::from(0u32),
"==? with LHS X at non-wildcard should be X"
);
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0b0000u32), BigUint::from(0b1100u32)); io.set_four_state(id_b, BigUint::from(0b1010u32), BigUint::from(0b0101u32)); })
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0u32),
"==? with definite mismatch should be definite even with X elsewhere"
);
assert_eq!(v, BigUint::from(0u32), "==? with definite mismatch = 0");
}
fn test_four_state_ne_wildcard_value_at_wildcard_pos(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<4>,
b: input logic<4>,
y: output logic
) {
assign y = a !=? b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0b1110u32), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(0b1010u32), BigUint::from(0b0101u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0u32),
"!=? with all matching should be definite"
);
assert_eq!(v, BigUint::from(0u32), "!=? with all matching = 0");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0b1100u32), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(0b1010u32), BigUint::from(0b0101u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0u32),
"!=? with definite mismatch should be definite"
);
assert_eq!(v, BigUint::from(1u32), "!=? with mismatch = 1");
}
fn test_four_state_wide_wildcard_equality(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<130>,
b: input logic<130>,
y_eq: output logic,
y_ne: output logic
) {
assign y_eq = a ==? b;
assign y_ne = a !=? b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y_eq = sim.signal("y_eq");
let id_y_ne = sim.signal("y_ne");
let bit_64 = BigUint::from(1u32) << 64usize;
let bit_65 = BigUint::from(1u32) << 65usize;
let bit_129 = BigUint::from(1u32) << 129usize;
let rhs_value = &bit_64 | &bit_129;
sim.modify(|io| {
io.set_four_state(id_a, &rhs_value | &bit_65, BigUint::from(0u32));
io.set_four_state(id_b, rhs_value.clone(), bit_65.clone());
})
.unwrap();
assert_eq!(
sim.get_four_state(id_y_eq),
(BigUint::from(1u32), BigUint::from(0u32))
);
assert_eq!(
sim.get_four_state(id_y_ne),
(BigUint::from(0u32), BigUint::from(0u32))
);
sim.modify(|io| {
io.set_four_state(id_a, rhs_value.clone(), bit_129.clone());
io.set_four_state(id_b, rhs_value.clone(), bit_65.clone());
})
.unwrap();
assert_eq!(
sim.get_four_state(id_y_eq),
(BigUint::from(1u32), BigUint::from(1u32))
);
assert_eq!(
sim.get_four_state(id_y_ne),
(BigUint::from(1u32), BigUint::from(1u32))
);
sim.modify(|io| {
io.set_four_state(id_a, bit_129.clone(), bit_129.clone());
io.set_four_state(id_b, rhs_value.clone(), bit_65.clone());
})
.unwrap();
assert_eq!(
sim.get_four_state(id_y_eq),
(BigUint::from(0u32), BigUint::from(0u32))
);
assert_eq!(
sim.get_four_state(id_y_ne),
(BigUint::from(1u32), BigUint::from(0u32))
);
}
fn test_four_state_wide_mul_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<128>,
b: input logic<128>,
y_mul: output logic<128>
) {
assign y_mul = a * b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y_mul");
let all_x_128 = (BigUint::from(u64::MAX) << 64) | BigUint::from(u64::MAX);
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(3u32), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(7u32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(v, BigUint::from(21u32), "Wide 3 * 7 = 21");
assert_eq!(m, BigUint::from(0u32), "No X when both defined");
let mask_a = BigUint::from(1u64) << 64;
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(3u32), mask_a);
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(m, all_x_128, "Wide MUL with X should yield all-X mask");
assert_eq!(v, all_x_128);
}
fn test_four_state_wide_div_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<128>,
b: input logic<128>,
y_div: output logic<128>
) {
assign y_div = a / b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y_div");
let all_x_128 = (BigUint::from(u64::MAX) << 64) | BigUint::from(u64::MAX);
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(20u32), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(4u32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(v, BigUint::from(5u32), "Wide 20 / 4 = 5");
assert_eq!(m, BigUint::from(0u32));
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0u32), BigUint::from(0x80u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(m, all_x_128, "Wide DIV with X dividend should yield all-X");
assert_eq!(v, all_x_128, "Operations produce X: v |= m");
}
fn test_four_state_wide_mod_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<128>,
b: input logic<128>,
y_mod: output logic<128>
) {
assign y_mod = a % b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y_mod");
let all_x_128 = (BigUint::from(u64::MAX) << 64) | BigUint::from(u64::MAX);
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(17u32), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(5u32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(v, BigUint::from(2u32), "Wide 17 % 5 = 2");
assert_eq!(m, BigUint::from(0u32));
sim.modify(|io| {
io.set_four_state(id_b, BigUint::from(1u32), BigUint::from(1u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(m, all_x_128, "Wide MOD with X divisor should yield all-X");
assert_eq!(v, all_x_128);
}
fn test_four_state_sar_both_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input signed logic<8>,
sh: input logic<8>,
y_sar: output signed logic<8>
) {
assign y_sar = a >>> sh;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_sh = sim.signal("sh");
let id_y = sim.signal("y_sar");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0x80u32), BigUint::from(0x0Fu32)); io.set_four_state(id_sh, BigUint::from(3u32), BigUint::from(1u32)); })
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0xFFu32),
"SAR with X in both data and shift amount → all-X"
);
assert_eq!(v, BigUint::from(0xFFu32));
}
fn test_four_state_wide_ne_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<128>,
b: input logic<128>,
y_ne: output logic
) {
assign y_ne = a != b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y_ne");
let val_a: BigUint = (BigUint::from(0xAAu64) << 64) | BigUint::from(0x55u64);
let val_b: BigUint = (BigUint::from(0xBBu64) << 64) | BigUint::from(0x55u64);
sim.modify(|io| {
io.set_four_state(id_a, val_a.clone(), BigUint::from(0u32));
io.set_four_state(id_b, val_b, BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(v, BigUint::from(1u32), "Different wide values → NE=1");
assert_eq!(m, BigUint::from(0u32));
sim.modify(|io| {
io.set_four_state(id_b, val_a.clone(), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(v, BigUint::from(0u32), "Same wide values → NE=0");
assert_eq!(m, BigUint::from(0u32));
let mask_a = BigUint::from(0xFFu64) << 64;
sim.modify(|io| {
io.set_four_state(id_a, val_a, mask_a);
})
.unwrap();
let (_, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(1u32),
"Wide NE with X should yield X result"
);
}
fn test_four_state_wide_gt_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<128>,
b: input logic<128>,
y_gt: output logic
) {
assign y_gt = a >: b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y = sim.signal("y_gt");
let val_a: BigUint = (BigUint::from(0xFFu64) << 64) | BigUint::from(0u64);
let val_b: BigUint = BigUint::from(0xFFu64);
sim.modify(|io| {
io.set_four_state(id_a, val_a.clone(), BigUint::from(0u32));
io.set_four_state(id_b, val_b, BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(v, BigUint::from(1u32), "Wide a > b should be true");
assert_eq!(m, BigUint::from(0u32));
let mask_a = BigUint::from(1u64) << 64;
sim.modify(|io| {
io.set_four_state(id_a, val_a, mask_a);
})
.unwrap();
let (_, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(1u32),
"Wide GT with X should yield X result"
);
}
fn test_four_state_wide_ge_le_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<128>,
b: input logic<128>,
y_ge: output logic,
y_le: output logic
) {
assign y_ge = a >= b;
assign y_le = a <= b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_y_ge = sim.signal("y_ge");
let id_y_le = sim.signal("y_le");
let val: BigUint = (BigUint::from(0xAAu64) << 64) | BigUint::from(0x55u64);
sim.modify(|io| {
io.set_four_state(id_a, val.clone(), BigUint::from(0u32));
io.set_four_state(id_b, val.clone(), BigUint::from(0u32));
})
.unwrap();
let (v_ge, m_ge) = sim.get_four_state(id_y_ge);
let (v_le, m_le) = sim.get_four_state(id_y_le);
assert_eq!(v_ge, BigUint::from(1u32), "Wide equal values → GE=1");
assert_eq!(m_ge, BigUint::from(0u32));
assert_eq!(v_le, BigUint::from(1u32), "Wide equal values → LE=1");
assert_eq!(m_le, BigUint::from(0u32));
let mask_a = BigUint::from(0xFFu64) << 64;
sim.modify(|io| {
io.set_four_state(id_a, val, mask_a);
})
.unwrap();
let (_, m_ge) = sim.get_four_state(id_y_ge);
let (_, m_le) = sim.get_four_state(id_y_le);
assert_eq!(m_ge, BigUint::from(1u32), "Wide GE with X should yield X");
assert_eq!(m_le, BigUint::from(1u32), "Wide LE with X should yield X");
}
fn test_four_state_wide_signed_comparison_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input signed logic<128>,
b: input signed logic<128>,
y_lt_s: output logic,
y_gt_s: output logic,
y_le_s: output logic,
y_ge_s: output logic
) {
assign y_lt_s = a <: b;
assign y_gt_s = a >: b;
assign y_le_s = a <= b;
assign y_ge_s = a >= b;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_lt = sim.signal("y_lt_s");
let id_gt = sim.signal("y_gt_s");
let id_le = sim.signal("y_le_s");
let id_ge = sim.signal("y_ge_s");
let all_ones_128 = (BigUint::from(u64::MAX) << 64) | BigUint::from(u64::MAX);
sim.modify(|io| {
io.set_four_state(id_a, all_ones_128, BigUint::from(0u32)); io.set_four_state(id_b, BigUint::from(1u32), BigUint::from(0u32));
})
.unwrap();
let (v_lt, m_lt) = sim.get_four_state(id_lt);
let (v_gt, m_gt) = sim.get_four_state(id_gt);
assert_eq!(
v_lt,
BigUint::from(1u32),
"Wide signed: -1 < 1 should be true"
);
assert_eq!(m_lt, BigUint::from(0u32));
assert_eq!(
v_gt,
BigUint::from(0u32),
"Wide signed: -1 > 1 should be false"
);
assert_eq!(m_gt, BigUint::from(0u32));
let mask_a = BigUint::from(1u64) << 64;
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0u32), mask_a);
})
.unwrap();
let (_, m_lt) = sim.get_four_state(id_lt);
let (_, m_gt) = sim.get_four_state(id_gt);
let (_, m_le) = sim.get_four_state(id_le);
let (_, m_ge) = sim.get_four_state(id_ge);
assert_eq!(
m_lt,
BigUint::from(1u32),
"Wide signed LT with X should yield X"
);
assert_eq!(
m_gt,
BigUint::from(1u32),
"Wide signed GT with X should yield X"
);
assert_eq!(
m_le,
BigUint::from(1u32),
"Wide signed LE with X should yield X"
);
assert_eq!(
m_ge,
BigUint::from(1u32),
"Wide signed GE with X should yield X"
);
}
fn test_four_state_wide_logical_not_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<128>,
y_lnot: output logic
) {
assign y_lnot = !(|a);
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_y = sim.signal("y_lnot");
let val: BigUint = BigUint::from(1u64) << 64;
sim.modify(|io| {
io.set_four_state(id_a, val, BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(v, BigUint::from(0u32), "Wide !nonzero = 0");
assert_eq!(m, BigUint::from(0u32));
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0u32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(v, BigUint::from(1u32), "Wide !0 = 1");
assert_eq!(m, BigUint::from(0u32));
let mask_a = BigUint::from(1u64) << 64;
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0u32), mask_a);
})
.unwrap();
let (_, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(1u32),
"Wide logical NOT with X should yield X"
);
}
fn test_four_state_concat_chunk_boundary_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input logic<48>,
b: input logic<32>,
c: input logic<48>,
y: output logic<128>
) {
assign y = {a, b, c};
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_b = sim.signal("b");
let id_c = sim.signal("c");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0x123456789ABCu64), BigUint::from(0u32));
io.set_four_state(id_b, BigUint::from(0u32), BigUint::from(0xFFFFFFFFu64)); io.set_four_state(id_c, BigUint::from(0xABCDEF012345u64), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
let expected_mask = BigUint::from(0xFFFFFFFFu64) << 48;
assert_eq!(
m, expected_mask,
"X in b should span bits [79:48] crossing chunk boundary"
);
let lower_48_mask = (BigUint::from(1u64) << 48) - BigUint::from(1u32);
let v_c = &v & &lower_48_mask;
assert_eq!(
v_c,
BigUint::from(0xABCDEF012345u64),
"Lower 48 bits from c should be intact"
);
let v_a = &v >> 80;
assert_eq!(
v_a,
BigUint::from(0x123456789ABCu64),
"Upper 48 bits from a should be intact"
);
}
fn test_four_state_ff_sync_reset_with_x(sim) {
@ignore_on(veryl, sv);
@setup {
let code = r#"
module Top (
clk: input clock,
rst: input reset,
sync_rst: input logic,
d: input logic<8>,
q: output logic<8>
) {
always_ff {
if_reset {
q = 8'd0;
} else {
if sync_rst {
q = 8'd0;
} else {
q = d;
}
}
}
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let clk = sim.event("clk");
let id_rst = sim.signal("rst");
let id_sync_rst = sim.signal("sync_rst");
let id_d = sim.signal("d");
let id_q = sim.signal("q");
sim.modify(|io| {
io.set_four_state(id_rst, BigUint::from(0u32), BigUint::from(0u32));
io.set_four_state(id_sync_rst, BigUint::from(0u32), BigUint::from(0u32));
io.set_four_state(id_d, BigUint::from(0u32), BigUint::from(0u32));
io.set_four_state(id_q, BigUint::from(0u32), BigUint::from(0u32));
})
.unwrap();
sim.tick(clk).unwrap();
let (v_q, m_q) = sim.get_four_state(id_q);
assert_eq!(v_q, BigUint::from(0u32));
assert_eq!(m_q, BigUint::from(0u32), "Async reset should clear X");
sim.modify(|io| {
io.set_four_state(id_rst, BigUint::from(1u32), BigUint::from(0u32));
io.set_four_state(id_sync_rst, BigUint::from(0u32), BigUint::from(0u32));
io.set_four_state(id_d, BigUint::from(0xABu32), BigUint::from(0x0Fu32)); })
.unwrap();
sim.tick(clk).unwrap();
let (_, m_q) = sim.get_four_state(id_q);
assert_eq!(m_q, BigUint::from(0x0Fu32), "q should capture X from d");
sim.modify(|io| {
io.set_four_state(id_sync_rst, BigUint::from(1u32), BigUint::from(0u32));
})
.unwrap();
sim.tick(clk).unwrap();
let (v_q, m_q) = sim.get_four_state(id_q);
assert_eq!(v_q, BigUint::from(0u32), "Sync reset should set q to 0");
assert_eq!(m_q, BigUint::from(0u32), "Sync reset should clear X in q");
sim.modify(|io| {
io.set_four_state(id_sync_rst, BigUint::from(0u32), BigUint::from(0u32));
io.set_four_state(id_d, BigUint::from(0u32), BigUint::from(0xFFu32)); })
.unwrap();
sim.tick(clk).unwrap();
let (_, m_q) = sim.get_four_state(id_q);
assert_eq!(m_q, BigUint::from(0xFFu32), "q should capture all-X from d");
sim.modify(|io| {
io.set_four_state(id_sync_rst, BigUint::from(1u32), BigUint::from(0u32));
})
.unwrap();
sim.tick(clk).unwrap();
let (v_q, m_q) = sim.get_four_state(id_q);
assert_eq!(
v_q,
BigUint::from(0u32),
"Second sync reset should set q to 0"
);
assert_eq!(
m_q,
BigUint::from(0u32),
"Second sync reset should clear all X"
);
}
fn test_four_state_explicit_cast_with_x(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (
a: input signed logic<8>,
y_to_unsigned: output logic<8>
) {
assign y_to_unsigned = a;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_a = sim.signal("a");
let id_y = sim.signal("y_to_unsigned");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0x80u32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
v,
BigUint::from(0x80u32),
"Signed→unsigned: value preserved"
);
assert_eq!(m, BigUint::from(0u32), "Signed→unsigned: no X");
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0x7Fu32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
v,
BigUint::from(0x7Fu32),
"Signed→unsigned: positive value preserved"
);
assert_eq!(m, BigUint::from(0u32));
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0x40u32), BigUint::from(0x80u32)); })
.unwrap();
let (_, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0x80u32),
"Signed→unsigned: X in sign bit preserved"
);
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0xA0u32), BigUint::from(0x0Fu32)); })
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0x0Fu32),
"Signed→unsigned: X in lower bits preserved"
);
assert_eq!(
v,
BigUint::from(0xA0u32),
"Signed→unsigned: value normalized (v &= ~m)"
);
sim.modify(|io| {
io.set_four_state(id_a, BigUint::from(0u32), BigUint::from(0xFFu32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0xFFu32),
"Signed→unsigned: all Z/X propagated"
);
assert_eq!(v, BigUint::from(0u32), "Signed→unsigned: value preserved");
}
fn test_z_literal_passthrough(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (a: input logic<8>, y: output logic<8>) {
assign y = 8'hzz;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let y = sim.signal("y");
let (v, m) = sim.get_four_state(y);
assert_eq!(
m,
BigUint::from(0xFFu32),
"Z literal: all bits should have mask=1"
);
assert_eq!(v, BigUint::from(0x00u32), "Z literal: Z encoding has v=0");
}
fn test_z_mux_tristate_pattern(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (en: input logic, d: input logic<8>, y: output logic<8>) {
assign y = if en ? d : 8'hzz;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let id_en = sim.signal("en");
let id_d = sim.signal("d");
let id_y = sim.signal("y");
sim.modify(|io| {
io.set_four_state(id_en, BigUint::from(1u32), BigUint::from(0u32));
io.set_four_state(id_d, BigUint::from(0xA5u32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(v, BigUint::from(0xA5u32), "en=1: y should be d");
assert_eq!(m, BigUint::from(0u32), "en=1: no X/Z bits");
sim.modify(|io| {
io.set_four_state(id_en, BigUint::from(0u32), BigUint::from(0u32));
})
.unwrap();
let (v, m) = sim.get_four_state(id_y);
assert_eq!(
m,
BigUint::from(0xFFu32),
"en=0: y should be all Z (mask=0xFF)"
);
assert_eq!(
v,
BigUint::from(0u32),
"en=0: Z encoding (v=0, m=1)"
);
}
fn test_x_literal_encoding(sim) {
@ignore_on(veryl);
@setup {
let code = r#"
module Top (y: output logic<8>) {
assign y = 8'hxx;
}
"#;
}
@build SimulatorBuilder::new(code, "Top")
.four_state(true);
let y = sim.signal("y");
let (v, m) = sim.get_four_state(y);
assert_eq!(
m,
BigUint::from(0xFFu32),
"X literal: all bits should have mask=1"
);
assert_eq!(v, BigUint::from(0xFFu32), "X literal: X encoding has v=1");
}
}