← Home Static Timing Analysis
16 Static Timing Analysis

Advanced Clocking: Generated, Divided & Gated

STA fundamentals — cell delay, interconnect, setup/hold, MCMM, OCV, noise, IR-drop and sign-off

Chapter 16 — Advanced Clocking: Generated, Divided, Multiplied

& Gated Clock Corner Cases

The worst mistake in static timing analysis (checking chip speed without running it) is a wrong clock. A wrong generated clock throws no error. The report looks clean and green. But the chip fails in real silicon. This chapter covers the tricky cases of advanced clocking. We look at how generated clocks link to their parents. We see how dividers and multipliers reshape the clock wave. We see how gating changes the clock. We see how the tool picks the worst pair of clock edges. The tone here is careful on purpose. The timer is only as honest as the clock model you give it.

Why Generated Clocks Exist At All

A primary clock (also called a master clock) is declared at a port or pin. You give it a wave from scratch: a period and edges. A generated clock is different. It is built from another clock. The source clock passes through logic. That logic can be a divider, a multiplier, an inverter, a clock gate, or a mux. The tool must know that the new wave is linked to the source. Without a generated clock, two bad things can happen. The tool may pass the master clock straight through, which is often wrong. Or it may see nothing and call the downstream registers unconstrained (not checked).

The key idea is the master-source link. Every generated clock points back to a source pin. That pin traces back to a master clock. This link sets two things. First, it sets the wave of the new clock. Second, it sets whether two clocks are related (timed against each other) or unrelated (treated as separate). A wrong source quietly breaks both.

Technical diagram

Two Ways to Define a Generated Clock

There are two very different styles. Mixing them up is a classic interview trap. Edge-based style names which edges of the master to keep. You list the source edge numbers (1, 2, 3, and so on, counting rising and falling). Only those edges survive at the output. This style models any duty cycle (the fraction of time the clock is high). It works for non-50% waves. Divide/multiply-based style names a ratio. Divide-by-N keeps every Nth edge, usually at 50% duty. Multiply-by-M packs M cycles into one master period.

AspectEdge-basedDivide/Multiply-based
What you specifyA list of source edgesA whole-number ratio
Duty cycle controlFull, any valueBuilt in (usually 50%)
Best forOdd dividers, skewed duty, phase shiftsClean /2, /4, x2
Failure modeWrong edge list = wrong waveWrong ratio = wrong period
Inversion handling-edges + -edge_shiftexplicit -invert
# standard (SDC) — primary clock, 1.25 ns period (800 MHz)
create_clock -name CLK -period 1.25 [get_ports CLK]
# standard (SDC) — divide-by-2 generated clock, ratio style
create_generated_clock -name CLK_DIV2 \
-source [get_ports CLK] -divide_by 2 \
[get_pins div_reg/Q]
# standard (SDC) — same divide-by-2, edge style
# master edges (rise=1, fall=2, rise=3, fall=4...); keep edges 1,3,5
create_generated_clock -name CLK_DIV2_E \
-source [get_ports CLK] -edges {1 3 5} \
[get_pins div_reg/Q]

Here is a subtle but key rule. The -source is the pin where the master clock arrives. It is not the master clock name. Say a register's clock pin sees CLK . You build a divider from that register's Q . Then the source is the register's clock pin, or the port that feeds it. The master is found from there. Point -source at the wrong pin and you re-link the whole chain. This is the number-one cause of "the report looks fine but the chip is dead."

Divided Clocks: Edge Alignment and Launch/Capture Bookkeeping

A divide-by-2 clock has twice the period. So setup is relaxed between two registers in the divided domain. But the interesting paths cross domains. One case launches in the master domain and captures in the divided domain. The other case goes the other way. The tool lays both waves over a common window. That window is the least common multiple (LCM) of the periods. Then, for each path, it picks the worst legal launch/capture edge pair. Take master CLK at 1.25 ns and CLK_DIV2 at 2.5 ns. Both rise together at t = 0.

Edge indexCLK rising (ns)CLK_DIV2 rising (ns)
00.00.0
11.252.5
22.55.0
33.757.5

