celox 0.4.1

Celox HDL Simulator
Documentation
use celox::Simulator;

#[path = "test_utils/mod.rs"]
#[macro_use]
#[allow(unused_macros)]
mod test_utils;

const DEPTH: usize = 100;
const SOURCE: &str = include_str!("fixtures/linear_sorter_pull_mre.veryl");

fn push_values<B: celox::SimBackend>(sim: &mut celox::Simulator<B>, clk: B::Event, values: &[u16]) {
    let push = sim.signal("push");
    let pop = sim.signal("pop");
    let d_in = sim.signal("d_in");

    sim.modify(|io| {
        io.set(pop, 0u8);
        io.set(push, 1u8);
    })
    .unwrap();
    for &value in values {
        sim.modify(|io| io.set(d_in, value)).unwrap();
        sim.tick(clk).unwrap();
    }
    sim.modify(|io| io.set(push, 0u8)).unwrap();
    sim.tick(clk).unwrap();
}

fn pull_until_empty<B: celox::SimBackend>(
    sim: &mut celox::Simulator<B>,
    clk: B::Event,
    max_cycles: usize,
) -> Vec<u16> {
    let pop = sim.signal("pop");
    let empty = sim.signal("empty");
    let d_out = sim.signal("d_out");
    let mut out = Vec::new();

    for _ in 0..max_cycles {
        if sim.get_as::<u8>(empty) != 0 {
            break;
        }
        out.push(sim.get_as::<u16>(d_out));
        sim.modify(|io| io.set(pop, 1u8)).unwrap();
        sim.tick(clk).unwrap();
        sim.modify(|io| io.set(pop, 0u8)).unwrap();
        sim.tick(clk).unwrap();
    }

    out
}

all_backends! {
fn bit_array_index_64_ff_roundtrips(sim) {
    @ignore_on(wasm, sv);
    @build Simulator::builder(r#"
module BitArrayIndex64 (
    clk: input clock,
    rst: input reset,
    d: input logic,
    q: output logic,
) {
    var bits: logic [65];

    always_ff {
        if_reset {
            bits[0] = 0;
            bits[64] = 0;
        } else {
            bits[0] = d;
            bits[64] = bits[0];
        }
    }

    assign q = bits[64];
}
"#, "BitArrayIndex64").reset_type(celox::ResetType::AsyncLow);

    let clk = sim.event("clk");
    let rst = sim.signal("rst");
    let d = sim.signal("d");
    let q = sim.signal("q");

    sim.modify(|io| {
        io.set(rst, 0u8);
        io.set(d, 0u8);
    }).unwrap();
    sim.tick(clk).unwrap();
    sim.modify(|io| io.set(rst, 1u8)).unwrap();
    sim.tick(clk).unwrap();
    assert_eq!(sim.get_as::<u8>(q), 0);

    sim.modify(|io| io.set(d, 1u8)).unwrap();
    sim.tick(clk).unwrap();
    assert_eq!(sim.get_as::<u8>(q), 0);
    sim.tick(clk).unwrap();
    assert_eq!(sim.get_as::<u8>(q), 1);
}

fn word_array_index_64_ff_roundtrips(sim) {
    @ignore_on(wasm, sv);
    @build Simulator::builder(r#"
module WordArrayIndex64 (
    clk: input clock,
    rst: input reset,
    d: input logic<16>,
    q: output logic<16>,
) {
    var words: logic<16> [65];

    always_ff {
        if_reset {
            words[0] = 0;
            words[64] = 0;
        } else {
            words[0] = d;
            words[64] = words[0];
        }
    }

    assign q = words[64];
}
"#, "WordArrayIndex64").reset_type(celox::ResetType::AsyncLow);

    let clk = sim.event("clk");
    let rst = sim.signal("rst");
    let d = sim.signal("d");
    let q = sim.signal("q");

    sim.modify(|io| {
        io.set(rst, 0u8);
        io.set(d, 0u16);
    }).unwrap();
    sim.tick(clk).unwrap();
    sim.modify(|io| io.set(rst, 1u8)).unwrap();
    sim.tick(clk).unwrap();
    assert_eq!(sim.get_as::<u16>(q), 0);

    sim.modify(|io| io.set(d, 0x1234u16)).unwrap();
    sim.tick(clk).unwrap();
    assert_eq!(sim.get_as::<u16>(q), 0);
    sim.tick(clk).unwrap();
    assert_eq!(sim.get_as::<u16>(q), 0x1234);
}

fn linear_sorter_pull_late_minima_drain_once_in_sorted_order(sim) {
    @omit_veryl;
    @ignore_on(wasm, sv);
    @build Simulator::builder(SOURCE, "LinearSorterPullMreU16")
        .param("DEPTH", DEPTH as u64)
        .reset_type(celox::ResetType::AsyncLow);

    let rst = sim.signal("rst");
    let clk = sim.event("clk");
    let clear = sim.signal("clear");
    let push = sim.signal("push");
    let pop = sim.signal("pop");
    let d_in = sim.signal("d_in");

    sim.modify(|io| {
        io.set(rst, 0u8);
        io.set(clear, 0u8);
        io.set(push, 0u8);
        io.set(pop, 0u8);
        io.set(d_in, 0u16);
    })
    .unwrap();
    sim.tick(clk).unwrap();
    sim.tick(clk).unwrap();
    sim.modify(|io| io.set(rst, 1u8)).unwrap();
    sim.tick(clk).unwrap();

    let mut input: Vec<u16> = (0..DEPTH - 4).map(|i| 1000 + i as u16).collect();
    input.extend([1, 2, 3, 4]);
    let mut expected = input.clone();
    expected.sort();

    push_values(&mut sim, clk, &input);
    let got = pull_until_empty(&mut sim, clk, DEPTH + 8);

    assert_eq!(got, expected);
}
}