Skip to content
VLSI Mentor

Tcl · Module 19

Finding High-Fanout Nets

Everyone knows the clock is high fanout. That knowledge is useless, because it is already handled. The finding is always the net nobody expected to be driving thirty things.

Advanced16 min readtcledapart-iifanoutnetsreportsanalysis

Part II · Module 19 · Chapter 19.4 · Finding High-Fanout Nets

A net driving many pins is a large load: slow, hard to time, and a candidate for buffering or a dedicated distribution structure.

Chapter 18.6 §4 established that fanout is an attribute, not something a name can tell you. This chapter is what you do with it — and the useful part is not the ranking.

1. Rank everything

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set rows {}
foreach_in_collection n [get_nets -hierarchical *] {
    lappend rows [list [get_attribute $n fanout] $n]
}
set rows [lsort -integer -decreasing -index 0 $rows]
foreach r $rows { puts [format "  %6d  %s" [lindex $r 0] [lindex $r 1]] }
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
=== rank every net by fanout, worst first ===
      48  reset_net
      31  u_core/sel
      12  u_mem/wr_en
       5  clk_net
       3  u_core/carry
       2  d0_net
       2  d1_net
       1  q0_net

Build a list of {fanout name} pairs, sort on element 0, print. The sort is lsort -integer -decreasing -index 0 — the -index option sorting a list of lists by one field, which is the Part I feature that makes this three lines instead of thirty.

Worst first, because that is the only order anyone reads a ranking in.

2. The top few

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
foreach r [lrange $rows 0 2] { puts [format "  %6d  %s" [lindex $r 0] [lindex $r 1]] }
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
=== the top 3 ===
      48  reset_net
      31  u_core/sel
      12  u_mem/wr_en

lrange on the sorted list. On a real design this is the difference between a report somebody reads and a thousand-line file nobody opens.

3. Why the ranking alone is not the answer

Look at what is at the top: reset_net, at 48.

That is not a finding. Reset is supposed to be high fanout — it goes to every flop, and the flow already has a strategy for it, the same way it does for the clock. Reporting it at the top of every run tells you nothing you did not know.

This is the registry's "reputation" problem, and it cuts both ways. Everyone knows the clock and reset are high fanout, so a ranking that confirms it is noise — while the two nets underneath, which nobody has an opinion about, are the actual content.

4. Separate the expected from the surprising

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set limit 10
set clockish {} ; set other {}
foreach r $rows {
    lassign $r f n
    if {$f <= $limit} { continue }
    if {[string match *clk* $n] || [string match *reset* $n] || [string match *rst* $n]} {
        lappend clockish [list $f $n]
    } else {
        lappend other [list $f $n]
    }
}
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
=== above a threshold, with the clock/reset ones separated out ===
  above 10, expected (clock/reset distribution):
        48  reset_net
  above 10, NOT expected — these are the findings:
        31  u_core/sel
        12  u_mem/wr_en

Note the classification uses a name pattern — and this is the one place in Module 18 and 19 where that is appropriate. We are not asking what a net is; we are asking whether it is one that already has an owner. A name pattern is exactly the right instrument for "is this one of the ones we already know about".

5. Choosing the threshold

10 is arbitrary. In practice the threshold comes from one of three places:

  • The technology. Beyond some load, a cell cannot drive the net within timing. That number comes from the library, not from taste.
  • The flow's own limit. Many flows have a maximum fanout rule; match it so the report agrees with what will be enforced later.
  • The distribution. Sort and look: there is often an obvious gap between the handful that are deliberate and the long tail.

What matters is being explicit and consistent. A threshold that changes between runs makes two reports incomparable — which defeats the main purpose of having the report at all.

6. Making it comparable between runs

A high-fanout report is most useful as a difference: what got worse since last week.

Three things to get right for that:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
proc fanout_report {limit} {
    set rows {}
    foreach_in_collection n [get_nets -hierarchical *] {
        set f [get_attribute $n fanout]
        if {$f > $limit} { lappend rows [list $f $n] }
    }
    return [lsort -integer -decreasing -index 0 $rows]
}
  • Deterministic order. Always sorted, so a diff shows real changes rather than reordering — the same reason Chapter 14.9 §3's parray sorts.
  • A stated threshold in the output, so a reader knows what they are comparing.
  • Machine-readable output — one fanout name pair per line. Then the comparison is a Python or shell job outside the tool, which is Chapter 16.3 §6's division of labour: get the numbers out, let the tool exit, analyse outside.

7. The whole check

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
proc check_fanout {limit {known {*clk* *reset* *rst*}}} {
    set findings {}
    foreach r [fanout_report $limit] {
        lassign $r f n
        set expected 0
        foreach pat $known { if {[string match $pat $n]} { set expected 1 ; break } }
        if {!$expected} { lappend findings $r }
    }
    puts "  fanout above $limit: [llength $findings] unexpected net(s)"
    foreach r $findings { puts [format "    %6d  %s" [lindex $r 0] [lindex $r 1]] }
    return [llength $findings]
}

The known patterns are a parameter with a default, so a project with its own distribution nets can extend the list without editing the procedure — the same allowlist idea as Chapter 19.3 §5, and the same discipline: the list of exceptions is itself worth reviewing.

Unlike the unconnected-port check, this one usually should not fail a build. High fanout is a design observation, not a correctness error — report it, count it, and let a human decide.

8. Exercises

Exercise 1. Why can no name pattern find high-fanout nets?

Exercise 2. Which lsort options rank a list of {fanout name} pairs worst-first?

Exercise 3. reset_net is top of the ranking. Why is that not a finding?

Exercise 4. Why is a name pattern the right instrument for the classification step, given 18.5 argued against name patterns?

Exercise 5. Name two principled sources for the threshold.

Exercise 6. What three properties make the report comparable between runs?

Exercise 7. Should this check fail a build? Why or why not?

Where this fits

Part of the Tcl curriculum.