# # Copyright 2017 Ettus Research, A National Instruments Company # SPDX-License-Identifier: LGPL-3.0 # # All the magic numbers come from the "/n3xx/dboards/mg/doc/mg_timing.xlsx" timing # analysis spreadsheet. Analysis should be re-performed every time a board rev occurs # that affects the CPLD interfaces. ## PS Slave Constraints ################################################################# # - PsClk Rate # - PsClk to SDI # - PsClk to LE (sync and async paths) # - PsClk to SDO # Maximum 4 MHz clock rate! This is heavily limited by the read data turnaround time... # and could be up to 20 MHz if only performing writes. create_clock -name PsClk -period 250 [get_ports {PsSpiSck}] # SDI is both registered in the CPLD and used as a direct passthrough. First constrain # the input delay on the local paths inside the CPLD. Passthrough constraints # are handled elsewhere. set PsSdiInputDelayMax 22.303 set PsSdiInputDelayMin -19.019 # SDI is driven from the PS on the falling edge of the Clk. Worst-case data-clock skew # is around +/-20ns due to FPGA routing delays and board buffering. Complete timing # analysis is performed and recorded elsewhere. set_input_delay -clock PsClk -max $PsSdiInputDelayMax [get_ports sPsSpiSdi] -clock_fall set_input_delay -clock PsClk -min $PsSdiInputDelayMin [get_ports sPsSpiSdi] -clock_fall # For the CPLD Cs_n, the latch enable is used both as an asynchronous reset and # synchronously to latch data. First, constrain the overall input delay for sync use. # Technically, Cs_n is asserted and de-asserted many nanoseconds before the clock arrives # but we still constrain it identically to the SDI in case something goes amiss. set_input_delay -clock PsClk -max $PsSdiInputDelayMax [get_ports sPsSpiLe] -clock_fall set_input_delay -clock PsClk -min $PsSdiInputDelayMin [get_ports sPsSpiLe] -clock_fall # Then set a false path only on the async reset flops. set_false_path -from [get_ports {sPsSpiLe}] -to [get_pins sPsMosiIndex[*]|*] set_false_path -from [get_ports {sPsSpiLe}] -to [get_pins sPsMisoIndex[*]|*] # Constrain MISO as snugly as possible through the CPLD without making the tools work # too hard. At a 200 ns period, this sets the clock-to-out for the CPLD at [10, 65]ns. # Math for Max = T_clk/2 - 60 = 250/2 - 60 = 65 ns. set PsSdoOutputDelayMax 60 set PsSdoOutputDelayMin -10 set_output_delay -clock PsClk -max $PsSdoOutputDelayMax [get_ports sPsSpiSdo] set_output_delay -clock PsClk -min $PsSdoOutputDelayMin [get_ports sPsSpiSdo] ## PL Slave Constraints ################################################################# # - PlClk Rate # - PlClk to SDI # - PlClk to LE (sync and async paths) # - PlClk to SDO # Maximum 5 MHz clock rate! create_clock -name PlClk -period 200 [get_ports {PlSpiSck}] # SDI is both registered in the CPLD and used as a direct passthrough. First constrain # the input delay on the local paths inside the CPLD. Passthrough constraints # are handled elsewhere. set PlSdiInputDelayMax 10.445 set PlSdiInputDelayMin -10.378 # SDI is driven from the FPGA on the falling edge of the Clk. Worst-case data-clock skew # is around +/-10ns. Complete timing analysis is performed and recorded elsewhere. set_input_delay -clock PlClk -max $PlSdiInputDelayMax [get_ports lPlSpiSdi] -clock_fall set_input_delay -clock PlClk -min $PlSdiInputDelayMin [get_ports lPlSpiSdi] -clock_fall # For the CPLD Cs_n, the latch enable is used both as an asynchronous reset and # synchronously to latch data. First, constrain the overall input delay for sync use. # Technically, Cs_n is asserted and de-asserted many nanoseconds before the clock arrives # but we still constrain it identically to the SDI in case something goes amiss. set_input_delay -clock PlClk -max $PlSdiInputDelayMax [get_ports lPlSpiLe] -clock_fall set_input_delay -clock PlClk -min $PlSdiInputDelayMin [get_ports lPlSpiLe] -clock_fall # Then set a false path only on the async reset flops. set_false_path -from [get_ports {lPlSpiLe}] -to [get_pins {lPlMosiIndex[*]|*}] set_false_path -from [get_ports {lPlSpiLe}] -to [get_pins {lPlMisoIndex[*]|*}] # Constrain MISO as snugly as possible through the CPLD without making the tools work # too hard. At a 200 ns period, this sets the clock-to-out for the CPLD at [10, 65]ns. # Math for Max = T_clk/2 - 35 = 200/2 - 35 = 65 ns. set PlSdoOutputDelayMax 35 set PlSdoOutputDelayMin -10 set_output_delay -clock PlClk -max $PlSdoOutputDelayMax [get_ports lPlSpiSdo] set_output_delay -clock PlClk -min $PlSdoOutputDelayMin [get_ports lPlSpiSdo] ## Passthrough Constraints ############################################################## # - LMK SYNC # - PlClk/PsClk passthrough # - SDI passthrough for both # - SDO return mux passthrough for both # - Cs_n passthrough for both # LMK Sync Passthrough: constrain min and max delays for output set_max_delay -from [get_ports {aPlSpiAddr[2]}] -to [get_ports {aLmkSync}] 17 set_min_delay -from [get_ports {aPlSpiAddr[2]}] -to [get_ports {aLmkSync}] 2 # SPI Passthroughs: constrain min and max delays for outputs and inputs. # Since the SDI ports have input delays pre-defined above, we have to remove those from # the delay analysis here by adding the input delay to the constraint. # Similarly, for the SDO pins add the output delay to the constraint. set SpiMaxDelay 25 set SpiMinDelay 5 # PS set_max_delay -to [get_ports {aDacDin aLmkSpiSdio}] [expr $PsSdiInputDelayMax + $SpiMaxDelay] set_min_delay -to [get_ports {aDacDin aLmkSpiSdio}] [expr $PsSdiInputDelayMin + $SpiMinDelay] set_max_delay -to [get_ports {aDacSync_n aLmkSpiCs_n}] $SpiMaxDelay set_min_delay -to [get_ports {aDacSync_n aLmkSpiCs_n}] $SpiMinDelay set_max_delay -to [get_ports {aDacSck aLmkSpiSck}] $SpiMaxDelay set_min_delay -to [get_ports {aDacSck aLmkSpiSck}] $SpiMinDelay set_max_delay -from [get_ports {aLmkClkinSel*}] [expr $SpiMaxDelay + $PsSdoOutputDelayMax] set_min_delay -from [get_ports {aLmkClkinSel*}] [expr $SpiMinDelay + $PsSdoOutputDelayMin] # PL set_max_delay -to [get_ports {aRxLoDin aTxLoDin}] [expr $PlSdiInputDelayMax + $SpiMaxDelay] set_min_delay -to [get_ports {aRxLoDin aTxLoDin}] [expr $PlSdiInputDelayMin + $SpiMinDelay] set_max_delay -to [get_ports {aRxLoCs_n aTxLoCs_n}] $SpiMaxDelay set_min_delay -to [get_ports {aRxLoCs_n aTxLoCs_n}] $SpiMinDelay set_max_delay -to [get_ports {aRxLoSck aTxLoSck}] $SpiMaxDelay set_min_delay -to [get_ports {aRxLoSck aTxLoSck}] $SpiMinDelay set_max_delay -from [get_ports {aTxLoMuxOut aRxLoMuxOut}] [expr $SpiMaxDelay + $PlSdoOutputDelayMax] set_min_delay -from [get_ports {aTxLoMuxOut aRxLoMuxOut}] [expr $SpiMinDelay + $PlSdoOutputDelayMin] ## Async Inputs ######################################################################### # aLmkStatus2 aRxLoLockDetect aTxLoLockDetect set_false_path -from [get_ports {aRxLoLockDetect}] set_false_path -from [get_ports {aTxLoLockDetect}] ## Async Outputs ######################################################################## # aMkReset_n aVcxoCtrl set_false_path -to [get_ports {aMkReset_n}] set_false_path -to [get_ports {aVcxoCtrl}] ## Sync Front End Outputs ############################################################### # All we need to do here is constrain for maximum path delay from the aAtr(Rx|Tx)(1|2) # control bits toggling to the outputs for aCh1* and aCh2* toggling. Just in case the # user attempts to write the ATR while it's in use, we also constrain from the flops # to the pins... which covers all paths... so just to -to option is needed. set_max_delay -to [get_ports {aCh1* aCh2* aMk*x*En}] 40 set_min_delay -to [get_ports {aCh1* aCh2* aMk*x*En}] 5 # We don't care about the LED timing whatsoever. Let's not have them clogging up our # precious timing paths. set_false_path -to [get_ports {aCh*Led*}]