Friday, June 19, 2009

SDC: Get Clocks Feeding a Pin

From Altera

Get Clocks Feeding a Pin

This design example shows a custom procedure, which you can use in SDC files, that returns a list of all clocks that feed a pin. The procedure can be helpful if you need to create generated clocks without knowing other clock names in a design.

The full code for the procedure is at the bottom of this page, following a complete explanation of how the procedure works. To use the get_clocks_driving_pins custom procedure in an SDC file, ensure the procedure has been defined, then call it like any other SDC command. There are two easy ways to ensure the procedure has been defined before use:

  • Save the procedure code in a separate SDC file and include the SDC file in the project
  • Copy and paste the procedure code at the top of any SDC file, before the get_clocks_driving_pins custom procedure is used

Separate SDC File

Saving the procedure code in a separate SDC file keeps the code separate from the rest of your constraints and makes it simpler to reuse in other projects. If you use a separate SDC file, you must add the SDC file with the procedure to the list of files in the project, and it must appear above any SDC files that use the procedure. Listing it above other SDC files ensures that the Quartus® II software defines the procedure before using it, whenever SDC files are read.

Copy and Paste

Copying and pasting the procedure code in the same SDC file where it is used results in fewer SDC files in a project. If you are creating an SDC file for a module that will be reused by other designers, it may be simplest to include all constraints and supporting code in a single SDC file. You must include the procedure code in the SDC file before the first use of the procedure so it is defined before use. Typically, you would put it at the top of the file to satisfy this requirement.

Script Operation

Getting a list of all clocks in a design that feed a pin takes three main steps:

  1. Get all clocks and create a mapping from their target nodes to the clocks on the target nodes.
  2. Get a list of nodes with clocks on them that are on the fanin path to the specified pin.
  3. From that list of nodes, find the node closest to the specified pin and return the clocks on that node.

Step 1. Get all Clocks and Create Mapping

The following Tcl code gets all clocks in the design and creates the mapping (with a Tcl array) from a node to the clocks on the node.

catch { array unset nodes_with_clocks }
array set nodes_with_clocks [list]

# Iterate over each clock in the design
foreach_in_collection clock_id [all_clocks] {

set clock_name [get_clock_info -name $clock_id]

# Each clock is applied to nodes. Get the collection of target nodes
foreach_in_collection target_id [get_clock_info -targets $clock_id] {

# Associate the clock name with its target node
set target_name [get_node_info -name $target_id]
lappend nodes_with_clocks($target_name) $clock_name
}
}

Virtual clocks have no targets, so no mapping is ever made with a virtual clock. In the full procedure code listed below, information about the type of the target nodes (register, pin, cell, or port) is saved for later use.

Step 2. Get Nodes with Clocks in Fanin Path

The second step is to find the subset of nodes with clocks that are on the fanin path to the specified pin. For each node with clocks (found in step 1), get the fanin to the specified pin through the node. If there is a fanin, the node is in the fanin path to the pin. If there is no fanin, the node is not on the fanin path to the pin.

The following Tcl code iterates through all nodes with clocks from step 1 and uses the get_fanins command to determine whether each node is on the fanin path of the specified pin. If the node is on the fanin path of the specified pin, the node is saved in the pin_drivers list.

set pin_drivers [list]

# Iterate over all nodes in the mapping created in step 1
foreach node_with_clocks [array names nodes_with_clocks] {

# Get any fanins to the specified pin through the current node
set fanin_col [get_fanins -clock -through $node_with_clock $pin_name]

# If there is at least one fanin node, the current node is on the
# fanin path to the specified pin, so save it.
if { 0 < [get_collection_size $fanin_col] } { lappend pin_drivers $node_with_clocks } }

The full procedure code listed below uses additional information about the node type to specify a type-specific collection for the -through value in the get_fanins command.

Step 3. Find Node Closest to Specified Pin

The pin_drivers variable now has a list of all the nodes with clocks that are on the fanin path to the specified pin. This step finds the node closest to the specified pin. While there is more than one node in the pin_drivers list, the code takes the first two nodes in the list and checks whether one is on the fanin path to the other. If it is on the fanin path, the first node must be further away from the pin than the second node, so it can be removed from the list.

