Fix 6 RTL files + add xfft_32 stub for successful Vivado synthesis

Resolves all synthesis errors across attempts 3-11, achieving clean
Vivado 2025.2 synthesis on XC7A100T (0 errors, 831 LUTs, 320 FFs, 2 DSPs).

radar_receiver_final.v:
- reg clk_400m -> wire; output reg -> output wire (x4)
- Replace ad9484_lvds_to_cmos_400m with ad9484_interface_400m
- Remove duplicate IBUFDS lvds_to_cmos_400m instantiation
- Remove non-existent ref_i/ref_q port connections on matched filter
- Connect adc_dco_bufg as 400MHz clock source

ad9484_interface_400m.v:
- Add adc_dco_bufg output port with BUFG instance
- Route all internal logic through buffered DCO clock

cic_decimator_4x_enhanced.v:
- Move reset_monitors handling inside else branch (fixes Vivado
  ambiguous clock error in both integrator and comb always blocks)
- Add separate comb_overflow_latched/comb_saturation_detected regs
  to eliminate multi-driven nets between integrator and comb blocks
- Remove standalone always @(posedge reset_monitors) block
- Add output_counter to async reset branch

matched_filter_processing_chain.v:
- Wrap behavioral FFT body (uses $cos/$sin/$rtoi) in ifdef SIMULATION
- Add synthesis stub tying outputs to safe defaults

chirp_memory_loader_param.v:
- Replace hardcoded Windows paths with relative filenames for all
  10 $readmem default parameters

latency_buffer_2159.v:
- Split single always block into separate BRAM write (synchronous
  only) and control logic (with async reset) blocks
- Fixes Vivado Synth 8-3391: BRAM cannot infer with async reset

