#
# Copyright 2014 Ettus Research LLC
#

#*******************************************************************************
## Primary clock definitions

# Define clocks
create_clock -name FPGA_CLK            -period   5.000 -waveform {0.000 2.500}   [get_ports FPGA_CLK_p]
create_clock -name FPGA_REFCLK_10MHz   -period 100.000 -waveform {0.000 50.000}  [get_ports FPGA_REFCLK_10MHz_p]
create_clock -name FPGA_125MHz_CLK     -period   8.000 -waveform {0.000 4.000}   [get_ports FPGA_125MHz_CLK]
create_clock -name DB0_ADC_DCLK        -period   5.000 -waveform {0.000 2.500}   [get_ports DB0_ADC_DCLK_P]
create_clock -name DB1_ADC_DCLK        -period   5.000 -waveform {0.000 2.500}   [get_ports DB1_ADC_DCLK_P]
create_clock -name IoRxClock           -period   4.000 -waveform {0.000 2.000}   [get_ports IoRxClock]
# Create virtual clock aligned with FPGA_CLK that is twice the frequency for DAC IO Timing. 
create_clock -name VIRT_DAC_CLK        -period   2.500 -waveform {0.000 1.250}

# Set clock properties
set_input_jitter [get_clocks FPGA_CLK] 0.05

set var_fpga_clk_delay  1.545    ;# LMK_Delay=0.900ns, LMK->FPGA=0.645ns
set var_fpga_clk_skew   0.100
set_clock_latency -source -early [expr $var_fpga_clk_delay - $var_fpga_clk_skew/2] [get_clocks FPGA_CLK]
set_clock_latency -source -late  [expr $var_fpga_clk_delay + $var_fpga_clk_skew/2] [get_clocks FPGA_CLK]

set var_adc_clk_delay   8.440    ;# LMK->ADC=1.04ns, ADC->FPGA=0.750ns, ADC=6.65ns=(0.69*5ns)+5.7-2.5 
set var_adc_clk_skew    0.500    ;# The real skew is ~3.5ns with which we will not meet static timing. Ignore skew by temp variations.
set_clock_latency -source -early [expr $var_adc_clk_delay - $var_adc_clk_skew/2] [get_clocks DB0_ADC_DCLK]
set_clock_latency -source -late  [expr $var_adc_clk_delay + $var_adc_clk_skew/2] [get_clocks DB0_ADC_DCLK]
set_clock_latency -source -early [expr $var_adc_clk_delay - $var_adc_clk_skew/2] [get_clocks DB1_ADC_DCLK]
set_clock_latency -source -late  [expr $var_adc_clk_delay + $var_adc_clk_skew/2] [get_clocks DB1_ADC_DCLK]

# FPGA_CLK_p/n is externally phase shifted to allow for crossing from the ADC clock domain
# to the radio_clk (aka FPGA_CLK_p/n) clock domain. To ensure this timing is consistent,
# lock the locations of the MMCM and BUFG to generate radio_clk.
set_property LOC MMCME2_ADV_X0Y0 [get_cells -hierarchical -filter {NAME =~ "*radio_clk_gen/*mmcm_adv_inst"}]
set_property LOC BUFGCTRL_X0Y8   [get_cells -hierarchical -filter {NAME =~ "*radio_clk_gen/*clkout1_buf"}]

# The PCIe specific 40MHz and 200MHz clocks are only active in clock regious X0Y0 and X1Y0 so we use BUFHs
# to distribute them. To do so, we have to use a PLL because the MMCM in that region is used by radio_clk_gen
# Since that MMCM is LOC constrained, we must LOC constrain this PLL as well.
set_property LOC PLLE2_ADV_X0Y0 [get_cells -hierarchical -filter {NAME =~ "*pcie_clk_gen/*plle2_adv_inst"}]


#*******************************************************************************
## Generated clock definitions

