Clock Groups & Relationships
Why Clock Relationships Matter
A modern chip has many clocks. Some tick together. Some drift apart. Some never run at the same time. The timing tool must know how each pair of clocks relates, or it will check the wrong things. By default the tool treats all clocks as related. It assumes any two clocks can interact and times every path that crosses between them. This is the safe default, but it is often wrong, and it creates checks that make no physical sense. When two clocks have no fixed timing relationship, checking paths between them is meaningless. The result is a long list of impossible violations. You must tell the tool how the clocks really relate so it checks only the paths that matter.

Clock relationships fall into three kinds: synchronous, asynchronous, and exclusive. Each kind tells the tool a different thing about whether and how to check crossings between the clocks.
Synchronous Clocks
Two clocks are synchronous when they share a fixed, known timing relationship. They usually come from the same source, so their edges line up in a repeating pattern. A master clock and its divide-by-2 generated clock are synchronous. For synchronous clocks, crossing paths are real and must be checked. The tool can compute exactly when one clock launches and another captures, because the edges are aligned. The slack on those crossings is meaningful. You usually do not need a special command for synchronous clocks. The default related behavior is correct for them. If the clocks share a source and have aligned edges, the tool times the crossings properly on its own.
# worked example — synchronous crossing (related clocks)
Master clk_a period: 2.0 ns
Generated clk_b (div-by-2): 4.0 ns
Both share the same source, so edges align every 4.0 ns.
The tool finds a common period and checks the crossing path
against a real, repeating edge relationship.
The lesson: synchronous clocks need real crossing checks, and the default usually handles them. Trouble starts when clocks are not synchronous but the tool still treats them as if they were.
Asynchronous Clocks
Two clocks are asynchronous when they have no fixed timing relationship. They come from different sources and their edges drift relative to each other. A chip's main clock and a separate interface clock are often asynchronous. Checking paths between asynchronous clocks is meaningless. Since the edges drift, there is no stable required time. The tool, left in its default related mode, invents an arbitrary worst-case edge alignment and reports failures that cannot be fixed. You handle this with set_clock_groups -asynchronous . This tells the tool the listed clocks have no relationship, so it stops checking paths between them. The crossings are instead handled by special synchronizer circuits in the hardware, not by static timing.
# standard SDC — portable across compliant tools
# Two clocks with no timing relationship: stop cross-checks
create_clock -name core_clk -period 2.5 [get_ports clk_core]
create_clock -name io_clk -period 3.7 [get_ports clk_io]
set_clock_groups -asynchronous \
-group {core_clk} \
-group {io_clk}
This says core_clk and io_clk are asynchronous. The tool will time paths within each clock but will not time paths that cross between them. That removes a flood of meaningless violations and lets you focus on real ones.
| Relationship | Edges align? | Check crossings? | Typical SDC |
|---|---|---|---|
| Synchronous | Yes, fixed | Yes | Default related behavior |
| Asynchronous | No, drifting | No | set_clock_groups -asynchronous |
| Exclusive | Never co-exist | No | set_clock_groups -exclusive |
Exclusive Clocks
Two clocks are exclusive when they never run at the same time. Only one is active at any moment. The classic case is a multiplexed clock (a clock chosen by a mux from two or more sources). Imagine a mux that selects either a fast 1.6 ns clock or a slow 6.4 ns clock onto one wire. Both clocks may be defined on that wire, but only one drives it at a time. Checking a path between them is impossible, because they are never both present. You handle this with set_clock_groups -logically_exclusive (or -physically_exclusive , depending on the situation). This tells the tool the clocks cannot coexist, so it should not check crossings between them.
# standard SDC — portable across compliant tools
# Two clocks muxed onto one wire: they never coexist
create_clock -name fast_clk -period 1.6 [get_pins mux/in0]
create_clock -name slow_clk -period 6.4 [get_pins mux/in1]
set_clock_groups -logically_exclusive \
-group {fast_clk} \
-group {slow_clk}
Without this, the tool would time paths as if both clocks were live together, mixing a 1.6 ns and a 6.4 ns clock on the same logic. That produces nonsense checks. Marking them exclusive keeps each clock's own paths checked correctly while skipping the impossible crossings.

The set_clock_groups command is how you fix the default's over-eager checking. You list clocks in groups. Clocks in different groups are treated as having no relationship of the chosen kind. Clocks inside one group stay related to each other. The three modes serve three needs. -asynchronous is for clocks that drift independently. - logically_exclusive and -physically_exclusive are for clocks that never coexist, like muxed clocks. Pick the mode that matches the real hardware. A common mistake is grouping too broadly. If you make two clocks asynchronous when they are actually synchronous, you skip real crossing checks and hide true failures. Only declare a relationship that is genuinely true in the hardware. Another mistake is forgetting to group at all. Leaving truly unrelated clocks in the default related mode buries you in impossible violations. You then waste time chasing failures that no amount of design change can fix.
| Mode | Use when | Effect |
|---|---|---|
| -asynchronous | Clocks drift independently | No cross-checks between |
groups
-logically_exclusive Clocks muxed, never coexist No cross-checks between
| -physically_exclusive | Clocks cannot be physically active | No cross-checks between |
|---|---|---|
| together | groups |
# worked example — why grouping cleans up reports
Before grouping (default related):
core_clk vs io_clk crossings: 412 reported violations (all impossible)
After set_clock_groups -asynchronous:
core_clk vs io_clk crossings: 0 checked
Real intra-clock violations now visible: 3
Grouping turned 412 false violations into a clean view of 3 real ones. That is the value: the tool stops checking impossible crossings, and the genuine problems finally stand out.
Interview Q&A
every path that crosses between any two clocks. This is the safe default, but it is often wrong. For unrelated clocks it produces a flood of impossible violations.
from the same source, so their edges align in a repeating pattern. A 2.0 ns master and its 4.0 ns divide-by-2 clock are synchronous. Crossing paths between them are real and the default handles them.
relationship; their edges drift because they come from different sources. You use set_clock_groups - asynchronous so the tool stops checking paths between them. Those crossings are handled by synchronizer circuits, not by static timing.
wire where only one is active. You mark them with set_clock_groups -logically_exclusive or - physically_exclusive so the tool does not check crossings that can never physically occur.
checks. In one example, making two clocks asynchronous turned 412 false violations into zero crossing checks, leaving just 3 real intra-clock violations visible. Grouping lets genuine problems stand out.
exclusive when they are actually synchronous, you skip real crossing checks and hide true failures. Only declare a relationship that genuinely matches the hardware, or you trade visible noise for invisible bugs.
Key Takeaways
- By default the tool treats all clocks as related and checks every crossing, which is safe but often wrong.
- Synchronous clocks share aligned edges and need real crossing checks; the default usually handles them.
- Asynchronous clocks drift independently; use
set_clock_groups -asynchronousso the tool skips meaningless crossings. - Exclusive clocks never coexist, like muxed clocks; mark them logically or physically exclusive to drop impossible checks.
- Grouping turns a flood of false violations into a clean view of real ones, but never declare a relationship that is not true in hardware.
ChipBuddy
← Home
Comments
Leave a Reply