AUDIT-S19/S20/S21: replace fpga_self_test tautologies with real arithmetic

Pre-fix Tests 1/2/4 in fpga_self_test.v gave false PASS even on broken
silicon:

  S-19 Test 1 (CIC): `result_flags[1] <= 1'b1` unconditional, comment
       admitted "always true for simple check".
  S-20 Test 2 (FFT): `(16'sd100+16'sd100 == 16'sd200) && (...)` —
       both predicates compile-time-fold to 1; synth reduces to a
       constant write.
  S-21 Test 4 (ADC): PASS once N samples land, regardless of value.
       A stuck-at-0 / stuck-at-MAX / dead LVDS link still PASSed
       provided adc_valid_in toggled.

Fixes:

  Test 1: drive impulse {5,0,0,0,0,0,0} through registered integrator
          y[n]=y[n-1]+x[n]; require accumulator==5 after step
          response. Real adder + register path; sign-extension
          exercised. Detail = 0xC1 on fail.

  Test 2: real radix-2 butterfly with twiddle multiply across 4 FSM
          states. A=8, B=4 (real), W=2+3j -> WB=(8,12), A'=(16,12),
          B'=(0,-12). Forces synth to instantiate signed multiplier
          (DSP slice) + 17-bit signed add/sub. Detail = 0xF2 on fail.

  Test 4: track min/max across 256-sample capture, require
          (max - min) > ADC_RANGE_THRESHOLD (10 LSB). Catches stuck-at
          faults. Does NOT distinguish AD9484 format mismatches
          (audit's per-mode mean check requires SPI, impossible per
          AUDIT-C13). Detail = 0xAD on fail.

Tests:
- tb_fpga_self_test.v existing Group 1-4 (16 PASS) still pass: varied
  ADC counter input gives range >> 10.
- New Group 5: drive constant 0 -> expect Test 4 FAIL + detail=0xAD.
- New Group 6: drive constant 0x7FFF -> expect Test 4 FAIL + detail=0xAD.
- Regression: 41/41 PASS; fpga_self_test 22/22 (was 16/16).
This commit is contained in:
Jason
2026-04-29 23:27:15 +05:45
parent 9bed35287a
commit 853d2a5fd9
2 changed files with 193 additions and 35 deletions
+72 -3
View File
@@ -77,8 +77,12 @@ task check;
end
endtask
// ADC data generator: provides synthetic samples when capture is active
// ADC data generator: provides synthetic samples when capture is active.
// `adc_stuck_mode` (driven from main test) forces every sample to a constant
// value, exercising the AUDIT-S21 stuck-at detection path.
reg [15:0] adc_sample_cnt;
reg adc_stuck_mode; // 1 = drive constant adc_stuck_value
reg [15:0] adc_stuck_value;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
adc_data_in <= 16'd0;
@@ -89,7 +93,8 @@ always @(posedge clk or negedge reset_n) begin
// Provide a new ADC sample every 4 cycles (simulating 25 MHz sample rate)
adc_sample_cnt <= adc_sample_cnt + 1;
if (adc_sample_cnt[1:0] == 2'b11) begin
adc_data_in <= adc_sample_cnt[15:0];
adc_data_in <= adc_stuck_mode ? adc_stuck_value
: adc_sample_cnt[15:0];
adc_valid_in <= 1'b1;
end else begin
adc_valid_in <= 1'b0;
@@ -123,7 +128,9 @@ initial begin
pass_count = 0;
fail_count = 0;
trigger = 0;
trigger = 0;
adc_stuck_mode = 1'b0;
adc_stuck_value = 16'd0;
$display("");
$display("============================================================");
@@ -221,6 +228,68 @@ initial begin
check("Re-trigger completes", result_valid);
check("All pass on re-run", result_flags == 5'b11111);
// =====================================================================
// Group 5: AUDIT-S21 stuck-at ADC must FAIL Test 4
// =====================================================================
// Pre-fix Test 4 set result_flags[4] <= 1'b1 once N samples landed,
// regardless of value. Drive a constant ADC sample (stuck-at-0) and
// verify Test 4 now FAILs with result_detail == 0xAD.
$display("");
$display("--- Group 5: ADC Stuck-At Detection (AUDIT-S21) ---");
adc_stuck_mode = 1'b1;
adc_stuck_value = 16'd0;
repeat (10) @(posedge clk);
@(posedge clk);
trigger = 1;
@(posedge clk);
trigger = 0;
begin : wait_for_done3
integer i;
for (i = 0; i < 5000; i = i + 1) begin
@(posedge clk);
if (result_valid) begin
i = 5000;
end
end
end
check("Stuck ADC: result_valid", result_valid);
check("Stuck ADC: Tests 0-3 pass", result_flags[3:0] == 4'b1111);
check("Stuck ADC: Test 4 FAILS", !result_flags[4]);
check("Stuck ADC: detail=0xAD", result_detail == 8'hAD);
// =====================================================================
// Group 6: AUDIT-S21 stuck-at-MAX (different stuck value) must also FAIL
// =====================================================================
$display("");
$display("--- Group 6: ADC Stuck-At-MAX Detection (AUDIT-S21) ---");
adc_stuck_mode = 1'b1;
adc_stuck_value = 16'h7FFF; // stuck high
repeat (10) @(posedge clk);
@(posedge clk);
trigger = 1;
@(posedge clk);
trigger = 0;
begin : wait_for_done4
integer i;
for (i = 0; i < 5000; i = i + 1) begin
@(posedge clk);
if (result_valid) begin
i = 5000;
end
end
end
check("Stuck-MAX: Test 4 FAILS", !result_flags[4]);
check("Stuck-MAX: detail=0xAD", result_detail == 8'hAD);
// Restore varied-sample mode
adc_stuck_mode = 1'b0;
// =====================================================================
// Summary
// =====================================================================