1# 2# Copyright 2017 Ettus Research, A National Instruments Company 3# SPDX-License-Identifier: LGPL-3.0 4# 5# Timing analysis is performed in "usrp3/top/n3xx/dboards/rh/doc/rh_timing.xlsx". 6# See this spreadsheet for more details and explanations. 7 8#******************************************************************************* 9## Asynchronous clock groups 10 11# MGT reference clocks are also async to everything. 12set_clock_groups -asynchronous -group [get_clocks mgt_clk_dba -include_generated_clocks] 13set_clock_groups -asynchronous -group [get_clocks mgt_clk_dbb -include_generated_clocks] 14 15# fpga_clk_a and fpga_clk_b are related to one another after synchronization. 16# However, we do need to declare that these clocks (both a and b) and their children 17# are async to the remainder of the design. Use the wildcard at the end to grab the 18# virtual clock as well as the real ones. 19set_clock_groups -asynchronous -group [get_clocks {fpga_clk_a* fpga_clk_b*} -include_generated_clocks] 20 21# The SPI readback and write clocks cannot be active at the same time, as they 22# originate from the same pin. 23set_clock_groups -physically_exclusive \ 24 -group [get_clocks pl_spi_rb_clk_a] \ 25 -group [get_clocks pl_spi_clk_a] 26set_clock_groups -physically_exclusive \ 27 -group [get_clocks pl_spi_rb_clk_b] \ 28 -group [get_clocks pl_spi_clk_b] 29 30#******************************************************************************* 31## PS SPI: since these lines all come from the PS and I don't have access to the 32# driving clock (or anything for that matter), I'm left with constraining the maximum 33# and minimum delay on these lines, per a Xilinx AR: 34# https://www.xilinx.com/support/answers/62122.html 35set CPLD_SPI_OUTS [get_ports {DB*_CPLD_PS_SPI_SCLK \ 36 DB*_CPLD_PS_SPI_MOSI \ 37 DB*_CPLD_PS_SPI_CS_B \ 38 DB*_CLKDIS_SPI_CS_B \ 39 DB*_PHDAC_SPI_CS_B \ 40 DB*_ADC_SPI_CS_B \ 41 DB*_DAC_SPI_CS_B}] 42 43# The actual min and max path delays before applying constraints were (from report_timing): 44# 3.332 ns (Min at Fast Process Corner) 45# 10.596 ns (Max at Slow Process Corner) 46# Therefore, we round those number to their immediate succesor respectively. 47# After implementation, the tools were unable to meet timing when leaving a 11 ns max 48# delay value, so it was incremented. 49set MIN_OUT_DELAY 3.0 50set MAX_OUT_DELAY 12.0 51 52set_max_delay $MAX_OUT_DELAY -to $CPLD_SPI_OUTS 53set_min_delay $MIN_OUT_DELAY -to $CPLD_SPI_OUTS 54 55# report_timing -to $CPLD_SPI_OUTS -max_paths 20 -delay_type min_max -name CpldSpiOutTiming 56 57# The actual min and max path delays before applying constraints were (from report_timing): 58# 2.733 ns (Min at Fast Process Corner) 59# 6.071 ns (Max at Slow Process Corner) 60# Therefore, we round those number to their immediate succesor respectively. 61set MIN_IN_DELAY 2.0 62set MAX_IN_DELAY 10.0 63 64set PS_SPI_INPUTS_0 [get_pins -hierarchical -filter {NAME =~ "*/PS7_i/EMIOSPI0MI"}] 65set PS_SPI_INPUTS_1 [get_pins -hierarchical -filter {NAME =~ "*/PS7_i/EMIOSPI1MI"}] 66 67set_max_delay $MAX_IN_DELAY -to $PS_SPI_INPUTS_0 68set_min_delay $MIN_IN_DELAY -to $PS_SPI_INPUTS_0 69set_max_delay $MAX_IN_DELAY -to $PS_SPI_INPUTS_1 70set_min_delay $MIN_IN_DELAY -to $PS_SPI_INPUTS_1 71 72# report_timing -to $PS_SPI_INPUTS_0 -max_paths 30 -delay_type min_max -nworst 30 -name Spi0InTiming 73# report_timing -to $PS_SPI_INPUTS_1 -max_paths 30 -delay_type min_max -nworst 30 -name Spi1InTiming 74 75 76 77#******************************************************************************* 78## PL SPI to the CPLD 79# 80# All of these lines are driven or received from flops in simple_spi_core. The CPLD 81# calculations assume the FPGA has less than 6 ns of skew between the SCK and 82# SDI/CS_n. Pretty easy constraint to write! See above for the clock definition. 83# Do this for DBA and DBB independently. 84set MAX_SKEW 6.0 85set SETUP_SKEW [expr {$MAX_SKEW / 2}] 86set HOLD_SKEW [expr {$MAX_SKEW / 2}] 87# Do not set the output delay constraint on the clock line! 88set PORT_LIST_A [get_ports {DBA_CPLD_PL_SPI_CS_B \ 89 DBA_CPLD_PL_SPI_MOSI \ 90 DBA_TXLO_SPI_CS_B \ 91 DBA_RXLO_SPI_CS_B \ 92 DBA_LODIS_SPI_CS_B }] 93set PORT_LIST_B [get_ports {DBB_CPLD_PL_SPI_CS_B \ 94 DBB_CPLD_PL_SPI_MOSI \ 95 DBB_TXLO_SPI_CS_B \ 96 DBB_RXLO_SPI_CS_B \ 97 DBB_LODIS_SPI_CS_B }] 98# Then add the output delay on each of the ports. 99set_output_delay -clock [get_clocks pl_spi_clk_a] -max -$SETUP_SKEW $PORT_LIST_A 100set_output_delay -add_delay -clock_fall -clock [get_clocks pl_spi_clk_a] -max -$SETUP_SKEW $PORT_LIST_A 101set_output_delay -clock [get_clocks pl_spi_clk_a] -min $HOLD_SKEW $PORT_LIST_A 102set_output_delay -add_delay -clock_fall -clock [get_clocks pl_spi_clk_a] -min $HOLD_SKEW $PORT_LIST_A 103set_output_delay -clock [get_clocks pl_spi_clk_b] -max -$SETUP_SKEW $PORT_LIST_B 104set_output_delay -add_delay -clock_fall -clock [get_clocks pl_spi_clk_b] -max -$SETUP_SKEW $PORT_LIST_B 105set_output_delay -clock [get_clocks pl_spi_clk_b] -min $HOLD_SKEW $PORT_LIST_B 106set_output_delay -add_delay -clock_fall -clock [get_clocks pl_spi_clk_b] -min $HOLD_SKEW $PORT_LIST_B 107# Finally, make both the setup and hold checks use the same launching and latching edges. 108set_multicycle_path -setup -from [get_clocks radio_clk] -to [get_clocks pl_spi_clk_a] -start 0 109set_multicycle_path -hold -from [get_clocks radio_clk] -to [get_clocks pl_spi_clk_a] -1 110set_multicycle_path -setup -from [get_clocks radio_clk] -to [get_clocks pl_spi_clk_b] -start 0 111set_multicycle_path -hold -from [get_clocks radio_clk] -to [get_clocks pl_spi_clk_b] -1 112 113# For SDO input timing (MISO), we need to look at the CPLD's constraints on turnaround 114# time plus any board propagation delay. 115# CPLD clk-to-q is 20 ns, then add 1.2 ns for board delay (once for clock, once for data) 116# For hold time, assume zero delay (likely overconstraining here, due to board delays) 117set MISO_INPUT_A [get_ports DBA_CPLD_PL_SPI_MISO] 118set MISO_INPUT_B [get_ports DBB_CPLD_PL_SPI_MISO] 119set_input_delay -clock [get_clocks pl_spi_rb_clk_a] -clock_fall -max 22.400 $MISO_INPUT_A 120set_input_delay -clock [get_clocks pl_spi_rb_clk_a] -clock_fall -min 0.000 $MISO_INPUT_A 121set_input_delay -clock [get_clocks pl_spi_rb_clk_b] -clock_fall -max 22.400 $MISO_INPUT_B 122set_input_delay -clock [get_clocks pl_spi_rb_clk_b] -clock_fall -min 0.000 $MISO_INPUT_B 123 124# Since the input delay span is clearly more than a period of the radio_clk, we need to 125# add a multicycle path here as well to define the clock divider ratio. The MISO data 126# is driven on the falling edge of the SPI clock and captured on the rising edge, so we 127# only have one half of a SPI clock cycle for our setup. Hold is left alone and is OK 128# as-is due to the delays in the CPLD and board. 129set SETUP_CYCLES [expr {$PL_SPI_RB_DIVIDE_VAL / 2}] 130set HOLD_CYCLES 0 131set_multicycle_path -setup -from [get_clocks pl_spi_rb_clk_a] -through $MISO_INPUT_A \ 132 $SETUP_CYCLES 133set_multicycle_path -hold -from [get_clocks pl_spi_rb_clk_a] -through $MISO_INPUT_A -end \ 134 [expr {$SETUP_CYCLES + $HOLD_CYCLES - 1}] 135set_multicycle_path -setup -from [get_clocks pl_spi_rb_clk_b] -through $MISO_INPUT_B \ 136 $SETUP_CYCLES 137set_multicycle_path -hold -from [get_clocks pl_spi_rb_clk_b] -through $MISO_INPUT_B -end \ 138 [expr {$SETUP_CYCLES + $HOLD_CYCLES - 1}] 139 140#******************************************************************************* 141## SYSREF/SYNC JESD Timing 142# 143# SYNC is async, SYSREF is tightly timed. 144 145# The SYNC output (to ADC) for both DBs is governed by the JESD cores, which are solely 146# driven by DB-A clock... but it is an asynchronous signal so we use the async_out_clk. 147set_output_delay -clock [get_clocks async_out_clk] 0.000 [get_ports DB*_ADC_SYNCB_P] 148set_max_delay -to [get_ports DB*_ADC_SYNCB_P] 50.000 149set_min_delay -to [get_ports DB*_ADC_SYNCB_P] 0.000 150 151# The SYNC input (from DAC) for both DBs is received by the DB-A clock inside the JESD 152# cores... but again, it is asynchronous and therefore uses the async_in_clk. 153set_input_delay -clock [get_clocks async_in_clk] 0.000 [get_ports DB*_DAC_SYNCB_P] 154set_max_delay -from [get_ports DB*_DAC_SYNCB_P] 50.000 155set_min_delay -from [get_ports DB*_DAC_SYNCB_P] 0.000 156 157# SYSREF is driven by the LMK directly to the FPGA. Timing analysis was performed once 158# for the worst-case numbers across both DBs to produce one set of numbers for both DBs. 159# Since we easily meet setup and hold in Vivado, then this is an acceptable approach. 160# SYSREF is captured by the local clock from each DB, so we have two sets of constraints. 161set_input_delay -clock fpga_clk_a_v -min -0.479 [get_ports DBA_FPGA_SYSREF_*] 162set_input_delay -clock fpga_clk_a_v -max 0.661 [get_ports DBA_FPGA_SYSREF_*] 163 164set_input_delay -clock fpga_clk_b_v -min -0.479 [get_ports DBB_FPGA_SYSREF_*] 165set_input_delay -clock fpga_clk_b_v -max 0.661 [get_ports DBB_FPGA_SYSREF_*] 166 167 168#******************************************************************************* 169## PPS Timing 170 171# Due to the N3xx synchronization and clocking structure, the PPS output is driven from 172# the Sample Clock domain instead of the input Reference Clock. Constrain the output as 173# tightly as possible to accurately mimic the internal Sample Clock timing. 174set SETUP_SKEW 2.0 175set HOLD_SKEW -0.5 176set_output_delay -clock [get_clocks fpga_clk_a_v] -max -$SETUP_SKEW [get_ports REF_1PPS_OUT] 177set_output_delay -clock [get_clocks fpga_clk_a_v] -min $HOLD_SKEW [get_ports REF_1PPS_OUT] 178set_multicycle_path -setup -to [get_ports REF_1PPS_OUT] -start 0 179set_multicycle_path -hold -to [get_ports REF_1PPS_OUT] -1 180 181#******************************************************************************* 182### Async I/Os 183set DB_ASYNC_OUTPUTS [get_ports { 184 DB*_MODULE_PWR_ENABLE 185 DB*_RF_PWR_ENABLE 186 DB*_CLKDIST_SYNC 187 DB*_ATR_TX 188 DB*_ATR_RX 189 DB*_TXRX_SW_CTRL_1 190 DB*_TXRX_SW_CTRL_2 191 DB*_LED_RX 192 DB*_LED_RX2 193 DB*_LED_TX 194 QSFP_I2C_* 195}] 196set_output_delay -clock [get_clocks async_out_clk] 0.000 $DB_ASYNC_OUTPUTS 197set_max_delay -to $DB_ASYNC_OUTPUTS 50.000 198set_min_delay -to $DB_ASYNC_OUTPUTS 0.000 199 200set_input_delay -clock [get_clocks async_in_clk] 0.000 [get_ports QSFP_I2C_*] 201set_max_delay -from [get_ports QSFP_I2C_*] 50.000 202set_min_delay -from [get_ports QSFP_I2C_*] 0.000 203 204#******************************************************************************* 205## JTAG 206 207## MAX 10 JTAG TDI setup: 2 ns 208## MAX 10 JTAG TMS setup: 3 ns 209## MAX 10 JTAG hold: 10 ns 210## MAX 10 JTAG clk-to-q: 18 ns 211## Board delay: < 1.5 ns 212## 213## Setup time = Board delay + TMS setup = 3 ns + 1.5 ns = 4.5 ns 214## Hold time = Board delay + TMS hold = 1.5 ns + 10 ns = 11.5 ns 215## Overconstrain output delay and keep skew to +/- 8 ns 216## 217## Input delay = 2x Board delay + clk-to-q = 3 ns + 18 ns = 21 ns 218 219# Constrain outputs for skew, with same latch/launch edge: 220set_output_delay -clock [get_clocks dba_jtag_tck] -max -4.0 \ 221 [get_ports {DBA_CPLD_JTAG_TDI DBA_CPLD_JTAG_TMS}] 222set_output_delay -add_delay -clock_fall -clock [get_clocks dba_jtag_tck] -max -4.0 \ 223 [get_ports {DBA_CPLD_JTAG_TDI DBA_CPLD_JTAG_TMS}] 224set_output_delay -clock [get_clocks dba_jtag_tck] -min 4.0 \ 225 [get_ports {DBA_CPLD_JTAG_TDI DBA_CPLD_JTAG_TMS}] 226set_output_delay -add_delay -clock_fall -clock [get_clocks dba_jtag_tck] -min 4.0 \ 227 [get_ports {DBA_CPLD_JTAG_TDI DBA_CPLD_JTAG_TMS}] 228set_output_delay -clock [get_clocks dbb_jtag_tck] -max -4.0 \ 229 [get_ports {DBB_CPLD_JTAG_TDI DBB_CPLD_JTAG_TMS}] 230set_output_delay -add_delay -clock_fall -clock [get_clocks dbb_jtag_tck] -max -4.0 \ 231 [get_ports {DBB_CPLD_JTAG_TDI DBB_CPLD_JTAG_TMS}] 232set_output_delay -clock [get_clocks dbb_jtag_tck] -min 4.0 \ 233 [get_ports {DBB_CPLD_JTAG_TDI DBB_CPLD_JTAG_TMS}] 234set_output_delay -add_delay -clock_fall -clock [get_clocks dbb_jtag_tck] -min 4.0 \ 235 [get_ports {DBB_CPLD_JTAG_TDI DBB_CPLD_JTAG_TMS}] 236# Finally, make both the setup and hold checks use the same launching and latching edges. 237set_multicycle_path -setup -from [get_clocks clk40] -to [get_clocks dba_jtag_tck] -start 0 238set_multicycle_path -hold -from [get_clocks clk40] -to [get_clocks dba_jtag_tck] -1 239set_multicycle_path -setup -from [get_clocks clk40] -to [get_clocks dbb_jtag_tck] -start 0 240set_multicycle_path -hold -from [get_clocks clk40] -to [get_clocks dbb_jtag_tck] -1 241 242set_input_delay -clock [get_clocks dba_jtag_tck] -clock_fall -max 21 \ 243 [get_ports DBA_CPLD_JTAG_TDO] 244set_input_delay -clock [get_clocks dba_jtag_tck] -clock_fall -min 0 \ 245 [get_ports DBA_CPLD_JTAG_TDO] 246set_input_delay -clock [get_clocks dbb_jtag_tck] -clock_fall -max 21 \ 247 [get_ports DBB_CPLD_JTAG_TDO] 248set_input_delay -clock [get_clocks dbb_jtag_tck] -clock_fall -min 0 \ 249 [get_ports DBB_CPLD_JTAG_TDO] 250# Inputs have setup checks relative to half a period of TCK (launch on fall, 251# latch on rise). Actual latch clock is faster, so push back setup and hold 252# checks to match. 253set_multicycle_path -setup -from [get_clocks dba_jtag_tck] \ 254 -through [get_ports DBA_CPLD_JTAG_TDO] \ 255 [expr {$DB_JTAG_DIVISOR / 2}] 256set_multicycle_path -end -hold -from [get_clocks dba_jtag_tck] \ 257 -through [get_ports DBA_CPLD_JTAG_TDO] \ 258 [expr {$DB_JTAG_DIVISOR - 1}] 259set_multicycle_path -setup -from [get_clocks dbb_jtag_tck] \ 260 -through [get_ports DBB_CPLD_JTAG_TDO] \ 261 [expr {$DB_JTAG_DIVISOR / 2}] 262set_multicycle_path -end -hold -from [get_clocks dbb_jtag_tck] \ 263 -through [get_ports DBB_CPLD_JTAG_TDO] \ 264 [expr {$DB_JTAG_DIVISOR - 1}] 265