create_generated_clock -name DB0_DAC_DCI  -source [get_pins gen_db0/oddr_clk/C] -divide_by 1 [get_ports DB0_DAC_DCI_P]
create_generated_clock -name DB1_DAC_DCI  -source [get_pins gen_db1/oddr_clk/C] -divide_by 1 [get_ports DB1_DAC_DCI_P]
create_generated_clock -name IoTxClock -multiply_by 1                                                               \
                       -source [get_pins -hier -filter {NAME =~ lvfpga_chinch_inst/*/TxClockGenx/TxUseMmcm.TxMmcm/CLKOUT0}] \
                       [get_ports {IoTxClock}]


#*******************************************************************************
## Aliases for auto-generated clocks

create_generated_clock -name radio_clk                [get_pins -hierarchical -filter {NAME =~ "*radio_clk_gen/*/CLKOUT0"}]
create_generated_clock -name radio_clk_2x             [get_pins -hierarchical -filter {NAME =~ "*radio_clk_gen/*/CLKOUT1"}]
#create_generated_clock -name dac_dci_clk              [get_pins -hierarchical -filter {NAME =~ "*radio_clk_gen/*/CLKOUT2"}]
create_generated_clock -name bus_clk                  [get_pins -hierarchical -filter {NAME =~ "*bus_clk_gen/*/CLKOUT0"}]
create_generated_clock -name bus_clk_div2             [get_pins -hierarchical -filter {NAME =~ "*bus_clk_gen/*/CLKOUT2"}]
create_generated_clock -name ce_clk                   [get_pins -hierarchical -filter {NAME =~ "*bus_clk_gen/*/CLKOUT3"}]
create_generated_clock -name ioport2_clk              [get_pins -hierarchical -filter {NAME =~ "*bus_clk_gen/*/CLKFBOUT"}]
create_generated_clock -name rio40_clk                [get_pins -hierarchical -filter {NAME =~ "*pcie_clk_gen/*/CLKOUT0"}]
create_generated_clock -name ioport2_idelay_ref_clk   [get_pins -hierarchical -filter {NAME =~ "*pcie_clk_gen/*/CLKOUT1"}]


#*******************************************************************************
## Asynchronous clock groups

set_clock_groups -asynchronous -group [get_clocks bus_clk]      -group [get_clocks ioport2_clk]
set_clock_groups -asynchronous -group [get_clocks ioport2_clk]  -group [get_clocks rio40_clk]
set_clock_groups -asynchronous -group [get_clocks bus_clk]      -group [get_clocks radio_clk]
set_clock_groups -asynchronous -group [get_clocks bus_clk_div2] -group [get_clocks radio_clk]
set_clock_groups -asynchronous -group [get_clocks ioport2_clk]  -group [get_clocks IoPort2Wrapperx/RxLowSpeedClk]
set_clock_groups -asynchronous -group [get_clocks bus_clk]      -group [get_clocks FPGA_REFCLK_10MHz]
set_clock_groups -asynchronous -group [get_clocks ce_clk]       -group [get_clocks bus_clk]
set_clock_groups -asynchronous -group [get_clocks ce_clk]       -group [get_clocks radio_clk]


#*******************************************************************************
## ADC Interface

# At 200 MHz, static timing cannot be closed so we tune data delays on the capture
# interface from software at device creation time.
# The data is center aligned wrt to the SS Clock when it is launched from the ADC
# So we tune the data IDELAYS to half the range (16) so we have slack in both directions
# In the constraints we capture this by padding the dv_before and dv_after by half the
# tuning range of the IDELAY.

# Using typical values for ADC
set adc_clk_delay_wrt_center    0.000      ;# Possible {-1.340, -0.769, 0, 0.769}
set adc_in_dv_before_clk_edge   0.550      ;# Typical: 0.90ns
set adc_in_dv_after_clk_edge    0.550      ;# Typical: 0.95ns
set idelay_tune_range           2.500      ;# Refclk for IDELAY is 200MHz. Range of idelay is 0.5*period

set adc_in_delay_max [expr 2.500 - $adc_in_dv_before_clk_edge - $idelay_tune_range + $adc_clk_delay_wrt_center]
set adc_in_delay_min [expr $adc_in_dv_after_clk_edge + $idelay_tune_range - $adc_clk_delay_wrt_center]

set_input_delay -clock DB0_ADC_DCLK -max $adc_in_delay_max                         [get_ports {DB0_ADC_DA*}]
set_input_delay -clock DB0_ADC_DCLK -min $adc_in_delay_min                         [get_ports {DB0_ADC_DA*}]
set_input_delay -clock DB0_ADC_DCLK -max $adc_in_delay_max -clock_fall -add_delay  [get_ports {DB0_ADC_DA*}]
set_input_delay -clock DB0_ADC_DCLK -min $adc_in_delay_min -clock_fall -add_delay  [get_ports {DB0_ADC_DA*}]

set_input_delay -clock DB0_ADC_DCLK -max $adc_in_delay_max                         [get_ports {DB0_ADC_DB*}]
set_input_delay -clock DB0_ADC_DCLK -min $adc_in_delay_min                         [get_ports {DB0_ADC_DB*}]
set_input_delay -clock DB0_ADC_DCLK -max $adc_in_delay_max -clock_fall -add_delay  [get_ports {DB0_ADC_DB*}]
set_input_delay -clock DB0_ADC_DCLK -min $adc_in_delay_min -clock_fall -add_delay  [get_ports {DB0_ADC_DB*}]

set_input_delay -clock DB1_ADC_DCLK -max $adc_in_delay_max                         [get_ports {DB1_ADC_DA*}]
set_input_delay -clock DB1_ADC_DCLK -min $adc_in_delay_min                         [get_ports {DB1_ADC_DA*}]
set_input_delay -clock DB1_ADC_DCLK -max $adc_in_delay_max -clock_fall -add_delay  [get_ports {DB1_ADC_DA*}]
set_input_delay -clock DB1_ADC_DCLK -min $adc_in_delay_min -clock_fall -add_delay  [get_ports {DB1_ADC_DA*}]

set_input_delay -clock DB1_ADC_DCLK -max $adc_in_delay_max                         [get_ports {DB1_ADC_DB*}]
set_input_delay -clock DB1_ADC_DCLK -min $adc_in_delay_min                         [get_ports {DB1_ADC_DB*}]
set_input_delay -clock DB1_ADC_DCLK -max $adc_in_delay_max -clock_fall -add_delay  [get_ports {DB1_ADC_DB*}]
set_input_delay -clock DB1_ADC_DCLK -min $adc_in_delay_min -clock_fall -add_delay  [get_ports {DB1_ADC_DB*}]

# We use a simple synchronizer to cross ADC data over from the ADC_CLK domain to the radio_clk domain
# Use max delay constraints to ensure that the transition happens safely
set_min_delay                0.700 -from [get_cells {cap_db0/gen_lvds_pins[*].iddr_i}] \
                                   -to   [get_cells {cap_db0/adc_data_rclk_reg*[*]}]
set_min_delay                0.700 -from [get_cells {cap_db1/gen_lvds_pins[*].iddr_i}] \
                                   -to   [get_cells {cap_db1/adc_data_rclk_reg*[*]}]
set_max_delay -datapath_only 0.950 -from [get_cells {cap_db0/gen_lvds_pins[*].iddr_i}] \
                                   -to   [get_cells {cap_db0/adc_data_rclk_reg*[*]}]
set_max_delay -datapath_only 0.950 -from [get_cells {cap_db1/gen_lvds_pins[*].iddr_i}] \
                                   -to   [get_cells {cap_db1/adc_data_rclk_reg*[*]}]

# We also need to location constrain the first flops in the synchronizer to help the tools
# meet timing reliably

# ADC0
set_property BEL A5FF           [get_cells {cap_db0/adc_data_rclk_reg*[0]}]
set_property LOC SLICE_X1Y192   [get_cells {cap_db0/adc_data_rclk_reg*[0]}]
set_property BEL B5FF           [get_cells {cap_db0/adc_data_rclk_reg*[1]}]
set_property LOC SLICE_X1Y192   [get_cells {cap_db0/adc_data_rclk_reg*[1]}]
set_property BEL AFF            [get_cells {cap_db0/adc_data_rclk_reg*[2]}]
set_property LOC SLICE_X1Y190   [get_cells {cap_db0/adc_data_rclk_reg*[2]}]
set_property BEL BFF            [get_cells {cap_db0/adc_data_rclk_reg*[3]}]
set_property LOC SLICE_X1Y190   [get_cells {cap_db0/adc_data_rclk_reg*[3]}]
set_property BEL A5FF           [get_cells {cap_db0/adc_data_rclk_reg*[4]}]
set_property LOC SLICE_X1Y188   [get_cells {cap_db0/adc_data_rclk_reg*[4]}]
set_property BEL B5FF           [get_cells {cap_db0/adc_data_rclk_reg*[5]}]
set_property LOC SLICE_X1Y188   [get_cells {cap_db0/adc_data_rclk_reg*[5]}]
set_property BEL A5FF           [get_cells {cap_db0/adc_data_rclk_reg*[6]}]
set_property LOC SLICE_X1Y186   [get_cells {cap_db0/adc_data_rclk_reg*[6]}]
set_property BEL B5FF           [get_cells {cap_db0/adc_data_rclk_reg*[7]}]
set_property LOC SLICE_X1Y186   [get_cells {cap_db0/adc_data_rclk_reg*[7]}]
set_property BEL A5FF           [get_cells {cap_db0/adc_data_rclk_reg*[8]}]
set_property LOC SLICE_X1Y184   [get_cells {cap_db0/adc_data_rclk_reg*[8]}]
set_property BEL B5FF           [get_cells {cap_db0/adc_data_rclk_reg*[9]}]
set_property LOC SLICE_X1Y184   [get_cells {cap_db0/adc_data_rclk_reg*[9]}]
set_property BEL A5FF           [get_cells {cap_db0/adc_data_rclk_reg*[10]}]
set_property LOC SLICE_X1Y182   [get_cells {cap_db0/adc_data_rclk_reg*[10]}]
set_property BEL B5FF           [get_cells {cap_db0/adc_data_rclk_reg*[11]}]
set_property LOC SLICE_X1Y182   [get_cells {cap_db0/adc_data_rclk_reg*[11]}]
set_property BEL A5FF           [get_cells {cap_db0/adc_data_rclk_reg*[12]}]
set_property LOC SLICE_X1Y180   [get_cells {cap_db0/adc_data_rclk_reg*[12]}]
set_property BEL B5FF           [get_cells {cap_db0/adc_data_rclk_reg*[13]}]
set_property LOC SLICE_X1Y180   [get_cells {cap_db0/adc_data_rclk_reg*[13]}]
set_property BEL A5FF           [get_cells {cap_db0/adc_data_rclk_reg*[14]}]
set_property LOC SLICE_X1Y178   [get_cells {cap_db0/adc_data_rclk_reg*[14]}]
set_property BEL B5FF           [get_cells {cap_db0/adc_data_rclk_reg*[15]}]
set_property LOC SLICE_X1Y178   [get_cells {cap_db0/adc_data_rclk_reg*[15]}]
set_property BEL A5FF           [get_cells {cap_db0/adc_data_rclk_reg*[16]}]
set_property LOC SLICE_X1Y174   [get_cells {cap_db0/adc_data_rclk_reg*[16]}]
set_property BEL B5FF           [get_cells {cap_db0/adc_data_rclk_reg*[17]}]
set_property LOC SLICE_X1Y174   [get_cells {cap_db0/adc_data_rclk_reg*[17]}]
set_property BEL AFF            [get_cells {cap_db0/adc_data_rclk_reg*[18]}]
set_property LOC SLICE_X1Y172   [get_cells {cap_db0/adc_data_rclk_reg*[18]}]
set_property BEL BFF            [get_cells {cap_db0/adc_data_rclk_reg*[19]}]
set_property LOC SLICE_X1Y172   [get_cells {cap_db0/adc_data_rclk_reg*[19]}]
set_property BEL A5FF           [get_cells {cap_db0/adc_data_rclk_reg*[20]}]
set_property LOC SLICE_X1Y218   [get_cells {cap_db0/adc_data_rclk_reg*[20]}]
set_property BEL B5FF           [get_cells {cap_db0/adc_data_rclk_reg*[21]}]
set_property LOC SLICE_X1Y218   [get_cells {cap_db0/adc_data_rclk_reg*[21]}]
set_property BEL A5FF           [get_cells {cap_db0/adc_data_rclk_reg*[22]}]
set_property LOC SLICE_X1Y198   [get_cells {cap_db0/adc_data_rclk_reg*[22]}]
set_property BEL B5FF           [get_cells {cap_db0/adc_data_rclk_reg*[23]}]
set_property LOC SLICE_X1Y198   [get_cells {cap_db0/adc_data_rclk_reg*[23]}]
set_property BEL AFF            [get_cells {cap_db0/adc_data_rclk_reg*[24]}]
set_property LOC SLICE_X1Y196   [get_cells {cap_db0/adc_data_rclk_reg*[24]}]
set_property BEL BFF            [get_cells {cap_db0/adc_data_rclk_reg*[25]}]
set_property LOC SLICE_X1Y196   [get_cells {cap_db0/adc_data_rclk_reg*[25]}]
set_property BEL A5FF           [get_cells {cap_db0/adc_data_rclk_reg*[26]}]
set_property LOC SLICE_X1Y194   [get_cells {cap_db0/adc_data_rclk_reg*[26]}]
set_property BEL B5FF           [get_cells {cap_db0/adc_data_rclk_reg*[27]}]
set_property LOC SLICE_X1Y194   [get_cells {cap_db0/adc_data_rclk_reg*[27]}]

# ADC1
set_property BEL A5FF           [get_cells {cap_db1/adc_data_rclk_reg*[0]}]
set_property LOC SLICE_X1Y298   [get_cells {cap_db1/adc_data_rclk_reg*[0]}]
set_property BEL B5FF           [get_cells {cap_db1/adc_data_rclk_reg*[1]}]
set_property LOC SLICE_X1Y298   [get_cells {cap_db1/adc_data_rclk_reg*[1]}]
set_property BEL A5FF           [get_cells {cap_db1/adc_data_rclk_reg*[2]}]
set_property LOC SLICE_X1Y284   [get_cells {cap_db1/adc_data_rclk_reg*[2]}]
set_property BEL B5FF           [get_cells {cap_db1/adc_data_rclk_reg*[3]}]
set_property LOC SLICE_X1Y284   [get_cells {cap_db1/adc_data_rclk_reg*[3]}]
set_property BEL A5FF           [get_cells {cap_db1/adc_data_rclk_reg*[4]}]
set_property LOC SLICE_X1Y288   [get_cells {cap_db1/adc_data_rclk_reg*[4]}]
set_property BEL B5FF           [get_cells {cap_db1/adc_data_rclk_reg*[5]}]
set_property LOC SLICE_X1Y288   [get_cells {cap_db1/adc_data_rclk_reg*[5]}]
set_property BEL A5FF           [get_cells {cap_db1/adc_data_rclk_reg*[6]}]
set_property LOC SLICE_X1Y282   [get_cells {cap_db1/adc_data_rclk_reg*[6]}]
set_property BEL B5FF           [get_cells {cap_db1/adc_data_rclk_reg*[7]}]
set_property LOC SLICE_X1Y282   [get_cells {cap_db1/adc_data_rclk_reg*[7]}]
set_property BEL AFF            [get_cells {cap_db1/adc_data_rclk_reg*[8]}]
set_property LOC SLICE_X1Y296   [get_cells {cap_db1/adc_data_rclk_reg*[8]}]
set_property BEL BFF            [get_cells {cap_db1/adc_data_rclk_reg*[9]}]
set_property LOC SLICE_X1Y296   [get_cells {cap_db1/adc_data_rclk_reg*[9]}]
set_property BEL A5FF           [get_cells {cap_db1/adc_data_rclk_reg*[10]}]
set_property LOC SLICE_X1Y280   [get_cells {cap_db1/adc_data_rclk_reg*[10]}]
set_property BEL B5FF           [get_cells {cap_db1/adc_data_rclk_reg*[11]}]
set_property LOC SLICE_X1Y280   [get_cells {cap_db1/adc_data_rclk_reg*[11]}]
set_property BEL A5FF           [get_cells {cap_db1/adc_data_rclk_reg*[12]}]
set_property LOC SLICE_X1Y286   [get_cells {cap_db1/adc_data_rclk_reg*[12]}]
set_property BEL B5FF           [get_cells {cap_db1/adc_data_rclk_reg*[13]}]
set_property LOC SLICE_X1Y286   [get_cells {cap_db1/adc_data_rclk_reg*[13]}]
set_property BEL AFF            [get_cells {cap_db1/adc_data_rclk_reg*[14]}]
set_property LOC SLICE_X1Y274   [get_cells {cap_db1/adc_data_rclk_reg*[14]}]
set_property BEL BFF            [get_cells {cap_db1/adc_data_rclk_reg*[15]}]
set_property LOC SLICE_X1Y274   [get_cells {cap_db1/adc_data_rclk_reg*[15]}]
set_property BEL A5FF           [get_cells {cap_db1/adc_data_rclk_reg*[16]}]
set_property LOC SLICE_X1Y272   [get_cells {cap_db1/adc_data_rclk_reg*[16]}]
set_property BEL B5FF           [get_cells {cap_db1/adc_data_rclk_reg*[17]}]
set_property LOC SLICE_X1Y272   [get_cells {cap_db1/adc_data_rclk_reg*[17]}]
set_property BEL AFF            [get_cells {cap_db1/adc_data_rclk_reg*[18]}]
set_property LOC SLICE_X1Y290   [get_cells {cap_db1/adc_data_rclk_reg*[18]}]
set_property BEL BFF            [get_cells {cap_db1/adc_data_rclk_reg*[19]}]
set_property LOC SLICE_X1Y290   [get_cells {cap_db1/adc_data_rclk_reg*[19]}]
set_property BEL A5FF           [get_cells {cap_db1/adc_data_rclk_reg*[20]}]
set_property LOC SLICE_X1Y342   [get_cells {cap_db1/adc_data_rclk_reg*[20]}]
set_property BEL B5FF           [get_cells {cap_db1/adc_data_rclk_reg*[21]}]
set_property LOC SLICE_X1Y342   [get_cells {cap_db1/adc_data_rclk_reg*[21]}]
set_property BEL A5FF           [get_cells {cap_db1/adc_data_rclk_reg*[22]}]
set_property LOC SLICE_X1Y294   [get_cells {cap_db1/adc_data_rclk_reg*[22]}]
set_property BEL B5FF           [get_cells {cap_db1/adc_data_rclk_reg*[23]}]
set_property LOC SLICE_X1Y294   [get_cells {cap_db1/adc_data_rclk_reg*[23]}]
set_property BEL A5FF           [get_cells {cap_db1/adc_data_rclk_reg*[24]}]
set_property LOC SLICE_X1Y268   [get_cells {cap_db1/adc_data_rclk_reg*[24]}]
set_property BEL B5FF           [get_cells {cap_db1/adc_data_rclk_reg*[25]}]
set_property LOC SLICE_X1Y268   [get_cells {cap_db1/adc_data_rclk_reg*[25]}]
set_property BEL A5FF           [get_cells {cap_db1/adc_data_rclk_reg*[26]}]
set_property LOC SLICE_X1Y292   [get_cells {cap_db1/adc_data_rclk_reg*[26]}]
set_property BEL B5FF           [get_cells {cap_db1/adc_data_rclk_reg*[27]}]
set_property LOC SLICE_X1Y292   [get_cells {cap_db1/adc_data_rclk_reg*[27]}]

# IODELAY constraints
set_property IODELAY_GROUP ADC_CAP_IODELAY_GRP [get_cells adc_cap_idelayctrl_i]
set_property IODELAY_GROUP ADC_CAP_IODELAY_GRP [get_cells {cap_db0/gen_lvds_pins[*].idelay_i}]
set_property IODELAY_GROUP ADC_CAP_IODELAY_GRP [get_cells {cap_db1/gen_lvds_pins[*].idelay_i}]


#*******************************************************************************
## DAC Interface

# DCI System-Sync Timing

# The DCI clock driven to the DACs must obey setup and hold timing with respect to
# the reference clock driven to the DACs (same as the FPGA_CLK, driven by the LMK).
# Define the minimum and maximum clock propagation delays through the FPGA in order to
# meet this system-wide timing.
set dac0_clk_offset_out_max  1.350
set dac0_clk_offset_out_min  0.225
set dac1_clk_offset_out_max  1.350
set dac1_clk_offset_out_min  0.225

# The absolute latest the DCI clock should change is the sum of the maximum delay through
# the FPGA and the latest the sourcing clock (FPGA_CLK) can arrive at the FPGA. This is an
# artifact of the set_clock_latency constraints and doing system-wide timing. Typically,
# these Early/Late delays are automatically compensated for by the analyzer. However this
# is only the case for signals that start and end in the same PRIMARY clock domain. In
# our case, VIRT_DAC_CLK and radio_clk are not the same clock domain and
# therefore we have to manually remove the added Early/Late values from analysis.
set dac0_dci_out_delay_max [expr $dac0_clk_offset_out_max + $var_fpga_clk_delay + $var_fpga_clk_skew/2]
set dac0_dci_out_delay_min [expr $dac0_clk_offset_out_min + $var_fpga_clk_delay - $var_fpga_clk_skew/2]
set dac1_dci_out_delay_max [expr $dac1_clk_offset_out_max + $var_fpga_clk_delay + $var_fpga_clk_skew/2]
set dac1_dci_out_delay_min [expr $dac1_clk_offset_out_min + $var_fpga_clk_delay - $var_fpga_clk_skew/2]

# The min set_output_delay is the earliest the DCI clock should change BEFORE the current
# edge of interest. Here it is inverted (negated) because the earliest the clock should
# change is dac0_dci_out_delay_min AFTER the launch edge of the virtual clock.
set_output_delay -clock VIRT_DAC_CLK -min [expr - $dac0_dci_out_delay_min]                        [get_ports {DB0_DAC_DCI_*}]
set_output_delay -clock VIRT_DAC_CLK -min [expr - $dac0_dci_out_delay_min] -clock_fall -add_delay [get_ports {DB0_DAC_DCI_*}] 
set_output_delay -clock VIRT_DAC_CLK -min [expr - $dac1_dci_out_delay_min]                        [get_ports {DB1_DAC_DCI_*}]
set_output_delay -clock VIRT_DAC_CLK -min [expr - $dac1_dci_out_delay_min] -clock_fall -add_delay [get_ports {DB1_DAC_DCI_*}] 

# The max set_output_delay is the time the data should be stable before the next
# edge of interest. Since we are DDR, this is the falling edge. Hence we subtract
# latest time the data should change, dac0_dci_out_delay_max, from the falling edge
# time, dci_period/2 = 1.25ns.
set_output_delay -clock VIRT_DAC_CLK -max [expr 1.25 - $dac0_dci_out_delay_max]                         [get_ports {DB0_DAC_DCI_*}]
set_output_delay -clock VIRT_DAC_CLK -max [expr 1.25 - $dac0_dci_out_delay_max] -clock_fall -add_delay  [get_ports {DB0_DAC_DCI_*}] 
set_output_delay -clock VIRT_DAC_CLK -max [expr 1.25 - $dac1_dci_out_delay_max]                         [get_ports {DB1_DAC_DCI_*}]
set_output_delay -clock VIRT_DAC_CLK -max [expr 1.25 - $dac1_dci_out_delay_max] -clock_fall -add_delay  [get_ports {DB1_DAC_DCI_*}]


# Data to DCI Source-Sync Timing

# The data setup and hold values must be modified in order to pass timing in
# the FPGA. The correct values are 0.270 and 0.090 for setup and hold, respectively.
# The interface fails by around 390 ps in both directions, so we subtract the failing
# amount from the actual amount to get a passing constraint.
# NOTE: Any changes to the adjustment margin below would need to be validated over
#       multiple builds, process and temperature. Try not to change it!
set dac_data_setup      0.270
set dac_data_hold       0.090
set dac_setup_adj       0.390
set dac_hold_adj        0.390

# These are real trace delays from the timing spreadsheet. Note that we are assuming
# no variability in our clock delay.
set dac0_data_delay_max 1.036
set dac0_data_delay_min 0.898
set dac0_clk_delay_max  0.974
set dac0_clk_delay_min  0.974

set dac1_data_delay_max 0.941
set dac1_data_delay_min 0.833
set dac1_clk_delay_max  0.930
set dac1_clk_delay_min  0.930

set dac0_out_delay_max [expr $dac0_data_delay_max - $dac0_clk_delay_min + $dac_data_setup - $dac_setup_adj]
set dac0_out_delay_min [expr $dac0_data_delay_min - $dac0_clk_delay_max - $dac_data_hold  + $dac_hold_adj]
set dac1_out_delay_max [expr $dac1_data_delay_max - $dac1_clk_delay_min + $dac_data_setup - $dac_setup_adj]
set dac1_out_delay_min [expr $dac1_data_delay_min - $dac1_clk_delay_max - $dac_data_hold  + $dac_hold_adj]

set_output_delay -clock [get_clocks DB0_DAC_DCI] -max $dac0_out_delay_max                        [get_ports -regexp {DB0_DAC_D._. DB0_DAC_FRAME_.}]
set_output_delay -clock [get_clocks DB0_DAC_DCI] -max $dac0_out_delay_max -clock_fall -add_delay [get_ports -regexp {DB0_DAC_D._. DB0_DAC_FRAME_.}]
set_output_delay -clock [get_clocks DB0_DAC_DCI] -min $dac0_out_delay_min                        [get_ports -regexp {DB0_DAC_D._. DB0_DAC_FRAME_.}]
set_output_delay -clock [get_clocks DB0_DAC_DCI] -min $dac0_out_delay_min -clock_fall -add_delay [get_ports -regexp {DB0_DAC_D._. DB0_DAC_FRAME_.}]

set_output_delay -clock [get_clocks DB1_DAC_DCI] -max $dac1_out_delay_max                        [get_ports -regexp {DB1_DAC_D._. DB1_DAC_FRAME_.}]
set_output_delay -clock [get_clocks DB1_DAC_DCI] -max $dac1_out_delay_max -clock_fall -add_delay [get_ports -regexp {DB1_DAC_D._. DB1_DAC_FRAME_.}]
set_output_delay -clock [get_clocks DB1_DAC_DCI] -min $dac1_out_delay_min                        [get_ports -regexp {DB1_DAC_D._. DB1_DAC_FRAME_.}]
set_output_delay -clock [get_clocks DB1_DAC_DCI] -min $dac1_out_delay_min -clock_fall -add_delay [get_ports -regexp {DB1_DAC_D._. DB1_DAC_FRAME_.}]


#*******************************************************************************
## IoPort2

# Constrain the location of the IDELAYCTERL associated with the interface trainer IDELAYs
set_property LOC IDELAYCTRL_X1Y0 [get_cells lvfpga_chinch_inst/IDELAYCTRLx]

# RX Pad Input constraints
set_input_delay -clock [get_clocks IoRxClock] -max 2.580                        [get_ports {irIoRx*}]
set_input_delay -clock [get_clocks IoRxClock] -min 2.280                        [get_ports {irIoRx*}]
set_input_delay -clock [get_clocks IoRxClock] -max 2.580 -clock_fall -add_delay [get_ports {irIoRx*}]
set_input_delay -clock [get_clocks IoRxClock] -min 2.280 -clock_fall -add_delay [get_ports {irIoRx*}]

# Note: The input clock N-Side ISERDES is not constrained for IO timing since
# adding an input delay does not work as the clock and data are the same.
# Since the architecture requires dedicated routes, the build-to-build
# variablilty will be zero and therefore, no separate timing constraint
# is necessary for the N-Side pin. The RxClock delay is constrained because
# of the input delay constraints on the rest of the bus. This path does, however,
# require a max delay constraint in order to override the default analysis:
set_max_delay -from [get_ports {IoRxClock*}]                                                       \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2Wrapperx/RxClockGenx/RxClockSerdes*}] \
              2.0 -datapath_only