while { 1 < [llength $pin_drivers] } {     # Get the first two nodes in the pin_drivers list    set node_a [lindex $pin_drivers 0]    set node_b [lindex $pin_drivers 1]     # Check whether node_b is on the fanin path of node_a    set fanin_col [get_fanins -clock -through $node_b $node_a]     # If there is at least one fanin node, node_b must be further    # away from the specified pin than node_a is.    # If there is no fanin node, node_b must be closer to the    # specified pin than node_a is.    if { 0 < [get_collection_size] } {         # node_a is closer to the pin.        # Remove node_b from the pin_drivers list        set pin_drivers [lreplace $pin_drivers 1 1]     } else {         # node_b is closer to the pin.        # Remove node_a from the pin_drivers list        set pin_drivers [lreplace $pin_drivers 0 0]    } }  # The one node left in pin_drivers is the node driving the specified pin set node_driving_pin [lindex $pin_drivers 0]  # Look up the clocks on the node in the mapping from step 1 and return them return $nodes_with_clocks($node_driving_pin 

The full procedure code listed below uses additional information about the node type to specify a type-specific collection for the -through value in the get_fanins command.

Full Procedure Code

The complete code for the get_clocks_driving_pin custom procedure is listed below. It includes additional error checking and support features that are not described in detail above.

proc get_clocks_feeding_pin { pin_name } {

# Before step 1, perform an error check to ensure that pin_name
# passed in to the procedure matches one and only one pin.
# Return an error if it does not match one and only one pin.
set pin_col [get_pins -compatibility_mode $pin_name]
if { 0 == [get_collection_size $pin_col] } {
return -code error "No pins match $pin_name"
} elseif { 1 < [get_collection_size $pin_col] } { return -code error "$pin_name matches [get_collection_size $pin_col]\ pins but must match only one" } # Initialize variables used in the procedure catch { array unset nodes_with_clocks } catch { array unset node_types } array set nodes_with_clocks [list] array set node_types [list] set pin_drivers [list] # Step 1. Get all clocks in the design and create a mapping from # the target nodes to the clocks on the target nodes # Iterate over each clock in the design foreach_in_collection clock_id [all_clocks] { set clock_name [get_clock_info -name $clock_id] set clock_target_col [get_clock_info -targets $clock_id] # Each clock is applied to nodes. Get the collection of target nodes foreach_in_collection target_id [get_clock_info -targets $clock_id] { # Associate the clock name with its target node set target_name [get_node_info -name $target_id] lappend nodes_with_clocks($target_name) $clock_name # Save the type of the target node for later use set target_type [get_node_info -type $target_id] set node_types($target_name) $target_type } } # Step 2. Get a list of nodes with clocks on them that are on the # fanin path to the specified pin # Iterate over all nodes in the mapping created in step 1 foreach node_with_clocks [array names nodes_with_clocks] { # Use the type of the target node to create a type-specific # collection for the -through value in the get_fanins command. switch -exact -- $node_types($node_with_clocks) { "pin" { set through_col [get_pins $node_with_clocks] } "port" { set through_col [get_ports $node_with_clocks] } "cell" { set through_col [get_cells $node_with_clocks] } "reg" { set through_col [get_registers $node_with_clocks] } default { return -code error "$node_types($node_with_clocks) is not handled\ as a fanin type by the script" } } # Get any fanins to the specified pin through the current node set fanin_col [get_fanins -clock -through $through_col $pin_name] # If there is at least one fanin node, the current node is on the # fanin path to the specified pin, so save it. if { 0 < [get_collection_size $fanin_col] } { lappend pin_drivers $node_with_clocks } } # Before step 3, perform an error check to ensure that at least one # of the nodes with clocks in the design is on the fanin path to # the specified pin. if { 0 == [llength $pin_drivers] } { return -code error "Can not find any node with clocks that drives $pin_name" } # Step 3. From the list of nodes created in step 2, find the node # closest to the specified pin and return the clocks on that node. while { 1 < [llength $pin_drivers] } { # Get the first two nodes in the pin_drivers list set node_a [lindex $pin_drivers 0] set node_b [lindex $pin_drivers 1] # Use the type of the target node to create a type-specific # collection for the -through value in the get_fanins command. switch -exact -- $node_types($node_b) { "pin" { set through_col [get_pins $node_b] } "port" { set through_col [get_ports $node_b] } "cell" { set through_col [get_cells $node_b] } "reg" { set through_col [get_registers $node_b] } default { return -code error "$node_types($node_b) is not handled\ as a fanin type by the script" } } # Check whether node_b is on the fanin path of node_a set fanin_col [get_fanins -clock -through $through_col $node_a] # If there is at least one fanin node, node_b must be further # away from the specified pin than node_a is. # If there is no fanin node, node_b must be closer to the # specified pin than node_a is. if { 0 < [get_collection_size $fanin_col] } { # node_a is closer to the pin. # Remove node_b from the pin_drivers list set pin_drivers [lreplace $pin_drivers 1 1] } else { # node_b is closer to the pin # Remove node_a from the pin_drivers list set pin_drivers [lrange $pin_drivers 1 end] } } # The one node left in pin_drivers is the node driving the specified pin set node_driving_pin [lindex $pin_drivers 0] # Look up the clocks on the node in the mapping from step 1 and return them return $nodes_with_clocks($node_driving_pin) }

Simplify Design Reuse with Dynamic SDC Constraints

Simplify Design Reuse with Dynamic SDC Constraints

When you create a design block or HDL component that can be reused in many designs, it may be necessary to create SDC constraints to go with it. It is useful to create constraints that don't require editing by the designer reusing the component. Constraints should be generic, so they work regardless of where the block is instantiated in the design hierarchy, and dynamic so they work regardless of how the design block is connected. If constraints must be manually edited to reflect design changes, they will become out of sync if the designer makes design changes without also updating the constraints.

This design example covers techniques for creating dynamic SDC constraints that address the following two issues:

  • Determining the name of a top-level I/O connected directly to a low-level module
  • Creating generated clocks on logic in low-level modules

The diagram in Figure 1 shows a very simple design for this example. It includes two instances of a reusable design block named reusable_block, shown in yellow. Figure 2 shows the contents of the reusable_block design. reusable_block functions as a double data rate clock for a source-synchronous output bus. Its output must be connected to a top-level output. Constraints for reusable_block must include generated clocks, because the output functions as a source-synchronous clock.

Figure 1. Sample Circuit for Design Example

Figure 1. Simplify Design Reuse with Dynamic SDC Constraints

Figure 2. Contents of reusable_block

Figure 2. Simplify Design Reuse with Dynamic SDC Constraints

Determining Top-Level I/O Names

Constraints for reusable_block must accommodate changes to top-level I/O names. Therefore, the top-level I/O name must be determined during compilation or timing analysis. The get_fanouts Tcl command returns a collection of IDs representing ports or registers that are fanouts of a specified name. The get_fanouts Tcl command uses a timing netlist that exists during compilation or timing analysis, so it dynamically determines the connectivity regardless of the names of the fanout nodes. The following Tcl code shows how to use get_fanouts to get the top-level output that is a direct fanout of a low-level register.

foreach_in_collection fanout_id [get_fanouts $low_level_register_name] { break }
set top_level_io_name [get_node_info -name $fanout_id]

The full hierarchy name of the low-level register does not have to be known, because you can use a wildcard and a known portion of the hierarchy that exists in the reusable design block to match it. The last code example on this page shows an example of how to match the low-level register name.

In the design in Figure 1, the low-level module output pin is connected directly to one top-level output. The following Tcl code adds error checking to ensure that the low-level register fans out to only one location and that the fanout location is an output port. This Tcl code should be part of the SDC file that constrains reusable_block.

# Get the fanouts of the low-level register
set fanout_collection [get_fanouts $low_level_register_name]

# Ensure there is only one fanout
set num_fanouts [get_collection_size $fanout_collection]
if { 1 != $num_fanouts } {
return -code error "$low_level_register_name fans out to $num_fanouts \
nodes but must fan out to one."
}

# Get the name of the fanout node
foreach_in_collection fanout_id $fanout_collection { break }
set fanout_name [get_node_info -name $fanout_id]

# Ensure the fanout node is an output port
if { [catch { get_port_info -is_output_port $fanout_id } is_output] } {
# There was an error - it does not fan out to a port
return -code error "$low_level_register_name fans out to $fanout_name \
which is not a port"
} elseif { ! $is_output } {
# There is no error, but the port is not an output port
return -code error "$fanout_name is not an output port"
} else {
set top_level_io_name $fanout_name
}

# top_level_io_name is the only fanout of low_level_register_name and it is
# an output port

Creating Generated Clocks

A source-synchronous output clock must be defined as a generated clock, based on the clock that feeds the double data rate output registers. The generated clock must be created without any manually entered information about clocks in the design, because the design block could be instantiated in any design with any clocking scheme.

The following SDC command shows a simple way to create a generated clock for the source-synchronous output clock for the design in Figure 1, when the location in the hierarchy is not known.

create_generated_clock -name reusable_generated -source [get_pins \
*|reusable_block_clock_out|altddio_out_component|auto_generated|ddio_outa[0]|muxsel] \
$top_level_io_name

It is a straightforward approach that works for a single instantiation of reusable_block anywhere in the design hierarchy, but it does not handle multiple instantiations or multiclock situations. When the clocking scheme is unknown, the generated clock constraint should be able to handle situations where multiple clocks have been defined on a single clock signal that feeds the design block. Multiple clocks on a single clock signal often exist in designs that support different I/O protocol speeds, or designs that support clock switchover for redundancy. The simple generated clock example above fails in multiclock situations because it does not include the
-master_clock option to distinguish between multiple source clocks.

To handle multiple instantiations, use a loop to create unique generated clocks for each instantiation. To handle multiclock situations, use a custom procedure called get_clocks_driving_pin, described in the Clocks Feeding a Pin design example. To use the custom procedure, you must copy it from the Clocks Feeding a Pin design example page. You can save it as a separate SDC file that is added to the project, or copy and paste it into one SDC file with all other constraints that constrain a reusable block. If you save it as an SDC file that is added to the project, ensure it is listed before any SDC file that uses the get_clocks_driving_pin custom procedure.

The following Tcl code shows how to create generated clock constraints on top-level outputs driven by low-level registers in the design shown in Figure 1. The generated clocks use the top-level outputs as their targets, and the muxsel pins of altddio_output registers as their sources. The code uses a loop to iterate through all the instantiations of reusable_block in the design, and a nested loop to handle multiclock situations with the get_clocks_driving_pin custom procedure. It assumes the get_clocks_driving_pin procedure has been defined already.

# get_pins returns one muxsel pin for each instantiation of reusable_block
# foreach_in_collection iterates over each muxsel pin
foreach_in_collection pin_id [get_pins -compatibility_mode \
*|reusable_block_clock_out|altddio_out_component|auto_generated|ddio_outa[0]|muxsel] {

# pin_name has the full design hierarchy of the muxsel pin for one
# instantiation of reusable_block
set pin_name [get_node_info -name $pin_id]

# Use the code shown above, without error checking, to get
# the name of the top level output
foreach_in_collection port_id [get_fanouts $pin_name] { break }
set port_name [get_node_info -name $port_id]

# There can be multiple clocks feeding the altddio_output register
# One generated clock is required for each clock that feeds
# a muxsel pin. Each clock feeding the muxsel pin is a master clock.
foreach master_clock [get_clocks_feeding_pin $pin_name] {

post_message "Creating generated clock on $port_name fed by $pin_name"
# Create the generated clock with the appropriate master clock.
# The source is the muxsel pin of the altddio_output cell in
# the current instantiation of reusable_block.
# The name is a combination of the master clock and the
# full hierarchy name of the muxsel pin.
# The target is the top-level port that is the fanout of the muxsel pin.
create_generated_clock -add -master_clock $master_clock \
-source [get_pins $pin_name] -name ${master_clock}-${pin_name} \
[get_ports $port_name]
}
}

With this code in an SDC file included in the project, all instantiations of reusable_block are automatically constrained with generated clocks. The generated clocks are always correct and up to date, even in the following situations:

  • reusable_block is instantiated at or moved to other points in the design hierarchy
  • Top-level I/Os are renamed
  • The designer uses multiple clock definitions in the design

Wednesday, June 10, 2009

Wildcard Assignments and Collections in Quartus Timequest

To simplify the task of applying constraints to many nodes in a design, the Quartus II
TimeQuest Timing Analyzer accepts the “*” and “?” wildcard characters. Use these
wildcard characters to reduce the number of individual constraints you must specify
in your design.
The “*” wildcard character matches any string. For example, given an assignment
made to a node specified as reg*, the Quartus II TimeQuest Timing Analyzer
searches for and applies the assignment to all design nodes that match the prefix reg
with none, one, or several characters following, such as reg1, reg[2], regbank, and
reg12bank.
The “?” wildcard character matches any single character. For example, given an
assignment made to a node specified as reg?, the Quartus II TimeQuest Timing
Analyzer searches and applies the assignment to all design nodes that match the
prefix reg and any single character following; for example, reg1, rega, and reg4.
Both the collection commands get_cells and get_pins have three options that
allow you to refine searches that include the wildcard character. To refine your search
results, select the default behavior, the -hierarchical option, or the
-compatibility option.
Example 7–58. Setting Operating Conditions with a Tcl Object
set_operating_conditions 4_slow_1100mv_85c
Chapter 7: The Quartus II TimeQuest Timing Analyzer 7–77
Timing Analysis Features
© March 2009 Altera Corporation Quartus II Handbook Version 9.0 Volume 3: Verification
1 The pipe character is used to separate one hierarchy level from the next in the
Quartus II TimeQuest Timing Analyzer. For example, | represents a hierarchical pin name with the “|” separating the hierarchy from
the pin name.
When you use the collection commands get_cells and get_pins without an
option, the default search behavior is performed on a per-hierarchical level of the pin
name; that is, the search is performed level by level. A full hierarchical name may
contain multiple hierarchical levels where a “|” is used to separate the hierarchical
levels, and each wildcard character represents only one hierarchical level. For
example,”*” represents the first hierarchical level and “*|*” represents the first and
second hierarchical levels.
When you use the collection commands get_cells and get_pins with the
-hierarchical option, a recursive match is performed on the relative hierarchical
path name of the form |. The search is performed on the
node name; for example, the last hierarchy of the name and not the hierarchy path.
Unlike the default behavior, this option does not limit the search to each hierarchy
level represented by the pipe character.
1 The pipe character cannot be used in the search with the get_cells
-hierarchical option. However, the pipe character can be used with the
get_pins collection search.
When you use the collection commands get_cells and get_pins with the
-compatibility option, the search performed is similar to that of the Quartus II
Classic Timing Analyzer. This option searches the entire hierarchical path and pipe
characters are not treated as special characters.
Assuming the following cells exist in a design:
foo
foo|bar
and the following pin names:
foo|dataa
foo|datab
foo|bar|datac
foo|bar|datad
Table 7–53 shows the results of using these search strings.
Table 7–53. Sample Search Strings and Search Results (Part 1 of 2)
Search String Search Result
get_pins *|dataa foo|dataa
get_pins *|datac
get_pins *|*|datac foo|bar|datac
get_pins foo*|* foo|dataa, foo|datab
get_pins -hierarchical *|*|datac (1)
get_pins -hierarchical foo|* foo|dataa, foo|datab
get_pins -hierarchical *|datac foo|bar|datac
get_pins -hierarchical foo|*|datac (1)
7–78 Chapter 7: The Quartus II TimeQuest Timing Analyzer
Timing Analysis Features
Quartus II Handbook Version 9.0 Volume 3: Verification © March 2009 Altera Corporation
Resetting a Design
Use the reset_design command to remove all timing constraints and exceptions
from the design under analysis. The command removes all clocks, generated clocks,
derived clocks, input delays, output delays, clock latency, clock uncertainty, clock
groups, false paths, multicycle paths, min delays, and max delays.
This command provides a convenient way to return to the initial state of analysis
without the need to delete and re-create a new timing netlist.
Cross-Probing
The cross-probing feature allows you to locate paths and elements from the
TimeQuest Timing Analyzer to various tools available in the Quartus II software (and
vice versa).
From the TimeQuest GUI, you can right-click any path in the View pane and select
either Locate Path or Locate.
The source is the element in the From Node column and the destination is the element
in the To Node column.
The Locate Path option allows you to located the data arrival path, default, of the
currently selected row. To locate the data required time path select a row in the data
required path panel.
1 The Locate Required Path command is available only when there is a path to show;
unless the user reports the clock path as well, there is probably only a single node in
the required path. In this case, the command is not available.
The Locate option allows you to locate the highlighted element.
The Locate Path and Locate commands can cross-probe to either the Chip Planner,
Technology Map Viewer, or Resource Property Editor. Additionally, the Locate Path
option can cross-probe to Critical Path Settings.
From the Critical Path Settings dialog box in the Chip Planner, you can cross-probe to
the TimeQuest Timing Analyzer to report critical paths in the design.
locate
Use the locate command in the Console pane to cross-probe to the Chip Editor,
Critical Path Settings, Resource Property Editor, and the Technology Map Viewer.
get_pins -compatibility *|datac foo|bar|datac
get_pins -compatibility *|*|datac foo|bar|datac
Note to Table 7–53:
(1) Due to the additional *|*| in the search string, the search result is

Testing

Testing my first blog