0% found this document useful (0 votes)
72 views

Write Path Summary

This document describes the version history of a Tcl script called write_path_summary.tcl that generates customizable summary tables for collections of timing paths. It has gone through several versions with fixes and enhancements, such as adding new timing metrics and handling unconstrained paths, based on feedback from other engineers.

Uploaded by

Amarnath Reddy
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
72 views

Write Path Summary

This document describes the version history of a Tcl script called write_path_summary.tcl that generates customizable summary tables for collections of timing paths. It has gone through several versions with fixes and enhancements, such as adding new timing metrics and handling unconstrained paths, based on feedback from other engineers.

Uploaded by

Amarnath Reddy
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 12

# write_path_summary.

tcl
# writes customizable summary table for a collection of paths
#
# v1.0 chrispy 04/02/2004
# initial release
# v1.1 chrispy 05/12/2004
# added startpoint/endpoint clock latency, clock skew, CRPR
# (thanks to John S. for article feedback!)
# v1.2 chrispy 06/15/2004
# changed net/cell delay code to work in 2003.03
# (thanks John Schritz @ Tektronix for feedback on this!)
# v1.3 chrispy 08/31/2004
# fixed append_to_collection bug (again, thanks to John Schritz @
Tektronix!)
# v1.4 chrispy 03/26/2006
# fixed handling of unconstrained paths
# v1.5 chrispy 09/01/2006
# fixed slowest_cell reporting (thanks Pradeep @ OpenSilicon!)
# v1.6 chrispy 11/17/2010
# fix harmless warning when a path has no cells (ie, feedthrough)
# fix harmless warning when a path has no startpoint or endpoint
clock
# v1.7 chrispy 01/31/2012
# rename total_xtalk as total_xtalk_data
# add total_xtalk_clock, total_xtalk (clock+data)
namespace eval path_summary {
set finfo(index) {int {index number of path in original path
collection (0, 1, 2...)} {{index} {#}}}
set finfo(startpoint) {string {name of path startpoint} {{startpoint}
{name}}}
set finfo(endpoint) {string {name of path endpoint} {{endpoint}
{name}}}
set finfo(start_clk) {string {name of startpoint launching clock}
{{startpoint} {clock}}}
set finfo(end_clk) {string {name of endpoint capturing clock}
{{endpoint} {clock}}}
set finfo(launch_latency) {real {launching clock latency} {{launch}
{latency}}}
set finfo(capture_latency) {real {capturing clock latency} {{capture}
{latency}}}
set finfo(skew) {real {skew between launch/capture clock (negative is
tighter)} {{clock} {skew}}}
set finfo(crpr) {real {clock reconvergence pessimism removal amount}
{{CRPR} {amount}}}
set finfo(path_group) {string {path group name} {{path} {group}}}
set finfo(slack) {real {path slack} {{path} {slack}}}
set finfo(duration) {real {combinational path delay between
startpoint and endpoint} {{path} {duration}}}
set finfo(levels) {real {levels of combinational logic} {{levels} {of
logic}}}

set finfo(hier_pins) {int {number of hierarchy pins in path} {{#


hier} {pins}}}
set finfo(num_segments) {int {number of segments in path} {{#}
{segments}}}
set finfo(num_unique_segments) {int {number of unique segments in
path} {{# unique} {segments}}}
set finfo(num_segment_crossings) {int {number of segment crossings in
path} {{# segment} {crossings}}}
set finfo(average_cell_delay) {real {average combinational cell delay
(duration / levels)} {{average} {cell delay}}}
set finfo(slowest_cell) {string {name of slowest cell in path}
{{slowest} {cell}}}
set finfo(slowest_cell_delay) {real {cell delay of slowest cell in
path} {{slowest} {cell delay}}}
set finfo(slowest_net) {string {name of slowest net in path}
{{slowest} {net}}}
set finfo(slowest_net_delay) {real {net delay of slowest net in path}
{{slowest} {net delay}}}
set finfo(slowest_net_R) {real {resistance of slowest net in path}
{{slowest} {net R}}}
set finfo(slowest_net_C) {real {capacitance of slowest net in path}
{{slowest} {net C}}}
set finfo(total_net_delay) {real {summation of all net delays in
path} {{total} {net delay}}}
set finfo(max_trans) {real {slowest pin transition in path} {{max}
{transition}}}
set finfo(total_xtalk_data) {real {summation of all crosstalk deltas
in data path} {{data} {xtalk}}}
set finfo(total_xtalk_clock) {real {summation of all crosstalk deltas
in clock path} {{clock} {xtalk}}}
set finfo(total_xtalk) {real {summation of all crosstalk deltas in
clock/data path} {{total} {xtalk}}}
set finfo(xtalk_ratio) {real {percentage ratio of 'total_xtalk_data'
versus 'duration'} {{xtalk} {ratio}}}
set known_fields {index startpoint endpoint start_clk end_clk
launch_latency capture_latency skew crpr path_group slack duration
levels hier_pins num_segments num_unique_segments
num_segment_crossings average_cell_delay slowest_cell
slowest_cell_delay slowest_net slowest_net_delay slowest_net_R
slowest_net_C total_net_delay max_trans total_xtalk_data
total_xtalk_clock total_xtalk xtalk_ratio}
proc max {a b} {
return [expr $a > $b ? $a : $b]
}
proc min {a b} {
return [expr $a < $b ? $a : $b]
}

proc process_paths {args} {

set results(-ungrouped) {}
parse_proc_arguments -args $args results
if {[set paths [filter_collection $results(paths) {object_class ==
timing_path}]] == ""} {
echo "Error: no timing paths provided"
return 0
}
set ungrouped_cells {}
if {[set cells [get_cells -quiet $results(-ungrouped) -filter
"is_hierarchical == true"]] != ""} {
echo "Assuming the following instances have been ungrouped and
flattened for segment processing:"
foreach_in_collection cell $cells {
echo " [get_object_name $cell]"
}
echo ""
# now build a list of all ungrouped hierarchical cells
while {$cells != ""} {
set cell [index_collection $cells 0]
set hier_cells [get_cells -quiet "[get_object_name $cell]/*"
-filter "is_hierarchical == true"]
set cells [remove_from_collection $cells $cell]
set cells [append_to_collection -unique cells $hier_cells]
set ungrouped_cells [append_to_collection -unique ungrouped_cells
$cell]
}
}
# come up with a list of index numbers where we want to print
progress
if {[set num_paths [sizeof $paths]] >= 25} {
set index_notice_point 0
set index_notice_messages {"\n(0%.."}
set index_notice_points {}
for {set i 10} {$i <= 90} {incr i 10} {
lappend index_notice_points [expr {int($i * ($num_paths - 1) /
100)}]
lappend index_notice_messages "${i}%.."
}
lappend index_notice_points [expr {$num_paths - 1}]
lappend index_notice_messages "100%)\n"
} else {
set index_notice_point 25
}
# store path data in this namespace
set path_summary::data_list {}
# we start at an index number of 0

set index 0
foreach_in_collection path $paths {
# print progress message if needed
if {$index == $index_notice_point} {
echo -n "[lindex $index_notice_messages 0]"
set index_notice_point [lindex $index_notice_points 0]
set index_notice_messages [lrange $index_notice_messages 1 [expr
[llength $index_notice_messages]-1]]
set index_notice_points [lrange $index_notice_points 1 [expr
[llength $index_notice_points]-1]]
}
set hier_pins 0
set combo_cell_pins 0
set last_cell_port {}
set slowest_cell {}
set slowest_cell_delay "-INFINITY"
set slowest_net_delay "-INFINITY"
set total_net_delay 0
set max_trans 0
set total_xtalk_data 0.0
set total_xtalk_clock 0.0
set hier_cell_paths {}
set last_cell_or_port {}
set change_in_hier 1
set last_cell_or_port {}
set cell_delay {}
set input_pin_arrival {}
foreach_in_collection point [set points [get_attribute $path
points]] {
set object [get_attribute $point object]
set port [get_ports -quiet $object]
set pin [get_pins -quiet $object]
set cell [get_cells -quiet -of $pin]
set is_hier [get_attribute -quiet $cell is_hierarchical]
set annotated_delta_transition [get_attribute -quiet $point
annotated_delta_transition]
if {$is_hier == "true"} {
# if the pin is hierarchical, increment (these are always in
pairs)
incr hier_pins
if {[remove_from_collection $cell $ungrouped_cells] != ""} {
set change_in_hier 1
}
continue
}
# if we are looking at a new cell just after a change in hierarchy,
# add this to our list
if {$change_in_hier} {

if {$cell != ""} {
# add cell path to list
set basename [get_attribute $cell base_name]
set fullname [get_attribute $cell full_name]
lappend hier_cell_paths [string range $fullname 0 [expr [string
last $basename $fullname]-2]]
} else {
# port, which is base level
lappend hier_cell_paths {}
}
}
# we've handled any change in hierarchy
set change_in_hier 0
# use the fact that a true expression evaluates to 1, count
combinational pins
incr combo_cell_pins [expr {[get_attribute -quiet $cell
is_sequential] == "false"}]
if {[set annotated_delay_delta [get_attribute -quiet $point
annotated_delay_delta]] != ""} {
set total_xtalk_data [expr $total_xtalk_data +
$annotated_delay_delta]
}
set max_trans [path_summary::max $max_trans [get_attribute $point
transition]]
# at this point, we have either a leaf pin or a port
# net delay - delay from previous point to current point with
annotated_delay_delta
# cell delay - delay from previous point with annotated_delay_delta
to current point
set this_arrival [get_attribute $point arrival]
set this_cell_or_port [add_to_collection $port $cell]
if {[compare_collection $this_cell_or_port $last_cell_or_port]} {
if {$last_cell_or_port != ""} {
if {[set net_delay [expr $this_arrival-$last_arrival]] >
$slowest_net_delay} {
set slowest_net_delay $net_delay
set slowest_net [get_nets -quiet -segments
-top_net_of_hierarchical_group [all_connected $object]]
}
set total_net_delay [expr $total_net_delay + $net_delay]
}
if {$input_pin_arrival != ""} {
set cell_delay [expr {$last_arrival - $input_pin_arrival}]
if {$cell_delay > $slowest_cell_delay} {
set slowest_cell_delay $cell_delay

set slowest_cell $last_cell_or_port

}
if {$cell != ""} {
set input_pin_arrival $this_arrival
}
set last_cell_or_port $this_cell_or_port

}
set last_arrival $this_arrival

# get first data arrival time, but skip any clock-as-data pins
set i 0
while {1} {
set startpoint_arrival [get_attribute [set point [index_collection
$points $i]] arrival]
if {[get_attribute -quiet [get_attribute $point object]
is_clock_pin] != "true"} {
break
}
incr i
}
# get clock crosstalk
# 1. pins may appear twice at gclock boundaries, but the delta only
appears once
# and is not double-counted
# 2. capture clock deltas are subtracted to account for inverted
sign
foreach_in_collection point [get_attribute -quiet [get_attribute
-quiet $path launch_clock_paths] points] {
if {[set annotated_delay_delta [get_attribute -quiet $point
annotated_delay_delta]] != ""} {
set total_xtalk_clock [expr $total_xtalk_clock +
$annotated_delay_delta]
}
}
foreach_in_collection point [get_attribute -quiet [get_attribute
-quiet $path capture_clock_paths] points] {
if {[set annotated_delay_delta [get_attribute -quiet $point
annotated_delay_delta]] != ""} {
set total_xtalk_clock [expr $total_xtalk_clock $annotated_delay_delta]
}
}
set data(startpoint) [get_object_name [get_attribute $path
startpoint]]
set data(endpoint) [get_object_name [get_attribute $path endpoint]]
set data(start_clk) [get_attribute -quiet [get_attribute -quiet
$path startpoint_clock] full_name]

set data(end_clk) [get_attribute -quiet [get_attribute -quiet $path


endpoint_clock] full_name]
if {[set data(launch_latency) [get_attribute -quiet $path
startpoint_clock_latency]] == {}} {set data(launch_latency) 0.0}
if {[set data(capture_latency) [get_attribute -quiet $path
endpoint_clock_latency]] == {}} {set data(capture_latency) 0.0}
set data(skew) [expr {($data(capture_latency)$data(launch_latency))*([get_attribute $path path_type]=="max" ? 1 :
-1)}]
if {[set data(crpr) [get_attribute -quiet $path
common_path_pessimism]] == ""} {set data(crpr) 0}
set data(path_group) [get_object_name [get_attribute -quiet $path
path_group]]
set data(duration) [format "%.8f" [expr {[get_attribute $path
arrival]-$data(launch_latency)-$startpoint_arrival}]]
set data(slack) [get_attribute $path slack]
set data(hier_pins) [expr $hier_pins / 2]
set data(num_segments) [llength $hier_cell_paths]
set data(num_segment_crossings) [expr $data(num_segments) - 1]
set data(num_unique_segments) [llength [lsort -unique
$hier_cell_paths]]
set data(levels) [expr {$combo_cell_pins / 2.0}]
set data(average_cell_delay) [expr {$data(levels) == 0 ? 0.0 :
[format "%.7f" [expr {($data(duration) / $data(levels))}]]}]
set data(slowest_cell) [get_attribute -quiet $slowest_cell
full_name]
set data(slowest_cell_delay) $slowest_cell_delay
set data(total_net_delay) $total_net_delay
set data(slowest_net) [get_object_name $slowest_net]
set data(slowest_net_delay) $slowest_net_delay
set data(slowest_net_R) [get_attribute $slowest_net
net_resistance_max]
set data(slowest_net_C) [get_attribute $slowest_net
total_capacitance_max]
set data(index) $index
set data(max_trans) $max_trans
set data(total_xtalk_data) $total_xtalk_data
set data(total_xtalk_clock) $total_xtalk_clock
set data(total_xtalk) [expr {$total_xtalk_data +
$total_xtalk_clock}]
set data(xtalk_ratio) [expr {$data(duration) == 0.0 ? 0 : (100.0 *
$total_xtalk_data / $data(duration))}]
incr index
set list_entry {}
foreach field $path_summary::known_fields {
lappend list_entry $data($field)
}
lappend path_summary::data_list $list_entry

}
echo "Path information stored."
echo ""

}
define_proc_attributes process_paths \
-info "Extract information from paths for write_path_summary" \
-define_args {\
{paths "Timing paths from get_timing_paths" "timing_paths" string
required}
{-ungrouped "Assume these instances have been ungrouped" ungrouped
list optional}
}

proc write_path_summary {args} {


# if user asks for help, remind him of what info is available
if {[lsearch -exact $args {-longhelp}] != -1} {
echo "Available data fields:"
foreach field $path_summary::known_fields {
echo " $field - [lindex $path_summary::finfo($field) 1]"
}
echo ""
return
}
# process arguments
set results(-fields) {startpoint endpoint levels slack}
set results(-csv) 0
set results(-descending) 0
parse_proc_arguments -args $args results
set num_fields [llength $results(-fields)]
# did the user ask for any fields we don't understand?
set leftovers [lminus $results(-fields) $path_summary::known_fields]
if {$leftovers != ""} {
echo "Error: unknown fields $leftovers"
echo " (Possible values: $path_summary::known_fields)"
return 0
}
# get sort type and direction, if specified
if {[info exists results(-sort)]} {
if {[set sort_field [lsearch -exact $path_summary::known_fields
$results(-sort)]] == -1} {
echo "Error: unknown sort field $results(-sort)"
echo " (Possible values: $path_summary::known_fields)"
return 0
}
set sort_type [lindex $path_summary::finfo($results(-sort)) 0]
set sort_dir [expr {$results(-descending) ? "-decreasing" : "increasing"}]
}

# obtain saved data from namespace, apply -sort and -max_paths


set data_list $path_summary::data_list
if {[info exists sort_field]} {
set data_list [lsort $sort_dir -$sort_type -index $sort_field
$data_list]
}
set data_list_length [llength $data_list]
if {[info exists results(-max_paths)] && $data_list_length >
$results(-max_paths)} {
set data_list [lrange $data_list 0 [expr $results(-max_paths)-1]]
}
# generate a list of field index numbers relating to our known fields
set field_indices {}
foreach field $results(-fields) {
lappend field_indices [lsearch $path_summary::known_fields $field]
}
# generate report
if {$results(-csv)} {
# join multi-line headers together
set headers {}
foreach index $field_indices {
lappend headers [join [lindex $path_summary::finfo([lindex
$path_summary::known_fields $index]) 2] { }]
}
# print headers
echo [join $headers {,}]
# print data
foreach item $data_list {
set print_list {}
foreach index $field_indices {
lappend print_list [lindex $item $index]
}
echo [join $print_list {,}]
}
} else {
# determine maximum column widths
echo ""
echo "Legend:"
foreach index $field_indices {
set this_field [lindex $path_summary::known_fields $index]
set this_finfo $path_summary::finfo($this_field)
set this_max_length 0
# check widths of each line of header
foreach header [lindex $this_finfo 2] {

set this_max_length [path_summary::max $this_max_length [string


length $header]]
}
# check widths of data
switch [lindex $this_finfo 0] {
real {
set max_pre 0
set max_post 0
foreach item $data_list {
if {[set this_item [lindex $item $index]] == {INFINITY} ||
$this_item == {-INFINITY}} {
set max_pre 3
set max_post 0
} else {
regexp {([-0-9]*\.?)(.*)} [expr $this_item] dummy pre post
set max_pre [path_summary::max $max_pre [string length $pre]]
set max_post [path_summary::max $max_post [string length
$post]]
}
}
if {[info exists results(-significant_digits)]} {
set max_post $results(-significant_digits)
} else {
set max_post [path_summary::min $max_post 7]
}
set this_max_length [path_summary::max $this_max_length [expr
$max_pre + $max_post]]
}
default {
foreach item $data_list {
set this_max_length [path_summary::max $this_max_length [string
length [lindex $item $index]]]
}
}
}
set max_length($index) $this_max_length
switch [lindex $this_finfo 0] {
int {
set formatting($index) "%${this_max_length}d"
}
real {
set formatting($index) "%${this_max_length}.${max_post}f"
}
string {
set formatting($index) "%-${this_max_length}s"
}

}
echo "$this_field - [lindex $this_finfo 1]"

# now print header


echo ""
for {set i 0} {$i <= 1} {incr i} {
set print_list {}
foreach index $field_indices {
set this_field [lindex $path_summary::known_fields $index]
set this_finfo $path_summary::finfo($this_field)
lappend print_list [format "%-$max_length($index)s" [lindex
[lindex $this_finfo 2] $i]]
}
echo [join $print_list { }]
}
set print_list {}
foreach index $field_indices {
lappend print_list [string repeat {-} $max_length($index)]
}
echo [join $print_list {+}]
# print all data
foreach item $data_list {
set print_list {}
foreach index $field_indices {
lappend print_list [format $formatting($index) [lindex $item
$index]]
}
echo [join $print_list { }]
}
echo ""
}
}
define_proc_attributes write_path_summary \
-info "Generate a summary report for given timing paths" \
-define_args {\
{-longhelp "Show description of available data fields" "" boolean
optional}
{-max_paths "Limit report to this many paths" "num_paths" int
optional}
{-fields "Information fields of interest" "fields" list optional}
{-sort "Sort by this field" "field" string optional}
{-descending "Sort in descending order" "" boolean optional}
{-csv "Generate CSV report for spreadsheet" "" boolean optional}
{-significant_digits "Number of digits to display" digits int
optional}
}

You might also like