# TX Pad Output constraints
set_output_delay -clock [get_clocks IoTxClock] -max 1.600                        [get_ports {itIoTx*}]
set_output_delay -clock [get_clocks IoTxClock] -min 0.400                        [get_ports {itIoTx*}]
set_output_delay -clock [get_clocks IoTxClock] -max 1.600 -clock_fall -add_delay [get_ports {itIoTx*}]
set_output_delay -clock [get_clocks IoTxClock] -min 0.400 -clock_fall -add_delay [get_ports {itIoTx*}]

# These signals are all treated as async signals so no stringent timing requirements are needed.
set_max_delay -to [get_ports aIrq*]              10.000
set_max_delay -from [get_ports aIoResetIn_n]     10.000
set_max_delay -from [get_ports aIoReadyIn]       10.000
set_max_delay -to [get_ports aIoReadyOut]        10.000
set_max_delay -to [get_ports aIoPort2Restart]    10.000
set_false_path -from [get_ports aStc3Gpio7]

# Async reset
set_false_path -from [get_cells -hier -filter {NAME =~ lvfpga_chinch_inst/*StartupFsmx/aResetLcl*}]

# Double Sync
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2Wrapperx/tIoResetSync/DoubleSyncBasex/iDlySig*}]                            \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2Wrapperx/tIoResetSync/DoubleSyncBasex/DoubleSyncAsyncInBasex/oSig_ms*}]     \
              6.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2Wrapperx/bIoResetAckSync/DoubleSyncBasex/iDlySig*}]                         \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2Wrapperx/bIoResetAckSync/DoubleSyncBasex/DoubleSyncAsyncInBasex/oSig_ms*}]  \
              6.0 -datapath_only

# Constrains HandshakeSLVx and IClkToPushClkHs in ControlIoDelayClockCross
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/*ControlIoDelayClockCrossx/*/HBx/*iLclStoredData*}] \
              -to   [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/*ControlIoDelayClockCrossx/*/HBx/*ODataFlop*}]      \
              8.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/*ControlIoDelayClockCrossx/*/HBx/iPushToggle}]           \
              -to   [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/*ControlIoDelayClockCrossx/*/HBx/BlkOut.oPushToggle0_ms*}] \
              4.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/*ControlIoDelayClockCrossx/*/HBx/BlkOut.oPushToggle0_ms*}] \
              -to   [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/*ControlIoDelayClockCrossx/*/HBx/BlkOut.oPushToggle1*}]    \
              4.0

