proc max {a b} {
return [expr $a > $b ? $a : $b]
}
proc min {a b} {
return [expr $a < $b ? $a : $b]
}
}
#-------------------------------------------------------------#
#-- MY procs
#-------------------------------------------------------------#
alias all "source ../custom/custom.csv_report/all_together.tcl"
alias ts "timing_summary"
alias gon "get_object_name "
alias fic "foreach_in_collection "
alias soc "sizeof_collection "
alias gat "get_attribute "
alias lat "list_attributes -application -nosplit -class"
alias rat "report_attribute -application -nosplit -class"
alias gp "get_pins "
alias gpo "get_ports "
alias gc "get_cells "
alias glc "get_lib_cells "
alias glp "get_lib_pins "
alias gn "get_nets "
alias galc "get_alternative_lib_cells "
alias gclk "get_clocks "
alias ggclk "get_generated_clocks "
alias gtp "get_timing_paths "
alias ac "all_connected "
alias aclf "all_connected -leaf "
alias rt "report_timing "
alias rac "report_analysis_coverage "
alias rdc "report_delay_calculation "
alias ut "update_timing -full"
alias rcmt "report_constraint -all_violators -max_transition -nosplit"
alias gd "get_drivers"
alias gl "get_loads"
alias gpg "get_path_groups"
#----------------------------------------------------------------------------------------------------------#
#-- END
#----------------------------------------------------------------------------------------------------------#
#----------------------------------------------------------------------------------------------------------#
#-- SETTING CUSTOM VARIABLES
#----------------------------------------------------------------------------------------------------------#
#-- THIS VARIABLE sdc_save_source_file_information prints the line where the exception is faulty
set_app_var sdc_save_source_file_information true
#----------------------------------------------------------------------------------------------------------#
#-- END
#----------------------------------------------------------------------------------------------------------#
#----------------------------------------------------------------------------------------------------------#
#-- LOCAL_PROCS
#----------------------------------------------------------------------------------------------------------#
proc gpl {var} {
foreach_in_collection pin [get_pins $var] {
puts "[gon $pin]"
}
}
proc gpol {var} {
foreach_in_collection port [get_ports $var] {
puts "[gon $port]"
}
}
proc gcl {var} {
foreach_in_collection cell [get_cells $var] {
puts "[gon $cell]"
}
}
proc glcl {var} {
foreach_in_collection lib_cell [get_lib_cells $var] {
puts "[gon $lib_cell]"
}
}
proc glpl {var} {
foreach_in_collection lib_pin [get_lib_pins $var] {
puts "[gon $lib_pin]"
}
}
proc gnl {var} {
foreach_in_collection net [get_nets $var] {
puts "[gon $net]"
}
}
proc galcl {var} {
foreach_in_collection alternative_lib_cell [get_alternative_lib_cells $var] {
puts "[gon $alternative_lib_cell]"
}
}
proc gclkl {var} {
foreach_in_collection clock [get_clocks $var] {
puts "[gon $clock]"
}
}
proc ggclkl {var} {
foreach_in_collection gen_clock [get_generated_clocks $var] {
puts "[gon $gen_clock]"
}
}
proc gtpl {var} {
foreach_in_collection timing_path [get_timing_paths $var] {
puts "[gon $timing_path]"
}
}
proc gpgl {var} {
foreach_in_collection path_group [get_path_groups $var] {
puts "[gon $path_group]"
}
}
proc acl {var} {
foreach_in_collection all_connection [all_connected [get_nets -of [get_pins $var]]] {
puts "[gon $all_connection]"
}
}
proc ll {var} {
fic var1 $var {
puts "[gon $var1]"
}
}
###Prints all connected output/inout pins if pin is input port
###Prints all connected input/inout pins if pin is output port
proc qnp {pin} {
if {[gat [gp $pin] direction]=="in"} {
fic p1 [aclf [ac $pin]] {
if {[gat [gp $p1] direction]=="out" || [gat [gp $p1] direction]=="inout" } {
puts "[gon $p1]"
}
}
} elseif {[gat [gp $pin] direction]=="out"} {
fic p1 [gp -of [gc -of [gp $pin]]] {
if {[gat [gp $p1] direction]=="in" || [gat [gp $p1] direction]=="inout" } {
puts "[gon $p1]"
}
}
}
}
proc qns {pin} {
if {[gat [gp $pin] direction]=="out"} {
fic p1 [aclf [ac $pin]] {
if {[gat [gp $p1] direction]=="in" || [gat [gp $p1] direction]=="inout" } {
puts "[gon $p1]"
}
}
} elseif {[gat [gp $pin] direction]=="in"} {
fic p1 [gp -of [gc -of [gp $pin]]] {
if {[gat [gp $p1] direction]=="out" || [gat [gp $p1] direction]=="inout" } {
puts "[gon $p1]"
}
}
}
}
proc ref_name {cell} {
puts "[gat [gc $cell] ref_name]"
}
proc lib_cell {cell} {
puts "[gon [gat [gc $cell] lib_cell]]"
}
proc get_instance {lib_cell} {
fic c1 [gc "*" -hier -filter "ref_name == $lib_cell"] {
puts "[gon $c1]"
}
}
proc clocks {pin} {
puts "[gon [gat [gp $pin] clocks]]"
}
proc case_value {pin} {
puts "[gat [gp $pin] case_value]"
}
proc constant_value {pin} {
puts "[gat [gp $pin] constant_value]"
}
proc is_sequential {cell} {
puts "[gat [gc $cell] is_sequential]"
}
proc is_combinational {cell} {
puts "[gat [gc $cell] is_combinational]"
}
proc is_integrated_clock_gating_cell {cell} {
puts "[gat [gc $cell] is_integrated_clock_gating_cell]"
}
#----------------------------------------------------------------------------------------------------------#
#-- END
#----------------------------------------------------------------------------------------------------------#
#----------------------------------------------------------------------------------------------------------#
#-- report_cells_on_clock_data_network
#----------------------------------------------------------------------------------------------------------#
proc report_cells_on_clock_data_network { args } {
set options(-network) both
set options(-exclude_lib_cells) ""
set options(-lib_cells) ""
parse_proc_arguments -args $args options
if { $options(-lib_cells)!="" && $options(-exclude_lib_cells)!="" } {
echo " -lib_cells and -exclude_lib_cells are mutually exclusive options, please specify only one of them"
return 0
} elseif { $options(-lib_cells)=="" && $options(-exclude_lib_cells)=="" } {
echo " either -lib_cells and -exclude_lib_cells options are required, please specify one of them"
return 0
}
if { $options(-lib_cells)!="" } {
set lib_cells $options(-lib_cells)
set operator1 "="
set operator2 "||"
set tag ""
} else {
set lib_cells $options(-exclude_lib_cells)
set operator1 "!"
set operator2 "&&"
set tag (excluded)
}
set network $options(-network)
set count [llength $lib_cells]
set filter_option ""
foreach lib_cell $lib_cells {
set count [expr $count - 1]
if { [regexp \\* $lib_cell ] } {
set filter_option "$filter_option ref_name${operator1}~${lib_cell}"
} else {
set filter_option "$filter_option ref_name${operator1}=${lib_cell}"
}
if { [expr $count > 0] } {
set filter_option "$filter_option $operator2"
}
}
#echo "$filter_option"
set instances_of_lib_cells [get_cells -hier * -filter "$filter_option"]
set clock_path_cells ""
set data_path_cells ""
foreach_in_collection cell $instances_of_lib_cells {
if { [get_attribute -quiet [get_pins -of [get_cells $cell]] clocks ] != "" } {
set clock_path_cells [add_to_collection $clock_path_cells $cell]
} else {
set data_path_cells [add_to_collection $data_path_cells $cell]
}
}
if { $network=="clock" || $network =="both"} {
echo "##################################################################"
echo "Cells on Clock Network of Lib Cells $tag: $lib_cells"
echo "##################################################################"
if { [sizeof $clock_path_cells] =="0" } { echo "None" }
foreach_in_collection cellc $clock_path_cells {
echo "[get_object_name $cellc] [get_attribute $cellc ref_name]"
}
}
if { $network=="data" || $network =="both" } {
echo "##################################################################"
echo "Cells on Data Network of Lib Cells $tag: $lib_cells"
echo "##################################################################"
if { [sizeof $data_path_cells] =="0" } { echo "None" }
foreach_in_collection celld $data_path_cells {
echo "[get_object_name $celld]\t[get_attribute $celld ref_name]"
}
}
return 1
}
define_proc_attributes report_cells_on_clock_data_network \
-info "report the given lib cells are on clock or data network " \
-define_args \
{
{ -network "report for clock, data or both" "" one_of_string {optional {values {clock data both}}} }
{ -lib_cells "list of lib_cells, wild cards supported" "
{ -exclude_lib_cells "list of lib cells to be excluded, wild cards supported" "
}
#----------------------------------------------------------------------------------------------------------#
#-- END
#----------------------------------------------------------------------------------------------------------#
#----------------------------------------------------------------------------------------------------------#
#-- report_slack_distribution
#----------------------------------------------------------------------------------------------------------#
proc report_slack_distribution { targetClock {marginPoints "0 .5 1 1.5" } {ListEndPoints 0}} {
#
# 5/8/97 xxxxxxx
# 6/13/05 update to tcl commands
# report_slack_distribution
# positionals
# target clock name
# list of interesting margin points
# list end points
#
# usage:
# report_slack_dist sysclk "0 0.1 0.5 1 2 3 4" 0
#
# reports the total negative slack, the worst violator at the given clock
# and then calculates the number of violating paths at each of the margin
# points subtracted from the clock
#
# Here is a sample report
#
# Timing Information for clock clk with 128 total endpoints:
#
# Worst Negative Slack: -1.39365
#
# margin Num. of Violators Total Neg. Slack percent violators
# ------ ----------------- ---------------- -----------------
# 0 16 -17.9794 13
# .5 24 -27.77 19
# 1 24 -39.7698 19
# 1.5 28 -53.1804 22
#
#set ListEndPoints 0
#set marginPoints 0.0
set WNS 100000.0
set TE 0
foreach margin $marginPoints {
set TNS($margin) 0.0
set NVE($margin) 0
set PCT($margin) 0
}
set pathsPerEndpoint 1
echo ""
echo "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-"
echo " Analyzing end point slack clocked by $targetClock"
echo "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-"
# find all the endpoints clocked by targetClock
set allRegisterPins [all_registers -clock $targetClock -data]
set allOutputPorts [all_outputs -clock $targetClock]
set allEndPoints [concat $allRegisterPins $allOutputPorts]
foreach_in_collection endPoint $allEndPoints {
# get and print the startpoint, arrival and slack
set maxTimingSelection [get_timing_path -nworst $pathsPerEndpoint -to $endPoint -delay max]
set firstFor 1
foreach_in_collection path $maxTimingSelection {
set TE [expr $TE + 1]
set slack [get_attribute $path slack]
set startpoint [get_attribute $path startpoint]
if { $firstFor == 1 } {
if { $slack < $WNS } {
set WNS $slack
}
if { $ListEndPoints == 1 } {
if { $slack < 0.0 } {
echo [format "Slack of %-5.2f from %-30s to %-30s" \
$slack [get_object_name $startpoint ] \
[get_object_name $endPoint ] ]
}
}
foreach margin $marginPoints {
if { $slack < $margin } {
set TNS($margin) [expr $TNS($margin) + ($slack-$margin)]
set NVE($margin) [expr $NVE($margin) + 1]
}
}
}
}
}
echo ""
echo "Timing Information for clock $targetClock with $TE total endpoints:"
echo ""
echo [format " Worst Negative Slack: %-20.2f" $WNS]
echo ""
echo " margin Num. of Violators Total Neg. Slack percent violators"
echo " ------ ----------------- ---------------- -----------------"
foreach margin $marginPoints {
echo [format "%6.2f %13d %14.2f %5.1f " \
$margin $NVE($margin) $TNS($margin) [expr 100-(100*($TE-$NVE($margin))/$TE) ]]
}
}
#------------------------------------------------------------------------------------------------#
#-- END
#------------------------------------------------------------------------------------------------#
#-- #----------------------------------------------------------------------------------------------------------#
#-- #-- curdes_prompt
#-- #----------------------------------------------------------------------------------------------------------#
#--
#-- proc curdes_prompt {} {
#-- global sh_dev_null
#-- global synopsys_program_name
#-- set des ""
#-- redirect $sh_dev_null {set des [current_design]}
#-- if { $des == "" } {
#-- echo -n "${synopsys_program_name}> "
#-- return
#-- }
#-- set des [get_object_name $des]
#-- set inst ""
#-- redirect $sh_dev_null {set inst [current_instance .]}
#-- if { $inst == "" } {
#-- set sep ""
#-- } else {
#-- set sep "/"
#-- }
#-- #-- "SETTING PRIMETIME PROMPT"
#-- set prmpt "${des}${sep}${inst}-pt_shell-> "
#-- #-- set prmpt "PRIMETIME-> "
#-- echo -n ${prmpt}
#-- }
#-- set tcl_prompt1 curdes_prompt
#-- #-- unset tcl_prompt1 curdes_prompt
#-- #------------------------------------------------------------------------------------------------#
#-- #-- END
#-- #------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#-- write_path_summary
#------------------------------------------------------------------------------------------------#
#-- USAGE :
#-- e.g.
#-- set paths [get_timing_paths -delay_type max -slack_lesser_than 1000 -max_paths 10]
#-- process_paths $paths
#-- write_path_summary -fields {index endpoint slack duration crpr num_segments num_unique_segments num_segment_crossings max_trans skew}
#-- where '-fields' can be
#-- index - index number of path in original path collection (0, 1, 2...)
#-- startpoint - name of path startpoint
#-- endpoint - name of path endpoint
#-- start_clk - name of startpoint launching clock
#-- end_clk - name of endpoint capturing clock
#-- launch_latency - launching clock latency
#-- capture_latency - capturing clock latency
#-- skew - skew between launch/capture clock (negative is tighter)
#-- crpr - clock reconvergence pessimism removal amount
#-- path_group - path group name
#-- slack - path slack
#-- duration - combinational path delay between startpoint and endpoint
#-- levels - levels of combinational logic
#-- hier_pins - number of hierarchy pins in path
#-- num_segments - number of segments in path
#-- num_unique_segments - number of unique segments in path
#-- num_segment_crossings - number of segment crossings in path
#-- average_cell_delay - average combinational cell delay (duration / levels)
#-- slowest_cell - name of slowest cell in path
#-- slowest_cell_delay - cell delay of slowest cell in path
#-- slowest_net - name of slowest net in path
#-- slowest_net_delay - net delay of slowest net in path
#-- slowest_net_R - resistance of slowest net in path
#-- slowest_net_C - capacitance of slowest net in path
#-- total_net_delay - summation of all net delays in path
#-- max_trans - slowest pin transition in path
#-- total_xtalk_data - summation of all crosstalk deltas in data path
#-- total_xtalk_clock - summation of all crosstalk deltas in clock path
#-- total_xtalk - summation of all crosstalk deltas in clock/data path
#-- xtalk_ratio - percentage ratio of 'total_xtalk_data' versus 'duration'
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 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}
}
#------------------------------------------------------------------------------------------------#
#-- END
#------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#-- get_drivers get_loads
#------------------------------------------------------------------------------------------------#
proc get_drivers {args} {
parse_proc_arguments -args $args results
# if it's not a collection, convert into one
redirect /dev/null {set size [sizeof_collection $results(object_spec)]}
if {$size == ""} {
set objects {}
foreach name $results(object_spec) {
if {[set stuff [get_ports -quiet $name]] == ""} {
if {[set stuff [get_cells -quiet $name]] == ""} {
if {[set stuff [get_pins -quiet $name]] == ""} {
if {[set stuff [get_nets -quiet $name]] == ""} {
continue
}
}
}
}
set objects [add_to_collection $objects $stuff]
}
} else {
set objects $results(object_spec)
}
if {$objects == ""} {
echo "Error: no objects given"
return 0
}
set driver_results {}
# process all cells
if {[set cells [get_cells -quiet $objects]] != ""} {
# add driver pins of these cells
set driver_results [add_to_collection -unique $driver_results \
[get_pins -quiet -of $cells -filter "pin_direction == out || pin_direction == inout"]]
}
# get any nets
set nets [get_nets -quiet $objects]
# get any pin-connected nets
if {[set pins [get_pins -quiet $objects]] != ""} {
set nets [add_to_collection -unique $nets \
[get_nets -quiet -of $pins]]
}
# get any port-connected nets
if {[set ports [get_ports -quiet $objects]] != ""} {
set nets [add_to_collection -unique $nets \
[get_nets -quiet -of $ports]]
}
# process all nets
if {$nets != ""} {
# add driver pins of these nets
set driver_results [add_to_collection -unique $driver_results \
[get_pins -quiet -leaf -of $nets -filter "pin_direction == out || pin_direction == inout"]]
set driver_results [add_to_collection -unique $driver_results \
[get_ports -quiet -of $nets -filter "port_direction == in || port_direction == inout"]]
}
# return results
return $driver_results
}
define_proc_attributes get_drivers \
-info "Return driver ports/pins of object" \
-define_args {\
{object_spec "Object(s) to report" "object_spec" string required}
}
proc get_loads {args} {
parse_proc_arguments -args $args results
# if it's not a collection, convert into one
redirect /dev/null {set size [sizeof_collection $results(object_spec)]}
if {$size == ""} {
set objects {}
foreach name $results(object_spec) {
if {[set stuff [get_ports -quiet $name]] == ""} {
if {[set stuff [get_cells -quiet $name]] == ""} {
if {[set stuff [get_pins -quiet $name]] == ""} {
if {[set stuff [get_nets -quiet $name]] == ""} {
continue
}
}
}
}
set objects [add_to_collection $objects $stuff]
}
} else {
set objects $results(object_spec)
}
if {$objects == ""} {
echo "Error: no objects given"
return 0
}
set load_results {}
# process all cells
if {[set cells [get_cells -quiet $objects]] != ""} {
# add load pins of these cells
set load_results [add_to_collection -unique $load_results \
[get_pins -quiet -of $cells -filter "pin_direction == in || pin_direction == inout"]]
}
# get any nets
set nets [get_nets -quiet $objects]
# get any pin-connected nets
if {[set pins [get_pins -quiet $objects]] != ""} {
set nets [add_to_collection -unique $nets \
[get_nets -quiet -of $pins]]
}
# get any port-connected nets
if {[set ports [get_ports -quiet $objects]] != ""} {
set nets [add_to_collection -unique $nets \
[get_nets -quiet -of $ports]]
}
# process all nets
if {$nets != ""} {
# add load pins of these nets
set load_results [add_to_collection -unique $load_results \
[get_pins -quiet -leaf -of $nets -filter "pin_direction == in || pin_direction == inout"]]
set load_results [add_to_collection -unique $load_results \
[get_ports -quiet -of $nets -filter "port_direction == out || port_direction == inout"]]
}
# return results
return $load_results
}
define_proc_attributes get_loads \
-info "Return load ports/pins of object" \
-define_args {\
{object_spec "Object(s) to report" "object_spec" string required}
}
#------------------------------------------------------------------------------------------------#
#-- END
#------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#-- get_failing_paths_high_slew
#------------------------------------------------------------------------------------------------#
#-- USAGE
#-- get_failing_paths_high_slew 1 max 0.01
#-- All Violations of nworst 1 and for 'max' paths with trans above 0.01
proc get_failing_paths_high_slew { Nworst_numb Path_type Tran_threshold } {
set Nworst_numb $Nworst_numb
set Path_type $Path_type
set Tran_threshold $Tran_threshold
foreach_in_collection path [get_timing_paths -delay_type $Path_type -nworst $Nworst_numb] {
foreach_in_collection itr $path {
set cnt 0
set Slack [get_attribute $itr slack]
set StartPoint [get_object_name [get_attribute $itr startpoint] ]
set EndPoint [get_object_name [get_attribute $itr endpoint] ]
if { $Slack < 1000.0 } {
if { $cnt == 0 } {
echo " Timing path fails: \t Start point: $StartPoint \t End Point $EndPoint \t Slack: $Slack";
set $cnt [ expr $cnt + 1]
}
;# violating paths next
foreach_in_collection point [get_attribute $path points] {
set Object [get_attribute $point object]
set Obj_name [get_object_name [get_attribute $point object] ]
set Obj_r_f [get_attribute $point rise_fall]
set Slew_att [format "actual_%s_transition_%s" $Obj_r_f $Path_type]
set Slew_val [ get_attribute $Object $Slew_att]
set Cell [ get_cells -quiet -of_objects $Object ]
if { [get_attribute -quiet $Object is_port] == "false" } {
set Lib_cell [ get_lib_cells -of_objects $Cell ]
set Ref_name [ get_attribute $Lib_cell base_name ]
} else {
;# it's a port
set Ref_name $Object
}
if { $Slew_val > $Tran_threshold } {
echo " has a $Obj_r_f slew = $Slew_val on pin $Obj_name \t Reference = $Ref_name"
}
} ;# end of foreach point
} else {
continue
;# slack is > 0.0 no violation
;# go to next timing path
}
}; # end foreach $path
} ;# end of foreach get_timing_path
;# variable cleanup
#-- unset Slack Obj_name Obj_r_f Slew_att Slew_val Nworst_numb Path_type Tran_threshold
} ;# end of proc
#------------------------------------------------------------------------------------------------#
#-- END
#------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#-- report_critical_loads
#------------------------------------------------------------------------------------------------#
namespace eval rcl {
proc pin_basename {object} {
set basename [get_attribute $object lib_pin_name]
set fullname [get_attribute $object full_name]
return [string range $fullname 0 [expr [string last $basename $fullname]-2]]
}
proc net_basename {object} {
set basename [get_attribute $object base_name]
set fullname [get_attribute $object full_name]
return [string range $fullname 0 [expr [string last $basename $fullname]-2]]
}
proc net_loads {net} {
set loads {}
foreach_in_collection object [all_connected $net] {
set direction [get_attribute $object direction]
if {[get_attribute $object object_class] == "pin" && [pin_basename $object] != [net_basename $net]} {
# pin at deeper hierarchical level
if {$direction != "out"} {
set loads [add_to_collection $loads $object]
}
} else {
# pin at same hierarchical level
if {$direction != "in"} {
set loads [add_to_collection $loads $object]
}
}
}
return $loads
}
proc net_drivers {net} {
set drivers {}
foreach_in_collection object [all_connected $net] {
set direction [get_attribute $object direction]
if {[get_attribute $object object_class] == "pin" && [pin_basename $object] != [net_basename $net]} {
# pin at deeper hierarchical level
if {$direction != "in"} {
set drivers [add_to_collection $drivers $object]
}
} else {
# pin at same hierarchical level
if {$direction != "out"} {
set drivers [add_to_collection $drivers $object]
}
}
}
return $drivers
}
proc max {a b} {return [expr {$a > $b ? $a : $b}]}
}
proc report_critical_loads {args} {
set results(-delay) "max"
parse_proc_arguments -args $args results
if {$::timing_save_pin_arrival_and_slack != "true"} {
echo "Error: the variable 'timing_save_pin_arrival_and_slack' must be set to 'true' for this procedure"
return 0
}
if {[set nets [get_nets -seg -quiet $results(object)]] == ""} {
if {[set object [get_pins -quiet $results(object)]] == ""} {
if {[set object [get_ports -quiet $results(object)]] == ""} {
echo "Error: couldn't find specified object"
return 0
} else {
set nets [get_nets -seg -of $object]
}
} else {
set nets [get_nets -seg -of $object]
}
}
set driver_load([list 0 1]) "load"
set driver_load([list 1 0]) "driver"
set driver_load([list 1 1]) "driver/load"
set min_max "max"
set max_pre 0
set max_post 0
echo "Number of net segments: [sizeof_collection $nets]"
echo ""
foreach_in_collection net $nets {
set driver_object_slack_list {}
set load_object_slack_list {}
echo "Net segment '[set net_name [get_object_name $net]]':"
# determine drivers/loads
set drivers [rcl::net_drivers $net]
set loads [rcl::net_loads $net]
# determine max length of all loads and driver slacks
set max_name_length 0
foreach_in_collection object [add_to_collection -unique $drivers $loads] {
set rise_slack [get_attribute $object ${min_max}_rise_slack]
set fall_slack [get_attribute $object ${min_max}_fall_slack]
# handle unconstrained load pins
if {$rise_slack == {INFINITY} && $fall_slack == {INFINITY}} {
set slack {INFINITY}
} else {
set slack [expr {"$rise_slack" < "$fall_slack" ? "$rise_slack" : "$fall_slack"}]
}
regexp {([-0-9]*\.?)(.*)} $slack dummy pre post
set max_pre [rcl::max $max_pre [string length $pre]]
set max_post [rcl::max $max_post [string length $post]]
set max_name_length [rcl::max $max_name_length [string length [get_object_name $object]]]
set is_driver [expr {[remove_from_collection $object $drivers] == ""}]
set is_load [expr {[remove_from_collection $object $loads] == ""}]
if {$is_driver} {
lappend driver_object_slack_list [list $object $slack $is_driver $is_load]
} else {
lappend load_object_slack_list [list $object $slack $is_driver $is_load]
}
}
set max_slack_length [expr $max_pre + $max_post]
echo [format "%-${max_slack_length}s %s" "slack" "name"]
echo [string repeat "-" [expr {$max_slack_length + 1 + $max_name_length}]]
set driver_object_slack_list [lsort -real -index 1 -increasing $driver_object_slack_list]
set load_object_slack_list [lsort -real -index 1 -increasing $load_object_slack_list]
foreach object [concat $driver_object_slack_list $load_object_slack_list] {
set obj [lindex $object 0]
set driver_or_load $driver_load([list [lindex $object 2] [lindex $object 3]])
set object_class [get_attribute $obj object_class]
if {$object_class == "pin"} {
set driver_or_load "[expr {[get_attribute [get_cells -of $obj] is_hierarchical] == "true" ? "hierarchical" : "leaf"}] $driver_or_load"
}
echo [format "%${max_slack_length}.${max_post}f %s (%s %s)" [lindex $object 1] [get_object_name $obj] $driver_or_load $object_class]
}
echo ""
echo "insert_buffer \[get_pins {"
foreach load_pin $load_object_slack_list {
echo " [get_object_name [lindex $load_pin 0]]"
}
echo "}\] lib/cell"
echo ""
echo ""
}
}
define_proc_attributes report_critical_loads \
-info "Show loads on a net sorted by slack" \
-define_args {\
{-delay_type "Type of slack to analyze" type one_of_string {optional value_help {values {min max}}}}
{object "Net, pin, or port to analyze" "objects" string required}
}
#------------------------------------------------------------------------------------------------#
#-- END
#------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#-- check_data_pulse_width [all_outputs]
#------------------------------------------------------------------------------------------------#
proc check_data_pulse_width {args} {
global sh_dev_null
set results(-verbose) 0
set results(data_pins) {}
set results(-width) 1.0
parse_proc_arguments -args $args results
if {! $results(-width) > 0.0} {
echo "Error: pulse width must be a positive value"
return 0
}
if {$results(data_pins) == ""} {
set results(data_pins) [all_registers -data_pins]
}
set pins [get_pins -quiet $results(data_pins)]
# support passing in a collection of ports (outputs or inouts) for pulsewidth calculation
set pins [add_to_collection $pins [get_ports -quiet $results(data_pins)]]
set rise_paths [get_timing_paths -delay max_rise -to $pins -max_paths 99999]
set fall_paths [get_timing_paths -delay max_fall -to $pins -max_paths 99999]
# first, do rising setup arrivals, falling hold arrivals
foreach_in_collection this_path $rise_paths {
set this_pin [get_attribute $this_path endpoint]
set max_this_pin_clock_close_edge_value [get_attribute -quiet $this_path endpoint_clock_close_edge_value]
set arrival_windows [lindex [get_attribute $this_pin arrival_window] 0]
if {$max_this_pin_clock_close_edge_value == ""} {continue}
# determine latest rising arrival, earliest falling arrival
set latest_rise_arrival {}
set earliest_fall_arrival {}
foreach window $arrival_windows {
# {CLK1} pos_edge {min_r_f 0.30098 0.328784} {max_r_f 0.30098 0.328784}
set max_rise_arrival [lindex [lindex $window 3] 1]
set min_fall_arrival [lindex [lindex $window 2] 2]
if {$latest_rise_arrival == "" || $max_rise_arrival > $latest_rise_arrival} {
set latest_rise_arrival $max_rise_arrival
}
if {$earliest_fall_arrival == "" || $min_fall_arrival < $earliest_fall_arrival} {
set earliest_fall_arrival $min_fall_arrival
}
}
set setup_window [expr $max_this_pin_clock_close_edge_value - $latest_rise_arrival]
set hold_window $earliest_fall_arrival
set pulse_width [expr $setup_window + $hold_window]
if {$results(-verbose) || $pulse_width < $results(-width)} {
echo "Rising setup window: $setup_window ($max_this_pin_clock_close_edge_value - $latest_rise_arrival)"
echo "Falling hold window: $earliest_fall_arrival"
echo "Active high pulse width for [get_object_name $this_pin]: $pulse_width ($setup_window $hold_window)\n"
}
}
# second, do falling setup arrivals, rising hold arrivals
foreach_in_collection this_path $fall_paths {
set this_pin [get_attribute $this_path endpoint]
set max_this_pin_clock_close_edge_value [get_attribute -quiet $this_path endpoint_clock_close_edge_value]
set arrival_windows [lindex [get_attribute $this_pin arrival_window] 0]
if {$max_this_pin_clock_close_edge_value == ""} {continue}
# determine latest falling arrival, earliest rising arrival
set latest_fall_arrival {}
set earliest_rise_arrival {}
foreach window $arrival_windows {
# {CLK1} pos_edge {min_r_f 0.30098 0.328784} {max_r_f 0.30098 0.328784}
set max_fall_arrival [lindex [lindex $window 3] 2]
set min_rise_arrival [lindex [lindex $window 2] 1]
if {$latest_fall_arrival == "" || $max_fall_arrival > $latest_fall_arrival} {
set latest_fall_arrival $max_fall_arrival
}
if {$earliest_rise_arrival == "" || $min_rise_arrival < $earliest_rise_arrival} {
set earliest_rise_arrival $min_rise_arrival
}
}
set setup_window [expr $max_this_pin_clock_close_edge_value - $latest_fall_arrival]
set hold_window $earliest_rise_arrival
set pulse_width [expr $setup_window + $hold_window]
if {$results(-verbose) || $pulse_width < $results(-width)} {
echo "Falling setup window: $setup_window ($max_this_pin_clock_close_edge_value - $latest_fall_arrival)"
echo "Rising hold window: $earliest_rise_arrival"
echo "Active low pulse width for [get_object_name $this_pin]: $pulse_width ($setup_window $hold_window)\n"
}
}
echo "Analysis of [sizeof_collection $pins] pin(s) complete."
}
define_proc_attributes check_data_pulse_width \
-info "checks data pulse width between setup/hold edge arrivals" \
-define_args \
{
{-verbose "show details of calculation" "" boolean optional}
{-width "minimum pulse width between setup/hold edge arrivals" min_width string optional}
{data_pins "data pins to check" "data_pins" string optional}
}
#------------------------------------------------------------------------------------------------#
#-- END
#------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#-- si_net_delta_delay
#------------------------------------------------------------------------------------------------#
#-- For finding the crosstalk delta delay associated with a net.
#-- It takes a net and returns the delta_delay for that net.
proc find_delta { net {min_max ""} {rise_fall ""} } {
set net_arcs [get_timing_arcs -of_objects $net]
set worst_delta 0.0
set abs_delta 0.0
if {$min_max == ""} {
set min_max "min max"
}
if {$rise_fall == ""} {
set rise_fall "rise fall"
}
set worst_mm_rf "$min_max\_$rise_fall"
foreach mm $min_max {
foreach rf $rise_fall {
foreach_in_collection net_arc $net_arcs {
set delta [get_attribute $net_arc \
"annotated_delay_delta_$mm\_$rf"]
set abs_delta [expr abs($delta)]
if {$abs_delta > $worst_delta } {
set worst_mm_rf "$mm\_$rf"
set worst_delta $abs_delta
}
}
}
}
return $worst_delta
}
#-- This procedure takes a collection of nets and crosstalk delay threshold as inputs.
#-- It will then find all of the nets in the collection that equal or surpass the specified threshold.
#-- The procedure then returns an array of these nets, the delta delay of the net,
#-- the driving pin of the net, and the reference name (library cell) of the driving cell.
#-- Timing units of the Threshold are in library units. Threshold should be >= 0.
#-- It is required to source the find_delta.tcl procedure.
#--
#-- USAGE :
#-- #Find all clock nets of clk1 that have more than 50 ps of crosstalk delay
#-- set NETS [get_clock_network_objects clk1 -include -type net]
#-- set THRESH 0.050
#-- si_net_delta_delay $NETS $THRESH si_net_delay_array_clk1
#-- # To access the net names use the following command
#-- array names si_net_delay_array_clk1
proc si_net_delta_delay { NETS THRESH ARRAY} {
upvar $ARRAY NET_DELTA_ARRAY
foreach_in_coll NET [get_nets $NETS] {
set DELTA [find_delta $NET]
if {$DELTA >= $THRESH } {
set DRIVER [filter_coll [all_connected $NET] direction==out]
if {[sizeof_collection $DRIVER] !=0} {
set NET_DELTA_ARRAY([get_object_name $NET]) "$DELTA [get_object_name $DRIVER] [get_attr [get_cell -of_obj $DRIVER] ref_name]"
echo $NET_DELTA_ARRAY([get_object_name $NET])
} else {
echo "No driver cell for " [get_att $NET full_name ]
}
}
}
}
#------------------------------------------------------------------------------------------------#
#-- END
#------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#-- plot_lcd
#------------------------------------------------------------------------------------------------#
#-- plot cell delay versus load, area, always_on and dont_use
#-- USAGE :
#-- plot_lcd hs_invd4 I ZN
#-- libcell_delay_plot -help
proc libcell_delay_plot {args} {
global link_path
set results(-transition) 0
set results(-delay_type) {max}
set results(-load_indices) {0 1}
set results(-num_points) 200
parse_proc_arguments -args $args results
set lib_cell $results(cell)
set from_pin $results(-from_pin)
set to_pin $results(-to_pin)
if {![string is double [set min_slew [lindex $results(-load_indices) 0]]] ||
![string is double [set max_slew [lindex $results(-load_indices) 1]]]} {
echo "Error: non-float value given in slew range list"
return 0
}
set min_slew [expr double($min_slew)]
set max_slew [expr double($max_slew)]
# create indices
set indices [list [set lastindex [lindex $results(-load_indices) 0]]]
foreach index [lrange $results(-load_indices) 1 [expr [llength $results(-load_indices)]-1]] {
for {set i 1} {$i < $results(-num_points)} {incr i} {
lappend indices [expr $lastindex + (($index - $lastindex) * double($i) / ($results(-num_points)))]
}
lappend indices [set lastindex $index]
}
foreach lib $link_path {
if {$lib == {*}} {continue}
set libpath [which $lib]
if {$libpath != ""} {
if {[get_libs -quiet "*" -filter "source_file_name == $libpath"] == ""} {
read_db $libpath
}
}
}
if {[set cell [get_lib_cells -quiet $lib_cell]] == ""} {
foreach_in_collection lib [get_libs -quiet "*"] {
if {[set cell [get_lib_cells -quiet [get_object_name $lib]/$lib_cell]] != ""} {
break;
}
}
}
set cellname [get_attribute $cell base_name]
set fullcellname [get_attribute $cell full_name]
if {[get_lib_pins -of $cell -filter "base_name == $from_pin"] == ""} {
echo "Error: couldn't find $from_pin on $cellname"
return 0
}
if {[get_lib_pins -of $cell -filter "base_name == $to_pin"] == ""} {
echo "Error: couldn't find $to_pin on $cellname"
return 0
}
set outfile [expr {[info exists results(-output)] ? "$results(-output)" : "${cellname}.txt"}]
set pins(in) {}
set pins(out) {}
set pins(inout) {}
foreach_in_collection pin [get_lib_pins -of $cell] {
lappend pins([get_attribute $pin pin_direction]) [get_attribute $pin base_name]
}
set allpins [concat $pins(in) $pins(out) $pins(inout)];
redirect ~/_${cellname}.v {
echo "module ${cellname}_inst ([join $allpins {,}]);"
if {$pins(in) != ""} {echo "input [join $pins(in) {,}];"}
if {$pins(out) != ""} {echo "output [join $pins(out) {,}];"}
if {$pins(inout) != ""} {echo "inout [join $pins(inout) {,}];"}
echo "$cellname U ([join $allpins {,}]);"
echo "endmodule"
}
redirect /dev/null {remove_design -all}
redirect /dev/null {set success [read_verilog ~/_${cellname}.v]}
if {!$success} {
echo "Error: read of temporary netlist _${cellname} failed"
return 0
}
file delete _${cellname}.v
redirect /dev/null {set success [link]}
if {!$success} {
echo "Error: link of temporary netlist _${cellname} failed"
return 0
}
set_input_transition $results(-transition) [all_inputs]
if {[info exists results(-oc_condition)]} {
set_operating_condition -analysis_type bc_wc $results(-oc_condition)
} else {
set results(-oc_condition) ""
}
redirect $outfile {
echo "# library cell: $fullcellname $from_pin -> $to_pin"
echo "# operating conditions: $results(-oc_condition)"
echo "# input pin transition: $results(-transition)"
foreach load $indices {
set_load -subtract_pin_load $load [get_nets "*"]
redirect /dev/null {update_timing}
set arcs [get_timing_arcs -from U/$from_pin -to U/$to_pin]
set dmaxr [get_attribute [index_collection [sort_collection $arcs delay_max_rise] 0] delay_max_rise]
set dmaxf [get_attribute [index_collection [sort_collection $arcs delay_max_rise] 0] delay_max_fall]
set dminr [get_attribute [index_collection [sort_collection -descending $arcs delay_max_rise] 0] delay_min_rise]
set dminf [get_attribute [index_collection [sort_collection -descending $arcs delay_max_rise] 0] delay_min_fall]
set area [get_attribute $fullcellname area]
echo $load $dmaxr $dmaxf $dminr $dminf $area
}
}
# now get time and load units
set tmpfilename "/tmp/[pid]_libinfo.txt"
redirect $tmpfilename {report_lib -nosplit [get_libs -of $cell]}
set file [open $tmpfilename]
set report_lib [read $file]
close $file
file delete $tmpfilename
regexp -linestop -- {Time Unit *: (.*)} $report_lib dummy time_unit
regexp -linestop -- {Capacitance Unit *: (.*)} $report_lib dummy cap_unit
# generate datafile
redirect ${outfile}.gnuplot {
echo "set data style linespoints"
echo "set key bottom right"
echo "set yrange \[0:\]"
echo "set title '$fullcellname $from_pin -> $to_pin ($results(-transition) slew on $from_pin)'"
echo "set label \" CELL $cellname\" right at graph 0.95, graph 0.28 font 'Calibri,12' textcolor lt 8"
echo "set label \"AREA (um^2) [get_attribute [get_lib_cells $fullcellname] area]\" right at graph 0.95, graph 0.24 font 'Courier,10' textcolor lt 3"
echo "set label \"ALWAYS_ON [get_attribute [get_lib_cells $fullcellname] always_on]\" right at graph 0.95, graph 0.21 font 'Courier,10' textcolor lt 3"
echo "set label \" DONT_USE [get_attribute [get_lib_cells $fullcellname] dont_use]\" right at graph 0.95, graph 0.18 font 'Courier,10' textcolor lt 3"
echo "set label \" DISABLE_TIMING [get_attribute [get_lib_cells $fullcellname] disable_timing]\" right at graph 0.95, graph 0.15 font 'Courier,10' textcolor lt 3"
echo "set xlabel 'output load ($cap_unit)'"
echo "set ylabel 'cell delay ($time_unit)'"
echo "set grid"
switch $results(-delay_type) {
max {
echo "plot '[pwd]/$outfile' using 1:2 title 'delay_max_rise'"
echo "replot '[pwd]/$outfile' using 1:3 title 'delay_max_fall'"
}
min {
echo "plot '[pwd]/$outfile' using 1:4 title 'delay_min_rise'"
echo "replot '[pwd]/$outfile' using 1:5 title 'delay_min_fall'"
}
}
}
echo " library cell: $fullcellname $from_pin -> $to_pin"
echo "operating conditions: $results(-oc_condition)"
echo "input pin transition: $results(-transition)"
echo ""
echo "ON UNIX SHELL, PLOT IT BY RUNNING :"
echo "\n"
echo " plot [pwd]/${outfile}.gnuplot"
echo "\n"
echo "\n"
}
define_proc_attributes libcell_delay_plot \
-info "plot cell delay versus load" \
-define_args {\
{-from_pin "from pin on cell" from_pin_name string required}
{-to_pin "from pin on cell" to_pin_name string required}
{-transition "input pin transition (default 0)" input_transition float optional}
{-delay_type "plot worst-case or best-case curves" type one_of_string {optional value_help {values {min max}}}}
{-oc_condition "operating condition" condition string optional}
{-load_indices "list of load indices {slew0 slew1 ...}" "indices" string optional}
{-num_points "number of points to interpolate per index" "num" int optional}
{-output "gnuplot output data file" "filename" string optional}
{cell "library cell, CELL or LIB/CELL" "cell" string required}
}
proc plot_lcd {lib_cell from_pin to_pin} {
libcell_delay_plot ${lib_cell} -from_pin ${from_pin} -to_pin ${to_pin}
file delete ~/_${lib_cell}.v
}
#------------------------------------------------------------------------------------------------#
#-- END
#------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#-- machine_stats
#------------------------------------------------------------------------------------------------#
#-- USAGE :
#-- pt_shell> machine_stats -start
#-- Top job started recording top.log every 60 seconds with pid 58347, issue machine_stats -stop to kill it.
#-- pt_shell> update_timing -full ; #or any command in any tool.
#-- pt_shell> machine_stats -stop
#-- Killing earlier top job with pid 58347.
proc machine_stats {args} {
suppress_message CMD-041
parse_proc_arguments -args ${args} opt
if {[info exists opt(-stop)]} {
if {![info exists ::top_pid]} { return "ERROR!! no prior top job started with machine_stats -start found to stop" }
echo "Killing earlier top job with pid $::top_pid"
puts "\n"
echo "Machine Usage details printed in "
echo "\t[pwd]/top.log"
puts "\n"
sh kill -9 $::top_pid
unset -nocomplain ::top_pid
return
} elseif {[info exists opt(-start)]} {
if {[info exists opt(-delay)]} { set delay $opt(-delay) } else { set delay 60 }
if {[info exists opt(-top_log)]} { set log $opt(-top_log) } else { set log "top.log" }
if {[info exists ::top_pid]} {
return "ERROR!! top job with pid $::top_pid already in progress, machine_stats -stop it first"
}
sh rm -rf $log
set user [exec whoami]
set ::top_pid [exec top -b -u $user -d $delay > $log &]
echo "top job started recording top.log every $delay seconds with pid $::top_pid, issue machine_stats -stop to kill it"
unsuppress_message CMD-041
} else {
return "ERROR!! -start or -stop are required, Exiting"
}
}
define_proc_attributes machine_stats \
-info "USER PROC: Use machine_stats -start and machine_stats -stop in scripts to start and stop batch top jobs and record results into top.log file" \
-define_args {
{-start "Optional - starts and runs a batch top job until machine_stats -stop is issued to kill it" "" boolean optional}
{-stop "Optional - stops an earlier batch top job started with machine_stats -start" "" boolean optional}
{-delay "Optional - refreshes top every given seconds, default is 60sec" "" int optional}
{-top_log "Optional - output top log file, default top.log" "" string optional}
}
echo "\tmachine_stats"
#------------------------------------------------------------------------------------------------#
#-- END
#------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#-- all_commands
#------------------------------------------------------------------------------------------------#
#-- USAGE :
#-- pt_shell> all_commands * -verbose
proc all_commands {args} {
parse_proc_arguments -args $args results
echo "#-- ALL COMMANDS --#"
help *$results(pattern)*
if {[info exists results(-verbose)]} {
echo "********* -help *************"
apropos *$results(pattern)*
}
}; # end proc
define_proc_attributes all_commands -info "lists all commands and their set explanation" \
-define_args {
{pattern "Pattern to search for" pattern string required}
{-verbose "Search -help as well" "" boolean optional}}
#------------------------------------------------------------------------------------------------#
#-- END
#------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#-- all_variables
#------------------------------------------------------------------------------------------------#
#-- USAGE :
#-- pt_shell> all_variables * -verbose
proc all_variables {args} {
parse_proc_arguments -args $args results
echo "#-- ALL VARIABLES --#"
uplevel "printvar *$results(pattern)*"
#-- if {[info exists results(-verbose)]} {
#-- echo "********* -help *************"
#-- apropos *$results(pattern)*
#-- }
}; # end proc
define_proc_attributes all_variables -info "lists all variables and their current values" \
-define_args {
{pattern "Pattern to search for" pattern string required}
{-verbose "Search -help as well" "" boolean optional}}
#------------------------------------------------------------------------------------------------#
#-- END
#------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#-- get_blocking_arcs
#------------------------------------------------------------------------------------------------#
#-- USAGE :
#-- pt_shell> get_blocking_arcs -from_pin/CP -to_pin /D
proc intersect {a b} {return [remove_from_collection $a [remove_from_collection $a $b]]}
proc get_blocking_arcs {args} {
set results(-include_net_arcs) 0
parse_proc_arguments -args $args results
if {[set p1 [get_pins $results(-from_pin)]] eq {}} {return 0}
if {[set p2 [get_pins $results(-to_pin)]] eq {}} {return 0}
# get intersection pins
set fanout [all_fanout -flat -from $p1 -trace_arcs all]
set fanin [all_fanin -flat -to $p2 -trace_arcs all]
if {[set intersection [intersect $fanin $fanout]] eq {}} {
echo "Error: no topological path between the pins."
return 0
}
# populate intersection pins into an array for efficient testing
foreach_in_collection pin $intersection {
set intersection_pin([get_object_name $pin]) 1
}
# determine the timing arc pin pairs between the pins
foreach_in_collection arc [expr {$results(-include_net_arcs) ? [get_timing_arcs -from $intersection] : [get_timing_arcs -from $intersection -filter {defined(sense) && sense != ""}]}] {
set from_pin_name [get_object_name [get_attribute $arc from_pin]]
set to_pin_name [get_object_name [get_attribute $arc to_pin]]
if {[info exists intersection_pin($to_pin_name)]} {
set pin_pairs([list $from_pin_name $to_pin_name]) 1
}
}
# now check each pin pair to see if traversal is blocked here
foreach pair [array names pin_pairs] {
foreach {from_pin_name to_pin_name} $pair {}
if {[intersect $p1 [all_fanin -flat -to $from_pin_name]] eq {} && [intersect $p2 [all_fanout -flat -from $to_pin_name]] eq {}} {
lappend unreachable $pair
}
if {[intersect $p2 [all_fanout -flat -from $to_pin_name]] ne {} && [intersect $p2 [all_fanout -flat -from $from_pin_name]] eq {}} {
lappend fanout_blocked $pair
}
if {[intersect $p1 [all_fanin -flat -to $from_pin_name]] ne {} && [intersect $p1 [all_fanin -flat -to $to_pin_name]] eq {}} {
lappend fanin_blocked $pair
}
}
# print results
if {[info exists fanin_blocked]} {
echo "\n"
echo "FANIN FROM '[get_object_name $p1]' BLOCKED AT TIMING ARCS :"
foreach pair $fanin_blocked {
echo " [lindex $pair 0] -> [lindex $pair 1]"
}
echo "\n"
}
if {[info exists unreachable]} {
echo "UNREACHABLE TIMING ARCS :"
foreach pair $unreachable {
echo " [lindex $pair 0] -> [lindex $pair 1]"
}
echo "\n"
}
if {[info exists fanout_blocked]} {
echo "FANOUT TO '[get_object_name $p2]' BLOCKED AT TIMING ARCS :"
foreach pair $fanout_blocked {
echo " [lindex $pair 0] -> [lindex $pair 1]"
}
}
echo "\n"
}
return [expr $a > $b ? $a : $b]
}
proc min {a b} {
return [expr $a < $b ? $a : $b]
}
}
#-------------------------------------------------------------#
#-- MY procs
#-------------------------------------------------------------#
alias all "source ../custom/custom.csv_report/all_together.tcl"
alias ts "timing_summary"
alias gon "get_object_name "
alias fic "foreach_in_collection "
alias soc "sizeof_collection "
alias gat "get_attribute "
alias lat "list_attributes -application -nosplit -class"
alias rat "report_attribute -application -nosplit -class"
alias gp "get_pins "
alias gpo "get_ports "
alias gc "get_cells "
alias glc "get_lib_cells "
alias glp "get_lib_pins "
alias gn "get_nets "
alias galc "get_alternative_lib_cells "
alias gclk "get_clocks "
alias ggclk "get_generated_clocks "
alias gtp "get_timing_paths "
alias ac "all_connected "
alias aclf "all_connected -leaf "
alias rt "report_timing "
alias rac "report_analysis_coverage "
alias rdc "report_delay_calculation "
alias ut "update_timing -full"
alias rcmt "report_constraint -all_violators -max_transition -nosplit"
alias gd "get_drivers"
alias gl "get_loads"
alias gpg "get_path_groups"
#----------------------------------------------------------------------------------------------------------#
#-- END
#----------------------------------------------------------------------------------------------------------#
#----------------------------------------------------------------------------------------------------------#
#-- SETTING CUSTOM VARIABLES
#----------------------------------------------------------------------------------------------------------#
#-- THIS VARIABLE sdc_save_source_file_information prints the line where the exception is faulty
set_app_var sdc_save_source_file_information true
#----------------------------------------------------------------------------------------------------------#
#-- END
#----------------------------------------------------------------------------------------------------------#
#----------------------------------------------------------------------------------------------------------#
#-- LOCAL_PROCS
#----------------------------------------------------------------------------------------------------------#
proc gpl {var} {
foreach_in_collection pin [get_pins $var] {
puts "[gon $pin]"
}
}
proc gpol {var} {
foreach_in_collection port [get_ports $var] {
puts "[gon $port]"
}
}
proc gcl {var} {
foreach_in_collection cell [get_cells $var] {
puts "[gon $cell]"
}
}
proc glcl {var} {
foreach_in_collection lib_cell [get_lib_cells $var] {
puts "[gon $lib_cell]"
}
}
proc glpl {var} {
foreach_in_collection lib_pin [get_lib_pins $var] {
puts "[gon $lib_pin]"
}
}
proc gnl {var} {
foreach_in_collection net [get_nets $var] {
puts "[gon $net]"
}
}
proc galcl {var} {
foreach_in_collection alternative_lib_cell [get_alternative_lib_cells $var] {
puts "[gon $alternative_lib_cell]"
}
}
proc gclkl {var} {
foreach_in_collection clock [get_clocks $var] {
puts "[gon $clock]"
}
}
proc ggclkl {var} {
foreach_in_collection gen_clock [get_generated_clocks $var] {
puts "[gon $gen_clock]"
}
}
proc gtpl {var} {
foreach_in_collection timing_path [get_timing_paths $var] {
puts "[gon $timing_path]"
}
}
proc gpgl {var} {
foreach_in_collection path_group [get_path_groups $var] {
puts "[gon $path_group]"
}
}
proc acl {var} {
foreach_in_collection all_connection [all_connected [get_nets -of [get_pins $var]]] {
puts "[gon $all_connection]"
}
}
proc ll {var} {
fic var1 $var {
puts "[gon $var1]"
}
}
###Prints all connected output/inout pins if pin is input port
###Prints all connected input/inout pins if pin is output port
proc qnp {pin} {
if {[gat [gp $pin] direction]=="in"} {
fic p1 [aclf [ac $pin]] {
if {[gat [gp $p1] direction]=="out" || [gat [gp $p1] direction]=="inout" } {
puts "[gon $p1]"
}
}
} elseif {[gat [gp $pin] direction]=="out"} {
fic p1 [gp -of [gc -of [gp $pin]]] {
if {[gat [gp $p1] direction]=="in" || [gat [gp $p1] direction]=="inout" } {
puts "[gon $p1]"
}
}
}
}
proc qns {pin} {
if {[gat [gp $pin] direction]=="out"} {
fic p1 [aclf [ac $pin]] {
if {[gat [gp $p1] direction]=="in" || [gat [gp $p1] direction]=="inout" } {
puts "[gon $p1]"
}
}
} elseif {[gat [gp $pin] direction]=="in"} {
fic p1 [gp -of [gc -of [gp $pin]]] {
if {[gat [gp $p1] direction]=="out" || [gat [gp $p1] direction]=="inout" } {
puts "[gon $p1]"
}
}
}
}
proc ref_name {cell} {
puts "[gat [gc $cell] ref_name]"
}
proc lib_cell {cell} {
puts "[gon [gat [gc $cell] lib_cell]]"
}
proc get_instance {lib_cell} {
fic c1 [gc "*" -hier -filter "ref_name == $lib_cell"] {
puts "[gon $c1]"
}
}
proc clocks {pin} {
puts "[gon [gat [gp $pin] clocks]]"
}
proc case_value {pin} {
puts "[gat [gp $pin] case_value]"
}
proc constant_value {pin} {
puts "[gat [gp $pin] constant_value]"
}
proc is_sequential {cell} {
puts "[gat [gc $cell] is_sequential]"
}
proc is_combinational {cell} {
puts "[gat [gc $cell] is_combinational]"
}
proc is_integrated_clock_gating_cell {cell} {
puts "[gat [gc $cell] is_integrated_clock_gating_cell]"
}
#----------------------------------------------------------------------------------------------------------#
#-- END
#----------------------------------------------------------------------------------------------------------#
#----------------------------------------------------------------------------------------------------------#
#-- report_cells_on_clock_data_network
#----------------------------------------------------------------------------------------------------------#
proc report_cells_on_clock_data_network { args } {
set options(-network) both
set options(-exclude_lib_cells) ""
set options(-lib_cells) ""
parse_proc_arguments -args $args options
if { $options(-lib_cells)!="" && $options(-exclude_lib_cells)!="" } {
echo " -lib_cells and -exclude_lib_cells are mutually exclusive options, please specify only one of them"
return 0
} elseif { $options(-lib_cells)=="" && $options(-exclude_lib_cells)=="" } {
echo " either -lib_cells and -exclude_lib_cells options are required, please specify one of them"
return 0
}
if { $options(-lib_cells)!="" } {
set lib_cells $options(-lib_cells)
set operator1 "="
set operator2 "||"
set tag ""
} else {
set lib_cells $options(-exclude_lib_cells)
set operator1 "!"
set operator2 "&&"
set tag (excluded)
}
set network $options(-network)
set count [llength $lib_cells]
set filter_option ""
foreach lib_cell $lib_cells {
set count [expr $count - 1]
if { [regexp \\* $lib_cell ] } {
set filter_option "$filter_option ref_name${operator1}~${lib_cell}"
} else {
set filter_option "$filter_option ref_name${operator1}=${lib_cell}"
}
if { [expr $count > 0] } {
set filter_option "$filter_option $operator2"
}
}
#echo "$filter_option"
set instances_of_lib_cells [get_cells -hier * -filter "$filter_option"]
set clock_path_cells ""
set data_path_cells ""
foreach_in_collection cell $instances_of_lib_cells {
if { [get_attribute -quiet [get_pins -of [get_cells $cell]] clocks ] != "" } {
set clock_path_cells [add_to_collection $clock_path_cells $cell]
} else {
set data_path_cells [add_to_collection $data_path_cells $cell]
}
}
if { $network=="clock" || $network =="both"} {
echo "##################################################################"
echo "Cells on Clock Network of Lib Cells $tag: $lib_cells"
echo "##################################################################"
if { [sizeof $clock_path_cells] =="0" } { echo "None" }
foreach_in_collection cellc $clock_path_cells {
echo "[get_object_name $cellc] [get_attribute $cellc ref_name]"
}
}
if { $network=="data" || $network =="both" } {
echo "##################################################################"
echo "Cells on Data Network of Lib Cells $tag: $lib_cells"
echo "##################################################################"
if { [sizeof $data_path_cells] =="0" } { echo "None" }
foreach_in_collection celld $data_path_cells {
echo "[get_object_name $celld]\t[get_attribute $celld ref_name]"
}
}
return 1
}
define_proc_attributes report_cells_on_clock_data_network \
-info "report the given lib cells are on clock or data network " \
-define_args \
{
{ -network "report for clock, data or both" "" one_of_string {optional {values {clock data both}}} }
{ -lib_cells "list of lib_cells, wild cards supported" "
- " string optional }
{ -exclude_lib_cells "list of lib cells to be excluded, wild cards supported" "
- " string optional }
}
#----------------------------------------------------------------------------------------------------------#
#-- END
#----------------------------------------------------------------------------------------------------------#
#----------------------------------------------------------------------------------------------------------#
#-- report_slack_distribution
#----------------------------------------------------------------------------------------------------------#
proc report_slack_distribution { targetClock {marginPoints "0 .5 1 1.5" } {ListEndPoints 0}} {
#
# 5/8/97 xxxxxxx
# 6/13/05 update to tcl commands
# report_slack_distribution
# positionals
# target clock name
# list of interesting margin points
# list end points
#
# usage:
# report_slack_dist sysclk "0 0.1 0.5 1 2 3 4" 0
#
# reports the total negative slack, the worst violator at the given clock
# and then calculates the number of violating paths at each of the margin
# points subtracted from the clock
#
# Here is a sample report
#
# Timing Information for clock clk with 128 total endpoints:
#
# Worst Negative Slack: -1.39365
#
# margin Num. of Violators Total Neg. Slack percent violators
# ------ ----------------- ---------------- -----------------
# 0 16 -17.9794 13
# .5 24 -27.77 19
# 1 24 -39.7698 19
# 1.5 28 -53.1804 22
#
#set ListEndPoints 0
#set marginPoints 0.0
set WNS 100000.0
set TE 0
foreach margin $marginPoints {
set TNS($margin) 0.0
set NVE($margin) 0
set PCT($margin) 0
}
set pathsPerEndpoint 1
echo ""
echo "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-"
echo " Analyzing end point slack clocked by $targetClock"
echo "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-"
# find all the endpoints clocked by targetClock
set allRegisterPins [all_registers -clock $targetClock -data]
set allOutputPorts [all_outputs -clock $targetClock]
set allEndPoints [concat $allRegisterPins $allOutputPorts]
foreach_in_collection endPoint $allEndPoints {
# get and print the startpoint, arrival and slack
set maxTimingSelection [get_timing_path -nworst $pathsPerEndpoint -to $endPoint -delay max]
set firstFor 1
foreach_in_collection path $maxTimingSelection {
set TE [expr $TE + 1]
set slack [get_attribute $path slack]
set startpoint [get_attribute $path startpoint]
if { $firstFor == 1 } {
if { $slack < $WNS } {
set WNS $slack
}
if { $ListEndPoints == 1 } {
if { $slack < 0.0 } {
echo [format "Slack of %-5.2f from %-30s to %-30s" \
$slack [get_object_name $startpoint ] \
[get_object_name $endPoint ] ]
}
}
foreach margin $marginPoints {
if { $slack < $margin } {
set TNS($margin) [expr $TNS($margin) + ($slack-$margin)]
set NVE($margin) [expr $NVE($margin) + 1]
}
}
}
}
}
echo ""
echo "Timing Information for clock $targetClock with $TE total endpoints:"
echo ""
echo [format " Worst Negative Slack: %-20.2f" $WNS]
echo ""
echo " margin Num. of Violators Total Neg. Slack percent violators"
echo " ------ ----------------- ---------------- -----------------"
foreach margin $marginPoints {
echo [format "%6.2f %13d %14.2f %5.1f " \
$margin $NVE($margin) $TNS($margin) [expr 100-(100*($TE-$NVE($margin))/$TE) ]]
}
}
#------------------------------------------------------------------------------------------------#
#-- END
#------------------------------------------------------------------------------------------------#
#-- #----------------------------------------------------------------------------------------------------------#
#-- #-- curdes_prompt
#-- #----------------------------------------------------------------------------------------------------------#
#--
#-- proc curdes_prompt {} {
#-- global sh_dev_null
#-- global synopsys_program_name
#-- set des ""
#-- redirect $sh_dev_null {set des [current_design]}
#-- if { $des == "" } {
#-- echo -n "${synopsys_program_name}> "
#-- return
#-- }
#-- set des [get_object_name $des]
#-- set inst ""
#-- redirect $sh_dev_null {set inst [current_instance .]}
#-- if { $inst == "" } {
#-- set sep ""
#-- } else {
#-- set sep "/"
#-- }
#-- #-- "SETTING PRIMETIME PROMPT"
#-- set prmpt "${des}${sep}${inst}-pt_shell-> "
#-- #-- set prmpt "PRIMETIME-> "
#-- echo -n ${prmpt}
#-- }
#-- set tcl_prompt1 curdes_prompt
#-- #-- unset tcl_prompt1 curdes_prompt
#-- #------------------------------------------------------------------------------------------------#
#-- #-- END
#-- #------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#-- write_path_summary
#------------------------------------------------------------------------------------------------#
#-- USAGE :
#-- e.g.
#-- set paths [get_timing_paths -delay_type max -slack_lesser_than 1000 -max_paths 10]
#-- process_paths $paths
#-- write_path_summary -fields {index endpoint slack duration crpr num_segments num_unique_segments num_segment_crossings max_trans skew}
#-- where '-fields' can be
#-- index - index number of path in original path collection (0, 1, 2...)
#-- startpoint - name of path startpoint
#-- endpoint - name of path endpoint
#-- start_clk - name of startpoint launching clock
#-- end_clk - name of endpoint capturing clock
#-- launch_latency - launching clock latency
#-- capture_latency - capturing clock latency
#-- skew - skew between launch/capture clock (negative is tighter)
#-- crpr - clock reconvergence pessimism removal amount
#-- path_group - path group name
#-- slack - path slack
#-- duration - combinational path delay between startpoint and endpoint
#-- levels - levels of combinational logic
#-- hier_pins - number of hierarchy pins in path
#-- num_segments - number of segments in path
#-- num_unique_segments - number of unique segments in path
#-- num_segment_crossings - number of segment crossings in path
#-- average_cell_delay - average combinational cell delay (duration / levels)
#-- slowest_cell - name of slowest cell in path
#-- slowest_cell_delay - cell delay of slowest cell in path
#-- slowest_net - name of slowest net in path
#-- slowest_net_delay - net delay of slowest net in path
#-- slowest_net_R - resistance of slowest net in path
#-- slowest_net_C - capacitance of slowest net in path
#-- total_net_delay - summation of all net delays in path
#-- max_trans - slowest pin transition in path
#-- total_xtalk_data - summation of all crosstalk deltas in data path
#-- total_xtalk_clock - summation of all crosstalk deltas in clock path
#-- total_xtalk - summation of all crosstalk deltas in clock/data path
#-- xtalk_ratio - percentage ratio of 'total_xtalk_data' versus 'duration'
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 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}
}
#------------------------------------------------------------------------------------------------#
#-- END
#------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#-- get_drivers get_loads
#------------------------------------------------------------------------------------------------#
proc get_drivers {args} {
parse_proc_arguments -args $args results
# if it's not a collection, convert into one
redirect /dev/null {set size [sizeof_collection $results(object_spec)]}
if {$size == ""} {
set objects {}
foreach name $results(object_spec) {
if {[set stuff [get_ports -quiet $name]] == ""} {
if {[set stuff [get_cells -quiet $name]] == ""} {
if {[set stuff [get_pins -quiet $name]] == ""} {
if {[set stuff [get_nets -quiet $name]] == ""} {
continue
}
}
}
}
set objects [add_to_collection $objects $stuff]
}
} else {
set objects $results(object_spec)
}
if {$objects == ""} {
echo "Error: no objects given"
return 0
}
set driver_results {}
# process all cells
if {[set cells [get_cells -quiet $objects]] != ""} {
# add driver pins of these cells
set driver_results [add_to_collection -unique $driver_results \
[get_pins -quiet -of $cells -filter "pin_direction == out || pin_direction == inout"]]
}
# get any nets
set nets [get_nets -quiet $objects]
# get any pin-connected nets
if {[set pins [get_pins -quiet $objects]] != ""} {
set nets [add_to_collection -unique $nets \
[get_nets -quiet -of $pins]]
}
# get any port-connected nets
if {[set ports [get_ports -quiet $objects]] != ""} {
set nets [add_to_collection -unique $nets \
[get_nets -quiet -of $ports]]
}
# process all nets
if {$nets != ""} {
# add driver pins of these nets
set driver_results [add_to_collection -unique $driver_results \
[get_pins -quiet -leaf -of $nets -filter "pin_direction == out || pin_direction == inout"]]
set driver_results [add_to_collection -unique $driver_results \
[get_ports -quiet -of $nets -filter "port_direction == in || port_direction == inout"]]
}
# return results
return $driver_results
}
define_proc_attributes get_drivers \
-info "Return driver ports/pins of object" \
-define_args {\
{object_spec "Object(s) to report" "object_spec" string required}
}
proc get_loads {args} {
parse_proc_arguments -args $args results
# if it's not a collection, convert into one
redirect /dev/null {set size [sizeof_collection $results(object_spec)]}
if {$size == ""} {
set objects {}
foreach name $results(object_spec) {
if {[set stuff [get_ports -quiet $name]] == ""} {
if {[set stuff [get_cells -quiet $name]] == ""} {
if {[set stuff [get_pins -quiet $name]] == ""} {
if {[set stuff [get_nets -quiet $name]] == ""} {
continue
}
}
}
}
set objects [add_to_collection $objects $stuff]
}
} else {
set objects $results(object_spec)
}
if {$objects == ""} {
echo "Error: no objects given"
return 0
}
set load_results {}
# process all cells
if {[set cells [get_cells -quiet $objects]] != ""} {
# add load pins of these cells
set load_results [add_to_collection -unique $load_results \
[get_pins -quiet -of $cells -filter "pin_direction == in || pin_direction == inout"]]
}
# get any nets
set nets [get_nets -quiet $objects]
# get any pin-connected nets
if {[set pins [get_pins -quiet $objects]] != ""} {
set nets [add_to_collection -unique $nets \
[get_nets -quiet -of $pins]]
}
# get any port-connected nets
if {[set ports [get_ports -quiet $objects]] != ""} {
set nets [add_to_collection -unique $nets \
[get_nets -quiet -of $ports]]
}
# process all nets
if {$nets != ""} {
# add load pins of these nets
set load_results [add_to_collection -unique $load_results \
[get_pins -quiet -leaf -of $nets -filter "pin_direction == in || pin_direction == inout"]]
set load_results [add_to_collection -unique $load_results \
[get_ports -quiet -of $nets -filter "port_direction == out || port_direction == inout"]]
}
# return results
return $load_results
}
define_proc_attributes get_loads \
-info "Return load ports/pins of object" \
-define_args {\
{object_spec "Object(s) to report" "object_spec" string required}
}
#------------------------------------------------------------------------------------------------#
#-- END
#------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#-- get_failing_paths_high_slew
#------------------------------------------------------------------------------------------------#
#-- USAGE
#-- get_failing_paths_high_slew 1 max 0.01
#-- All Violations of nworst 1 and for 'max' paths with trans above 0.01
proc get_failing_paths_high_slew { Nworst_numb Path_type Tran_threshold } {
set Nworst_numb $Nworst_numb
set Path_type $Path_type
set Tran_threshold $Tran_threshold
foreach_in_collection path [get_timing_paths -delay_type $Path_type -nworst $Nworst_numb] {
foreach_in_collection itr $path {
set cnt 0
set Slack [get_attribute $itr slack]
set StartPoint [get_object_name [get_attribute $itr startpoint] ]
set EndPoint [get_object_name [get_attribute $itr endpoint] ]
if { $Slack < 1000.0 } {
if { $cnt == 0 } {
echo " Timing path fails: \t Start point: $StartPoint \t End Point $EndPoint \t Slack: $Slack";
set $cnt [ expr $cnt + 1]
}
;# violating paths next
foreach_in_collection point [get_attribute $path points] {
set Object [get_attribute $point object]
set Obj_name [get_object_name [get_attribute $point object] ]
set Obj_r_f [get_attribute $point rise_fall]
set Slew_att [format "actual_%s_transition_%s" $Obj_r_f $Path_type]
set Slew_val [ get_attribute $Object $Slew_att]
set Cell [ get_cells -quiet -of_objects $Object ]
if { [get_attribute -quiet $Object is_port] == "false" } {
set Lib_cell [ get_lib_cells -of_objects $Cell ]
set Ref_name [ get_attribute $Lib_cell base_name ]
} else {
;# it's a port
set Ref_name $Object
}
if { $Slew_val > $Tran_threshold } {
echo " has a $Obj_r_f slew = $Slew_val on pin $Obj_name \t Reference = $Ref_name"
}
} ;# end of foreach point
} else {
continue
;# slack is > 0.0 no violation
;# go to next timing path
}
}; # end foreach $path
} ;# end of foreach get_timing_path
;# variable cleanup
#-- unset Slack Obj_name Obj_r_f Slew_att Slew_val Nworst_numb Path_type Tran_threshold
} ;# end of proc
#------------------------------------------------------------------------------------------------#
#-- END
#------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#-- report_critical_loads
#------------------------------------------------------------------------------------------------#
namespace eval rcl {
proc pin_basename {object} {
set basename [get_attribute $object lib_pin_name]
set fullname [get_attribute $object full_name]
return [string range $fullname 0 [expr [string last $basename $fullname]-2]]
}
proc net_basename {object} {
set basename [get_attribute $object base_name]
set fullname [get_attribute $object full_name]
return [string range $fullname 0 [expr [string last $basename $fullname]-2]]
}
proc net_loads {net} {
set loads {}
foreach_in_collection object [all_connected $net] {
set direction [get_attribute $object direction]
if {[get_attribute $object object_class] == "pin" && [pin_basename $object] != [net_basename $net]} {
# pin at deeper hierarchical level
if {$direction != "out"} {
set loads [add_to_collection $loads $object]
}
} else {
# pin at same hierarchical level
if {$direction != "in"} {
set loads [add_to_collection $loads $object]
}
}
}
return $loads
}
proc net_drivers {net} {
set drivers {}
foreach_in_collection object [all_connected $net] {
set direction [get_attribute $object direction]
if {[get_attribute $object object_class] == "pin" && [pin_basename $object] != [net_basename $net]} {
# pin at deeper hierarchical level
if {$direction != "in"} {
set drivers [add_to_collection $drivers $object]
}
} else {
# pin at same hierarchical level
if {$direction != "out"} {
set drivers [add_to_collection $drivers $object]
}
}
}
return $drivers
}
proc max {a b} {return [expr {$a > $b ? $a : $b}]}
}
proc report_critical_loads {args} {
set results(-delay) "max"
parse_proc_arguments -args $args results
if {$::timing_save_pin_arrival_and_slack != "true"} {
echo "Error: the variable 'timing_save_pin_arrival_and_slack' must be set to 'true' for this procedure"
return 0
}
if {[set nets [get_nets -seg -quiet $results(object)]] == ""} {
if {[set object [get_pins -quiet $results(object)]] == ""} {
if {[set object [get_ports -quiet $results(object)]] == ""} {
echo "Error: couldn't find specified object"
return 0
} else {
set nets [get_nets -seg -of $object]
}
} else {
set nets [get_nets -seg -of $object]
}
}
set driver_load([list 0 1]) "load"
set driver_load([list 1 0]) "driver"
set driver_load([list 1 1]) "driver/load"
set min_max "max"
set max_pre 0
set max_post 0
echo "Number of net segments: [sizeof_collection $nets]"
echo ""
foreach_in_collection net $nets {
set driver_object_slack_list {}
set load_object_slack_list {}
echo "Net segment '[set net_name [get_object_name $net]]':"
# determine drivers/loads
set drivers [rcl::net_drivers $net]
set loads [rcl::net_loads $net]
# determine max length of all loads and driver slacks
set max_name_length 0
foreach_in_collection object [add_to_collection -unique $drivers $loads] {
set rise_slack [get_attribute $object ${min_max}_rise_slack]
set fall_slack [get_attribute $object ${min_max}_fall_slack]
# handle unconstrained load pins
if {$rise_slack == {INFINITY} && $fall_slack == {INFINITY}} {
set slack {INFINITY}
} else {
set slack [expr {"$rise_slack" < "$fall_slack" ? "$rise_slack" : "$fall_slack"}]
}
regexp {([-0-9]*\.?)(.*)} $slack dummy pre post
set max_pre [rcl::max $max_pre [string length $pre]]
set max_post [rcl::max $max_post [string length $post]]
set max_name_length [rcl::max $max_name_length [string length [get_object_name $object]]]
set is_driver [expr {[remove_from_collection $object $drivers] == ""}]
set is_load [expr {[remove_from_collection $object $loads] == ""}]
if {$is_driver} {
lappend driver_object_slack_list [list $object $slack $is_driver $is_load]
} else {
lappend load_object_slack_list [list $object $slack $is_driver $is_load]
}
}
set max_slack_length [expr $max_pre + $max_post]
echo [format "%-${max_slack_length}s %s" "slack" "name"]
echo [string repeat "-" [expr {$max_slack_length + 1 + $max_name_length}]]
set driver_object_slack_list [lsort -real -index 1 -increasing $driver_object_slack_list]
set load_object_slack_list [lsort -real -index 1 -increasing $load_object_slack_list]
foreach object [concat $driver_object_slack_list $load_object_slack_list] {
set obj [lindex $object 0]
set driver_or_load $driver_load([list [lindex $object 2] [lindex $object 3]])
set object_class [get_attribute $obj object_class]
if {$object_class == "pin"} {
set driver_or_load "[expr {[get_attribute [get_cells -of $obj] is_hierarchical] == "true" ? "hierarchical" : "leaf"}] $driver_or_load"
}
echo [format "%${max_slack_length}.${max_post}f %s (%s %s)" [lindex $object 1] [get_object_name $obj] $driver_or_load $object_class]
}
echo ""
echo "insert_buffer \[get_pins {"
foreach load_pin $load_object_slack_list {
echo " [get_object_name [lindex $load_pin 0]]"
}
echo "}\] lib/cell"
echo ""
echo ""
}
}
define_proc_attributes report_critical_loads \
-info "Show loads on a net sorted by slack" \
-define_args {\
{-delay_type "Type of slack to analyze" type one_of_string {optional value_help {values {min max}}}}
{object "Net, pin, or port to analyze" "objects" string required}
}
#------------------------------------------------------------------------------------------------#
#-- END
#------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#-- check_data_pulse_width [all_outputs]
#------------------------------------------------------------------------------------------------#
proc check_data_pulse_width {args} {
global sh_dev_null
set results(-verbose) 0
set results(data_pins) {}
set results(-width) 1.0
parse_proc_arguments -args $args results
if {! $results(-width) > 0.0} {
echo "Error: pulse width must be a positive value"
return 0
}
if {$results(data_pins) == ""} {
set results(data_pins) [all_registers -data_pins]
}
set pins [get_pins -quiet $results(data_pins)]
# support passing in a collection of ports (outputs or inouts) for pulsewidth calculation
set pins [add_to_collection $pins [get_ports -quiet $results(data_pins)]]
set rise_paths [get_timing_paths -delay max_rise -to $pins -max_paths 99999]
set fall_paths [get_timing_paths -delay max_fall -to $pins -max_paths 99999]
# first, do rising setup arrivals, falling hold arrivals
foreach_in_collection this_path $rise_paths {
set this_pin [get_attribute $this_path endpoint]
set max_this_pin_clock_close_edge_value [get_attribute -quiet $this_path endpoint_clock_close_edge_value]
set arrival_windows [lindex [get_attribute $this_pin arrival_window] 0]
if {$max_this_pin_clock_close_edge_value == ""} {continue}
# determine latest rising arrival, earliest falling arrival
set latest_rise_arrival {}
set earliest_fall_arrival {}
foreach window $arrival_windows {
# {CLK1} pos_edge {min_r_f 0.30098 0.328784} {max_r_f 0.30098 0.328784}
set max_rise_arrival [lindex [lindex $window 3] 1]
set min_fall_arrival [lindex [lindex $window 2] 2]
if {$latest_rise_arrival == "" || $max_rise_arrival > $latest_rise_arrival} {
set latest_rise_arrival $max_rise_arrival
}
if {$earliest_fall_arrival == "" || $min_fall_arrival < $earliest_fall_arrival} {
set earliest_fall_arrival $min_fall_arrival
}
}
set setup_window [expr $max_this_pin_clock_close_edge_value - $latest_rise_arrival]
set hold_window $earliest_fall_arrival
set pulse_width [expr $setup_window + $hold_window]
if {$results(-verbose) || $pulse_width < $results(-width)} {
echo "Rising setup window: $setup_window ($max_this_pin_clock_close_edge_value - $latest_rise_arrival)"
echo "Falling hold window: $earliest_fall_arrival"
echo "Active high pulse width for [get_object_name $this_pin]: $pulse_width ($setup_window $hold_window)\n"
}
}
# second, do falling setup arrivals, rising hold arrivals
foreach_in_collection this_path $fall_paths {
set this_pin [get_attribute $this_path endpoint]
set max_this_pin_clock_close_edge_value [get_attribute -quiet $this_path endpoint_clock_close_edge_value]
set arrival_windows [lindex [get_attribute $this_pin arrival_window] 0]
if {$max_this_pin_clock_close_edge_value == ""} {continue}
# determine latest falling arrival, earliest rising arrival
set latest_fall_arrival {}
set earliest_rise_arrival {}
foreach window $arrival_windows {
# {CLK1} pos_edge {min_r_f 0.30098 0.328784} {max_r_f 0.30098 0.328784}
set max_fall_arrival [lindex [lindex $window 3] 2]
set min_rise_arrival [lindex [lindex $window 2] 1]
if {$latest_fall_arrival == "" || $max_fall_arrival > $latest_fall_arrival} {
set latest_fall_arrival $max_fall_arrival
}
if {$earliest_rise_arrival == "" || $min_rise_arrival < $earliest_rise_arrival} {
set earliest_rise_arrival $min_rise_arrival
}
}
set setup_window [expr $max_this_pin_clock_close_edge_value - $latest_fall_arrival]
set hold_window $earliest_rise_arrival
set pulse_width [expr $setup_window + $hold_window]
if {$results(-verbose) || $pulse_width < $results(-width)} {
echo "Falling setup window: $setup_window ($max_this_pin_clock_close_edge_value - $latest_fall_arrival)"
echo "Rising hold window: $earliest_rise_arrival"
echo "Active low pulse width for [get_object_name $this_pin]: $pulse_width ($setup_window $hold_window)\n"
}
}
echo "Analysis of [sizeof_collection $pins] pin(s) complete."
}
define_proc_attributes check_data_pulse_width \
-info "checks data pulse width between setup/hold edge arrivals" \
-define_args \
{
{-verbose "show details of calculation" "" boolean optional}
{-width "minimum pulse width between setup/hold edge arrivals" min_width string optional}
{data_pins "data pins to check" "data_pins" string optional}
}
#------------------------------------------------------------------------------------------------#
#-- END
#------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#-- si_net_delta_delay
#------------------------------------------------------------------------------------------------#
#-- For finding the crosstalk delta delay associated with a net.
#-- It takes a net and returns the delta_delay for that net.
proc find_delta { net {min_max ""} {rise_fall ""} } {
set net_arcs [get_timing_arcs -of_objects $net]
set worst_delta 0.0
set abs_delta 0.0
if {$min_max == ""} {
set min_max "min max"
}
if {$rise_fall == ""} {
set rise_fall "rise fall"
}
set worst_mm_rf "$min_max\_$rise_fall"
foreach mm $min_max {
foreach rf $rise_fall {
foreach_in_collection net_arc $net_arcs {
set delta [get_attribute $net_arc \
"annotated_delay_delta_$mm\_$rf"]
set abs_delta [expr abs($delta)]
if {$abs_delta > $worst_delta } {
set worst_mm_rf "$mm\_$rf"
set worst_delta $abs_delta
}
}
}
}
return $worst_delta
}
#-- This procedure takes a collection of nets and crosstalk delay threshold as inputs.
#-- It will then find all of the nets in the collection that equal or surpass the specified threshold.
#-- The procedure then returns an array of these nets, the delta delay of the net,
#-- the driving pin of the net, and the reference name (library cell) of the driving cell.
#-- Timing units of the Threshold are in library units. Threshold should be >= 0.
#-- It is required to source the find_delta.tcl procedure.
#--
#-- USAGE :
#-- #Find all clock nets of clk1 that have more than 50 ps of crosstalk delay
#-- set NETS [get_clock_network_objects clk1 -include -type net]
#-- set THRESH 0.050
#-- si_net_delta_delay $NETS $THRESH si_net_delay_array_clk1
#-- # To access the net names use the following command
#-- array names si_net_delay_array_clk1
proc si_net_delta_delay { NETS THRESH ARRAY} {
upvar $ARRAY NET_DELTA_ARRAY
foreach_in_coll NET [get_nets $NETS] {
set DELTA [find_delta $NET]
if {$DELTA >= $THRESH } {
set DRIVER [filter_coll [all_connected $NET] direction==out]
if {[sizeof_collection $DRIVER] !=0} {
set NET_DELTA_ARRAY([get_object_name $NET]) "$DELTA [get_object_name $DRIVER] [get_attr [get_cell -of_obj $DRIVER] ref_name]"
echo $NET_DELTA_ARRAY([get_object_name $NET])
} else {
echo "No driver cell for " [get_att $NET full_name ]
}
}
}
}
#------------------------------------------------------------------------------------------------#
#-- END
#------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#-- plot_lcd
#------------------------------------------------------------------------------------------------#
#-- plot cell delay versus load, area, always_on and dont_use
#-- USAGE :
#-- plot_lcd hs_invd4 I ZN
#-- libcell_delay_plot -help
proc libcell_delay_plot {args} {
global link_path
set results(-transition) 0
set results(-delay_type) {max}
set results(-load_indices) {0 1}
set results(-num_points) 200
parse_proc_arguments -args $args results
set lib_cell $results(cell)
set from_pin $results(-from_pin)
set to_pin $results(-to_pin)
if {![string is double [set min_slew [lindex $results(-load_indices) 0]]] ||
![string is double [set max_slew [lindex $results(-load_indices) 1]]]} {
echo "Error: non-float value given in slew range list"
return 0
}
set min_slew [expr double($min_slew)]
set max_slew [expr double($max_slew)]
# create indices
set indices [list [set lastindex [lindex $results(-load_indices) 0]]]
foreach index [lrange $results(-load_indices) 1 [expr [llength $results(-load_indices)]-1]] {
for {set i 1} {$i < $results(-num_points)} {incr i} {
lappend indices [expr $lastindex + (($index - $lastindex) * double($i) / ($results(-num_points)))]
}
lappend indices [set lastindex $index]
}
foreach lib $link_path {
if {$lib == {*}} {continue}
set libpath [which $lib]
if {$libpath != ""} {
if {[get_libs -quiet "*" -filter "source_file_name == $libpath"] == ""} {
read_db $libpath
}
}
}
if {[set cell [get_lib_cells -quiet $lib_cell]] == ""} {
foreach_in_collection lib [get_libs -quiet "*"] {
if {[set cell [get_lib_cells -quiet [get_object_name $lib]/$lib_cell]] != ""} {
break;
}
}
}
set cellname [get_attribute $cell base_name]
set fullcellname [get_attribute $cell full_name]
if {[get_lib_pins -of $cell -filter "base_name == $from_pin"] == ""} {
echo "Error: couldn't find $from_pin on $cellname"
return 0
}
if {[get_lib_pins -of $cell -filter "base_name == $to_pin"] == ""} {
echo "Error: couldn't find $to_pin on $cellname"
return 0
}
set outfile [expr {[info exists results(-output)] ? "$results(-output)" : "${cellname}.txt"}]
set pins(in) {}
set pins(out) {}
set pins(inout) {}
foreach_in_collection pin [get_lib_pins -of $cell] {
lappend pins([get_attribute $pin pin_direction]) [get_attribute $pin base_name]
}
set allpins [concat $pins(in) $pins(out) $pins(inout)];
redirect ~/_${cellname}.v {
echo "module ${cellname}_inst ([join $allpins {,}]);"
if {$pins(in) != ""} {echo "input [join $pins(in) {,}];"}
if {$pins(out) != ""} {echo "output [join $pins(out) {,}];"}
if {$pins(inout) != ""} {echo "inout [join $pins(inout) {,}];"}
echo "$cellname U ([join $allpins {,}]);"
echo "endmodule"
}
redirect /dev/null {remove_design -all}
redirect /dev/null {set success [read_verilog ~/_${cellname}.v]}
if {!$success} {
echo "Error: read of temporary netlist _${cellname} failed"
return 0
}
file delete _${cellname}.v
redirect /dev/null {set success [link]}
if {!$success} {
echo "Error: link of temporary netlist _${cellname} failed"
return 0
}
set_input_transition $results(-transition) [all_inputs]
if {[info exists results(-oc_condition)]} {
set_operating_condition -analysis_type bc_wc $results(-oc_condition)
} else {
set results(-oc_condition) "
}
redirect $outfile {
echo "# library cell: $fullcellname $from_pin -> $to_pin"
echo "# operating conditions: $results(-oc_condition)"
echo "# input pin transition: $results(-transition)"
foreach load $indices {
set_load -subtract_pin_load $load [get_nets "*"]
redirect /dev/null {update_timing}
set arcs [get_timing_arcs -from U/$from_pin -to U/$to_pin]
set dmaxr [get_attribute [index_collection [sort_collection $arcs delay_max_rise] 0] delay_max_rise]
set dmaxf [get_attribute [index_collection [sort_collection $arcs delay_max_rise] 0] delay_max_fall]
set dminr [get_attribute [index_collection [sort_collection -descending $arcs delay_max_rise] 0] delay_min_rise]
set dminf [get_attribute [index_collection [sort_collection -descending $arcs delay_max_rise] 0] delay_min_fall]
set area [get_attribute $fullcellname area]
echo $load $dmaxr $dmaxf $dminr $dminf $area
}
}
# now get time and load units
set tmpfilename "/tmp/[pid]_libinfo.txt"
redirect $tmpfilename {report_lib -nosplit [get_libs -of $cell]}
set file [open $tmpfilename]
set report_lib [read $file]
close $file
file delete $tmpfilename
regexp -linestop -- {Time Unit *: (.*)} $report_lib dummy time_unit
regexp -linestop -- {Capacitance Unit *: (.*)} $report_lib dummy cap_unit
# generate datafile
redirect ${outfile}.gnuplot {
echo "set data style linespoints"
echo "set key bottom right"
echo "set yrange \[0:\]"
echo "set title '$fullcellname $from_pin -> $to_pin ($results(-transition) slew on $from_pin)'"
echo "set label \" CELL $cellname\" right at graph 0.95, graph 0.28 font 'Calibri,12' textcolor lt 8"
echo "set label \"AREA (um^2) [get_attribute [get_lib_cells $fullcellname] area]\" right at graph 0.95, graph 0.24 font 'Courier,10' textcolor lt 3"
echo "set label \"ALWAYS_ON [get_attribute [get_lib_cells $fullcellname] always_on]\" right at graph 0.95, graph 0.21 font 'Courier,10' textcolor lt 3"
echo "set label \" DONT_USE [get_attribute [get_lib_cells $fullcellname] dont_use]\" right at graph 0.95, graph 0.18 font 'Courier,10' textcolor lt 3"
echo "set label \" DISABLE_TIMING [get_attribute [get_lib_cells $fullcellname] disable_timing]\" right at graph 0.95, graph 0.15 font 'Courier,10' textcolor lt 3"
echo "set xlabel 'output load ($cap_unit)'"
echo "set ylabel 'cell delay ($time_unit)'"
echo "set grid"
switch $results(-delay_type) {
max {
echo "plot '[pwd]/$outfile' using 1:2 title 'delay_max_rise'"
echo "replot '[pwd]/$outfile' using 1:3 title 'delay_max_fall'"
}
min {
echo "plot '[pwd]/$outfile' using 1:4 title 'delay_min_rise'"
echo "replot '[pwd]/$outfile' using 1:5 title 'delay_min_fall'"
}
}
}
echo " library cell: $fullcellname $from_pin -> $to_pin"
echo "operating conditions: $results(-oc_condition)"
echo "input pin transition: $results(-transition)"
echo ""
echo "ON UNIX SHELL, PLOT IT BY RUNNING :"
echo "\n"
echo " plot [pwd]/${outfile}.gnuplot"
echo "\n"
echo "\n"
}
define_proc_attributes libcell_delay_plot \
-info "plot cell delay versus load" \
-define_args {\
{-from_pin "from pin on cell" from_pin_name string required}
{-to_pin "from pin on cell" to_pin_name string required}
{-transition "input pin transition (default 0)" input_transition float optional}
{-delay_type "plot worst-case or best-case curves" type one_of_string {optional value_help {values {min max}}}}
{-oc_condition "operating condition" condition string optional}
{-load_indices "list of load indices {slew0 slew1 ...}" "indices" string optional}
{-num_points "number of points to interpolate per index" "num" int optional}
{-output "gnuplot output data file" "filename" string optional}
{cell "library cell, CELL or LIB/CELL" "cell" string required}
}
proc plot_lcd {lib_cell from_pin to_pin} {
libcell_delay_plot ${lib_cell} -from_pin ${from_pin} -to_pin ${to_pin}
file delete ~/_${lib_cell}.v
}
#------------------------------------------------------------------------------------------------#
#-- END
#------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#-- machine_stats
#------------------------------------------------------------------------------------------------#
#-- USAGE :
#-- pt_shell> machine_stats -start
#-- Top job started recording top.log every 60 seconds with pid 58347, issue machine_stats -stop to kill it.
#-- pt_shell> update_timing -full ; #or any command in any tool.
#-- pt_shell> machine_stats -stop
#-- Killing earlier top job with pid 58347.
proc machine_stats {args} {
suppress_message CMD-041
parse_proc_arguments -args ${args} opt
if {[info exists opt(-stop)]} {
if {![info exists ::top_pid]} { return "ERROR!! no prior top job started with machine_stats -start found to stop" }
echo "Killing earlier top job with pid $::top_pid"
puts "\n"
echo "Machine Usage details printed in "
echo "\t[pwd]/top.log"
puts "\n"
sh kill -9 $::top_pid
unset -nocomplain ::top_pid
return
} elseif {[info exists opt(-start)]} {
if {[info exists opt(-delay)]} { set delay $opt(-delay) } else { set delay 60 }
if {[info exists opt(-top_log)]} { set log $opt(-top_log) } else { set log "top.log" }
if {[info exists ::top_pid]} {
return "ERROR!! top job with pid $::top_pid already in progress, machine_stats -stop it first"
}
sh rm -rf $log
set user [exec whoami]
set ::top_pid [exec top -b -u $user -d $delay > $log &]
echo "top job started recording top.log every $delay seconds with pid $::top_pid, issue machine_stats -stop to kill it"
unsuppress_message CMD-041
} else {
return "ERROR!! -start or -stop are required, Exiting"
}
}
define_proc_attributes machine_stats \
-info "USER PROC: Use machine_stats -start and machine_stats -stop in scripts to start and stop batch top jobs and record results into top.log file" \
-define_args {
{-start "Optional - starts and runs a batch top job until machine_stats -stop is issued to kill it" "" boolean optional}
{-stop "Optional - stops an earlier batch top job started with machine_stats -start" "" boolean optional}
{-delay "Optional - refreshes top every given seconds, default is 60sec" "
{-top_log "Optional - output top log file, default top.log" "
}
echo "\tmachine_stats"
#------------------------------------------------------------------------------------------------#
#-- END
#------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#-- all_commands
#------------------------------------------------------------------------------------------------#
#-- USAGE :
#-- pt_shell> all_commands * -verbose
proc all_commands {args} {
parse_proc_arguments -args $args results
echo "#-- ALL COMMANDS --#"
help *$results(pattern)*
if {[info exists results(-verbose)]} {
echo "********* -help *************"
apropos *$results(pattern)*
}
}; # end proc
define_proc_attributes all_commands -info "lists all commands and their set explanation" \
-define_args {
{pattern "Pattern to search for" pattern string required}
{-verbose "Search -help as well" "" boolean optional}}
#------------------------------------------------------------------------------------------------#
#-- END
#------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#-- all_variables
#------------------------------------------------------------------------------------------------#
#-- USAGE :
#-- pt_shell> all_variables * -verbose
proc all_variables {args} {
parse_proc_arguments -args $args results
echo "#-- ALL VARIABLES --#"
uplevel "printvar *$results(pattern)*"
#-- if {[info exists results(-verbose)]} {
#-- echo "********* -help *************"
#-- apropos *$results(pattern)*
#-- }
}; # end proc
define_proc_attributes all_variables -info "lists all variables and their current values" \
-define_args {
{pattern "Pattern to search for" pattern string required}
{-verbose "Search -help as well" "" boolean optional}}
#------------------------------------------------------------------------------------------------#
#-- END
#------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#-- get_blocking_arcs
#------------------------------------------------------------------------------------------------#
#-- USAGE :
#-- pt_shell> get_blocking_arcs -from_pin
proc intersect {a b} {return [remove_from_collection $a [remove_from_collection $a $b]]}
proc get_blocking_arcs {args} {
set results(-include_net_arcs) 0
parse_proc_arguments -args $args results
if {[set p1 [get_pins $results(-from_pin)]] eq {}} {return 0}
if {[set p2 [get_pins $results(-to_pin)]] eq {}} {return 0}
# get intersection pins
set fanout [all_fanout -flat -from $p1 -trace_arcs all]
set fanin [all_fanin -flat -to $p2 -trace_arcs all]
if {[set intersection [intersect $fanin $fanout]] eq {}} {
echo "Error: no topological path between the pins."
return 0
}
# populate intersection pins into an array for efficient testing
foreach_in_collection pin $intersection {
set intersection_pin([get_object_name $pin]) 1
}
# determine the timing arc pin pairs between the pins
foreach_in_collection arc [expr {$results(-include_net_arcs) ? [get_timing_arcs -from $intersection] : [get_timing_arcs -from $intersection -filter {defined(sense) && sense != ""}]}] {
set from_pin_name [get_object_name [get_attribute $arc from_pin]]
set to_pin_name [get_object_name [get_attribute $arc to_pin]]
if {[info exists intersection_pin($to_pin_name)]} {
set pin_pairs([list $from_pin_name $to_pin_name]) 1
}
}
# now check each pin pair to see if traversal is blocked here
foreach pair [array names pin_pairs] {
foreach {from_pin_name to_pin_name} $pair {}
if {[intersect $p1 [all_fanin -flat -to $from_pin_name]] eq {} && [intersect $p2 [all_fanout -flat -from $to_pin_name]] eq {}} {
lappend unreachable $pair
}
if {[intersect $p2 [all_fanout -flat -from $to_pin_name]] ne {} && [intersect $p2 [all_fanout -flat -from $from_pin_name]] eq {}} {
lappend fanout_blocked $pair
}
if {[intersect $p1 [all_fanin -flat -to $from_pin_name]] ne {} && [intersect $p1 [all_fanin -flat -to $to_pin_name]] eq {}} {
lappend fanin_blocked $pair
}
}
# print results
if {[info exists fanin_blocked]} {
echo "\n"
echo "FANIN FROM '[get_object_name $p1]' BLOCKED AT TIMING ARCS :"
foreach pair $fanin_blocked {
echo " [lindex $pair 0] -> [lindex $pair 1]"
}
echo "\n"
}
if {[info exists unreachable]} {
echo "UNREACHABLE TIMING ARCS :"
foreach pair $unreachable {
echo " [lindex $pair 0] -> [lindex $pair 1]"
}
echo "\n"
}
if {[info exists fanout_blocked]} {
echo "FANOUT TO '[get_object_name $p2]' BLOCKED AT TIMING ARCS :"
foreach pair $fanout_blocked {
echo " [lindex $pair 0] -> [lindex $pair 1]"
}
}
echo "\n"
}
No comments:
Post a Comment