use celox::{SimBackend, Simulator};
#[path = "test_utils/mod.rs"]
#[macro_use]
#[allow(unused_macros)]
mod test_utils;
const TOP: &str = r#"
module Top (
clk : input clock,
rst : input reset,
i_clear : input logic,
i_push : input logic,
i_data : input logic<8>,
i_pop : input logic,
o_data : output logic<8>,
o_empty : output logic,
o_almost_full: output logic,
o_full : output logic,
o_word_count: output logic<3>,
) {
inst u_fifo: fifo #(
WIDTH: 8,
DEPTH: 4,
) (
i_clk: clk,
i_rst: rst,
i_clear,
o_empty,
o_almost_full,
o_full,
o_word_count,
i_push,
i_data,
i_pop,
o_data,
);
}
"#;
fn fifo_source() -> String {
format!(
"{}\n{}\n{}\n{TOP}",
test_utils::veryl_std::source(&["ram", "ram.veryl"]),
test_utils::veryl_std::source(&["fifo", "fifo_controller.veryl"]),
test_utils::veryl_std::source(&["fifo", "fifo.veryl"]),
)
}
fn reset<B: SimBackend>(sim: &mut Simulator<B>) {
let clk = sim.event("clk");
let rst = sim.signal("rst");
let i_clear = sim.signal("i_clear");
let i_push = sim.signal("i_push");
let i_pop = sim.signal("i_pop");
sim.modify(|io| {
io.set(rst, 0u8);
io.set(i_clear, 0u8);
io.set(i_push, 0u8);
io.set(i_pop, 0u8);
})
.unwrap();
sim.tick(clk).unwrap();
sim.modify(|io| io.set(rst, 1u8)).unwrap();
sim.tick(clk).unwrap();
}
all_backends! {
fn test_fifo_initial_empty(sim) {
@omit_veryl;
@ignore_on(sv);
@setup { let code = fifo_source(); }
@build Simulator::builder(&code, "Top");
reset(&mut sim);
let o_empty = sim.signal("o_empty");
let o_full = sim.signal("o_full");
let o_word_count = sim.signal("o_word_count");
assert_eq!(sim.get_as::<u8>(o_empty), 1, "should be empty after reset");
assert_eq!(
sim.get_as::<u8>(o_full),
0,
"should not be full after reset"
);
assert_eq!(sim.get_as::<u8>(o_word_count), 0, "word_count should be 0");
}
fn test_fifo_push_pop_single(sim) {
@omit_veryl;
@ignore_on(sv);
@setup { let code = fifo_source(); }
@build Simulator::builder(&code, "Top");
reset(&mut sim);
let clk = sim.event("clk");
let i_push = sim.signal("i_push");
let i_data = sim.signal("i_data");
let i_pop = sim.signal("i_pop");
let o_data = sim.signal("o_data");
let o_empty = sim.signal("o_empty");
let o_word_count = sim.signal("o_word_count");
sim.modify(|io| {
io.set(i_push, 1u8);
io.set(i_data, 0xAAu8);
})
.unwrap();
sim.tick(clk).unwrap();
sim.modify(|io| io.set(i_push, 0u8)).unwrap();
sim.tick(clk).unwrap();
assert_eq!(
sim.get_as::<u8>(o_empty),
0,
"should not be empty after push"
);
assert_eq!(sim.get_as::<u8>(o_word_count), 1, "word_count should be 1");
assert_eq!(sim.get_as::<u8>(o_data), 0xAA, "output should be 0xAA");
sim.modify(|io| io.set(i_pop, 1u8)).unwrap();
sim.tick(clk).unwrap();
sim.modify(|io| io.set(i_pop, 0u8)).unwrap();
sim.tick(clk).unwrap();
assert_eq!(sim.get_as::<u8>(o_empty), 1, "should be empty after pop");
assert_eq!(sim.get_as::<u8>(o_word_count), 0, "word_count should be 0");
}
fn test_fifo_full(sim) {
@omit_veryl;
@ignore_on(sv);
@setup { let code = fifo_source(); }
@build Simulator::builder(&code, "Top");
reset(&mut sim);
let clk = sim.event("clk");
let i_push = sim.signal("i_push");
let i_data = sim.signal("i_data");
let o_full = sim.signal("o_full");
let o_word_count = sim.signal("o_word_count");
for i in 0u8..4 {
sim.modify(|io| {
io.set(i_push, 1u8);
io.set(i_data, i + 1);
})
.unwrap();
sim.tick(clk).unwrap();
}
sim.modify(|io| io.set(i_push, 0u8)).unwrap();
sim.tick(clk).unwrap();
assert_eq!(sim.get_as::<u8>(o_full), 1, "should be full after 4 pushes");
assert_eq!(sim.get_as::<u8>(o_word_count), 4);
}
fn test_fifo_ordering(sim) {
@omit_veryl;
@ignore_on(sv);
@setup { let code = fifo_source(); }
@build Simulator::builder(&code, "Top");
reset(&mut sim);
let clk = sim.event("clk");
let i_push = sim.signal("i_push");
let i_data = sim.signal("i_data");
let i_pop = sim.signal("i_pop");
let o_data = sim.signal("o_data");
for val in [0x10u8, 0x20, 0x30, 0x40] {
sim.modify(|io| {
io.set(i_push, 1u8);
io.set(i_data, val);
})
.unwrap();
sim.tick(clk).unwrap();
}
sim.modify(|io| io.set(i_push, 0u8)).unwrap();
assert_eq!(sim.get_as::<u8>(o_data), 0x10, "first out should be 0x10");
sim.modify(|io| io.set(i_pop, 1u8)).unwrap();
sim.tick(clk).unwrap();
assert_eq!(sim.get_as::<u8>(o_data), 0x20, "second out should be 0x20");
sim.tick(clk).unwrap();
assert_eq!(sim.get_as::<u8>(o_data), 0x30, "third out should be 0x30");
sim.tick(clk).unwrap();
assert_eq!(sim.get_as::<u8>(o_data), 0x40, "fourth out should be 0x40");
}
fn test_fifo_clear(sim) {
@omit_veryl;
@ignore_on(sv);
@setup { let code = fifo_source(); }
@build Simulator::builder(&code, "Top");
reset(&mut sim);
let clk = sim.event("clk");
let i_push = sim.signal("i_push");
let i_data = sim.signal("i_data");
let i_clear = sim.signal("i_clear");
let o_empty = sim.signal("o_empty");
let o_word_count = sim.signal("o_word_count");
for val in [0x11u8, 0x22] {
sim.modify(|io| {
io.set(i_push, 1u8);
io.set(i_data, val);
})
.unwrap();
sim.tick(clk).unwrap();
}
sim.modify(|io| io.set(i_push, 0u8)).unwrap();
sim.tick(clk).unwrap();
assert_eq!(sim.get_as::<u8>(o_word_count), 2);
sim.modify(|io| io.set(i_clear, 1u8)).unwrap();
sim.tick(clk).unwrap();
sim.modify(|io| io.set(i_clear, 0u8)).unwrap();
sim.tick(clk).unwrap();
assert_eq!(sim.get_as::<u8>(o_empty), 1, "should be empty after clear");
assert_eq!(sim.get_as::<u8>(o_word_count), 0);
}
}