test(fpga): regression coverage for C-3 and USB NUM_CELLS bugs

Two bugs fixed recently had no tests that would have failed before the
fix. Add direct regressions so either cannot silently return:

1. tb_chirp_controller Group 3b (multi-frame, C-3): run a second full
   frame back-to-back after DONE and assert chirp_counter returns to 0,
   frame 2 reaches GUARD_TIME after exactly CHIRP_MAX/2 long chirps,
   and frame 2 reaches DONE. Before the fix, chirp_counter held at
   CHIRP_MAX after frame 1, the LONG_LISTEN -> GUARD guard (=CHIRP_MAX/2-1)
   never matched, and frame 2 ran extra chirps until the 6-bit counter
   wrapped — these checks fail loudly if that regresses.

2. tb_usb_data_interface frame-sync width + value pins: assert
   $bits(uut.sample_counter) >= 15 and uut.NUM_CELLS == 15'd16384.
   Protects against reintroducing the 12-bit / 2048-cell constants
   that fired 8 false frame-start markers per real 512 x 32 frame.

Regression: 32/32 PASS; USB TB 89 -> 91 checks.
This commit is contained in:
Jason
2026-04-22 19:44:25 +05:45
parent 3d0ee50999
commit 27c9c22ad2
2 changed files with 65 additions and 1 deletions
+50 -1
View File
@@ -322,7 +322,56 @@ initial begin
// With new_chirp=0, FSM should stay in IDLE
@(posedge clk_120m);
check("FSM: returns to IDLE after DONE", dut.current_state == 3'b000);
// =====================================================================
// TEST GROUP 3b: MULTI-FRAME REGRESSION (C-3)
//
// Bug: plfm_chirp_controller_enhanced never reset chirp_counter when the
// frame completed. After frame 1 the counter sat at CHIRP_MAX, so the
// LONG_LISTEN -> GUARD transition guard (== CHIRP_MAX/2-1) never matched
// on subsequent frames and frame 2+ ran extra chirps until the 6-bit
// counter wrapped.
//
// These checks prove the counter is cleared at DONE and frame 2 matches
// frame 1 exactly.
// =====================================================================
$display("--- Group 3b: Multi-Frame Regression (C-3) ---");
// T3b.1: Immediately after frame 1 DONE -> IDLE, counter is back to 0.
check("C-3: chirp_counter reset to 0 after 1st DONE", chirp_counter == 6'd0);
// Kick off frame 2 from the same IDLE state (no reset between frames).
@(posedge clk_120m);
new_chirp = 1;
@(posedge clk_120m);
// T3b.2: Frame 2 enters LONG_CHIRP.
wait_for_state(3'b001, 10);
check("Frame 2: enters LONG_CHIRP", dut.current_state == 3'b001);
// T3b.3: Frame 2 reaches GUARD_TIME after exactly CHIRP_MAX/2 long chirps.
// (If the counter were not reset, the FSM would stall in
// LONG_CHIRP/LONG_LISTEN until the 6-bit counter wrapped.)
wait_for_state(3'b011,
(T1_SAMPLES + T1_RADAR_LISTENING) * (CHIRP_MAX/2) + 20);
check("Frame 2: reaches GUARD_TIME after CHIRP_MAX/2 long chirps",
dut.current_state == 3'b011);
check("Frame 2: chirp_counter == CHIRP_MAX/2 at GUARD_TIME",
chirp_counter == CHIRP_MAX/2);
// T3b.4: Frame 2 reaches DONE.
wait_for_state(3'b110,
GUARD_SAMPLES +
(T2_SAMPLES + T2_RADAR_LISTENING) * (CHIRP_MAX/2) + 20);
check("Frame 2: reaches DONE", dut.current_state == 3'b110);
// Deassert new_chirp so FSM stays in IDLE after DONE.
new_chirp = 0;
@(posedge clk_120m);
// T3b.5: Counter cleared again after frame 2 completes.
check("C-3: chirp_counter reset to 0 after 2nd DONE", chirp_counter == 6'd0);
// =====================================================================
// TEST GROUP 4: SINGLE-DRIVER VERIFICATION (A5 FIX CORE TEST)
// =====================================================================
@@ -411,6 +411,21 @@ module tb_usb_data_interface;
check(ft601_siwu_n === 1'b1,
"ft601_siwu_n=1 after reset");
// ────────────────────────────────────────────────────────
// Frame-sync regression (NUM_CELLS bug)
//
// sample_counter was 12 bits wide with NUM_CELLS=2048 before the
// 2048-pt FFT architecture was completed. With 512 range bins x 32
// Doppler = 16384 cells per frame, the old 12-bit counter wrapped
// 8 times per real frame and the host saw 8 false frame-start
// markers. These checks pin the counter width and NUM_CELLS value
// so the regression fails loudly if either is narrowed again.
// ────────────────────────────────────────────────────────
check($bits(uut.sample_counter) >= 15,
"Frame-sync: sample_counter width >= 15 bits (holds 0..16383)");
check(uut.NUM_CELLS === 15'd16384,
"Frame-sync: NUM_CELLS == 16384 (512 range x 32 Doppler)");
// ════════════════════════════════════════════════════════
// TEST GROUP 2: Data packet word packing
//