Volume 04 Advanced 5 sub-modules ~55 min read

Placement & Clock Tree Synthesis

Placement decides where every cell physically lives, which fixes the length of every wire and therefore most of your timing. Then CTS does the thing the whole flow has been postponing: it turns the clock from a convenient fiction that arrives everywhere at once into a real network of thousands of buffers with real, unequal delay. Hold violations you have never seen before appear at exactly this moment, and they are supposed to.

4.1 Global, legal, detailed

Placement runs in three stages that solve genuinely different problems, and confusing them makes the logs unreadable.

Placement in three stages: global placement with overlapping cells at approximate positions, legalisation snapping cells into rows, and detailed placement refining local order GLOBAL → LEGAL → DETAILED 1. global overlapping, off-row minimises total wire length analytic / force-directed 2. legalised snapped to rows and sites no overlaps, minimal movement legality, not quality 3. detailed local swaps, resized cells purple = buffers just inserted now timing-driven and this is why you left space
Figure 4.1 - Global placement optimises; legalisation makes the result physically valid; detailed placement then fixes timing locally and inserts the buffers that need somewhere to go.

Global placement optimises a proxy for wire length, almost always HPWL - the half-perimeter of the bounding box enclosing a net's pins. It is not the true routed length, but it is fast to compute and correlates well enough, and modern analytic placers solve for millions of cells by treating the problem as a system of springs.

The stage that most affects your timing report is the third one. After legalisation the tool finally knows real distances, so it can do timing-driven optimisation: resize a cell whose load turned out to be larger than synthesis assumed, insert a buffer on a net that turned out to be long, or swap in a lower-Vth cell on a critical path.

4.2 Congestion and density maps

Two different maps get called "the placement picture", and they answer different questions.

Density map Congestion map
Shows How much cell area sits in each region Routing demand versus available tracks
Units Per cent occupied Overflow: needed tracks minus supplied tracks
Available Right after global placement After a trial global route
High values mean Cells are packed here The router will fail here
Density and congestion are not the same thing A region can be only 40% dense and severely congested, because the cells there have many pins and the nets crossing it are numerous - a crossbar, a wide multiplexer tree, an address decoder. Conversely a 70%-dense region of a regular datapath can route cleanly. Always look at the congestion map, not the density map, when the router is struggling; density is a proxy and it can point you at the wrong place entirely.
Fix Effect Cost
Lower PL_TARGET_DENSITY Spreads everything; the blunt instrument that usually works Longer wires everywhere, worse timing globally
Cell padding around high-pin-count cells Targets the actual offenders Needs you to know which cells they are
A soft blockage over the hot region Forces the placer to spread just there Manual, and it moves when the design changes
Restructure the RTL The real fix for a crossbar or a huge mux A front-end change, and a schedule conversation
Grow the core Always works Area, and a full flow re-run

4.3 Why the clock is built last

Everything so far has treated the clock as ideal: it arrives at every flip-flop at exactly the same instant, with zero delay from the port. That is a deliberate fiction, and STA has been told to believe it.

The fiction is necessary because a clock tree cannot be built until you know where the sinks are. Before placement, a flip-flop has no coordinates, so there are no distances, so there is nothing to balance. CTS therefore has to come after placement - and its arrival changes the timing picture more than any other single step in the flow.

Before CTS (ideal clock) After CTS (propagated clock)
Clock arrival Identical everywhere, zero delay Real, unequal, 0.5-2 ns of insertion delay
Skew Zero, replaced by a lump of set_clock_uncertainty Computed per path from the real tree
Hold analysis Nearly meaningless The main event
Cell count Your logic Plus hundreds or thousands of clock buffers
Power Underestimated The clock tree is often 20-40% of total dynamic power

# Before CTS: the clock is a promise. Uncertainty is a placeholder for
# the skew and jitter the tree does not have yet.
set_clock_uncertainty 0.25 [get_clocks clk]

# After CTS: analyse the tree that actually exists.
set_propagated_clock [all_clocks]

# And now uncertainty only has to cover what STA still cannot see --
# source jitter and a little modelling margin. The skew is measured.
set_clock_uncertainty -setup 0.10 [get_clocks clk]
set_clock_uncertainty -hold  0.05 [get_clocks clk]

# Running STA before this line and calling it sign-off is the single
# most common way to convince yourself a design is finished.

4.4 Building the clock tree

CTS starts from one root and thousands of sinks and must deliver an edge to all of them at nearly the same time, with a clean transition, without exceeding any buffer's load limit. It works bottom-up: cluster nearby sinks, drive each cluster with a buffer, then treat those buffers as the sinks of the next level, and repeat until one root remains.

