Multi-cycle path constraints in FPGA timing constraints actual combat

Multi-cycle path constraints in FPGA timing constraints actual combat

Multi-period path constraint

  For multi-period paths, we generally follow the following 4 steps to constrain:

  1. Data with enable

  First look at the data with enablement. In the Tming Report in this project, it is also suggested that the establishment time of several paths between the same clock domain does not meet the requirements.

  In fact, these paths are all paths with enable, and the period of the enable is twice the clock period, and it should be judged the timing closure within 2 clock periods. Therefore, we add timing constraints:

set_multicycle_path 2 -setup -from [get_cells {cmd_parse_i0/send_resp_data_reg[*]} -include_replicated_objects] -to [get_cells {resp_gen_i0/to_bcd_i0/bcd_out_reg[*]}]
set_multicycle_path 1 -hold -from [get_cells {cmd_parse_i0/send_resp_data_reg[*]} -include_replicated_objects] -to [get_cells {resp_gen_i0/to_bcd_i0/bcd_out_reg[*]}]

It can also be written as:

set_multicycle_path -from [get_cells {cmd_parse_i0/send_resp_data_reg[*]} -include_replicated_objects] -to [get_cells {resp_gen_i0/to_bcd_i0/bcd_out_reg[*]}] 2
set_multicycle_path -hold -from [get_cells {cmd_parse_i0/send_resp_data_reg[*]} -include_replicated_objects] -to [get_cells {resp_gen_i0/to_bcd_i0/bcd_out_reg[*]}] 1

These two ways of writing are equivalent.

We can also directly click the right button to constrain through the GUI, and the effect is the same.

  In the project uart_tx_ctl.vand uart_rx_ctl.vfile, there are also data with enable, but these paths do not report timing errors or warnings when multipath constraints are not added.

At the receiving end, the capture clock frequency is 200MHz, the serial port rate is 115200, and 16 times the Oversampling is used, so the enable signal cycle is 200e6/115200/16=108.5 times the clock cycle.

At the receiving end, the capture clock frequency is 166667MHz, the serial port rate is 115200, and 16 times the Oversampling is used, so the enable signal cycle is 166.667e6/115200/16=90.4 times the clock cycle.

  Therefore, the timing constraints are as follows:

