Skip to content
VLSI Mentor

Tcl · Module 23

Placement Reports

Placement is not judged on its own terms. It is judged on whether routing will succeed afterwards — which makes congestion a prediction, and predictions need reading carefully.

Intermediate15 min readtcledapart-iiphysical-designplacementcongestion

Part II · Module 23 · Chapter 23.3 · Placement Reports

Placement decides where every cell sits. The question afterwards is not "is this placement good" in the abstract — it is can routing succeed from here, because routing is the long and expensive step that follows.

Congestion is how that question gets answered before paying for the answer.

1. What congestion measures

Roughly: in each small region of the die, how much routing is demanded against how much is available. Where demand exceeds supply, the router has to detour — and past some point it cannot complete at all.

It is reported per layer, because routing resource is per layer, and that detail is the subject of §4.

2. Reading it

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
foreach {layer pct} [report_congestion] {
    set flag [expr {$pct > 2.0 ? "  <- over the 2% limit" : ""}]
    puts [format "    %-3s overflow %4.1f%%%s" $layer $pct $flag]
}
set worst 0 ; set worst_layer ""
foreach {l p} [report_congestion] { if {$p > $worst} { set worst $p ; set worst_layer $l } }
puts [format "    worst: %s at %.1f%%" $worst_layer $worst]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
=== 23.3 congestion by layer ===
    M2  overflow  0.8%
    M3  overflow  1.4%
    M4  overflow  6.2%  <- over the 2% limit
    M5  overflow  0.3%
    M6  overflow  0.0%
    worst: M4 at 6.2%

Ordinary Part I: foreach over pairs (Chapter 9.3), a comparison, format to line up the columns. The tool supplies the numbers; everything else is yours.

The layer names and the overflow figures come from a teaching mock, not a tool. Real congestion reports use vendor-specific metric names and formats — some report overflow as a percentage, some as tracks demanded against tracks available, some per region rather than per layer. What transfers is the reading, which is the rest of this chapter.

3. Congestion is a prediction, not a verdict

Worth being clear about what the number is.

It says the router will have difficulty in those regions, not that it will fail. A design with a few percent overflow usually routes, with detours that cost timing. A design with a lot does not route at all, and the discovery takes however long the router runs before giving up.

So the useful question is not "is this congested" but "is this congested enough to stop now" — and that threshold is a flow decision, stated in the script rather than judged each time, exactly as in Chapter 23.1 §7.

4. Per layer, not a single number

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
    worst: M4 at 6.2%

That is the number people quote, and on its own it supports the wrong decision as often as the right one.

So a congestion summary should carry the distribution, not just the maximum:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
proc congestion_summary {limit} {
    set over {} ; set worst 0 ; set worst_layer ""
    foreach {l p} [report_congestion] {
        if {$p > $limit} { lappend over [list $l $p] }
        if {$p > $worst} { set worst $p ; set worst_layer $l }
    }
    return [dict create worst $worst worst_layer $worst_layer \
                        over $over layers [expr {[llength [report_congestion]] / 2}]]
}

[llength [report_congestion]] / 2 because the report is a flat list of pairs — the same structure foreach consumed above.

5. The same worst number, twice

The argument in §4 is worth running rather than asserting. Here is congestion_summary against two different placements, reported through one formatter:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
proc show {label} {
    set c [congestion_summary 2.0]
    puts [format "  %-10s worst %.1f%% on %-3s   over the limit: %d of %d layers" \
              $label [dict get $c worst] [dict get $c worst_layer] \
              [llength [dict get $c over]] [dict get $c layers]]
    foreach o [dict get $c over] { puts [format "                 %-3s %.1f%%" {*}$o] }
}
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
=== one hot layer ===
  local      worst 6.2% on M4    over the limit: 1 of 5 layers
                 M4  6.2%

=== every layer loaded, same worst number ===
  global     worst 6.2% on M4    over the limit: 5 of 5 layers
                 M2  5.9%
                 M3  6.1%
                 M4  6.2%
                 M5  5.7%
                 M6  4.8%

worst 6.2% on M4 in both runs. Identical headline, identical worst layer. A script that gated on the worst number alone would treat these two placements as the same situation.

1 of 5 and 5 of 5 is what separates them, and the fix for each is in a different part of the flow — a local placement adjustment for the first, a floorplan change for the second.

This is the same demonstration Chapter 23.5 §4 makes for DRC: two runs, the same summary number, different decisions. The pattern to carry away is that a one-number summary needs a companion number saying how much of the design the one number describes.

One Tcl detail: {*}$o expands the {layer percent} pair into format's two arguments. Without it format receives a single argument that merely looks like a list — which is what Chapter 6.13 is for.

6. What else placement leaves behind

Congestion is the headline. A placement report set should also capture:

  • Density per region, which shows hotspots congestion may not yet reflect.
  • Timing after placement — the first estimate with real locations, and usually much worse than the pre-placement estimate because wire delay is now partly real. Module 22 applies, with the caveat from Chapter 22.3 §4: these are estimated parasitics, not extracted ones.
  • Legality — every cell on a legal site, nothing overlapping. A tool-specific check, and one that must pass rather than merely be small.

That last distinction is Chapter 23.5's subject, and it applies here too: some results are thresholds and some are absolutes.

7. The gate before routing

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
place_design
set c [congestion_summary $CONGESTION_LIMIT]
puts "  worst congestion: [dict get $c worst]% on [dict get $c worst_layer]"
puts "  layers over the limit: [llength [dict get $c over]] of [dict get $c layers]"
foreach o [dict get $c over] { puts [format "      %-3s %.1f%%" {*}$o] }

if {[llength [dict get $c over]] > 0} {
    puts stderr "  placement is congested — routing is likely to struggle"
    if {$::STOP_ON_CONGESTION} { exit 1 }
}
route_design

Two things worth noting in that shape.

It reports the count and the denominator — "2 of 5 layers over the limit" — which is Chapter 22.7 §4's denominator argument. "Worst 6.2%" alone does not say how much of the design is affected.

Whether it stops is a policy flag, not a judgement. During exploration you may want to route anyway and see what happens; at a milestone you do not. Making that a variable means the same script serves both, which is Chapter 21.7 §5's one-script-with-options argument.

8. Exercises

Exercise 1. What question is placement actually judged against?

Exercise 2. What does congestion measure?

Exercise 3. Why is congestion a prediction rather than a verdict?

Exercise 4. One layer at 6.2% with the rest below 1.5% — what kind of problem is that?

Exercise 5. Every layer at 4–6% gives a similar worst number. Why is the conclusion different?

Exercise 6. Two placements both report worst 6.2% on M4. What single extra number tells them apart, and what does each value imply?

Exercise 7. Why report the count of layers over the limit as well as the worst?

Exercise 8. Why make "stop on congestion" a flag rather than always stopping?

Where this fits

Part of the Tcl curriculum.