set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/*ControlIoDelayClockCrossx/*/HBx/*oPushToggleToReady*}] \
              -to   [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/*ControlIoDelayClockCrossx/*/HBx/*iRdyPushToggle_ms*}]  \
              4.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/*ControlIoDelayClockCrossx/*/HBx/*iRdyPushToggle_ms*}] \
              -to   [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/*ControlIoDelayClockCrossx/*/HBx/*iRdyPushToggle*}]    \
              4.0

# SamplerResultsHandshake and SamplerControlHandshake
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/ClockSamplerBlock.Sampler*Handshake/HBx/*iLclStoredData*}] \
              -to   [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/ClockSamplerBlock.Sampler*Handshake/HBx/*ODataFlop*}]      \
              6.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/ClockSamplerBlock.Sampler*Handshake/HBx/iPushToggle}]           \
              -to   [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/ClockSamplerBlock.Sampler*Handshake/HBx/BlkOut.oPushToggle0_ms*}] \
              4.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/ClockSamplerBlock.Sampler*Handshake/HBx/BlkOut.oPushToggle0_ms*}] \
              -to   [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/ClockSamplerBlock.Sampler*Handshake/HBx/BlkOut.oPushToggle1*}]    \
              4.0
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/ClockSamplerBlock.Sampler*Handshake/HBx/*oPushToggleToReady*}]  \
              -to   [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/ClockSamplerBlock.Sampler*Handshake/HBx/*iRdyPushToggle_ms*}]   \
              4.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/ClockSamplerBlock.Sampler*Handshake/HBx/*iRdyPushToggle_ms*}]   \
              -to   [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/ClockSamplerBlock.Sampler*Handshake/HBx/*iRdyPushToggle*}]      \
              4.0

# Constrain PhyResetSync PulseSync
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/TrainerBlock.PhyResetSync/PulseSyncBasex/iHoldSigInx*}]     \
              -to   [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/TrainerBlock.PhyResetSync/PulseSyncBasex/oHoldSigIn_msx*}]  \
              4.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/TrainerBlock.PhyResetSync/PulseSyncBasex/oHoldSigIn_msx*}]  \
              -to   [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/TrainerBlock.PhyResetSync/PulseSyncBasex/oLocalSigOutCEx*}] \
              4.0
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/TrainerBlock.PhyResetSync/PulseSyncBasex/oLocalSigOutCEx*}] \
              -to   [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/TrainerBlock.PhyResetSync/PulseSyncBasex/iSigOut_msx*}]     \
              4.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/TrainerBlock.PhyResetSync/PulseSyncBasex/iSigOut_msx*}]     \
              -to   [get_cells -hier -filter {NAME =~ *IoPortClkDelayTrainerx/TrainerBlock.PhyResetSync/PulseSyncBasex/iSigOutx*}]        \
              4.0

# IoPort2 Core Clock Crossings
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/ReceiveSide.IoPort2Receiverx/PacketReceivedDoublesync*iDlySigx*}]               \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/ReceiveSide.IoPort2Receiverx/PacketReceivedDoublesync*DoubleSyncAsyncInBasex*}] \
              6.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/ReceiveSide.IoPort2Receiverx/PacketReceivedDoublesync*DoubleSyncAsyncInBasex/oSig_msx*}] \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/ReceiveSide.IoPort2Receiverx/PacketReceivedDoublesync*DoubleSyncAsyncInBasex/oSigx*}]    \
              6.0

# Handshake
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/ReceiveSide.IoReceiveFifoBasex/CreditManager*/HBx/*iLclStoredData*}] \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/ReceiveSide.IoReceiveFifoBasex/CreditManager*/HBx/*ODataFlop*}]      \
              10.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/ReceiveSide.IoReceiveFifoBasex/CreditManager*/HBx/iPushToggle}]           \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/ReceiveSide.IoReceiveFifoBasex/CreditManager*/HBx/BlkOut.oPushToggle0_ms*}] \
              6.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/ReceiveSide.IoReceiveFifoBasex/CreditManager*/HBx/BlkOut.oPushToggle0_ms*}] \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/ReceiveSide.IoReceiveFifoBasex/CreditManager*/HBx/BlkOut.oPushToggle1*}]    \
              4.0
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/ReceiveSide.IoReceiveFifoBasex/CreditManager*/HBx/*oPushToggleToReady*}] \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/ReceiveSide.IoReceiveFifoBasex/CreditManager*/HBx/*iRdyPushToggle_ms*}]  \
              6.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/ReceiveSide.IoReceiveFifoBasex/CreditManager*/HBx/*iRdyPushToggle_ms*}]  \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/ReceiveSide.IoReceiveFifoBasex/CreditManager*/HBx/*iRdyPushToggle*}]     \
              4.0

# FIFO Clock Crossings
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/ReceiveSide.IoReceiveFifoBasex/FifoFlags/ieInputCountGrayx*}]    \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/ReceiveSide.IoReceiveFifoBasex/FifoFlags/oInputCountGray_msx*}]  \
              5.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/ReceiveSide.IoReceiveFifoBasex/FifoFlags/oInputCountGray_msx*}]  \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/ReceiveSide.IoReceiveFifoBasex/FifoFlags/oInputCountGrayx*}]     \
              4.0
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/ReceiveSide.IoReceiveFifoBasex/PacketFullyReceived/ieInputCountGrayx*}]   \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/ReceiveSide.IoReceiveFifoBasex/PacketFullyReceived/oInputCountGray_msx*}] \
              5.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/ReceiveSide.IoReceiveFifoBasex/PacketFullyReceived/oInputCountGray_msx*}] \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/ReceiveSide.IoReceiveFifoBasex/PacketFullyReceived/oInputCountGrayx*}]    \
              4.0
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/TransmitFifo.PacketFullyReceived/ieInputCountGrayx*}]    \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/TransmitFifo.PacketFullyReceived/oInputCountGray_msx*}]  \
              5.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/TransmitFifo.PacketFullyReceived/oInputCountGray_msx*}]  \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/TransmitFifo.PacketFullyReceived/oInputCountGrayx*}]     \
              4.0
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/TransmitFifo.PacketFullyReceived/oeOutputCountGrayx*}]   \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/TransmitFifo.PacketFullyReceived/iOutputCountGray_msx*}] \
              5.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/TransmitFifo.PacketFullyReceived/iOutputCountGray_msx*}] \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/TransmitFifo.PacketFullyReceived/iOutputCountGrayx*}]    \
              4.0
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/TransmitFifo.InputFifo.FifoFlags/ieInputCountGrayx*}]    \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/TransmitFifo.InputFifo.FifoFlags/oInputCountGray_msx*}]  \
              5.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/TransmitFifo.InputFifo.FifoFlags/oInputCountGray_msx*}]  \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/TransmitFifo.InputFifo.FifoFlags/oInputCountGrayx*}]     \
              4.0
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/TransmitFifo.InputFifo.FifoFlags/oeOutputCountGrayx*}]   \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/TransmitFifo.InputFifo.FifoFlags/iOutputCountGray_msx*}] \
              5.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/TransmitFifo.InputFifo.FifoFlags/iOutputCountGray_msx*}] \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/TransmitFifo.InputFifo.FifoFlags/iOutputCountGrayx*}]    \
              4.0
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/TransmitFifo.InputFifo.FifoFlags/oeOutputCountGrayx*}]   \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/TransmitFifo*DualPortRAMx*oDlyAddr*}]                    \
              5.0
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/CreditManager.HandshakeCredits/HBx/*iLclStoredData*}] \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/CreditManager.HandshakeCredits/HBx/*ODataFlop*}]      \
              10.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/CreditManager.HandshakeCredits/HBx/iPushToggle}]           \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/CreditManager.HandshakeCredits/HBx/BlkOut.oPushToggle0_ms*}] \
              6.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/CreditManager.HandshakeCredits/HBx/BlkOut.oPushToggle0_ms*}] \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/CreditManager.HandshakeCredits/HBx/BlkOut.oPushToggle1*}]    \
              4.0
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/CreditManager.HandshakeCredits/HBx/*oPushToggleToReady*}] \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/CreditManager.HandshakeCredits/HBx/*iRdyPushToggle_ms*}]  \
              6.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/CreditManager.HandshakeCredits/HBx/*iRdyPushToggle_ms*}]  \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2Basex/TransmitSide.IoTransmitFifox/CreditManager.HandshakeCredits/HBx/*iRdyPushToggle*}]     \
              4.0

# Double Sync
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/Startup.DoubleSyncEnableTransmit/iDlySigx*}]                         \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/Startup.DoubleSyncEnableTransmit/*DoubleSyncAsyncInBasex/oSig_msx*}] \
              6.0 -datapath_only
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/Startup.DoubleSyncEnableTransmit/*DoubleSyncAsyncInBasex/oSig_msx*}] \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2x/IoPort2Basex/Startup.DoubleSyncEnableTransmit/*DoubleSyncAsyncInBasex/oSigx*}]    \
              4.0
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2Basex/DoubleSyncWidePortMode.DoubleSync*WidePortMode/iDlySigx*}]               \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2Basex/DoubleSyncWidePortMode.DoubleSync*WidePortMode/DoubleSyncAsyncInBasex*}] \
              6.0 -datapath_only -quiet
set_max_delay -from [get_cells -hier -filter {NAME =~ *IoPort2Basex/DoubleSyncWidePortMode.DoubleSync*WidePortMode/DoubleSyncAsyncInBasex/oSig_msx*}] \
              -to   [get_cells -hier -filter {NAME =~ *IoPort2Basex/DoubleSyncWidePortMode.DoubleSync*WidePortMode/DoubleSyncAsyncInBasex/oSigx*}]    \
              5.0 -quiet


#*******************************************************************************
## PPS Timing

# Constrain delay from PPS input pins to the first stage synchronizer flip-flop
set_max_delay 5.000 -from [get_ports EXT_PPS_IN] \
                    -to [get_pins -hier -filter {NAME =~ */pps_sync_refclk_inst/synchronizer_constrained/stages[0].value_reg[*]/D}] \
                    -datapath_only
