Experimenting with SDC/Tcl wildcards: Quartus TimingQuest Timing Analyzer

This post was written by eli on November 9, 2013
Posted Under: FPGA,Intel FPGA (Altera),Tcl


There is a certain confusion regarding how wildcards are matched in the SDC file (in fact, by the Tcl commands), which is why full paths are often used. This causes overloaded SDC files that don’t survive changes in the hierarchy.

For example, regarding get_pins, the SDC and TimeQuest API Reference Manual page 2-15 states that pipe characters (“|”) are treated as special characters, and are therefore not matched against the “*” wildcard in the default mode. So by default, the full path has to be given, except for specific strings within hierarchies.

The -hierarchical flag somewhat helps by allowing relative names (skip the beginning of the path).

For a classic Tcl match, where ‘*’ can match a pipe character, use -compatibility_mode.

But what about get_clocks?


One significant advantage of Tcl scripting over Xilinx’ UCF is that one can try out the expressions in a Tcl shell. Some basics can be found in page 3-17 of the Quartus II Handbook, vol.1, chapter 3.

More inspiration can be taken from the examples in the SDC and TimeQuest API Reference Manual. It may also be helpful to look at the Quartus II Scripting Reference Manual.

From the command line, using the “-s” flag:

$ quartus_sta -s

After the welcome note, open the project (after fitting) and create a timing netlist:

tcl> project_open myproject
tcl> create_timing_netlist
tcl> read_sdc
tcl> update_timing_netlist

for effectively opening myproject.qsf. The two latter are required for get_clocks to work. One can go e.g.

tcl> get_clocks -long_help

to get some help (same text as in the manuals).

It’s possible to test what matches which command. For example, to list the PLL-derived clocks (based upon the signal’s name):

tcl> set mypins [ get_pins -compatibility_mode *|divclk ]
tcl> foreach_in_collection pin $mypins { puts [get_pin_info -name $pin] }

The Tcl shell will print something like “_col0″ in the middle to indicate that a collection has been set up. This collection is accessed through $mypins. The second command prints the matched pins to the console.

Or for those who prefer one-liners (all pins on top-level):

tcl> query_collection -all [ get_pins * ]

The “-all” flag overrides the default limit of 20 elements. To have each printed on a separate line,

tcl> foreach i [ query_collection -all [ get_pins -hierarchical * ] ] { puts "Pin: $i" }

The -hierarchical flag is important. Without it, only the toplevel pins are given (even for just [ get_pins ]). Counterintuitive, but nevertheless true. The -compatibility_mode flag is also fine (used a lot in this post) but is Quartus specific.

The counterpart for “-all” is “-limit 1″, which fetches only the first element.

So what about get_clocks?

Listing all clocks in the design on separate lines:

tcl> foreach i [ query_collection -all [ get_clocks ] ] { puts "$i" }

Or use foreach_in_collection:

tcl > foreach_in_collection i [ get_clocks ] { puts [ get_clock_info $i -name ] }

Note that get_clock_info can obtain information other than just the name.

Alternatively, use “join” instead of “foreach”:

tcl> join [ query_collection -all [ get_clocks ] ] "\n"

If nothing is printed, and instead it says

Warning (332173): Ignored filter: * could not be matched with a clock

it’s most likely because read_sdc and update_timing_netlist haven’t been issued, as mentioned above.

tcl> foreach i [ query_collection -all [ get_clocks *|vga_pll|*|divclk] ] { puts $i }

which, surprisingly enough worked in the convenient way: The wildcards matched pipe characters, so one can, in fact, use this simple format in SDC files, e.g.

set_false_path -from [get_clocks *|vga_pll|*|divclk] -to [get_clocks *|bus_pll|*|divclk]
set_false_path -from [get_clocks *|bus_pll|*|divclk] -to [get_clocks *|vga_pll|*|divclk]

for setting up false paths between two clocks that are derived from a common reference with PLLs, the wrong way.

The correct way is with set_clock_groups, but that’s not what this post is about… And by the way, Quartus doesn’t have a shortcut to include derived clocks in set_clock_groups, like in Vivado. So the PLLs’ output clocks must be named explicitly (but wildcards help).

Getting all kind of info

If we’re at it, all kind of info can be obtained on cells in the design. For example, the location of certain instances in the design (pins etc. can also be obtained with different parameters to get_cell_info):

foreach_in_collection cell [ get_cells -compatibility_mode *rx_pma.rx_cdr] { puts "[get_cell_info $cell -location ]: [get_cell_info $cell -name]" }

QSF scripting

Pointing at specific cells by virtue of expressions works within a script, but not in the QSF file. For example, this works as a script

set_instance_assignment -name CDR_BANDWIDTH_PRESET High -to [ get_cells -compatibility_mode *|xcvr_inst|*rx_pma.rx_cdr]

but fails in a QSF file.

It’s possible to retrieve the already existing assignments. Try

tcl> get_instance_assignment -help
tcl> get_all_assignments -long_help

The latter gives some interesting examples on scanning existing assignments. In particular, turning one of the examples into a (very long) one-liner, once can go

tcl> foreach_in_collection asgn_id [get_all_assignments -type instance -name *] { set from [get_assignment_info $asgn_id -from] ; set to [get_assignment_info $asgn_id -to] ; set name   [get_assignment_info $asgn_id -name] ; set value  [get_assignment_info $asgn_id -value] ; puts "$name ($from -> $to) = $value" }

in order to list all instance assignments (i.e. echo the QSF’s assignments).

Same for all global assignments (and there are many):

foreach_in_collection asgn_id [get_all_assignments -type global -name *] { set entity [get_assignment_info $asgn_id -entity] ; set name [get_assignment_info $asgn_id -name] ; set value  [get_assignment_info $asgn_id -value] ; puts "$entity: $name = $value" }

Not clear what it’s useful for, but anyhow

Add a Comment

required, use real name
required, will not be published
optional, your blog address