Quartus® II Tcl Example: Report Levels of Logic

author-image

By

When you are optimizing a design, it is useful to view information about levels of logic between registers. The following script generates a Comma Separated Value (.csv) file with the number of paths with different levels of logic in your design. You can chart this data or create a histogram in Excel showing the distribution of paths by levels of logic.

If two registers have multiple logic paths between them, only the path with the most levels of logic is counted by this script. For example, two registers with one four-level and one two-level path would be counted as one four-level path.

The script generates a CSV file named <revision name>.levels_of_logic.csv.

Assuming you save the script in a file named report_levels_of_logic.tcl, you can run it with the following command:

quartus_tan -t report_levels_of_logic.tcl -project <project name> [-revision <revision name>] [-name_pattern <string to match>]

You can use the -name_pattern option to restrict path counting to a specific hierarchy in your design. Specify a string to match with tool command language (Tcl) wildcard matching. If you do not specify a value for the -name_pattern option, it defaults to *. For example, if you want to report levels of logic between registers in the mult:inst6|lpm_mult:lpm_mult_component hierarchy of your design, specify mult:inst6|lpm_mult:lpm_mult_component* for the value of the -name_pattern option.

load_package advanced_timing
package require cmdline

set options {\
    { "project.arg" "" "Project name" } \
    { "revision.arg" "" "Revision name" } \
    { "name_pattern.arg" "*" "Restrict to registers matching this pattern"}
}

array set opts [::cmdline::getoptions quartus(args) $options]
array set num_levels [list]

# Open the project and get the revision name
if { [string equal "" $opts(revision)] } {
    project_open $opts(project) -current_revision
} else {
    project_open $opts(project) -revision $opts(revision)
}
set rev [get_current_revision]

# Prepare the timing netlist
if { [catch { create_timing_netlist; create_p2p_delays } res] } {
    post_message -type error $res
    project_close
    qexit -error
}

# Iterate through every register in the design
foreach_in_collection dest [get_timing_nodes -type reg] {

    # Get a list of keepers (registers, pins, clocks)
    # that feed to the register node
    set delays_from_keepers [get_delays_from_keepers $dest]
    
    # If the destination register name doesn't match the pattern,
    # simply go on to the next one.
    set dest_name [get_timing_node_info -info name $dest]
    if { ! [string match $opts(name_pattern) $dest_name] } {
        continue
    }
    # Walk through all keepers feeding the register node
    foreach delay $delays_from_keepers {

        set src [lindex $delay 0]

        # Keeper can include pins and clocks, and we want only  registers.
        if { ! [string equal "reg" [get_timing_node_info -info type $src]] } {
            continue
        }

        # If the source register name doesn't match the pattern,
        # simply go on to the next one
        set src_name [get_timing_node_info -info name $src]
        if { ! [string match $opts(name_pattern) $src_name] } {
            continue
        }

        # At this point, both the source and destination names
        # match the pattern, and it's a register-to-register path.
        # The get_delay_path command returns a list of nodes on
        # a path. The length of the path is the length of the list.
        # The list includes the source and destination registers,
        # so the levels of logic between registers is
  
  


- 2
        set path [get_delay_path -type longest -from $src -to $dest]
        set levels_of_logic [expr { [llength $path] - 2 } ]
        
        # Save the information in an array
        if { [info exists num_levels($levels_of_logic)] } {
            incr num_levels($levels_of_logic)
        } else {
            set num_levels($levels_of_logic) 1
        }
    }
}

project_close

# Write the information out to a file
if { [catch {open ${rev}.levels_of_logic.csv w} fh] } {
    post_message -type error $fh
} else {

    # Write a descriptive header into the file
    puts $fh "Levels of logic for project $opts(project) revision $rev"
    puts $fh "File generated by Quartus® II $quartus(version) on \
        [clock format [clock seconds]]"
    puts $fh "\nReporting paths for register names matching $opts(name_pattern)"
    puts $fh "Levels of logic,Number in design"

    foreach level [lsort -integer [array names num_levels]] {

        if { [catch { puts $fh "$level,$num_levels($level)" } res] } {
            post_message -type error $res
            break
        }
    }
    catch { close $fh }
}