Tcl · Module 18
Querying Nets
Nets are the wires. Finding the ones that matter means accepting that nobody agreed how to spell 'reset' — and that the most important property of a net is not in its name at all.
Intermediate15 min readtcledapart-iinetsfanoutattributescollections
Part II · Module 18 · Chapter 18.6 · Querying Nets
A net is a wire — the connection between a driver and the pins it drives. Ports and pins are endpoints; nets are what joins them.
You will query nets for three things above all: the clock, the reset, and whatever is driving too much.
1. Nets follow the hierarchy
get_nets * size 2 clk_net reset_n_net
get_nets -hierarchical * size 4 clk_net reset_n_net u_fifo/wr_en u_alu/carryLike cells, nets exist at every level, and -hierarchical is the difference between the top-level wires and all of them. A net inside a block is named by its path — u_fifo/wr_en.
Top-level nets are usually the interesting ones for constraints: the clock and reset distribution. Block-internal nets matter when you are chasing a specific problem.
2. Finding the clock
get_nets -hierarchical *clk* size 1 clk_netStraightforward, and note the pattern is a substring search rather than a guess at the exact name. *clk* finds clk_net, clock, sys_clk, clk_div2 and anything else with those three letters in it.
That is deliberate, and §3 is why.
3. Finding the reset: the spelling problem
get_nets -hierarchical *reset* size 1 reset_n_net
get_nets -hierarchical *rst* size 0The working habit is to search broadly first, then narrow:
puts [collection_to_list [get_nets -hierarchical *rst*]]
puts [collection_to_list [get_nets -hierarchical *reset*]]One line each at the prompt, and you know what this design actually calls it before you write anything that depends on it. This is Chapter 17.2 §6's point again: the console is for finding out.
For a script that must work across designs, accept several spellings rather than assuming one:
proc find_reset_nets {} {
set found [get_nets -hierarchical *reset*]
if {[sizeof_collection $found] == 0} {
set found [get_nets -hierarchical *rst*]
}
if {[sizeof_collection $found] == 0} {
error "no net matched *reset* or *rst*" {} {DESIGN NORESET}
}
return $found
}Note that it still raises when both fail. A fallback chain that ends in silence is just a slower way to constrain nothing.
4. High fanout: not a name question at all
The registry's purpose asks for clock, reset and high-fanout nets "by pattern rather than by eye". The first two are patterns. The third cannot be.
fanout is an attribute, not a guess:
clk_net fanout 4
reset_n_net fanout 7
u_fifo/wr_en fanout 2
u_alu/carry fanout 1Fanout — how many pins a net drives — is a property the tool computed. Nothing in the name tells you, and nothing could: a net called clk_net might drive four pins or forty thousand depending on the design.
So the selection is by attribute:
set hi {}
foreach_in_collection n [get_nets -hierarchical *] {
if {[get_attribute $n fanout] > 3} { lappend hi $n }
}
puts " fanout > 3 : $hi" the high-fanout nets, by attribute:
fanout > 3 : clk_net reset_n_netThat is the correct answer and nothing about the names would have produced it.
5. A fanout report
The query you will actually keep, rather than type once:
set rows {}
foreach_in_collection n [get_nets -hierarchical *] {
lappend rows [list [get_attribute $n fanout] $n]
}
foreach r [lsort -integer -decreasing -index 0 $rows] {
puts [format " %-16s fanout %s" [lindex $r 1] [lindex $r 0]]
}=== a fanout report, sorted worst first ===
reset_n_net fanout 7
clk_net fanout 4
u_fifo/wr_en fanout 2
u_alu/carry fanout 1Worst first, which is the only order anyone reads. The sort is lsort -integer -decreasing -index 0 over a list of {fanout name} pairs — ordinary Part I list handling, applied to data the tool supplied.
And flagging against a threshold, which is what a script does rather than a human:
set limit 3
set over {}
foreach r $rows { if {[lindex $r 0] > $limit} { lappend over [lindex $r 1] } }
if {[llength $over] == 0} {
puts " no net exceeds fanout $limit"
} else {
puts " [llength $over] net(s) exceed fanout $limit: [join $over {, }]"
}=== flagging anything above a threshold ===
2 net(s) exceed fanout 3: clk_net, reset_n_net6. Why high fanout matters
Briefly, since it is the reason anyone queries for it: a net driving many pins presents a large load, so it is slow and its timing is hard to close. Clock and reset nets are high fanout by nature and get special treatment — a clock tree, a reset synchroniser and distribution network.
An unexpected high-fanout net is the interesting case: a control signal nobody intended to broadcast. Finding those is a maintenance query you will run repeatedly, which is a good argument for keeping it in a script rather than typing it.
7. The three questions
Nets are usually queried to answer one of these, and each takes a different approach:
| Question | How |
|---|---|
| What is the clock called? | substring pattern, *clk* |
| What is the reset called? | substring pattern, several spellings |
| What is driving too much? | attribute, not a pattern |
And all three deserve the same guard:
set nets [get_nets -hierarchical *clk*]
if {[sizeof_collection $nets] == 0} {
error "no net matched '*clk*'" {} {DESIGN NONET}
}8. Exercises
Exercise 1. What is a net, as distinct from a port or a pin?
Exercise 2. get_nets * returned two on a design with thousands. What is missing?
Exercise 3. Why search *clk* rather than the exact net name?
Exercise 4. get_nets -hierarchical *rst* returned nothing on a design that definitely has a reset. What happened?
Exercise 5. Why can no name pattern find high-fanout nets?
Exercise 6. Write a fallback that tries two reset spellings. What must it do if both fail?
Exercise 7. Why is an unexpected high-fanout net more interesting than the clock being high fanout?
Where this fits
Part of the Tcl curriculum.
