use celox::{BigUint, Simulator};
#[path = "test_utils/mod.rs"]
#[macro_use]
mod test_utils;
all_backends! {
fn test_wide_addition_128bit(sim) {
@setup { let code = r#"
module Top (
a: input logic<128>,
b: input logic<128>,
o: output logic<128>
) {
assign o = a + b;
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let b = sim.signal("b");
let o = sim.signal("o");
let val_a = BigUint::from(1u64) << 64 | BigUint::from(0x1234_5678u64);
let val_b = BigUint::from(0u64) << 64 | BigUint::from(0x0000_0001u64);
let expected = &val_a + &val_b;
sim.modify(|io| {
io.set_wide(a, val_a);
io.set_wide(b, val_b);
})
.unwrap();
assert_eq!(sim.get(o), expected);
}
fn test_wide_addition_carry_propagation(sim) {
@setup { let code = r#"
module Top (
a: input logic<128>,
b: input logic<128>,
o: output logic<128>
) {
assign o = a + b;
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let b = sim.signal("b");
let o = sim.signal("o");
let val_a = BigUint::from(u64::MAX);
let val_b = BigUint::from(1u64);
let expected = BigUint::from(1u128 << 64);
sim.modify(|io| {
io.set_wide(a, val_a);
io.set_wide(b, val_b);
})
.unwrap();
assert_eq!(sim.get(o), expected);
}
fn test_wide_subtraction_128bit(sim) {
@setup { let code = r#"
module Top (
a: input logic<128>,
b: input logic<128>,
o: output logic<128>
) {
assign o = a - b;
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let b = sim.signal("b");
let o = sim.signal("o");
let val_a = BigUint::from(1u128 << 64) + BigUint::from(100u64);
let val_b = BigUint::from(50u64);
let expected = BigUint::from(1u128 << 64) + BigUint::from(50u64);
sim.modify(|io| {
io.set_wide(a, val_a);
io.set_wide(b, val_b);
})
.unwrap();
assert_eq!(sim.get(o), expected);
}
fn test_wide_subtraction_borrow(sim) {
@setup { let code = r#"
module Top (
a: input logic<128>,
b: input logic<128>,
o: output logic<128>
) {
assign o = a - b;
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let b = sim.signal("b");
let o = sim.signal("o");
let val_a = BigUint::from(1u128 << 64);
let val_b = BigUint::from(1u64);
let expected = BigUint::from(u64::MAX as u128);
sim.modify(|io| {
io.set_wide(a, val_a);
io.set_wide(b, val_b);
})
.unwrap();
assert_eq!(sim.get(o), expected);
}
fn test_wide_bitwise_operations(sim) {
@setup { let code = r#"
module Top (
a: input logic<128>,
b: input logic<128>,
o_and: output logic<128>,
o_or: output logic<128>,
o_xor: output logic<128>
) {
assign o_and = a & b;
assign o_or = a | b;
assign o_xor = a ^ b;
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let b = sim.signal("b");
let o_and = sim.signal("o_and");
let o_or = sim.signal("o_or");
let o_xor = sim.signal("o_xor");
let val_a: BigUint = BigUint::from(0xFF00_FF00u64) | (BigUint::from(0xAAAA_AAAAu64) << 64);
let val_b: BigUint = BigUint::from(0x0FF0_0FF0u64) | (BigUint::from(0x5555_5555u64) << 64);
sim.modify(|io| {
io.set_wide(a, val_a.clone());
io.set_wide(b, val_b.clone());
})
.unwrap();
assert_eq!(sim.get(o_and), &val_a & &val_b);
assert_eq!(sim.get(o_or), &val_a | &val_b);
assert_eq!(sim.get(o_xor), &val_a ^ &val_b);
}
fn test_wide_comparison_eq(sim) {
@setup { let code = r#"
module Top (
a: input logic<128>,
b: input logic<128>,
o_eq: output logic,
o_ne: output logic
) {
assign o_eq = a == b;
assign o_ne = a != b;
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let b = sim.signal("b");
let o_eq = sim.signal("o_eq");
let o_ne = sim.signal("o_ne");
let val: BigUint = BigUint::from(0xDEAD_BEEFu64) | (BigUint::from(0xCAFE_BABEu64) << 64);
sim.modify(|io| {
io.set_wide(a, val.clone());
io.set_wide(b, val.clone());
})
.unwrap();
assert_eq!(sim.get(o_eq), 1u8.into());
assert_eq!(sim.get(o_ne), 0u8.into());
let val2 = BigUint::from(0xDEAD_BEEFu64) | (BigUint::from(0xCAFE_BABFu64) << 64);
sim.modify(|io| {
io.set_wide(b, val2);
})
.unwrap();
assert_eq!(sim.get(o_eq), 0u8.into());
assert_eq!(sim.get(o_ne), 1u8.into());
}
fn test_wide_shift_left(sim) {
@setup { let code = r#"
module Top (
a: input logic<128>,
amt: input logic<8>,
o: output logic<128>
) {
assign o = a << amt;
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let amt = sim.signal("amt");
let o = sim.signal("o");
let val = BigUint::from(1u64);
sim.modify(|io| {
io.set_wide(a, val.clone());
io.set(amt, 0u8);
})
.unwrap();
assert_eq!(sim.get(o), BigUint::from(1u64));
sim.modify(|io| io.set(amt, 64u8)).unwrap();
assert_eq!(sim.get(o), BigUint::from(1u128 << 64));
sim.modify(|io| {
io.set_wide(a, BigUint::from(0xFFFF_FFFFu64));
io.set(amt, 32u8);
})
.unwrap();
assert_eq!(sim.get(o), BigUint::from(0xFFFF_FFFFu128 << 32));
}
fn test_wide_ff_accumulator(sim) {
@setup { let code = r#"
module Top (
clk: input clock,
inc: input logic<128>,
o: output logic<128>
) {
var acc: logic<128>;
always_ff {
acc = acc + inc;
}
assign o = acc;
}
"#; }
@build Simulator::builder(code, "Top");
let clk = sim.event("clk");
let inc = sim.signal("inc");
let o = sim.signal("o");
let step = BigUint::from(u64::MAX);
sim.modify(|io| io.set_wide(inc, step.clone())).unwrap();
sim.tick(clk).unwrap();
assert_eq!(sim.get(o), step.clone());
sim.tick(clk).unwrap();
assert_eq!(sim.get(o), &step * 2u32);
sim.tick(clk).unwrap();
assert_eq!(sim.get(o), &step * 3u32);
}
fn test_wide_comb_logic_and_or(sim) {
@ignore_on(veryl);
@setup { let code = r#"
module Top (
a: input logic<128>,
b: input logic<128>,
y_and: output logic,
y_or: output logic,
y_and_w: output logic<128>,
y_or_w: output logic<128>
) {
assign y_and = (|a) && (|b);
assign y_or = (|a) || (|b);
assign y_and_w = (|a) && (|b);
assign y_or_w = (|a) || (|b);
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let b = sim.signal("b");
let y_and = sim.signal("y_and");
let y_or = sim.signal("y_or");
let y_and_w = sim.signal("y_and_w");
let y_or_w = sim.signal("y_or_w");
sim.modify(|io| {
io.set(a, 0u128);
io.set(b, 0u128);
})
.unwrap();
assert_eq!(sim.get(y_and), 0u8.into());
assert_eq!(sim.get(y_or), 0u8.into());
assert_eq!(sim.get(y_and_w), 0u128.into());
assert_eq!(sim.get(y_or_w), 0u128.into());
sim.modify(|io| {
io.set(a, 1u128 << 96);
io.set(b, 0u128);
})
.unwrap();
assert_eq!(sim.get(y_and), 0u8.into());
assert_eq!(sim.get(y_or), 1u8.into());
assert_eq!(sim.get(y_and_w), 0u128.into());
assert_eq!(sim.get(y_or_w), 1u128.into());
sim.modify(|io| {
io.set(a, 1u128 << 96);
io.set(b, 1u128 << 4);
})
.unwrap();
assert_eq!(sim.get(y_and), 1u8.into());
assert_eq!(sim.get(y_or), 1u8.into());
assert_eq!(sim.get(y_and_w), 1u128.into());
assert_eq!(sim.get(y_or_w), 1u128.into());
}
fn test_wide_logic_or_with_narrow_operand(sim) {
@setup { let code = r#"
module Top (
a: input logic<65>,
b: input logic,
o_or: output logic,
o_and: output logic,
) {
assign o_or = (|a) || b;
assign o_and = (|a) && b;
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let b = sim.signal("b");
let o_or = sim.signal("o_or");
let o_and = sim.signal("o_and");
sim.set(b, 0u8);
sim.set_wide(a, 0u8.into());
assert_eq!(sim.get(o_or), 0u8.into());
assert_eq!(sim.get(o_and), 0u8.into());
sim.set(b, 1u8);
assert_eq!(sim.get(o_or), 1u8.into());
assert_eq!(sim.get(o_and), 0u8.into());
sim.set(b, 0u8);
sim.set_wide(a, BigUint::from(1u64) << 64);
assert_eq!(sim.get(o_or), 1u8.into());
assert_eq!(sim.get(o_and), 0u8.into());
sim.set(b, 1u8);
assert_eq!(sim.get(o_or), 1u8.into());
assert_eq!(sim.get(o_and), 1u8.into());
}
fn test_wide_comb_mul(sim) {
@setup { let code = r#"
module Top (
a: input logic<128>,
b: input logic<128>,
y: output logic<128>
) {
assign y = a * b;
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let b = sim.signal("b");
let y = sim.signal("y");
sim.modify(|io| {
io.set(a, 3u128);
io.set(b, 7u128);
})
.unwrap();
assert_eq!(sim.get(y), 21u128.into());
sim.modify(|io| {
io.set(a, 0x1_0000_0000u128);
io.set(b, 0x1_0000_0000u128);
})
.unwrap();
assert_eq!(sim.get(y), 0x1_0000_0000_0000_0000u128.into());
}
fn test_wide_ff_mul(sim) {
@setup { let code = r#"
module Top (
clk: input clock,
rst: input reset,
a: input logic<128>,
b: input logic<128>,
y: output logic<128>
) {
var r: logic<128>;
always_ff (clk, rst) {
if_reset {
r = 128'd0;
} else {
r = a * b;
}
}
assign y = r;
}
"#; }
@build Simulator::builder(code, "Top");
let clk = sim.event("clk");
let rst = sim.signal("rst");
let a = sim.signal("a");
let b = sim.signal("b");
let y = sim.signal("y");
sim.modify(|io| {
io.set(rst, 0u8);
io.set(a, 0u128);
io.set(b, 0u128);
})
.unwrap();
sim.tick(clk).unwrap();
assert_eq!(sim.get(y), 0u128.into());
sim.modify(|io| {
io.set(rst, 1u8);
io.set(a, 12345u128);
io.set(b, 67890u128);
})
.unwrap();
sim.tick(clk).unwrap();
assert_eq!(sim.get(y), (12345u128 * 67890u128).into());
}
fn test_wide_comb_div(sim) {
@ignore_on(veryl);
@setup { let code = r#"
module Top (
a: input logic<128>,
b: input logic<128>,
q: output logic<128>
) {
assign q = a / b;
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let b = sim.signal("b");
let q = sim.signal("q");
sim.modify(|io| {
io.set(a, 100u128);
io.set(b, 7u128);
})
.unwrap();
assert_eq!(sim.get(q), 14u128.into());
let big_a: u128 = 1u128 << 100;
let big_b: u128 = 1u128 << 50;
sim.modify(|io| {
io.set(a, big_a);
io.set(b, big_b);
})
.unwrap();
assert_eq!(sim.get(q), (1u128 << 50).into());
}
fn test_wide_comb_rem(sim) {
@ignore_on(veryl);
@setup { let code = r#"
module Top (
a: input logic<128>,
b: input logic<128>,
r: output logic<128>
) {
assign r = a % b;
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let b = sim.signal("b");
let r = sim.signal("r");
sim.modify(|io| {
io.set(a, 100u128);
io.set(b, 7u128);
})
.unwrap();
assert_eq!(sim.get(r), 2u128.into());
let big_a: u128 = (1u128 << 100) + 42;
let big_b: u128 = 1u128 << 100;
sim.modify(|io| {
io.set(a, big_a);
io.set(b, big_b);
})
.unwrap();
assert_eq!(sim.get(r), 42u128.into());
}
fn test_wide_comb_bitxnor(sim) {
@ignore_on(sv);
@setup { let code = r#"
module Top (
a: input logic<128>,
b: input logic<128>,
y: output logic<128>
) {
assign y = a ~^ b;
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let b = sim.signal("b");
let y = sim.signal("y");
let va: u128 = 0xFFFF_FFFF_FFFF_FFFF_0000_0000_0000_0000;
let vb: u128 = 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF;
let expected = !(va ^ vb);
sim.modify(|io| {
io.set(a, va);
io.set(b, vb);
})
.unwrap();
assert_eq!(sim.get(y), expected.into());
}
fn test_wide_comb_sar(sim) {
@ignore_on(veryl);
@setup { let code = r#"
module Top (
a: input signed logic<128>,
b: input logic<7>,
y: output signed logic<128>
) {
assign y = a >>> b;
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let b = sim.signal("b");
let y = sim.signal("y");
sim.modify(|io| {
io.set(a, 0x100u128);
io.set(b, 4u8);
})
.unwrap();
assert_eq!(sim.get(y), 0x10u128.into());
let neg_val: u128 = u128::MAX - 15; sim.modify(|io| {
io.set(a, neg_val);
io.set(b, 2u8);
})
.unwrap();
assert_eq!(sim.get(y), (u128::MAX - 3).into());
}
fn test_wide_comb_signed_lt(sim) {
@ignore_on(veryl);
@setup { let code = r#"
module Top (
a: input signed logic<128>,
b: input signed logic<128>,
y: output logic
) {
assign y = a <: b;
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let b = sim.signal("b");
let y = sim.signal("y");
sim.modify(|io| {
io.set(a, u128::MAX); io.set(b, 1u128);
})
.unwrap();
assert_eq!(sim.get(y), 1u8.into());
sim.modify(|io| {
io.set(a, 1u128);
io.set(b, u128::MAX); })
.unwrap();
assert_eq!(sim.get(y), 0u8.into());
sim.modify(|io| {
io.set(a, 42u128);
io.set(b, 42u128);
})
.unwrap();
assert_eq!(sim.get(y), 0u8.into());
}
fn test_wide_comb_signed_gt(sim) {
@ignore_on(veryl);
@setup { let code = r#"
module Top (
a: input signed logic<128>,
b: input signed logic<128>,
y: output logic
) {
assign y = a >: b;
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let b = sim.signal("b");
let y = sim.signal("y");
sim.modify(|io| {
io.set(a, 1u128);
io.set(b, u128::MAX); })
.unwrap();
assert_eq!(sim.get(y), 1u8.into());
sim.modify(|io| {
io.set(a, u128::MAX); io.set(b, 1u128);
})
.unwrap();
assert_eq!(sim.get(y), 0u8.into());
}
fn test_wide_signed_compare_non_chunk_aligned(sim) {
@setup { let code = r#"
module Top (
a65: input signed logic<65>,
b65: input signed logic<65>,
a127: input signed logic<127>,
b127: input signed logic<127>,
lt65: output logic,
le65: output logic,
gt65: output logic,
ge65: output logic,
lt127: output logic,
le127: output logic,
gt127: output logic,
ge127: output logic,
) {
assign lt65 = a65 <: b65;
assign le65 = a65 <= b65;
assign gt65 = a65 >: b65;
assign ge65 = a65 >= b65;
assign lt127 = a127 <: b127;
assign le127 = a127 <= b127;
assign gt127 = a127 >: b127;
assign ge127 = a127 >= b127;
}
"#; }
@build Simulator::builder(code, "Top");
let a65 = sim.signal("a65");
let b65 = sim.signal("b65");
let a127 = sim.signal("a127");
let b127 = sim.signal("b127");
let outputs = [
sim.signal("lt65"),
sim.signal("le65"),
sim.signal("gt65"),
sim.signal("ge65"),
sim.signal("lt127"),
sim.signal("le127"),
sim.signal("gt127"),
sim.signal("ge127"),
];
let negative65 = (BigUint::from(1u8) << 65usize) - BigUint::from(1u8);
let negative127 = (BigUint::from(1u8) << 127usize) - BigUint::from(1u8);
sim.modify(|io| {
io.set_wide(a65, negative65.clone());
io.set_wide(b65, BigUint::from(1u8));
io.set_wide(a127, negative127.clone());
io.set_wide(b127, BigUint::from(1u8));
})
.unwrap();
for (signal, expected) in outputs.iter().zip([1u8, 1, 0, 0, 1, 1, 0, 0]) {
assert_eq!(sim.get(*signal), expected.into());
}
sim.modify(|io| {
io.set_wide(a65, BigUint::from(1u8));
io.set_wide(b65, negative65);
io.set_wide(a127, BigUint::from(1u8));
io.set_wide(b127, negative127);
})
.unwrap();
for (signal, expected) in outputs.iter().zip([0u8, 0, 1, 1, 0, 0, 1, 1]) {
assert_eq!(sim.get(*signal), expected.into());
}
}
fn test_wide_comb_reduction_nand(sim) {
@ignore_on(veryl);
@setup { let code = r#"
module Top (
a: input logic<128>,
y: output logic
) {
assign y = ~&a;
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let y = sim.signal("y");
sim.modify(|io| io.set(a, u128::MAX)).unwrap();
assert_eq!(sim.get(y), 0u8.into());
sim.modify(|io| io.set(a, u128::MAX - 1)).unwrap();
assert_eq!(sim.get(y), 1u8.into());
}
fn test_wide_comb_reduction_nor(sim) {
@setup { let code = r#"
module Top (
a: input logic<128>,
y: output logic
) {
assign y = ~|a;
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let y = sim.signal("y");
sim.modify(|io| io.set(a, 0u128)).unwrap();
assert_eq!(sim.get(y), 1u8.into());
sim.modify(|io| io.set(a, 1u128)).unwrap();
assert_eq!(sim.get(y), 0u8.into());
}
fn test_wide_comb_reduction_xnor(sim) {
@setup { let code = r#"
module Top (
a: input logic<128>,
y: output logic
) {
assign y = ~^a;
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let y = sim.signal("y");
sim.modify(|io| io.set(a, 0u128)).unwrap();
assert_eq!(sim.get(y), 1u8.into());
sim.modify(|io| io.set(a, 1u128)).unwrap();
assert_eq!(sim.get(y), 0u8.into());
sim.modify(|io| io.set(a, 3u128)).unwrap();
assert_eq!(sim.get(y), 1u8.into());
}
}