set_min_delay 2.500 -from [get_ports EXT_PPS_IN] \
                    -to [get_pins -hier -filter {NAME =~ */pps_sync_refclk_inst/synchronizer_constrained/stages[0].value_reg[*]/D}]
set_max_delay 5.000 -from [get_ports GPS_PPS_OUT] \
                    -to [get_pins -hier -filter {NAME =~ */pps_sync_refclk_inst/synchronizer_constrained/stages[0].value_reg[*]/D}] \
                    -datapath_only
set_min_delay 2.500 -from [get_ports GPS_PPS_OUT] \
                    -to [get_pins -hier -filter {NAME =~ */pps_sync_refclk_inst/synchronizer_constrained/stages[0].value_reg[*]/D}]

# Constrain input-output delay for external PPS
set_max_delay 10.000 -from [get_ports EXT_PPS_IN] -to [get_ports {EXT_PPS_OUT}] -datapath_only
set_min_delay 5.000  -from [get_ports EXT_PPS_IN] -to [get_ports {EXT_PPS_OUT}]

# Constrain delay to the first flop in radio_clk with about 1ns of slack
set_max_delay 6.500 -to [get_pins -hier -filter {NAME =~ */pps_sync_tbclk_inst/synchronizer_constrained/stages[0].value_reg[*]/D}]
set_min_delay 0.500 -to [get_pins -hier -filter {NAME =~ */pps_sync_tbclk_inst/synchronizer_constrained/stages[0].value_reg[*]/D}]

