fix(fpga): move IBUF+BUFIO+BUFR into 50T wrapper (same scope as pad)

The previous attempt put BUFIO inside u_core/gen_ft_bufr, but the pad
(ft_clkout) and its inferred IBUF live at the top wrapper level. Vivado
shape-packs IBUF↔BUFIO into the same IOB tile, and it couldn't do that
across the wrapper→u_core hierarchy boundary — producing CRITICAL
WARNING [12-1411] "Illegal to place BUFIO on TIEOFF site" and WNS=-5.737
(worse than the CLOCK_DEDICATED_ROUTE=FALSE baseline).

Fix: instantiate IBUF+BUFIO+BUFR explicitly in radar_system_top_50t.v
and pass the BUFR output into u_core.ft601_clk_in. radar_system_top.v
now does a pass-through wire assign for USB_MODE=1 (no BUFG) so the
clock net doesn't get double-buffered.
This commit is contained in:
Jason
2026-04-20 21:02:56 +05:45
parent 30279e8c4d
commit 813ee4c962
2 changed files with 29 additions and 18 deletions
+8 -16
View File
@@ -329,22 +329,14 @@ BUFG bufg_120m (
// USB clock buffering: // USB clock buffering:
// USB_MODE=0 (200T/FT601): pin is MRCC (D17) BUFG, global clock network. // USB_MODE=0 (200T/FT601): pin is MRCC (D17) BUFG, global clock network.
// USB_MODE=1 (50T/FT2232H): pin is SRCC (C4, non-MRCC) BUFIO + BUFR for // USB_MODE=1 (50T/FT2232H): pin is SRCC (C4, non-MRCC). The wrapper
// regional dedicated routing. SRCC can drive BUFIO/BUFR but not BUFG // radar_system_top_50t.v instantiates IBUF+BUFIO+BUFR on the pin
// directly (the "poor placement IOBUFG" CLOCK_DEDICATED_ROUTE=FALSE // and passes the already-buffered clock into ft601_clk_in. We only
// override was burning ~5 ns in fabric routing on the ft_clkout path). // pass it through here inserting a BUFG would create a second
// All ft_clkout-domain logic (FT2232H FSM, FIFO flops, toggle CDCs) is // buffer on an already-clock-network net and break the BUFIO/BUFR
// contained in bank 35 / one clock region, so regional distribution // shape packing. See UG472 §3 BUFIO/BUFR.
// is sufficient. See UG472 §3 BUFIO/BUFR. generate if (USB_MODE == 1) begin : gen_ft_passthru
generate if (USB_MODE == 1) begin : gen_ft_bufr assign ft601_clk_buf = ft601_clk_in;
wire ft_clk_bufio;
BUFIO bufio_ft (.I(ft601_clk_in), .O(ft_clk_bufio));
BUFR #(.BUFR_DIVIDE("BYPASS"), .SIM_DEVICE("7SERIES")) bufr_ft (
.I(ft_clk_bufio),
.O(ft601_clk_buf),
.CE(1'b1),
.CLR(1'b0)
);
end else begin : gen_ft_bufg end else begin : gen_ft_bufg
BUFG bufg_ft601 (.I(ft601_clk_in), .O(ft601_clk_buf)); BUFG bufg_ft601 (.I(ft601_clk_in), .O(ft601_clk_buf));
end endgenerate end endgenerate
+21 -2
View File
@@ -71,7 +71,7 @@ module radar_system_top_50t (
input wire stm32_mixers_enable, input wire stm32_mixers_enable,
// ===== FT2232H USB 2.0 Interface (Bank 35: 3.3V) ===== // ===== FT2232H USB 2.0 Interface (Bank 35: 3.3V) =====
input wire ft_clkout, // 60 MHz from FT2232H CLKOUT (MRCC pin C4) input wire ft_clkout, // 60 MHz from FT2232H CLKOUT (SRCC pin C4 not MRCC)
inout wire [7:0] ft_data, // 8-bit bidirectional data bus inout wire [7:0] ft_data, // 8-bit bidirectional data bus
input wire ft_rxf_n, // RX FIFO not empty (active low) input wire ft_rxf_n, // RX FIFO not empty (active low)
input wire ft_txe_n, // TX FIFO not full (active low) input wire ft_txe_n, // TX FIFO not full (active low)
@@ -86,6 +86,25 @@ module radar_system_top_50t (
output wire gpio_dig7 // DIG_7 (H12PD15): reserved output wire gpio_dig7 // DIG_7 (H12PD15): reserved
); );
// ===== FT2232H clock buffering IBUF BUFIO BUFR =====
// C4 is SRCC (IS_CLK_CAPABLE=1, IS_MASTER=0). SRCC cannot drive BUFG
// with dedicated routing, but can drive BUFIO BUFR regionally. All
// ft_clkout-domain logic fits in Bank 35's clock region. All three
// primitives must live in the same hierarchical scope so Vivado can
// shape-pack IBUFBUFIO correctly that's why this lives here in the
// wrapper and not inside u_core.
wire ft_clkout_ibuf;
wire ft_clkout_bufio;
wire ft_clkout_bufr;
IBUF ibuf_ft (.I(ft_clkout), .O(ft_clkout_ibuf));
BUFIO bufio_ft (.I(ft_clkout_ibuf), .O(ft_clkout_bufio));
BUFR #(.BUFR_DIVIDE("BYPASS"), .SIM_DEVICE("7SERIES")) bufr_ft (
.I(ft_clkout_bufio),
.O(ft_clkout_bufr),
.CE(1'b1),
.CLR(1'b0)
);
// ===== Tie-off wires for unconstrained FT601 inputs (inactive with USB_MODE=1) ===== // ===== Tie-off wires for unconstrained FT601 inputs (inactive with USB_MODE=1) =====
wire ft601_txe_tied = 1'b0; wire ft601_txe_tied = 1'b0;
wire ft601_rxf_tied = 1'b0; wire ft601_rxf_tied = 1'b0;
@@ -123,7 +142,7 @@ module radar_system_top_50t (
// ----- Clocks & Reset ----- // ----- Clocks & Reset -----
.clk_100m (clk_100m), .clk_100m (clk_100m),
.clk_120m_dac (clk_120m_dac), .clk_120m_dac (clk_120m_dac),
.ft601_clk_in (ft_clkout), // FT2232H 60 MHz CLKOUT shared USB clock port .ft601_clk_in (ft_clkout_bufr), // Pre-buffered via IBUF+BUFIO+BUFR above (SRCC fix)
.reset_n (reset_n), .reset_n (reset_n),
// ----- DAC ----- // ----- DAC -----