Constraining the IP - Constraining the IP - 3.2 English - PG153

AXI Quad SPI LogiCORE IP Product Guide (PG153)

Document ID
PG153
Release Date
2026-01-16
Version
3.2 English

To understand how the constraints are added, it is important to understand the logic structure around the clock and data in AXI Quad SPI flash memory.

The following figure gives an idea of the logic structure:

Figure 1. Logic Structure
Note: Refer to UltraScale FPGA Post-Configuration Access of SPI Flash Memory using STARTUPE3 (XAPP1280).
Note: Refer to UltraScale FPGA Post-Configuration Access of Parallel NOR Flash Memory using STARTUPE3 (XAPP1282).

The STARTUP primitive adds delay on the USRCCLKO to the CCLK pin. This delay is unaccounted for in the tool and is not considered in the timing calculation. For the tool, the timing path ends at USRCCLKO.

To obtain the required constraints you must account for the STARTUP primitive delay. As the timing path ends at USRCCLKO, you cannot create a clock on the CCLK pin.

To emulate the SCK clock, you must create a generated clock such that the STARTUP primitive delay is taken into account. This can be achieved by creating a generated clock on the USRCCLKO pin.

This takes into account the delay of the flip-flop that generates the SCK, the routing delay from that flip-flop to USRCCLKO pin, and the STARTUP primitive delay. Further, to reduce the delay on SCK you must ensure that the delay from the flip-flop to USRCCLKO is as low as possible. This can be constrained by using set_max_delay.

