Skip to content
VLSI Mentor

Tcl · Module 18

Filtering a Collection by Attribute

Selecting by name gets you close. Selecting by what something actually is gets you right — and one expression does what a loop takes six lines to do badly.

Advanced17 min readtcledapart-iicollectionsfilteringattributes

Part II · Module 18 · Chapter 18.7 · Filtering a Collection by Attribute

Chapter 18.5 §4 showed that selecting sequential cells by name found one of four. The fix was an attribute, and this chapter is about the command that uses them.

It replaces a loop you would otherwise write by hand — and it does so in a way that matters more than brevity.

1. Narrowing by a property

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set all [get_cells -hierarchical *]
show {everything}                              $all
show {filter "is_sequential == true"}          [filter_collection $all "is_sequential == true"]
show {filter "is_sequential != true"}          [filter_collection $all "is_sequential != true"]
show {filter "ref_name == DFF"}                [filter_collection $all "ref_name == DFF"]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  everything                                   size 7   u_fifo u_alu u_fifo/u_ctrl u_fifo/u_ram u_fifo/u_decode u_alu/u_add u_alu/u_acc_reg
  filter "is_sequential == true"               size 4   u_fifo u_fifo/u_ctrl u_fifo/u_ram u_alu/u_acc_reg
  filter "is_sequential != true"               size 3   u_alu u_fifo/u_decode u_alu/u_add
  filter "ref_name == DFF"                     size 2   u_fifo/u_ctrl u_alu/u_acc_reg

filter_collection takes a collection and a predicate, and returns a new collection of the objects that satisfy it. The original is unchanged — filters produce, they do not modify.

Note the third row: 4 and 3 sum to 7, so != is a genuine complement here. Be careful assuming that in general — an attribute that is undefined on some objects will not satisfy either comparison, so the two halves can sum to less than the whole.

2. Chaining

Filters compose, and reading them as successive narrowings is usually clearer than one compound expression:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set seq [filter_collection $all "is_sequential == true"]
show {  step 1: is_sequential == true} $seq
show {  step 2: ref_name == DFF}       [filter_collection $seq "ref_name == DFF"]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  chaining: sequential, then only the DFFs
    step 1: is_sequential == true              size 4   u_fifo u_fifo/u_ctrl u_fifo/u_ram u_alu/u_acc_reg
    step 2: ref_name == DFF                    size 2   u_fifo/u_ctrl u_alu/u_acc_reg

Seven to four to two. Each step has a size you can check, which makes a chain far easier to debug than a single expression that returned nothing — you can see which step emptied it.

3. Why not a loop?

You could write it yourself, and the registry's purpose is explicit that you should not:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set seq {}
foreach_in_collection c $all {
    if {[get_attribute $c is_sequential] eq "true"} { lappend seq $c }
}
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  manual loop result : u_fifo u_fifo/u_ctrl u_fifo/u_ram u_alu/u_acc_reg
  same as filter?    : 1

Same answer. Two reasons to prefer the filter anyway:

It is evaluated by the tool. The loop asks Tcl to iterate, call get_attribute once per object, compare in Tcl, and build a list. The filter hands one expression to the tool, which evaluates it against its own data structures. On seven cells the difference is nothing; on four million it is the difference between seconds and a coffee break.

It produces a collection, not a list. The loop above built a Tcl list, so the attributes are gone and the next step has to re-query. The filter's result is still a collection — chainable, countable, and usable anywhere a collection is.

That second reason is the one that bites in practice. A loop that converts to a list quietly ends your ability to keep filtering.

4. What the predicate can say

The mock supports == and != on an attribute. Real tools support more — numeric comparisons, pattern matches, existence tests — with the exact syntax varying.

Find yours the usual way, from the tool's reference (Chapter 17.6). What is consistent everywhere:

  • the left side is an attribute name,
  • the right side is a value,
  • and the whole thing is a string argument, which is why it needs quoting.

5. A filter that matches nothing

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  a filter that matches nothing:
  filter "ref_name == NOSUCHCELL"              size 0

Size 0, no error — the same silence as a query that matched nothing. Everything Chapter 18.8 says applies to filters too.

6. The typo that returns nothing

This one deserves its own section, because the two ways of reading an attribute disagree about mistakes.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set good [filter_collection $all "is_sequential == true"]
puts "    is_sequential == true   -> rc 0, size [sizeof_collection $good]"
set bad [filter_collection $all "is_sequental == true"]
puts "    is_sequental  == true   -> rc 0, size [sizeof_collection $bad]"

set obj [index_collection $all 0]
puts "    [catch {get_attribute $obj is_sequental} e] / $e"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  correct attribute name:
    is_sequential == true   -> rc 0, size 4
  MISSPELLED attribute name:
    is_sequental  == true   -> rc 0, size 0   <- no error, nothing matched

  get_attribute on the same typo DOES raise:
    1 / attribute 'is_sequental' not defined on 'u_fifo'

A malformed expression is caught, which is worth knowing so you do not assume all filter mistakes are silent:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  a malformed filter expression:
    1 / cannot parse filter expression: 'is_sequential'

The distinction: the tool checks the shape of the predicate, not whether the attribute exists.

7. The pattern worth keeping

A helper that makes every filter loud:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
proc need_filter {coll expr {what "objects"}} {
    set r [filter_collection $coll $expr]
    if {[sizeof_collection $r] == 0} {
        error "no $what matched '$expr'" {} [list DESIGN NOMATCH $expr]
    }
    return $r
}

set seq [need_filter [get_cells -hierarchical *] {is_sequential == true} "sequential cells"]

One line at the call site, and a typo or a wrong assumption now stops the script with a message naming the predicate that failed. This is the same shape as need_ports from Chapter 18.3 §7, and the same Chapter 14.11 discipline.

8. Exercises

Exercise 1. What does filter_collection take and return?

Exercise 2. Give two reasons to prefer it over a hand-written loop.

Exercise 3. Why does a loop that builds a list end your ability to keep filtering?

Exercise 4. Why must the predicate be quoted or braced?

Exercise 5. A filter on a misspelled attribute name — what happens, and how does that differ from get_attribute with the same typo?

Exercise 6. A malformed predicate like "is_sequential" — error or empty result?

Exercise 7. When is an empty filter result not a bug?

Where this fits

Part of the Tcl curriculum.