use celox::Simulator;
#[path = "test_utils/mod.rs"]
#[macro_use]
mod test_utils;
const TOP_W1: &str = r#"
module Top (
clk : input clock,
rst : input reset,
i_clear : input logic,
i_data : input logic,
o_edge : output logic,
o_posedge: output logic,
o_negedge: output logic,
) {
inst u: edge_detector #(WIDTH: 1) (
i_clk: clk,
i_rst: rst,
i_clear,
i_data,
o_edge,
o_posedge,
o_negedge,
);
}
"#;
all_backends! {
fn test_edge_detector_basic(sim) {
@setup { let code = format!("{}\n{TOP_W1}", test_utils::veryl_std::source(&["edge_detector", "edge_detector.veryl"])); }
@build Simulator::builder(&code, "Top");
let clk = sim.event("clk");
let rst = sim.signal("rst");
let i_clear = sim.signal("i_clear");
let i_data = sim.signal("i_data");
let o_edge = sim.signal("o_edge");
let o_posedge = sim.signal("o_posedge");
let o_negedge = sim.signal("o_negedge");
sim.modify(|io| {
io.set(rst, 0u8);
io.set(i_clear, 0u8);
io.set(i_data, 0u8);
})
.unwrap();
sim.tick(clk).unwrap();
sim.modify(|io| io.set(rst, 1u8)).unwrap();
sim.tick(clk).unwrap();
sim.eval_comb().unwrap();
assert_eq!(sim.get_as::<u8>(o_posedge), 0, "no edge: data=0, i_data=0");
assert_eq!(sim.get_as::<u8>(o_negedge), 0);
sim.modify(|io| io.set(i_data, 1u8)).unwrap();
sim.eval_comb().unwrap();
assert_eq!(sim.get_as::<u8>(o_posedge), 1, "posedge: i_data=1, data=0");
assert_eq!(sim.get_as::<u8>(o_negedge), 0);
assert_eq!(sim.get_as::<u8>(o_edge), 1);
sim.tick(clk).unwrap();
sim.eval_comb().unwrap();
assert_eq!(sim.get_as::<u8>(o_posedge), 0, "no edge: data=1, i_data=1");
assert_eq!(sim.get_as::<u8>(o_negedge), 0);
assert_eq!(sim.get_as::<u8>(o_edge), 0);
sim.modify(|io| io.set(i_data, 0u8)).unwrap();
sim.eval_comb().unwrap();
assert_eq!(sim.get_as::<u8>(o_posedge), 0);
assert_eq!(sim.get_as::<u8>(o_negedge), 1, "negedge: i_data=0, data=1");
assert_eq!(sim.get_as::<u8>(o_edge), 1);
}
fn test_edge_detector_clear(sim) {
@setup { let code = format!("{}\n{TOP_W1}", test_utils::veryl_std::source(&["edge_detector", "edge_detector.veryl"])); }
@build Simulator::builder(&code, "Top");
let clk = sim.event("clk");
let rst = sim.signal("rst");
let i_clear = sim.signal("i_clear");
let i_data = sim.signal("i_data");
let o_posedge = sim.signal("o_posedge");
let o_negedge = sim.signal("o_negedge");
sim.modify(|io| {
io.set(rst, 0u8);
io.set(i_clear, 0u8);
io.set(i_data, 0u8);
})
.unwrap();
sim.tick(clk).unwrap();
sim.modify(|io| io.set(rst, 1u8)).unwrap();
sim.tick(clk).unwrap();
sim.modify(|io| {
io.set(i_data, 1u8);
io.set(i_clear, 1u8);
})
.unwrap();
sim.eval_comb().unwrap();
assert_eq!(
sim.get_as::<u8>(o_posedge),
0,
"clear should suppress posedge"
);
assert_eq!(
sim.get_as::<u8>(o_negedge),
0,
"clear should suppress negedge"
);
}
fn test_edge_detector_multibit(sim) {
@setup { let top = r#"
module Top (
clk : input clock,
rst : input reset,
i_data : input logic<4>,
o_edge : output logic<4>,
o_posedge: output logic<4>,
o_negedge: output logic<4>,
) {
inst u: edge_detector #(WIDTH: 4) (
i_clk : clk,
i_rst : rst,
i_clear: 1'b0,
i_data,
o_edge,
o_posedge,
o_negedge,
);
}
"#;
let code = format!("{}\n{top}", test_utils::veryl_std::source(&["edge_detector", "edge_detector.veryl"])); }
@build Simulator::builder(&code, "Top");
let clk = sim.event("clk");
let rst = sim.signal("rst");
let i_data = sim.signal("i_data");
let o_edge = sim.signal("o_edge");
sim.modify(|io| {
io.set(rst, 0u8);
io.set(i_data, 0u8);
})
.unwrap();
sim.tick(clk).unwrap();
sim.modify(|io| io.set(rst, 1u8)).unwrap();
sim.tick(clk).unwrap();
sim.modify(|io| io.set(i_data, 0b0101u8)).unwrap();
sim.eval_comb().unwrap();
assert_eq!(
sim.get_as::<u8>(o_edge),
0b0101,
"bits 0,2 should have edge"
);
sim.tick(clk).unwrap();
sim.modify(|io| io.set(i_data, 0b1010u8)).unwrap();
sim.eval_comb().unwrap();
assert_eq!(
sim.get_as::<u8>(o_edge),
0b1111,
"all changed bits should report an edge"
);
sim.tick(clk).unwrap();
sim.eval_comb().unwrap();
assert_eq!(
sim.get_as::<u8>(o_edge),
0,
"steady state should report no edges"
);
}
}