Constraining Generated Clocks and Asynchronous Clocks in Synthesis

This is article-4 of how to define Synthesis timing constraint

Generated Clocks

Figure 1: Generated clock in a design

Consider the example shown in Figure 1, the clock goes through a divide-by-2 flip-flop (or flop-1) before driving another flip-flop (or flop-2). The problem is the clock definition on the clock port along with other definitions related to clock, like uncertainty, don’t propagate through the sequential logic; in this case don’t propagate to the output of divide-by-2 flip-flop (or flop-1). Therefore, for flop-2 to be constrained by a clock, a new clock definition needs to be applied at the output of flop-1’s instance.

The recommended way of doing this is to create a generated clock at the output of flop1’s instance, along with the clock definition on the clock port. The benefit of a generated clock is that it can establish a relationship between it and its master clock.

create_clock -period 2 [get_ports CLK]
set_clock_uncertainty -setup 0.25 [get_clocks CLK]

create_generated_clock -divide_by 2 -name -CLK_SLW -source [get_ports CLK] [get_pins div2flop/out]
set_clock_uncertainty -setup 0.4 [get_clocks CLK_SLW]

Notice that the divide_by option is applied to the frequency, not the time period, so actually we are doubling the time period of 2ns and making it 4ns in this example. We are then giving the generated clock a name, CLK_SLW and we specify the source as the port called CLK. Finally, we apply the generated clock on a pin called div2flop/out. Since we specify the source clock as the port CLK, if the source clock period changes, the generated clock period will automatically be updated as well. And then we can apply other constraints like, uncertainty to clock CLK_SLW as well.  

In this example it was assumed that flop-1 was instantiated in our RTL code, therefore we knew the name of the flop-1’s instance and the name of the output pin ‘out’.

But if the flop is not instantiated in the RTL but coded in the RTL using the Verilog construct –

always@(posedge CLK) begin DIV_CLK <= ~DIV_CLK; end

then we don’t know what instance & pin name to use for constraining. Therefore, with RTL coding registers, we need to apply constraints to the flop using the gtech (generic technology) cell or pin name. By definition, the cell name of the flop will always be its output signal name followed by _reg.

In our example, the output signal name is called DIV_CLK, so the cell name of the flop will be called DIV_CELL_reg. The gtech output pin of the flop will always be called Q, so in the example below we apply the generated clock to the pin called DIV_CLK_reg/Q –

create_generated_clock -divide_by 2 -name -CLK_SLW -source [get_ports CLK] [get_pins DIV_CLK_reg/Q]

After synthesis, when this generic register is replaced with an actual register from library, the constraint will automatically be updated with the actual pin from the library cell.

Asynchronous Clocks

Figure 2: Asynchronous clocks in a design
Figure 3: Asynchronous clocks

Consider the example shown in Figure 2, the flop-1 is clocked by CLKB, 500 MHz clock and the flop-2 is clocked by CLKA, a 333.3 MHz clock. But as shown in Figure 3, CLKA and CLKB are derived from different crystal oscillators; since these two clocks come from different sources, they are asynchronous to each other. To handle the clock domain crossing data, there is a double synchronizer at the input of flop-2. When we constrain our design using two create_clock commands for CLKA and CLKB, the synthesis tool by default considers the two clocks as synchronous. This means the timing path between flop-1 and flop-2 will be constrained by the worst-case timing between the launching clock CLKA and the capturing clock CLKB within the base period of two clock periods. However, since these two clocks are asynchronous, we don’t want any timing constraints applied to the CLKA and CLKB interfaces.

We can disable the timing between asynchronous clock domains by defining the clock groups as asynchronous as shown below –

create_clock -period 3 [get_ports CLKA]
create_clock -period 2 [get_ports CLKB]
set_clock_groups -asynchronous -group CLKA -group CLKB

The bottom line is, if we have a design with asynchronous clocks, then it is our responsibility to design the logic in order to prevent metastability at the interfaces (using double synchronizer, etc). We next need to create clocks to constrain the paths within each clock domain for synchronous timing and then finally we need to disable timing optimization along the paths between the asynchronous clock domains to prevent synthesis tool from wasting run time on non-critical timing paths (optimizing timing across these non-critical paths may lead to ignorance of optimization of actual timing critical paths by the synthesis tool).

NOTE:

Case – 1: If we have a design with multiple clocks, and there is a clock (named CLKX) which is asynchronous to all other clocks, then we can constrain the same using –
set_clock_groups -asynchronous -group CLKX
Also, this implies all other clocks are synchronous to each other

Case – 2: If we have five clocks in our design (CLKA, CLKB, CLKC, CLKD & CLKE) and CLKA & CLKB are synchronous to each other but asynchronous to all other clocks, then we can constrain the same using –
set_clock_groups -asynchronous -group {CLKA CLKB}
Also, this implies CLKC, CLKD & CLKE are synchronous to each other