#*******************************************************************************
## Miscellaneous Interfaces

# Dboard and Front-Panel GPIO Interfaces 
# We force the registers closest to the PADs into the IOB to achieve lowest skew between individual bits
# in the parallel bus. However, as a sanity check we add the following constraints that will fail if the 
# registers don't get placed in the IOB for whatever reason.
set_max_delay 6.000 -to   [get_ports * -filter {(DIRECTION == OUT || DIRECTION == INOUT) && NAME =~ "DB*_*X_IO*"}]
set_max_delay 3.000 -from [get_ports * -filter {(DIRECTION == IN  || DIRECTION == INOUT) && NAME =~ "DB*_*X_IO*"}]
set_max_delay 6.000 -to   [get_ports * -filter {(DIRECTION == OUT || DIRECTION == INOUT) && NAME =~ "FrontPanelGpio[*]"}]
set_max_delay 3.000 -from [get_ports * -filter {(DIRECTION == IN  || DIRECTION == INOUT) && NAME =~ "FrontPanelGpio[*]"}]

# SPI Lines
set_max_delay 10.000 -datapath_only \
                     -from [get_ports {DB*_*X*MISO*}] 
set_max_delay 10.000 -to   [get_ports {DB*_*SCLK DB*_*SEN DB*_*MOSI}]
set_max_delay 10.000 -to   [get_ports {DB_SCL DB_SDA DB0_DAC_ENABLE DB1_DAC_ENABLE DB_ADC_RESET DB_DAC_RESET}]
set_max_delay 10.000 -from [get_ports {DB_SCL DB_SDA DB_DAC_MOSI}]

