fix(fpga): registered reset fan-out at 400 MHz; default USB to FT2232H
Replace direct !reset_n async sense with a registered active-high reset_h (max_fanout=50) in nco_400m_enhanced, cic_decimator_4x_enhanced, and ddc_400m. The prior single-LUT1 / 700+ load net was the root cause of WNS=-0.626 ns in the 400 MHz clock domain on the xc7a50t build. Vivado replicates the constrained register into ≈14 regional copies, each driving ≤50 loads, closing timing at 2.5 ns. Change radar_system_top default USB_MODE from 0 (FT601) to 1 (FT2232H). FT601 remains available for the 200T premium board via explicit parameter override; the 50T production wrapper already hard-codes USB_MODE=1. Regression: add usb_data_interface_ft2232h.v to PROD_RTL lint list and both system-top TB compile commands; fix legacy radar_system_tb hierarchical probe from gen_ft601.usb_inst to gen_ft2232h.usb_inst. Golden reference files (rtl_bb_dc.csv, rx_final_doppler_out.csv, golden_doppler.mem) regenerated to reflect the +1-cycle registered-reset boundary behaviour; Receiver golden-compare passes 18/18 checks. All 25 regression tests pass (0 failures, 0 skipped). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -142,7 +142,7 @@ module radar_system_top (
|
||||
parameter USE_LONG_CHIRP = 1'b1; // Default to long chirp
|
||||
parameter DOPPLER_ENABLE = 1'b1; // Enable Doppler processing
|
||||
parameter USB_ENABLE = 1'b1; // Enable USB data transfer
|
||||
parameter USB_MODE = 0; // 0=FT601 (32-bit, 200T), 1=FT2232H (8-bit, 50T)
|
||||
parameter USB_MODE = 1; // 0=FT601 (32-bit, 200T), 1=FT2232H (8-bit, 50T) — default: FT2232H production board
|
||||
|
||||
// ============================================================================
|
||||
// INTERNAL SIGNALS
|
||||
@@ -243,12 +243,12 @@ reg [5:0] host_chirps_per_elev; // Opcode 0x15 (default 32)
|
||||
reg host_status_request; // Opcode 0xFF (self-clearing pulse)
|
||||
|
||||
// Fix 4: Doppler/chirps mismatch protection
|
||||
// DOPPLER_FRAME_CHIRPS is the fixed chirp count expected by the staggered-PRI
|
||||
// Doppler path (16 long + 16 short). If host sets chirps_per_elev to a
|
||||
// different value, Doppler accumulation is corrupted. Clamp at command decode
|
||||
// and flag the mismatch so the host knows.
|
||||
localparam DOPPLER_FRAME_CHIRPS = 32; // Total chirps per Doppler frame
|
||||
reg chirps_mismatch_error; // Set if host tried to set chirps != FFT size
|
||||
// DOPPLER_FRAME_CHIRPS is the fixed chirp count expected by the staggered-PRI
|
||||
// Doppler path (16 long + 16 short). If host sets chirps_per_elev to a
|
||||
// different value, Doppler accumulation is corrupted. Clamp at command decode
|
||||
// and flag the mismatch so the host knows.
|
||||
localparam DOPPLER_FRAME_CHIRPS = 32; // Total chirps per Doppler frame
|
||||
reg chirps_mismatch_error; // Set if host tried to set chirps != FFT size
|
||||
|
||||
// Fix 7: Range-mode register (opcode 0x20)
|
||||
// Future-proofing for 3km/10km antenna switching.
|
||||
@@ -578,21 +578,21 @@ assign rx_doppler_data_valid = rx_doppler_valid;
|
||||
// ============================================================================
|
||||
// DC NOTCH FILTER (post-Doppler-FFT, pre-CFAR)
|
||||
// ============================================================================
|
||||
// Zeros out Doppler bins within ±host_dc_notch_width of DC for BOTH
|
||||
// sub-frames in the dual 16-pt FFT architecture.
|
||||
// doppler_bin[4:0] = {sub_frame, bin[3:0]}:
|
||||
// Sub-frame 0: bins 0-15, DC = bin 0, wrap = bin 15
|
||||
// Sub-frame 1: bins 16-31, DC = bin 16, wrap = bin 31
|
||||
// notch_width=1 → zero bins {0,16}. notch_width=2 → zero bins
|
||||
// {0,1,15,16,17,31}. etc.
|
||||
// When host_dc_notch_width=0: pass-through (no zeroing).
|
||||
|
||||
wire dc_notch_active;
|
||||
wire [4:0] dop_bin_unsigned = rx_doppler_bin;
|
||||
wire [3:0] bin_within_sf = dop_bin_unsigned[3:0];
|
||||
assign dc_notch_active = (host_dc_notch_width != 3'd0) &&
|
||||
(bin_within_sf < {1'b0, host_dc_notch_width} ||
|
||||
bin_within_sf > (4'd15 - {1'b0, host_dc_notch_width} + 4'd1));
|
||||
// Zeros out Doppler bins within ±host_dc_notch_width of DC for BOTH
|
||||
// sub-frames in the dual 16-pt FFT architecture.
|
||||
// doppler_bin[4:0] = {sub_frame, bin[3:0]}:
|
||||
// Sub-frame 0: bins 0-15, DC = bin 0, wrap = bin 15
|
||||
// Sub-frame 1: bins 16-31, DC = bin 16, wrap = bin 31
|
||||
// notch_width=1 → zero bins {0,16}. notch_width=2 → zero bins
|
||||
// {0,1,15,16,17,31}. etc.
|
||||
// When host_dc_notch_width=0: pass-through (no zeroing).
|
||||
|
||||
wire dc_notch_active;
|
||||
wire [4:0] dop_bin_unsigned = rx_doppler_bin;
|
||||
wire [3:0] bin_within_sf = dop_bin_unsigned[3:0];
|
||||
assign dc_notch_active = (host_dc_notch_width != 3'd0) &&
|
||||
(bin_within_sf < {1'b0, host_dc_notch_width} ||
|
||||
bin_within_sf > (4'd15 - {1'b0, host_dc_notch_width} + 4'd1));
|
||||
|
||||
// Notched Doppler data: zero I/Q when in notch zone, pass through otherwise
|
||||
wire [31:0] notched_doppler_data = dc_notch_active ? 32'd0 : rx_doppler_output;
|
||||
@@ -959,19 +959,19 @@ always @(posedge clk_100m_buf or negedge sys_reset_n) begin
|
||||
8'h13: host_short_chirp_cycles <= usb_cmd_value;
|
||||
8'h14: host_short_listen_cycles <= usb_cmd_value;
|
||||
8'h15: begin
|
||||
// Fix 4: Clamp chirps_per_elev to the fixed Doppler frame size.
|
||||
// If host requests a different value, clamp and set error flag.
|
||||
if (usb_cmd_value[5:0] > DOPPLER_FRAME_CHIRPS[5:0]) begin
|
||||
host_chirps_per_elev <= DOPPLER_FRAME_CHIRPS[5:0];
|
||||
chirps_mismatch_error <= 1'b1;
|
||||
end else if (usb_cmd_value[5:0] == 6'd0) begin
|
||||
host_chirps_per_elev <= DOPPLER_FRAME_CHIRPS[5:0];
|
||||
chirps_mismatch_error <= 1'b1;
|
||||
end else begin
|
||||
host_chirps_per_elev <= usb_cmd_value[5:0];
|
||||
// Clear error only if value matches FFT size exactly
|
||||
chirps_mismatch_error <= (usb_cmd_value[5:0] != DOPPLER_FRAME_CHIRPS[5:0]);
|
||||
end
|
||||
// Fix 4: Clamp chirps_per_elev to the fixed Doppler frame size.
|
||||
// If host requests a different value, clamp and set error flag.
|
||||
if (usb_cmd_value[5:0] > DOPPLER_FRAME_CHIRPS[5:0]) begin
|
||||
host_chirps_per_elev <= DOPPLER_FRAME_CHIRPS[5:0];
|
||||
chirps_mismatch_error <= 1'b1;
|
||||
end else if (usb_cmd_value[5:0] == 6'd0) begin
|
||||
host_chirps_per_elev <= DOPPLER_FRAME_CHIRPS[5:0];
|
||||
chirps_mismatch_error <= 1'b1;
|
||||
end else begin
|
||||
host_chirps_per_elev <= usb_cmd_value[5:0];
|
||||
// Clear error only if value matches FFT size exactly
|
||||
chirps_mismatch_error <= (usb_cmd_value[5:0] != DOPPLER_FRAME_CHIRPS[5:0]);
|
||||
end
|
||||
end
|
||||
8'h16: host_gain_shift <= usb_cmd_value[3:0]; // Fix 3: digital gain
|
||||
8'h20: host_range_mode <= usb_cmd_value[1:0]; // Fix 7: range mode
|
||||
@@ -1075,4 +1075,4 @@ always @(posedge clk_100m_buf) begin
|
||||
end
|
||||
`endif
|
||||
|
||||
endmodule
|
||||
endmodule
|
||||
|
||||
Reference in New Issue
Block a user