Plain global placement treats every net the same: it minimizes the total wire length. But some nets are on critical timing paths, and some regions of the core are harder to route than others. Timing-driven placement gives critical nets more weight so their cells move closer together. Congestion-driven (routability-driven) placement estimates routing demand during placement and spreads cells out where the wires would not fit. This article runs both modes of OpenROAD's placer on the 16x16 multiplier and reads what they did.

8 min read | Intermediate

What You'll Learn

  • Explain how timing-driven placement weights critical nets
  • Explain how routability-driven placement uses a congestion estimate
  • Recognize when timing-driven mode is silently disabled
  • Judge the result of a placement mode by the final routed design

Timing-Driven Placement

A timing-driven placer runs static timing analysis during placement. Nets on paths with negative or small slack get a higher weight in the wire length cost, so the placer pulls their cells closer together, at the expense of nets with plenty of slack.

In OpenROAD it is a flag on the global placer:

create_clock -name clk -period 6.0 [get_ports clk]
global_placement -density 0.50 -timing_driven

At a few points during the run, when the overflow passes set thresholds, the placer stops, estimates the wire parasitics from the current positions, runs repair_design (buffering and sizing, see Design Repair), times the design and updates the net weights.

The Clock Must Exist First

Timing-driven placement needs timing constraints. If the clock is defined only later in the script, the placer finds no slack to work with and turns the mode off:

[INFO GPL-0106] Timing-driven: worst slack 1e+30
[WARNING GPL-0102] Timing-driven: no slacks found. Timing-driven mode disabled.

A script that creates the clock right before clock tree synthesis, after placement, has exactly this problem: a run with -timing_driven produced a layout identical to the run without it. The lab's flow creates the clock, with its input and output delays, right after reading the netlist, so the placer can see it. Always read the constraints before placement, and check the log for this warning.

Quick Check

Q: A script reads the SDC file after global_placement -timing_driven. The run finishes without errors. What has the timing-driven option done?

Show Answer

Nothing. Without a clock there are no slacks, so the placer prints GPL-0102 and continues as a plain wire length driven placement.

The Multiplier at 6 ns

At a 6 ns clock the multiplier is too slow: its longest path through the partial product adders is about 9 ns before any repair. Two runs, both with the clock defined before placement, one plain and one timing-driven:

[INFO GPL-0100] Timing-driven iteration 1/2, virtual: false.
[INFO GPL-0101]    Iter: 287, overflow: 0.631, keep resizer changes at: 1, HPWL: 16757673
[INFO GPL-0106] Timing-driven: worst slack -1.5831116e-09
[INFO GPL-0107] Timing-driven: repair_design delta area: 1924.346 um^2 (+18.69%)
[INFO GPL-0110] Timing-driven: new target density: 0.58289766
[INFO GPL-0100] Timing-driven iteration 2/2, virtual: false.
[INFO GPL-0101]    Iter: 398, overflow: 0.194, keep resizer changes at: 1, HPWL: 23692557
[INFO GPL-0106] Timing-driven: worst slack -1.7006838e-09

The timing-driven run stopped twice. In the first stop, repair_design inserted 253 buffers, 18.7 % more cell area, and the placer raised its target density to make room. The results through the flow:

StepPlain placementTiming-driven
Worst slack after placement, before setup repair-2.98 ns-1.74 ns
Worst slack after setup repair (after CTS)-0.69 ns-0.71 ns
Worst slack after routing-0.92 ns-1.03 ns
Buffers in the final design48257
Cell area10,919 um2 (46 %)12,394 um2 (52 %)
Routed signal wire29.5 mm30.4 mm

Timing-driven placement gave a much better starting point: 1.24 ns less negative slack right after placement. But the setup repair that runs after CTS closed most of that gap for the plain run too, and after routing the timing-driven run ended slightly worse, with five times as many buffers and 14 % more area.

The lesson is not that timing-driven placement is useless. On designs where long wires cause the violations, it helps a lot. Here the problem is logic depth: no placement can make a 9 ns adder tree fit in 6 ns. Judge every placement option by the final routed result, not by an intermediate number.

Routability-Driven Placement

Routability-driven placement runs a quick global routing estimate during placement. Where the estimated demand for routing tracks exceeds the supply, the placer inflates the cells in that area, so they take more room and spread out, leaving more tracks for the wires.

global_placement -density 0.90 -routability_driven

The multiplier at a target density of 0.9, the most crowded placement from Global Placement:

[INFO GPL-0038] Routability snapshot saved at iter = 283
[INFO GPL-0041] Total routing overflow: 0.0000
[INFO GPL-0043] Average top 0.5% routing congestion: 0.8490
[INFO GPL-0047] Routability iteration weighted routing congestion: 0.8422
[INFO GPL-0050] Weighted routing congestion is lower than target routing congestion(1.0100), end routability optimization.

The placer checked: even the most congested 0.5 % of the routing tiles were at 85 % of their capacity, below the target of 1.01. So it inflated nothing, and the layout came out identical to the run without the flag. The option only acts when there is congestion to fix. Global Routing and Congestion shows how congestion is measured.

Quick Check

Q: Routability-driven placement inflates cells in a congested area. Why does that help the router?

Show Answer

Inflated cells need more space, so fewer of them fit in the congested area. Fewer cells there means fewer pins and nets that need tracks in that area, so the demand for routing drops to what the area can supply.

Running It in ChipVerify Lab

Run Place and Route on the multiplier with a 6 ns clock. Read the GPL section: there is no timing-driven iteration, because the lab's global_placement line has no -timing_driven flag, although the clock is already defined. Then read the repair_timing table after CTS: it shows the worst slack before and after setup repair. With PRO, add -timing_driven to the global_placement line in a custom script and compare the tables; the PRO option for routability-driven placement adds -routability_driven to the same line.

Common Mistakes

Mistake #1: Constraints read after placement

Timing-driven placement and pre-CTS repair need the clock and the I/O constraints. Load the SDC right after the netlist.

Mistake #2: Judging a mode by one intermediate number

In the 6 ns run, timing-driven placement improved the post-placement slack by 1.24 ns but ended worse after routing. Compare the final, routed results.

Mistake #3: Expecting placement to fix logic depth

Placement can shorten wires, not remove logic levels. A path that is too long in gates needs synthesis or RTL changes, or a slower clock.

Practice Exercise

Challenge: Where Did the Area Go?

The timing-driven run ended with 257 buffers and 12,394 um2 of cells, against 48 buffers and 10,919 um2 for the plain run. Estimate the average area per extra buffer. Which buffer sizes does that suggest?

Hint

Divide the extra area by the number of extra buffers. In sky130 hd a buf_1 is 3.75 um2, a buf_2 5.0, a buf_4 7.51 and a buf_6 11.26 um2.

Solution

1,475 um2 / 209 buffers = 7.1 um2 per buffer, close to a buf_4. The final DEF confirms it: of the 254 buffers named buf_*, 243 are buf_4, 9 buf_6, one buf_8 and one buf_12. The rest of the difference comes from gates resized by the repair steps.

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

Summary

  • Timing-driven placement weights nets on critical paths; it needs the clock defined before placement or it disables itself (GPL-0102).
  • OpenROAD stops placement a few times to repair, time the design and update the net weights.
  • On the multiplier at 6 ns it improved the post-placement slack by 1.24 ns, but not the final routed slack.
  • Routability-driven placement inflates cells in congested areas; with congestion below the target it does nothing.
Did you find what you were looking for?

Quiz

Test Your Knowledge

1 of 5 Score: 0 / 5