Once the clock tree exists, the timing picture changes: the clock has real latency and skew, the clock buffers have taken space, and hold can be checked properly for the first time. Post-CTS optimization is the round of repair that follows: fix setup with real clocks, fix hold, and legalize everything that was inserted. This article walks through that step in the lab's flow on the 16x16 multiplier at a 6 ns clock, and shows what a complete post-CTS sequence looks like.

7 min read | Intermediate

What You'll Learn

  • List the steps of post-CTS optimization and their order
  • Read the post-CTS setup repair table
  • Explain when ideal and propagated clocks give different repair results
  • Write a complete post-CTS sequence for OpenROAD

What Changes at CTS

  • Clock latency and skew become real numbers, so every setup and hold slack shifts by the skew of its path.
  • Clock buffers occupy sites that the placer had given to logic, and the detailed placement after CTS moves some cells to make room.
  • Hold can be checked meaningfully, as described in Skew, Useful Skew and Hold After CTS.
  • Clock transition at each flip-flop is now the tree's real edge rate, which changes clock-to-Q delays and setup and hold times.

The Lab's Post-CTS Step

In the lab's flow, five commands follow clock_tree_synthesis:

clock_tree_synthesis -apply_ndr none
set_propagated_clock [all_clocks]
estimate_parasitics -placement
repair_timing -setup
repair_timing -hold
detailed_placement

For the multiplier at 6 ns, a clock it cannot meet, the setup repair log is:

[INFO RSZ-0094] Found 18 endpoints with setup violations.
   Iter   | Removed | Resized | Inserted | Cloned |  Pin  |   Area   |    WNS   |   StTNS    |   EnTNS    |  Viol
          | Buffers |  Gates  | Buffers  |  Gates | Swaps |          |          |            |            | Endpts
       0* |       0 |       0 |        0 |      0 |     0 |    +0.0% |   -3.859 |      -86.0 |      -36.6 |     18
    final |       0 |      95 |       67 |      0 |    52 |    +7.7% |   -1.018 |      -26.1 |       -5.2 |      8
[INFO RSZ-0045] Inserted 67 buffers, 8 to split loads.
[INFO RSZ-0051] Resized 95 instances: 95 up, 0 up match, 0 down, 0 VT
[INFO RSZ-0043] Swapped pins on 52 instances.
[WARNING RSZ-0062] Unable to repair all setup violations.
[INFO RSZ-0033] No hold violations found.
  • WNS: worst negative slack, from -3.86 to -1.02 ns.
  • StTNS: total negative slack summed over all start-end pairs; EnTNS: summed over endpoints only. Both dropped by more than two thirds.
  • Viol Endpts: 18 failing endpoints before, 8 after.
  • The rows marked * are progress lines; final is the result after a last cleanup pass.

Hold repair then found nothing to fix. The following detailed_placement legalizes the 67 new buffers and the 95 upsized cells. The cells moved only 0.4 um on average, 11.7 um at most, because the changes were local.

Ideal or Propagated Clocks During Repair

The lab's script calls set_propagated_clock right after CTS, so the repair sees the real tree. Without that line, the repair would work with an ideal clock even though the tree exists. Two runs of the multiplier at 6 ns, from the same script with and without the line, came out the same:

Multiplier at 6 nsRepair with ideal clockRepair with propagated clock
WNS before repair-3.859 ns-3.859 ns
WNS after repair (placement estimate)-1.018 ns-1.018 ns
Buffers inserted / cells resized67 / 9567 / 95
Final WNS after routing-1.06 ns-1.06 ns
Final worst hold slack+0.71 ns+0.71 ns

That is expected here. The multiplier's tree has about 0.33 ns of latency and 0.01 ns of skew, so every path's launch and capture clocks move together, and the ideal clock is an excellent approximation. The difference shows up in designs where the tree is less balanced, such as the clock-gated register file in Clock Gating and the Clock Tree with 0.12 ns of skew, or with I/O paths, where the clock latency does not cancel. Using propagated clocks costs nothing and removes the risk.

Quick Check

