This commit is contained in:
parent
343805f80b
commit
0d54b9a2a9
6 changed files with 183 additions and 86 deletions
|
|
@ -49,7 +49,6 @@ impl<T: Type> ReadyValid<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: needs testing
|
||||
#[hdl_module]
|
||||
pub fn queue<T: Type>(
|
||||
ty: T,
|
||||
|
|
@ -134,7 +133,7 @@ pub fn queue<T: Type>(
|
|||
#[hdl]
|
||||
if inp_fire {
|
||||
#[hdl]
|
||||
if inp_index.cmp_eq(capacity) {
|
||||
if inp_index.cmp_eq(capacity.get() - 1) {
|
||||
connect_any(inp_index, 0_hdl_u0);
|
||||
} else {
|
||||
connect_any(inp_index, inp_index + 1_hdl_u1);
|
||||
|
|
@ -144,7 +143,7 @@ pub fn queue<T: Type>(
|
|||
#[hdl]
|
||||
if out_fire {
|
||||
#[hdl]
|
||||
if out_index.cmp_eq(capacity) {
|
||||
if out_index.cmp_eq(capacity.get() - 1) {
|
||||
connect_any(out_index, 0_hdl_u0);
|
||||
} else {
|
||||
connect_any(out_index, out_index + 1_hdl_u1);
|
||||
|
|
@ -153,10 +152,12 @@ pub fn queue<T: Type>(
|
|||
|
||||
#[hdl]
|
||||
if indexes_equal {
|
||||
connect(
|
||||
count,
|
||||
maybe_full.cast_to_static::<UInt<1>>() << (count_ty.width() - 1),
|
||||
);
|
||||
#[hdl]
|
||||
if maybe_full {
|
||||
connect_any(count, capacity);
|
||||
} else {
|
||||
connect_any(count, 0_hdl_u0);
|
||||
}
|
||||
} else {
|
||||
if capacity.is_power_of_two() {
|
||||
debug_assert_eq!(count_ty.width(), index_ty.width() + 1);
|
||||
|
|
@ -182,6 +183,7 @@ mod tests {
|
|||
use crate::{
|
||||
cli::FormalMode, firrtl::ExportOptions,
|
||||
module::transform::simplify_enums::SimplifyEnumsKind, testing::assert_formal,
|
||||
ty::StaticType,
|
||||
};
|
||||
use std::num::NonZero;
|
||||
|
||||
|
|
@ -190,8 +192,8 @@ mod tests {
|
|||
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,
|
||||
FormalMode::Prove,
|
||||
14,
|
||||
None,
|
||||
ExportOptions {
|
||||
simplify_enums: Some(SimplifyEnumsKind::ReplaceWithBundleOfUInts),
|
||||
|
|
@ -200,12 +202,6 @@ mod tests {
|
|||
);
|
||||
#[hdl_module]
|
||||
fn queue_test(capacity: NonZeroUsize, inp_ready_is_comb: bool, out_valid_is_comb: bool) {
|
||||
#[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]
|
||||
|
|
@ -219,6 +215,24 @@ mod tests {
|
|||
},
|
||||
);
|
||||
#[hdl]
|
||||
let inp_data: HdlOption<UInt<8>> = wire();
|
||||
#[hdl]
|
||||
if any_seq(Bool) {
|
||||
connect(inp_data, HdlSome(any_seq(UInt::<8>::TYPE)));
|
||||
} else {
|
||||
connect(inp_data, HdlNone());
|
||||
}
|
||||
#[hdl]
|
||||
let out_ready: Bool = wire();
|
||||
connect(out_ready, any_seq(Bool));
|
||||
let index_ty: UInt<32> = UInt::TYPE;
|
||||
#[hdl]
|
||||
let index_to_check = wire();
|
||||
connect(index_to_check, any_const(index_ty));
|
||||
let index_max = !index_ty.zero();
|
||||
// we saturate at index_max, so only check indexes where we properly maintain position
|
||||
hdl_assume(clk, index_to_check.cmp_ne(index_max), "");
|
||||
#[hdl]
|
||||
let dut = instance(queue(
|
||||
UInt[ConstUsize::<8>],
|
||||
capacity,
|
||||
|
|
@ -228,63 +242,97 @@ mod tests {
|
|||
connect(dut.cd, cd);
|
||||
connect(dut.inp.data, inp_data);
|
||||
connect(dut.out.ready, out_ready);
|
||||
hdl_assume(
|
||||
clk,
|
||||
index_to_check.cmp_ne(!Expr::ty(index_to_check).zero()),
|
||||
"",
|
||||
);
|
||||
|
||||
#[hdl]
|
||||
let count = reg_builder().clock_domain(cd).reset(0u32);
|
||||
let expected_count = reg_builder().clock_domain(cd).reset(0u32);
|
||||
#[hdl]
|
||||
let next_count = wire();
|
||||
connect(next_count, count);
|
||||
connect(count, next_count);
|
||||
let next_expected_count = wire();
|
||||
connect(next_expected_count, expected_count);
|
||||
connect(expected_count, next_expected_count);
|
||||
#[hdl]
|
||||
if ReadyValid::fire(dut.inp) & !ReadyValid::fire(dut.out) {
|
||||
connect_any(next_count, count + 1u8);
|
||||
connect_any(next_expected_count, expected_count + 1u8);
|
||||
} else if !ReadyValid::fire(dut.inp) & ReadyValid::fire(dut.out) {
|
||||
connect_any(next_count, count - 1u8);
|
||||
connect_any(next_expected_count, expected_count - 1u8);
|
||||
}
|
||||
hdl_assert(cd.clk, count.cmp_eq(dut.count), "");
|
||||
hdl_assert(cd.clk, expected_count.cmp_eq(dut.count), "");
|
||||
|
||||
#[hdl]
|
||||
let started_check = reg_builder().clock_domain(cd).reset(false);
|
||||
let prev_out_ready = reg_builder().clock_domain(cd).reset(!0_hdl_u3);
|
||||
connect_any(
|
||||
prev_out_ready,
|
||||
(prev_out_ready << 1) | out_ready.cast_to(UInt[1]),
|
||||
);
|
||||
#[hdl]
|
||||
let steps_till_output = reg_builder().clock_domain(cd).reset(0u32);
|
||||
let prev_inp_valid = reg_builder().clock_domain(cd).reset(!0_hdl_u3);
|
||||
connect_any(
|
||||
prev_inp_valid,
|
||||
(prev_inp_valid << 1) | HdlOption::is_some(inp_data).cast_to(UInt[1]),
|
||||
);
|
||||
hdl_assume(clk, (prev_out_ready & prev_inp_valid).cmp_ne(0u8), "");
|
||||
|
||||
#[hdl]
|
||||
let expected_output = reg_builder().clock_domain(cd).reset(HdlNone());
|
||||
let inp_index = reg_builder().clock_domain(cd).reset(index_ty.zero());
|
||||
#[hdl]
|
||||
if start_check & !started_check {
|
||||
let stored_inp_data = reg_builder().clock_domain(cd).reset(0u8);
|
||||
|
||||
#[hdl]
|
||||
if let HdlSome(data) = ReadyValid::fire_data(dut.inp) {
|
||||
#[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));
|
||||
}
|
||||
} 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 {
|
||||
if inp_index.cmp_lt(index_max) {
|
||||
connect_any(inp_index, inp_index + 1u8);
|
||||
#[hdl]
|
||||
if let HdlSome(stored_output) = stored_output {
|
||||
hdl_assert(cd.clk, stored_output.cmp_eq(expected_output), "");
|
||||
} else {
|
||||
hdl_assert(cd.clk, false.to_expr(), "");
|
||||
if inp_index.cmp_eq(index_to_check) {
|
||||
connect(stored_inp_data, data);
|
||||
}
|
||||
} else {
|
||||
hdl_assert(cd.clk, false.to_expr(), "");
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
if inp_index.cmp_lt(index_to_check) {
|
||||
hdl_assert(clk, stored_inp_data.cmp_eq(0u8), "");
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
let out_index = reg_builder().clock_domain(cd).reset(index_ty.zero());
|
||||
#[hdl]
|
||||
let stored_out_data = reg_builder().clock_domain(cd).reset(0u8);
|
||||
|
||||
#[hdl]
|
||||
if let HdlSome(data) = ReadyValid::fire_data(dut.out) {
|
||||
#[hdl]
|
||||
if out_index.cmp_lt(index_max) {
|
||||
connect_any(out_index, out_index + 1u8);
|
||||
#[hdl]
|
||||
if out_index.cmp_eq(index_to_check) {
|
||||
connect(stored_out_data, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
if out_index.cmp_lt(index_to_check) {
|
||||
hdl_assert(clk, stored_out_data.cmp_eq(0u8), "");
|
||||
}
|
||||
|
||||
hdl_assert(clk, inp_index.cmp_ge(out_index), "");
|
||||
|
||||
#[hdl]
|
||||
if inp_index.cmp_lt(index_max) & out_index.cmp_lt(index_max) {
|
||||
hdl_assert(clk, expected_count.cmp_eq(inp_index - out_index), "");
|
||||
} else {
|
||||
hdl_assert(clk, expected_count.cmp_ge(inp_index - out_index), "");
|
||||
}
|
||||
|
||||
#[hdl]
|
||||
if inp_index.cmp_gt(index_to_check) & out_index.cmp_gt(index_to_check) {
|
||||
hdl_assert(clk, stored_inp_data.cmp_eq(stored_out_data), "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -328,49 +376,41 @@ mod tests {
|
|||
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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue