Quartus® II Tcl Example: Find a Timing Node

author-image

By

Nodes in the Quartus II timing netlist are referred to with IDs, which are positive integers. Every node has a name, the name in the post-fitting netlist. When you work with the timing netlist with commands in the ::quartus::advanced_timing package, it's common to search for a node based on its name. For example, you may want to trace the fanout of a particular I/O pin. To do that, you need to find the node ID that has the pin name you want to trace from. The following example procedure searches all timing nodes in the netlist for the name you specify and returns the ID of the matching node, or -1 if it does not exist.

package require ::quartus::advanced_timing

proc find { name } {
    
    foreach_in_collection node_id [get_timing_nodes -type all] {

        set node_name [get_timing_node_info -info name $node_id]
           
        if { [string equal $name $node_name ] } {
            return $node_id
        }
    }   
    
    return -1
}

In a Tcl script, you can call that procedure as shown in the following example:

set id [find clk_33MHz]
if { $id == -1 } {
    post_message -type warning "Couldn't find clock pin node"
}

Improving the Sample Code

There are a variety of ways the example code can be improved.

Add Wildcard Support & Multiple Returned IDs

Requiring an exact match becomes inconvenient for names with long hierarchy paths. Changing the example to support wildcard matches makes it easier to search for nodes with long hierarchy paths. With an additional modification to return multiple node IDs for all matches, you can use the script to return groups of node IDs. This makes it easier to iterate over all bits in a bus, for example.

Because a wildcard can match more than one name, it is necessary to support multiple returned IDs. An easy way to do that is to return a list of all node IDs with names that match the pattern. If no names match the pattern, an empty list is returned.

The following example searches all nodes in the timing netlist and returns a list with every node ID that has a name matching the pattern. This example uses Tcl glob-style matching, with support for asterisks (*), question marks (?), and square brackets ([]).

package require ::quartus::advanced_timing

proc find { pattern } {
    
    set return_ids {}
    foreach_in_collection node_id [get_timing_nodes -type all] {

        set node_name [get_timing_node_info -info name $node_id]
           
        if { [string match $pattern $node_name ] } {
            lappend return_ids $node_id
        }
    }   
    
    return $return_ids
}

Remember that Tcl uses square brackets to delimit characters to match in the string match command. Calling the find command as shown in the following example matches addr1 and addr0, not addr[10]!

set matches [find addr[10]]

Because bus names use square brackets to indicate individual bits, you should escape patterns with square brackets used as bus bit selectors. Calling the find command as shown in the following example, with the escape_brackets command, returns the node ID for the node named addr[10].

set matches [find [escape_brackets addr[10]]]

You should always use the escape_brackets command to escape patterns you pass into the find command unless you intend to use square brackets to indicate a character range to match.

Add Node-Type Filtering

You may want to restrict the kinds of nodes that are searched for a matching name. This can speed up the search in a design with a large timing netlist. You can use the -type option for the get_timing_nodes command to restrict the nodes in the returned collection to pins, registers, clocks, and various other types of nodes.

The following example builds on the previous example of pattern matching. If no pattern is specified, it defaults to *, to match everything. There is an option for restricting the node type, which defaults to all.

This example uses the cmdline Tcl package, included with the Quartus II software, to set up an easy way to pass arguments into the procedure in a self-documenting way.

package require ::quartus::advanced_timing
package require cmdline

proc find { args } {
    
    set options {\
        { "pattern.arg" "*" "Pattern to search for" } \
        { "type.arg" "all" "Node type to search" } \
    }
    array set opts [::cmdline::getoptions args $options]

    set return_ids {}
    foreach_in_collection node_id [get_timing_nodes -type $opts(type)] {

        set node_name [get_timing_node_info -info name $node_id]
           
        if { [string match $opts(pattern) $node_name ] } {
            lappend return_ids $node_id
        }
    }   
    
    return $return_ids
}

The following code shows some ways of using the previous example.

# Returns every node ID in the timing netlist.
# Pattern defaults to *
# Type defaults to all
find 

# Returns node IDs of all pins in the timing netlist
# Pattern defaults to *
find -type pin

# Returns node IDs of pins beginning with addr
find -pattern addr* -type pin

# Returns node IDs of registers in bit 0 of a bus
find -pattern [escape_brackets *[0]] -type reg]