docs(fpga-xdc): PR-AD.b — close H-1/H-2/H-4 (FT601 XDC documentation rot)

H-1: ft601_rd_n/ft601_oe_n IOB-packing block claimed "constant-1, USB read
not implemented" but the driver has had a full RD_OE_ASSERT/READING/DEASSERT
read FSM since the host-command path was added. Rewrote the comment to
describe the real FSM-driven traffic and explain that -quiet is now for
post-synthesis retiming/consolidation cases, not because the registers
don't exist.

H-2: production XDC (create_generated_clock ft601_clk_fwd + set_output_delay)
and FMC dev XDC (set_max_delay -datapath_only) implement two different but
deliberate timing strategies for the same FT601 output ports — production
forwards ft601_clk_out via ODDR, FMC UMFT601X-B has no return path. Added
cross-reference VARIANT STRATEGY blocks in both XDCs explaining the choice
and the no-mixing rule.

H-4: set_false_path -from ft601_txe -to clk_100m registers was undocumented.
Traced both capture paths: ft601_clk_in (write FSM in usb_data_interface.v)
and clk_100m (cdc_single_bit in radar_system_top.v driving status_reg[1]).
Added comment explaining the async port → clk_100m sync-FF path is what
this constraint covers.

Comment-only XDC change; regression 46/0/0 unchanged.
This commit is contained in:
Jason
2026-05-18 15:11:31 +05:45
parent 4c9032187a
commit 1342ce7b9d
2 changed files with 33 additions and 4 deletions

View File

@@ -233,6 +233,15 @@ set_input_delay -clock [get_clocks ft601_clk_in] -min 1.000 [get_ports {ft601_rx
# --------------------------------------------------------------------------
# FT601 output timing — source-synchronous, datapath-only constraints
# --------------------------------------------------------------------------
# VARIANT STRATEGY: this is the FMC-board approach. The production board XDC
# (constraints/xc7a200t_fbg484.xdc, "FT601 output delay relative to ODDR-
# forwarded clock" section) uses a DIFFERENT strategy
# (create_generated_clock ft601_clk_fwd + set_output_delay) because the
# production board DOES forward ft601_clk_out via ODDR back to the FT601.
# Only ONE of these XDCs should be included per build. Do NOT mix or both
# will fight each other (conflicting or over-constrained timing on the same
# ports).
#
# The FT601 provides its own 100 MHz clock (D_CLK) and samples data on
# the next rising edge of that same clock. The FPGA receives D_CLK through
# IBUF→BUFG (~5 ns insertion), but this insertion delay is COMMON to both

View File

@@ -568,7 +568,16 @@ set_false_path -hold -from [get_clocks clk_120m_dac] -to [get_clocks dac_clk_fwd
# --------------------------------------------------------------------------
# FT601 output delay relative to ODDR-forwarded clock
# --------------------------------------------------------------------------
# ft601_clk_out is now forwarded via ODDR from ft601_clk_in BUFG output.
# VARIANT STRATEGY: this is the PRODUCTION-board approach. The TE0713/TE0701
# FMC dev variant uses a DIFFERENT strategy (set_max_delay -datapath_only,
# no forwarded clock) because the UMFT601X-B FMC adapter has no return
# path for ft601_clk_out — see constraints/te0713_te0701_umft601x.xdc
# "FT601 output timing" section for the FMC rationale. Only ONE of these
# XDCs should be included per build (set in the Vivado project per board
# variant). Do NOT mix or both will fight each other (conflicting or
# over-constrained timing on the same ports).
#
# ft601_clk_out is forwarded via ODDR from ft601_clk_in BUFG output.
# Since both data FFs and clock ODDR are driven by the same BUFG, insertion
# delays cancel. Output delay only needs to cover FT601 Tsu/Th + trace skew.
#
@@ -631,6 +640,13 @@ set_false_path -from [get_clocks clk_120m_dac] -to [get_clocks clk_100m]
# clk_100m ↔ ft601_clk_in: USB data interface has CDC synchronizers
set_false_path -from [get_clocks clk_100m] -to [get_clocks ft601_clk_in]
set_false_path -from [get_clocks ft601_clk_in] -to [get_clocks clk_100m]
# ft601_txe is captured in BOTH the ft601_clk_in domain (write FSM in
# usb_data_interface.v gates on `!ft601_txe`) AND the clk_100m domain
# (cdc_single_bit synchronizer in radar_system_top.v drives status_reg[1]
# for host telemetry). The set_input_delay on ft601_txe (earlier in this
# file, in the FT601 input timing block) covers the ft601_clk_in capture;
# this false_path covers the async port → clk_100m sync-FF path, which is
# an explicit CDC and not source-synchronous to ft601_clk_in.
set_false_path -from [get_ports {ft601_txe}] -to [all_registers -clock [get_clocks clk_100m]]
# clk_120m_dac ↔ ft601_clk_in: no direct data path expected
@@ -711,9 +727,13 @@ set_property IOB TRUE [get_cells -hierarchical -filter {NAME =~ *oddr_ft601_clk*
set_property -quiet IOB TRUE [get_cells -hierarchical -filter {NAME =~ *usb_inst/ft601_data_out_reg*}]
set_property -quiet IOB TRUE [get_cells -hierarchical -filter {NAME =~ *usb_inst/ft601_be_reg*}]
set_property IOB TRUE [get_cells -hierarchical -filter {NAME =~ *usb_inst/ft601_wr_n_reg*}]
# ft601_rd_n and ft601_oe_n are constant-1 (USB read not implemented) —
# Vivado removes the registers via constant propagation. Use -quiet to
# suppress CRITICAL WARNING [Common 17-55] when the cells don't exist.
# ft601_rd_n and ft601_oe_n are driven by the host-command read FSM
# (RD_OE_ASSERT / RD_READING / RD_DEASSERT in usb_data_interface.v). They
# carry real toggling traffic and are constrained by the set_output_delay
# block above. -quiet stays because Vivado may consolidate the register
# names during synthesis (retiming into the FSM state register), in which
# case the filter returns no objects and the WARNING is benign — timing
# is still met via the set_output_delay constraints.
set_property -quiet IOB TRUE [get_cells -hierarchical -filter {NAME =~ *usb_inst/ft601_rd_n_reg*}]
set_property -quiet IOB TRUE [get_cells -hierarchical -filter {NAME =~ *usb_inst/ft601_oe_n_reg*}]