Widen ft601_be to [3:0] for 32-bit FT601 mode, fix NCO XSim TB

- Expand ft601_be from [1:0] to [3:0] across RTL, top-level, testbenches,
  and XDC (uncomment be[2:3] pin assignments B21/A21)
- Fix NCO XSim testbench: correct reset check (0x7FFF not 0), add pipeline
  warmup and sample skip for DSP48E1 quadrature test
- All local regression tests pass (39/39 USB, 10/10 integration, all co-sim)
This commit is contained in:
Jason
2026-03-16 23:17:38 +02:00
parent af1af3bb91
commit 49eb6169b6
7 changed files with 35 additions and 33 deletions
+1 -1
View File
@@ -43,7 +43,7 @@ own constraint file. Both files constrain the same RTL top module (`radar_system
|--------|-------------------|---------------------|
| FT601 USB | Unwired (chip placed, no nets) | Fully wired, Bank 16 |
| `dac_clk` | Not connected (DAC clocked by AD9523 directly) | Routed, FPGA drives DAC |
| `ft601_be` width | `[1:0]` in RTL | `[3:0]` needed (RTL update required) |
| `ft601_be` width | `[1:0]` in upstream RTL | `[3:0]` (RTL updated) |
| ADC LVDS standard | LVDS_33 (3.3V bank) | LVDS_25 (2.5V bank, better quality) |
| Status/debug outputs | No physical pins (commented out) | All routed to Banks 35 + 13 |
@@ -35,7 +35,7 @@
# 1. ADC uses LVDS_25 (2.5V VCCO) instead of LVDS_33 (better signal quality)
# 2. FT601 USB 3.0 is fully wired (Bank 16) — unwired on upstream board
# 3. dac_clk output is routed — unconnected on upstream board
# 4. ft601_be is 4 bits wide for 32-bit FT601 mode (upstream RTL has [1:0])
# 4. ft601_be is 4 bits wide [3:0] for 32-bit FT601 mode
# 5. All status/debug outputs have physical pins (Banks 35 + 13)
# ============================================================================
@@ -280,8 +280,6 @@ set_property IOSTANDARD LVCMOS18 [get_ports {stm32_*_1v8}]
# FT601 is fully wired on the production board.
# 32-bit data bus + 4-bit byte enable + control signals.
#
# NOTE: Current RTL declares ft601_be[1:0]. Production board requires
# ft601_be[3:0] for 32-bit FT601 mode. RTL update needed.
# --- ft601_clk_in on MRCC (D17) constrained above in CLOCK section ---
@@ -330,14 +328,10 @@ set_property SLEW FAST [get_ports {ft601_data[*]}]
set_property DRIVE 8 [get_ports {ft601_data[*]}]
# FT601 Byte Enable [3:0]
# NOTE: RTL currently only drives ft601_be[1:0]. Bits [3:2] are allocated
# for future 32-bit mode but have no driver yet. Constrain only [1:0]
# to avoid critical warnings; add [3:2] when RTL is updated.
set_property PACKAGE_PIN C22 [get_ports {ft601_be[0]}]
set_property PACKAGE_PIN B22 [get_ports {ft601_be[1]}]
# Reserved for future 4-bit byte enable (uncomment when RTL supports [3:0]):
# set_property PACKAGE_PIN B21 [get_ports {ft601_be[2]}]
# set_property PACKAGE_PIN A21 [get_ports {ft601_be[3]}]
set_property PACKAGE_PIN B21 [get_ports {ft601_be[2]}]
set_property PACKAGE_PIN A21 [get_ports {ft601_be[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ft601_be[*]}]
set_property SLEW FAST [get_ports {ft601_be[*]}]
set_property DRIVE 8 [get_ports {ft601_be[*]}]
+1 -1
View File
@@ -52,7 +52,7 @@ reg [7:0] adc_d_n;
// FT601 interface
wire [31:0] ft601_data;
wire [1:0] ft601_be;
wire [3:0] ft601_be;
wire ft601_txe_n;
wire ft601_rxf_n;
reg ft601_txe;
+1 -1
View File
@@ -77,7 +77,7 @@ module radar_system_top (
// Data bus
inout wire [31:0] ft601_data, // 32-bit bidirectional data bus
output wire [1:0] ft601_be, // Byte enable
output wire [3:0] ft601_be, // Byte enable (4 lanes for 32-bit mode)
// Control signals
output wire ft601_txe_n, // Transmit enable (active low)
+17 -9
View File
@@ -86,8 +86,8 @@ module tb_nco_xsim;
//
$display("--- Test Group 1: Reset Behaviour ---");
#50;
check(cos_out === 16'sd0 || cos_out === 16'sd1,
"cos_out near zero during reset");
check(cos_out === 16'sh7FFF,
"cos_out = 0x7FFF during reset");
check(output_valid === 1'b0, "output_valid = 0 during reset");
//
@@ -184,26 +184,34 @@ module tb_nco_xsim;
#50;
phase_increment = 32'h4CCCCCCD;
reset_n = 1;
repeat (15) @(posedge clk);
// Allow 25 cycles for pipeline flush (DSP48E1 has 67 stage latency)
repeat (25) @(posedge clk);
begin : quad_test
reg [63:0] mag_sq;
reg [63:0] mag_min, mag_max;
integer sample_count;
integer skip;
mag_min = 64'hFFFFFFFFFFFFFFFF;
mag_max = 0;
sample_count = 0;
skip = 0;
for (i = 0; i < 200; i = i + 1) begin
@(posedge clk); #0.1;
if (output_valid) begin
// cos^2 + sin^2
mag_sq = cos_out * cos_out + sin_out * sin_out;
if (mag_sq > 0) begin // skip zeros during pipeline fill
if (mag_sq < mag_min) mag_min = mag_sq;
if (mag_sq > mag_max) mag_max = mag_sq;
sample_count = sample_count + 1;
// Skip first 4 valid samples (pipeline settling)
if (skip < 4) begin
skip = skip + 1;
end else begin
// cos^2 + sin^2
mag_sq = cos_out * cos_out + sin_out * sin_out;
if (mag_sq > 0) begin // skip zeros during pipeline fill
if (mag_sq < mag_min) mag_min = mag_sq;
if (mag_sq > mag_max) mag_max = mag_sq;
sample_count = sample_count + 1;
end
end
end
end
@@ -30,7 +30,7 @@ module tb_usb_data_interface;
// FT601 interface
wire [31:0] ft601_data;
wire [1:0] ft601_be;
wire [3:0] ft601_be;
wire ft601_txe_n;
wire ft601_rxf_n;
reg ft601_txe;
@@ -271,8 +271,8 @@ module tb_usb_data_interface;
check(ft601_wr_n === 1'b0,
"Write strobe active during range data");
check(ft601_be === 2'b11,
"Byte enable=11 for range data");
check(ft601_be === 4'b1111,
"Byte enable=1111 for range data");
// Wait for all 4 range words to complete
wait_for_state(S_SEND_DOPPLER, 50);
@@ -307,8 +307,8 @@ module tb_usb_data_interface;
check(uut.ft601_data_out[7:0] === 8'hAA,
"Header byte 0xAA on data bus");
check(ft601_be === 2'b01,
"Byte enable=01 for header (lower byte only)");
check(ft601_be === 4'b0001,
"Byte enable=0001 for header (lower byte only)");
check(ft601_wr_n === 1'b0,
"Write strobe active during header");
check(uut.ft601_data_oe === 1'b1,
+7 -7
View File
@@ -14,7 +14,7 @@ module usb_data_interface (
// FT601 Interface (Slave FIFO mode)
// Data bus
inout wire [31:0] ft601_data, // 32-bit bidirectional data bus
output reg [1:0] ft601_be, // Byte enable (for 32-bit mode)
output reg [3:0] ft601_be, // Byte enable (4 lanes for 32-bit mode)
// Control signals
output reg ft601_txe_n, // Transmit enable (active low)
@@ -118,7 +118,7 @@ always @(posedge ft601_clk_in or negedge reset_n) begin
byte_counter <= 0;
ft601_data_out <= 0;
ft601_data_oe <= 0;
ft601_be <= 2'b11; // Both bytes enabled for 32-bit mode
ft601_be <= 4'b1111; // All bytes enabled for 32-bit mode
ft601_txe_n <= 1;
ft601_rxf_n <= 1;
ft601_wr_n <= 1;
@@ -142,7 +142,7 @@ always @(posedge ft601_clk_in or negedge reset_n) begin
if (!ft601_txe) begin // FT601 TX FIFO not empty
ft601_data_oe <= 1;
ft601_data_out <= {24'b0, HEADER};
ft601_be <= 2'b01; // Only lower byte valid
ft601_be <= 4'b0001; // Only lower byte valid
ft601_wr_n <= 0; // Assert write strobe
current_state <= SEND_RANGE_DATA;
end
@@ -151,7 +151,7 @@ always @(posedge ft601_clk_in or negedge reset_n) begin
SEND_RANGE_DATA: begin
if (!ft601_txe) begin
ft601_data_oe <= 1;
ft601_be <= 2'b11; // All bytes valid for 32-bit word
ft601_be <= 4'b1111; // All bytes valid for 32-bit word
case (byte_counter)
0: ft601_data_out <= range_profile_cap;
@@ -174,7 +174,7 @@ always @(posedge ft601_clk_in or negedge reset_n) begin
SEND_DOPPLER_DATA: begin
if (!ft601_txe && doppler_valid_ft) begin
ft601_data_oe <= 1;
ft601_be <= 2'b11;
ft601_be <= 4'b1111;
case (byte_counter)
0: ft601_data_out <= {doppler_real_cap, doppler_imag_cap};
@@ -197,7 +197,7 @@ always @(posedge ft601_clk_in or negedge reset_n) begin
SEND_DETECTION_DATA: begin
if (!ft601_txe && cfar_valid_ft) begin
ft601_data_oe <= 1;
ft601_be <= 2'b01;
ft601_be <= 4'b0001;
ft601_data_out <= {24'b0, 7'b0, cfar_detection_cap};
ft601_wr_n <= 0;
current_state <= SEND_FOOTER;
@@ -207,7 +207,7 @@ always @(posedge ft601_clk_in or negedge reset_n) begin
SEND_FOOTER: begin
if (!ft601_txe) begin
ft601_data_oe <= 1;
ft601_be <= 2'b01;
ft601_be <= 4'b0001;
ft601_data_out <= {24'b0, FOOTER};
ft601_wr_n <= 0;
current_state <= WAIT_ACK;