From 53c7f416a78a201d856083839743be8fab09f86c Mon Sep 17 00:00:00 2001 From: Jason <83615043+JJassonn69@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:09:28 +0545 Subject: [PATCH] cfar_ca: reset detect_count per frame (AUDIT-C6) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 16-bit detect_count was reset only on power-on; increments at three sites (ST_IDLE/ST_BUFFER simple-threshold paths and ST_CFAR_CMP) accumulate across frames. At 178 fps with even 2-3 average detections per frame the counter wraps in 100-180 seconds, breaking any rate-based host telemetry or health check that reads it. Fix: add `detect_count <= 16'd0` in ST_DONE so the counter represents "detections this frame" instead of cumulative-since-boot. Updated $display wording from "total detections" to "frame detections". T13 flipped from "count keeps growing" to "identical-scene frames produce identical counts" (the actual contract a per-frame counter must satisfy). TB snapshots detect_count during ST_DONE because cfar_busy only goes low on ST_IDLE entry — after the reset has fired. Verification: tb_cfar_ca 24/24 PASS, quick regression 31/31 PASS. Note: detect_count output port is now "live" (accumulates during frame, 0 between frames). Audit confirmed no current host telemetry consumes this port. If future host code needs a stable last-frame total, add a detect_count_last_frame snapshot register then. --- 9_Firmware/9_2_FPGA/cfar_ca.v | 10 ++++++++- 9_Firmware/9_2_FPGA/tb/tb_cfar_ca.v | 34 +++++++++++++++++++++++------ 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/9_Firmware/9_2_FPGA/cfar_ca.v b/9_Firmware/9_2_FPGA/cfar_ca.v index 3d59278..653bc4e 100644 --- a/9_Firmware/9_2_FPGA/cfar_ca.v +++ b/9_Firmware/9_2_FPGA/cfar_ca.v @@ -575,13 +575,21 @@ always @(posedge clk or negedge reset_n) begin // ================================================================ // ST_DONE: Frame complete, return to idle // ================================================================ + // AUDIT-C6 fix: reset detect_count per-frame so it represents + // "detections this frame" instead of "total since power-on". The + // 16-bit counter saturates after ~6500 frames at typical detection + // rates (tens of seconds of real traffic), breaking any rate-based + // host telemetry that reads it. + // ================================================================ ST_DONE: begin cfar_status <= 8'd0; state <= ST_IDLE; `ifdef SIMULATION - $display("[CFAR] Frame complete: %0d total detections", detect_count); + $display("[CFAR] Frame complete: %0d frame detections", detect_count); `endif + + detect_count <= 16'd0; end default: state <= ST_IDLE; diff --git a/9_Firmware/9_2_FPGA/tb/tb_cfar_ca.v b/9_Firmware/9_2_FPGA/tb/tb_cfar_ca.v index d4b180d..80212c8 100644 --- a/9_Firmware/9_2_FPGA/tb/tb_cfar_ca.v +++ b/9_Firmware/9_2_FPGA/tb/tb_cfar_ca.v @@ -19,7 +19,8 @@ * T10: Zero guard, zero train corner case * T11: Reset during processing → clean recovery * T12: Back-to-back frames → second frame processes correctly - * T13: detect_count accumulates across frames + * T13: detect_count resets per frame (AUDIT-C6 fix); identical-scene frames + * produce identical counts instead of cumulative-since-boot accumulation * T14: cfar_busy asserts during processing, deasserts after */ @@ -63,6 +64,16 @@ wire [15:0] detect_count; wire cfar_busy; wire [7:0] cfar_status; +// AUDIT-C6: detect_count is reset in ST_DONE before transitioning to +// ST_IDLE, so reads after wait_cfar_done (which returns when cfar_busy +// goes low at ST_IDLE) see 0. Snapshot the count whenever the FSM is in +// ST_DONE so T13 can verify per-frame counting. +reg [15:0] tb_detect_count_at_done; +always @(posedge clk) begin + if (dut.state == 4'd7 /* ST_DONE */) + tb_detect_count_at_done <= dut.detect_count; +end + // ============================================================================ // TEST TRACKING // ============================================================================ @@ -604,7 +615,8 @@ initial begin check(12, "T12: Back-to-back frame 2: target at (20,10) detected", find_detection(6'd20, 5'd10) == 1); // ================================================================ - // T13: detect_count accumulates + // T13: detect_count per-frame reset (AUDIT-C6) + // Identical-scene frames must produce identical counts (not cumulative). // ================================================================ test_num = 13; do_reset; @@ -623,16 +635,24 @@ initial begin wait_cfar_done(20000); begin : t13_save reg [15:0] count_after_frame1; - count_after_frame1 = detect_count; - $display(" [INFO] T13: detect_count after frame 1 = %0d", count_after_frame1); + // Use TB snapshot of detect_count at ST_DONE (live counter is reset + // before ST_IDLE so direct read returns 0). See tb_detect_count_at_done. + count_after_frame1 = tb_detect_count_at_done; + $display(" [INFO] T13: detect_count at frame 1 ST_DONE = %0d", count_after_frame1); - // Frame 2 (same target) + // Sanity: frame 1 produced at least one detection + check(13, "T13: frame 1 produced detections", count_after_frame1 > 16'd0); + + // Frame 2 (same target — should produce same per-frame count) feed_frame(16'd1000); pulse_frame_complete; wait_cfar_done(20000); - $display(" [INFO] T13: detect_count after frame 2 = %0d", detect_count); + $display(" [INFO] T13: detect_count at frame 2 ST_DONE = %0d", tb_detect_count_at_done); - check(13, "T13: detect_count increases after second frame", detect_count > count_after_frame1); + // AUDIT-C6 fix: per-frame counter, identical scene → identical count. + // Pre-fix this would have shown ~2x count_after_frame1 (cumulative). + check(13, "T13: detect_count resets per frame (==frame 1 count)", + tb_detect_count_at_done == count_after_frame1); end // ================================================================