Skip to content
VLSI Mentor

Tcl · Module 19

Finding Unconnected Ports

Some unconnected ports are deliberate and some are mistakes, and a list that does not tell them apart gets ignored. The useful query is the one that reports only the surprising ones.

Advanced16 min readtcledapart-iiconnectivitychecksqueriesquality

Part II · Module 19 · Chapter 19.3 · Finding Unconnected Ports

A top-level port that connects to nothing is a defect with an unusual cost curve. At RTL it is a minute's work. After synthesis it is an hour of tracing. After tapeout it is a respin.

The query that finds it is five lines. The entire value is in running it early, and automatically, so nobody has to remember to look.

1. Every port, and what it connects to

Start by making connectivity visible:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
foreach_in_collection p [get_ports *] {
    set n [get_attribute $p net]
    puts [format "  %-12s %-4s %s" $p [get_attribute $p direction] \
        [expr {$n eq "" ? "<UNCONNECTED>" : $n}]]
}
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
=== every port, with the net it connects to ===
  clk          in   clk_net
  reset_n      in   reset_net
  d_in[0]      in   d0_net
  d_in[1]      in   d1_net
  d_out[0]     out  q0_net
  d_out[1]     out  <UNCONNECTED>
  test_mode    in   <UNCONNECTED>
  scan_en      in   <UNCONNECTED>

Three of eight connect to nothing. On a real design this table has hundreds of rows, which is exactly why it has to become a query rather than something you read.

2. The query

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
proc unconnected_ports {} {
    set bad {}
    foreach_in_collection p [get_ports *] {
        if {[get_attribute $p net] eq ""} { lappend bad $p }
    }
    return $bad
}
set bad [unconnected_ports]
puts "  [llength $bad] unconnected: [join $bad {, }]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
=== the query that finds them ===
  3 unconnected: d_out[1], test_mode, scan_en

Five lines, and now the problem: three findings, and only one of them is a bug.

3. Why the raw list gets ignored

This is the failure mode of most automated checks. A list that reports three things when one matters trains people to skim it; a list that reports two hundred trains them to switch it off.

test_mode and scan_en are almost certainly deliberate — test ports that are unused in this configuration. Reporting them every run, forever, is how a useful check becomes noise.

So the query is not the hard part. Separating the expected from the surprising is. Two ways to do it, and they are complementary.

4. Cut one: direction

The better first cut, because it needs no configuration:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
foreach_in_collection p [get_ports *] {
    if {[get_attribute $p net] ne ""} { continue }
    set d [get_attribute $p direction]
    set verdict [expr {$d eq "out" ? "SUSPICIOUS - an output driving nothing" \
                                   : "often intentional - an unused input"}]
    puts [format "  %-12s %-4s %s" $p $d $verdict]
}
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
=== classify by direction, which is the better first cut ===
  d_out[1]     out  SUSPICIOUS - an output driving nothing
  test_mode    in   often intentional - an unused input
  scan_en      in   often intentional - an unused input

5. Cut two: an allowlist

Direction is a good heuristic and not a rule — an unused input can be a bug too, when it is the enable nobody wired up. The complement is to declare what you expect:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set expected {test_mode scan_en}
set real {}
foreach p $bad { if {[lsearch -exact $expected $p] < 0} { lappend real $p } }
puts "  known-unused (declared) : [join $expected {, }]"
puts "  genuinely unexpected    : [expr {[llength $real] ? [join $real {, }] : "<none>"}]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
=== but not every one is a bug ===
  known-unused (declared) : test_mode, scan_en
  genuinely unexpected    : d_out[1]
  -> this is the one to investigate

One finding. The same one the direction rule flagged — and the two cuts agreeing is itself reassuring.

6. The check worth automating

Putting it together, as something a flow runs every time:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
proc check_unconnected_ports {{expected {}}} {
    set problems {}
    foreach_in_collection p [get_ports *] {
        if {[get_attribute $p net] ne ""} { continue }
        if {[lsearch -exact $expected $p] >= 0} { continue }
        lappend problems [list $p [get_attribute $p direction]]
    }
    foreach entry $problems {
        lassign $entry name dir
        set sev [expr {$dir eq "out" ? "ERROR" : "WARNING"}]
        puts stderr [format "  %-7s unconnected %-3s port: %s" $sev $dir $name]
    }
    set errs 0
    foreach entry $problems { if {[lindex $entry 1] eq "out"} { incr errs } }
    return $errs
}

exit [expr {[check_unconnected_ports {test_mode scan_en}] > 0 ? 1 : 0}]

Four design decisions, each from Part I:

  • Diagnostics go to stderr, so the check can run in a pipeline whose stdout is the real report — Chapter 14.9 §2.
  • Outputs are errors, inputs are warnings. Different severities mean the check can fail a build on the serious case without blocking on the routine one.
  • It returns a count and the caller exits on it, rather than exiting itself — Chapter 15.4 §3.
  • The allowlist is a parameter, so the same procedure serves every block with its own exceptions.

7. When to run it

As early as possible. The query works on any loaded design, so it belongs immediately after the netlist is read — before synthesis, before anything expensive.

On every run, not on request. A check somebody has to remember is a check that gets run after the problem is expensive.

With a non-zero exit status when it finds something serious, so the surrounding automation stops rather than continuing to the next stage — the whole argument of Chapter 15.4 §6.

8. Exercises

Exercise 1. Why is a dangling port much cheaper to fix early?

Exercise 2. Write the five-line query that lists unconnected ports.

Exercise 3. Why does the raw list get ignored in practice?

Exercise 4. Why is an unconnected output more suspicious than an unconnected input?

Exercise 5. Give an example of an unconnected input that is a real bug.

Exercise 6. Why keep a reason next to each allowlist entry?

Exercise 7. The check reports no problems on a design that was never loaded. What has gone wrong, and what is the fix?

Where this fits

Part of the Tcl curriculum.