fix(pre-bringup): resolve P0 + quick-win P1 findings from 2026-04-19 audit

Addresses findings from docs/DEVELOP_AUDIT_2026-04-19.md:

P0 source-level:
- F-4.3 ADAR1000_Manager::adarSetTxPhase now writes REG_LOAD_WORKING
  with LD_WRK_REGS_LDTX_OVERRIDE (0x02) instead of 0x01. Previous value
  toggled the LDRX latch on a TX-phase write, so host TX phase updates
  never reached the working registers.
- F-6.1 DDC mixer_saturation / filter_overflow / diagnostics were deleted
  at the receiver boundary. Now plumbed to new outputs on
  radar_receiver_final (ddc_overflow_any, ddc_saturation_count) and
  aggregated into gpio_dig5 in radar_system_top. Added mark_debug
  attributes for ILA visibility. Test/debug inputs tied low explicitly.
- F-0.8 adc_clk_mmcm.xdc set_clock_uncertainty: removed invalid -add
  flag (Vivado silently rejected it, applying zero guardband). Now uses
  absolute 0.150 ns which covers 53 ps jitter + ~100 ps PVT margin.

P1:
- F-4.2 adarSetBit / adarResetBit reject broadcast=ON — the RMW sampled
  a single device but wrote to all four, clobbering the other three's
  state.
- F-4.4 initializeSingleDevice returns false and leaves initialized=false
  when scratchpad verification fails; previously marked the device
  initialized anyway so downstream PA enable could drive a dead bus.
- F-6.2 FIR I/Q filter_overflow ports, previously unconnected, now OR'd
  into the module-level filter_overflow output.
- F-6.3 mti_canceller exposes 8-bit saturation counter. Saturation was
  previously invisible and produces spurious Doppler harmonics.

Verification:
- 27/27 iverilog testbenches pass
- 228/228 pytest pass (cross-layer contract + cosim)
- MCU unit tests 51/51 + 24/24 pass
- Remote Vivado 2025.2 build: bitstream writes; 400 MHz mixer pipeline
  now shows WNS -0.109 ns which MATCHES the audit's F-0.9 prediction
  that the design only closed because F-0.8's guardband was silently
  dropped. ft_clkout F-0.9 remains a show-stopper (requires MRCC pin
  move), tracked separately.

Not addressed in this PR (larger scope, follow-up tickets):
F-0.4, F-0.5, F-0.6, F-0.7, F-0.9, F-1.1, F-1.2, F-2.2, F-3.2, F-4.1,
F-4.7, F-6.4, F-6.5.
This commit is contained in:
Jason
2026-04-20 13:48:36 +05:45
parent c82b25f7a0
commit 3f47d1ef71
6 changed files with 190 additions and 92 deletions
+24 -7
View File
@@ -58,7 +58,12 @@ module mti_canceller #(
input wire mti_enable, // 1=MTI active, 0=pass-through
// ========== STATUS ==========
output reg mti_first_chirp // 1 during first chirp (output muted)
output reg mti_first_chirp, // 1 during first chirp (output muted)
// Audit F-6.3: count of saturated samples since last reset. Saturation
// here produces spurious Doppler harmonics (phantom targets at ±fs/2)
// and was previously invisible to the MCU. Saturates at 0xFF.
output reg [7:0] mti_saturation_count
);
// ============================================================================
@@ -104,18 +109,30 @@ assign diff_q_sat = (diff_q_full > $signed({{2{1'b0}}, {(DATA_WIDTH-1){1'b1}}}))
? $signed({1'b1, {(DATA_WIDTH-1){1'b0}}})
: diff_q_full[DATA_WIDTH-1:0];
// Saturation detection (F-6.3): the top two bits of the DATA_WIDTH+1 signed
// difference disagree iff the value exceeds the DATA_WIDTH signed range.
wire diff_i_overflow = (diff_i_full[DATA_WIDTH] != diff_i_full[DATA_WIDTH-1]);
wire diff_q_overflow = (diff_q_full[DATA_WIDTH] != diff_q_full[DATA_WIDTH-1]);
// ============================================================================
// MAIN LOGIC
// ============================================================================
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
range_i_out <= {DATA_WIDTH{1'b0}};
range_q_out <= {DATA_WIDTH{1'b0}};
range_valid_out <= 1'b0;
range_bin_out <= 6'd0;
has_previous <= 1'b0;
mti_first_chirp <= 1'b1;
range_i_out <= {DATA_WIDTH{1'b0}};
range_q_out <= {DATA_WIDTH{1'b0}};
range_valid_out <= 1'b0;
range_bin_out <= 6'd0;
has_previous <= 1'b0;
mti_first_chirp <= 1'b1;
mti_saturation_count <= 8'd0;
end else begin
// Count saturated MTI-active samples (F-6.3). Clamp at 0xFF.
if (range_valid_in && mti_enable && has_previous
&& (diff_i_overflow || diff_q_overflow)
&& (mti_saturation_count != 8'hFF)) begin
mti_saturation_count <= mti_saturation_count + 8'd1;
end
// Default: no valid output
range_valid_out <= 1'b0;