Take a path that launches on CLK and captures on CLK_DIV2. The launch can happen at 0.0, 1.25, 2.5, and so on. The capture can happen at 0.0, 2.5, 5.0, and so on. Setup needs the capture edge to come after the launch edge. It must come after by at least the data delay. The tool picks the smallest positive launch-to-capture gap as the worst case. Launch at 1.25 and capture at 2.5 gives a 1.25 ns window. That is tighter than launch at 0.0 capturing at 2.5, which is 2.5 ns. So the crossing path is held to 1.25 ns. It is not the relaxed 2.5 ns you might guess from the slow clock.

Worked Example 1 — divide-by-2 capture-edge selection. Master CLK period 5.0 ns. CLK_DIV2 period 10.0 ns, aligned at 0. A path launches from a CLK_DIV2 register. It captures into a CLK register. Data path delay = 4.5 ns. Capture flop setup = 0.3 ns. Clocks are ideal, with no skew.

  • Launch edges (CLK_DIV2 rising): 0, 10, 20...
  • Capture edges (CLK rising): 0, 5, 10, 15...
  • For launch at 0, captures after the data arrives: 5, 10, 15...
  • Worst-case setup uses the earliest capture edge later than the launch edge. That is capture at 5.0 ns. Setup slack = (capture_edge − launch_edge) − data_delay − setup = (5.0 − 0.0) − 4.5 − 0.3 = +0.2 ns. It passes, but only just. Now see the trap. The divided clock is slow at 10 ns. But the capture clock is the fast one. So the real requirement is 5 ns. And we are 0.2 ns from failing. Suppose the tool wrongly paired launch-0 with capture-10. It would report a fat +5.2 ns slack. That would hide a near-miss. This is why correct master-source linking matters.
Technical diagram

Hold Checks Across Dividers

Hold uses the same launch edge. But it uses the capture edge one before the setup capture edge. That is often the edge that lines up with launch. Across a divider the danger is clear. Launch and capture edges line up at t = 0. They also line up at every LCM boundary. This gives a zero-cycle hold relationship. There the data must not race through on the same edge. Divided clocks often create same-edge hold checks at these points. Designers forget them. So always check the hold report at the LCM boundary, not just setup.

Multiplied Clocks: Tighter Periods

A frequency multiplier makes a clock with a shorter period. Think of a clock doubler or a PLL output (a phase-locked loop, a circuit that builds a faster clock from a slower one). Multiply-by-2 of a 5 ns master gives a 2.5 ns clock. The hazard is the opposite of division. Now both the launch-to-capture window and any cross-domain check shrink. A path that used to pass at 5 ns must now close at 2.5 ns.

# standard (SDC) — multiply-by-2 generated clock (e.g., PLL/DLL output, conceptual)
create_generated_clock -name CLK_X2 \
-source [get_pins pll/REFCLK] -multiply_by 2 \
[get_pins pll/CLKOUT]
OperationMaster periodDerived periodEffect on intra-domain setup
divide-by-25 ns10 nsrelaxed (10 ns)
divide-by-45 ns20 nsrelaxed (20 ns)
multiply-by-25 ns2.5 nstightened (2.5 ns)
multiply-by-312 ns4 nstightened (4 ns)

In practice a real PLL multiplies a slow reference up to the core clock. You usually declare the core clock as a primary clock with its true period. You let that primary declaration model the PLL. You rarely chain -multiply_by from the reference. But you must still know how multiply works. On-chip clock doublers and edge-combining circuits do need generated multiplied clocks.

Gated Clocks: How Gating Bends the Waveform

A clock gate can be a special cell, or an AND/OR with a latch-based enable. When enabled, it does not change the period. When disabled, it removes pulses. So in steady state the gated wave matches the source. The real job is timing the enable. The gate must open and close only while the clock is on its inactive level. That gives glitch-free gating (no half-pulses).

Technical diagram

The setup/hold check on the enable is the heart of it. Take an AND-based gate. The clock is activehigh, so the gate passes when EN = 1. The enable must be stable before the rising edge of the clock. That way no half-pulse is made. This is a setup check tied to the next active edge. The hold is tied to the falling edge. A negative-level latch sits ahead of the AND. This latch is what makes real gating cells glitch-free. The latch updates the enable only while the clock is low. So the enable can never change during the high phase. During the high phase a change would chop a pulse.

