Menu

Reading time:

Understanding AMD Timing Constraints Management

Primary Clocks and Generated Clocks

 

Reading time 10 minutes

 

As HDL languages do not support definitions of clock characteristics like the frequency and phase, these characteristics needs to be defined with timing constraints. AMD Vivado defines this constraints based on Synopsys. Synopsys has standardized the constraints for objects which are available to the designer, such as FPGA pins.
 
With AMD Vivado, the netlist database differs between pins and ports: pins are the inner hierarchical connecvity ports, while a port in the Vivado database is a top-level pin. Be aware that pins and ports in the database are exclusive, not subgroups. This means that a definition of a port and a pin is not unique; it depends on its language and tool context. A primary clock constraint means a timing constraint for a clock object, where the syntax defines a clock period, clock phase, and waveform characteristic – independant of propagating dependencies. Typically, the user will define a primary clock constraint on all incoming clocks at these ports. For Zynq and adaptive SoC devices, the clock for the programmable hardware is mostly sourced from the processing system. Here, the required primary clock constraint is auto-generated and should no be overwritten by the user. As described in the previous blog, Vivado IPs, such as the Clocking Wizard, will also create a primary clock constraint.
 
A declaration of a primary clock constraint:
 

create_clock -name <my_clock_name> -period <values_ns> [get_ports <my_clock_input>]

 
You can also add the option -waveform to define a specific pulse meander (by default it is a pulse width ratio of 50% high and 50% low). However, before doing this, you should check for existing timing constraints, as IPs like the Clocking Wizzard IP also creates a primary clock constraint.
 
You have three options to manage this situation:
 
01. Check the validity of this constraint for your design if this simply can be accepted. Have a look for warnings in the synthesis report. Run get_clocks * in the TCL console to find this existing constraint in the database after a successful synthesis run.
 
02. You could only rename the clock constraint with the same constraint syntax without the option of -period and/or -waveform
 

create_clock -name <my_clock_name> [get_ports <my_clock_input>]

 
03. You could define the clock constraint in the user file set (i.e. constr_1) and this will overwrite the IP generated constraint. However, it is important to ensure that the clock characteristics are not altered, as the IP customization defines these characteristics, and they must be preserved. This is especially important when defining a primary clock constraint on a port that propagates through the hierarchy to any clock pins.

 

pro:

we see and maintain all primary clock constraints from the user side stored in user constraint files.

 

con:

when using IPs including PLLs we need to maintain pair definitions of IP clock features with our user constraints. And this needs to match!

 

If all clocks in the FPGA are distributed in a direct manner from the ports, including only clock buffers, so that all clock pins have a same clock characteristic as the clocks from the input ports, primary clock constraints are sufficiant, without a need for generated clock constraints. But whenever clock characteristica change in the hardware architecture – defined from IPs and user HDL files – a generated clock constraint can specify the part of the clock characteristic that has changed.
 
For example, if we use falling edge clock sensitivity in the design, there are two possibilities: one is an inversion in the clock tree, and another is the inversion at the endpoint cell, like a D-flip-flop in a CLB. If we see the falling edge in a timing report, we know that the database recognized the falling edge characteristic correctly. However, if a clock inversion is caused by HDL coding using a non-clock dedicated resource, like a LUT in the CLB, this inversion is typically not seen as the timing engine not interpreting transitions – only register and RAM type cells.

The characteristic of dedicated clock resources, such as PLLs MMCM or serializer/deserializers in I/O banks, are fully analyzed for the clock behavior, so there is no need for the user to define a generated clock constraint. This distinction in the analysis during synthesis compilation is similar to RTL coding rules at the Register-Transfer Level (RTL). Timing paths do not care about functionality in transitions when using non-clocking resources.
 
To resolve this issue and getting the correct clock characteristics, we can define a generated clock constraint that defines the inversion characteristic of this LUT.
 

create_generated_clock -name -from [get_pins my_master_clock_pin] -to [get_pins my_master_clock_pin] -relation invert

 
 

Example: A need for primary and generated clock constraints

Example: A need for primary and generated clock constraints

 
 

The key point:
Instead of using a primary clock constraint, we define a generated clock constraint when we have a better understanding of the transition behavior that goes beyond Static Timing Analysis (STA). This allows us to overwrite the clock characteristics in the database for specific segments. With a generated clock constraint, we can phase shift, divide frequencies, move clock edges, and employ many options to model and to correct the clock behavior. We differentiate auto-generated clock constraints and user-generated clock constraints.
 

Hints:

When the clock tree is purely using dedicated clock resources, generated clock constraints will be created automatically in the synthesis run. This is the regular expectation and a good design rule: avoid using non-dedicated clocking resources as we also need to investigate how a user generated clock needs to be specified by the user to model this behavior. Validating the timing engine’s assumptions against the behavior achieved from the HDL coding after synthesis is also very important. This ensures that the assumptions are consistent with the actual behavior, helping to avoid any extra effort required for corrections.

 

There are two practical situations where it is meaningful to write generated clock constraints:
 
01. A clock is created in the FPGA for an external device but is not used in the FPGA fabric. The database identifies this as a clocked object rather than a clock object. By defining a generated clock, we inform the database that this port is a clock port with the specified behavior.
 
02. When we create a clock division using counters with Terminal Count (TC) periodically and use it as an enable signal for a clock (such as D-flip-flop clock enable, DSP slice clock enable, or an enable port of a clock buffer), we can define the generated clock constraints

 

Generated clock constraints will be auto-created, if:
 
01. All PLL/MMCM clock outputs will get an auto-created generated clock constraint if the PLL is using an appropriate use-case.
 

02. IOB serializers/deserializers are used following recommended design rules.
 

03. Dedicated hard silicon clocking features are used following recommended design rules.
 

04. Clock buffers with integrated clock dividers are used.

 

Finally the TCL command report_clocks is recommended to determine all clock objects behaviors in the hardware design, which can be launched after the synthesis or an implementation run.