Tcl for EDA · lesson 10

Working with design objects

The query, filter, loop and act pattern behind most EDA scripts, practised on plain Tcl lists first and then on Innovus collections and database queries.

9 min read · Free, no login

Most useful scripts in a physical design flow do four things: ask the tool for a set of objects, narrow the set, go through it, and act on each item. The objects are cells, nets, pins, ports, clocks. This lesson practises that pattern on plain Tcl lists, so you can run it anywhere, and then shows the commands Innovus provides to do the same on a real design.

Reading time: about 9 minutes.

10.1 Query, filter, loop, act

Figure 10.1 shows the four steps. The first step is the only one that talks to the tool. After it, you hold a set of names or objects, and the rest is ordinary Tcl.

1 Queryget the objects2 Filterkeep what you need3 Loopvisit each one4 Actreport, set, countdbGet / get_cells-filter / lsearchforeach_in_collectionputs / set / reportAsk for as little as you can, then loop over the small result.
Figure 10.1 – Query, filter, loop and act: only the first step reaches the tool, everything after is ordinary Tcl.

Let us consider a small design written as a list of records, each holding an instance name and its master (library cell) name.

set insts {
    {u_alu/reg_a DFFX1}
    {ff_sum_reg[0] DFFX1}
    {ff_sum_reg[1] DFFX1}
    {u_alu/g1 AND2X1}
    {u_ctl/g2 AND2X1}
    {u_ctl/inv1 INVX1}
}

This stands in for the answer to a query. The records are invented for the lesson.

10.2 Filter

Select the instances whose name contains reg.

set hits {}
foreach i $insts {
    if {[string match *reg* [lindex $i 0]]} { lappend hits [lindex $i 0] }
}
puts $hits

This prints u_alu/reg_a {ff_sum_reg[0]} {ff_sum_reg[1]}. Tcl shows the names with brackets in braces, which is how it protects them inside a list.

10.3 Group by block

The block is the first part of the hierarchical name. Names with no slash belong to the top level.

set blocks [dict create]
foreach i $insts {
    lassign $i name master
    set parts [split $name /]
    set blk [expr {[llength $parts] > 1 ? [lindex $parts 0] : "(top)"}]
    dict incr blocks $blk
}
dict for {b n} $blocks { puts "$b: $n" }

This prints:

u_alu: 2
(top): 2
u_ctl: 2

10.4 A histogram of masters and the total area

set area [dict create DFFX1 12.6 AND2X1 5.4 INVX1 3.6]
set hist [dict create]
set tot 0.0
foreach i $insts {
    dict incr hist [lindex $i 1]
    set tot [expr {$tot + [dict get $area [lindex $i 1]]}]
}
foreach m [lsort [dict keys $hist]] { puts "$m [dict get $hist $m]" }
puts "total area [format %.1f $tot]"

This prints:

AND2X1 2
DFFX1 3
INVX1 1
total area 52.2

The areas are invented numbers to show the arithmetic. In a real flow, the tool reports the area, and you should check which unit the library uses.

10.5 Names with brackets

Bus bits are the usual trouble. In a glob pattern, [0] means "the character 0", so it will not match a name that contains the literal text [0].

puts [string match {ff_sum_reg\[0\]} {ff_sum_reg[0]}]
puts [string match {ff_sum_reg[0]} {ff_sum_reg[0]}]
puts [regsub -all {[][]} {ff_sum_reg[0]} _]

This prints:

1
0
ff_sum_reg_0_

The first form escapes the brackets and matches. The second reads [0] as a character set and fails. The regsub replaces both bracket characters, which is useful when a name becomes part of a file name. Lesson 5 showed why the quoted form of such a name breaks, and it applies here too: keep names with brackets in braces, or build them with list.

10.6 Collections and lists

Innovus returns many objects in a collection, which is a handle to a set of objects that lives inside the tool. A collection is not a Tcl list. You cannot call lindex on it, and printing it shows a handle rather than names. Three commands work on collections: sizeof_collection counts them, sort_collection orders them by a property, and foreach_in_collection walks them. To get a string out of one object, use get_property.

Other commands, such as dbGet, return an ordinary Tcl list or string. The reference states this, so every list command in Lessons 4 to 8 applies. When you read a script, check which kind you hold.

10.7 Innovus: collections

To be run at the Innovus prompt. Check the details against your release with the -help option of each command.

Legacy UI.

puts [sizeof_collection [all_registers -flops]]
foreach_in_collection c [get_cells *] {
    puts [get_property $c hierarchical_name]
}
set sorted [sort_collection [all_inputs] hierarchical_name]

The reference documents the first as the flop-count idiom, the second as the pattern for printing every cell name, and the third as the sorting example. Each pass of foreach_in_collection holds a one-object collection, which is why get_property is needed to read its name.

The get_cells command accepts a -filter expression on any cell property. The reference lists properties such as area, ref_lib_cell_name and hierarchical_name, and shows this pattern:

Legacy UI.

get_cells "o*" -filter "@ref_lib_cell_name != FD2 && @is_black_box==false"

In this form, @ introduces a property name. Filtering inside the tool is usually faster than fetching everything and filtering in Tcl.

10.8 Innovus: database queries

dbGet walks the database by a dotted path and returns a Tcl list or string.

Legacy UI.

set masters [dbGet top.insts.cell.name]
set n [dbGet top.numInsts]
set names [dbGet top.terms.name]

The reference lists top.insts.cell.name for master names, top.numInsts for the instance count and top.terms.name for the top ports. Adding -u returns unique results. A pattern after the path filters: dbGet top.insts.cell.name INV1 selects instances of that master, and -p2 goes back two levels to return the instance objects instead. Use dbGet -help and the .?? suffix on a path to list the attributes of an object in your release. The reference also warns never to paste the pointers it prints into other commands or into another session.

A change is made with dbSet, which sets an attribute that dbGet shows as settable. The reference gives dbSet top.insts.pStatus fixed as a pattern. This changes every instance, so read it twice before running it on a design you care about.

10.9 Innovus: Common UI

The Common UI describes the same data as attributes. The only Common UI forms in the lab kit used for this course are the following. They are shown as the lab writes them, and the lab text says they are used with the synthesis flow.

Common UI.

get_db scan_segments *spi*
set_db inst:dtmf_recvr_core/PM_INST/isolation_enable_reg_reg .dft_dont_scan true

get_db reads an object or attribute, and set_db writes an attribute. The first line, from the scan-chain lab, returns the scan segments whose names contain spi. The second keeps one register out of scan. Do not mix Legacy and Common UI commands in a single script, and for anything beyond these forms, check the Common UI guide for your release.

10.10 Why an interviewer asks about this

Typical questions: "how do you get all the flops in a design and count them", "what is the difference between a collection and a list" and "how do you match a net name that has brackets". A strong answer uses all_registers -flops with sizeof_collection, says that a collection is a handle inside the tool and must be walked with foreach_in_collection, and escapes the brackets in the pattern. Interviewers also like the question "how would you find the cells of one master in a hierarchical block", where the expected reply is a get_cells -filter or a dbGet pattern.

Key takeaways

  • The four steps are query, filter, loop and act, and only the first needs the tool.
  • A collection is a handle inside the tool, so use sizeof_collection, sort_collection, foreach_in_collection and get_property on it.
  • dbGet returns an ordinary Tcl list or string, so all the list and dictionary commands apply.
  • Escape brackets in glob patterns, keep names with brackets in braces, and filter inside the tool when it is faster.