aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/top/x400/constraints/timing
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/top/x400/constraints/timing')
-rw-r--r--fpga/usrp3/top/x400/constraints/timing/common.xdc415
-rw-r--r--fpga/usrp3/top/x400/constraints/timing/dram.xdc55
-rw-r--r--fpga/usrp3/top/x400/constraints/timing/qsfp_10gbe.xdc19
-rw-r--r--fpga/usrp3/top/x400/constraints/timing/shared_constants.sdc130
4 files changed, 619 insertions, 0 deletions
diff --git a/fpga/usrp3/top/x400/constraints/timing/common.xdc b/fpga/usrp3/top/x400/constraints/timing/common.xdc
new file mode 100644
index 000000000..288465ad0
--- /dev/null
+++ b/fpga/usrp3/top/x400/constraints/timing/common.xdc
@@ -0,0 +1,415 @@
+#
+# Copyright 2021 Ettus Research, a National Instruments Brand
+#
+# SPDX-License-Identifier: LGPL-3.0-or-later
+#
+# Description:
+# Common timing constraints for X410.
+#
+
+###############################################################################
+# Motherboard Clocks
+###############################################################################
+
+# 10/25 MHz reference clock from rear panel connector.
+# Constrain to the fastest possible clock rate.
+set ref_clk_period 40.00
+create_clock -name ref_clk -period $ref_clk_period [get_ports BASE_REFCLK_FPGA_P]
+
+# PLL Reference Clock. Used to derive data clocks.
+# Constrain to the fastest possible clock rate supported in the driver.
+# MPM supports 61.44 / 62.5 / 64.0 MHz.
+set pll_ref_clk_period 15.625
+create_clock -name pll_ref_clk -period $pll_ref_clk_period [get_ports PLL_REFCLK_FPGA_P]
+
+# MGT Clocks
+# Clock Reference | Frequency | Purpose
+# MGT_REFCLK_LMK0 | 156.25/125 MHz | 10 GbE
+# MGT_REFCLK_LMK1 | 100.00 MHz | Reserved
+# MGT_REFCLK_LMK2 | 100.00 MHz | Reserved
+# MGT_REFCLK_LMK3 | 156.25/125 MHz | 10 GbE
+create_clock -name mgt_ref_0 -period 6.400 [get_ports MGT_REFCLK_LMK0_P]
+create_clock -name mgt_ref_1 -period 10.000 [get_ports MGT_REFCLK_LMK1_P]
+create_clock -name mgt_ref_2 -period 10.400 [get_ports MGT_REFCLK_LMK2_P]
+create_clock -name mgt_ref_3 -period 6.400 [get_ports MGT_REFCLK_LMK3_P]
+
+# Virtual clocks for constraining misc. I/Os.
+create_clock -name async_in_clk -period 50.00
+create_clock -name async_out_clk -period 50.00
+
+
+###############################################################################
+# Aliases for auto-generated clocks
+###############################################################################
+
+# Name the PS clocks. These are originally declared in the PS8 IP block.
+# Create the clocks based on the PS PLCLK pins.
+# This generates critical warnings in the OSS flow because the clocks were already
+# define and we are completely rewriting the old clock definition... this is OK.
+create_clock -name clk100 -period 10.000 \
+ [get_pins -of_objects [get_cells -hierarchical {*PS8_i}] -filter {NAME =~ *PLCLK[0]}]
+
+create_clock -name clk40 -period 25.000 \
+ [get_pins -of_objects [get_cells -hierarchical {*PS8_i}] -filter {NAME =~ *PLCLK[1]}]
+
+create_clock -name clk166 -period 6.000 \
+ [get_pins -of_objects [get_cells -hierarchical {*PS8_i}] -filter {NAME =~ *PLCLK[2]}]
+
+create_clock -name clk200 -period 5.000 \
+ [get_pins -of_objects [get_cells -hierarchical {*PS8_i}] -filter {NAME =~ *PLCLK[3]}]
+
+
+###############################################################################
+# Sync to DB synthesizer sync CPLD input
+###############################################################################
+
+# synth_sync_hold_requirement and synth_sync_setup_requirement are shared
+# between the FPGA and DB CPLD. The values are set in shared_constants.sdc
+set synth_sync_ports [get_ports {DB0_SYNTH_SYNC DB1_SYNTH_SYNC}]
+set_output_delay -clock [get_clocks pll_ref_clk] -min -$synth_sync_hold_requirement $synth_sync_ports
+set_output_delay -clock [get_clocks pll_ref_clk] -max $synth_sync_setup_requirement $synth_sync_ports
+
+
+###############################################################################
+# SPI to MB CPLD (PL)
+# This interface is defined as system synchronous to pll_ref_clk.
+###############################################################################
+
+# The output delays are chosen to allow a large time window of valid data for
+# the MB CPLD logic.
+set spi_min_out_delay 0.000
+set spi_max_out_delay 11.000
+
+# Set output constraints for all ports.
+set spi_out_ports [get_ports {PL_CPLD_SCLK PL_CPLD_MOSI PL_CPLD_CS0_n PL_CPLD_CS1_n}]
+set_output_delay -clock [get_clocks pll_ref_clk] -min $spi_min_out_delay $spi_out_ports
+set_output_delay -clock [get_clocks pll_ref_clk] -max $spi_max_out_delay $spi_out_ports
+
+# Both CPLD and FPGA use PLL reference clock from a common clock chip.
+# The traces from that clock chip to the ICs are not length matched. Assume a
+# worst case clock difference of 0.5 ns at the IC inputs. There is no direction
+# defined. The clock can arrive faster or slower at one IC.
+set pl_clock_diff 0.500
+
+# The longest trace on the PL SPI interface is (assuming 170.0 ps/in)
+# Longest trace | Trace length | Trace delay
+# PL_CPLD_MISO | 3.863 in | 0.657 ns
+set pl_spi_board_delay 0.657
+
+# Output delay timings of the MB CPLD design, which still meet timing
+set pl_spi_cpld_min_out -1.000
+set pl_spi_cpld_max_out 8.000
+
+set spi_in_port [get_ports {PL_CPLD_MISO}]
+set_input_delay -clock [get_clocks pll_ref_clk] \
+ -min [expr {- $pl_spi_cpld_min_out - $pl_clock_diff}] \
+ $spi_in_port
+set_input_delay -clock [get_clocks pll_ref_clk] \
+ -max [expr {$pll_ref_clk_period - $pl_spi_cpld_max_out + $pl_spi_board_delay + $pl_clock_diff}] \
+ $spi_in_port
+
+
+###############################################################################
+# 10 GbE
+###############################################################################
+
+# These are the exceptions from "xge_pcs_pma_exceptions.xdc" which are to be
+# used when not using the example design.
+#
+# "clk100" used here is the clock that's connected to the "dclk" input in the core.
+set_max_delay -from [get_clocks -of_objects [get_pins -hierarchical -filter {NAME =~ */channel_inst/*_CHANNEL_PRIM_INST/RXOUTCLK}]] -to [get_clocks -of_objects [get_pins -hierarchical -filter {NAME =~ */channel_inst/*_CHANNEL_PRIM_INST/TXOUTCLK}]] -datapath_only 6.40
+set_max_delay -from [get_clocks -of_objects [get_pins -hierarchical -filter {NAME =~ */channel_inst/*_CHANNEL_PRIM_INST/TXOUTCLK}]] -to [get_clocks -of_objects [get_pins -hierarchical -filter {NAME =~ */channel_inst/*_CHANNEL_PRIM_INST/RXOUTCLK}]] -datapath_only 6.40
+set_max_delay -from [get_clocks -of_objects [get_pins -hierarchical -filter {NAME =~ */channel_inst/*_CHANNEL_PRIM_INST/RXOUTCLK}]] -to [get_clocks clk100] -datapath_only 6.40
+set_max_delay -from [get_clocks -of_objects [get_pins -hierarchical -filter {NAME =~ */channel_inst/*_CHANNEL_PRIM_INST/TXOUTCLK}]] -to [get_clocks clk100] -datapath_only 6.40
+set_max_delay -from [get_clocks clk100] -to [get_clocks -of_objects [get_pins -hierarchical -filter {NAME =~ */channel_inst/*_CHANNEL_PRIM_INST/TXOUTCLK}]] -datapath_only 10.000
+set_max_delay -from [get_clocks clk100] -to [get_clocks -of_objects [get_pins -hierarchical -filter {NAME =~ */channel_inst/*_CHANNEL_PRIM_INST/RXOUTCLK}]] -datapath_only 10.000
+
+
+###############################################################################
+# DIO
+# Those GPIO pins are considered asynchronous paths. The user has to add
+# constraints in case required. Therefore not setting false_paths from / to
+# user logic to allow user generated timing constraints to be applied.
+###############################################################################
+
+# Ignore paths from "slow" PS interface to not interfere with user constraints.
+set dio_ports [get_ports {DIOA_FPGA[*] DIOB_FPGA[*]}]
+set dio_registers [get_cells -hierarchical -filter {NAME =~ *x4xx_dio_i* && IS_SEQUENTIAL && IS_PRIMITIVE}]
+set_false_path -from $dio_registers -to $dio_ports
+set_false_path -from $dio_ports -to $dio_registers
+
+
+###############################################################################
+# PPS
+###############################################################################
+
+# The TRIG_IO port may be driven by either the PPS in BRC domain to
+# enable direct sync between 2 devices, or by any other user logic.
+# When PPS is exported through Trigger I/O, timing must be analyzed
+# to ensure determinism in the PPS exporting.
+# But, when other user logic drives TRIG_IO, then the port should be
+# treated as asynchronous (or close to async. at least).
+# To achieve this conditional timing analysis, the following trick is
+# used:
+# 1. A virtual copy of ref_clk is created for I/O timing - virtual_ref_clk
+# 2. Set output_delay constraints to assign a clock to the TRIG_IO port.
+# 3. A set_max_delay constraint is used to time the output path to TRIG_IO
+# set_max_delay makes the timing constraint driver agnostic, and as long
+# as the critical output delay is met for driving PPS through TRIG_IO,
+# we should be fine as this requirement is relatively loose.
+
+# 1) Creating copy of ref_clk to only analyze timing to TRIG_IO port (output)
+# when output is driven by ref_clk (PPS generation in ref_clk domain).
+create_clock -name virtual_ref_clk -period $ref_clk_period
+
+# Trigger IO port is used as output for the PPS signal
+# TRIG_IO_1V8 trace length MB = 4.050 + 1.190 inch = 5.240 inch
+# TRIG_IO_1V8 trace length DB = 2.401 + 0.120 + 0.457 + 0.261 inch = 3.239 inch
+# TRIG_IO buffer max switching time = 3.3
+set trig_max_out_delay [expr {8.479 * 0.17 + 3.3}]
+
+# Set minimum output delay hold time to a small amount to grant external
+# devices some hold time. Delay should be simple to achieve as there is no PLL
+# in the clocking path and some combinatorial logic.
+set trig_min_out_delay 2.000
+
+# 2) set_output_delay for assigning clocks to TRIG_IO. Use zero for delay to
+# avoid adding extra delay requirements on top of the set_max|min_delay
+# constraints below.
+set_output_delay -clock [get_clocks virtual_ref_clk] 0.0 [get_ports {TRIG_IO}]
+
+# 3) Min and max delays make constraining driver agnostic. We just make sure
+# the critical timing for PPS export is met though.
+set_max_delay -through [get_port {TRIG_IO}] -to [get_clocks {virtual_ref_clk}] \
+ [expr {$ref_clk_period - $trig_max_out_delay}]
+set_min_delay -through [get_port {TRIG_IO}] -to [get_clocks {virtual_ref_clk}] \
+ $trig_min_out_delay
+
+# Treat TRIG_IO input as asynchronous.
+set_false_path -from [get_ports {TRIG_IO}]
+# For documentation purposes, these are the input max/min delays for TRIG_IO:
+# - Input delay assuming zero trace delay and TRIG_IO buffer min switching
+# time (B->A) = 0.1 ns.
+# - TRIG_IO buffer max switching time (B->A = input) = 3.7 ns + same trace
+# length as for output (8.479).
+
+# Assuming no delay on external clock distribution.
+
+# Account for the PPS min output delay only (for the case two X410 are directly
+# connected to each other).
+set pps_min_in_delay $trig_min_out_delay
+
+# PPS_IN trace length DB = 0.535 + 0.133 + 0.117 + 0.061 + 2.745 inch = 3.591 inch
+# PPS_IN trace length MB = 5.726 inch
+# PPS switch max propagation delay = 3.6
+
+# Assume 50% of the clock period is used for external PPS clock distribution as
+# the PPS out is used to synchronize one X410 (master) with another X410
+# (slave) the PPS out (trig_io) delay is added to the PPS input.
+set pps_max_in_delay [expr {9.317 * 0.17 + 3.6 + 0.5 * $ref_clk_period + $trig_max_out_delay}]
+
+# Apply PPS input constraints.
+set_input_delay -clock [get_clocks ref_clk] -min $pps_min_in_delay [get_ports {PPS_IN}]
+set_input_delay -clock [get_clocks ref_clk] -max $pps_max_in_delay [get_ports {PPS_IN}]
+
+# PPS clock domain crossing BRC -> PRC on the aligned edge.
+# Use a data path of half PLL reference clock period to make sure the value is
+# captured without metastability.
+set_max_delay -from [get_cells -hierarchical pps_delayed_brc_reg] \
+ -to [get_clocks pll_ref_clk*] [expr {$pll_ref_clk_period/2}]
+
+
+###############################################################################
+# LMK sync
+###############################################################################
+
+# The timings are derived from simulation.
+
+# Clock Buffer ADCLK944 -> FPGA.
+set buffer_to_fpga_min_clk_delay 0.997
+set buffer_to_fpga_max_clk_delay 1.154
+
+# Clock Buffer ADCLK944 -> Sample clock PLL (LMK04832).
+set buffer_to_spll_min_clk_delay 0.000
+set buffer_to_spll_max_clk_delay 0.014
+
+# FPGA -> Sample clock PLL SYNC input.
+set fpga_to_spll_min_clk_delay 0.381
+set fpga_to_spll_max_clk_delay 0.460
+
+# Sample clock PLL requirements.
+set lmk_sync_input_hold 4.000
+set lmk_sync_input_setup 4.000
+
+set lmk_sync_output_max_delay [expr {$fpga_to_spll_max_clk_delay + $buffer_to_fpga_max_clk_delay + \
+ $lmk_sync_input_setup - $buffer_to_spll_min_clk_delay}]
+set lmk_sync_output_min_delay [expr {$fpga_to_spll_min_clk_delay + $buffer_to_fpga_min_clk_delay - \
+ $buffer_to_spll_max_clk_delay - $lmk_sync_input_hold}]
+set_output_delay -clock ref_clk -max $lmk_sync_output_max_delay [get_ports {LMK_SYNC}]
+set_output_delay -clock ref_clk -min $lmk_sync_output_min_delay [get_ports {LMK_SYNC}]
+
+
+###############################################################################
+# SPLL SYSREF Capture
+###############################################################################
+
+# SYSREF is generated by the LMK04832 clocking chip (SPLL), which also produces
+# the PLL reference clock (PRC) used to generate data clocks with a MMCM. Both
+# SYSREF and PLL reference clock are directly fed into the RFSoC.
+# SYSREF is captured by the FPGA fabric in the PRC clock domain (MMCM's PRC
+# output) with a double synchronizer and then transfered to the RFDC clock
+# domain. Both SYSREF versions (PRC and RFDC) are used by downstream logic for
+# sync. purposes.
+# SYSREF is a continuous signal running at PRC freq. / 25, and it is
+# intentionally shifted in the LMK chip to align it closer to the
+# PRC's falling edge.
+# The added delay follows the formula:
+# SYSREF LMK delay = 22 * sample clock period
+# The highest sampling frequency supported in MPM (3.072 GHz) is used for
+# timing constrains. Therefore, SYSREF LMK's delay = 22 * (1 / 3.072e9).
+set sysref_lmk_delay 7.161
+#
+# These are the signals' lengths and corresponding delays (assuming 170 ps/in):
+# - SYSREF --> 5794 mils (5.794 inches) = 0.985 ns
+# - PRC --> 5668 mils (5.668 inches) = 0.964 ns
+#
+# For min/max input delay calculations, it is assumed min prop. delay of 0 ns,
+# which essentially over-constrains SYSREF.
+#
+# The max input delay is the latest that SYSREF may arrive w.r.t PRC, and it is
+# calculated as follows:
+# Input delay (max) = SYSREF's LMK delay + SYSREF prop. delay (max)
+# - PRC prop. delay (min)
+set sysref_max_input_delay [expr {$sysref_lmk_delay + 0.985 - 0}]
+#
+# The min input delay is the earliest that SYSREF may arrive w.r.t PRC, and it
+# is calculated as follows:
+# Input delay (min) = SYSREF's LMK delay + SYSREF prop. delay (min)
+# - PRC prop. delay (min)
+set sysref_min_input_delay [expr {$sysref_lmk_delay + 0 - 0.964}]
+
+set_input_delay -clock pll_ref_clk -max $sysref_max_input_delay [get_ports {SYSREF_FABRIC_P}]
+set_input_delay -clock pll_ref_clk -min $sysref_min_input_delay [get_ports {SYSREF_FABRIC_P}]
+
+
+###############################################################################
+# DB GPIO
+# This interface is defined as system synchronous to pll_ref_clk.
+# Some timing constants in this section are declared in
+# <repo>/fpga/usrp3/top/x400/constraints/timing/shared_constants.sdc
+###############################################################################
+
+# Set output constraints for all ports.
+set db_gpio_ports [get_ports {DB0_GPIO[*] DB1_GPIO[*]}]
+set_output_delay -clock [get_clocks pll_ref_clk] -min $db_gpio_fpga_min_out $db_gpio_ports
+set_output_delay -clock [get_clocks pll_ref_clk] -max $db_gpio_fpga_max_out $db_gpio_ports
+
+# Output enable signal is available one clock cycle ahead of valid data, this
+# enables the use of multi-cycle paths.
+set db_gpio_out_en_regs [get_cells -hierarchical -filter \
+ {PRIMITIVE_TYPE =~ REGISTER.*.* && NAME =~ "*bytestream_output_enable*"}]
+set_multicycle_path 2 -setup -from $db_gpio_out_en_regs -to $db_gpio_ports
+set_multicycle_path 1 -hold -from $db_gpio_out_en_regs -to $db_gpio_ports
+
+# Calculate output delays back from capturing edge, add board delay and clock
+# difference.
+# Assume worst case as data being generated late and receiving an early clock:
+# - Max CPLD TCO
+# - Max data propagation delay
+# - Max CPLD clock propagation delay and minimum FPGA clock propagation delay
+# - Maximum delay from MC100EPT23 clock buffer
+set_input_delay -clock pll_ref_clk \
+ -max [expr {$pll_ref_clk_period - $db_gpio_cpld_max_out + $db_gpio_board_max_delay \
+ + $db_cpld_prc_clock_prop_max - $fpga_prc_clock_prop_min + $clock_translate_max}] \
+ $db_gpio_ports
+
+# Negate minimum output delay as it is defined from the change to the start
+# clock edge.
+# Assume worst case as data being generated early and receiving an late clock:
+# - Min CPLD TCO
+# - Min data propagation delay (0)
+# - Min CPLD clock propagation delay and max FPGA clock propagation delay
+set_input_delay -clock pll_ref_clk \
+ -min [expr {- $db_gpio_cpld_min_out \
+ - $db_gpio_board_min_delay \
+ - $db_cpld_prc_clock_prop_min + $fpga_prc_clock_prop_max}] \
+ $db_gpio_ports
+
+
+###############################################################################
+# x4xx_ps_rfdc_bd
+###############################################################################
+
+# The calibration_muxes component contains a clock crossing from some GPIO
+# component instances that are synchronous to a configuration clock and ending
+# in some AXI registers synchronous to data clock. The GPIO registers are
+# essentially constant. When they are changing (due to a register write), the
+# latching registers can definitely become metastable, so the software must
+# ensure that the corrupted data appears at a safe time.
+set gpio_regs [get_pins -of [get_cells -filter {IS_SEQUENTIAL && NAME =~ *rfdc/calibration_muxes/axi_gpio*} -hier] -filter {IS_CLOCK}]
+set mux_regs [get_cells -hier -filter {IS_SEQUENTIAL && NAME =~ *rfdc/calibration_muxes/gpio_to_axis_mux*}]
+set_false_path -from $gpio_regs -to $mux_regs
+
+# This property tells Vivado that we require these clocks to be well aligned.
+# We have synchronous clock domain crossings between these clocks that can have
+# large hold violations after placement due to uneven clock loading.
+set_property CLOCK_DELAY_GROUP DataClkGroup [get_nets -hier -filter {\
+ NAME=~*/rfdc/data_clock_mmcm/inst/CLK_CORE_DRP_I/clk_inst/data_clk ||\
+ NAME=~*/rfdc/data_clock_mmcm/inst/CLK_CORE_DRP_I/clk_inst/data_clk_2x ||\
+ NAME=~*/rfdc/data_clock_mmcm/inst/CLK_CORE_DRP_I/clk_inst/pll_ref_clk_out ||\
+ NAME=~*/rfdc/data_clock_mmcm/inst/CLK_CORE_DRP_I/clk_inst/rfdc_clk_2x ||\
+ NAME=~*/rfdc/data_clock_mmcm/inst/CLK_CORE_DRP_I/clk_inst/rfdc_clk \
+}]
+
+# We treat rfdc_clk and data_clk buffers as asynchronous, with knowledge that
+# code clocked in this domain will be reset after this clocked is enabled. This
+# will make timing easier to meet on these clock domains.
+set_false_path -from [get_pins -hierarchical -filter {NAME =~ */rfdc/clock_gates_0/*rEnableRfdcBufg1x*/C}] \
+ -to [get_pins -hierarchical -filter {NAME =~ */rfdc/rf_clock_buffers/rfdc_clk_1x_buf/*BUFGCE*/CE}]
+
+set_false_path -from [get_pins -hierarchical -filter {NAME =~ */rfdc/clock_gates_0/*rEnableRfdcBufg2x*/C}] \
+ -to [get_pins -hierarchical -filter {NAME =~ */rfdc/rf_clock_buffers/rfdc_clk_2x_buf/*BUFGCE*/CE}]
+
+set_false_path -from [get_pins -hierarchical -filter {NAME =~ */rfdc/clock_gates_0/*rEnableDataBufg1x*/C}] \
+ -to [get_pins -hierarchical -filter {NAME =~ */rfdc/clock_gates_0/*DataClk1xSafeBufg/CE}]
+
+set_false_path -from [get_pins -hierarchical -filter {NAME =~ */rfdc/clock_gates_0/*rEnableDataBufg2x*/C}] \
+ -to [get_pins -hierarchical -filter {NAME =~ */rfdc/clock_gates_0/*DataClk2xSafeBufg/CE}]
+
+
+###############################################################################
+# Misc Constraints
+###############################################################################
+
+# Double synchronizer false paths.
+set_false_path -to [get_pins -hierarchical -filter {NAME =~ */synchronizer_false_path/stages[0].value_reg[0][*]/D}]
+set_false_path -to [get_pins -hierarchical -filter {NAME =~ */rf_reset_controller*/*_ms_reg/D}]
+set_false_path -to [get_pins -hierarchical -filter {NAME =~ */rfdc/rf_nco_reset_0/*_ms*/D}]
+
+# GTY_RCV_CLK_* is driven by a OBUFDS_GTE4 buffer, which has an asynchronous
+# clock-enable pin.
+# By experimentation, it was observed that explicitly setting a false_path to
+# this pin improved timing.
+set gty_rcv_clk_buff_ceb [get_pins -of_objects [get_cells -of_objects [all_fanin -flat -startpoints_only [get_ports {GTY_RCV_CLK_P}]]] -filter {NAME=~ "*CEB"}]
+set_false_path -from [get_clocks {clk40}] -through $gty_rcv_clk_buff_ceb
+
+
+###############################################################################
+# Asynchronous / misc. I/O constraints
+# Loosely constrain these to prevent warnings in Vivado.
+# Using set_input_delay associates the I/Os to a clock group, but
+# set_(min|max)_delay overwrites the setup/hold analysis values.
+###############################################################################
+
+set async_inputs [get_ports {FPGA_AUX_REF}]
+
+set_input_delay -clock [get_clocks async_in_clk] 0.000 $async_inputs
+set_max_delay -from $async_inputs 50.000
+set_min_delay -from $async_inputs 0.000
+
+
+set async_outputs [get_ports {FABRIC_CLK_OUT_P PPS_LED}]
+
+set_output_delay -clock [get_clocks async_out_clk] 0.000 $async_outputs
+set_max_delay -to $async_outputs 50.000
+set_min_delay -to $async_outputs 0.000
diff --git a/fpga/usrp3/top/x400/constraints/timing/dram.xdc b/fpga/usrp3/top/x400/constraints/timing/dram.xdc
new file mode 100644
index 000000000..ed2d2aa64
--- /dev/null
+++ b/fpga/usrp3/top/x400/constraints/timing/dram.xdc
@@ -0,0 +1,55 @@
+#
+# Copyright 2021 Ettus Research, a National Instruments Brand
+#
+# SPDX-License-Identifier: LGPL-3.0-or-later
+#
+# Description:
+# DRAM timing constraints for X410.
+#
+
+set DramSysClockPeriod 9.996
+set DramSysClockWave {0.0 4.998}
+create_clock -name Dram0SysClock -period $DramSysClockPeriod -waveform $DramSysClockWave [get_ports {DRAM0_REFCLK_P}]
+create_clock -name Dram1SysClock -period $DramSysClockPeriod -waveform $DramSysClockWave [get_ports {DRAM1_REFCLK_P}]
+
+## This calibration signal is a static signal. Once asserted it will stay HIGH.
+## The multi cycle path constraint is added to improve timing.
+set_multicycle_path -setup 8 -from [get_pins */inst/u_ddr4_mem_intfc/u_ddr_cal_top/calDone*/C]
+set_multicycle_path -end -hold 7 -from [get_pins */inst/u_ddr4_mem_intfc/u_ddr_cal_top/calDone*/C]
+
+## These signals once asserted, stay asserted for multiple clock cycles.
+## False path constraint is added to improve the HOLD timing.
+set_false_path -hold -to [get_pins */inst/*/*/*/*/*/*.u_xiphy_control/xiphy_control/RIU_ADDR*]
+set_false_path -hold -to [get_pins */inst/*/*/*/*/*/*.u_xiphy_control/xiphy_control/RIU_WR_DATA*]
+
+## Multi-cycle path constraints for Fabric - RIU clock domain crossing signals
+set_max_delay 5.0 -datapath_only -from [get_pins */inst/*/*/*/u_ddr_cal_addr_decode/io_ready_lvl_reg/C] -to [get_pins */inst/*/u_io_ready_lvl_sync/SYNC[*].sync_reg_reg[0]/D]
+set_max_delay 5.0 -datapath_only -from [get_pins */inst/*/*/*/u_ddr_cal_addr_decode/io_read_data_reg[*]/C] -to [get_pins */inst/*/u_io_read_data_sync/SYNC[*].sync_reg_reg[0]/D]
+set_max_delay 3.0 -datapath_only -from [get_pins */inst/*/*/*/phy_ready_riuclk_reg/C] -to [get_pins */inst/*/u_phy2clb_phy_ready_sync/SYNC[*].sync_reg_reg[0]/D]
+set_max_delay 3.0 -datapath_only -from [get_pins */inst/*/*/*/bisc_complete_riuclk_reg/C] -to [get_pins */inst/*/u_phy2clb_bisc_complete_sync/SYNC[*].sync_reg_reg[0]/D]
+set_max_delay 3.0 -datapath_only -from [get_pins */inst/*/*/io_addr_strobe_lvl_riuclk_reg/C] -to [get_pins */inst/*/u_io_addr_strobe_lvl_sync/SYNC[*].sync_reg_reg[0]/D]
+set_max_delay 3.0 -datapath_only -from [get_pins */inst/*/*/io_write_strobe_riuclk_reg/C] -to [get_pins */inst/*/u_io_write_strobe_sync/SYNC[*].sync_reg_reg[0]/D]
+set_max_delay 3.0 -datapath_only -from [get_pins */inst/*/*/io_address_riuclk_reg[*]/C] -to [get_pins */inst/*/u_io_addr_sync/SYNC[*].sync_reg_reg[0]/D]
+set_max_delay 3.0 -datapath_only -from [get_pins */inst/*/*/io_write_data_riuclk_reg[*]/C] -to [get_pins */inst/*/u_io_write_data_sync/SYNC[*].sync_reg_reg[0]/D]
+set_max_delay 10.0 -datapath_only -from [get_pins */inst/*/en_vtc_in_reg/C] -to [get_pins */inst/*/u_en_vtc_sync/SYNC[*].sync_reg_reg[0]/D]
+set_max_delay 10.0 -datapath_only -from [get_pins */inst/*/*/riu2clb_valid_r1_riuclk_reg[*]/C] -to [get_pins */inst/*/u_riu2clb_valid_sync/SYNC[*].sync_reg_reg[0]/D]
+set_max_delay 10.0 -datapath_only -from [get_pins */inst/*/*/*/phy2clb_fixdly_rdy_low_riuclk_int_reg[*]/C] -to [get_pins */inst/*/u_phy2clb_fixdly_rdy_low/SYNC[*].sync_reg_reg[0]/D]
+set_max_delay 10.0 -datapath_only -from [get_pins */inst/*/*/*/phy2clb_fixdly_rdy_upp_riuclk_int_reg[*]/C] -to [get_pins */inst/*/u_phy2clb_fixdly_rdy_upp/SYNC[*].sync_reg_reg[0]/D]
+set_max_delay 10.0 -datapath_only -from [get_pins */inst/*/*/*/phy2clb_phy_rdy_low_riuclk_int_reg[*]/C] -to [get_pins */inst/*/u_phy2clb_phy_rdy_low/SYNC[*].sync_reg_reg[0]/D]
+set_max_delay 10.0 -datapath_only -from [get_pins */inst/*/*/*/phy2clb_phy_rdy_upp_riuclk_int_reg[*]/C] -to [get_pins */inst/*/u_phy2clb_phy_rdy_upp/SYNC[*].sync_reg_reg[0]/D]
+set_max_delay 10.0 -datapath_only -from [get_pins */inst/*/rst_r1_reg/C] -to [get_pins */inst/*/u_fab_rst_sync/SYNC[*].sync_reg_reg[0]/D]
+set_max_delay 3.0 -datapath_only -from [get_pins */inst/*/*/*/clb2phy_t_b_addr_riuclk_reg/C] -to [get_pins */inst/*/*/*/clb2phy_t_b_addr_i_reg[0]/D]
+set_max_delay 3.0 -datapath_only -from [get_pins */inst/*/*/*/*/slave_en_lvl_reg/C] -to [get_pins */inst/*/*/*/*/u_slave_en_sync/SYNC[*].sync_reg_reg[0]/D]
+set_max_delay 3.0 -datapath_only -from [get_pins */inst/*/*/*/*/slave_we_r_reg/C] -to [get_pins */inst/*/*/*/*/u_slave_we_sync/SYNC[*].sync_reg_reg[0]/D]
+set_max_delay 3.0 -datapath_only -from [get_pins */inst/*/*/*/*/slave_addr_r_reg[*]/C] -to [get_pins */inst/*/*/*/*/u_slave_addr_sync/SYNC[*].sync_reg_reg[0]/D]
+set_max_delay 3.0 -datapath_only -from [get_pins */inst/*/*/*/*/slave_di_r_reg[*]/C] -to [get_pins */inst/*/*/*/*/u_slave_di_sync/SYNC[*].sync_reg_reg[0]/D]
+set_max_delay 3.0 -datapath_only -from [get_pins */inst/*/*/*/*/slave_rdy_cptd_sclk_reg/C] -to [get_pins */inst/*/*/*/*/u_slave_rdy_cptd_sync/SYNC[*].sync_reg_reg[0]/D]
+set_max_delay 12.0 -datapath_only -from [get_pins */inst/*/*/*/*/slave_rdy_lvl_fclk_reg/C] -to [get_pins */inst/*/*/*/*/u_slave_rdy_sync/SYNC[*].sync_reg_reg[0]/D]
+set_max_delay 12.0 -datapath_only -from [get_pins */inst/*/*/*/*/slave_do_fclk_reg[*]/C] -to [get_pins */inst/*/*/*/*/u_slave_do_sync/SYNC[*].sync_reg_reg[0]/D]
+set_false_path -through [get_pins */inst/u_ddr4_infrastructure/sys_rst]
+set_false_path -from [get_pins */inst/*/input_rst_design_reg/C] -to [get_pins */inst/*/rst_div_sync_r_reg[0]/D]
+set_false_path -from [get_pins */inst/*/input_rst_design_reg/C] -to [get_pins */inst/*/rst_riu_sync_r_reg[0]/D]
+set_false_path -from [get_pins */inst/*/input_rst_design_reg/C] -to [get_pins */inst/*/rst_mb_sync_r_reg[0]/D]
+set_false_path -from [get_pins */inst/*/rst_async_riu_div_reg/C] -to [get_pins */inst/*/rst_div_sync_r_reg[0]/D]
+set_false_path -from [get_pins */inst/*/rst_async_mb_reg/C] -to [get_pins */inst/*/rst_mb_sync_r_reg[0]/D]
+set_false_path -from [get_pins */inst/*/rst_async_riu_div_reg/C] -to [get_pins */inst/*/rst_riu_sync_r_reg[0]/D]
diff --git a/fpga/usrp3/top/x400/constraints/timing/qsfp_10gbe.xdc b/fpga/usrp3/top/x400/constraints/timing/qsfp_10gbe.xdc
new file mode 100644
index 000000000..2438138e3
--- /dev/null
+++ b/fpga/usrp3/top/x400/constraints/timing/qsfp_10gbe.xdc
@@ -0,0 +1,19 @@
+#
+# Copyright 2021 Ettus Research, a National Instruments Brand
+#
+# SPDX-License-Identifier: LGPL-3.0-or-later
+#
+# Description:
+# 10 GbE Timing Constraints.
+#
+
+# Specify which clock is used for dclk in the 10 GbE IP.
+set DCLK_NAME clk100
+
+# Constraints taken from xge_pcs_pma_exceptions.xdc in the example design.
+set_max_delay -from [get_clocks -of_objects [get_pins -hierarchical -filter {NAME =~ */channel_inst/*_CHANNEL_PRIM_INST/RXOUTCLK}]] -to [get_clocks -of_objects [get_pins -hierarchical -filter {NAME =~ */channel_inst/*_CHANNEL_PRIM_INST/TXOUTCLK}]] -datapath_only 6.40
+set_max_delay -from [get_clocks -of_objects [get_pins -hierarchical -filter {NAME =~ */channel_inst/*_CHANNEL_PRIM_INST/TXOUTCLK}]] -to [get_clocks -of_objects [get_pins -hierarchical -filter {NAME =~ */channel_inst/*_CHANNEL_PRIM_INST/RXOUTCLK}]] -datapath_only 6.40
+set_max_delay -from [get_clocks -of_objects [get_pins -hierarchical -filter {NAME =~ */channel_inst/*_CHANNEL_PRIM_INST/RXOUTCLK}]] -to [get_clocks $DCLK_NAME] -datapath_only 6.40
+set_max_delay -from [get_clocks -of_objects [get_pins -hierarchical -filter {NAME =~ */channel_inst/*_CHANNEL_PRIM_INST/TXOUTCLK}]] -to [get_clocks $DCLK_NAME] -datapath_only 6.40
+set_max_delay -from [get_clocks $DCLK_NAME] -to [get_clocks -of_objects [get_pins -hierarchical -filter {NAME =~ */channel_inst/*_CHANNEL_PRIM_INST/TXOUTCLK}]] -datapath_only 10.000
+set_max_delay -from [get_clocks $DCLK_NAME] -to [get_clocks -of_objects [get_pins -hierarchical -filter {NAME =~ */channel_inst/*_CHANNEL_PRIM_INST/RXOUTCLK}]] -datapath_only 10.000
diff --git a/fpga/usrp3/top/x400/constraints/timing/shared_constants.sdc b/fpga/usrp3/top/x400/constraints/timing/shared_constants.sdc
new file mode 100644
index 000000000..e7d389435
--- /dev/null
+++ b/fpga/usrp3/top/x400/constraints/timing/shared_constants.sdc
@@ -0,0 +1,130 @@
+#
+# Copyright 2021 Ettus Research, a National Instruments Brand
+#
+# SPDX-License-Identifier: LGPL-3.0-or-later
+#
+# Description:
+# Shared constants for the X410 FPGA and the ZBX CPLD.
+#
+
+# These output delays are more or less arbitrarily chosen, but they dictate the
+# delays at the input of the DB CPLD.
+# Since the CPLD is built in Quartus, the file extension is .sdc.
+set synth_sync_hold_requirement 1.0
+set synth_sync_setup_requirement 8.5
+
+# A MC100EPT23 clock translator is placed on the daughterboard to convert
+# pll_ref_clk clock IO Standard to 3.3V. The minimum and maximum delays across
+# this part are 1.1 ns and 1.8 ns, respectively.
+# https://www.onsemi.com/pub/Collateral/MC100EPT23-D.PDF
+set clock_translate_min 1.1
+set clock_translate_max 1.8
+
+## DB GPIO interface.
+# The following values have been adjusted after verifying the slack on input
+# and output path for the Post-synthesized designs for FPGA (Vivado) and CPLD
+# (Quartus). Values are chosen as those that provide the most slack for FPGA
+# timing, while still meeting timing on the CPLD.
+
+# FPGA output constraints
+set db_gpio_fpga_min_out 0.000
+set db_gpio_fpga_max_out 3.250
+
+# CPLD output constraints
+set db_gpio_cpld_min_out -2.000
+set db_gpio_cpld_max_out 8.500
+
+# The longest traces on the DB GPIO interface.
+# In order to compute the db_gpio_board_max_delay, the longest GPIO trace from
+# the FPGA to any of the DB connector was simulated, and its worst-case value
+# was added to the worst-case value obtained while simulating the longest GPIO
+# trace on the DB. Both directions (FPGA <-> CPLD) were considered when
+# computing the longest propagation delays. Propagation through the Board to
+# board connector is assumed shorter than the effect of having the edge
+# propagation time twice, as well as adding the two longest traces, instead of
+# the longest corresponding pair.
+# Longest trace | Trace length | Worst-case delay
+# MB: DB0_GPIO[19] | 4.25 in | 912 ps
+# DB: MB_FPGA_GPIO_A8 | 3.83 in | 862 ps
+set db_gpio_board_max_delay 1.774
+
+# The shortest traces on the DB GPIO interface are (assuming 170.0 ps/in).
+# A similar consideration was made as for db_gpio_board_max_delay, but using
+# the shortest traces in each CCA.
+# In this case, edge propagation was not taken into account, as the trace delay
+# can act as the worst-case minimum.
+# Shorted trace | Trace length | Trace delay
+# MB: DB1_GPIO[8] | 2.23 in | 379 ps
+# DB: MB_FPGA_GPIO_B12| 2.57 in | 436 ps
+set db_gpio_board_min_delay 0.815
+
+# DB and FPGA both use PLL reference clock from a common clock chip.
+# The common chip that drives these clocks is a LMK04832.
+# There exist two additional clock buffers within the trace taking the clock to
+# the daughterboard CPLD, a ADCLK944 located in the DB, and a MC100EPT23 near
+# the CPLD which takes care of level translation.
+# The largest delay that can exist between clocks exists when the LMK04832
+# presents its max skew between outputs and when all clock buffers present
+# their maximum delay.
+# MC100EPT23 propagation delays will be handled separately in constraints due
+# to their significant impact in timing closure, as well as to enable support
+# for various corner-cases.
+# Board delays were simulated in HyperLynx. Minimum delays considered time
+# between start of edge at the source to the start of edge at destination.
+# Maximum delays considered time between the start of an edge at the source and
+# the settling of the edge at destination. Corner cases were considered for IC
+# modeling.
+#
+# The clock path to the FPGA is composed by a single trace:
+# - Minimum clock propagation delay to FPGA = 815 ps.
+# - Maximum clock propagation delay to FPGA = 1.329 ps.
+#
+# The clock path to the CPLD (w/o MC100EPT23) is comprised by multiple traces:
+# - Path from MB LMK04832 to DB connector
+# - Minimum delay : 1636 ps
+# - Path from DB Connector to DB ADCLK944
+# - Minimum delay : 299 ps
+# - Path from DB ADCLK944 to CPLD:
+# - Minimum delay : 197 ps
+#
+# The clock path to the CPLD (w/ MC100EPT23) is comprised of multiple traces:
+# - Path from MB LMK04832 to DB connector
+# - Minimum delay : 1636 ps
+# - Maximum delay : 1890 ps
+# - Path from DB Connector to DB ADCLK944
+# - Minimum delay : 299 ps
+# - Maximum delay : 397 ps
+# - Path from DB ADCLK944 to MC100EPT23:
+# - Minimum delay : 120 ps
+# - Maximum delay : 411 ps
+# - Path from MC100EPT23 to CPLD:
+# - Minimum delay : 365 ps
+# - Maximum delay : 847 ps
+#
+# The minimum and maximum delays for all traces can be added to account for the
+# total board delay to the CPLD:
+#
+# Max total Board delay = 1890 + 397 + 411 + 847 = 3545 ps
+#
+# Min total Board delay = 1636 + 299 + 197 = 2132 ps
+
+# This leaves the worst-case clock arrival values for the different ICs as:
+
+# Max total Board delay + (Max LMK Skew) + (Max DB ADCLK Prop)
+# 3.545 + .1 + .130 = 3.775 ns,
+set db_cpld_prc_clock_prop_max 3.775
+
+# Min total Board delay - (Max LMK Skew) + (Min DB ADCLK Prop)
+# 2.132 - .1 + .07 = 2.102 ns,
+set db_cpld_prc_clock_prop_min 2.102
+
+# Board delay + (Max LMK Skew)
+# 1.329 + .1 = 1.429 ns
+set fpga_prc_clock_prop_max 1.429
+
+# Board delay - (Max LMK Skew)
+# .815 - .1 = 0.715 ns
+set fpga_prc_clock_prop_min 0.715
+
+# When combining these values, the LMK Skew will be accounted for twice,
+# which will just result in more conservative constraints.