WIP getting queue formal to pass -- passes for capacity <= 2
Some checks failed
/ test (push) Has been cancelled

This commit is contained in:
Jacob Lifshay 2024-10-03 01:08:01 -07:00
parent bc26fe32fd
commit 3e2fb9b94f
Signed by: programmerjake
SSH key fingerprint: SHA256:B1iRVvUJkvd7upMIiMqn6OyxvD2SgJkAH3ZnUOj6z+c
5 changed files with 343 additions and 77 deletions

View file

@ -23,6 +23,19 @@ impl<T: Type> ReadyValid<T> {
fire
}
#[hdl]
pub fn fire_data(expr: impl ToExpr<Type = Self>) -> Expr<HdlOption<T>> {
let expr = expr.to_expr();
let option_ty = Expr::ty(expr).data;
#[hdl]
let fire_data = wire(option_ty);
connect(fire_data, option_ty.HdlNone());
#[hdl]
if expr.ready {
connect(fire_data, expr.data);
}
fire_data
}
#[hdl]
pub fn map<R: Type>(
expr: Expr<Self>,
f: impl FnOnce(Expr<T>) -> Expr<R>,
@ -163,7 +176,6 @@ pub fn queue<T: Type>(
}
}
#[cfg(todo)]
#[cfg(test)]
mod tests {
use super::*;
@ -171,27 +183,39 @@ mod tests {
cli::FormalMode, firrtl::ExportOptions,
module::transform::simplify_enums::SimplifyEnumsKind, testing::assert_formal,
};
use std::num::NonZero;
#[test]
fn test_queue() {
#[track_caller]
fn test_queue(capacity: NonZeroUsize, inp_ready_is_comb: bool, out_valid_is_comb: bool) {
assert_formal(
format_args!("test_queue_{capacity}_{inp_ready_is_comb}_{out_valid_is_comb}"),
queue_test(capacity, inp_ready_is_comb, out_valid_is_comb),
FormalMode::BMC,
20,
None,
ExportOptions {
simplify_enums: Some(SimplifyEnumsKind::ReplaceWithBundleOfUInts),
..ExportOptions::default()
},
);
#[hdl_module]
fn queue_test(capacity: NonZeroUsize, inp_ready_is_comb: bool, out_valid_is_comb: bool) {
#[hdl]
let clk: Clock = m.input();
#[hdl]
let rst: SyncReset = m.input();
#[hdl]
let inp_data: HdlOption<UInt<8>> = m.input();
#[hdl]
let out_ready: Bool = m.input();
#[hdl]
let start_check: Bool = m.input();
#[hdl]
let clk: Clock = m.input();
#[hdl]
let cd = wire();
connect(
cd,
#[hdl]
ClockDomain {
clk,
rst: rst.to_reset(),
rst: formal_reset().to_reset(),
},
);
#[hdl]
@ -216,52 +240,139 @@ mod tests {
} else if !ReadyValid::fire(dut.inp) & ReadyValid::fire(dut.out) {
connect_any(next_count, count - 1u8);
}
hdl_assert(clk, count.cmp_eq(dut.count), "");
hdl_assert(cd.clk, count.cmp_eq(dut.count), "");
#[hdl]
let index = reg_builder().clock_domain(cd).reset(HdlNone::<UInt<32>>());
let started_check = reg_builder().clock_domain(cd).reset(false);
#[hdl]
let data = reg_builder().clock_domain(cd).reset(HdlNone());
let steps_till_output = reg_builder().clock_domain(cd).reset(0u32);
#[hdl]
match index {
HdlNone =>
{
#[hdl]
if ReadyValid::fire(dut.inp) {
connect(index, HdlSome(0u32));
connect(data, dut.inp.data);
}
let expected_output = reg_builder().clock_domain(cd).reset(HdlNone());
#[hdl]
if start_check & !started_check {
#[hdl]
if let HdlSome(inp) = ReadyValid::fire_data(dut.inp) {
connect(started_check, true);
connect_any(
steps_till_output,
count + (!ReadyValid::fire(dut.out)).cast_to(UInt[1]),
);
connect(expected_output, HdlSome(inp));
}
HdlSome(cur_index) =>
} else if started_check & steps_till_output.cmp_ne(0u32) & ReadyValid::fire(dut.out) {
connect_any(steps_till_output, steps_till_output - 1u32);
}
#[hdl]
let stored_output = reg_builder().clock_domain(cd).reset(HdlNone());
#[hdl]
if let HdlSome(out) = ReadyValid::fire_data(dut.out) {
#[hdl]
if (start_check & !started_check) | (started_check & steps_till_output.cmp_ne(0u32))
{
connect(stored_output, HdlSome(out));
}
}
#[hdl]
if started_check & steps_till_output.cmp_eq(0u32) {
#[hdl]
if let HdlSome(expected_output) = expected_output {
#[hdl]
if cur_index.cmp_ge(next_count) {
connect(index, HdlNone());
#[hdl]
if let HdlSome(data) = data {
#[hdl]
if let HdlSome(out_data) = dut.out.data {
hdl_assert(clk, data.cmp_eq(out_data), "");
} else {
hdl_assert(clk, false.to_expr(), "");
}
} else {
hdl_assert(clk, false.to_expr(), "");
}
if let HdlSome(stored_output) = stored_output {
hdl_assert(cd.clk, stored_output.cmp_eq(expected_output), "");
} else {
connect(index, HdlSome((cur_index + 1u8).cast_to_static()));
hdl_assert(cd.clk, false.to_expr(), "");
}
} else {
hdl_assert(cd.clk, false.to_expr(), "");
}
}
}
assert_formal(
queue_test(NonZeroUsize::new(2).unwrap(), false, false),
FormalMode::BMC,
20,
None,
ExportOptions {
simplify_enums: Some(SimplifyEnumsKind::ReplaceWithBundleOfUInts),
..ExportOptions::default()
},
);
}
#[test]
fn test_1_false_false() {
test_queue(NonZero::new(1).unwrap(), false, false);
}
#[test]
fn test_1_false_true() {
test_queue(NonZero::new(1).unwrap(), false, true);
}
#[test]
fn test_1_true_false() {
test_queue(NonZero::new(1).unwrap(), true, false);
}
#[test]
fn test_1_true_true() {
test_queue(NonZero::new(1).unwrap(), true, true);
}
#[test]
fn test_2_false_false() {
test_queue(NonZero::new(2).unwrap(), false, false);
}
#[test]
fn test_2_false_true() {
test_queue(NonZero::new(2).unwrap(), false, true);
}
#[test]
fn test_2_true_false() {
test_queue(NonZero::new(2).unwrap(), true, false);
}
#[test]
fn test_2_true_true() {
test_queue(NonZero::new(2).unwrap(), true, true);
}
#[cfg(todo)]
#[test]
fn test_3_false_false() {
test_queue(NonZero::new(3).unwrap(), false, false);
}
#[cfg(todo)]
#[test]
fn test_3_false_true() {
test_queue(NonZero::new(3).unwrap(), false, true);
}
#[cfg(todo)]
#[test]
fn test_3_true_false() {
test_queue(NonZero::new(3).unwrap(), true, false);
}
#[cfg(todo)]
#[test]
fn test_3_true_true() {
test_queue(NonZero::new(3).unwrap(), true, true);
}
#[cfg(todo)]
#[test]
fn test_4_false_false() {
test_queue(NonZero::new(4).unwrap(), false, false);
}
#[cfg(todo)]
#[test]
fn test_4_false_true() {
test_queue(NonZero::new(4).unwrap(), false, true);
}
#[cfg(todo)]
#[test]
fn test_4_true_false() {
test_queue(NonZero::new(4).unwrap(), true, false);
}
#[cfg(todo)]
#[test]
fn test_4_true_true() {
test_queue(NonZero::new(4).unwrap(), true, true);
}
}