# Serial port receiver
set_multicycle_path -from [get_cells uart_rx_i0/uart_rx_ctl_i0/* -filter IS_SEQUENTIAL] -to [get_cells uart_rx_i0/uart_rx_ctl_i0/* -filter IS_SEQUENTIAL] 108
set_multicycle_path -hold -from [get_cells uart_rx_i0/uart_rx_ctl_i0/* -filter IS_SEQUENTIAL] -to [get_cells uart_rx_i0/uart_rx_ctl_i0/* -filter IS_SEQUENTIAL] 107
# Serial port sender
set_multicycle_path -from [get_cells uart_tx_i0/uart_tx_ctl_i0/* -filter IS_SEQUENTIAL] -to [get_cells uart_tx_i0/uart_tx_ctl_i0/* -filter IS_SEQUENTIAL] 90
set_multicycle_path -hold -from [get_cells uart_tx_i0/uart_tx_ctl_i0/* -filter IS_SEQUENTIAL] -to [get_cells uart_tx_i0/uart_tx_ctl_i0/* -filter IS_SEQUENTIAL] 89

The filterparameters in the constraints will also be explained in detail in the next chapter.

  1. There is a phase difference between two clocks that exchange data

  In this project, there is no such application scenario, so there is no need to add such constraints.

  1. There is a path from fast clock to slow clock

  In this project, there is no such application scenario, so there is no need to add such constraints.

  1. There is a path from slow clock to fast clock

  In this project, there is no such application scenario, so there is no need to add such constraints.

In summary, all our timing constraints are as follows:

# Master clock constraint
create_clock -period 25.000 -name clk2 [get_ports clk_in2]

# Derived clock constraints
create_generated_clock -name clk_samp -source [get_pins clk_gen_i0/clk_core_i0/clk_tx] -divide_by 32 [get_pins clk_gen_i0/BUFHCE_clk_samp_i0/O]
create_generated_clock -name spi_clk -source [get_pins dac_spi_i0/out_ddr_flop_spi_clk_i0/ODDR_inst/C] -divide_by 1 -invert [get_ports spi_clk_pin]
create_generated_clock -name clk_tx -source [get_pins clk_gen_i0/clk_core_i0/inst/mmcm_adv_inst/CLKIN1] [get_pins clk_gen_i0/clk_core_i0/inst/mmcm_adv_inst/CLKOUT1]
create_generated_clock -name clk_rx -source [get_pins clk_gen_i0/clk_core_i0/inst/mmcm_adv_inst/CLKIN1] [get_pins clk_gen_i0/clk_core_i0/inst/mmcm_adv_inst/CLKOUT0]

# Set asynchronous clock
set_clock_groups -asynchronous -group [get_clocks clk_samp] -group [get_clocks clk2]

# Delay constraint
create_clock -period 6.000 -name virtual_clock
set_input_delay -clock [get_clocks -of_objects [get_ports clk_pin_p]] 0.000 [get_ports rxd_pin]
set_input_delay -clock [get_clocks -of_objects [get_ports clk_pin_p]] -min -0.500 [get_ports rxd_pin]
set_input_delay -clock virtual_clock -max 0.000 [get_ports lb_sel_pin]
set_input_delay -clock virtual_clock -min -0.500 [get_ports lb_sel_pin]
set_output_delay -clock virtual_clock -max 0.000 [get_ports {txd_pin {led_pins[*]}}]
set_output_delay -clock virtual_clock -min -0.500 [get_ports {txd_pin {led_pins[*]}}]
set_output_delay -clock spi_clk -max 1.000 [get_ports {spi_mosi_pin dac_cs_n_pin dac_clr_n_pin}]
set_output_delay -clock spi_clk -min -1.000 [get_ports {spi_mosi_pin dac_cs_n_pin dac_clr_n_pin}]

# Pseudo path constraint
set_false_path -from [get_clocks clk_rx] -to [get_clocks clk_tx]
set_false_path -from [get_ports rst_pin]

# Multi-period constraints
set_multicycle_path 2 -setup -from [get_cells {cmd_parse_i0/send_resp_data_reg[*]} -include_replicated_objects] -to [get_cells {resp_gen_i0/to_bcd_i0/bcd_out_reg[*]}]
set_multicycle_path 1 -hold -from [get_cells {cmd_parse_i0/send_resp_data_reg[*]} -include_replicated_objects] -to [get_cells {resp_gen_i0/to_bcd_i0/bcd_out_reg[*]}]

# Serial port receiver
set_multicycle_path 108 -setup -from [get_cells uart_rx_i0/uart_rx_ctl_i0/* -filter IS_SEQUENTIAL] -to [get_cells uart_rx_i0/uart_rx_ctl_i0/* -filter IS_SEQUENTIAL]
set_multicycle_path 107 -hold -from [get_cells uart_rx_i0/uart_rx_ctl_i0/* -filter IS_SEQUENTIAL] -to [get_cells uart_rx_i0/uart_rx_ctl_i0/* -filter IS_SEQUENTIAL]
# Serial port sender
set_multicycle_path 90 -setup -from [get_cells uart_tx_i0/uart_tx_ctl_i0/* -filter IS_SEQUENTIAL] -to [get_cells uart_tx_i0/uart_tx_ctl_i0/* -filter IS_SEQUENTIAL] 
set_multicycle_path 89 -hold -from [get_cells uart_tx_i0/uart_tx_ctl_i0/* -filter IS_SEQUENTIAL] -to [get_cells uart_tx_i0/uart_tx_ctl_i0/* -filter IS_SEQUENTIAL]

  After re-Synthesis and Implementation, you can see that there are no timing errors

  The only two warnings only say that rst does not set input_delay, spi_clk_pin does not set output_delay, but we have set a pseudo path to rst, and spi_clk_pin is our constrained output clock, and there is no need to set output_delay.

  At this point, the timing constraint tutorial of the textbook version is basically finished. But in our usual projects, there are still differences with the above constraints:

  1. The first is the virtual clock. This constraint is basically not used in ordinary projects. For scenarios where a virtual clock needs to be set, we also use design to ensure timing closure. Setting a virtual clock does not make much sense.
  2. The second is output delay. In the path from the last-level register of FPGA to the output, IOB is often used, that is, IO block, so the position of the last-level register is fixed, and the wiring delay from buffer to pad Is ok. In this case, whether the timing requirements are met is entirely up to the design, and the constraints are just to verify whether the timing is closed. So basically don't do it. But input delay is needed because this is the timing relationship of the output of the upper-level device.
  3. The third is the multi-cycle path. We have talked about so many application scenarios of the multi-cycle path, but in reality, we are constrained according to the Timing report, even if those scenarios exist, if there is no timing warning in the Timing report , We often do not add constraints.
  4. The fourth is that after setting up multiple cycles, if the setup time of Intra-Clocks Paths is still prompted, then it depends on whether the program is written irregularly. such as

  If the set multi-cycle path, or prompt Intra-Clocks Pathsthe setup timeHowever, it depends on the next program, if writing is not standardized. such as

always @ (posedge clk)
begin
    regA <= regB;

    if(regA != regB)
        regC <= 4'hf;
    else 
        regC <= {regC[2:0], 1'b0};

    if((&flag[3:0]) && regA != regB) 
        regD <= regB;
end

In this way, if the clock frequency is slightly higher, such as 250MHz, it is easy to cause the setup time from regB to regD to fail to meet the requirements. Because the codes in the begin end are executed in sequence, it is still quite a challenge to complete the logic of these assignments and judgments within 4ns. Therefore, we can rewrite it as:

always @ (posedge clk)
begin
    regA <= regB;
end 

always @ (posedge clk)
begin
    if(regA != regB)
        regC <= 4'hf;
    else 
        regC <= {regC[2:0], 1'b0};
end 

always @ (posedge phy_clk)
begin
    if((&flag[3:0]) && regA != regB) 
        regD <= regB;
end 

Separate the assignment of the register, the function is still the same, but divided into several always, so that it will not cause timing problems.

Reference: https://cloud.tencent.com/developer/article/1653055 FPGA Timing Constraint Practical Chapter: Multi-cycle Path Constraints-Cloud + Community-Tencent Cloud