# illustrative — generic, not tool-specific:
# model the gated clock branch so downstream regs are still constrained
create_generated_clock -name GCLK \
-source [get_pins icg/CK] -divide_by 1 \
[get_pins icg/GCK]
# illustrative — generic, not tool-specific:
# constrain the enable to arrive on the inactive (low) phase of CLK
set_multicycle_path ... ;# only if the enable path legitimately spans phases

A -divide_by 1 generated clock is the normal way to say one thing. It says "same wave, but a derived node, so treat it as a distinct, related clock." Without it, the gated registers may go unconstrained. Or they may take the ungated clock's name. Either way it corrupts cross-domain grouping. Worked Example 2 — gated-clock enable check. Active-high clock CLK , period 3.0 ns, 50% duty. It rises at 0, falls at 1.5, rises again at 3.0. The gate is AND-based with a negative-level latch on the enable. The enable signal EN_pre arrives at the latch D. It launches from a CLK -domain flop. The latch is transparent while CLK is low, from 1.5 ns to 3.0 ns. The gate's enable setup = 0.2 ns. The enable launched at edge 0 (t = 0) must be captured by the latch. It must also be stable before the gate's controlling rising edge at t = 3.0. So the enable must arrive before (3.0 − 0.2) = 2.8 ns. Say the enable delay from the launch flop = 2.4 ns. Slack = 2.8 − 2.4 = +0.4 ns. Glitch-free gating is safe. Now say a designer routed the enable through a slower logic cone of 3.0 ns. Slack = 2.8 − 3.0 = −0.2 ns. The gate could chop a pulse. That is a true functional bug, not just a speed miss. The negative latch is what helps here. It lets the enable borrow time across the low phase. Remove the latch and use a plain AND gate. Then the enable would need to be stable a full setup before edge 0. That is much harder. This is why hand-built clock gates glitch.

Clock Muxes and Switching Sources

A clock mux picks among several sources. It may pick a fast functional clock and a slow test clock. Or two PLL outputs. Two separate generated clocks travel through the mux to the same output pin. So the tool sees two clocks on one node. The key question is simple: can both be active at once?

  • Physically exclusive: only one source is ever live. The other input is held quiet. Declare them exclusive so the tool never mixes them.
  • Logically exclusive: both could toggle. But a select signal lets only one reach the output at a time. Glitch and select-timing concerns may still apply.
  • Overlapping / non-exclusive: both really interact. This is rare for muxes. It is common for two functional clocks meeting at a CDC boundary (clock domain crossing).
# standard (SDC) — two generated clocks at a mux output, one per input
create_generated_clock -name MCLK_FAST -source [get_pins mux/I0] \
-divide_by 1 [get_pins mux/Z] -add
create_generated_clock -name MCLK_SLOW -source [get_pins mux/I1] \
-divide_by 1 [get_pins mux/Z] -add
# standard (SDC) — tell the timer they never coexist
set_clock_groups -physically_exclusive \
-group {MCLK_FAST} -group {MCLK_SLOW}

The -add flag lets two clocks live on one pin. Forget it and the second definition overwrites the first. Then you quietly lose one clock.

Clock Groups: Exclusive vs Asynchronous

set_clock_groups  tells the timer which clocks not to time against each other. The three types have

different physical meaning.

Group typeMeaningPaths between groupsTypical use
-asynchronousUnrelated; no phase linkNot timed (needs synchronizers)Independent PLLs, CDC
-physically_exclusiveCannot exist at the sameNot timedMux-selected clocks

time

-logically_exclusiveSelect logic allows oneNot timed (watchTest vs functional
at a timecrosstalk)muxing
# standard (SDC) — two asynchronous functional domains
set_clock_groups -asynchronous \
-group {CLK_CPU CLK_DIV2} \
-group {CLK_PERIPH}

The danger with set_clock_groups is overuse. Every clock you wave off as asynchronous is a set of paths the timer stops checking. Suppose two clocks are really related. A divided clock and its master are always related. Call them asynchronous and you hide real setup/hold checks. So a divided clock and its master must never be grouped asynchronous. They share edges and must be timed. Keep asynchronous grouping for truly independent oscillators with real synchronizers. For mux structures with one live source, prefer physically_exclusive .

Inactive / Disabled Arcs and Domain Grouping

