SDC - clock commands

SDC Clock cmds:

Here are some of the imp clock cmds as part of SDC spec. Many of these are used in synthesis also.

 


 

create_clock:

creates clock on specified source object (usually  clk ports, but may be pins or nets too. When a net is used as source, then the first driver pin of net is the actual source used in creating clk. If clk is defined on an internal pin, maybe because it's a PLL or osc o/p inside the block, we may see a warning in PT (UITE-130 warning), since "create_generated_clock" is the cmd for clks on internal pins/nets. When "create_clock" is used on internal pin, any upstream timing info is lost for that clock, i.e any logic before that pin is not considered for timing. Clk starts at time 0 from that pin, so we may need to add latency for this clk to account for extra delay before this pin). If source object is not specified, then a virtual clk is created with the given name. A virtual clk is usually used to rep an off chip clk for input output delay spec (i.e set_input_delay, set_output_delay). For each clk specified, by default, a new path group is created for that clk. A path group is all the paths in design that have that clk as the endpoint. This is used for cost calc func for optimization. see "group_path" cmd for more info.

This new clk has ideal latency (zero delay at source of clk), 0 transition time (i.e slope of 90 degrees for rise/fall) and 0 propagated delay. That means that even if there are muxes, gates, clkgaters etc in design, they are all assumed ideal with 0 delay. To enable propagated delay, use "set_propagated_delay" cmd. To enable latency, use "set_clock_latency" cmd. To enable transition, use "set_clock_transition" cmd. "set_clock_uncertainty" cmd is used to account for clk edge variation from cycle to cycle. This in a way, makes clk more pessimistic, and we have to meet tighter timing requirements. These 4 cmds are detailed below later.

syntax: create_clock -name <clk_name> -period <period_vale> <other_options> <src_pin_or_port>

<other_options>:

  • -add: sometimes multiple clks are speciifed on same src for simultaneous analysis with multiple clks. In such cases, using -add, adds the clock on that source on top of whtever clks were already specified on that src. W/o this option, the new clk would over write other clocks.
  • -waveform {1st_rising_edge_after_time_0 1st_falling_edge_after_time_0 2nd_rising_edge_after_time_0 ... }. There must be even num of edges. W/o this option, rise is assumed at 0, and fall at period/2.
    • ex: create clock  -name "spi_clk" -period 50 -waveform { 2 27 } [get_ports spi_clk] => 20 MHz clk (period is in specified lib time units), rising edge at 2ns and falling edge at 27ns. To get inverted clock which starts high, we should do "-waveform {27 2}" which makes clock go high at 27ns and go low at 2ns, i.e clk is inverted. -waveform {2 25 40 45} indicates 2 high pulses in 1 period (goes high at 2, low at 25, then goes high at 40, low at 45.

ex:  create clock -name "clkm" -period 50 {cla/Z clb/Y} => creates clk with name clkm, with multiple sources "cla/Z, clb/Y", rise at 0, fall at 25. equiv to -waveform {0 25}. This is different than "-add" where there were multiple clks defined on same source. Here, it's same clk defined on multiple source. Basically, it's saying that same clk waveform exists on both of these clks. They are connected externally, but here they appear as 2 separate pin. But we define same clk on both these ports to indicate they have same waveform.



create_generated_clock:

Creates generated clk which is synchronous with other clocks. Syntax is almost same as that of create_clock. Here we specify gen_clk along with it's master clk which is the source of this gen_clk.

So, these 2 options are required:

  • gen_clk and on which pin/port/net it is on - i.e the name of the port, pin, etc where this gen clk is defined. PT starts the gen clk from this point onwards.
  • what is the source master pin (aka src pin) for this gen_clk? This is specified via -source option. There's a different "master clk", which is a clk and NOT pin. See below for details.

Clks start from their origin, and by default, keep flowing thru combo logic, until it hits seq pins where it stops. It stops on sequential pin for obvious reason - clks usually don't go thru flops as clk pin of flop is the final destination (sink point for a clk). This becomes an issue when we want to have divided clks. Divided clks are mostly generated at o/p of flop. To make this work, sdc allows us to use this cmd. We define the gen_clk on the o/p pin of this flop.

If gen_clk is on o/p pin of flop, then timing tool cannot trace the clk back without help. Here we help the tool by defining src clk of this gen clk. -source is used to specify the master or source of gen_clk which is generally the clk pin of seq logic. Tool starts tracing path from src clk going thru combo logic (assuming src clk is defined little further up from the clk pin of flop). When it comes to flop clk pin, it needs to see a path from input clk to generated clk, meaning a timing arc has to exist between these 2 pins (i.e for flop, it sees arc from clk pin to Q pin [CLK->Q arc, i.e Q pin has "related pin" as CLK]). If it sees that arc, it continues and is able to calc the clk latency for the generated clk from the src clk. If there's no arc from CLK->Q pin, then we can't have CLK pin as source for clk on Q pin of flop as PT can't calc delay w/o any timing arc (we get PTE-075 error. see below for details). src clk itself may be generated clk, which eventually will lead to a real clk created using "create_clock" cmd.

Also, the tool doesn't know the logic to figure out waveform relation between clk pin and o/p pin of the seq logic. So, we need to define the relationship too. Gen_clk can either be div_by, mul_by or same clk as master (i.e div_by 1 specified by using -combinational), or edge derived clk. Gen clk can only have edges corresponding to src clk edges, i.e it's not possible for gen_clk to have an edge at 1.5ns, when src clk is changing edges only at 1 ns increment. Tht is why mul_by or div_by can only have integer numbers and can't be decimals. In short, a generated clk edge must always come from certain edge of src clk. We do not define period for gen_clk, as it's deduced automatically from these options.

NOTE:  Although gen_clk can be specified on any ports/pins/nets, we should generally specify it on driving pin. When we define it on a net, tool automatically uses the driver pin of the net as the src pin of the clk. We should avoid defining it on module boundary pin, since that causes the net to be segmented, so xtalk can't be calc on that net, resulting in 0 delta delay for that net (PT issues UITE-136 warning). A tcl procedure can be used to get driving pin for any net or port of a block:

proc get_driving_pin {pin} {
 return [get_pins -leaf -of [all_connected [get_pins $pin]] \
  -filter {pin_direction =~ *out}]
}

create_clock ... [get_driving_pin CLKGEN/CLKOUT] => preferred way

create_clock ... [get_pins CLKGEN/CLKOUT] => not recommended since the hierarchical pin name may change from one synthesis to another.

syntax: create_generated_clock -name <clk_name> -source <master_pin> -divide_by/multiply_by/combinational <other_options> <gen_clk_pin_or_port>

<other_options>:

  • -name => name of clock,
  • -divide_by/multiply_by => divide frequency of src clk by that number (-multiply_by multiplies freq. -duty_cycle used to specify duty cycle for multipled clks). These can only be integers as explained above. We don't have period or frequency for generated clk, as it's derived via this option.
    • -combinational => This is special option for "-divide_by 1" gen_clk. It tells to include only combo logic when calc delay from master clk to gen_clk, and not to include delay thru latch data pin, flop clk pin or src pin of other gen_clk. This is done when logically the gen clk is not really a divided clk, but we define a new gen clk anyway for some other STA reason.
  • -source <master_pin> => Specifies the name of the source master pin from which the new clock is to be derived (delays for gen clk are computed using the source clk. A path should exist from src clk to gen clk or else tool will report PTE-075 error). If mutiple clks exist on master src pin, then use "-add" and "-master_clock" (or -master in short form) option to add more gen clks on the same pin/port. If there are 10 clks specified on master source pin for this gen clk, then there must be 10 gen_clks defined, 1 for each src master clk with -add option and -master_clock option indicating the master clk for that gen clk. -add option is required, else existing gen clks on that pin will be replaced with the latest clk defined. It's 10 diff gen_clk (since 10 diff name of gen clk) each with it's own clock waveforms on it. A lot of bogus launch/capture paths will show up when we define multiple clks on same src pin, so use FP (or set_clock_groups -exclusive) to remove such paths. If we want to define just 1 gen clk (instead of 10) on the gen_pin, then we should choose the src master clk that we want to use as the parent of this gen_clk. In this case, the tool will ignore the other 9 clks and won't have any paths from these other 9 clks to the gen clk.
    • NOTE: -source specifies pin while -master_clock specifies "clock" in design and not a pin (as same pin may have multiple clks since there may be a mux before the source pin). If we define gen_clk source to be before all the muxes in clk path, then no -master_clock needed, since there is usually single clk defined on input ports. For single clk cases, just defining with "-source <master_pin> suffices, and the tool is able to figure out the clk on that pin. However, if we do use -master_clock in such a case, it's harmless since it will anyway trace to that clk. It's a good practise to use -master for all gen_clks irrespective of how many clks are there on master pin. If we don't specify a -master_clock when there are multiple clks in the path of CGC, then it seems like PT picks up one of the clks as master (we can see that, when we do report_clocks). So, always specify a -master when having multiple clks on the source.
    • NOTE: It always safe to use port name or o/p pin of gate, or module pin name as -source of generated clock. Do not use internal net name as timing tools (such as Cadence VDIO) may just ignore such a clock. Also, if you want to use clkname as -source, use "-master_clock <source_clock_name>" instead of -source else VDIO may ignore it.
    • One more subtle issue on how -source is treated for generated clk. If we define gen_clk on the o/p of a mux for multiple clks coming into the mux, then the behaviour of -source option causes PT to take paths that we don't expect. This is because -source is only used to determine master clk taced back thru the src pin (It doesn't force the path to go thru that -source pin. So, when we define gen_clk at o/p of mux, it considers all possible paths from master_clk of that gen clk. To prevent this, we should define gen_clk directly on the o/p of the divider, so that gen_clk only sees one path thru that master clk. See article below for details =>
      • See this solvnet article: https://solvnetplus.synopsys.com/s/article/Specifying-MUXed-Clocks-in-PrimeTime-1576002495523
        • From above link: The -source option of the create_generated_clock command determines the identity of the master clock, and the sense (non-inverted or inverted) of that master clock. It does not steer the source latency path. Once the master clock's identity and sense are determined, all possible paths back to that clock's source are considered for the source latency path.
  • -invert => inverts the gen clk (only in case of div_by or mul_by). This is needed in cases where is inverter on the path from master clk to gen clk, which causes the polarity of gen_clk to be opposite to that of master clk.
    • Warning: Not using -invert option when design has inverter b/w source and gen clk will cause warning ""no src latency defined for gen_clk". See below for details
  • -edges {1 2 4 5 7} -edge_shift {5 10 5 10 5} => This ption is provided for genrated clock to change the edges of gen clk, i.e 25-75 duty cycle. The numbers represent edges from the source clock that are to form the edges of the generated clock. Number of edges must be odd and >=3 to make 1 full clk cycle. edge_shift represents amount of shift that specified edges undergo to yield final gen clk. These shifts are logical shifts. Delay due to gate latency will automatically be handled by tool. Usually, edge_shifts are not needed, but may be useful to model clks which are not integer divided. NOTE: no "-waveform" used for gen clks, as waveforms are automatically derived based on src clk or by using -edges. Also, num of edges need to be odd (atleast 3 for 1st rise, 1st fall and 2nd rise), while for waveform it needed to be even (atleast 2 for 1st rise and 1st fall).


ex: create_generated_clock -name "reg_clk" -divide_by 1 -source [get_ports clock_12m_port] [get_pins clk_rst_gen/reg_clk_mux/clock_out] => Creates  a new clock signal from the clock waveform of a given pin in the design, and binds it with the pins or hierarchical pins in the <target_pin_list> argument. Here target_pin_list is clk_rst_gen/reg_clk_mux/clock_out. Here gen_clk is same as master_clk. There's just a mux in b/w to select clk_12m_port (normal mode) or scan_clk_port (scan mode).

ex: create_generated_clock -name "reg_clk" -edges {1 7 13} -source [get_ports clock_12m] [get_pins clkgen/reg_clk_mux/clock_out] => Same as above, except we are using -edges here. creates "reg_clk" from src_clk clock_12m using 1st edge (rising or falling) of src_clk as 1st rising edge of gen_clk, 7th edge (rising or falling) of src_clk as 1st falling edge of gen_clk and 13th edge (rising or falling) of src_clk as 2nd rising edge of gen_clk => that completes 1 clk cycle of gen_clk. gen_clk is high for 3 clk cycles of src_clk and low for next 3 clk cycles of src_clk, so effectively it's a divide by 6 clock (could have used -divide_by 6 also). Atleast 3 edges need to be specified to form 1 cycle.  we use this edge based way when we want to have asymmetric clk where high and low time are different.

ex: create_generated_clock -edges {1 1 3} -edge_shift {0 2.5 0} -invert -source [get_pins CLK] {u_COR_FRQ/.../CLKOUT} => This creates a falling edge  pulse  (since inverted) of 2.5 units triggered  by  the rising edge of its master clock with a period 10 (since 1st rising and 1st falling are both from same rising edge of source clk with shift of 2.5 time units). gen clk object may be a list of port/pin/net (if net is used, then first driver pin of the net is the actual source used in  creating the generated clock). Here CLKOUT is a net, so it's driver pin used as gen clk object. -invert is used since there's a inverter in design b/w src master clk and gen clk.

WARNING: We should also watch out for warning as "no src latency defined for gen_clk" as this may indicate that the clk is not traced back to the master clk. I've seen this happening with gen_clk which was inverted in design, but I didin't use the -invert option. This caused the gen_clk not to be traced back as the tool was looking for rise->rise or fall->fall arc based on clk definition, but instead got rise->fall or fall->rise path in design. It couldn't find rise->rise or fall->fall arc in the inverter and so just dropped the path before the gen clk pin. Gen_clk started from the source_pin (i.e Q pin of flop) with 0ns delay and continued forward. This is incorrect as all setup/hold time calculated will be wrong in the absence of gen_clk not traced back to include src latency.

NOTE: create_clock and create_generated_clock are 2 most imp cmds for creating clks during Synthesis as well as STA. All the clls in the design need to be defined using these 2 cmds. Whenever we define a generated clk on any pin, clk from that point onward is the clk of this generated clk. i.e, let's say we define a gen clk on o/p pin of a clk gater, then, the regular clk that was propagating thru the clk gater (since it's a clk gater, PT can propagate clks thru it) will not propagate any more beyond the o/p pin of that clk gater. On any clk path before the o/p pin of clk gater, we'll see regular clocks, but on the o/p pin of clk gater, we'll see regular clock + our newly defined gen clk, and on any pin coming after this clkgater pin, we will only see the gen clk (and not any of regular clocks). So, the o/p pin of clk gater where we defined our gen clk is kind of odd in that it reports both clocks. We should not look at this pin, as it may confuse us, but always look at pins on the fanout of this clk gater o/p.

  • From Synopsys solvnet: When a generated clock is created at a pin, all other clocks arriving at that pin are blocked unless they too have generated clock versions created at that pin.

 

CLK on Ports/Pads of Chip:

Most of the times, pads on chip are bidirectional. They are set as "input only" pad by setting the "OE" (Output Enable) line of the Pad to "zero", or as "output only" pad by setting the "IE" (Input Enable) line of the Pad to "zero". These pads are designed as bidirectional, so that they may be used for multiple functions. For ex, in scan mode, we may want to set the pad as scanclk (as an input pad), while in Functional mode, we may want to drive data out on the pin. In this case, the pad being bidirectional helps, and we can make it input or output by setting bit via software.

The bidir PAD has 3 pins. One is the bidir PAD (seen as a pin on chip by the outside world). The other 2 pins are the input pin (IN) and output pin (OUT) inside the chip. The i/p IN pin takes incoming data from the PAD and passes it to the chip. The o/p OUT pin takes data generated from the logic on the chip, and passes it to the PAD.

Let's say we have a case, where the PAD acts as the clk. There are 3 cases possible:

  1. Chip as a Driver of Clk: Here the clk is driven from the chip to the outside world. We have a create_clk/create_generated clk on some internal node of the logic driving this clk. This clk will flow to the PAD as long as there is combo path from the internal clk to the PAD. The clk will flow from the OUT pin to the PAD. There's no need to define any separate CC or CGC on the PAD. If we report clock attribute on the PAD, we'll see the clk on the PAD meaning it propagated correctly.
  2. Chip as the Receiver of Clk: Here the clk is driven from the outside world to the chip. We have a create_clock cmd on the PAD to genreate a clk. Now this clk will flow from the PAD to the IN pin and then into the internal logic. We need to have a CC cmd on PAD, else there will be no clk on PAD.
  3. Chip as both Driver and Receiver of Clk: This is the weird case, where we want the clk to be both coming in and going out of the chip. You may wonder, if we have case 1 above, then will the clk going out from the chip to the PAD, come back into the chip? There are 2 timing arcs => one from the OUT pin to PAD, and other from PAD to IN pin. USually there's no timing arc from OUT to IN pin in the .lib of the PAD cell. It's possible that timing path takes the route from OUT to PAD and then from PAD to IN, thus creating a path from OUT to IN pin. Checking in PT, this does NOT seem to be the case. If you report clock attribute on the OUT pin and the PAD, you will see clock attr, but you will no clock attribute on the IN pin.  There will also be no timing path from OUT to IN pin. The reason is that the path breaks at the bidirectional pin/port. If we want the clk to propagate from the OUT pin to PAD to IN pin, then we have to do create_generated_clock on the PAd, with the "Source" pin as the OUT pin or some other pin on internal logic of OUT pin path. Then the tool sees the generated clock on the PAD (in addition to whatever clocks were previously there on the PAD), and this newly generated clock is now seen on IN pin of PAD. This can be checked via "clcok" attribute on IN pin.
    1. NOTE: Remeber to do this CGC on the PAD if you do want to loop back a clock from the OUT to IN pin. This is sometimes needed, as there are many high speed interfaces which have a loop back clk or data path for debug purposes.

We have associated remove_*, report_*, get_* cmds for clks.

  • remove_clock <clk_list> => It takes a list of collection containing clks or patterns and removes them from design (only ones that were previously created using "create_clock" cmd). "remove_clock -all" removes all clocks from design. All associated input/output delay wrt these clks are also removed. If there was path group with only these clks in it, then those path groups are also removed. NOTE: If you are on PT_SHELL, and use this cmd to remove a clk, and then add the same clk with any changes, then all previous clk grps are gone, and since we don't define any new clk grps, this clk will be synchronous to all existing clks. So, be sure to add appr clk grps, etc.
    • ex: remove_clock clk1 => removes previously defined clk1 from design.
  • remove_generated_clock <clk_list> => It's similar to remove_clock except that it applies to generated clks only. "remove_generated_clock -all" removes all generated clocks from design.
  • report_clock => always run this cmd after creating all clks to see all clks (incl generated_clks), their period, waveform, attribute (i.e generated/propagated) and their source(port or pin where it's defined). For generated clk, it shows additional info as generated src pin, master clk, master src pin(or port) and waveform modification (i.e div by 1 , combinational, etc). To see details of a specific clk, just provide the name of the clock. If no clk name provided, all clks shown
    • ex: report_clock -nosplit => Most used cmd when all clk creation is done. This dumps all clk info for all clks in design. -nosplit prevents line splitting so that it's easier to read and parse the file by scripts.
    • ex: report_clock [get_clocks clk1] => provides details of clk1 (i.e it's master_clk, src_pin, period, etc)
    • ex: report_clock -skew [get_clocks clk1] => Using option "-skew" reports clk uncertainty for given clk for all edges of clk. So, if we used 24 clk uncertainty cmds as shown below, we'll see all those values here (including any other clk to which we defined interclk uncertainty wrt this clk). This cmd also reports src clk latency for given clk under both setup and hold condition (for early and late arrivals).
  • get_clocks => Just like other get_* comds, it returns collection of clk objects that can be used within the tool for further processing.
  • get_clock_network_objects => returns a collection of clock network objects of certain type (i.e cells, nets, etc) that belong or relate to one or several clock domains. A clock network is a special logic part of the design that propagates the clocks from the clock sources to the clock pins of latches, flip-flops (that function as anything but propagating clocks) or black-box IPs. The propagation also stops at design output ports, dangling pins or nets, or the sources of other clocks (i.e src pin of generated clk). So, basically this cmd retrieves certain types of objects from the direct clock network (including the latches, flip-flops and black-box IPs driven by the clock network). If you specify to retrieve objects from some master clk n/w, then this stops at generated clk, as that's considered part of other clk n/w. Similarly, if you specify to retrieve objects from some generated clk n/w, then this doesn't trace back to src of that generated clk, as that's considered part of other clk n/w.
    • ex: get_clock_network_objects -type cell -include_clock_gating_network [all_clocks] => This reports all cells (buffers, inverters, combo cells, etc) on all clks in design. by default, if clk list is not specified, then all clks in design are considered (so [all_clocks] is not required strictly). option -include_clock_gating_network causes clk gating cells and it's fanout to be included in clk n/w. Otherwise, clk gating cell is a latch, and is considered endpoint for determining clk n/w.

 




set clock uncertainty => For clk uncertainty details, see the "clock tree" section. We can specify clk uncertainty (amount of variation in arrival times of successive clock edges, in library time units) b/w edges of same clk, or b/w edges of 2 diff clks. Usually it's set for edges of same clk, both for setup and hold. During synthesis, clk uncertainty is used to model skew which is going to occur during CTS in PnR. It's equiv to reducing clk period by skew amount.

syntax: set_clock_uncertainty <options> <uncertainty_number> <object_list>=> The object list is either a list of clocks, ports, or pins. For a clock object, the uncertainty applies to capturing latches clocked by that clock. For a port or pin, the uncertainty applies to capturing latches whose clock pins are in the fanout of that port or pin. It's preferred to use get_clocks, get_ports or get_pins for object_list, but we can use the patterns directly too. Clock uncertainty number is usually +ve (-ve numbers not encouraged). 

options:

-setup/-hold => By default uncertainty applies to both setup and hold checks, unless we specifically say -setup or -hold only.

-from/rise_from/fall_from <src_clock>, -to/-rise_to/-fall_to <dest_clock> => Specifies the source and destination clock for clk uncertainty for specified edges of clock. For 1 clock, src and dest cclk are same, while for 2 clks, src and dest clks are diferent. We need these options for a single clk, when we specify uncertainty for half cycle paths. We can use these options for full cycle paths too.

We can specify interclock uncertainty or simple uncertainty. These are mutually exclusive. For same clk, we can't use both options below.

  • for simple uncertainty: Here we specify uncertainty to edges of same clk. These are all possible combo of simple uncertainty for a given clk (6 uncertainty values provided as shown below):
    • SETUP clk uncertainty:
      • clk1 -> clk1 Full cycle setup uncertainty (R->R, F->F) => Here clk jitter, but no clk dcd.  
        • ex: set_clock_uncertainty -setup 0.8 clk1 (this takes care of all cases, R->R, F->F, R->F, F->R. However, R->F and F->R are overwritten by next 2 cmds). We could also write 2 separate cmds for r->R and F->F as we did in inter clock uncertainty.
      • clk1 -> clk1 Half cycle setup uncertainty (R->F, F->R)         => Here both clk jitter and clk dcd (since it's half cycle).
        • ex: set_clock_uncertainty -setup 1.2 -rise_from clk1 -fall_to clk1
        • ex: set_clock_uncertainty -setup 1.2 -fall_from clk1 -rise_to clk1
    • HOLD clk uncertainty:
      • clk1 -> clk1 Full cycle hold uncertainty (R->R, F->F) => Here no clk jitter, and no clk dcd as it's a 0 cycle path. However, a small hold value is provided as margin. 
        • ex: set_clock_uncertainty -hold 0.05 clk1 (this takes care of all cases, R->R, F->F, R->F, F->R. However, R->F and F->R are overwritten by next 2 cmds)
      • clk1 -> clk1 Half cycle hold uncertainty (R->F)         => Here both clk jitter and clk dcd (since it's half cycle). Hold half cycle jitter and dcd very similar to setup half cycle jitter and dcd values since paths are the same.
        • ex: set_clock_uncertainty -hold 1.21 -rise_from clk1 -fall_to clk1
        • ex: set_clock_uncertainty -hold 1.21 -fall_from clk1 -rise_to clk1
  • for interclock uncertainty: This is used to specify uncertainty b/w edges of different clks which are async to each other. Most of the times paths b/w 2 unrelated clks are declared as false paths. However, if we really want to time such paths, we can use this cmd to set uncertainty b/w the 2 clks. The worst uncertainty of the 2 clks is assigned to interclock uncertainty (as that's the worst deviation of clk edge. Adding the uncertainty from the 2 clocks is not right, as one of the edges is going to be fixed). Interclock uncertainty is direction specific. So, to apply clk uncertainty from other direction, we have to specify clk uncertainty cmd in other direction too. These are all possible combo of simple uncertainty for a given clk (8 uncertainty values provided as shown below for clk1->clk2). Similarly we've 8 such uncertainty values for clk2->clk1 (they usually are same values as clk paths remain the same).
    • SETUP clk uncertainty from clk1 to clk2:
      • clk1 -> clk2 Full cycle setup uncertainty (R->R, F->F) => Here clk jitter, but no clk dcd as it's assumed that rise (fall) from one clk to rise (fall) of other clk is a full cycle path. That may not be true if clk is inverted or some othe rleationship exists, that makes rise to rise (or fall to fall) half cycle path. 
        • ex: set_clock_uncertainty -setup 0.8 -rise_from clk1 -rise_to clk2
        • ex: set_clock_uncertainty -setup 0.8 -fall_from clk1 -fall_to clk2
      • clk1 -> clk2 Half cycle setup uncertainty (R->F, F->R) => Here both clk jitter and clk dcd (since it's half cycle). again it's assumed that R->F or F->R implies half cycle path (may not be true)
        • ex: set_clock_uncertainty -setup 1.2 -rise_from clk1 -fall_to clk2
        • ex: set_clock_uncertainty -setup 1.2 -fall_from clk1 -rise_to clk2
    • HOLD clk uncertainty from clk1 to clk2:
      • clk1 -> clk2 Full cycle hold uncertainty (R->R, F->F) => Here no clk jitter, and no clk dcd as it's assumed to be a 0 cycle path. However, a small hold value is provided as margin. 
        • ex: set_clock_uncertainty -hold 0.05 -rise_from clk1 -rise_to clk2
        • ex: set_clock_uncertainty -hold 0.05 -fall_from clk1 -fall_to clk2
      • clk1 -> clk2 Half cycle hold uncertainty (R->F, F->R) => Here both clk jitter and clk dcd (since it's half cycle). Hold half cycle jitter and dcd very similar to setup half cycle jitter and dcd values since paths are the same.
        • ex: set_clock_uncertainty -hold 1.21 -rise_from clk1 -fall_to clk1
        • ex: set_clock_uncertainty -hold 1.21 -fall_from clk1 -rise_to clk1

 

So, in above ex we see that we need 8 uncertainty values for simple uncertainty and 16 uncertainty values for interclock uncertainty (8 for clk1->clk2 nd 8 for clk2->clk1).

ex: set_clock_uncertainty 1.0  [get_clocks clkosc] => sets uncertainty of 1ns to clkosc successive rise or fall edges. uncertainty is same for setup runs and hold runs

ex: set_clock_uncertainty -setup 0.8 -hold 0.2  clkosc => here uncertainty is set differently for setup (0.8ns) and hold (0.2ns). Usually hold clk uncertainty is much lower as it's launch/capture on same edge.

ex: set_clock_uncertainty  -setup 1.3 -fall_from s_clk -fall_to d_clk => setup uncertainty is 1.3 from falling edge of s_clk to falling edge of d_clk. Most of the times, we also want to have same clk uncertainty in other direction too. So, we have to specify "set_clock_uncertainty  -setup 1.3 -fall_from d_clk -fall_to s_clk" too.

report_clock_uncertainty => There's no such cmd. To see clk uncertainty, we have to use report_clock with -skew option. See in report_clock section below.

remove_clock_uncertainty => removes clk uncertainty set by set_clk_uncertainty cmd. We use same syntax as above. Note that interclock uncertainty can be removed by providing -from/-to, while simple uncertainty can be removed just by providing <object-list>. We can't remove clk uncertainty by providing different syntax cmd that the one that was used to set clk uncertainty.

ex: remove_clock_uncertainty [all_clocks] => This removes simple uncertainty for all clocks

ex: remove_clock_uncertainty -from s_clk -to d_clk => This removes inter clk uncertainty that was set above. We don't have to use "-fall_from s_clk -fall_to d_clk" as this remove uncertainty cmd is a superset and removes uncertainty for all edges rise->rise and fall->fall. If we had uncertainty b/w rise->fall or fall->rise, then we would have to use the more targeted cmd: remove_clock_uncertainty -rise_from s_clk -fall_to d_clk

 



set_clock_transition -min -rise 0.4 [get_clocks SCLK] => specifies slew rate for ideal clocks (slew rates for gen clocks are calculated by tool). Here, it's 0.4ns rise time slew at min(fast) process corner.

 



set_clock_latency 0.4 -source -rise [get_clocks  SYSCLK] => rise latency of 0.4 for SYSCLK. This latency is used to model off-chip clk latency. clk network latency is internal to design and is still propagated as it should.

 




set_propagated_clock [all_clocks] => Specifies that delays be propagated through the clock network to determine latency at register clock pins.  If not specified, ideal  clocking is  assumed.   Ideal  clocking  means  clock  networks have a specified latency (from  the  set_clock_latency  command),  or  zero  latency  by default.

 




set_clock_groups (added in sdc 1.7): all create/gen clk cmd above creat sync clocks, so all paths analyzed b/w different clocks. To specify different behaviour of clk, use set_clock_groups.

Clks can be sync or async in terms of timing relationship. They can also be exclusive in terms of their functionality (i.e only 1 clk or set of clocks can be active at a time. An ex might be a mux on clk path that selects 1 of 2 clocks to propagate, in this case the 2 clks are exclusive). Timing paths are analyzed only b/w sync clocks. Paths b/w clocks which are declared async or exclusive are considered as equiv to declaring false paths b/w these clocks. So, no timing paths analyzed b/w these clks. Within exclusive, we have 2 varieties: logically exclusive and physically exclusive. Logically exclusive is when clocks are logically exclusive, but physically they can still fire at same time. An ex would be when there is a mux choosing b/w 2 clocks, so only 1 clk is acive downstream. However, these 2 clks are active at same time upstream of mux. Physically exclusive is when these  clocks can never physically interact with each other. In above ex, if mux is placed right at i/p port of chip, then these 2 clocks will have no interaction b/w each other. Thus physically exclusive is more restrictive than logically exclusive.The only diff b/w these 3 kind of paths is in how they are handled during crosstalk analysis (noise runs), otherwise for regular timing runs, they are all treated the same (i.e treated as false paths). For crosstalk analysis b/w clocks, depending on whether clocks are sync, async, logically exclusive or physically exclusive, we do diff thing:

  • sync: For sync clocks, clocks have finite timing window based on when they arrive, so they can couple with each other or other signals within that timing window. This is the default behaviour for all clocks. Timing paths are analyzed for all paths b/w sync clocks.
  • async: For async clocks, clocks are assumed to have infinite window relationship, so they can couple with each other at any time. Timing paths are not analyzed b/w async clocks, but they are still analyzed for everything else, so these coupling are considered.
  • logically exclusive: For logically exclusive clks, there might be coupling b/w clock, so crosstalk computation is done normally (i.e for sync, we have finite window while for async, we have infinite window)
  • physically exclusive: For physically exclusive clks, there is no coupling b/w clocks, so only one of these clks can be an aggressor or victim for noise purpose.

Usually we can just declare false paths b/w clks which are async or exclusive. This will work OK as long as we don't run any noise runs (i.e noise impact on timing, or noise bumps). For noise runs, we do need to have these, as "set_false_path" doesn't say anything about relationship b/w clocks, so all clks will be considered sync, resulting in optimistic timing runs (as sync clks can have finite timing window, while in reality, async clk can fire at any time, and hence cause worst case coupling at the right time).


ex: set_clock_groups -asynchronous -group {reg_clk} -group {spi_clk} => reg_clk and spi_clk are async, so don't analyze any path b/w these. equiv to declaring false paths b/w these.

ex: set_clock_groups -logically_exclusive -group {clk1 clk3} -group {clk2 clk4} => Here, clk1/Clk2 are 2 i/p to same mux, and Clk3/Clk4 are 2 i/p to other mux. If they share same select signal, then we can use this style to say that the 2 groups are exclusive to each other (don't interact with each other as they might be muxed so only one of them is ON), so don't analyze any path b/w these (paths that start in one group and end in other group, i.e fp b/w clk1 and clk2/clk4 and fp b/w clk3 and clk2/clk4), equiv to declaring false paths b/w these. However, no relationship is specified b/w clk1 and clk3, or clk2 and clk4.

#set_clock_groups -physically_exclusive -group [get_clocks {clk1 clk22*}] -name grp1 => when we specify only 1 clk group, that implies this group (clk1, clk22*) is async to all other clocks in design. Here, a separate default "other" group is created for  this single group. However, no relationship is specifed b/w clk1 and clk22*, so these clks are sync to each other unless specified via a separate "set_clock_groups" cmd.

remove_clock_group => This is used to remove clk grp set by the above cmd. You must specify either the -exclusive (or -logically_exclusive or -physically_exclusive too depending on how clk grp was set) or -asynchronous option. You must specify either the name_list or -all option. -all removes all clk grps while providing a name removes only that clk grp.

  • remove_clock_group -exclusive -name grp1 => removes exclusive clk grp named grp1
  • remove_clock_group -asynchronous -all => removes all asynchronous clock groups from the current design

 

set_clock_exclusivity => This is another way to set different clks exclusive to each other. As we saw in the example of mux above, all clks coming into a mux will be mutually exclusive to each other, provided the mux select lines are not dynamically changing. This cmd makes all clks mutually exclusive to each other that traverse from i/p to o/p of the cell. We specify the cell, it's o/p pin and i/p pins whose clks we want to be exclusive. All clocks at the
specified inputs are considered mutually exclusive clocks beyond the output.

syntax: set_clock_exclusivity -output <output_pin> [-type mux | user_defined] [-inputs <input_pin_list>] => If the cell is a Mux, we can use -type as mux, and then we don't need to define i/p pins. But for other non-mux cells as and gate etc, we need to use -type "user_defined" and specify all i/p pins.

ex: set_clock_exclusivity -type mux -output MUX25/Z => mux25 cell is defined as point of exclusivity

ex: set_clock_exclusivity -type user_defined -output AND3/Z -inputs {AND37/A AND37/B} => Here AND3 cell is defined as point of exclusivity. Since it's not mux type, we had to specify input pins explicitly.

remove_clock_exclusivity =>To remove exclusivity set above

report_clock -exclusivity => reports exclusivity defined in the design

 

 



set_clock_gating_check => Whenever a clk encounters any logic on it's path, other than a buf/inv, the other leg of that logic has the poyential to cause glitches on the clk that is coming out of this logic. To prevent such glitches from happening on the o/p clk of logic, we have a clk gating check. As an ex, if we have an AND gate, and 1 signal is is clock, while other leg of the AND gate is some "data" signal from a flop, then we have to make sure that the output of this and gate is free of glitches. AND/OR gate may not provide glitch free clock output. It depends on the clk gating "data" signal timing. That is why latch based clk gaters were introduced which guarantee glitch free clk o/p.

CG CHECK: STA tools perform clk gating check only on simple gates as AND/NAND, OR/NOR. For any complex gate as XOR, MUX, etc, PT doesn't perform clk gating check and issues a PTE-060 warning. That's OK as most of the times presence of MUX implies that 2 clks are coming in and only 1 will be active at a time and select signal is quasi static (i. Select signal fires only once in a while, and that also when the clk is inactive). However, if you have design, where select signal of MUX is actively switching while clk is active, then you need to design more complex logic to go with the mux that can achieve that. That's totally separate topic that we'll touch on "glitchless clock mux design". For our case, STA tools as PT only CG checks on simple gates. If we have case analysis or constant values on complex gates such that the complex gates can be reduced to simple gate, then PT will infer CG, and do the CG check. So, when PT is doing CG check on complex gate, it's a red flag that something in the mu is tied off or has a set case analysis. You may want to trace that, and make sure that is what you want.

Solvnet article on MUX CG: https://solvnetplus.synopsys.com/s/article/Clock-Gating-Checks-on-Multiplexers-1576002513927

Nice artice on CG check: https://solvnetplus.synopsys.com/s/article/How-Are-Clock-Gating-Checks-Inferred-1576020186140

By default, latch based clk gaters have setup/hold checks in their .lib. However, other logic gates as AND/NAND, OR/NOR, MUX, OR-AND on clock path do not have any setup/hold checks specified in .lib (even though you may have special clock gates as CKAND2, their timing might be just in->out timing). Gating check is required on any pin gating a clock signal. This cmd specifies a setup and hold time check on those pins gating clk (by default, setup and hold time check are 0). -high and -low options help PT in situations where it can't determine whether enable pin needs to set to "high clk" or "low clk". This happens for complex cells as MUX, OR_AND, AOI. For AND/NAND, check is performed against high clk, while for OR/NOR, check is against low clock.

Below cmd forces tool to perform clk gating check on cells where by default tool doesn't do CG check, or to put specific setup/hold values to be applied for CG check.

syntax: set_clock_gating_check <options> <object_list>

options: -setup/-hold, -rise/-fall, -low/-high

object list to be specified here is optional. If nothing specified, clk gating check is applied to all of design. Objects specified can be cell, pins or clocks. If cell specified, then all i/p pins of that cell are affected, while if particular pin specified, then clk gating check applied only to that pin. If clock specified, then clk gating check applied to all gates gating that clk. clk is most commonly used, since it's simpler to cover all gaters in the path.

ex: set_clock_gating_check -setup 0.2 -hold 0.4 [get_clocks CK1] => specifies a setup time of 0.2 and a hold time of 0.4 for all gates in the clock network of clock CK1.

ex: set_clock_gating_check -setup 0.5 -hold 0.2 [get_cells and1] => specifies a setup time of 0.5 and hold of 0.2 on the and1 cell

remove_clock_gating_check => removes clk gating check set using above cmd. Use same options as what was used in "set_clock_gating_check" cmd.

report_clock_gating_check => reports all clk gating checks done by PT on cells. user specified high/low options for clk gating checks shown by *, while PT inferred ones show no *

set_disable_clock_gating_check => Disables the clock gating check for specified cells/lib_cells and pins in the current design. This command will only disable auto-inferred clock gating checks. Clock gating checks from library will not be disabled.

ex: set_disable_clock_gating_check [get_lib_cells {"class/AND1"}] => It disables clk gating check on this AND1 lib cell. When the checking through a cell is disabled, all gating checks in the cell are disabled.
ex: set_disable_clock_gating_check mod1/AND2/A => It disables clk gating check on A pin of this clk gating instantiated cell. When the checking through a pin is disabled, any gating check is disabled if it uses the disabled pin as a gating clock pin or a gating enable pin.

Most of the cells have just one clk gating check, where there's a clk pin and an en pin. So, specifying the cell works for most of the cases.

 



set_clock_sense / set_sense => set_clock_sense has been deprecated and replaced by set_sense. Generally, we have simple gaters on clk paths, and PT is able to propagate clk thru these gates on clk paths. For AND/NAND, OR/NOR, it's able to figure out the clk dirn at o/p of gate (known as unateness => +ve unate means if clk rises, o/p of gate rises, and if clk falls, o/p of gate falls, while -v unate means the opposite).  This cmd is  generally used on more complex gaters where tool cannot figure out the unateness of clk at that pin. If we know what the unateness of clk is ging to be at that pin (based on functionality), we can specify it via this cmd.  It restricts unateness at pin (to positive or negative unate) with respect to clock source. However, the specified unateness only applies within the non-unate clock network (If PT can figure out unateness by itself, it will issue a warning).

This cmd is also used to stop clks from propapagting forward. This is useful in cases where we have defined multiple clks on the same net, but we don't want one or more of these clks to propagate to some part of design.

syntax: set_sense -type <clock|data> -clocks <clock_list> <more_options> <object_list>

options:

  • -positive/-negative => applies +ve/-ve unateness to all pins in object list wrt clk src.
  • -clocks => by default, all clocks passing through the given pin objects are considered for unateness. However, we can restrict it to a given set of clocks by specifying it via -clocks.
  • -stop_propagation => Stops the propagation of specified clocks in the clock_list (via -clocks) from the specified pins or cell timing arcs in the object_list. This option is not used with -positive/-negative, as we aren't specifying any unateness here, but instead stopping clk propagation all together.
  • object list can be pins, ports, or cell timing arcs.

ex: set_sense -positive -clocks [get_clocks CLK1] XOR/Z => specifies a positive unateness for the XOR/Z pin with respect to the CLK1 clock. If -clocks is omitted, then +ve unateness is applied on XOR/Z pin for all clocks.

ex: set_sense -stop_propagation -clocks [get_clocks {my_clk your_clk}] [get_pins  {chip/mod/reg1/Q ... }] => this stops propagation of my_clk and your_clk on pin Q. Instead of {my_clk your_clk} we may also provide it as a list => [list my_clk your_clk]

ex: set_sense -stop_propagation [get_pins $mod/gateer1/CLK_OUT] => This stops propagation of all clocks from CLK_OUT pin onwards. CLK_OUT pin still has clk attribute set to true, but CLK_IN pin on this clk gater wiil have clk attribute set to false.

remove_sense => This cmd undoes the effect of set_sense. Syntax here is little different than set_sense as we only specify clocks and pin that were used when using set_sense. Otherwise the cmd needs to have the same options and pin names as what was used in set_sense.

syntax: remove_sense -type <clock|data> -clocks <clock_list> <object_list> => -type specifies sense is to be removed from clock (default) or data network. -clcoks is used only if -clocks was used with set_sense cmd. <object_list> should be the same as what was used with set_sense cmd.

Other option "-all" is used to remove all the unateness/clk_prop info from clk network network. If we specify -type data along with -all, then it removes unateness info from data network too.

ex:

set_sense -positive -clocks [get_clocks CLK1] XOR/Z
remove_sense -clocks [get_clocks CLK1] XOR/Z => Here we didn't use -positive option as that's not in the syntax of remove_sense cmd.

 


 

PT Clk Propagartion Errors (PTE-075):

NOTE: There are 2 cmds that are used to kill clks from propagating in PT. One is the "set_case_analysis" cmd which forces a constant 0 or 1 value on the pin, and the other is "set sense -stop_propagation" cmd. PT errors as PTE-025 or PTE-075, where the  tool is not able to trace a generated clk back to it's master clk are usually due to one of these cmds in sdc file (assuming netlist by itself is structurally correct, i.e there is correct clk net connection). One of the best ways to debug such PT errors is to use "all_fanout" or "all_fanin" cmd (see in PT cmds section for details). Use "-from master_clk_pin" and "-to generated_clk_pin" in this cmd, and check if it reports any path between these 2 points. Then keep on doing it, until you come to a point, where it doesn't show any path. However, when the issue is due to "set_sense" cmd, then all_fanout/all_fanin will still show the path as correct, but on reporting clk attribute, we will see no such attribute on the gates in the clk tree path.

Procedure to debug PTE-075 Error (Error: Generated clock 'my_gen_clk' has no path to its master clock. (PTE-075)). Bring up PT_SHELL by running Primetime and run below cmds:

  1. Report generated clk to make sure it's reported as expected. This is a sanity check to make sure our gen_clk definition is correct.
    • pt_shell> report_clock my_gen_clk => This will show master_clk (my_clk), as well as generated src (as top/.../INVX1/Z). If not, then debug why by looking at your clk defn.
  2. Now report fanin or fanout from gen_src to/from master src. We can just use one of the 2 cmds below. It will either show "no path found" or will show all the cells in the path if the path exists.
    • pt_shell> all_fanin -to top/.../INVX1/Z -from CLK_PORT -flat => This reports all the cells in the path starting from gen_clk src all the way backward to master_src
    • pt_shell> all_fanout -to top/.../INVX1/Z -from CLK_PORT -flat => This reports all the cells in the path starting from master_clk and going forward all the way to gen_clk src.
  3. If the all_fanin/all_fanout cmd in bullet 2 above shows valid path, then the issue is probably due to clk cells not having clk attribute on them. Not having "clk" attribute on relevant pins of all the cells in the clk path, breaks the clk path and causes "PTE-075" error, even though the path exists both logically and physically. This issue commonly happens due to "set sense -stop_propagation" cmd being used on some of the cells in the sdc constraints file written by the user. Debug it using "get_att" cmd recursively from the gen_clk src all the way to the master_clk src.
    • pt_shell> get_att [get_pins top/.../INVX1/Z] clocks => This cmd is run on o/p pin of the gate, where gen_clk is defined. It should show both gen_clk and master_clk {my_clk my_gen_clk}
    • pt_shell> get_att [get_pins top/.../INVX1/I] clocks => Now we keep moving backward from gen_clk to master_clk. We move to i/p pin of buffer where we defined gen_clk (gen_clk is defined on o/p pin). This should show only master_clk {my_clk}. Every gate pin going all the way to the master_clk pin should show master_clk. We stop when "get_att" cmd shows this msg => "Warning: Attribute 'clocks' does not exist on pin 'top/.../INVX1/Z' (ATTR-3)". That is where clk is being stopped from getting propgagted due to "set_sense" cmd. Remove that cmd from constraints to fix this.
  4. If the all_fanin/all_fanout cmd above in bullet 2 doesn't show any path, then we need to rerun all_fanin/all_fanout cmds with option "-trace_arcs all". If that shows the path, then there's a set_case_analysis or tie off somewhere that will need to be debugged by using other options "-trace_arcs".
  5. Once we've narrowed the issue in bullet 3 or 4 above, we can fix it in PT_SHELL itself by runing "remove_sense" (bullet 3) or "set_case_analysis" (bullet 4). Then we rerun "check_timing" cmd to get PT to update timing. On the screen, we shouldn't see any PTE-075 error anymore while "check_timing" is running.
  6. We can also run report_timing cmd to see the clk path.
    • pt_shell> report_timing -from CLK_PORT -thr top/.../INVX1/Z -exceptions all => This should show the clk path if structurally and logically the clk path exists (even though "set_sense" cmd may be blocking the clk from propagating, but seems like report_timing doesn't care about that).

 

Exception to PTE-075 Error: We sometimes don't get a PTE-075 Error, but we still see a generated clk which shows up as if it's generated using "create_clock". It doesn't trace back to it's master clock, and generated clk starts from the point where it's defined (with 0 delay).

 

 


misc clk attribute cmds:

1. get_attribute => this cmd can be used to get value of various attributes for cells, nets, and other design objects. For more details on syntax, see in PrimeTime Commands section. In this section, we will only discuss about clk attributes, which can be used to debug clk errors. 

To see list of all attr for clock object, run list_attr cmd: ex: list_attribute -application -class clock -nosplit => (details in PT cmds section). Below are few of such attr for clks which are commonly used.

A. clk period for clock object:

ex: get_attribute [get_clocks] period => get_clocks returns collection of all clocks in design, Then get_attribute which works on collection, looks at each object of collection and returns attribute "period" for each of them. get_clocks actually returns a pointer to the collection of clock object (echo [get_clocks] = _sel1245). get_attribute which expects it's arg to be a collection, gets this pointer, and grabs period from it. If we diretly provide clk name as arg, it will error out, as that is not a collection (i.e pointer). The return value is a list of periods, i.e [12, 17.4, 81, ..]. We can do any list operation on this i.e lsort, etc, or we can also pass this list thru foreach_in_collection to get each individual period (as if they were a collection)

ex: get_attribute [get_clocks clk1] period => returns valid period of clk1 as 20, as [get_clocks clk1] returns a collection of object "clk1"

ex:  get_attribute clk1 period => Warning: Nothing implicitly matched 'clk1' (SEL-003) => this happens because clk1 is not a valid collection here

B. clk source pin or master clk for clock object:

ex: get_attribute [get_clocks clk1] sources => this returns the source pin of the clk => {"mod1/clk_buffer/I_clkinv/ZN"}

ex: get_attribute [get_clocks clk1] master_clock => this returns the master clk for this generated clk which is {"clk2"} here.

C. clocks on pins: "clocks" attr returns a a collection of clock objects that propagate through the pin. It is undefined if no clocks are present. This cmd only works on pins of leaf cells. If you apply this on non-leaf cells (i.e a net, module port, etc), it will return an error "no such attr found".

ex: set clkName [get_attr [get_pins $ModName/GATE_latch_0/CLK] clocks -quiet] => here we are retreiving all clocks on CLK pin of a latch. Then this collection is put into a var named clkName. This is very imp cmd to see if all clocks are seen on CLK pin of various flops.

D. clock, is_clock_pin and is_clock_source_network attr on pins: (Looks like clock attr is not valid anymore, "clocks" (plural of clock with a s) attr above gives all valid clocks on that pin)

clock and is_clock_pin => The clock attribute indicates that the pin is a clock pin in the library cell definition (i.e "pin (CK) {clock: true}" in lib cell defn) whereas the is_clock_pin attribute indicates that the library or instance pin is an active and valid clock pin in the design (i.e it is reached by a clock signal and the sequential cell instance containing this pin is not disabled by disabled timing arcs or by case analysis). For tied off pin, or clock pins which are not reachable via any clk in that mode, the is_clock_pin attr will be seen as set to false.

ex: get_attr [get_pins $ModName/GATE_latch_0/Q] is_clock_ source_network => Returns true if the pin is part of a clock source latency network. This is very useful cmd to see where on clk tree does the clk not propagate. i.e if we see that this attr is false on the o/p of a clk gater, but is true on i/p CLK pin of that clk gater, that means that there is possibly "set_case_analysis" or "stop propagation" on that clk gater.