-
Notifications
You must be signed in to change notification settings - Fork 0
Clock Tree Synthesis
Clock Tree Synthesis (CTS) builds the physical network that delivers the clock from its source to every sequential element on the die. Until CTS runs, the clock is ideal — the tools pretend it arrives everywhere at the same instant. CTS replaces that fiction with real buffers, real wires, and real delay.
It runs after Placement and before Routing, and it is where a lot of optimistic pre-CTS timing goes to die.
- Low skew — the clock should arrive at related flops at nearly the same time
- Low insertion delay — shorter total latency means less variation and less jitter accumulation
- Low power — the clock network is often 20–40% of total dynamic power
- Robustness — tolerate on-chip variation (OCV) across process, voltage, and temperature
- Signal integrity — the clock is the highest-activity net on the chip and a major aggressor
flowchart LR
A[Placement<br/>ideal clocks] --> B[CTS]
B --> C[Post-CTS opt<br/>propagated clocks]
C --> D[Routing]
style B fill:#2d6a9f,color:#fff
The important change at CTS is that timing analysis switches from ideal to propagated clocks. Setup slack usually gets worse; hold violations appear in large numbers. Both are expected.
| Term | Definition | Why it matters |
|---|---|---|
| Insertion delay (latency) | Source to sink delay | Longer trees accumulate more variation |
| Skew | Arrival-time difference between two sinks | Directly eats setup and hold margin |
| Local skew | Skew between flops that actually talk to each other | The one that matters |
| Global skew | Max minus min arrival across all sinks | Easy to report, often misleading |
| Jitter | Cycle-to-cycle source variation | Comes from the PLL, not the tree; budget it in uncertainty |
| Transition | Clock edge rate at a sink | Slow edges worsen variation and setup/hold accuracy |
Setup and hold with real skew:
Setup: T_clk ≥ t_cq + t_logic + t_setup − t_skew
Hold: t_cq + t_logic ≥ t_hold + t_skew
Read those together and the tension is obvious: positive skew helps setup and hurts hold. You can't just minimize one.
That's also the insight behind useful skew — deliberately delaying a capture clock to give a slow path more time, borrowed from the next stage which has slack to spare. Modern tools (Cadence CCOpt) do this automatically as part of CTS rather than targeting zero skew.
Why insertion delay matters even when skew is fine: two paths through a long tree share fewer common buffers, so on-chip variation affects them more independently. Less shared path means more effective skew after derating. This is the common path pessimism effect, and CPPR (common path pessimism removal) credits it back during Timing Closure.
| Topology | Structure | Use when |
|---|---|---|
| Buffer tree | Balanced fanout tree of clock buffers | Default for most blocks |
| H-tree | Geometrically symmetric recursive H | Regular arrays where sinks are uniformly distributed |
| Clock mesh / grid | Buffers drive a shorted metal grid | Very low skew needed; high power cost |
| Multi-source CTS | Several drivers into a mesh or spine | Large dies, high-performance designs |
Meshes short all sinks together, so skew is very low almost by construction — but the grid switches enormous capacitance every cycle. Apple and NVIDIA use mesh or hybrid structures on high-performance clock domains and plain trees elsewhere. Pick per domain, not per chip.
Clock gating shuts off the clock to idle logic. It is the single largest clock power lever.
- Integrated clock gating (ICG) cells are inserted by synthesis and preserved through CTS
- CTS must balance through the ICG, since it sits in the clock path
- Gating high in the tree saves more power; gating low gives finer control
- Over-gating creates a deep tree with more variation
For an inference accelerator this matters a lot: Verification activity traces will show large idle fractions in the compute array during memory-bound phases, and that's free power savings.
Innovus uses CCOpt (Clock Concurrent Optimization), which builds the tree and optimizes datapath timing together rather than sequentially.
# 1. Constrain the tree
create_clock_tree_spec ;# auto-generate a starting spec
set_db cts_target_skew 0.05 ;# ns
set_db cts_target_max_transition 0.10 ;# ns
set_db cts_buffer_cells {CLKBUF_X4 CLKBUF_X8 CLKBUF_X16}
set_db cts_inverter_cells {CLKINV_X8 CLKINV_X16}
# 2. Build + optimize concurrently
ccopt_design
# 3. Switch analysis to real clocks
set_interactive_constraint_mode {propagated}
update_io_latency -adjust_source_latency
# 4. Post-CTS optimization
opt_design -post_cts ;# setup
opt_design -post_cts -hold ;# hold fixing
# 5. Reports
report_clock_trees -summary
report_skew
report_timing -path_group reg2reg
report_timing -early -path_group reg2reg ;# hold pathsWhat matters here:
-
cts_target_skew— the skew you're asking for; tighter costs buffers and power -
cts_buffer_cells— restrict to real clock buffers (balanced rise/fall), never ordinary logic buffers -
ccopt_design— builds the tree while optimizing datapath, which is why it beats classic build-then-fix CTS -
-post_cts -hold— hold fixing is a separate pass and inserts delay buffers, often thousands of them
Clock nets are usually routed with wider wires and extra spacing to cut resistance and crosstalk:
create_route_rule -name clk_rule -spacing_multiplier 2 -width_multiplier 2
set_db cts_route_type_leaf clk_rule
set_db cts_route_type_trunk clk_rule| Metric | Typical target | How to improve |
|---|---|---|
| Global skew | < 5–10% of clock period | Better sink clustering; balanced tree |
| Local skew | As low as possible on real paths | This is the one to actually optimize |
| Insertion delay | Minimize; a few hundred ps typical | Fewer levels, stronger buffers |
| Clock power | 20–40% of dynamic total | More clock gating, smaller mesh, fewer buffers |
| Max transition | Within library limit | Add buffers, widen routing |
| Clock buffer count | Design-dependent | Excess means sinks are too dispersed |
| Hold violations post-CTS | Thousands is normal | Fixed by opt_design -post_cts -hold
|
| Problem | Root cause | Fix |
|---|---|---|
| Skew blows up | Sinks physically dispersed | Cluster related flops in Placement; revisit Floorplanning |
| Huge insertion delay | Deep tree, weak buffers | Stronger buffers, fewer levels, multi-source CTS |
| Thousands of hold violations | Expected — skew is now real |
opt_design -post_cts -hold; budget the area for delay cells |
| Setup got much worse post-CTS | Pre-CTS ideal-clock optimism | Use realistic uncertainty pre-CTS in Design Constraints |
| Clock power too high | Too many buffers / mesh too dense | More gating; relax skew target; check for over-constraint |
| Crosstalk on clock | Aggressors adjacent to clock routes | Non-default rules with extra spacing; shielding |
| Skew fine, timing still fails | Global skew reported, local skew bad | Report skew per clock group, on real paths |
| CTS ignores a domain | Clock not defined in SDC | Every clock must be declared — see Design Constraints |
- Cluster sinks in placement. CTS quality is mostly determined before CTS runs. Flops that share a clock should be physically near each other.
- Optimize local skew, not global. Global skew is a headline number; local skew is what fails silicon.
- Let CCOpt use useful skew. Forcing zero skew throws away free timing margin.
- Expect hold violations and budget for them. Hold fixing adds real area and power.
- Use dedicated clock buffers only — balanced rise/fall matters for duty cycle.
-
Handle clock domain crossings explicitly. Group asynchronous clocks with
set_clock_groups -asynchronousor CTS will try to balance unrelated trees. - Check transition times everywhere. A slow clock edge quietly degrades every timing check that depends on it.
- Keep the tree shallow. Fewer levels means less variation and less power.
See also: Placement · Routing · Timing Closure · Design Constraints · Physical Design