When you assert exclusivity, the tool disables timing arcs through the unselected mux input. Those arcs go "inactive." You should check this in your analysis. An arc that should be live but got disabled by

a too-broad clock group is a silent coverage hole. The reverse also works. A constant on a select line, via case analysis, can disable one mux input for sure.

# standard (SDC) — force the mux select so only the functional clock is analyzed
set_case_analysis 0 [get_pins mux/SEL]

Case analysis is the precise option instead of clock groups. Use it when you really want to analyze one mode, like functional mode, and remove the other source.

Selecting the Worst Launch/Capture Edge Pair

You may have many related clocks with different periods and phases. The tool builds the combined wave over the LCM window. It checks every legal launch/capture edge pair. It keeps the most pessimistic one per path.

  • Setup: take the smallest positive (capture − launch) gap over all positive pairs.
  • Hold: take the most risky pair. That is the capture edge just before the setup capture, often the same-edge (zero) case. Phase shifts move edges inside the LCM grid. They come from -edge_shift or a non-aligned create_clock -waveform . They can create surprisingly tight pairs. Always read the path report's clock edge times at the top. If launch and capture edge times are not what the waves predict, your generated clock is wrong. Full stop. # standard (SDC) — phase-shifted master to model a 90-degree clock create_clock -name CLK_Q -period 4.0 -waveform {1.0 3.0} [get_ports CLK_Q]

Interview Q&A

Q
Why does a wrong generated clock not produce an error? STA is model-driven. It times

whatever wave you declare. A wrong -source or wrong -divide_by gives a self-consistent but false wave. So every check still finishes cleanly. The error shows up only as a silicon failure or in a separate cross-check. This is why generated clocks need manual review against the netlist.

Q
A divide-by-2 register feeds a master-clock register. Is the path relaxed to the slow clock?

No. The capture clock sets the limit. If capture is the fast master, the real window is the master period or tighter. It is not the divided period. The tool pairs the worst launch/capture edges. The smallest positive gap wins. That is often the fast clock's period.

Q
What makes real clock-gating cells glitch-free, and how does that change the enable

check? A negative-level latch ahead of the AND lets the enable change only while the clock is low. So the gate never chops a pulse during the high phase. The enable can borrow time across the low phase. That relaxes its setup need. A plain AND without the latch needs the enable stable a full setup before the active edge. That is much harder and prone to glitches.

Q
When do you use physically_exclusive versus asynchronous groups? Use

physically_exclusive for clocks that cannot coexist on hardware. That is usually mux-selected sources with one live input. Use asynchronous for independent domains that both run but share no phase link and cross only through synchronizers. Use asynchronous where you meant exclusive and you wrongly ignore crosstalk. Use exclusive where domains are truly independent and you mask CDC issues.

Q
Why is the -add option important on a clock mux output? Two source clocks must both live

on the one mux output pin. Without -add , the second create_generated_clock overwrites the first. That leaves only one clock defined. It quietly drops all paths run by the other. That is a serious coverage hole.

Q
Where do divided clocks create hold violations that designers forget? At the LCM and

alignment points, such as t = 0. There the master and divided edges line up. That makes a same-edge (zero-cycle) hold relationship. Data that races through on that shared edge can violate hold. Always check the hold report at the alignment points, not just the relaxed setup numbers.

Key Takeaways

  • A generated clock is anchored by its master-source link. The -source is the pin where the parent clock arrives. Getting it wrong quietly corrupts both the wave and the clock relationship.
  • Use edge-based definitions for odd dividers and any duty cycle. Use divide/multiply-based for clean whole-number ratios.
  • For cross-domain paths, the capture clock sets the limit. Divided clocks do not auto-relax crossing paths. The tool always picks the worst legal edge pair over the LCM window.
  • Multiplied clocks tighten every window. Treat them as carefully as the fastest primary clock.
  • Glitch-free gating needs a negative-level latch. It keeps enable changes in the inactive phase. The enable's setup check is a functional need, not just speed.
  • Use -add to host many clocks on a mux output. Choose physically_exclusive , logically_exclusive , or asynchronous groups on purpose. Never group a divided clock asynchronous with its own master.
  • Check clock edge times at the top of every critical path report. If they do not match your intended wave, fix the clock before you trust a single slack number.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

Replying to