use celox::{Simulator, SimulatorErrorKind};
#[path = "test_utils/mod.rs"]
#[macro_use]
mod test_utils;
all_backends! {
fn test_multiple_modify_no_tick(sim) {
@setup { let code = r#"
module Top (
a: input logic<8>,
b: input logic<8>,
s: output logic<8>
) {
assign s = a + b;
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let b = sim.signal("b");
let s = sim.signal("s");
sim.modify(|io| io.set(a, 10u8)).unwrap();
sim.modify(|io| io.set(b, 20u8)).unwrap();
assert_eq!(sim.get(s), 30u8.into());
}
fn test_modify_triggers_comb_reevaluation(sim) {
@ignore_on(sv);
@setup { let code = r#"
module Top (
sel: input logic,
a: input logic<8>,
b: input logic<8>,
y: output logic<8>
) {
always_comb {
if sel {
y = a;
} else {
y = b;
}
}
}
"#; }
@build Simulator::builder(code, "Top");
let sel = sim.signal("sel");
let a = sim.signal("a");
let b = sim.signal("b");
let y = sim.signal("y");
sim.modify(|io| {
io.set(a, 0xAAu8);
io.set(b, 0xBBu8);
io.set(sel, 0u8);
})
.unwrap();
assert_eq!(sim.get(y), 0xBBu8.into());
sim.modify(|io| io.set(sel, 1u8)).unwrap();
assert_eq!(sim.get(y), 0xAAu8.into());
}
fn test_initial_state(sim) {
@setup { let code = r#"
module Top (
a: input logic<8>,
b: output logic<8>
) {
assign b = a;
}
"#; }
@build Simulator::builder(code, "Top");
let b = sim.signal("b");
assert_eq!(sim.get(b), 0u8.into());
}
fn test_rapid_tick_counter(sim) {
@ignore_on(veryl);
@setup { let code = r#"
module Top (
clk: input clock,
rst: input reset,
cnt: output logic<16>
) {
var counter: logic<16>;
always_ff (clk, rst) {
if_reset {
counter = 16'd0;
} else {
counter = counter + 16'd1;
}
}
assign cnt = counter;
}
"#; }
@build Simulator::builder(code, "Top");
let clk = sim.event("clk");
let rst = sim.signal("rst");
let cnt = sim.signal("cnt");
sim.modify(|io| io.set(rst, 0u8)).unwrap();
sim.tick(clk).unwrap();
sim.modify(|io| io.set(rst, 1u8)).unwrap();
for _ in 0..100 {
sim.tick(clk).unwrap();
}
assert_eq!(sim.get(cnt), 100u16.into());
}
fn test_modify_multiple_ports(sim) {
@setup { let code = r#"
module Top (
a: input logic<8>,
b: input logic<8>,
c: input logic<8>,
sum: output logic<8>
) {
assign sum = a + b + c;
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let b = sim.signal("b");
let c = sim.signal("c");
let sum = sim.signal("sum");
sim.modify(|io| {
io.set(a, 10u8);
io.set(b, 20u8);
io.set(c, 30u8);
})
.unwrap();
assert_eq!(sim.get(sum), 60u8.into());
}
fn test_overlapping_partial_write_keeps_untouched_bit_dependency(sim) {
@setup { let code = r#"
module Top (
a: input logic,
b: input logic,
c: input logic,
y: output logic,
x0: output logic,
) {
var x: logic<2>;
var t: logic;
always_comb {
x[1] = a;
x[0] = b;
x[0] = c;
t = x[1];
}
assign y = t;
assign x0 = x[0];
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let b = sim.signal("b");
let c = sim.signal("c");
let y = sim.signal("y");
let x0 = sim.signal("x0");
sim.modify(|io| {
io.set(a, 0u8);
io.set(b, 1u8);
io.set(c, 0u8);
})
.unwrap();
assert_eq!(sim.get(y), 0u8.into());
assert_eq!(sim.get(x0), 0u8.into());
sim.modify(|io| {
io.set(a, 1u8);
io.set(b, 0u8);
io.set(c, 1u8);
})
.unwrap();
assert_eq!(sim.get(y), 1u8.into());
assert_eq!(sim.get(x0), 1u8.into());
}
fn test_concat_with_dynamic_index_runtime(sim) {
@ignore_on(sv);
@setup { let code = r#"
module Top (
a: input logic<4>,
i: input logic<2>,
out: output logic<2>,
) {
var x: logic<2>;
assign x = {a[i], a[0]};
assign out = x;
}
"#; }
@build Simulator::builder(code, "Top");
let a = sim.signal("a");
let i = sim.signal("i");
let out = sim.signal("out");
sim.modify(|io| {
io.set(a, 0b1010u8);
io.set(i, 1u8);
})
.unwrap();
assert_eq!(sim.get(out), 0b10u8.into());
sim.modify(|io| io.set(i, 3u8)).unwrap();
assert_eq!(sim.get(out), 0b10u8.into());
sim.modify(|io| {
io.set(a, 0b0101u8);
io.set(i, 2u8);
})
.unwrap();
assert_eq!(sim.get(out), 0b11u8.into());
}
}
#[test]
fn test_try_new_valid() {
let code = r#"
module Top (
a: input logic<8>,
b: output logic<8>
) {
assign b = a;
}
"#;
let result = Simulator::builder(code, "Top").build();
assert!(result.is_ok());
}
#[test]
fn test_try_new_comb_loop() {
let code = r#"
module Top (
a: input logic,
b: output logic
) {
var x: logic;
assign x = x ^ a;
assign b = x;
}
"#;
let result = Simulator::builder(code, "Top").build();
let err = result.expect_err("Expected error for combinational loop");
assert!(
matches!(
err.kind(),
SimulatorErrorKind::Analyzer(_) | SimulatorErrorKind::SIRParser(_)
),
"Expected Analyzer or SIRParser error, got: {err:?}"
);
}