fix(fpga): implement 5 P0 invariant fixes with adversarial testbenches
Fixes 5 critical cross-layer invariant violations found during system-level analysis. Each fix has a dedicated adversarial testbench that actively tries to break the fix under race conditions, reset mid-operation, overflow, and pathological input patterns. RTL fixes: - Fix #1: Replace flawed cdc_adc_to_processing with Gray-coded async FIFO (cdc_async_fifo) for DDC 400->100 MHz CDC path. Pre-fetch show-ahead architecture with CDC-safe registered reads. - Fix #2: XOR toggle detection for mc_new_chirp in matched filter (cross-clock-domain safe vs level-sensitive). - Fix #3: ST_WAIT_LISTEN state with configurable listen_delay to prevent matched filter re-trigger during chirp dead time. - Fix #4: Overlap-save output trim in matched filter to suppress circular convolution artifacts at segment boundaries. - Fix #7: Falling-edge frame_complete pulse in doppler_processor (was stuck high, causing continuous AGC resets). RTL cleanup: - Refactor CDC synchronizer arrays from memory arrays to scalar regs for explicit ASYNC_REG flop naming and synthesis constraint clarity. Testbenches (70 checks total, all passing): - tb_p0_async_fifo.v: 20 checks (fill, overflow, reset, streaming, show-ahead capacity, pathological data patterns) - tb_p0_mf_adversarial.v: 33 checks (toggle detection, listen state, overlap trim, rapid chirp sequences, reset recovery) - tb_p0_frame_pulse.v: 17 checks (pulse width, idle behavior, processing duration sweep, regression vs old stuck-high bug) Regression: 24/24 pass (--quick), 57/57 existing CDC tests pass. Golden references updated for doppler output timing change.
This commit is contained in:
@@ -584,41 +584,59 @@ cic_decimator_4x_enhanced cic_q_inst (
|
||||
assign cic_valid = cic_valid_i & cic_valid_q;
|
||||
|
||||
// ============================================================================
|
||||
// Enhanced FIR Filters with FIXED valid signal handling
|
||||
// NOTE: Wire declarations moved BEFORE CDC instances to fix forward-reference
|
||||
// error in Icarus Verilog (was originally after CDC instantiation)
|
||||
// Clock Domain Crossing: 400 MHz CIC output → 100 MHz FIR input
|
||||
// ============================================================================
|
||||
// The CIC decimates 4:1, producing one sample per 4 clk_400m cycles (~100 MSPS).
|
||||
// The FIR runs at clk_100m (100 MHz). The two clocks have unknown phase
|
||||
// relationship, so a proper asynchronous FIFO with Gray-coded pointers is
|
||||
// required. The old cdc_adc_to_processing module Gray-encoded the sample
|
||||
// DATA which is invalid (Gray encoding only guarantees single-bit transitions
|
||||
// for monotonically incrementing counters, not arbitrary sample values).
|
||||
//
|
||||
// Depth 8 provides margin: worst case, 2 samples can be in flight before
|
||||
// the read side pops, well within a depth-8 budget.
|
||||
// ============================================================================
|
||||
wire fir_in_valid_i, fir_in_valid_q;
|
||||
wire fir_valid_i, fir_valid_q;
|
||||
wire fir_i_ready, fir_q_ready;
|
||||
wire [17:0] fir_d_in_i, fir_d_in_q;
|
||||
wire [17:0] fir_d_in_i, fir_d_in_q;
|
||||
|
||||
cdc_adc_to_processing #(
|
||||
.WIDTH(18),
|
||||
.STAGES(3)
|
||||
)CDC_FIR_i(
|
||||
.src_clk(clk_400m),
|
||||
.dst_clk(clk_100m),
|
||||
.src_reset_n(reset_n_400m),
|
||||
.dst_reset_n(reset_n),
|
||||
.src_data(cic_i_out),
|
||||
.src_valid(cic_valid_i),
|
||||
.dst_data(fir_d_in_i),
|
||||
.dst_valid(fir_in_valid_i)
|
||||
// I-channel CDC: async FIFO, 400 MHz write → 100 MHz read
|
||||
cdc_async_fifo #(
|
||||
.WIDTH(18),
|
||||
.DEPTH(8),
|
||||
.ADDR_BITS(3)
|
||||
) CDC_FIR_i (
|
||||
.wr_clk(clk_400m),
|
||||
.wr_reset_n(reset_n_400m),
|
||||
.wr_data(cic_i_out),
|
||||
.wr_en(cic_valid_i),
|
||||
.wr_full(), // At 1:1 data rate, overflow should not occur
|
||||
|
||||
.rd_clk(clk_100m),
|
||||
.rd_reset_n(reset_n),
|
||||
.rd_data(fir_d_in_i),
|
||||
.rd_valid(fir_in_valid_i),
|
||||
.rd_ack(fir_in_valid_i) // Auto-pop: consume every valid sample
|
||||
);
|
||||
|
||||
cdc_adc_to_processing #(
|
||||
.WIDTH(18),
|
||||
.STAGES(3)
|
||||
)CDC_FIR_q(
|
||||
.src_clk(clk_400m),
|
||||
.dst_clk(clk_100m),
|
||||
.src_reset_n(reset_n_400m),
|
||||
.dst_reset_n(reset_n),
|
||||
.src_data(cic_q_out),
|
||||
.src_valid(cic_valid_q),
|
||||
.dst_data(fir_d_in_q),
|
||||
.dst_valid(fir_in_valid_q)
|
||||
// Q-channel CDC: async FIFO, 400 MHz write → 100 MHz read
|
||||
cdc_async_fifo #(
|
||||
.WIDTH(18),
|
||||
.DEPTH(8),
|
||||
.ADDR_BITS(3)
|
||||
) CDC_FIR_q (
|
||||
.wr_clk(clk_400m),
|
||||
.wr_reset_n(reset_n_400m),
|
||||
.wr_data(cic_q_out),
|
||||
.wr_en(cic_valid_q),
|
||||
.wr_full(),
|
||||
|
||||
.rd_clk(clk_100m),
|
||||
.rd_reset_n(reset_n),
|
||||
.rd_data(fir_d_in_q),
|
||||
.rd_valid(fir_in_valid_q),
|
||||
.rd_ack(fir_in_valid_q)
|
||||
);
|
||||
|
||||
// ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user