A balanced clock buffer tree from root through two buffer levels to sixteen flip-flops, annotated with insertion delay at each level and the resulting skew BALANCED PATHS, NOT SHORT PATHS clk t = 0 clkbuf_8 t = 0.31 t = 0.58 FF FF FF FF FF FF FF FF insertion delay 0.84 ns skew = max(arrival) - min(arrival) = 0.04 ns
Figure 4.4 - A balanced tree. Note what CTS is optimising: not the shortest path to each flop, but the most equal path to all of them. A nearby flop may be deliberately given extra buffering so that it does not arrive early.
Clock buffers are a different species A clock tree is built from clkbuf and clkinv cells, not ordinary buffers. They are characterised for balanced rise and fall delay, because an imbalance would distort duty cycle a little more at every level, and after six levels a 50% duty cycle can become 42% - which breaks anything using both edges. They also have lower delay sensitivity to supply variation, which limits how much IR drop (Volume 03) can turn into skew.

# Which cells CTS may use. Ordinary buffers are deliberately excluded.
set ::env(CTS_CLK_BUFFER_LIST) "sky130_fd_sc_hd__clkbuf_4 \
                                sky130_fd_sc_hd__clkbuf_8 \
                                sky130_fd_sc_hd__clkbuf_16"
set ::env(CTS_ROOT_BUFFER)     "sky130_fd_sc_hd__clkbuf_16"

# Target skew, in nanoseconds. Asking for less than the tool can deliver
# just burns buffers and power for no benefit.
set ::env(CTS_TARGET_SKEW)  0.05
set ::env(CTS_TOLERANCE)    100

# Sink clustering: how many flops one leaf buffer may drive, and how far
# apart they may be. Tighter clustering = lower skew, more buffers.
set ::env(CTS_SINK_CLUSTERING_SIZE)     25
set ::env(CTS_SINK_CLUSTERING_MAX_DIAMETER) 50

4.5 Skew, insertion delay and useful skew

Two numbers describe a clock tree, and they are frequently confused.

The two quantities
Insertion delay (latency) troot → tsink   -   how long the clock takes to arrive
Skew tcapture − tlaunch   -   the difference between two sinks
A tree can have 2 ns of insertion delay and 20 ps of skew - every path long, but all equally long. Skew is what enters the setup and hold equations; insertion delay mostly affects timing relative to the outside world, and how long the clock takes to settle after reset.

Skew is signed, and the sign decides which check it helps:

Case Meaning Setup Hold
Positive skew Capture clock arrives later than launch Helps - more time for data Hurts - the edge waits for a racing signal
Negative skew Capture clock arrives earlier than launch Hurts - less time for data Helps
Zero skew Simultaneous Neutral Neutral

That table is why hold violations appear at CTS and not before. With an ideal clock, skew is zero and a short combinational path is fine. Give the capture flop a clock that arrives 60 ps early and that same short path now races the edge. The fix is to slow the data down - insert delay buffers - which is why post-CTS optimisation adds cells to paths that were never a problem.

Useful skew: turning the problem into a tool If a path from A to B is 200 ps too slow and the following path from B to C has 400 ps of slack to spare, you can deliberately delay B's clock by 200 ps. Path A→B gains the time; path B→C loses it and can afford to. Nothing in the RTL changed - you moved slack between adjacent pipeline stages by shaping the clock tree. This is useful skew, it is standard practice in high-performance design, and it is the same idea as time borrowing with latches. The catch: it makes hold analysis harder and the design more sensitive to on-chip variation, so it is applied surgically, to named paths, not globally.
Interview grilling - "Setup was clean before CTS. Now you have 4,000 hold violations. Panic?"

No - that is the expected shape of the flow, and saying so calmly is most of the answer.

  • Why it happened. Before CTS the clock was ideal, so skew was zero and every short path passed trivially. CTS gave the clock real, unequal arrival times. Anywhere the capture flop's clock now arrives early, a short data path violates hold.
  • Why it is not alarming. Hold is fixed by adding delay to the data path, and there is always somewhere to add it. Unlike setup, hold has no fundamental barrier - it costs area and a little power, not architecture.
  • How to fix it. Post-CTS optimisation inserts delay cells automatically. Four thousand violations at a few picoseconds each is routine; four thousand at 500 ps each means the clock tree is badly unbalanced and should be rebuilt rather than patched.
  • What would worry me instead. Setup degrading sharply after CTS. That means insertion delay or skew is far worse than the set_clock_uncertainty placeholder assumed - the estimate was wrong, and every pre-CTS decision was made against a target that did not exist.

The line that shows real experience: "I would check hold at the fast corner, not typical. Hold failures are worst when cells are fastest, and a design that is hold-clean at typical can still be broken at ff."

Volume 04 recap

Concept The one thing to remember
Global placement Minimises HPWL. Overlaps allowed, rows ignored.
Detailed placement Where timing-driven sizing and buffering actually happen.
Density vs congestion Read the congestion map. Density is a proxy that misleads.
Ideal clock A fiction held until CTS. Uncertainty is its placeholder.
CTS goal Equal paths, not short paths.
Clock buffers Balanced rise/fall, or duty cycle drifts down the tree.
Skew sign Positive helps setup, hurts hold. Negative the reverse.
Post-CTS hold Thousands of small violations is normal. Fix by adding delay.