Write Path Summary
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 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
}
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]
}
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}
}
}
echo "$this_field - [lindex $this_finfo 1]"