# Clock distribution chip control
set_max_delay -from   [get_ports {LMK_Status[*] LMK_Holdover LMK_Lock LMK_Sync}] 10.000
set_max_delay -to     [get_ports {LMK_SEN LMK_MOSI LMK_SCLK}]                    10.000
set_max_delay -to     [get_ports {ClockRefSelect*}]                              10.000
set_max_delay -to     [get_ports {TCXO_ENA}]                                     10.000

# GPS UART
set_max_delay -from   [get_ports {GPS_SER_OUT}] 6.000
set_max_delay -to     [get_ports {GPS_SER_IN}]  6.000
set_max_delay -from   [get_ports {GPS_LOCK_OK}] 25.000

# Reset paths
# All asynchronous resets must be held for at least 20ns
# which is 2+2 radio_clk cycles @200MHz or 2+2 bus_clk cycles @166MHz
set_max_delay -to [get_pins {int_reset_sync/reset_int*/PRE}]        12.000
set_max_delay -to [get_pins {int_div2_reset_sync/reset_int*/PRE}]   12.000
set_max_delay -to [get_pins {ce_reset_sync/reset_int*/PRE}]         12.000
set_max_delay -to [get_pins {radio_reset_sync/reset_int*/PRE}]      10.000

#*******************************************************************************
## Asynchronous paths

set_false_path -to   [get_pins -hier -filter {NAME =~ */synchronizer_false_path/stages[0].value_reg[*]/D}]
set_false_path -to   [get_ports LED_*]
set_false_path -to   [get_ports {SFPP*_RS0 SFPP*_RS1 SFPP*_SCL SFPP*_SDA SFPP*_TxDisable}]
set_false_path -from [get_ports {SFPP*_ModAbs SFPP*_RxLOS SFPP*_SCL SFPP*_SDA SFPP*_TxFault}]
set_false_path -to   [get_ports GPSDO_PWR_ENA]
