Report Levels of Logic

author-image

By

When you are closing timing on a design, it is often useful to know how many levels of logic are in failing paths. The Timing Analyzer displays the number of levels of logic when you report timing for a path, but there is no default report that lists the number of levels of logic for a set of paths. This design example defines a custom procedure you can use to create reports that show the number of levels of logic for sets of paths.

The custom procedure supports the same arguments as the report_timing command. You should use the same options with the custom procedure that you would with the report_timing command. The custom procedure also supports three additional options: -greater_than <value>, -less_than <value>, and -file <report file>. You can use the -greater_than and -less_than options to limit reporting to paths with greater than or less than the specified levels of logic. You can use the -file option to write the report to a file.

The custom procedure displays the numbers of levels of logic for the paths with the worst timing slack. It does not necessarily display the paths in the design with the largest number of levels of logic. The paths with the worst timing slack are not always the paths with the largest numbers of levels of logic, though that is often true.

Procedure Operation

The custom procedure uses the following steps.

  1. Get a list of paths that meet the reporting criteria
  2. Get the number of levels of logic for each path
  3. Display the number of levels of logic and path information in a chart

Step 1: Get a List of Paths

The custom procedure uses the get_timing_paths command, which supports the same arguments as the report_timing command. You can use any options for report_timing to control timing analysis. For example, you could restrict the report of the number of levels of logic to paths that end in a certain register name. The following Tcl code shows the procedure definition, and passes all arguments to the get_timing_paths command.

proc report_levels_of_logic { args } {
    
    # Pass all arguments straight to get_timing_paths
    if { [catch { eval get_timing_paths $args } paths_col] } {
        post_message -type error $paths_col
        return
    }
}

Step 2: Get the Number of Levels of Logic for Each Path

Use a loop to iterate over the path collection in the paths_col variable and extract the number of levels of logic in each path. Save information about the path in a Tcl matrix data structure that will be used to print out the results. The information that is saved is the number of levels of logic, the slack of the path, and the source and destination node names.

foreach_in_collection path_obj $paths_col {

        # How many levels of logic are there in the path?
        set levels_of_logic [get_path_info -num_logic_levels $path_obj]
        
        # Add the path information to a matrix.
        $logic_levels_matrix add row [list \
            $levels_of_logic \
            [get_path_info -slack $path_obj] \
            [get_node_info -name [get_path_info -from $path_obj]] \
            [get_node_info -name [get_path_info -to $path_obj]] ]
    }

Step 3: Display Path Information in a Chart

Finally, display all the path information stored in the matrix variable. This example uses the Tcl report package to format the matrix to print it out. The following code adds a heading row to the matrix, defines the visual style of the report, sets the cell padding, and displays the report.

# Put in the header row
        $logic_levels_matrix insert row 0 \
            [list "Levels of logic" "Slack" "From" "To"]
    
        # We need a style defined to print out the table of results
        catch { ::report::rmstyle basicrpt }
        ::report::defstyle basicrpt {{cap_rows 1}} {
            data        set [split "[string repeat " "   [columns]];"]
            top         set [split "[string repeat "+ - " [columns]]+"]
            bottom      set [top get]
            topcapsep   set [top get]
            topdata     set [data get]
            top         enable
            topcapsep   enable
            bottom      enable
            tcaption    $cap_rows
        }
        
        # Create the report, set the columns to have one space of padding, and
        # print out the matrix with the specified format
        catch { r destroy }
        ::report::report r 4 style basicrpt
        for { set col 0 } { $col < [r columns]} { incr col } {
            r pad $col both " "
        }
        post_message "Levels of logic\n[r printmatrix $logic_levels_matrix]"

Custom Procedure

The code for the custom procedure listed below includes options to write the report to a file, and to limit the paths reported unless the number of levels of logic is greater than or less than user-specified values.

These are some examples of how you can use the custom procedure.

  • report_levels_of_logic -setup -greater_than 10 -to [get_registers data*] -npaths 1000
  • report_levels_of_logic -hold -from_clock core_50 -npaths 50 -file levels.txt

To use the custom procedure, save the Tcl code below in a file named report_levels_of_logic.tcl. Then use the command source report_levels_of_logic.tcl at the Timing Analyzer Tcl prompt. Sourcing the file defines the custom procedure. You can then use the newly-defined command report_levels_of_logic until you exit the Timing Analyzer.

package require cmdline
package require struct::matrix
package require report