Q: After post-CTS repair the estimated WNS is -1.02 ns, and after routing, with extracted parasitics, it is -1.06 ns. Where does the difference come from, and can it be much larger?

Show Answer

From the parasitics. Before routing, wire delays are estimated from placement as straight connections with average layer properties. After routing, the real routes are longer, with detours and vias. Here the difference is small, but in a crowded layout the critical nets can detour a lot: the same multiplier at 60 % utilization passed the repair step at 10 ns and missed timing by 0.37 ns after routing, as shown in Floorplan Trade-offs: A Utilization Sweep.

A Complete Post-CTS Sequence

The lab's sequence already propagates the clock and repairs hold. A fuller post-CTS step, as used in OpenROAD-based flows, also checks the result before routing:

clock_tree_synthesis
set_propagated_clock [all_clocks]
estimate_parasitics -placement
repair_timing -setup
repair_timing -hold
detailed_placement
check_placement
report_worst_slack -max
report_worst_slack -min
report_clock_skew
  • Setup before hold. Setup repair speeds up paths and can create new hold violations; hold repair adds delay and must not break setup. Running hold last lets it see the final fast paths. repair_timing -hold avoids inserting delay where it would create a setup violation.
  • Legalize after both, since both insert and resize cells.
  • Check the result before routing: setup and hold slack, skew, and that the placement is legal.

On the shift register with 0.5 ns of hold uncertainty, repair_timing -hold fixed all 63 hold violations with delay cells and added about 0.53 ns to every flip-flop to flip-flop path, as measured in Skew, Useful Skew and Hold After CTS.

Quick Check

Q: Why should hold repair not be run before setup repair?

Show Answer

Setup repair upsizes gates and inserts buffers that make paths faster. A path that just passed hold may then fail it, and the delay cells added earlier may have been placed on paths that setup repair later changed. Fixing hold last works on the final set of short paths.

Running It in ChipVerify Lab

Run Place and Route on the multiplier with a 6 ns clock. Find the repair_timing table after CTS and note the WNS, the failing endpoints and the cells changed. Then compare the WNS at the end of the table with the final WNS after routing. With PRO, set a hold uncertainty in the panel and watch the hold repair line after the setup table change from "No hold violations found" to inserted hold buffers.

Common Mistakes

Mistake #1: Repairing with an ideal clock after CTS

It worked on the balanced multiplier tree, but on a tree with real skew the repair optimizes the wrong paths. Propagate the clock as soon as the tree exists.

Mistake #2: Skipping hold repair

Setup problems make a chip slow; hold problems make it fail at any frequency. A flow that never repairs hold depends on luck and on clock-to-Q delay.

Mistake #3: Trusting the pre-route WNS

The multiplier lost another 0.24 ns between post-CTS estimate and routed result. Keep some margin at this stage for the routing parasitics.

Practice Exercise

Challenge: Reading the Table

In the post-CTS repair table, WNS went from -3.859 to -1.018 ns and the number of failing endpoints from 18 to 8. EnTNS went from -36.6 to -5.2 ns. What is the average negative slack per failing endpoint before and after? What does that say about the remaining violations?

Hint

Divide EnTNS by the number of failing endpoints.

Solution

Before: -36.6 / 18 = -2.03 ns per endpoint. After: -5.2 / 8 = -0.65 ns, against a worst of -1.02 ns. The 8 remaining endpoints are the ends of a few long paths through the multiplier array, which need a longer clock period or a pipelined design, not more repair.

Open the ready-made example in the lab, synthesize it and run Place and Route.

Summary

  • Post-CTS optimization repairs setup with real clocks, then hold, then legalizes.
  • On the multiplier at 6 ns, post-CTS repair took WNS from -3.86 to -1.02 ns with 67 buffers and 95 resized cells; routing then cost another 0.04 ns.
  • The lab repairs with a propagated clock; on the balanced multiplier tree an ideal clock gave the same result.
  • A complete sequence propagates the clock, repairs setup and then hold, legalizes, and checks the result before routing.
Did you find what you were looking for?

Quiz

Test Your Knowledge

1 of 5 Score: 0 / 5