The datapaths can then be constrained using set_output_delay and set_input_delay along with set_multicyle_path constraints. All the following constraints are provided for SCK_ratio = 2.

  1. STARTUPE3 (UltraScale) primitive included inside IP:
    # You must provide all the delay numbers
    # CCLK delay is 0.1, 6.7 ns min/max for ultra-scale devices; refer Data sheet
    # Consider the max delay for worst case analysis
    set cclk_delay 6.7
    create_generated_clock -name clk_sck -source [get_pins -filter {REF_PIN_NAME==ext_spi_clk} -of [get_cells -hier -filter {x_core_info=~axi_quad_spi,*}]] -edges {3 5 7} -edge_shift [list
    $cclk_delay $cclk_delay $cclk_delay] [get_pins -hierarchical *USRCCLKO]
    set_multicycle_path -setup -from clk_sck -to [get_clocks -of_objects [get_pins -hierarchical */ext_spi_clk]] 2
    set_multicycle_path -hold -end -from clk_sck -to [get_clocks -of_objects [get_pins -hierarchical */ext_spi_clk]] 1
    set_multicycle_path -setup -start -from [get_clocks -of_objects [get_pins -hierarchical */ext_spi_clk]] -to clk_sck 2
    set_multicycle_path -hold -from [get_clocks -of_objects [get_pins -hierarchical */ext_spi_clk]] -to clk_sck 1
    set_max_delay -datapath_only -from [get_pins -hier {*STARTUP*_inst/DI[*]}] 1.000
    set_max_delay -datapath_only -from [get_clocks -of_objects [get_pins -hierarchical */ext_spi_clk]] -to [get_pins -hier *STARTUP*_inst/USRCCLKO] 1.000
    set_max_delay -datapath_only -from [get_clocks -of_objects [get_pins -hierarchical */ext_spi_clk]] -to [get_pins -hier *STARTUP*_inst/DO[*]] 1.000
    set_max_delay -datapath_only -from [get_clocks -of_objects [get_pins -hierarchical */ext_spi_clk]] -to [get_pins -hier *STARTUP*_inst/DTS[*]] 1.000
  2. STARTUPE3 (UltraScale+) primitive included inside IP: Vivado times the STARTUPE3 differently for UltraScale+ devices. For the purpose of timing the STARTUPE3, certain internal pins were modeled which can be used to time the primitive. Below lines show the set of constraints that can be used with UltraScale+ devices.
    set tdata_trace_delay_max 0.25
    set tdata_trace_delay_min 0.25
    set tclk_trace_delay_max 0.2
    set tclk_trace_delay_min 0.2
    create_generated_clock -name clk_sck -source [get_pins -filter {REF_PIN_NAME==ext_spi_clk} -of [get_cells -hier -filter {x_core_info=~axi_quad_spi,*}]] [get_pins -hierarchical */CCLK] -edges {3 5 7}
    set_input_delay -clock clk_sck -max [expr $tco_max + $tdata_trace_delay_max + $tclk_trace_delay_max] [get_pins -hierarchical *STARTUP*/DATA_IN[*]] -clock_fall;
    set_input_delay -clock clk_sck -min [expr $tco_min + $tdata_trace_delay_min + $tclk_trace_delay_min] [get_pins -hierarchical *STARTUP*/DATA_IN[*]] -clock_fall;
    set_multicycle_path 2 -setup -from clk_sck -to [get_clocks -of_objects [get_pins -hierarchical */ext_spi_clk]]
    set_multicycle_path 1 -hold -end -from clk_sck -to [get_clocks -of_objects [get_pins -hierarchical */ext_spi_clk]]
    set_output_delay -clock clk_sck -max [expr $tsu + $tdata_trace_delay_max - $tclk_trace_delay_min] [get_pins -hierarchical *STARTUP*/DATA_OUT[*]];
    set_output_delay -clock clk_sck -min [expr $tdata_trace_delay_min -$th - $tclk_trace_delay_max] [get_pins -hierarchical *STARTUP*/DATA_OUT[*]];
    set_multicycle_path 2 -setup -start -from [get_clocks -of_objects [get_pins -hierarchical */ext_spi_clk]] -to clk_sck
    set_multicycle_path 1 -hold -from [get_clocks -of_objects [get_pins -hierarchical */ext_spi_clk]] -to clk_sck
    set_max_delay -datapath_only -from [get_pins -hier {*STARTUP*_inst/DI[*]}] 1.000
    set_max_delay -datapath_only -from [get_clocks -of_objects [get_pins -hierarchical */ext_spi_clk]] -to [get_pins -hier *STARTUP*_inst/USRCCLKO] 1.000
    set_max_delay -datapath_only -from [get_clocks -of_objects [get_pins -hierarchical */ext_spi_clk]] -to [get_pins -hier *STARTUP*_inst/DO[*]] 1.000
    set_max_delay -datapath_only -from [get_clocks -of_objects [get_pins -hierarchical */ext_spi_clk]] -to [get_pins -hier *STARTUP*_inst/DTS[*]] 1.000
    Note: [1] Multi Cycle Path constraints can be removed or updated on getting any timing violations.
    Note: [2] Regarding set_max_delay constraints, recent Vivado tool (From 2020.1 onwards) flow takes care of adding set_max_delay constraints for UltraScale/UltraScale+. In this case, do not add explicit constraints mentioned above and make sure to comment the set_max/min_delay constraints.
  3. STARTUPE2 Enabled:

    Use the set of constraints for STARTUPE2.

    
    # You must provide all the delay numbers
    # CCLK delay is 0.5, 6.7 ns min/max for K7-2; refer Data sheet
    # Consider the max delay for worst case analysis
    set cclk_delay 6.7
    #Following are the SPI device parameters according to the data sheet
    
    # Maximum Clock-to-output delay
    set tco_max 7
    # Minimum Clock-to-output delay
    set tco_min 1
    # Data in Setup time requirement
    set tsu 2
    # Data in Hold time requirement
    set th 3
    # Following are the board/trace delay numbers
    # Assumption is that all Data lines are matched
    set tdata_trace_delay_max 0.25
    set tdata_trace_delay_min 0.25
    set tclk_trace_delay_max 0.2
    set tclk_trace_delay_min 0.2
    ### End of user provided delay numbers
    # this is to ensure min routing delay from SCK generation to STARTUP input
    # User should change this value based on the results
    # having more delay on this net reduces the Fmax
    set_max_delay 1.5 -from [get_pins -hier *SCK_O_reg_reg/C] -to [get_pins -hier *USRCCLKO] -datapath_only
    set_min_delay 0.1 -from [get_pins -hier *SCK_O_reg_reg/C] -to [get_pins -hier *USRCCLKO]
    # Following command creates a divide by 2 clock
    # It also takes into account the delay added by STARTUP block to route the CCLK
    create_generated_clock -name clk_sck -source [get_pins -filter {REF_PIN_NAME==ext_spi_clk} -of [get_cells -hier -filter {x_core_info=~axi_quad_spi,*}]]  [get_pins -hierarchical *USRCCLKO] -edges
    {3 5 7} -edge_shift [list $cclk_delay $cclk_delay $cclk_delay]
    # Data is captured into FPGA on the second rising edge of ext_spi_clk after the SCK falling edge
    # Data is driven by the FPGA on every alternate rising_edge of ext_spi_clk
    set_input_delay -clock clk_sck -max [expr $tco_max + $tdata_trace_delay_max + $tclk_trace_delay_max] [get_ports IO*_IO] -clock_fall;
    set_input_delay -clock clk_sck -min [expr $tco_min + $tdata_trace_delay_min + $tclk_trace_delay_min] [get_ports IO*_IO] -clock_fall;
    set_multicycle_path 2 -setup -from clk_sck -to [get_clocks -of_objects [get_pins -hierarchical */ext_spi_clk]]
    set_multicycle_path 1 -hold -end -from clk_sck -to [get_clocks -of_objects [get_pins -hierarchical */ext_spi_clk]]
    # Data is captured into SPI on the following rising edge of SCK
    # Data is driven by the IP on alternate rising_edge of the ext_spi_clk
    set_output_delay -clock clk_sck -max [expr $tsu + $tdata_trace_delay_max - $tclk_trace_delay_min] [get_ports IO*_IO];
    set_output_delay -clock clk_sck -min [expr $tdata_trace_delay_min -$th - $tclk_trace_delay_max] [get_ports IO*_IO];
    set_multicycle_path 2 -setup -start -from [get_clocks -of_objects [get_pins -hierarchical */ext_spi_clk]] -to clk_sck
    set_multicycle_path 1 -hold -from [get_clocks -of_objects [get_pins -hierarchical */ext_spi_clk]] -to clk_sck
    STARTUP is Disabled:
    #Following are the SPI device parameters according to the data sheet
    
    # Maximum Clock-to-output delay
    set tco_max 7
    # Minimum Clock-to-output delay
    set tco_min 1
    # Data in Setup time requirement
    set tsu 2
    # Data in Hold time requirement
    set th 3
    # Following are the board/trace delay numbers
    # Assumption is that all Data lines are matched
    set tdata_trace_delay_max 0.25
    set tdata_trace_delay_min 0.25
    set tclk_trace_delay_max 0.2
    set tclk_trace_delay_min 0.2
    ### End of user provided delay numbers
    create_generated_clock -name clk_sck -source [get_pins -filter {REF_PIN_NAME==ext_spi_clk} -of [get_cells -hier -filter {x_core_info=~axi_quad_spi,*}]] [get_ports <SCK_IO>] -edges {3 5 7}
    # Data is captured into FPGA on the second rising edge of ext_spi_clk after the SCK falling edge
    # Data is driven by the FPGA on every alternate rising_edge of ext_spi_clk
    set_input_delay -clock clk_sck -max [expr $tco_max + $tdata_trace_delay_max + $tclk_trace_delay_max] [get_ports IO*_IO] -clock_fall;
    set_input_delay -clock clk_sck -min [expr $tco_min + $tdata_trace_delay_min + $tclk_trace_delay_min] [get_ports IO*_IO] -clock_fall;
    set_multicycle_path 2 -setup -from clk_sck -to [get_clocks -of_objects [get_pins -hierarchical */ext_spi_clk]]
    set_multicycle_path 1 -hold -end -from clk_sck -to [get_clocks -of_objects [get_pins -hierarchical */ext_spi_clk]]
    # Data is captured into SPI on the following rising edge of SCK
    # Data is driven by the IP on alternate rising_edge of the ext_spi_clk
    set_output_delay -clock clk_sck -max [expr $tsu + $tdata_trace_delay_max - $tclk_trace_delay_min] [get_ports IO*_IO];
    set_output_delay -clock clk_sck -min [expr $tdata_trace_delay_min -$th - $tclk_trace_delay_max] [get_ports IO*_IO];
    #tCSS - chip select setup time requirement
    set tCSS 2
    #tCSH - chip select hold time requirement
    set tCSH 3
    #SS Setup: Must be asserted before first clock edge
    set_output_delay -clock clk_sck -max [expr $tCSS + $tdata_trace_delay_max - $tclk_trace_delay_min] [get_ports ss_*]
    #SS Hold: Must remain asserted after last clock edge
    set_output_delay -clock clk_sck -min [expr $tdata_trace_delay_min - $tCSH - $tclk_trace_delay_max] [get_ports ss_*]
    set_multicycle_path 2 -setup -start -from [get_clocks -of_objects [get_pins -hierarchical */ext_spi_clk]] -to clk_sck
    set_multicycle_path 1 -hold -from [get_clocks -of_objects [get_pins -hierarchical */ext_spi_clk]] -to clk_sck