proc report_levels_of_logic { args } {

    set options {
        { "less_than.arg" "" "Limit to paths with less than this number" }
        { "greater_than.arg" "" "Limit to paths with greater than this number" }
        { "file.arg" "" "Output file name" }
        
    }
    array set opts [::cmdline::getKnownOptions args $options]

    # Ensure that the procedure is called with some arguments
    if { [string equal "" $opts(less_than)] && [string equal "" $opts(greater_than)] } {
        post_message -type warning "You must specify a numeric value\
            for -less_than or -greater_than"
        return
    }
    
    # Ensure that the procedure is called with numeric argument values
    if { ![string is double $opts(less_than)] } {
        post_message -type warning "You must specify a numeric value\
            for -less_than"
        return
    }
    if { ![string is double $opts(greater_than)] } {
        post_message -type warning "You must specify a numeric value\
            for -greater_than"
        return
    }
    
    # Create a matrix to hold information about the failing paths
    set logic_levels_matrix [::struct::matrix]
    $logic_levels_matrix add columns 4

    # Pass all unknown arguments straight to get_timing_paths
    if { [catch { eval get_timing_paths $args } paths_col] } {
        post_message -type error $paths_col
        return
    }
    
    # Walk through the list of timing paths, getting information
    # about the levels of logic
    foreach_in_collection path_obj $paths_col {
    
        # Assume the path will be reported, unless the number of levels of
        # logic is outside the specified bounds.
        set include_path 1
        
        # How many levels of logic are there in the path?
        set levels_of_logic [get_path_info -num_logic_levels $path_obj]
        
        # If we specified a lower bound, we do not report the path if the
        # levels of logic are greater than or equal to the lower bound
        if { ! [string equal "" $opts(less_than)] } {
            if { $levels_of_logic >= $opts(less_than) } {
                set include_path 0
            }
        }
        
        # If we specified an upper bound, we do not report the path if the
        # levels of logic are less than or equal to the upper bound
        if { ! [string equal "" $opts(greater_than)] } {
            if { $levels_of_logic <= $opts(greater_than) } {
                set include_path 0
            }
        }
        
        # If the path has levels of logic that fall within our bounds,
        # report on it
        if { $include_path } {
        
            $logic_levels_matrix add row [list \
                $levels_of_logic \
                [get_path_info -slack $path_obj] \
                [get_node_info -name [get_path_info -from $path_obj]] \
                [get_node_info -name [get_path_info -to $path_obj]] ]
        }
    }
    # Finished going through all the paths from get_timing_paths
    
    # If there are any rows in the matrix, paths match the criteria.
    # We have to print out the table with that information.
    if { 0 == [$logic_levels_matrix rows] } {
    
        # No paths meet the criteria
        # Print out a quick message
        post_message "No paths meet the criteria to report levels of logic"
        
        # If there is an error opening the file, print a message saying
        # that. Otherwise, say there are no paths meeting the criteria
        if { ! [string equal "" $opts(file)] } {
            if { [catch { open $opts(file) w } fh] } {
                post_message -type error "Couldn't open file: $fh"
            } else {
                puts $fh "No paths meet the criteria to report levels of logic"
                catch { close $fh }
            }
        }
    
    } else {
    
        # Put in the header row
        $logic_levels_matrix insert row 0 \
            [list "Levels of logic" "Slack" "From" "To"]
    
        # We need a style defined to print out the table of results
        catch { ::report::rmstyle basicrpt }
        ::report::defstyle basicrpt {{cap_rows 1}} {
            data        set [split "[string repeat " "   [columns]];"]
            top         set [split "[string repeat "+ - " [columns]]+"]
            bottom      set [top get]
            topcapsep   set [top get]
            topdata     set [data get]
            top         enable
            topcapsep   enable
            bottom      enable
            tcaption    $cap_rows
        }
        
        # Create the report, set the columns to have one space of padding, and
        # print out the matrix with the specified format
        catch { r destroy }
        ::report::report r 4 style basicrpt
        for { set col 0 } { $col < [r columns]} { incr col } {
            r pad $col both " "
        }
        post_message "Levels of logic\n[r printmatrix $logic_levels_matrix]"
        
        # Save the report to a file if a file name is specified
        if { ! [string equal "" $opts(file)] } {
            if { [catch { open $opts(file) w } fh] } {
                post_message -type error "Couldn't open file: $fh"
            } else {
                puts $fh "Levels of logic"
                r printmatrix2channel $logic_levels_matrix $fh
                catch { close $fh }
            }
        }
    }
}