xfft_32.v (NEW):
- Synthesis stub for Xilinx 32-point FFT IP core
- AXI-Stream interface with pass-through and 1-cycle latency
- Placeholder until real xfft IP is generated
This commit is contained in:
Jason
2026-03-15 17:37:59 +02:00
parent c871281f1e
commit eefaf94e9e
7 changed files with 407 additions and 321 deletions
+12 -3
View File
@@ -11,7 +11,8 @@ module ad9484_interface_400m (
// Output at 400MHz domain // Output at 400MHz domain
output wire [7:0] adc_data_400m, // ADC data at 400MHz output wire [7:0] adc_data_400m, // ADC data at 400MHz
output wire adc_data_valid_400m // Valid at 400MHz output wire adc_data_valid_400m, // Valid at 400MHz
output wire adc_dco_bufg // Buffered 400MHz DCO clock for downstream use
); );
// LVDS to single-ended conversion // LVDS to single-ended conversion
@@ -43,6 +44,14 @@ IBUFDS #(
.IB(adc_dco_n) .IB(adc_dco_n)
); );
// Global clock buffer for DCO — used as 400MHz clock throughout receiver
wire adc_dco_buffered;
BUFG bufg_dco (
.I(adc_dco),
.O(adc_dco_buffered)
);
assign adc_dco_bufg = adc_dco_buffered;
// IDDR for capturing DDR data // IDDR for capturing DDR data
wire [7:0] adc_data_rise; // Data on rising edge wire [7:0] adc_data_rise; // Data on rising edge
wire [7:0] adc_data_fall; // Data on falling edge wire [7:0] adc_data_fall; // Data on falling edge
@@ -58,7 +67,7 @@ generate
) iddr_inst ( ) iddr_inst (
.Q1(adc_data_rise[j]), // Rising edge data .Q1(adc_data_rise[j]), // Rising edge data
.Q2(adc_data_fall[j]), // Falling edge data .Q2(adc_data_fall[j]), // Falling edge data
.C(adc_dco), // 400MHz DCO .C(adc_dco_buffered), // 400MHz DCO (buffered)
.CE(1'b1), .CE(1'b1),
.D(adc_data[j]), .D(adc_data[j]),
.R(1'b0), .R(1'b0),
@@ -72,7 +81,7 @@ reg [7:0] adc_data_400m_reg;
reg adc_data_valid_400m_reg; reg adc_data_valid_400m_reg;
reg dco_phase; reg dco_phase;
always @(posedge adc_dco or negedge reset_n) begin always @(posedge adc_dco_buffered or negedge reset_n) begin
if (!reset_n) begin if (!reset_n) begin
adc_data_400m_reg <= 8'b0; adc_data_400m_reg <= 8'b0;
adc_data_valid_400m_reg <= 1'b0; adc_data_valid_400m_reg <= 1'b0;
+10 -10
View File
@@ -1,15 +1,15 @@
`timescale 1ns / 1ps `timescale 1ns / 1ps
module chirp_memory_loader_param #( module chirp_memory_loader_param #(
parameter LONG_I_FILE_SEG0 = "C:/Users/dell/Desktop/ASUS/RADAR_V5/Firmware/FPGA/PLFM_RADAR_Xilinx_ISE_V2/Python/mem_files/fpga_mem_files/long_chirp_seg0_i.mem", parameter LONG_I_FILE_SEG0 = "long_chirp_seg0_i.mem",
parameter LONG_Q_FILE_SEG0 = "C:/Users/dell/Desktop/ASUS/RADAR_V5/Firmware/FPGA/PLFM_RADAR_Xilinx_ISE_V2/Python/mem_files/fpga_mem_files/long_chirp_seg0_q.mem", parameter LONG_Q_FILE_SEG0 = "long_chirp_seg0_q.mem",
parameter LONG_I_FILE_SEG1 = "C:/Users/dell/Desktop/ASUS/RADAR_V5/Firmware/FPGA/PLFM_RADAR_Xilinx_ISE_V2/Python/mem_files/fpga_mem_files/long_chirp_seg1_i.mem", parameter LONG_I_FILE_SEG1 = "long_chirp_seg1_i.mem",
parameter LONG_Q_FILE_SEG1 = "C:/Users/dell/Desktop/ASUS/RADAR_V5/Firmware/FPGA/PLFM_RADAR_Xilinx_ISE_V2/Python/mem_files/fpga_mem_files/long_chirp_seg1_q.mem", parameter LONG_Q_FILE_SEG1 = "long_chirp_seg1_q.mem",
parameter LONG_I_FILE_SEG2 = "C:/Users/dell/Desktop/ASUS/RADAR_V5/Firmware/FPGA/PLFM_RADAR_Xilinx_ISE_V2/Python/mem_files/fpga_mem_files/long_chirp_seg2_i.mem", parameter LONG_I_FILE_SEG2 = "long_chirp_seg2_i.mem",
parameter LONG_Q_FILE_SEG2 = "C:/Users/dell/Desktop/ASUS/RADAR_V5/Firmware/FPGA/PLFM_RADAR_Xilinx_ISE_V2/Python/mem_files/fpga_mem_files/long_chirp_seg2_q.mem", parameter LONG_Q_FILE_SEG2 = "long_chirp_seg2_q.mem",
parameter LONG_I_FILE_SEG3 = "C:/Users/dell/Desktop/ASUS/RADAR_V5/Firmware/FPGA/PLFM_RADAR_Xilinx_ISE_V2/Python/mem_files/fpga_mem_files/long_chirp_seg3_i.mem", parameter LONG_I_FILE_SEG3 = "long_chirp_seg3_i.mem",
parameter LONG_Q_FILE_SEG3 = "C:/Users/dell/Desktop/ASUS/RADAR_V5/Firmware/FPGA/PLFM_RADAR_Xilinx_ISE_V2/Python/mem_files/fpga_mem_files/long_chirp_seg3_q.mem", parameter LONG_Q_FILE_SEG3 = "long_chirp_seg3_q.mem",
parameter SHORT_I_FILE = "C:/Users/dell/Desktop/ASUS/RADAR_V5/Firmware/FPGA/PLFM_RADAR_Xilinx_ISE_V2/Python/mem_files/fpga_mem_files/short_chirp_i.mem", parameter SHORT_I_FILE = "short_chirp_i.mem",
parameter SHORT_Q_FILE = "C:/Users/dell/Desktop/ASUS/RADAR_V5/Firmware/FPGA/PLFM_RADAR_Xilinx_ISE_V2/Python/mem_files/fpga_mem_files/short_chirp_q.mem", parameter SHORT_Q_FILE = "short_chirp_q.mem",
parameter DEBUG = 1 parameter DEBUG = 1
)( )(
input wire clk, input wire clk,
+215 -221
View File
@@ -29,9 +29,14 @@ reg [35:0] max_integrator_value;
reg overflow_detected; reg overflow_detected;
reg overflow_latched; // Latched overflow indicator reg overflow_latched; // Latched overflow indicator
// Diagnostic registers // Diagnostic registers
reg [7:0] saturation_event_count; reg [7:0] saturation_event_count;
reg [31:0] sample_count; reg [31:0] sample_count;
// Comb-stage saturation flags (separate from integrator block to avoid multi-driven nets)
reg comb_overflow_latched;
reg comb_saturation_detected;
reg [7:0] comb_saturation_event_count;
// Temporary signals for calculations // Temporary signals for calculations
reg signed [35:0] abs_integrator_value; reg signed [35:0] abs_integrator_value;
@@ -63,113 +68,108 @@ initial begin
data_out = 0; data_out = 0;
data_out_valid = 0; data_out_valid = 0;
abs_integrator_value = 0; abs_integrator_value = 0;
temp_scaled_output = 0; temp_scaled_output = 0;
temp_output = 0; temp_output = 0;
comb_overflow_latched = 0;
comb_saturation_detected = 0;
comb_saturation_event_count = 0;
end end
// Enhanced integrator section with proper saturation monitoring // Enhanced integrator section with proper saturation monitoring
always @(posedge clk or negedge reset_n) begin always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin if (!reset_n) begin
for (i = 0; i < STAGES; i = i + 1) begin for (i = 0; i < STAGES; i = i + 1) begin
integrator[i] <= 0; integrator[i] <= 0;
end end
decimation_counter <= 0; decimation_counter <= 0;
data_valid_delayed <= 0; data_valid_delayed <= 0;
data_valid_comb <= 0; max_integrator_value <= 0;
max_integrator_value <= 0; overflow_detected <= 0;
overflow_detected <= 0; sample_count <= 0;
sample_count <= 0; abs_integrator_value <= 0;
abs_integrator_value <= 0; overflow_latched <= 0;
saturation_detected <= 0;
if (reset_monitors) begin saturation_event_count <= 0;
overflow_latched <= 0; max_value_monitor <= 0;
saturation_detected <= 0; output_counter <= 0;
saturation_event_count <= 0; end else begin
max_value_monitor <= 0; // Monitor control - clear latched saturation on reset_monitors
end // (must be inside else branch so Vivado sees a clean async-reset FF template)
end else if (data_valid) begin if (reset_monitors) begin
sample_count <= sample_count + 1; overflow_latched <= 0;
saturation_detected <= 0;
// First integrator stage with enhanced saturation detection max_integrator_value <= 0;
if (integrator[0] + $signed({{18{data_in[17]}}, data_in}) > (2**35 - 1)) begin max_value_monitor <= 0;
integrator[0] <= (2**35 - 1); saturation_event_count <= 0;
overflow_detected <= 1'b1; end
overflow_latched <= 1'b1;
saturation_detected <= 1'b1; if (data_valid) begin
saturation_event_count <= saturation_event_count + 1; sample_count <= sample_count + 1;
`ifdef SIMULATION
$display("CIC_SATURATION: Positive overflow at sample %0d", sample_count); // First integrator stage with enhanced saturation detection
`endif if (integrator[0] + $signed({{18{data_in[17]}}, data_in}) > (2**35 - 1)) begin
end else if (integrator[0] + $signed({{18{data_in[17]}}, data_in}) < -(2**35)) begin integrator[0] <= (2**35 - 1);
integrator[0] <= -(2**35); overflow_detected <= 1'b1;
overflow_detected <= 1'b1; overflow_latched <= 1'b1;
overflow_latched <= 1'b1; saturation_detected <= 1'b1;
saturation_detected <= 1'b1; saturation_event_count <= saturation_event_count + 1;
saturation_event_count <= saturation_event_count + 1; `ifdef SIMULATION
`ifdef SIMULATION $display("CIC_SATURATION: Positive overflow at sample %0d", sample_count);
$display("CIC_SATURATION: Negative overflow at sample %0d", sample_count); `endif
`endif end else if (integrator[0] + $signed({{18{data_in[17]}}, data_in}) < -(2**35)) begin
end else begin integrator[0] <= -(2**35);
integrator[0] <= integrator[0] + $signed({{18{data_in[17]}}, data_in}); overflow_detected <= 1'b1;
overflow_detected <= 1'b0; // Only clear immediate detection, not latched overflow_latched <= 1'b1;
end saturation_detected <= 1'b1;
saturation_event_count <= saturation_event_count + 1;
// Calculate absolute value for monitoring `ifdef SIMULATION
abs_integrator_value <= (integrator[0][35]) ? -integrator[0] : integrator[0]; $display("CIC_SATURATION: Negative overflow at sample %0d", sample_count);
`endif
// Track maximum integrator value for gain monitoring (absolute value) end else begin
if (abs_integrator_value > max_integrator_value) begin integrator[0] <= integrator[0] + $signed({{18{data_in[17]}}, data_in});
max_integrator_value <= abs_integrator_value; overflow_detected <= 1'b0; // Only clear immediate detection, not latched
max_value_monitor <= abs_integrator_value[31:24]; // Fixed: use the calculated absolute value
end
// Remaining integrator stages with saturation protection
for (i = 1; i < STAGES; i = i + 1) begin
if (integrator[i] + integrator[i-1] > (2**35 - 1)) begin
integrator[i] <= (2**35 - 1);
overflow_detected <= 1'b1;
overflow_latched <= 1'b1;
saturation_detected <= 1'b1;
end else if (integrator[i] + integrator[i-1] < -(2**35)) begin
integrator[i] <= -(2**35);
overflow_detected <= 1'b1;
overflow_latched <= 1'b1;
saturation_detected <= 1'b1;
end else begin
integrator[i] <= integrator[i] + integrator[i-1];
end
end
// Enhanced decimation control
if (decimation_counter == DECIMATION - 1) begin
decimation_counter <= 0;
data_valid_delayed <= 1;
output_counter <= output_counter + 1;
/*// Debug output for first few samples
if (output_counter < 10) begin
$display("CIC_DECIM: sample=%0d, integrator[%0d]=%h, max_val=%h, sat=%b",
output_counter, STAGES-1, integrator[STAGES-1],
max_integrator_value, saturation_detected);
end end
*/
end else begin // Calculate absolute value for monitoring
decimation_counter <= decimation_counter + 1; abs_integrator_value <= (integrator[0][35]) ? -integrator[0] : integrator[0];
data_valid_delayed <= 0;
end // Track maximum integrator value for gain monitoring (absolute value)
end else begin if (abs_integrator_value > max_integrator_value) begin
data_valid_delayed <= 0; max_integrator_value <= abs_integrator_value;
overflow_detected <= 1'b0; // Clear immediate detection when no data max_value_monitor <= abs_integrator_value[31:24];
end end
// Monitor control - clear latched saturation on reset_monitors // Remaining integrator stages with saturation protection
if (reset_monitors) begin for (i = 1; i < STAGES; i = i + 1) begin
overflow_latched <= 0; if (integrator[i] + integrator[i-1] > (2**35 - 1)) begin
saturation_detected <= 0; integrator[i] <= (2**35 - 1);
max_integrator_value <= 0; overflow_detected <= 1'b1;
max_value_monitor <= 0; overflow_latched <= 1'b1;
saturation_event_count <= 0; saturation_detected <= 1'b1;
end end else if (integrator[i] + integrator[i-1] < -(2**35)) begin
integrator[i] <= -(2**35);
overflow_detected <= 1'b1;
overflow_latched <= 1'b1;
saturation_detected <= 1'b1;
end else begin
integrator[i] <= integrator[i] + integrator[i-1];
end
end
// Enhanced decimation control
if (decimation_counter == DECIMATION - 1) begin
decimation_counter <= 0;
data_valid_delayed <= 1;
output_counter <= output_counter + 1;
end else begin
decimation_counter <= decimation_counter + 1;
data_valid_delayed <= 0;
end
end else begin
data_valid_delayed <= 0;
overflow_detected <= 1'b0; // Clear immediate detection when no data
end
end
end end
// Pipeline the valid signal for comb section // Pipeline the valid signal for comb section
@@ -181,111 +181,112 @@ always @(posedge clk or negedge reset_n) begin
end end
end end
// Enhanced comb section with FIXED scaling and saturation monitoring // Enhanced comb section with FIXED scaling and saturation monitoring
always @(posedge clk or negedge reset_n) begin always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin if (!reset_n) begin
for (i = 0; i < STAGES; i = i + 1) begin for (i = 0; i < STAGES; i = i + 1) begin
comb[i] <= 0; comb[i] <= 0;
for (j = 0; j < COMB_DELAY; j = j + 1) begin for (j = 0; j < COMB_DELAY; j = j + 1) begin
comb_delay[i][j] <= 0; comb_delay[i][j] <= 0;
end end
end end
data_out <= 0; data_out <= 0;
data_out_valid <= 0; data_out_valid <= 0;
temp_scaled_output <= 0; temp_scaled_output <= 0;
temp_output <= 0; temp_output <= 0;
end else if (data_valid_comb) begin comb_overflow_latched <= 0;
// Enhanced comb processing with saturation check comb_saturation_detected <= 0;
for (i = 0; i < STAGES; i = i + 1) begin comb_saturation_event_count <= 0;
if (i == 0) begin end else begin
// Check for comb stage saturation // Monitor control - clear latched comb saturation on reset_monitors
if (integrator[STAGES-1] - comb_delay[0][COMB_DELAY-1] > (2**35 - 1)) begin // (inside else branch so Vivado sees clean async-reset FF template)
comb[0] <= (2**35 - 1); if (reset_monitors) begin
overflow_latched <= 1'b1; comb_overflow_latched <= 0;
saturation_detected <= 1'b1; comb_saturation_detected <= 0;
end else if (integrator[STAGES-1] - comb_delay[0][COMB_DELAY-1] < -(2**35)) begin comb_saturation_event_count <= 0;
comb[0] <= -(2**35); end
overflow_latched <= 1'b1;
saturation_detected <= 1'b1; if (data_valid_comb) begin
end else begin // Enhanced comb processing with saturation check
comb[0] <= integrator[STAGES-1] - comb_delay[0][COMB_DELAY-1]; for (i = 0; i < STAGES; i = i + 1) begin
end if (i == 0) begin
// Check for comb stage saturation
// Update delay line for first stage if (integrator[STAGES-1] - comb_delay[0][COMB_DELAY-1] > (2**35 - 1)) begin
for (j = COMB_DELAY-1; j > 0; j = j - 1) begin comb[0] <= (2**35 - 1);
comb_delay[0][j] <= comb_delay[0][j-1]; comb_overflow_latched <= 1'b1;
end comb_saturation_detected <= 1'b1;
comb_delay[0][0] <= integrator[STAGES-1]; end else if (integrator[STAGES-1] - comb_delay[0][COMB_DELAY-1] < -(2**35)) begin
end else begin comb[0] <= -(2**35);
// Check for comb stage saturation comb_overflow_latched <= 1'b1;
if (comb[i-1] - comb_delay[i][COMB_DELAY-1] > (2**35 - 1)) begin comb_saturation_detected <= 1'b1;
comb[i] <= (2**35 - 1); end else begin
overflow_latched <= 1'b1; comb[0] <= integrator[STAGES-1] - comb_delay[0][COMB_DELAY-1];
saturation_detected <= 1'b1; end
end else if (comb[i-1] - comb_delay[i][COMB_DELAY-1] < -(2**35)) begin
comb[i] <= -(2**35); // Update delay line for first stage
overflow_latched <= 1'b1; for (j = COMB_DELAY-1; j > 0; j = j - 1) begin
saturation_detected <= 1'b1; comb_delay[0][j] <= comb_delay[0][j-1];
end else begin end
comb[i] <= comb[i-1] - comb_delay[i][COMB_DELAY-1]; comb_delay[0][0] <= integrator[STAGES-1];
end end else begin
// Check for comb stage saturation
// Update delay line if (comb[i-1] - comb_delay[i][COMB_DELAY-1] > (2**35 - 1)) begin
for (j = COMB_DELAY-1; j > 0; j = j - 1) begin comb[i] <= (2**35 - 1);
comb_delay[i][j] <= comb_delay[i][j-1]; comb_overflow_latched <= 1'b1;
end comb_saturation_detected <= 1'b1;
comb_delay[i][0] <= comb[i-1]; end else if (comb[i-1] - comb_delay[i][COMB_DELAY-1] < -(2**35)) begin
end comb[i] <= -(2**35);
end comb_overflow_latched <= 1'b1;
comb_saturation_detected <= 1'b1;
// FIXED: Use proper scaling for 5 stages and decimation by 4 end else begin
// Gain = (4^5) = 1024 = 2^10, so scale by 2^10 to normalize comb[i] <= comb[i-1] - comb_delay[i][COMB_DELAY-1];
temp_scaled_output <= comb[STAGES-1] >>> 10; end
// FIXED: Extract 18-bit output properly // Update delay line
temp_output <= temp_scaled_output[17:0]; for (j = COMB_DELAY-1; j > 0; j = j - 1) begin
comb_delay[i][j] <= comb_delay[i][j-1];
// FIXED: Proper saturation detection for 18-bit signed range end
// Check if the 18-bit truncated value matches the intended value comb_delay[i][0] <= comb[i-1];
if (temp_scaled_output > 131071) begin // 2^17 - 1 end
data_out <= 131071; end
overflow_latched <= 1'b1;
saturation_detected <= 1'b1; // FIXED: Use proper scaling for 5 stages and decimation by 4
saturation_event_count <= saturation_event_count + 1; // Gain = (4^5) = 1024 = 2^10, so scale by 2^10 to normalize
`ifdef SIMULATION temp_scaled_output <= comb[STAGES-1] >>> 10;
$display("CIC_OUTPUT_SAT: TRUE Positive saturation, raw=%h, scaled=%h, temp_out=%d, final_out=%d",
comb[STAGES-1], temp_scaled_output, temp_output, 131071); // FIXED: Extract 18-bit output properly
`endif temp_output <= temp_scaled_output[17:0];
end else if (temp_scaled_output < -131072) begin // -2^17
data_out <= -131072; // FIXED: Proper saturation detection for 18-bit signed range
overflow_latched <= 1'b1; if (temp_scaled_output > 131071) begin // 2^17 - 1
saturation_detected <= 1'b1; data_out <= 131071;
saturation_event_count <= saturation_event_count + 1; comb_overflow_latched <= 1'b1;
`ifdef SIMULATION comb_saturation_detected <= 1'b1;
$display("CIC_OUTPUT_SAT: TRUE Negative saturation, raw=%h, scaled=%h, temp_out=%d, final_out=%d", comb_saturation_event_count <= comb_saturation_event_count + 1;
comb[STAGES-1], temp_scaled_output, temp_output, -131072); `ifdef SIMULATION
`endif $display("CIC_OUTPUT_SAT: TRUE Positive saturation, raw=%h, scaled=%h, temp_out=%d, final_out=%d",
end else begin comb[STAGES-1], temp_scaled_output, temp_output, 131071);
// FIXED: Use the properly truncated 18-bit value `endif
data_out <= temp_output; end else if (temp_scaled_output < -131072) begin // -2^17
overflow_latched <= 1'b0; data_out <= -131072;
saturation_detected <= 1'b0; comb_overflow_latched <= 1'b1;
if (output_counter < 20) begin comb_saturation_detected <= 1'b1;
//$display("CIC_OUTPUT_GOOD: raw=%h, scaled=%h, temp_out=%d, final_out=%d", comb_saturation_event_count <= comb_saturation_event_count + 1;
// comb[STAGES-1], temp_scaled_output, temp_output, data_out); `ifdef SIMULATION
end $display("CIC_OUTPUT_SAT: TRUE Negative saturation, raw=%h, scaled=%h, temp_out=%d, final_out=%d",
end comb[STAGES-1], temp_scaled_output, temp_output, -131072);
`endif
data_out_valid <= 1; end else begin
data_out <= temp_output;
// Debug output for first samples comb_overflow_latched <= 1'b0;
if (output_counter < 10) begin comb_saturation_detected <= 1'b0;
// $display("CIC_DEBUG: sample=%0d, raw=%h, scaled=%h, out=%d, sat=%b", end
// output_counter, comb[STAGES-1], temp_scaled_output, data_out, saturation_detected);
end data_out_valid <= 1;
end else begin end else begin
data_out_valid <= 0; data_out_valid <= 0;
end end
end
end end
// Continuous monitoring of saturation status // Continuous monitoring of saturation status
@@ -297,14 +298,7 @@ always @(posedge clk) begin
end end
`endif `endif
// Clear saturation on external reset // Clear saturation on external reset — handled in integrator always block
always @(posedge reset_monitors) begin // (lines 165-172, using synchronous check of reset_monitors)
if (reset_monitors) begin
overflow_latched <= 0;
saturation_detected <= 0;
saturation_event_count <= 0;
//$display("CIC_MONITORS: All monitors reset");
end
end
endmodule endmodule
+60 -57
View File
@@ -39,63 +39,66 @@ initial begin
buffer_has_data = 0; buffer_has_data = 0;
end end
// ========== FIXED STATE MACHINE ========== // ========== BRAM WRITE (synchronous only, no async reset) ==========
always @(posedge clk or negedge reset_n) begin // Xilinx Block RAMs do not support asynchronous resets.
if (!reset_n) begin // Separating the BRAM write into its own always block avoids Synth 8-3391.
write_ptr <= 0; // The initial block above handles power-on initialization for FPGA.
read_ptr <= 0; always @(posedge clk) begin
valid_out_reg <= 0; if (valid_in) begin
delay_counter <= 0; bram[write_ptr] <= data_in;
buffer_has_data <= 0; end
end else begin end
// Default: no valid output
valid_out_reg <= 0; // ========== CONTROL LOGIC (with async reset) ==========
always @(posedge clk or negedge reset_n) begin
// ===== WRITE SIDE ===== if (!reset_n) begin
if (valid_in) begin write_ptr <= 0;
// Store data read_ptr <= 0;
bram[write_ptr] <= data_in; valid_out_reg <= 0;
delay_counter <= 0;
// Increment write pointer (wrap at 4095) buffer_has_data <= 0;
if (write_ptr == 4095) begin end else begin
write_ptr <= 0; // Default: no valid output
end else begin valid_out_reg <= 0;
write_ptr <= write_ptr + 1;
end // ===== WRITE SIDE =====
if (valid_in) begin
// Count how many samples we've written // Increment write pointer (wrap at 4095)
if (delay_counter < LATENCY) begin if (write_ptr == 4095) begin
delay_counter <= delay_counter + 1; write_ptr <= 0;
end else begin
// When we've written LATENCY samples, buffer is "primed" write_ptr <= write_ptr + 1;
if (delay_counter == LATENCY - 1) begin end
buffer_has_data <= 1'b1;
// $display("[LAT_BUF] Buffer now has %d samples (primed)", LATENCY); // Count how many samples we've written
end if (delay_counter < LATENCY) begin
end delay_counter <= delay_counter + 1;
end
// When we've written LATENCY samples, buffer is "primed"
// ===== READ SIDE ===== if (delay_counter == LATENCY - 1) begin
// Only start reading after we have LATENCY samples in buffer buffer_has_data <= 1'b1;
if (buffer_has_data && valid_in) begin end
// Read pointer follows write pointer with LATENCY delay end
// Calculate: read_ptr = (write_ptr - LATENCY) mod 4096 end
// Handle wrap-around correctly // ===== READ SIDE =====
if (write_ptr >= LATENCY) begin // Only start reading after we have LATENCY samples in buffer
read_ptr <= write_ptr - LATENCY; if (buffer_has_data && valid_in) begin
end else begin // Read pointer follows write pointer with LATENCY delay
// Wrap around: 4096 + write_ptr - LATENCY // Calculate: read_ptr = (write_ptr - LATENCY) mod 4096
read_ptr <= 4096 + write_ptr - LATENCY;
end // Handle wrap-around correctly
if (write_ptr >= LATENCY) begin
// Output is valid read_ptr <= write_ptr - LATENCY;
valid_out_reg <= 1'b1; end else begin
// Wrap around: 4096 + write_ptr - LATENCY
//$display("[LAT_BUF] Reading: write_ptr=%d, read_ptr=%d, data=%h", read_ptr <= 4096 + write_ptr - LATENCY;
// write_ptr, read_ptr, bram[read_ptr]); end
end
end // Output is valid
valid_out_reg <= 1'b1;
end
end
end end
// ========== OUTPUTS ========== // ========== OUTPUTS ==========
@@ -62,6 +62,7 @@ module matched_filter_processing_chain (
output wire [3:0] chain_state output wire [3:0] chain_state
); );
`ifdef SIMULATION
// ============================================================================ // ============================================================================
// PARAMETERS // PARAMETERS
// ============================================================================ // ============================================================================
@@ -526,4 +527,21 @@ initial begin
end end
end end
`else
// ============================================================================
// SYNTHESIS STUB
// ============================================================================
// The behavioral FFT implementation above uses $cos/$sin/$rtoi (non-
// synthesizable). For real hardware, replace this stub with Xilinx xfft
// IP cores or a synthesizable pipelined FFT. The stub ties outputs to
// safe defaults so the rest of the design can be synthesized and verified.
// ============================================================================
assign range_profile_i = 16'd0;
assign range_profile_q = 16'd0;
assign range_profile_valid = 1'b0;
assign chain_state = 4'd0; // permanently IDLE
`endif
endmodule endmodule
+21 -30
View File
@@ -14,10 +14,10 @@ module radar_receiver_final (
// Chirp counter from transmitter (for frame sync and matched filter) // Chirp counter from transmitter (for frame sync and matched filter)
input wire [5:0] chirp_counter, input wire [5:0] chirp_counter,
output reg [31:0] doppler_output, output wire [31:0] doppler_output,
output reg doppler_valid, output wire doppler_valid,
output reg [4:0] doppler_bin, output wire [4:0] doppler_bin,
output reg [5:0] range_bin output wire [5:0] range_bin
); );
// ========== INTERNAL SIGNALS ========== // ========== INTERNAL SIGNALS ==========
@@ -53,7 +53,6 @@ wire new_chirp_frame;
wire [31:0] doppler_spectrum; wire [31:0] doppler_spectrum;
wire doppler_spectrum_valid; wire doppler_spectrum_valid;
wire [4:0] doppler_bin_out; wire [4:0] doppler_bin_out;
wire [5:0] doppler_range_bin_out;
wire doppler_processing; wire doppler_processing;
wire doppler_frame_done; wire doppler_frame_done;
@@ -92,46 +91,41 @@ radar_mode_controller rmc (
.scanning(rmc_scanning), .scanning(rmc_scanning),
.scan_complete(rmc_scan_complete) .scan_complete(rmc_scan_complete)
); );
reg clk_400m; wire clk_400m;
lvds_to_cmos_400m clk_400m_inst( // NOTE: lvds_to_cmos_400m removed ad9484_interface_400m now provides
// ADC Physical Interface (LVDS Inputs) // the buffered 400MHz DCO clock via adc_dco_bufg, avoiding duplicate
.clk_400m_p(adc_dco_p), // Data Clock Output P (400MHz LVDS, 2.5V) // IBUFDS instantiations on the same LVDS clock pair.
.clk_400m_n(adc_dco_n), // Data Clock Output N (400MHz LVDS, 2.5V)
.reset_n(reset_n), // Active-low reset
// CMOS Output Interface (400MHz Domain)
.clk_400m_cmos(clk_400m) // ADC data clock (CMOS, 3.3V)
);
// 1. ADC + CDC + AGC // 1. ADC + CDC + AGC
// CMOS Output Interface (400MHz Domain) // CMOS Output Interface (400MHz Domain)
wire [7:0] adc_data_cmos; // 8-bit ADC data (CMOS) wire [7:0] adc_data_cmos; // 8-bit ADC data (CMOS, from ad9484_interface_400m)
wire adc_dco_cmos; // ADC data clock (CMOS, 400MHz)
wire adc_valid; // Data valid signal wire adc_valid; // Data valid signal
wire [7:0] cdc_data_cmos; // 8-bit ADC data (CMOS) wire [7:0] cdc_data_cmos; // 8-bit ADC data (CMOS)
wire cdc_valid; // Data valid signal wire cdc_valid; // Data valid signal
// ADC power-down control (directly tie low = ADC always on)
assign adc_pwdn = 1'b0;
ad9484_lvds_to_cmos_400m adc ( ad9484_interface_400m adc (
.adc_d_p(adc_d_p), .adc_d_p(adc_d_p),
.adc_d_n(adc_d_n), .adc_d_n(adc_d_n),
.adc_dco_p(adc_dco_p), .adc_dco_p(adc_dco_p),
.adc_dco_n(adc_dco_n), .adc_dco_n(adc_dco_n),
.sys_clk(clk),
.reset_n(reset_n), .reset_n(reset_n),
.adc_data_cmos(adc_data_cmos), .adc_data_400m(adc_data_cmos),
.adc_dco_cmos(adc_dco_cmos), .adc_data_valid_400m(adc_valid),
.adc_valid(adc_valid), .adc_dco_bufg(clk_400m)
.adc_pwdn(adc_pwdn)
); );
cdc_adc_to_processing #( cdc_adc_to_processing #(
.WIDTH(8), .WIDTH(8),
.STAGES(3) .STAGES(3)
)cdc( )cdc(
.src_clk(adc_dco_cmos), .src_clk(clk_400m),
.dst_clk(clk_400m), .dst_clk(clk_400m),
.reset_n(reset_n), .reset_n(reset_n),
.src_data(adc_data_cmos), .src_data(adc_data_cmos),
@@ -199,7 +193,7 @@ always @(posedge clk or negedge reset_n) begin
if (sample_addr_reg == 1023) sample_addr_reg <= 0; if (sample_addr_reg == 1023) sample_addr_reg <= 0;
end end
end end
assign sample_addr_wire = sample_addr_reg; // sample_addr_wire removed was unused implicit wire (synthesis warning)
// 4. CRITICAL: Reference Chirp Latency Buffer // 4. CRITICAL: Reference Chirp Latency Buffer
// This aligns reference data with FFT output (2159 cycle delay) // This aligns reference data with FFT output (2159 cycle delay)
@@ -249,8 +243,6 @@ matched_filter_multi_segment mf_dual (
.segment_request(segment_request), .segment_request(segment_request),
.mem_request(mem_request), .mem_request(mem_request),
.sample_addr_out(sample_addr_from_chain), .sample_addr_out(sample_addr_from_chain),
.ref_i(16'd0), // Direct ref to multi_seg
.ref_q(16'd0),
.mem_ready(mem_ready), .mem_ready(mem_ready),
.pc_i_w(range_profile_i), .pc_i_w(range_profile_i),
.pc_q_w(range_profile_q), .pc_q_w(range_profile_q),
@@ -338,7 +330,7 @@ doppler_processor_optimized #(
.doppler_output(doppler_output), .doppler_output(doppler_output),
.doppler_valid(doppler_valid), .doppler_valid(doppler_valid),
.doppler_bin(doppler_bin), .doppler_bin(doppler_bin),
.range_bin(doppler_range_bin_out), .range_bin(range_bin),
// Status // Status
.processing_active(doppler_processing), .processing_active(doppler_processing),
@@ -347,9 +339,8 @@ doppler_processor_optimized #(
); );
// ========== OUTPUT CONNECTIONS ========== // ========== OUTPUT CONNECTIONS ==========
assign doppler_range_bin = doppler_range_bin_out; // doppler_output, doppler_valid, doppler_bin, range_bin are directly
assign doppler_processing_active = doppler_processing; // connected to doppler_proc ports above
assign doppler_frame_complete = doppler_frame_done;
// ========== STATUS ========== // ========== STATUS ==========
+71
View File
@@ -0,0 +1,71 @@
`timescale 1ns / 1ps
// ============================================================================
// xfft_32.v Synthesis stub for Xilinx 32-point FFT IP core
// ============================================================================
// This is a PLACEHOLDER module that provides the port interface expected by
// doppler_processor.v. It does NOT perform an actual FFT it simply passes
// input data through with a one-cycle latency and generates proper AXI-Stream
// handshake signals.
//
// For real hardware, replace this stub with either:
// (a) A Xilinx FFT IP core generated via Vivado IP Catalog, or
// (b) A custom synthesizable radix-2 DIT 32-point FFT in Verilog.
//
// Port interface matches the Xilinx LogiCORE IP Fast Fourier Transform
// (AXI-Stream variant) as instantiated in doppler_processor.v.
// ============================================================================
module xfft_32 (
input wire aclk,
input wire aresetn,
// Configuration channel (AXI-Stream slave)
input wire [7:0] s_axis_config_tdata,
input wire s_axis_config_tvalid,
output wire s_axis_config_tready,
// Data input channel (AXI-Stream slave)
input wire [31:0] s_axis_data_tdata,
input wire s_axis_data_tvalid,
input wire s_axis_data_tlast,
// Data output channel (AXI-Stream master)
output wire [31:0] m_axis_data_tdata,
output wire m_axis_data_tvalid,
output wire m_axis_data_tlast,
input wire m_axis_data_tready
);
// ----------------------------------------------------------------------------
// Synthesis stub: pass-through with one-cycle latency
// ----------------------------------------------------------------------------
// This gives Vivado a real module to synthesize so it can check port
// connectivity, infer timing paths, and estimate utilization. The actual
// FFT computation is deferred to IP integration or a custom RTL FFT.
// ----------------------------------------------------------------------------
// Always accept config
assign s_axis_config_tready = 1'b1;
// Pipeline registers for data pass-through
reg [31:0] data_reg;
reg valid_reg;
reg last_reg;
always @(posedge aclk) begin
if (!aresetn) begin
data_reg <= 32'd0;
valid_reg <= 1'b0;
last_reg <= 1'b0;
end else begin
data_reg <= s_axis_data_tdata;
valid_reg <= s_axis_data_tvalid;
last_reg <= s_axis_data_tlast;
end
end
assign m_axis_data_tdata = data_reg;
assign m_axis_data_tvalid = valid_reg;
assign m_axis_data_tlast = last_reg;
endmodule