use celox::{OptimizeOptions, Simulator};
#[path = "test_utils/mod.rs"]
#[macro_use]
#[allow(unused_macros)]
mod test_utils;
const BRAM_CODE: &str = r#"
module BramTdp #(
param ADDR_W: u32 = 4,
param DATA_W: u32 = 8,
) (
clk: input clock,
a_we : input logic ,
a_addr: input logic<ADDR_W>,
a_din : input logic<DATA_W>,
a_dout: output logic<DATA_W>,
b_we : input logic ,
b_addr: input logic<ADDR_W>,
b_din : input logic<DATA_W>,
b_dout: output logic<DATA_W>,
) {
const DEPTH: u32 = 1 << ADDR_W;
var mem : logic<DATA_W> [DEPTH];
always_ff (clk) {
if a_we {
mem[a_addr] = a_din;
}
if b_we {
mem[b_addr] = b_din;
}
a_dout = mem[a_addr];
b_dout = mem[b_addr];
}
}
"#;
all_backends! {
fn bram_rewrite_no_corruption_all_opts(sim) {
@ignore_on(sv);
@build Simulator::builder(BRAM_CODE, "BramTdp")
.optimize_options(OptimizeOptions::all());
let clk = sim.event("clk");
let a_we = sim.signal("a_we");
let a_addr = sim.signal("a_addr");
let a_din = sim.signal("a_din");
let a_dout = sim.signal("a_dout");
let b_we = sim.signal("b_we");
let b_addr = sim.signal("b_addr");
let b_din = sim.signal("b_din");
sim.set(a_we, 0u8);
sim.set(a_addr, 0u8);
sim.set(a_din, 0u8);
sim.set(b_we, 0u8);
sim.set(b_addr, 0u8);
sim.set(b_din, 0u8);
sim.tick(clk).unwrap();
for addr in [0u8, 4, 8, 12] {
sim.set(a_we, 1u8);
sim.set(a_addr, addr);
sim.set(a_din, 0xA0u8.wrapping_add(addr));
sim.tick(clk).unwrap();
}
for addr in [0u8, 4, 8, 12] {
sim.set(a_we, 0u8);
sim.set(a_addr, addr);
sim.tick(clk).unwrap();
let val: u8 = sim.get_as(a_dout);
assert_eq!(
val,
0xA0u8.wrapping_add(addr),
"Initial write: mem[{addr}] should be 0x{:02x}, got 0x{val:02x}",
0xA0u8.wrapping_add(addr)
);
}
sim.set(a_we, 1u8);
sim.set(a_addr, 0u8);
sim.set(a_din, 0xBBu8);
sim.tick(clk).unwrap();
sim.set(a_we, 0u8);
sim.set(a_addr, 0u8);
sim.tick(clk).unwrap();
let val: u8 = sim.get_as(a_dout);
assert_eq!(
val, 0xBB,
"Re-write: mem[0] should be 0xBB, got 0x{val:02x}"
);
for addr in [4u8, 8, 12] {
sim.set(a_addr, addr);
sim.tick(clk).unwrap();
let val: u8 = sim.get_as(a_dout);
assert_eq!(
val,
0xA0u8.wrapping_add(addr),
"After re-write of addr 0: mem[{addr}] should be 0x{:02x}, got 0x{val:02x}",
0xA0u8.wrapping_add(addr)
);
}
}
fn bram_rewrite_no_corruption_no_opts(sim) {
@ignore_on(sv);
@build Simulator::builder(BRAM_CODE, "BramTdp")
.optimize_options(OptimizeOptions::none());
let clk = sim.event("clk");
let a_we = sim.signal("a_we");
let a_addr = sim.signal("a_addr");
let a_din = sim.signal("a_din");
let a_dout = sim.signal("a_dout");
let b_we = sim.signal("b_we");
let b_addr = sim.signal("b_addr");
let b_din = sim.signal("b_din");
sim.set(a_we, 0u8);
sim.set(a_addr, 0u8);
sim.set(a_din, 0u8);
sim.set(b_we, 0u8);
sim.set(b_addr, 0u8);
sim.set(b_din, 0u8);
sim.tick(clk).unwrap();
for addr in [0u8, 4, 8, 12] {
sim.set(a_we, 1u8);
sim.set(a_addr, addr);
sim.set(a_din, 0xA0u8.wrapping_add(addr));
sim.tick(clk).unwrap();
}
for addr in [0u8, 4, 8, 12] {
sim.set(a_we, 0u8);
sim.set(a_addr, addr);
sim.tick(clk).unwrap();
let val: u8 = sim.get_as(a_dout);
assert_eq!(
val,
0xA0u8.wrapping_add(addr),
"Initial write: mem[{addr}] should be 0x{:02x}, got 0x{val:02x}",
0xA0u8.wrapping_add(addr)
);
}
sim.set(a_we, 1u8);
sim.set(a_addr, 0u8);
sim.set(a_din, 0xBBu8);
sim.tick(clk).unwrap();
sim.set(a_we, 0u8);
sim.set(a_addr, 0u8);
sim.tick(clk).unwrap();
let val: u8 = sim.get_as(a_dout);
assert_eq!(
val, 0xBB,
"Re-write: mem[0] should be 0xBB, got 0x{val:02x}"
);
for addr in [4u8, 8, 12] {
sim.set(a_addr, addr);
sim.tick(clk).unwrap();
let val: u8 = sim.get_as(a_dout);
assert_eq!(
val,
0xA0u8.wrapping_add(addr),
"After re-write of addr 0: mem[{addr}] should be 0x{:02x}, got 0x{val:02x}",
0xA0u8.wrapping_add(addr)
);
}
}
}