2018-09-28 17:54:21 +02:00
|
|
|
# OpenSTA, Static Timing Analyzer
|
2022-01-04 18:17:08 +01:00
|
|
|
# Copyright (c) 2022, Parallax Software, Inc.
|
2018-09-28 17:54:21 +02:00
|
|
|
#
|
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
# (at your option) any later version.
|
|
|
|
|
#
|
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2022-01-04 18:17:08 +01:00
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2018-09-28 17:54:21 +02:00
|
|
|
# GNU General Public License for more details.
|
|
|
|
|
#
|
|
|
|
|
# You should have received a copy of the GNU General Public License
|
2022-01-04 18:17:08 +01:00
|
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
#
|
|
|
|
|
# SDC commands.
|
|
|
|
|
# Alphabetical within groups as in the SDC spec.
|
|
|
|
|
#
|
|
|
|
|
# Argument parsing and checking is done in TCL before calling a
|
|
|
|
|
# SWIG interface function.
|
|
|
|
|
#
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
namespace eval sta {
|
|
|
|
|
|
|
|
|
|
define_cmd_args "read_sdc" {[-echo] filename}
|
|
|
|
|
|
|
|
|
|
proc_redirect read_sdc {
|
|
|
|
|
parse_key_args "read_sdc" args keys {} flags {-echo}
|
|
|
|
|
|
|
|
|
|
check_argc_eq1 "read_sdc" $args
|
|
|
|
|
set echo [info exists flags(-echo)]
|
2020-12-23 17:02:56 +01:00
|
|
|
set filename [file nativename [lindex $args 0]]
|
2018-09-28 17:54:21 +02:00
|
|
|
source_ $filename $echo 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
2020-02-14 20:29:22 +01:00
|
|
|
set ::sta_continue_on_error 0
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
define_cmd_args "source" \
|
|
|
|
|
{[-echo] [-verbose] filename [> filename] [>> filename]}
|
|
|
|
|
|
|
|
|
|
# Override source to support -echo and return codes.
|
|
|
|
|
proc_redirect source {
|
|
|
|
|
parse_key_args "source" args keys {-encoding} flags {-echo -verbose}
|
|
|
|
|
if { [llength $args] != 1 } {
|
|
|
|
|
cmd_usage_error "source"
|
|
|
|
|
}
|
|
|
|
|
set echo [info exists flags(-echo)]
|
|
|
|
|
set verbose [info exists flags(-verbose)]
|
2020-12-23 17:02:56 +01:00
|
|
|
set filename [file nativename [lindex $args 0]]
|
2018-09-28 17:54:21 +02:00
|
|
|
source_ $filename $echo $verbose
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc source_ { filename echo verbose } {
|
|
|
|
|
global sta_continue_on_error
|
|
|
|
|
variable sdc_file
|
|
|
|
|
variable sdc_line
|
|
|
|
|
if [catch {open $filename r} stream] {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 511 "cannot open '$filename'."
|
2018-09-28 17:54:21 +02:00
|
|
|
} else {
|
2021-11-15 01:53:25 +01:00
|
|
|
if { [file extension $filename] == ".gz" } {
|
|
|
|
|
zlib push gunzip $stream
|
|
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
# Save file and line in recursive call to source.
|
|
|
|
|
if { [info exists sdc_file] } {
|
|
|
|
|
set sdc_file_save $sdc_file
|
|
|
|
|
set sdc_line_save $sdc_line
|
|
|
|
|
}
|
|
|
|
|
set sdc_file $filename
|
|
|
|
|
set sdc_line 1
|
|
|
|
|
set cmd ""
|
2020-11-13 20:46:19 +01:00
|
|
|
set error {}
|
2018-09-28 17:54:21 +02:00
|
|
|
while {![eof $stream]} {
|
|
|
|
|
gets $stream line
|
|
|
|
|
if { $line != "" } {
|
|
|
|
|
if {$echo} {
|
2020-12-26 01:55:46 +01:00
|
|
|
report_line $line
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
append cmd $line "\n"
|
|
|
|
|
if { [string index $line end] != "\\" \
|
|
|
|
|
&& [info complete $cmd] } {
|
|
|
|
|
set error {}
|
2020-03-09 00:58:10 +01:00
|
|
|
set error_code [catch {uplevel \#0 $cmd} result]
|
2020-11-13 20:46:19 +01:00
|
|
|
# cmd consumed
|
|
|
|
|
set cmd ""
|
2020-03-09 00:58:10 +01:00
|
|
|
# Flush results printed outside tcl to stdout/stderr.
|
|
|
|
|
fflush
|
|
|
|
|
switch $error_code {
|
2020-12-26 01:55:46 +01:00
|
|
|
0 { if { $verbose && $result != "" } { report_line $result } }
|
2018-09-28 17:54:21 +02:00
|
|
|
1 { set error $result }
|
|
|
|
|
2 { set error {invoked "return" outside of a proc.} }
|
|
|
|
|
3 { set error {invoked "break" outside of a loop.} }
|
|
|
|
|
4 { set error {invoked "continue" outside of a loop.} }
|
|
|
|
|
}
|
|
|
|
|
if { $error != {} } {
|
2020-11-13 20:46:19 +01:00
|
|
|
if { $sta_continue_on_error } {
|
|
|
|
|
# Only prepend error message with file/line once.
|
|
|
|
|
if { [string first "Error" $error] == 0 } {
|
2020-12-26 01:55:46 +01:00
|
|
|
report_line $error
|
2020-11-13 20:46:19 +01:00
|
|
|
} else {
|
2020-12-26 01:55:46 +01:00
|
|
|
report_line "Error: [file tail $sdc_file], $sdc_line $error"
|
2020-11-13 20:46:19 +01:00
|
|
|
}
|
|
|
|
|
set error {}
|
|
|
|
|
} else {
|
2018-09-28 17:54:21 +02:00
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
incr sdc_line
|
|
|
|
|
}
|
|
|
|
|
close $stream
|
|
|
|
|
if { $cmd != {} } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 512 "incomplete command at end of file."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2020-11-13 20:46:19 +01:00
|
|
|
set error_sdc_file $sdc_file
|
|
|
|
|
set error_sdc_line $sdc_line
|
2018-09-28 17:54:21 +02:00
|
|
|
if { [info exists sdc_file_save] } {
|
|
|
|
|
set sdc_file $sdc_file_save
|
|
|
|
|
set sdc_line $sdc_line_save
|
|
|
|
|
} else {
|
|
|
|
|
unset sdc_file
|
|
|
|
|
unset sdc_line
|
|
|
|
|
}
|
2020-11-13 20:46:19 +01:00
|
|
|
if { $error != {} } {
|
|
|
|
|
# Only prepend error message with file/line once.
|
|
|
|
|
if { [string first "Error" $error] == 0 } {
|
|
|
|
|
error $error
|
|
|
|
|
} else {
|
|
|
|
|
error "Error: [file tail $error_sdc_file], $error_sdc_line $error"
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "write_sdc" \
|
2021-11-15 15:31:29 +01:00
|
|
|
{[-map_hpins] [-digits digits] [-gzip] [-no_timestamp] filename}
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
proc write_sdc { args } {
|
|
|
|
|
parse_key_args "write_sdc" args keys {-digits -significant_digits} \
|
2021-11-15 15:31:29 +01:00
|
|
|
flags {-map_hpins -compatible -gzip -no_timestamp}
|
2018-09-28 17:54:21 +02:00
|
|
|
check_argc_eq1 "write_sdc" $args
|
|
|
|
|
|
|
|
|
|
set digits 4
|
|
|
|
|
if { [info exists keys(-digits)] } {
|
|
|
|
|
set digits $keys(-digits)
|
|
|
|
|
}
|
|
|
|
|
check_positive_integer "-digits" $digits
|
|
|
|
|
|
|
|
|
|
set filename [file nativename [lindex $args 0]]
|
2021-11-15 15:31:29 +01:00
|
|
|
set gzip [info exists flags(-gzip)]
|
2018-09-28 17:54:21 +02:00
|
|
|
set no_timestamp [info exists flags(-no_timestamp)]
|
2019-10-25 17:51:59 +02:00
|
|
|
set map_hpins [info exists flags(-map_hpins)]
|
|
|
|
|
set native [expr ![info exists flags(-compatible)]]
|
2021-11-15 15:31:29 +01:00
|
|
|
write_sdc_cmd $filename $map_hpins $native $digits $gzip $no_timestamp
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
#
|
|
|
|
|
# General Purpose Commands
|
|
|
|
|
#
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "current_instance" {[instance]}
|
|
|
|
|
|
|
|
|
|
proc current_instance { {inst ""} } {
|
|
|
|
|
if { $inst == "" } {
|
|
|
|
|
set current_instance [top_instance]
|
|
|
|
|
} else {
|
|
|
|
|
set current_instance [get_instance_error "instance" $inst]
|
|
|
|
|
}
|
2019-01-17 00:37:31 +01:00
|
|
|
set cell [get_name [$current_instance cell]]
|
2020-12-26 01:55:46 +01:00
|
|
|
report_line "Current instance is $cell."
|
2018-09-28 17:54:21 +02:00
|
|
|
# Current instance state variable must be part of the sta state so
|
|
|
|
|
# the tcl interpreter can be shared by multiple sdc files.
|
|
|
|
|
set_current_instance $current_instance
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_hierarchy_separator" { seperator }
|
|
|
|
|
|
|
|
|
|
set ::hierarchy_separator "/"
|
|
|
|
|
|
|
|
|
|
proc set_hierarchy_separator { separator } {
|
|
|
|
|
global hierarchy_separator
|
|
|
|
|
check_path_divider $separator
|
|
|
|
|
set_path_divider $separator
|
|
|
|
|
set hierarchy_separator $separator
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc check_path_divider { divider } {
|
|
|
|
|
set sdc_dividers "/@^#.|"
|
|
|
|
|
if { !([string length $divider] == 1
|
|
|
|
|
&& [string first $divider $sdc_dividers] != -1)} {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 513 "hierarchy separator must be one of '$sdc_dividers'."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_units" \
|
2020-04-09 23:21:10 +02:00
|
|
|
{[-time time_unit] [-capacitance cap_unit] [-resistance res_unit]\
|
2019-07-08 20:50:41 +02:00
|
|
|
[-voltage voltage_unit] [-current current_unit] [-power power_unit]\
|
|
|
|
|
[-distance distance_unit]}
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2019-07-08 20:50:41 +02:00
|
|
|
# Note that the set_units command does NOT actually set the units.
|
|
|
|
|
# It merely checks that the current units are the same as the
|
2020-05-15 03:05:17 +02:00
|
|
|
# units in the set_units command.
|
2018-09-28 17:54:21 +02:00
|
|
|
proc set_units { args } {
|
2019-07-07 18:58:47 +02:00
|
|
|
parse_key_args "set_units" args \
|
2019-07-08 20:50:41 +02:00
|
|
|
keys {-capacitance -resistance -time -voltage -current -power -distance} \
|
|
|
|
|
flags {}
|
|
|
|
|
check_argc_eq0 "set_units" $args
|
2019-04-19 03:01:10 +02:00
|
|
|
check_unit "time" -time "s" keys
|
2020-04-09 23:21:10 +02:00
|
|
|
check_unit "capacitance" -capacitance "f" keys
|
|
|
|
|
check_unit "resistance" -resistance "ohm" keys
|
2019-04-19 03:01:10 +02:00
|
|
|
check_unit "voltage" -voltage "v" keys
|
|
|
|
|
check_unit "current" -current "A" keys
|
2020-04-09 23:21:10 +02:00
|
|
|
check_unit "power" -power "W" keys
|
2019-07-08 20:50:41 +02:00
|
|
|
check_unit "distance" -distance "m" keys
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2019-04-19 03:01:10 +02:00
|
|
|
proc check_unit { unit key unit_name key_var } {
|
2018-09-28 17:54:21 +02:00
|
|
|
upvar 1 $key_var keys
|
|
|
|
|
if { [info exists keys($key)] } {
|
|
|
|
|
set value $keys($key)
|
|
|
|
|
if { [string equal -nocase $value $unit_name] } {
|
2019-04-19 03:01:10 +02:00
|
|
|
check_unit_scale $unit 1.0
|
2018-09-28 17:54:21 +02:00
|
|
|
} else {
|
|
|
|
|
set prefix [string index $value 0]
|
|
|
|
|
set suffix [string range $value 1 end]
|
2020-01-27 17:37:36 +01:00
|
|
|
# unit includes "1" prefix
|
|
|
|
|
if { [string is digit $prefix] } {
|
|
|
|
|
set prefix [string index $value 1]
|
|
|
|
|
set suffix [string range $value 2 end]
|
|
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
if { [string equal -nocase $suffix $unit_name] } {
|
2019-07-08 20:50:41 +02:00
|
|
|
set scale [unit_prefix_scale $unit $prefix]
|
2019-07-14 01:56:46 +02:00
|
|
|
check_unit_scale $unit $scale
|
2018-09-28 17:54:21 +02:00
|
|
|
} else {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 514 "unknown unit $unit '$suffix'."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-19 03:01:10 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-08 20:50:41 +02:00
|
|
|
proc unit_prefix_scale { unit prefix } {
|
|
|
|
|
if { [string equal $prefix "M"] } {
|
|
|
|
|
return 1E+6
|
|
|
|
|
} elseif { [string equal $prefix "k"] } {
|
|
|
|
|
return 1E+3
|
|
|
|
|
} elseif { [string equal $prefix "m"] } {
|
|
|
|
|
return 1E-3
|
|
|
|
|
} elseif { [string equal $prefix "u"] } {
|
|
|
|
|
return 1E-6
|
|
|
|
|
} elseif { [string equal $prefix "n"] } {
|
|
|
|
|
return 1E-9
|
|
|
|
|
} elseif { [string equal $prefix "p"] } {
|
|
|
|
|
return 1E-12
|
|
|
|
|
} elseif { [string equal $prefix "f"] } {
|
|
|
|
|
return 1E-15
|
|
|
|
|
} else {
|
2020-12-20 19:21:50 +01:00
|
|
|
sta_error 604 "unknown $unit prefix '$prefix'."
|
2019-07-08 20:50:41 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-19 03:01:10 +02:00
|
|
|
proc check_unit_scale { unit scale } {
|
|
|
|
|
set unit_scale [unit_scale $unit]
|
|
|
|
|
if { ![fuzzy_equal $scale $unit_scale] } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 319 "$unit scale [format %.0e $scale] does not match library scale [format %.0e $unit_scale]."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-08 20:50:41 +02:00
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_cmd_units" \
|
|
|
|
|
{[-capacitance cap_unit] [-resistance res_unit] [-time time_unit]\
|
|
|
|
|
[-voltage voltage_unit] [-current current_unit] [-power power_unit]\
|
|
|
|
|
[-distance distance_unit]}
|
|
|
|
|
|
|
|
|
|
proc set_cmd_units { args } {
|
|
|
|
|
parse_key_args "set_cmd_units" args \
|
|
|
|
|
keys {-capacitance -resistance -time -voltage -current -power \
|
|
|
|
|
-distance -digits -suffix} \
|
|
|
|
|
flags {}
|
|
|
|
|
|
|
|
|
|
check_argc_eq0 "set_cmd_units" $args
|
|
|
|
|
set_unit_values "capacitance" -capacitance "f" keys
|
|
|
|
|
set_unit_values "time" -time "s" keys
|
|
|
|
|
set_unit_values "voltage" -voltage "v" keys
|
|
|
|
|
set_unit_values "current" -current "A" keys
|
|
|
|
|
set_unit_values "resistance" -resistance "ohm" keys
|
|
|
|
|
set_unit_values "distance" -distance "m" keys
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc set_unit_values { unit key unit_name key_var } {
|
|
|
|
|
upvar 1 $key_var keys
|
|
|
|
|
if { [info exists keys($key)] } {
|
|
|
|
|
set value $keys($key)
|
|
|
|
|
if { [string equal -nocase $value $unit_name] } {
|
|
|
|
|
set_cmd_unit_scale $unit 1.0
|
|
|
|
|
} else {
|
|
|
|
|
set prefix [string index $value 0]
|
|
|
|
|
set suffix [string range $value 1 end]
|
2020-06-11 17:45:14 +02:00
|
|
|
# unit includes "1" prefix
|
|
|
|
|
if { [string is digit $prefix] } {
|
|
|
|
|
set prefix [string index $value 1]
|
|
|
|
|
set suffix [string range $value 2 end]
|
|
|
|
|
}
|
2019-07-08 20:50:41 +02:00
|
|
|
if { [string equal -nocase $suffix $unit_name] } {
|
|
|
|
|
set scale [unit_prefix_scale $unit $prefix]
|
|
|
|
|
set_cmd_unit_scale $unit $scale
|
|
|
|
|
} else {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 515 "unknown $unit unit '$suffix'."
|
2019-07-08 20:50:41 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if [info exists keys(-digits)] {
|
|
|
|
|
set_cmd_unit_digits $unit $keys(-digits)
|
|
|
|
|
}
|
|
|
|
|
if [info exists keys(-suffix)] {
|
|
|
|
|
set_cmd_unit_suffix $unit $keys(-suffix)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
################################################################
|
|
|
|
|
#
|
|
|
|
|
# Object Access Commands
|
|
|
|
|
#
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "all_clocks" {}
|
|
|
|
|
|
|
|
|
|
proc all_clocks { } {
|
|
|
|
|
set clks {}
|
|
|
|
|
set clk_iter [clock_iterator]
|
|
|
|
|
while {[$clk_iter has_next]} {
|
|
|
|
|
set clk [$clk_iter next]
|
|
|
|
|
lappend clks $clk
|
|
|
|
|
}
|
|
|
|
|
$clk_iter finish
|
|
|
|
|
return $clks
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "all_inputs" {}
|
|
|
|
|
|
|
|
|
|
proc all_inputs { } {
|
|
|
|
|
return [all_ports_for_direction "input"]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "all_outputs" {}
|
|
|
|
|
|
|
|
|
|
proc all_outputs { } {
|
|
|
|
|
return [all_ports_for_direction "output"]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc all_ports_for_direction { direction } {
|
|
|
|
|
set top_instance [top_instance]
|
|
|
|
|
set top_cell [$top_instance cell]
|
|
|
|
|
set ports {}
|
|
|
|
|
set iter [$top_cell port_iterator]
|
|
|
|
|
while {[$iter has_next]} {
|
|
|
|
|
set port [$iter next]
|
2019-01-17 00:37:31 +01:00
|
|
|
set port_dir [port_direction $port]
|
2018-09-28 17:54:21 +02:00
|
|
|
if { $port_dir == $direction || $port_dir == "bidirect" } {
|
|
|
|
|
set ports [concat $ports [port_members $port]]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$iter finish
|
|
|
|
|
return $ports
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc port_members { port } {
|
|
|
|
|
if [$port is_bus] {
|
|
|
|
|
# Expand bus ports.
|
|
|
|
|
set ports {}
|
|
|
|
|
set member_iter [$port member_iterator]
|
|
|
|
|
while {[$member_iter has_next]} {
|
|
|
|
|
set bit_port [$member_iter next]
|
|
|
|
|
lappend ports $bit_port
|
|
|
|
|
}
|
|
|
|
|
$member_iter finish
|
|
|
|
|
return $ports
|
|
|
|
|
} else {
|
|
|
|
|
return $port
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args all_registers \
|
|
|
|
|
{[-clock clocks] [-rise_clock clocks] [-fall_clock clocks] [-cells] [-data_pins] [-clock_pins]\
|
|
|
|
|
[-async_pins] [-output_pins] [-level_sensitive] [-edge_triggered]}
|
|
|
|
|
|
|
|
|
|
proc all_registers { args } {
|
|
|
|
|
parse_key_args "all_registers" args keys {-clock -rise_clock -fall_clock} \
|
|
|
|
|
flags {-cells -data_pins -clock_pins -async_pins -output_pins -level_sensitive -edge_triggered}
|
|
|
|
|
check_argc_eq0 "all_registers" $args
|
|
|
|
|
|
|
|
|
|
set clks {}
|
2019-11-11 23:30:19 +01:00
|
|
|
set clk_rf "rise_fall"
|
2018-09-28 17:54:21 +02:00
|
|
|
if [info exists keys(-clock)] {
|
|
|
|
|
set clks [get_clocks_warn "clocks" $keys(-clock)]
|
|
|
|
|
}
|
|
|
|
|
if [info exists keys(-rise_clock)] {
|
|
|
|
|
set clks [get_clocks_warn "clocks" $keys(-rise_clock)]
|
2019-11-11 23:30:19 +01:00
|
|
|
set clk_rf "rise"
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
if [info exists keys(-fall_clock)] {
|
|
|
|
|
set clks [get_clocks_warn "clocks" $keys(-fall_clock)]
|
2019-11-11 23:30:19 +01:00
|
|
|
set clk_rf "fall"
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if {[info exists flags(-edge_triggered)] \
|
|
|
|
|
&& ![info exists flags(-level_sensitive)]} {
|
|
|
|
|
set edge_triggered 1
|
|
|
|
|
set level_sensitive 0
|
|
|
|
|
} elseif {[info exists flags(-level_sensitive)] \
|
|
|
|
|
&& ![info exists flags(-edge_triggered)]} {
|
|
|
|
|
set level_sensitive 1
|
|
|
|
|
set edge_triggered 0
|
|
|
|
|
} else {
|
|
|
|
|
set edge_triggered 1
|
|
|
|
|
set level_sensitive 1
|
|
|
|
|
}
|
|
|
|
|
if [info exists flags(-cells)] {
|
2019-11-11 23:30:19 +01:00
|
|
|
return [find_register_instances $clks $clk_rf \
|
2018-09-28 17:54:21 +02:00
|
|
|
$edge_triggered $level_sensitive]
|
|
|
|
|
} elseif [info exists flags(-data_pins)] {
|
2019-11-11 23:30:19 +01:00
|
|
|
return [find_register_data_pins $clks $clk_rf \
|
2018-09-28 17:54:21 +02:00
|
|
|
$edge_triggered $level_sensitive]
|
|
|
|
|
} elseif [info exists flags(-clock_pins)] {
|
2019-11-11 23:30:19 +01:00
|
|
|
return [find_register_clk_pins $clks $clk_rf \
|
2018-09-28 17:54:21 +02:00
|
|
|
$edge_triggered $level_sensitive]
|
|
|
|
|
} elseif [info exists flags(-async_pins)] {
|
2019-11-11 23:30:19 +01:00
|
|
|
return [find_register_async_pins $clks $clk_rf \
|
2018-09-28 17:54:21 +02:00
|
|
|
$edge_triggered $level_sensitive]
|
|
|
|
|
} elseif [info exists flags(-output_pins)] {
|
2019-11-11 23:30:19 +01:00
|
|
|
return [find_register_output_pins $clks $clk_rf \
|
2018-09-28 17:54:21 +02:00
|
|
|
$edge_triggered $level_sensitive]
|
|
|
|
|
} else {
|
|
|
|
|
# -cells is the default.
|
2019-11-11 23:30:19 +01:00
|
|
|
return [find_register_instances $clks $clk_rf \
|
2018-09-28 17:54:21 +02:00
|
|
|
$edge_triggered $level_sensitive]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "current_design" {[design]}
|
|
|
|
|
|
|
|
|
|
variable current_design_name ""
|
|
|
|
|
|
|
|
|
|
proc current_design { {design ""} } {
|
|
|
|
|
variable current_design_name
|
|
|
|
|
|
|
|
|
|
if { $design == "" } {
|
|
|
|
|
# top_instance errors if the network has not been linked.
|
2019-01-17 00:37:31 +01:00
|
|
|
set current_design_name [get_name [get_object_property [top_instance] cell]]
|
2018-09-28 17:54:21 +02:00
|
|
|
} elseif { ![network_is_linked] } {
|
|
|
|
|
set current_design_name $design
|
|
|
|
|
return $design
|
2019-01-17 00:37:31 +01:00
|
|
|
} elseif { [network_is_linked] && $design == [get_name [get_object_property [top_instance] cell]] } {
|
2018-09-28 17:54:21 +02:00
|
|
|
set current_design_name $design
|
|
|
|
|
return $design
|
|
|
|
|
} else {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 320 "current_design for other than top cell not supported."
|
2018-09-28 17:54:21 +02:00
|
|
|
set current_design_name $design
|
|
|
|
|
return $design
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "get_cells" \
|
|
|
|
|
{[-hierarchical] [-hsc separator] [-filter expr]\
|
|
|
|
|
[-regexp] [-nocase] [-quiet] [-of_objects objects] [patterns]}
|
|
|
|
|
|
|
|
|
|
define_cmd_alias "get_cell" "get_cells"
|
|
|
|
|
|
|
|
|
|
# Really get_instances, but SDC calls instances "cells".
|
|
|
|
|
proc get_cells { args } {
|
|
|
|
|
global hierarchy_separator
|
|
|
|
|
|
|
|
|
|
parse_key_args "get_cells" args keys {-hsc -filter -of_objects} \
|
|
|
|
|
flags {-hierarchical -regexp -nocase -quiet}
|
|
|
|
|
check_argc_eq0or1 "get_cells" $args
|
|
|
|
|
check_nocase_flag flags
|
|
|
|
|
|
|
|
|
|
set regexp [info exists flags(-regexp)]
|
|
|
|
|
set nocase [info exists flags(-nocase)]
|
|
|
|
|
set hierarchical [info exists flags(-hierarchical)]
|
|
|
|
|
set quiet [info exists flags(-quiet)]
|
|
|
|
|
# Copy backslashes that will be removed by foreach.
|
|
|
|
|
set patterns [string map {\\ \\\\} [lindex $args 0]]
|
|
|
|
|
set divider $hierarchy_separator
|
|
|
|
|
if [info exists keys(-hsc)] {
|
|
|
|
|
set divider $keys(-hsc)
|
|
|
|
|
check_path_divider $divider
|
|
|
|
|
}
|
|
|
|
|
set insts {}
|
|
|
|
|
if [info exists keys(-of_objects)] {
|
|
|
|
|
if { $args != {} } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 321 "patterns argument not supported with -of_objects."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2020-07-04 03:19:39 +02:00
|
|
|
parse_port_pin_net_arg $keys(-of_objects) pins nets
|
2018-09-28 17:54:21 +02:00
|
|
|
foreach pin $pins {
|
2020-07-04 03:19:39 +02:00
|
|
|
if { [$pin is_top_level_port] } {
|
|
|
|
|
set net [get_nets [get_name $pin]]
|
|
|
|
|
if { $net != "NULL" } {
|
|
|
|
|
lappend nets $net
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
lappend insts [$pin instance]
|
|
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
foreach net $nets {
|
|
|
|
|
set pin_iter [$net pin_iterator]
|
|
|
|
|
while { [$pin_iter has_next] } {
|
|
|
|
|
set pin [$pin_iter next]
|
|
|
|
|
lappend insts [$pin instance]
|
|
|
|
|
}
|
|
|
|
|
$pin_iter finish
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if { $args == {} } {
|
|
|
|
|
set insts [network_leaf_instances]
|
|
|
|
|
} else {
|
|
|
|
|
foreach pattern $patterns {
|
|
|
|
|
if { $divider != $hierarchy_separator } {
|
|
|
|
|
regsub $divider $pattern $hierarchy_separator pattern
|
|
|
|
|
}
|
|
|
|
|
if { $hierarchical } {
|
|
|
|
|
set matches [find_instances_hier_matching $pattern $regexp $nocase]
|
|
|
|
|
} else {
|
|
|
|
|
set matches [find_instances_matching $pattern $regexp $nocase]
|
|
|
|
|
}
|
|
|
|
|
if { $matches == {} && !$quiet} {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 322 "instance '$pattern' not found."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
set insts [concat $insts $matches]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if [info exists keys(-filter)] {
|
|
|
|
|
set insts [filter_insts1 $keys(-filter) $insts]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $insts
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc filter_insts1 { filter objects } {
|
|
|
|
|
variable filter_regexp1
|
|
|
|
|
variable filter_or_regexp
|
|
|
|
|
variable filter_and_regexp
|
|
|
|
|
set filtered_objects {}
|
|
|
|
|
# Ignore sub-exprs in filter_regexp1 for expr2 match var.
|
|
|
|
|
if { [regexp $filter_or_regexp $filter ignore expr1 \
|
|
|
|
|
ignore ignore ignore expr2] } {
|
|
|
|
|
regexp $filter_regexp1 $expr1 ignore attr_name op arg
|
|
|
|
|
set filtered_objects1 [filter_insts $attr_name $op $arg $objects]
|
|
|
|
|
regexp $filter_regexp1 $expr2 ignore attr_name op arg
|
|
|
|
|
set filtered_objects2 [filter_insts $attr_name $op $arg $objects]
|
|
|
|
|
set filtered_objects [concat $filtered_objects1 $filtered_objects2]
|
|
|
|
|
} elseif { [regexp $filter_and_regexp $filter ignore expr1 \
|
|
|
|
|
ignore ignore ignore expr2] } {
|
|
|
|
|
regexp $filter_regexp1 $expr1 ignore attr_name op arg
|
|
|
|
|
set filtered_objects [filter_insts $attr_name $op $arg $objects]
|
|
|
|
|
regexp $filter_regexp1 $expr2 ignore attr_name op arg
|
|
|
|
|
set filtered_objects [filter_insts $attr_name $op $arg $filtered_objects]
|
|
|
|
|
} elseif { [regexp $filter_regexp1 $filter ignore attr_name op arg] } {
|
|
|
|
|
set filtered_objects [filter_insts $attr_name $op $arg $objects]
|
|
|
|
|
} else {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 516 "unsupported -filter expression."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
return $filtered_objects
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "get_clocks" {[-regexp] [-nocase] [-quiet] patterns}
|
|
|
|
|
|
|
|
|
|
define_cmd_alias "get_clock" "get_clocks"
|
|
|
|
|
|
|
|
|
|
proc get_clocks { args } {
|
|
|
|
|
parse_key_args "get_clocks" args keys {} flags {-regexp -nocase -quiet}
|
|
|
|
|
check_argc_eq1 "get_clocks" $args
|
|
|
|
|
check_nocase_flag flags
|
|
|
|
|
|
|
|
|
|
# Copy backslashes that will be removed by foreach.
|
|
|
|
|
set patterns [string map {\\ \\\\} [lindex $args 0]]
|
|
|
|
|
set regexp [info exists flags(-regexp)]
|
|
|
|
|
set nocase [info exists flags(-nocase)]
|
|
|
|
|
set clocks {}
|
|
|
|
|
foreach pattern $patterns {
|
|
|
|
|
set matches [find_clocks_matching $pattern $regexp $nocase]
|
|
|
|
|
if { $matches != {} } {
|
|
|
|
|
set clocks [concat $clocks $matches]
|
|
|
|
|
} else {
|
|
|
|
|
if {![info exists flags(-quiet)]} {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 323 "clock '$pattern' not found."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $clocks
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "get_lib_cells" \
|
|
|
|
|
{[-hsc separator] [-regexp] [-nocase] [-quiet]\
|
|
|
|
|
[-of_objects objects] [patterns]}
|
|
|
|
|
|
|
|
|
|
define_cmd_alias "get_lib_cell" "get_lib_cells"
|
|
|
|
|
|
|
|
|
|
proc get_lib_cells { args } {
|
|
|
|
|
global hierarchy_separator
|
|
|
|
|
parse_key_args "get_lib_cells" args keys {-hsc -of_objects} \
|
|
|
|
|
flags {-regexp -nocase -quiet}
|
|
|
|
|
check_argc_eq0or1 "get_lib_cells" $args
|
|
|
|
|
check_nocase_flag flags
|
|
|
|
|
|
|
|
|
|
set regexp [info exists flags(-regexp)]
|
|
|
|
|
set nocase [info exists flags(-nocase)]
|
|
|
|
|
set cells {}
|
|
|
|
|
if [info exists keys(-of_objects)] {
|
|
|
|
|
if { $args != {} } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 324 "positional arguments not supported with -of_objects."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
set insts [get_instances_error "objects" $keys(-of_objects)]
|
|
|
|
|
foreach inst $insts {
|
|
|
|
|
lappend cells [$inst liberty_cell]
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
# Copy backslashes that will be removed by foreach.
|
|
|
|
|
set patterns [string map {\\ \\\\} [lindex $args 0]]
|
|
|
|
|
# Parse library_name/pattern.
|
|
|
|
|
set divider $hierarchy_separator
|
|
|
|
|
if [info exists keys(-hsc)] {
|
|
|
|
|
set divider $keys(-hsc)
|
|
|
|
|
check_path_divider $divider
|
|
|
|
|
}
|
2021-04-10 07:32:51 +02:00
|
|
|
set cell_regexp [cell_regexp_hsc $divider]
|
2019-06-24 06:38:01 +02:00
|
|
|
set quiet [info exists flags(-quiet)]
|
2018-09-28 17:54:21 +02:00
|
|
|
foreach pattern $patterns {
|
2020-04-26 17:49:09 +02:00
|
|
|
if { ![regexp $cell_regexp $pattern ignore lib_name cell_pattern]} {
|
|
|
|
|
set lib_name "*"
|
|
|
|
|
set cell_pattern $pattern
|
|
|
|
|
}
|
|
|
|
|
# Allow wildcards in the library name (incompatible).
|
|
|
|
|
set libs [get_libs -quiet $lib_name]
|
|
|
|
|
if { $libs == {} } {
|
|
|
|
|
if {!$quiet} {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 325 "library '$lib_name' not found."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
2020-04-26 17:49:09 +02:00
|
|
|
foreach lib $libs {
|
|
|
|
|
set matches [$lib find_liberty_cells_matching $cell_pattern \
|
|
|
|
|
$regexp $nocase]
|
|
|
|
|
if {$matches != {}} {
|
|
|
|
|
set cells [concat $cells $matches]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if { $cells == {} } {
|
|
|
|
|
if {!$quiet} {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 326 "cell '$cell_pattern' not found."
|
2020-04-26 17:49:09 +02:00
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $cells
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "get_lib_pins" \
|
|
|
|
|
{[-hsc separator] [-regexp] [-nocase] [-quiet] patterns}
|
|
|
|
|
|
|
|
|
|
define_cmd_alias "get_lib_pin" "get_lib_pins"
|
|
|
|
|
|
|
|
|
|
# "get_lib_ports" in sta terminology.
|
|
|
|
|
proc get_lib_pins { args } {
|
|
|
|
|
global hierarchy_separator
|
|
|
|
|
parse_key_args "get_lib_pins" args keys {-hsc} flags {-regexp -nocase -quiet}
|
|
|
|
|
check_argc_eq1 "get_lib_pins" $args
|
|
|
|
|
check_nocase_flag flags
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
set regexp [info exists flags(-regexp)]
|
|
|
|
|
set nocase [info exists flags(-nocase)]
|
2020-02-01 18:19:10 +01:00
|
|
|
set quiet [info exists flags(-quiet)]
|
2018-09-28 17:54:21 +02:00
|
|
|
# Copy backslashes that will be removed by foreach.
|
|
|
|
|
set patterns [string map {\\ \\\\} [lindex $args 0]]
|
|
|
|
|
# Parse library_name/cell_name/pattern.
|
|
|
|
|
set divider $hierarchy_separator
|
|
|
|
|
if [info exists keys(-hsc)] {
|
|
|
|
|
set divider $keys(-hsc)
|
|
|
|
|
check_path_divider $divider
|
|
|
|
|
}
|
2021-04-10 07:32:51 +02:00
|
|
|
set port_regexp1 [port_regexp_hsc $divider]
|
|
|
|
|
set port_regexp2 [cell_regexp_hsc $divider]
|
2018-09-28 17:54:21 +02:00
|
|
|
set ports {}
|
|
|
|
|
foreach pattern $patterns {
|
2020-05-08 03:00:15 +02:00
|
|
|
# match library/cell/port
|
|
|
|
|
set libs {}
|
|
|
|
|
if { [regexp $port_regexp1 $pattern ignore lib_name cell_name port_pattern] } {
|
|
|
|
|
set libs [get_libs -quiet $lib_name]
|
|
|
|
|
# match cell/port
|
|
|
|
|
} elseif { [regexp $port_regexp2 $pattern ignore cell_name port_pattern] } {
|
|
|
|
|
set libs [get_libs *]
|
|
|
|
|
} else {
|
|
|
|
|
if { !$quiet } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 327 "library/cell/port '$pattern' not found."
|
2020-05-08 03:00:15 +02:00
|
|
|
}
|
|
|
|
|
return {}
|
|
|
|
|
}
|
|
|
|
|
if { $libs != {} } {
|
|
|
|
|
set found_match 0
|
|
|
|
|
set cells {}
|
|
|
|
|
foreach lib $libs {
|
|
|
|
|
set cells [$lib find_liberty_cells_matching $cell_name $regexp $nocase]
|
|
|
|
|
foreach cell $cells {
|
|
|
|
|
set matches [$cell find_liberty_ports_matching $port_pattern \
|
|
|
|
|
$regexp $nocase]
|
|
|
|
|
foreach match $matches {
|
|
|
|
|
lappend ports $match
|
|
|
|
|
set found_match 1
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
2020-05-08 03:00:15 +02:00
|
|
|
}
|
|
|
|
|
if { !$found_match } {
|
2020-02-01 18:19:10 +01:00
|
|
|
if { !$quiet } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 328 "port '$port_pattern' not found."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2020-02-01 18:19:10 +01:00
|
|
|
if { !$quiet } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 329 "library '$lib_name' not found."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $ports
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc check_nocase_flag { flags_var } {
|
|
|
|
|
upvar 1 $flags_var flags
|
|
|
|
|
if { [info exists flags(-nocase)] && ![info exists flags(-regexp)] } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 330 "-nocase ignored without -regexp."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "get_libs" {[-regexp] [-nocase] [-quiet] patterns}
|
|
|
|
|
|
|
|
|
|
define_cmd_alias "get_lib" "get_libs"
|
|
|
|
|
|
|
|
|
|
proc get_libs { args } {
|
|
|
|
|
parse_key_args "get_libs" args keys {} flags {-regexp -nocase -quiet}
|
|
|
|
|
check_argc_eq1 "get_libs" $args
|
|
|
|
|
check_nocase_flag flags
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
# Copy backslashes that will be removed by foreach.
|
|
|
|
|
set patterns [string map {\\ \\\\} [lindex $args 0]]
|
|
|
|
|
set regexp [info exists flags(-regexp)]
|
|
|
|
|
set nocase [info exists flags(-nocase)]
|
|
|
|
|
set libs {}
|
|
|
|
|
foreach pattern $patterns {
|
|
|
|
|
set matches [find_liberty_libraries_matching $pattern $regexp $nocase]
|
|
|
|
|
if {$matches != {}} {
|
|
|
|
|
set libs [concat $libs $matches]
|
|
|
|
|
} else {
|
|
|
|
|
if {![info exists flags(-quiet)]} {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 331 "library '$pattern' not found."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $libs
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc find_liberty_libraries_matching { pattern regexp nocase } {
|
|
|
|
|
# Remove "lib.db:" reference from the library name.
|
|
|
|
|
set ix [string last ".db:" $pattern]
|
|
|
|
|
if { $ix != -1 } {
|
|
|
|
|
set pattern2 [string range $pattern [expr $ix + 4] end]
|
|
|
|
|
} else {
|
|
|
|
|
set pattern2 $pattern
|
|
|
|
|
}
|
|
|
|
|
if { $regexp } {
|
|
|
|
|
# Anchor the regexp pattern.
|
|
|
|
|
set pattern2 "^${pattern}$"
|
|
|
|
|
}
|
|
|
|
|
set lib_iter [liberty_library_iterator]
|
|
|
|
|
set matches {}
|
|
|
|
|
while { [$lib_iter has_next] } {
|
|
|
|
|
set lib [$lib_iter next]
|
2019-01-17 00:37:31 +01:00
|
|
|
set lib_name [get_name $lib]
|
2018-09-28 17:54:21 +02:00
|
|
|
if { (!$regexp && [string match $pattern2 $lib_name]) \
|
|
|
|
|
|| ($regexp && $nocase && [regexp -nocase $pattern2 $lib_name]) \
|
|
|
|
|
|| ($regexp && !$nocase && [regexp $pattern2 $lib_name]) } {
|
|
|
|
|
lappend matches $lib
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$lib_iter finish
|
|
|
|
|
return $matches
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "get_nets" \
|
|
|
|
|
{[-hierarchical] [-hsc separator] [-regexp] [-nocase] [-quiet]\
|
|
|
|
|
[-of_objects objects] [patterns]}
|
|
|
|
|
|
|
|
|
|
define_cmd_alias "get_net" "get_nets"
|
|
|
|
|
|
|
|
|
|
proc get_nets { args } {
|
|
|
|
|
global hierarchy_separator
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
parse_key_args get_nets args keys {-hsc -of_objects} \
|
|
|
|
|
flags {-hierarchical -regexp -nocase -quiet}
|
|
|
|
|
check_nocase_flag flags
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
set regexp [info exists flags(-regexp)]
|
|
|
|
|
set nocase [info exists flags(-nocase)]
|
|
|
|
|
set hierarchical [info exists flags(-hierarchical)]
|
|
|
|
|
set quiet [info exists flags(-quiet)]
|
|
|
|
|
# Copy backslashes that will be removed by foreach.
|
|
|
|
|
set patterns [string map {\\ \\\\} [lindex $args 0]]
|
|
|
|
|
if [info exists keys(-hsc)] {
|
|
|
|
|
set divider $keys(-hsc)
|
|
|
|
|
check_path_divider $divider
|
|
|
|
|
set patterns [string map "$divider $hierarchy_separator" $patterns]
|
|
|
|
|
}
|
|
|
|
|
set nets {}
|
|
|
|
|
if [info exists keys(-of_objects)] {
|
|
|
|
|
if { $args != {} } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 332 "patterns argument not supported with -of_objects."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
parse_inst_pin_arg $keys(-of_objects) insts pins
|
|
|
|
|
foreach inst $insts {
|
|
|
|
|
set pin_iter [$inst pin_iterator]
|
|
|
|
|
while { [$pin_iter has_next] } {
|
|
|
|
|
set pin [$pin_iter next]
|
|
|
|
|
lappend nets [$pin net]
|
|
|
|
|
}
|
|
|
|
|
$pin_iter finish
|
|
|
|
|
}
|
|
|
|
|
foreach pin $pins {
|
|
|
|
|
lappend nets [$pin net]
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
check_argc_eq1 "get_nets" $args
|
|
|
|
|
foreach pattern $patterns {
|
|
|
|
|
if { $hierarchical } {
|
|
|
|
|
set matches [find_nets_hier_matching $pattern $regexp $nocase]
|
|
|
|
|
} else {
|
|
|
|
|
set matches [find_nets_matching $pattern $regexp $nocase]
|
|
|
|
|
}
|
|
|
|
|
set nets [concat $nets $matches]
|
|
|
|
|
if { $matches == {} && !$quiet } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 333 "net '$pattern' not found."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $nets
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "get_pins" \
|
|
|
|
|
{[-hierarchical] [-hsc separator] [-quiet] [-filter expr]\
|
|
|
|
|
[-regexp] [-nocase] [-of_objects objects] patterns}
|
|
|
|
|
|
|
|
|
|
define_cmd_alias "get_pin" "get_pins"
|
|
|
|
|
|
|
|
|
|
proc get_pins { args } {
|
|
|
|
|
global hierarchy_separator
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
parse_key_args "get_pins" args keys {-hsc -of_objects -filter} \
|
|
|
|
|
flags {-hierarchical -regexp -nocase -quiet}
|
|
|
|
|
check_nocase_flag flags
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
set regexp [info exists flags(-regexp)]
|
|
|
|
|
set nocase [info exists flags(-nocase)]
|
|
|
|
|
set hierarchical [info exists flags(-hierarchical)]
|
|
|
|
|
set quiet [info exists flags(-quiet)]
|
|
|
|
|
set pins {}
|
|
|
|
|
if [info exists keys(-of_objects)] {
|
|
|
|
|
if { $args != {} } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 334 "patterns argument not supported with -of_objects."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
parse_inst_net_arg $keys(-of_objects) insts nets
|
|
|
|
|
foreach inst $insts {
|
|
|
|
|
set pin_iter [$inst pin_iterator]
|
|
|
|
|
while { [$pin_iter has_next] } {
|
|
|
|
|
set pin [$pin_iter next]
|
|
|
|
|
lappend pins $pin
|
|
|
|
|
}
|
|
|
|
|
$pin_iter finish
|
|
|
|
|
}
|
|
|
|
|
foreach net $nets {
|
|
|
|
|
set pin_iter [$net pin_iterator]
|
|
|
|
|
while { [$pin_iter has_next] } {
|
|
|
|
|
set pin [$pin_iter next]
|
|
|
|
|
lappend pins $pin
|
|
|
|
|
}
|
|
|
|
|
$pin_iter finish
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
check_argc_eq1 "get_pins" $args
|
|
|
|
|
set patterns [lindex $args 0]
|
|
|
|
|
if [info exists keys(-hsc)] {
|
|
|
|
|
set divider $keys(-hsc)
|
|
|
|
|
check_path_divider $divider
|
|
|
|
|
set patterns [string map "$divider $hierarchy_separator" $patterns]
|
|
|
|
|
}
|
|
|
|
|
# Copy backslashes that will be removed by foreach.
|
|
|
|
|
set patterns [string map {\\ \\\\} $patterns]
|
|
|
|
|
foreach pattern $patterns {
|
|
|
|
|
if { $hierarchical } {
|
|
|
|
|
set matches [find_pins_hier_matching $pattern $regexp $nocase]
|
|
|
|
|
} else {
|
|
|
|
|
set matches [find_pins_matching $pattern $regexp $nocase]
|
|
|
|
|
}
|
|
|
|
|
set pins [concat $pins $matches]
|
|
|
|
|
if { $matches == {} && !$quiet } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 335 "pin '$pattern' not found."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if [info exists keys(-filter)] {
|
|
|
|
|
set pins [filter_pins1 $keys(-filter) $pins]
|
|
|
|
|
}
|
|
|
|
|
return $pins
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc filter_pins1 { filter objects } {
|
|
|
|
|
variable filter_regexp1
|
|
|
|
|
variable filter_or_regexp
|
|
|
|
|
variable filter_and_regexp
|
|
|
|
|
set filtered_objects {}
|
|
|
|
|
# Ignore sub-exprs in filter_regexp1 for expr2 match var.
|
|
|
|
|
if { [regexp $filter_or_regexp $filter ignore expr1 \
|
|
|
|
|
ignore ignore ignore expr2] } {
|
|
|
|
|
regexp $filter_regexp1 $expr1 ignore attr_name op arg
|
|
|
|
|
set filtered_objects1 [filter_pins $attr_name $op $arg $objects]
|
|
|
|
|
regexp $filter_regexp1 $expr2 ignore attr_name op arg
|
|
|
|
|
set filtered_objects2 [filter_pins $attr_name $op $arg $objects]
|
|
|
|
|
set filtered_objects [concat $filtered_objects1 $filtered_objects2]
|
|
|
|
|
} elseif { [regexp $filter_and_regexp $filter ignore expr1 \
|
|
|
|
|
ignore ignore ignore expr2] } {
|
|
|
|
|
regexp $filter_regexp1 $expr1 ignore attr_name op arg
|
|
|
|
|
set filtered_objects [filter_pins $attr_name $op $arg $objects]
|
|
|
|
|
regexp $filter_regexp1 $expr2 ignore attr_name op arg
|
|
|
|
|
set filtered_objects [filter_pins $attr_name $op $arg $filtered_objects]
|
|
|
|
|
} elseif { [regexp $filter_regexp1 $filter ignore attr_name op arg] } {
|
|
|
|
|
set filtered_objects [filter_pins $attr_name $op $arg $objects]
|
|
|
|
|
} else {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 517 "unsupported -filter expression."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
return $filtered_objects
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "get_ports" \
|
|
|
|
|
{[-quiet] [-filter expr] [-regexp] [-nocase] [-of_objects objects] [patterns]}
|
|
|
|
|
|
|
|
|
|
define_cmd_alias "get_port" "get_ports"
|
|
|
|
|
|
|
|
|
|
# Find top level design ports matching pattern.
|
|
|
|
|
proc get_ports { args } {
|
|
|
|
|
parse_key_args "get_ports" args keys {-of_objects -filter} \
|
|
|
|
|
flags {-regexp -nocase -quiet}
|
|
|
|
|
check_nocase_flag flags
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
set regexp [info exists flags(-regexp)]
|
|
|
|
|
set nocase [info exists flags(-nocase)]
|
|
|
|
|
# Copy backslashes that will be removed by foreach.
|
|
|
|
|
set patterns [string map {\\ \\\\} [lindex $args 0]]
|
|
|
|
|
set ports {}
|
|
|
|
|
if [info exists keys(-of_objects)] {
|
|
|
|
|
if { $args != {} } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 336 "patterns argument not supported with -of_objects."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
set nets [get_nets_warn "objects" $keys(-of_objects)]
|
|
|
|
|
foreach net $nets {
|
|
|
|
|
set ports [concat $ports [$net ports]]
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
check_argc_eq1 "get_ports" $args
|
|
|
|
|
foreach pattern $patterns {
|
|
|
|
|
set matches [find_ports_matching $pattern $regexp $nocase]
|
|
|
|
|
if { $matches != {} } {
|
|
|
|
|
set ports [concat $ports $matches]
|
|
|
|
|
} else {
|
|
|
|
|
if {![info exists flags(-quiet)]} {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 337 "port '$pattern' not found."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if [info exists keys(-filter)] {
|
|
|
|
|
set ports [filter_ports1 $keys(-filter) $ports]
|
|
|
|
|
}
|
|
|
|
|
return $ports
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-04 17:26:11 +02:00
|
|
|
variable filter_regexp1 {@?([a-zA-Z_]+) *(==|=~) *([0-9a-zA-Z_\*]+)}
|
2018-09-28 17:54:21 +02:00
|
|
|
variable filter_or_regexp "($filter_regexp1) +\\|\\| +($filter_regexp1)"
|
|
|
|
|
variable filter_and_regexp "($filter_regexp1) +&& +($filter_regexp1)"
|
|
|
|
|
|
|
|
|
|
proc filter_ports1 { filter objects } {
|
|
|
|
|
variable filter_regexp1
|
|
|
|
|
variable filter_or_regexp
|
|
|
|
|
variable filter_and_regexp
|
|
|
|
|
set filtered_objects {}
|
|
|
|
|
# Ignore sub-exprs in filter_regexp1 for expr2 match var.
|
|
|
|
|
if { [regexp $filter_or_regexp $filter ignore expr1 \
|
|
|
|
|
ignore ignore ignore expr2] } {
|
|
|
|
|
regexp $filter_regexp1 $expr1 ignore attr_name op arg
|
|
|
|
|
set filtered_objects1 [filter_ports $attr_name $op $arg $objects]
|
|
|
|
|
regexp $filter_regexp1 $expr2 ignore attr_name op arg
|
|
|
|
|
set filtered_objects2 [filter_ports $attr_name $op $arg $objects]
|
|
|
|
|
set filtered_objects [concat $filtered_objects1 $filtered_objects2]
|
|
|
|
|
} elseif { [regexp $filter_and_regexp $filter ignore expr1 \
|
|
|
|
|
ignore ignore ignore expr2] } {
|
|
|
|
|
regexp $filter_regexp1 $expr1 ignore attr_name op arg
|
|
|
|
|
set filtered_objects [filter_ports $attr_name $op $arg $objects]
|
|
|
|
|
regexp $filter_regexp1 $expr2 ignore attr_name op arg
|
|
|
|
|
set filtered_objects [filter_ports $attr_name $op $arg $filtered_objects]
|
|
|
|
|
} elseif { [regexp $filter_regexp1 $filter ignore attr_name op arg] } {
|
|
|
|
|
set filtered_objects [filter_ports $attr_name $op $arg $objects]
|
|
|
|
|
} else {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 518 "unsupported -filter expression."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
return $filtered_objects
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
#
|
|
|
|
|
# Timing Constraints
|
|
|
|
|
#
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "create_clock" \
|
|
|
|
|
{[-name name] [-period period] [-waveform waveform] [-add]\
|
|
|
|
|
[-comment comment] [pins]}
|
|
|
|
|
|
|
|
|
|
proc create_clock { args } {
|
|
|
|
|
parse_key_args "create_clock" args \
|
|
|
|
|
keys {-name -period -waveform -comment} \
|
|
|
|
|
flags {-add}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
check_argc_eq0or1 "create_clock" $args
|
|
|
|
|
set argc [llength $args]
|
|
|
|
|
if { $argc == 0 } {
|
|
|
|
|
set pins {}
|
|
|
|
|
} elseif { $argc == 1 } {
|
|
|
|
|
set pins [get_port_pins_error "pins" [lindex $args 0]]
|
|
|
|
|
}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
set add [info exists flags(-add)]
|
|
|
|
|
if [info exists keys(-name)] {
|
|
|
|
|
set name $keys(-name)
|
|
|
|
|
} elseif { $pins != {} } {
|
|
|
|
|
if { $add } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 519 "-add requires -name."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
# Default clock name is the first pin name.
|
2019-01-17 00:37:31 +01:00
|
|
|
set name [get_full_name [lindex $pins 0]]
|
2018-09-28 17:54:21 +02:00
|
|
|
} else {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 520 "-name or port_pin_list must be specified."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
if [info exists keys(-period)] {
|
|
|
|
|
set period $keys(-period)
|
|
|
|
|
check_positive_float "period" $period
|
|
|
|
|
set period [time_ui_sta $period]
|
|
|
|
|
} else {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 521 "missing -period argument."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
if [info exists keys(-waveform)] {
|
|
|
|
|
set wave_arg $keys(-waveform)
|
|
|
|
|
if { [expr [llength $wave_arg] % 2] != 0 } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 522 "-waveform edge_list must have an even number of edge times."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
set first_edge 1
|
|
|
|
|
set prev_edge 0
|
|
|
|
|
set waveform {}
|
|
|
|
|
foreach edge $wave_arg {
|
|
|
|
|
check_float "-waveform edge" $edge
|
|
|
|
|
set edge [time_ui_sta $edge]
|
|
|
|
|
if { !$first_edge && $edge < $prev_edge } {
|
2021-08-14 23:54:49 +02:00
|
|
|
sta_error 338 "non-increasing clock -waveform edge times."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
if { $edge > [expr $period * 2] } {
|
2021-08-14 23:54:49 +02:00
|
|
|
sta_error 339 "-waveform time greater than two periods."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
lappend waveform $edge
|
|
|
|
|
set prev_edge $edge
|
|
|
|
|
set first_edge 0
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
set waveform [list 0 [expr $period / 2.0]]
|
|
|
|
|
}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
set comment [parse_comment_key keys]
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
make_clock $name $pins $add $period $waveform $comment
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "create_generated_clock" \
|
|
|
|
|
{[-name clock_name] -source master_pin [-master_clock clock]\
|
|
|
|
|
[-divide_by divisor | -multiply_by multiplier]\
|
|
|
|
|
[-duty_cycle duty_cycle] [-invert] [-edges edge_list]\
|
|
|
|
|
[-edge_shift edge_shift_list] [-combinational] [-add]\
|
|
|
|
|
[-pll_output pll_out_pin] [-pll_feedback pll_fdbk_pin]\
|
|
|
|
|
[-comment comment] port_pin_list}
|
|
|
|
|
|
|
|
|
|
proc create_generated_clock { args } {
|
|
|
|
|
parse_key_args "create_generated_clock" args keys \
|
|
|
|
|
{-name -source -master_clock -divide_by -multiply_by \
|
|
|
|
|
-duty_cycle -edges -edge_shift -pll_output -pll_feedback -comment} \
|
|
|
|
|
flags {-invert -combinational -add}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
check_argc_eq1 "create_generated_clock" $args
|
2020-09-21 07:30:22 +02:00
|
|
|
parse_port_pin_net_arg [lindex $args 0] pins nets
|
|
|
|
|
# Convert net args to net driver pin.
|
|
|
|
|
foreach net $nets {
|
|
|
|
|
set drivers [net_driver_pins $net]
|
|
|
|
|
if { $drivers != {} } {
|
|
|
|
|
lappend pins [lindex $drivers 0]
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
if { $pins == {} } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 523 "empty ports/pins/nets argument."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
set add [info exists flags(-add)]
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
if [info exists keys(-name)] {
|
|
|
|
|
set name $keys(-name)
|
|
|
|
|
} elseif { $pins != {} } {
|
|
|
|
|
if { $add } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 524 "-add requires -name."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
# Default clock name is the first pin name.
|
2019-01-17 00:37:31 +01:00
|
|
|
set name [get_full_name [lindex $pins 0]]
|
2018-09-28 17:54:21 +02:00
|
|
|
} else {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 525 "name or port_pin_list must be specified."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
if [info exists keys(-source)] {
|
|
|
|
|
set source $keys(-source)
|
|
|
|
|
set source_pin [get_port_pin_error "master_pin" $source]
|
|
|
|
|
} else {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 526 "missing -source argument."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
set master_clk "NULL"
|
|
|
|
|
set divide_by 0
|
|
|
|
|
set multiply_by 0
|
|
|
|
|
set duty_cycle 0
|
|
|
|
|
set edges {}
|
|
|
|
|
set edge_shifts {}
|
|
|
|
|
set pll_out "NULL"
|
|
|
|
|
set pll_feedback "NULL"
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
set combinational [info exists flags(-combinational)]
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
if {[info exists keys(-master_clock)]} {
|
|
|
|
|
set master_clk [get_clock_error "-master_clk" $keys(-master_clock)]
|
|
|
|
|
if { $master_clk == "NULL" } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 527 "-master_clock argument empty."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
} elseif { $add } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 528 "-add requireds -master_clock."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
if {[info exists keys(-divide_by)] && [info exists keys(-multiply_by)]} {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 529 "-multiply_by and -divide_by options are exclusive."
|
2018-09-28 17:54:21 +02:00
|
|
|
} elseif {[info exists keys(-divide_by)]} {
|
|
|
|
|
set divide_by $keys(-divide_by)
|
|
|
|
|
if {![string is integer $divide_by] || $divide_by < 1} {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 530 "-divide_by is not an integer greater than one."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
if {$combinational && $divide_by != 1} {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 531 "-combinational implies -divide_by 1."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
} elseif {[info exists keys(-multiply_by)]} {
|
|
|
|
|
set multiply_by $keys(-multiply_by)
|
|
|
|
|
if {![string is integer $multiply_by] || $multiply_by < 1} {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 532 "-multiply_by is not an integer greater than one."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
if {[info exists keys(-duty_cycle)]} {
|
|
|
|
|
set duty_cycle $keys(-duty_cycle)
|
|
|
|
|
if {![string is double $duty_cycle] \
|
|
|
|
|
|| $duty_cycle < 0.0 || $duty_cycle > 100.0} {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 533 "-duty_cycle is not a float between 0 and 100."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} elseif {[info exists keys(-edges)]} {
|
|
|
|
|
set edges $keys(-edges)
|
|
|
|
|
if { [llength $edges] != 3 } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 534 "-edges only supported for three edges."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
set prev_edge [expr [lindex $edges 0] - 1]
|
|
|
|
|
foreach edge $edges {
|
|
|
|
|
check_cardinal "-edges" $edge
|
|
|
|
|
if { $edge <= $prev_edge } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 535 "edges times are not monotonically increasing."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if [info exists keys(-edge_shift)] {
|
|
|
|
|
foreach shift $keys(-edge_shift) {
|
|
|
|
|
check_float "-edge_shift" $shift
|
|
|
|
|
lappend edge_shifts [time_ui_sta $shift]
|
|
|
|
|
}
|
|
|
|
|
if { [llength $edge_shifts] != [llength $edges] } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 536 "-edge_shift length does not match -edges length."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} elseif { $combinational } {
|
|
|
|
|
set divide_by 1
|
|
|
|
|
} else {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 537 "missing -multiply_by, -divide_by, -combinational or -edges argument."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
set invert 0
|
|
|
|
|
if {[info exists flags(-invert)]} {
|
|
|
|
|
if {!([info exists keys(-divide_by)] \
|
|
|
|
|
|| [info exists keys(-multiply_by)] \
|
|
|
|
|
|| [info exists flags(-combinational)])} {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 538 "cannot specify -invert without -multiply_by, -divide_by or -combinational."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
set invert 1
|
|
|
|
|
}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
if {[info exists keys(-duty_cycle)] && ![info exists keys(-multiply_by)]} {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 539 "-duty_cycle requires -multiply_by value."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
if { [info exists keys(-pll_feedback)] || [info exists keys(-pll_output)] } {
|
|
|
|
|
if {![info exists keys(-pll_output)] } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 540 "missing -pll_output argument."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
if { ![info exists keys(-pll_feedback)] } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 541 "missing -pll_feedback argument."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
set pll_feedback [get_pin_error "-pll_feedback" $keys(-pll_feedback)]
|
|
|
|
|
set pll_out [get_pin_error "-pll_output" $keys(-pll_output)]
|
|
|
|
|
set pll_inst [$pll_out instance]
|
|
|
|
|
if { [$pll_feedback instance] != $pll_inst } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 542 "PLL output and feedback pins must be on the same instance."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
if { [$source_pin instance] != $pll_inst } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 543 "source pin must be on the same instance as the PLL output pin."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
if { [lsearch $pins $pll_out] == -1 } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 544 "PLL output must be one of the clock pins."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
set comment [parse_comment_key keys]
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
make_generated_clock $name $pins $add $source_pin $master_clk \
|
|
|
|
|
$pll_out $pll_feedback \
|
|
|
|
|
$divide_by $multiply_by $duty_cycle $invert $combinational \
|
|
|
|
|
$edges $edge_shifts $comment
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "group_path" \
|
|
|
|
|
{-name group_name [-weight weight] [-critical_range range]\
|
|
|
|
|
[-default] [-comment comment]\
|
|
|
|
|
[-from from_list] [-rise_from from_list] [-fall_from from_list]\
|
|
|
|
|
[-through through_list] [-rise_through through_list]\
|
|
|
|
|
[-fall_through through_list] [-to to_list] [-rise_to to_list]\
|
|
|
|
|
[-fall_to to_list]}
|
|
|
|
|
|
|
|
|
|
# The -weight and -critical_range arguments are ignored.
|
|
|
|
|
proc group_path { args } {
|
|
|
|
|
parse_key_args "group_path" args \
|
|
|
|
|
keys {-name -weight -critical_range \
|
|
|
|
|
-from -rise_from -fall_from \
|
|
|
|
|
-to -rise_to -fall_to -comment} \
|
|
|
|
|
flags {-default} 0
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
set cmd "group_path"
|
|
|
|
|
set arg_error 0
|
|
|
|
|
set from [parse_from_arg keys arg_error]
|
|
|
|
|
set thrus [parse_thrus_arg args arg_error]
|
|
|
|
|
set to [parse_to_arg1 keys "rise_fall" arg_error]
|
|
|
|
|
check_exception_pins $from $to
|
|
|
|
|
if { $arg_error } {
|
|
|
|
|
delete_from_thrus_to $from $thrus $to
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 545 "group_path command failed."
|
2018-09-28 17:54:21 +02:00
|
|
|
return 0
|
|
|
|
|
}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
check_for_key_args $cmd args
|
|
|
|
|
if { $args != {} } {
|
|
|
|
|
delete_from_thrus_to $from $thrus $to
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 546 "positional arguments not supported."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
if { ($from == "NULL" && $thrus == "" && $to == "NULL") } {
|
|
|
|
|
delete_from_thrus_to $from $thrus $to
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 547 "-from, -through or -to required."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
set default [info exists flags(-default)]
|
|
|
|
|
set name_exists [info exists keys(-name)]
|
|
|
|
|
if { $default && $name_exists } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 548 "-name and -default are mutually exclusive."
|
2018-09-28 17:54:21 +02:00
|
|
|
} elseif { !$name_exists && !$default } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 549 "-name or -default option is required."
|
2018-09-28 17:54:21 +02:00
|
|
|
} elseif { $default } {
|
|
|
|
|
set name ""
|
|
|
|
|
} else {
|
|
|
|
|
set name $keys(-name)
|
|
|
|
|
}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
set comment [parse_comment_key keys]
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
make_group_path $name $default $from $thrus $to $comment
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc check_exception_pins { from to } {
|
|
|
|
|
variable sdc_file
|
|
|
|
|
variable sdc_line
|
|
|
|
|
if { [info exists sdc_file] } {
|
|
|
|
|
set file $sdc_file
|
|
|
|
|
set line $sdc_line
|
|
|
|
|
} else {
|
|
|
|
|
set file ""
|
|
|
|
|
set line 0
|
|
|
|
|
}
|
|
|
|
|
check_exception_from_pins $from $file $line
|
|
|
|
|
check_exception_to_pins $to $file $line
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_clock_gating_check" \
|
|
|
|
|
{[-setup setup_time] [-hold hold_time] [-rise] [-fall]\
|
|
|
|
|
[-low] [-high] [objects]}
|
|
|
|
|
|
|
|
|
|
proc set_clock_gating_check { args } {
|
|
|
|
|
parse_key_args "set_clock_gating_check" args keys {-setup -hold } \
|
|
|
|
|
flags {-rise -fall -high -low}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
check_argc_eq0or1 "set_clock_gating_check" $args
|
|
|
|
|
set tr [parse_rise_fall_flags flags]
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
set active_value ""
|
|
|
|
|
if {[info exists flags(-high)] && [info exists flags(-low)]} {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 550 "cannot specify both -high and -low."
|
2018-09-28 17:54:21 +02:00
|
|
|
} elseif [info exists flags(-low)] {
|
|
|
|
|
set active_value "0"
|
|
|
|
|
} elseif [info exists flags(-high)] {
|
|
|
|
|
set active_value "1"
|
|
|
|
|
}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
if { !([info exists keys(-hold)] || [info exists keys(-setup)]) } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 551 "missing -setup or -hold argument."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
if [info exists keys(-hold)] {
|
|
|
|
|
set_clock_gating_check1 $args $tr "min" $keys(-hold) $active_value
|
|
|
|
|
}
|
|
|
|
|
if [info exists keys(-setup)] {
|
|
|
|
|
set_clock_gating_check1 $args $tr "max" $keys(-setup) $active_value
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc set_clock_gating_check1 { args tr setup_hold margin active_value } {
|
|
|
|
|
set margin [time_ui_sta $margin]
|
|
|
|
|
if { [llength $args] == 0 } {
|
|
|
|
|
if { $active_value != "" } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 552 "-high and -low only permitted for pins and instances."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
set_clock_gating_check_cmd $tr $setup_hold $margin
|
|
|
|
|
} elseif { [llength $args] == 1 } {
|
|
|
|
|
parse_clk_inst_port_pin_arg [lindex $args 0] clks insts pins
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
if { $clks != {} && $active_value != "" } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 553 "-high and -low only permitted for pins and instances."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
foreach clk $clks {
|
|
|
|
|
set_clock_gating_check_clk_cmd $clk $tr $setup_hold $margin
|
|
|
|
|
}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
if { $active_value == "" } {
|
|
|
|
|
set active_value "X"
|
|
|
|
|
}
|
|
|
|
|
foreach pin $pins {
|
|
|
|
|
set_clock_gating_check_pin_cmd $pin $tr $setup_hold \
|
|
|
|
|
$margin $active_value
|
|
|
|
|
}
|
|
|
|
|
foreach inst $insts {
|
|
|
|
|
set_clock_gating_check_instance_cmd $inst $tr $setup_hold \
|
|
|
|
|
$margin $active_value
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_clock_groups" \
|
|
|
|
|
{[-name name] [-logically_exclusive] [-physically_exclusive]\
|
|
|
|
|
[-asynchronous] [-allow_paths] [-comment comment] -group clocks}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
proc set_clock_groups { args } {
|
|
|
|
|
parse_key_args "set_clock_groups" args \
|
|
|
|
|
keys {-name -comment} \
|
|
|
|
|
flags {-logically_exclusive -physically_exclusive \
|
|
|
|
|
-asynchronous -allow_paths} 0
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
if {[info exists keys(-name)]} {
|
|
|
|
|
set name $keys(-name)
|
|
|
|
|
} else {
|
|
|
|
|
set name ""
|
|
|
|
|
}
|
|
|
|
|
set logically_exclusive [info exists flags(-logically_exclusive)]
|
|
|
|
|
set physically_exclusive [info exists flags(-physically_exclusive)]
|
|
|
|
|
set asynchronous [info exists flags(-asynchronous)]
|
|
|
|
|
set allow_paths [info exists flags(-allow_paths)]
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
if { ($logically_exclusive+$physically_exclusive+$asynchronous) == 0 } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 554 "one of -logically_exclusive, -physically_exclusive or -asynchronous is required."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
if { ($logically_exclusive+$physically_exclusive+$asynchronous) > 1 } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 555 "the keywords -logically_exclusive, -physically_exclusive and -asynchronous are mutually exclusive."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
set comment [parse_comment_key keys]
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
set clk_groups [make_clock_groups $name $logically_exclusive \
|
|
|
|
|
$physically_exclusive $asynchronous $allow_paths \
|
|
|
|
|
$comment]
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
while { $args != "" } {
|
|
|
|
|
set arg [lindex $args 0]
|
|
|
|
|
if {[string match $arg "-group"]} {
|
|
|
|
|
set group_clks [get_clocks_warn "clocks" [lindex $args 1]]
|
|
|
|
|
if { $group_clks != {} } {
|
|
|
|
|
clock_groups_make_group $clk_groups $group_clks
|
|
|
|
|
}
|
|
|
|
|
set args [lrange $args 2 end]
|
|
|
|
|
} else {
|
|
|
|
|
if {[is_keyword_arg $arg]} {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 349 "unknown keyword argument $arg."
|
2018-09-28 17:54:21 +02:00
|
|
|
} else {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 341 "extra positional argument $arg."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
set args [lrange $args 1 end]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_clock_latency" \
|
|
|
|
|
{[-source] [-clock clock] [-rise] [-fall] [-min] [-max]\
|
|
|
|
|
[-early] [-late] delay objects}
|
|
|
|
|
|
|
|
|
|
proc set_clock_latency { args } {
|
|
|
|
|
parse_key_args "set_clock_latency" args keys {-clock} \
|
|
|
|
|
flags {-rise -fall -min -max -source -late -early}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
check_argc_eq2 "set_clock_latency" $args
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
set delay [lindex $args 0]
|
|
|
|
|
check_float "delay" $delay
|
|
|
|
|
set delay [time_ui_sta $delay]
|
|
|
|
|
set objects [lindex $args 1]
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
parse_clk_port_pin_arg $objects clks pins
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
set tr [parse_rise_fall_flags flags]
|
|
|
|
|
set min_max [parse_min_max_all_flags flags]
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
set pin_clk "NULL"
|
|
|
|
|
if { [info exists keys(-clock)] } {
|
|
|
|
|
set pin_clk [get_clock_warn "clock" $keys(-clock)]
|
|
|
|
|
if { $clks != {} } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 342 "-clock ignored for clock objects."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
if {[info exists flags(-source)]} {
|
|
|
|
|
# Insertion delay (source latency).
|
|
|
|
|
set early_late [parse_early_late_all_flags flags]
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
foreach clk $clks {
|
|
|
|
|
set_clock_insertion_cmd $clk "NULL" $tr $min_max $early_late $delay
|
|
|
|
|
}
|
|
|
|
|
foreach pin $pins {
|
|
|
|
|
# Source only allowed on clocks and clock pins.
|
|
|
|
|
if { ![is_clock_src $pin] } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 556 "-source '[get_full_name $pin]' is not a clock pin."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
set_clock_insertion_cmd $pin_clk $pin $tr $min_max $early_late $delay
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
# Latency.
|
|
|
|
|
if {[info exists flags(-early)] || [info exists flags(-late)]} {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 557 "-early/-late is only allowed with -source."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
foreach clk $clks {
|
|
|
|
|
set_clock_latency_cmd $clk "NULL" $tr $min_max $delay
|
|
|
|
|
}
|
|
|
|
|
foreach pin $pins {
|
|
|
|
|
set_clock_latency_cmd $pin_clk $pin $tr $min_max $delay
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
2019-06-24 04:52:29 +02:00
|
|
|
define_cmd_args "set_sense" \
|
|
|
|
|
{[-type clock|data] [-positive] [-negative] [-pulse pulse_type]\
|
|
|
|
|
[-stop_propagation] [-clocks clocks] pins}
|
|
|
|
|
|
|
|
|
|
proc set_sense { args } {
|
2019-06-24 06:38:01 +02:00
|
|
|
parse_key_args "set_sense" args keys {-type} flags {} 0
|
|
|
|
|
|
2019-06-24 04:52:29 +02:00
|
|
|
set type "clock"
|
|
|
|
|
if { [info exists keys(-type)] } {
|
|
|
|
|
set type $keys(-type)
|
|
|
|
|
if { $type == "data" } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 343 "set_sense -type data not supported."
|
2019-06-24 04:52:29 +02:00
|
|
|
} elseif { $type == "clock" } {
|
|
|
|
|
set_clock_sense_cmd1 "set_sense" $args
|
|
|
|
|
} else {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 558 "set_sense -type clock|data"
|
2019-06-24 04:52:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# deprecated in SDC 2.1
|
2018-09-28 17:54:21 +02:00
|
|
|
define_cmd_args "set_clock_sense" \
|
|
|
|
|
{[-positive] [-negative] [-pulse pulse_type] [-stop_propagation] \
|
|
|
|
|
[-clock clocks] pins}
|
|
|
|
|
|
|
|
|
|
proc set_clock_sense { args } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 344 "set_clock_sense is deprecated as of SDC 2.1. Use set_sense -type clock."
|
2019-06-24 04:52:29 +02:00
|
|
|
set_clock_sense_cmd1 "set_clock_sense" $args
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc set_clock_sense_cmd1 { cmd cmd_args } {
|
2018-09-28 17:54:21 +02:00
|
|
|
# SDC uses -clock, OT, OC use -clocks
|
2019-06-24 04:52:29 +02:00
|
|
|
parse_key_args $cmd cmd_args keys {-clock -clocks -pulse} \
|
|
|
|
|
flags {-positive -negative -stop_propagation} 0
|
2019-06-24 06:38:01 +02:00
|
|
|
check_argc_eq1 $cmd $cmd_args
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
set pulse [info exists keys(-pulse)]
|
|
|
|
|
if { $pulse } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 345 "-pulse argument not supported."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
set positive [info exists flags(-positive)]
|
|
|
|
|
set negative [info exists flags(-negative)]
|
|
|
|
|
set stop_propagation [info exists flags(-stop_propagation)]
|
|
|
|
|
if { ($positive && ($negative || $stop_propagation || $pulse)) \
|
|
|
|
|
|| ($negative && ($positive || $stop_propagation || $pulse)) \
|
|
|
|
|
|| ($stop_propagation && ($positive || $negative || $pulse))
|
2019-06-24 06:38:01 +02:00
|
|
|
|| ($pulse && ($positive || $negative || $stop_propagation)) } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 346 "-positive, -negative, -stop_propagation and -pulse are mutually exclusive."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2019-06-24 04:52:29 +02:00
|
|
|
set pins [get_port_pins_error "pins" [lindex $cmd_args 0]]
|
2018-09-28 17:54:21 +02:00
|
|
|
set clks {}
|
|
|
|
|
if {[info exists keys(-clock)]} {
|
|
|
|
|
set clks [get_clocks_warn "clock" $keys(-clock)]
|
|
|
|
|
}
|
|
|
|
|
if {[info exists keys(-clocks)]} {
|
|
|
|
|
set clks [get_clocks_warn "clocks" $keys(-clocks)]
|
|
|
|
|
}
|
|
|
|
|
foreach pin $pins {
|
|
|
|
|
if {[$pin is_hierarchical]} {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 347 "hierarchical pin '[get_full_name $pin]' not supported."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
set_clock_sense_cmd $pins $clks $positive $negative $stop_propagation
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_clock_transition" \
|
|
|
|
|
{[-rise] [-fall] [-min] [-max] transition clocks}
|
|
|
|
|
|
|
|
|
|
proc set_clock_transition { args } {
|
|
|
|
|
parse_key_args "set_clock_transition" args keys {} \
|
|
|
|
|
flags {-rise -fall -max -min}
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
set tr [parse_rise_fall_flags flags]
|
|
|
|
|
set min_max [parse_min_max_all_flags flags]
|
|
|
|
|
check_argc_eq2 "set_clock_transition" $args
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
set slew [lindex $args 0]
|
|
|
|
|
set clks [get_clocks_warn "clocks" [lindex $args 1]]
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
foreach clk $clks {
|
|
|
|
|
if { [$clk is_virtual] } {
|
2021-01-19 19:13:57 +01:00
|
|
|
sta_warn 559 "transition time can not be specified for virtual clocks."
|
2018-09-28 17:54:21 +02:00
|
|
|
} else {
|
|
|
|
|
set_clock_slew_cmd $clk $tr $min_max [time_ui_sta $slew]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
# -rise/-fall are obsolete.
|
|
|
|
|
define_cmd_args "set_clock_uncertainty" \
|
2019-06-27 00:58:23 +02:00
|
|
|
{[-from|-rise_from|-fall_from from_clock]\
|
2020-04-26 17:49:09 +02:00
|
|
|
[-to|-rise_to|-fall_to to_clock] [-rise] [-fall]\
|
|
|
|
|
[-setup] [-hold] uncertainty [objects]}
|
2019-06-27 00:58:23 +02:00
|
|
|
|
|
|
|
|
proc set_clock_uncertainty { args } {
|
|
|
|
|
parse_key_args "set_clock_uncertainty" args \
|
|
|
|
|
keys {-from -rise_from -fall_from -to -rise_to -fall_to} \
|
|
|
|
|
flags {-rise -fall -setup -hold}
|
2020-04-26 17:49:09 +02:00
|
|
|
|
2019-06-27 00:58:23 +02:00
|
|
|
if { [llength $args] == 0 } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 560 "missing uncertainty value."
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
set uncertainty [lindex $args 0]
|
|
|
|
|
check_float "uncertainty" $uncertainty
|
|
|
|
|
set uncertainty [time_ui_sta $uncertainty]
|
2020-04-26 17:49:09 +02:00
|
|
|
|
2019-06-27 00:58:23 +02:00
|
|
|
set min_max "min_max"
|
|
|
|
|
if { [info exists flags(-setup)] && ![info exists flags(-hold)] } {
|
|
|
|
|
set min_max "max"
|
|
|
|
|
}
|
|
|
|
|
if { [info exists flags(-hold)] && ![info exists flags(-setup)] } {
|
|
|
|
|
set min_max "min"
|
|
|
|
|
}
|
2020-04-26 17:49:09 +02:00
|
|
|
|
2019-06-27 00:58:23 +02:00
|
|
|
if { [info exists keys(-from)] } {
|
|
|
|
|
set from_key "-from"
|
2019-11-11 23:30:19 +01:00
|
|
|
set from_rf "rise_fall"
|
2019-06-27 00:58:23 +02:00
|
|
|
} elseif { [info exists keys(-rise_from)] } {
|
|
|
|
|
set from_key "-rise_from"
|
2019-11-11 23:30:19 +01:00
|
|
|
set from_rf "rise"
|
2019-06-27 00:58:23 +02:00
|
|
|
} elseif { [info exists keys(-fall_from)] } {
|
|
|
|
|
set from_key "-fall_from"
|
2019-11-11 23:30:19 +01:00
|
|
|
set from_rf "fall"
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
|
|
|
|
set from_key "none"
|
|
|
|
|
}
|
2020-04-26 17:49:09 +02:00
|
|
|
|
2019-06-27 00:58:23 +02:00
|
|
|
if { [info exists keys(-to)] } {
|
|
|
|
|
set to_key "-to"
|
2019-11-11 23:30:19 +01:00
|
|
|
set to_rf "rise_fall"
|
2019-06-27 00:58:23 +02:00
|
|
|
} elseif { [info exists keys(-rise_to)] } {
|
|
|
|
|
set to_key "-rise_to"
|
2019-11-11 23:30:19 +01:00
|
|
|
set to_rf "rise"
|
2019-06-27 00:58:23 +02:00
|
|
|
} elseif { [info exists keys(-fall_to)] } {
|
|
|
|
|
set to_key "-fall_to"
|
2019-11-11 23:30:19 +01:00
|
|
|
set to_rf "fall"
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
|
|
|
|
set to_key "none"
|
|
|
|
|
}
|
2020-04-26 17:49:09 +02:00
|
|
|
|
2019-06-27 00:58:23 +02:00
|
|
|
if { $from_key != "none" && $to_key == "none" \
|
|
|
|
|
|| $from_key == "none" && $to_key != "none" } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 561 "-from/-to must be used together."
|
2019-06-27 00:58:23 +02:00
|
|
|
} elseif { $from_key != "none" && $to_key != "none" } {
|
|
|
|
|
# Inter-clock uncertainty.
|
|
|
|
|
check_argc_eq1 "-from/-to" $args
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2019-06-27 00:58:23 +02:00
|
|
|
# -from/-to can be lists.
|
|
|
|
|
set from_clks [get_clocks_warn "from_clocks" $keys($from_key)]
|
|
|
|
|
set to_clks [get_clocks_warn "to_clocks" $keys($to_key)]
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2019-06-27 00:58:23 +02:00
|
|
|
foreach from_clk $from_clks {
|
|
|
|
|
foreach to_clk $to_clks {
|
2019-11-11 23:30:19 +01:00
|
|
|
set_inter_clock_uncertainty $from_clk $from_rf \
|
|
|
|
|
$to_clk $to_rf $min_max $uncertainty
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
|
|
|
|
# Single clock uncertainty.
|
|
|
|
|
check_argc_eq2 "set_clock_uncertainty" $args
|
|
|
|
|
if { [info exists flags(-rise)] \
|
|
|
|
|
|| [info exists flags(-fall)] } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 562 "-rise, -fall options not allowed for single clock uncertainty."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
set objects [lindex $args 1]
|
|
|
|
|
parse_clk_port_pin_arg $objects clks pins
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2019-06-27 00:58:23 +02:00
|
|
|
foreach clk $clks {
|
|
|
|
|
set_clock_uncertainty_clk $clk $min_max $uncertainty
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
foreach pin $pins {
|
|
|
|
|
set_clock_uncertainty_pin $pin $min_max $uncertainty
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_data_check" \
|
|
|
|
|
{[-from from_pin] [-rise_from from_pin] [-fall_from from_pin]\
|
|
|
|
|
[-to to_pin] [-rise_to to_pin] [-fall_to to_pin]\
|
|
|
|
|
[-setup | -hold] [-clock clock] margin}
|
|
|
|
|
|
|
|
|
|
proc set_data_check { args } {
|
|
|
|
|
parse_key_args "set_data_check" args \
|
|
|
|
|
keys {-from -rise_from -fall_from -to -rise_to -fall_to -clock} \
|
|
|
|
|
flags {-setup -hold}
|
|
|
|
|
check_argc_eq1 "set_data_check" $args
|
2020-04-26 17:49:09 +02:00
|
|
|
|
2019-06-27 00:58:23 +02:00
|
|
|
set margin [time_ui_sta $args]
|
2019-11-11 23:30:19 +01:00
|
|
|
set from_rf "rise_fall"
|
|
|
|
|
set to_rf "rise_fall"
|
2019-06-27 00:58:23 +02:00
|
|
|
set clk "NULL"
|
2020-04-26 17:49:09 +02:00
|
|
|
|
2019-06-27 00:58:23 +02:00
|
|
|
if [info exists keys(-from)] {
|
|
|
|
|
set from [get_port_pin_error "from_pin" $keys(-from)]
|
|
|
|
|
} elseif [info exists keys(-rise_from)] {
|
|
|
|
|
set from [get_port_pin_error "from_pin" $keys(-rise_from)]
|
2019-11-11 23:30:19 +01:00
|
|
|
set from_rf "rise"
|
2019-06-27 00:58:23 +02:00
|
|
|
} elseif [info exists keys(-fall_from)] {
|
|
|
|
|
set from [get_port_pin_error "from_pin" $keys(-fall_from)]
|
2019-11-11 23:30:19 +01:00
|
|
|
set from_rf "fall"
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 563 "missing -from, -rise_from or -fall_from argument."
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
2020-04-26 17:49:09 +02:00
|
|
|
|
2019-06-27 00:58:23 +02:00
|
|
|
if [info exists keys(-to)] {
|
|
|
|
|
set to [get_port_pin_error "to_pin" $keys(-to)]
|
|
|
|
|
} elseif [info exists keys(-rise_to)] {
|
|
|
|
|
set to [get_port_pin_error "to_pin" $keys(-rise_to)]
|
2019-11-11 23:30:19 +01:00
|
|
|
set to_rf "rise"
|
2019-06-27 00:58:23 +02:00
|
|
|
} elseif [info exists keys(-fall_to)] {
|
|
|
|
|
set to [get_port_pin_error "to_pin" $keys(-fall_to)]
|
2019-11-11 23:30:19 +01:00
|
|
|
set to_rf "fall"
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 564 "missing -to, -rise_to or -fall_to argument."
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
2020-04-26 17:49:09 +02:00
|
|
|
|
2019-06-27 00:58:23 +02:00
|
|
|
if [info exists keys(-clock)] {
|
|
|
|
|
set clk [get_clock_warn "clock" $keys(-clock)]
|
|
|
|
|
}
|
2020-04-26 17:49:09 +02:00
|
|
|
|
2019-06-27 00:58:23 +02:00
|
|
|
if { [info exists flags(-setup)] && ![info exists flags(-hold)] } {
|
|
|
|
|
set setup_hold "setup"
|
|
|
|
|
} elseif { [info exists flags(-hold)] && ![info exists flags(-setup)] } {
|
|
|
|
|
set setup_hold "hold"
|
|
|
|
|
} else {
|
|
|
|
|
set setup_hold "setup_hold"
|
|
|
|
|
}
|
2020-04-26 17:49:09 +02:00
|
|
|
|
2019-11-11 23:30:19 +01:00
|
|
|
set_data_check_cmd $from $from_rf $to $to_rf $clk $setup_hold $margin
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_disable_timing" \
|
|
|
|
|
{[-from from_port] [-to to_port] objects}
|
|
|
|
|
|
|
|
|
|
# Parallax supports -from or -to alone.
|
|
|
|
|
# OT requires both -from and -to args.
|
|
|
|
|
proc set_disable_timing { args } {
|
|
|
|
|
parse_key_args "set_disable_timing" args keys {-from -to} flags {}
|
|
|
|
|
check_argc_eq1 "set_disable_timing" $args
|
|
|
|
|
|
|
|
|
|
set from {}
|
|
|
|
|
if { [info exists keys(-from)] } {
|
|
|
|
|
set from $keys(-from)
|
|
|
|
|
}
|
|
|
|
|
set to {}
|
|
|
|
|
if { [info exists keys(-to)] } {
|
|
|
|
|
set to $keys(-to)
|
|
|
|
|
}
|
|
|
|
|
parse_libcell_libport_inst_port_pin_edge_timing_arc_set_arg $args \
|
|
|
|
|
libcells libports insts ports pins edges timing_arc_sets
|
|
|
|
|
|
|
|
|
|
if { ([info exists keys(-from)] || [info exists keys(-to)]) \
|
|
|
|
|
&& ($libports != {} || $pins != {} || $ports != {}) } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 348 "-from/-to keywords ignored for lib_pin, port and pin arguments."
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach libcell $libcells {
|
|
|
|
|
set_disable_timing_cell $libcell $from $to
|
|
|
|
|
}
|
|
|
|
|
foreach libport $libports {
|
|
|
|
|
disable_lib_port $libport
|
|
|
|
|
}
|
|
|
|
|
foreach inst $insts {
|
|
|
|
|
set_disable_timing_instance $inst $from $to
|
|
|
|
|
}
|
|
|
|
|
foreach pin $pins {
|
|
|
|
|
disable_pin $pin
|
|
|
|
|
}
|
|
|
|
|
foreach port $ports {
|
|
|
|
|
disable_port $port
|
|
|
|
|
}
|
|
|
|
|
foreach edge $edges {
|
|
|
|
|
disable_edge $edge
|
|
|
|
|
}
|
|
|
|
|
foreach timing_arc_set $timing_arc_sets {
|
|
|
|
|
disable_timing_arc_set $timing_arc_set
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc set_disable_timing_instance { inst from to } {
|
|
|
|
|
set from_ports [parse_disable_inst_ports $inst $from]
|
|
|
|
|
set to_ports [parse_disable_inst_ports $inst $to]
|
|
|
|
|
if { ![$inst is_leaf] } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 565 "-from/-to hierarchical instance not supported."
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
if { $from_ports == "NULL" && $to_ports == "NULL" } {
|
|
|
|
|
disable_instance $inst "NULL" "NULL"
|
|
|
|
|
} elseif { $from_ports == "NULL" } {
|
|
|
|
|
foreach to_port $to_ports {
|
|
|
|
|
disable_instance $inst "NULL" $to_port
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
} elseif { $to_ports == "NULL" } {
|
|
|
|
|
foreach from_port $from_ports {
|
|
|
|
|
disable_instance $inst $from_port "NULL"
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
|
|
|
|
foreach from_port $from_ports {
|
|
|
|
|
foreach to_port $to_ports {
|
|
|
|
|
disable_instance $inst $from_port $to_port
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Find ports in inst's cell that have pins.
|
|
|
|
|
# Bus ports are expanded into a list.
|
|
|
|
|
proc parse_disable_inst_ports { inst port_name } {
|
|
|
|
|
global hierarchy_separator
|
|
|
|
|
|
|
|
|
|
if { $port_name == "" } {
|
|
|
|
|
set ports "NULL"
|
|
|
|
|
} else {
|
2019-07-02 16:07:34 +02:00
|
|
|
set cell [instance_property $inst cell]
|
|
|
|
|
set port [$cell find_port $port_name]
|
2019-06-27 00:58:23 +02:00
|
|
|
if { $port == "NULL" } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 566 "pin '[get_full_name $inst]${hierarchy_separator}${port_name}' not found."
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
2019-07-02 16:07:34 +02:00
|
|
|
set lib_port [get_property $port liberty_port]
|
|
|
|
|
set ports [port_members $lib_port]
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
return $ports
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc set_disable_timing_cell { cell from to } {
|
|
|
|
|
set from_ports [parse_disable_cell_ports $cell $from]
|
|
|
|
|
set to_ports [parse_disable_cell_ports $cell $to]
|
|
|
|
|
if { $from_ports == "NULL" && $to_ports == "NULL" } {
|
|
|
|
|
disable_cell $cell "NULL" "NULL"
|
|
|
|
|
} elseif { $from_ports == "NULL" } {
|
|
|
|
|
foreach to_port $to_ports {
|
|
|
|
|
disable_cell $cell "NULL" $to_port
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
} elseif { $to_ports == "NULL" } {
|
|
|
|
|
foreach from_port $from_ports {
|
|
|
|
|
disable_cell $cell $from_port "NULL"
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
|
|
|
|
foreach from_port $from_ports {
|
|
|
|
|
foreach to_port $to_ports {
|
|
|
|
|
disable_cell $cell $from_port $to_port
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Find cell ports.
|
|
|
|
|
# Bus ports are expanded into a list.
|
|
|
|
|
proc parse_disable_cell_ports { cell port_name } {
|
|
|
|
|
global hierarchy_separator
|
|
|
|
|
|
|
|
|
|
if { $port_name == "" } {
|
|
|
|
|
set ports "NULL"
|
|
|
|
|
} else {
|
|
|
|
|
set port [$cell find_liberty_port $port_name]
|
|
|
|
|
if { $port == "NULL" } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 567 "pin '[get_name $cell]${hierarchy_separator}${port_name}' not found."
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
|
|
|
|
set ports [port_members $port]
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
return $ports
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_false_path" \
|
|
|
|
|
{[-setup] [-hold] [-rise] [-fall] [-reset_path] [-comment comment]\
|
|
|
|
|
[-from from_list] [-rise_from from_list] [-fall_from from_list]\
|
|
|
|
|
[-through through_list] [-rise_through through_list]\
|
|
|
|
|
[-fall_through through_list] [-to to_list] [-rise_to to_list]\
|
|
|
|
|
[-fall_to to_list]}
|
|
|
|
|
|
|
|
|
|
proc set_false_path { args } {
|
|
|
|
|
parse_key_args "set_false_path" args \
|
|
|
|
|
keys {-from -rise_from -fall_from -to -rise_to -fall_to -comment} \
|
|
|
|
|
flags {-setup -hold -rise -fall -reset_path} 0
|
|
|
|
|
|
|
|
|
|
set min_max "min_max"
|
|
|
|
|
if { [info exists flags(-setup)] && ![info exists flags(-hold)] } {
|
|
|
|
|
set min_max "max"
|
|
|
|
|
}
|
|
|
|
|
if { [info exists flags(-hold)] && ![info exists flags(-setup)] } {
|
|
|
|
|
set min_max "min"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set cmd "set_false_path"
|
|
|
|
|
set arg_error 0
|
|
|
|
|
set from [parse_from_arg keys arg_error]
|
|
|
|
|
set thrus [parse_thrus_arg args arg_error]
|
|
|
|
|
set to [parse_to_arg keys flags arg_error]
|
|
|
|
|
check_exception_pins $from $to
|
|
|
|
|
if { $arg_error } {
|
|
|
|
|
delete_from_thrus_to $from $thrus $to
|
2020-04-25 04:53:22 +02:00
|
|
|
} else {
|
|
|
|
|
check_for_key_args $cmd args
|
|
|
|
|
if { $args != {} } {
|
2020-12-20 19:21:50 +01:00
|
|
|
sta_warn 600 "'$args' ignored."
|
2020-04-25 04:53:22 +02:00
|
|
|
}
|
|
|
|
|
if { ($from == "NULL" && $thrus == "" && $to == "NULL") } {
|
|
|
|
|
delete_from_thrus_to $from $thrus $to
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 350 "-from, -through or -to required."
|
2020-04-25 04:53:22 +02:00
|
|
|
} else {
|
|
|
|
|
if [info exists flags(-reset_path)] {
|
|
|
|
|
reset_path_cmd $from $thrus $to $min_max
|
|
|
|
|
}
|
2020-04-26 17:49:09 +02:00
|
|
|
|
2020-04-25 04:53:22 +02:00
|
|
|
set comment [parse_comment_key keys]
|
2020-04-26 17:49:09 +02:00
|
|
|
|
2020-04-25 04:53:22 +02:00
|
|
|
make_false_path $from $thrus $to $min_max $comment
|
|
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_ideal_latency" \
|
|
|
|
|
{[-rise] [-fall] [-min] [-max] delay objects}
|
|
|
|
|
|
|
|
|
|
proc set_ideal_latency { args } {
|
|
|
|
|
# ignored
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
# Specifies net has zero weight for placement.
|
|
|
|
|
define_cmd_args "set_ideal_net" { nets }
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_ideal_network" {[-no_propagation] objects}
|
|
|
|
|
|
|
|
|
|
proc set_ideal_network { args } {
|
|
|
|
|
# ignored
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_ideal_transition" \
|
|
|
|
|
{[-rise] [-fall] [-min] [-max] transition_time objects}
|
|
|
|
|
|
|
|
|
|
proc set_ideal_transition { args } {
|
|
|
|
|
# ignored
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_input_delay" \
|
|
|
|
|
{[-rise] [-fall] [-max] [-min]\
|
|
|
|
|
[-clock clock] [-clock_fall]\
|
|
|
|
|
[-reference_pin ref_pin]\
|
|
|
|
|
[-source_latency_included] [-network_latency_included]\
|
|
|
|
|
[-add_delay] delay port_pin_list}
|
|
|
|
|
|
|
|
|
|
proc set_input_delay { args } {
|
|
|
|
|
set_port_delay "set_input_delay" "set_input_delay_cmd" $args \
|
|
|
|
|
{"input" "bidirect"}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc set_port_delay { cmd sta_cmd cmd_args port_dirs } {
|
|
|
|
|
parse_key_args $cmd cmd_args \
|
|
|
|
|
keys {-clock -reference_pin} \
|
|
|
|
|
flags {-rise -fall -max -min -clock_fall -add_delay \
|
|
|
|
|
-source_latency_included -network_latency_included}
|
|
|
|
|
check_argc_eq2 $cmd $cmd_args
|
|
|
|
|
|
|
|
|
|
set delay_arg [lindex $cmd_args 0]
|
|
|
|
|
check_float "delay" $delay_arg
|
|
|
|
|
set delay [time_ui_sta $delay_arg]
|
|
|
|
|
set pins [get_port_pins_error "pins" [lindex $cmd_args 1]]
|
|
|
|
|
|
|
|
|
|
set clk "NULL"
|
|
|
|
|
if [info exists keys(-clock)] {
|
|
|
|
|
set clk [get_clock_warn "clock" $keys(-clock)]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set ref_pin "NULL"
|
|
|
|
|
if [info exists keys(-reference_pin)] {
|
|
|
|
|
set ref_pin [get_port_pin_error "ref_pin" $keys(-reference_pin)]
|
|
|
|
|
if { [info exists flags(-source_latency_included)] } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 351 "-source_latency_included ignored with -reference_pin."
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
if { [info exists flags(-network_latency_included)] } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 352 "-network_latency_included ignored with -reference_pin."
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if [info exists flags(-clock_fall)] {
|
2019-11-11 23:30:19 +01:00
|
|
|
set clk_rf "fall"
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
2019-11-11 23:30:19 +01:00
|
|
|
set clk_rf "rise"
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set tr [parse_rise_fall_flags flags]
|
|
|
|
|
set min_max [parse_min_max_all_flags flags]
|
|
|
|
|
set add [info exists flags(-add_delay)]
|
|
|
|
|
set source_latency_included [info exists flags(-source_latency_included)]
|
|
|
|
|
set network_latency_included [info exists flags(-network_latency_included)]
|
|
|
|
|
|
|
|
|
|
foreach pin $pins {
|
|
|
|
|
if { [$pin is_top_level_port] \
|
|
|
|
|
&& [lsearch $port_dirs [pin_direction $pin]] == -1 } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 353 "$cmd not allowed on [pin_direction $pin] port '[get_full_name $pin]'."
|
2019-06-27 00:58:23 +02:00
|
|
|
} elseif { $clk != "NULL" && [lsearch [$clk sources] $pin] != -1 } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 354 "$cmd relative to a clock defined on the same port/pin not allowed."
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
2019-11-11 23:30:19 +01:00
|
|
|
$sta_cmd $pin $tr $clk $clk_rf $ref_pin\
|
2019-06-27 00:58:23 +02:00
|
|
|
$source_latency_included $network_latency_included \
|
|
|
|
|
$min_max $add $delay
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_max_delay" \
|
|
|
|
|
{[-rise] [-fall] [-ignore_clock_latency] [-reset_path] [-comment comment]\
|
|
|
|
|
[-from from_list] [-rise_from from_list] [-fall_from from_list]\
|
|
|
|
|
[-through through_list] [-rise_through through_list]\
|
|
|
|
|
[-fall_through through_list]\
|
|
|
|
|
[-to to_list] [-rise_to to_list] [-fall_to to_list] delay}
|
|
|
|
|
|
|
|
|
|
proc set_max_delay { args } {
|
|
|
|
|
set_path_delay "set_max_delay" $args max
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc set_path_delay { cmd args min_max } {
|
|
|
|
|
parse_key_args $cmd args \
|
|
|
|
|
keys {-from -rise_from -fall_from -to -rise_to -fall_to -comment} \
|
|
|
|
|
flags {-rise -fall -ignore_clock_latency -reset_path} 0
|
|
|
|
|
|
|
|
|
|
set arg_error 0
|
|
|
|
|
set from [parse_from_arg keys arg_error]
|
|
|
|
|
set thrus [parse_thrus_arg args arg_error]
|
|
|
|
|
set to [parse_to_arg keys flags arg_error]
|
|
|
|
|
if { $arg_error } {
|
|
|
|
|
delete_from_thrus_to $from $thrus $to
|
|
|
|
|
} else {
|
2020-04-25 04:53:22 +02:00
|
|
|
check_for_key_args $cmd args
|
|
|
|
|
if { [llength $args] == 0 } {
|
|
|
|
|
delete_from_thrus_to $from $thrus $to
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 568 "missing delay argument."
|
2020-04-25 04:53:22 +02:00
|
|
|
} elseif { [llength $args] == 1 } {
|
|
|
|
|
set delay $args
|
|
|
|
|
check_float "$cmd delay" $delay
|
|
|
|
|
set delay [time_ui_sta $delay]
|
|
|
|
|
} else {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 355 "'$args' ignored."
|
2020-04-25 04:53:22 +02:00
|
|
|
}
|
2020-04-26 17:49:09 +02:00
|
|
|
|
2020-04-25 04:53:22 +02:00
|
|
|
set ignore_clk_latency [info exists flags(-ignore_clock_latency)]
|
2020-04-26 17:49:09 +02:00
|
|
|
|
2020-04-25 04:53:22 +02:00
|
|
|
if [info exists flags(-reset_path)] {
|
|
|
|
|
reset_path_cmd $from $thrus $to "all"
|
|
|
|
|
}
|
2020-04-26 17:49:09 +02:00
|
|
|
|
2020-04-25 04:53:22 +02:00
|
|
|
set comment [parse_comment_key keys]
|
2020-04-26 17:49:09 +02:00
|
|
|
|
2020-04-25 04:53:22 +02:00
|
|
|
make_path_delay $from $thrus $to $min_max $ignore_clk_latency \
|
|
|
|
|
$delay $comment
|
|
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_max_time_borrow" {limit objects}
|
|
|
|
|
|
|
|
|
|
proc set_max_time_borrow { limit objects } {
|
|
|
|
|
check_positive_float "borrow_limit" $limit
|
|
|
|
|
set limit [time_ui_sta $limit]
|
|
|
|
|
parse_clk_inst_pin_arg $objects clks insts pins
|
|
|
|
|
foreach pin $pins {
|
|
|
|
|
set_latch_borrow_limit_pin $pin $limit
|
|
|
|
|
}
|
|
|
|
|
foreach inst $insts {
|
|
|
|
|
set_latch_borrow_limit_inst $inst $limit
|
|
|
|
|
}
|
|
|
|
|
foreach clk $clks {
|
|
|
|
|
set_latch_borrow_limit_clk $clk $limit
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_min_delay" \
|
|
|
|
|
{[-rise] [-fall] [-ignore_clock_latency] [-reset_path] [-comment comment]\
|
|
|
|
|
[-from from_list] [-rise_from from_list] [-fall_from from_list]\
|
|
|
|
|
[-through through_list] [-rise_through through_list]\
|
|
|
|
|
[-fall_through through_list]\
|
|
|
|
|
[-to to_list] [-rise_to to_list] [-fall_to to_list] delay}
|
|
|
|
|
|
|
|
|
|
proc set_min_delay { args } {
|
|
|
|
|
set_path_delay "set_min_delay" $args min
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_min_pulse_width" {[-low] [-high] value [objects]}
|
|
|
|
|
|
|
|
|
|
proc set_min_pulse_width { args } {
|
|
|
|
|
parse_key_args "set_min_pulse_width" args keys {} flags {-low -high}
|
|
|
|
|
check_argc_eq1or2 "set_min_pulse_width" $args
|
|
|
|
|
|
|
|
|
|
if { [info exists flags(-low)] } {
|
|
|
|
|
set hi_low "fall"
|
|
|
|
|
} elseif { [info exists flags(-high)] } {
|
|
|
|
|
set hi_low "rise"
|
|
|
|
|
} else {
|
|
|
|
|
set hi_low "rise_fall"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set min_width [lindex $args 0]
|
|
|
|
|
check_positive_float "min pulse width" $min_width
|
|
|
|
|
set min_width [time_ui_sta $min_width]
|
|
|
|
|
|
|
|
|
|
if { [llength $args] == 2 } {
|
|
|
|
|
set objects [lindex $args 1]
|
|
|
|
|
parse_clk_inst_pin_arg $objects clks insts pins
|
|
|
|
|
foreach pin $pins {
|
|
|
|
|
set_min_pulse_width_pin $pin $hi_low $min_width
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
foreach inst $insts {
|
|
|
|
|
set_min_pulse_width_inst $inst $hi_low $min_width
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
foreach clk $clks {
|
|
|
|
|
set_min_pulse_width_clk $clk $hi_low $min_width
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
|
|
|
|
set_min_pulse_width_global $hi_low $min_width
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_multicycle_path" \
|
|
|
|
|
{[-setup] [-hold] [-rise] [-fall] [-start] [-end]\
|
|
|
|
|
[-reset_path] [-comment comment]\
|
|
|
|
|
[-from from_list] [-rise_from from_list]\
|
|
|
|
|
[-fall_from from_list] [-through through_list]\
|
|
|
|
|
[-rise_through through_list] [-fall_through through_list]\
|
|
|
|
|
[-to to_list] [-rise_to to_list] [-fall_to to_list] path_multiplier}
|
|
|
|
|
|
|
|
|
|
proc set_multicycle_path { args } {
|
|
|
|
|
parse_key_args "set_multicycle_path" args \
|
|
|
|
|
keys {-from -rise_from -fall_from -to -rise_to -fall_to -comment} \
|
|
|
|
|
flags {-setup -hold -rise -fall -start -end -reset_path} 0
|
|
|
|
|
|
|
|
|
|
set min_max "min_max"
|
|
|
|
|
set use_end_clk 1
|
|
|
|
|
if { [info exists flags(-setup)] && ![info exists flags(-hold)] } {
|
|
|
|
|
# -setup
|
|
|
|
|
set min_max "max"
|
|
|
|
|
set use_end_clk 1
|
|
|
|
|
}
|
|
|
|
|
if { [info exists flags(-hold)] && ![info exists flags(-setup)] } {
|
|
|
|
|
# -hold
|
|
|
|
|
set min_max "min"
|
|
|
|
|
set use_end_clk 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set cmd "set_multicycle_path"
|
|
|
|
|
set arg_error 0
|
|
|
|
|
set from [parse_from_arg keys arg_error]
|
|
|
|
|
set thrus [parse_thrus_arg args arg_error]
|
|
|
|
|
set to [parse_to_arg keys flags arg_error]
|
|
|
|
|
check_exception_pins $from $to
|
|
|
|
|
if { $arg_error } {
|
|
|
|
|
delete_from_thrus_to $from $thrus $to
|
|
|
|
|
} else {
|
2020-04-25 04:53:22 +02:00
|
|
|
check_for_key_args $cmd args
|
|
|
|
|
if { [llength $args] == 0 } {
|
|
|
|
|
delete_from_thrus_to $from $thrus $to
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 569 "missing path multiplier argument."
|
2020-04-25 04:53:22 +02:00
|
|
|
} elseif { [llength $args] == 1 } {
|
|
|
|
|
set path_multiplier $args
|
|
|
|
|
check_integer "path multiplier" $path_multiplier
|
|
|
|
|
} else {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 356 "'$args' ignored."
|
2020-04-25 04:53:22 +02:00
|
|
|
}
|
2020-04-26 17:49:09 +02:00
|
|
|
|
2020-04-25 04:53:22 +02:00
|
|
|
set start [info exists flags(-start)]
|
|
|
|
|
set end [info exists flags(-end)]
|
|
|
|
|
if { $start && $end } {
|
|
|
|
|
delete_from_thrus_to $from $thrus $to
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 570 "cannot use -start with -end."
|
2020-04-25 04:53:22 +02:00
|
|
|
} elseif { $start } {
|
|
|
|
|
set use_end_clk 0
|
|
|
|
|
} elseif { $end } {
|
|
|
|
|
set use_end_clk 1
|
|
|
|
|
}
|
2020-04-26 17:49:09 +02:00
|
|
|
|
2020-04-25 04:53:22 +02:00
|
|
|
if [info exists flags(-reset_path)] {
|
|
|
|
|
reset_path_cmd $from $thrus $to $min_max
|
|
|
|
|
}
|
2020-04-26 17:49:09 +02:00
|
|
|
|
2020-04-25 04:53:22 +02:00
|
|
|
set comment [parse_comment_key keys]
|
2020-04-26 17:49:09 +02:00
|
|
|
|
2020-04-25 04:53:22 +02:00
|
|
|
make_multicycle_path $from $thrus $to $min_max $use_end_clk \
|
|
|
|
|
$path_multiplier $comment
|
|
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_output_delay" \
|
|
|
|
|
{[-rise] [-fall] [-max] [-min]\
|
|
|
|
|
[-clock clock] [-clock_fall]\
|
|
|
|
|
[-reference_pin ref_pin]\
|
|
|
|
|
[-source_latency_included] [-network_latency_included]\
|
|
|
|
|
[-add_delay] delay port_pin_list}
|
|
|
|
|
|
|
|
|
|
proc set_output_delay { args } {
|
|
|
|
|
set_port_delay "set_output_delay" "set_output_delay_cmd" $args \
|
|
|
|
|
{"output" "tristate" "bidirect"}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_propagated_clock" {objects}
|
|
|
|
|
|
|
|
|
|
proc set_propagated_clock { objects } {
|
|
|
|
|
parse_clk_port_pin_arg $objects clks pins
|
|
|
|
|
foreach clk $clks {
|
|
|
|
|
if { [$clk is_virtual] } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 357 "virtual clock [get_name $clk] can not be propagated."
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
|
|
|
|
set_propagated_clock_cmd $clk
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
foreach pin $pins {
|
|
|
|
|
set_propagated_clock_pin_cmd $pin
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
#
|
|
|
|
|
# Environment Commands
|
|
|
|
|
#
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_case_analysis" \
|
|
|
|
|
{0|1|zero|one|rise|rising|fall|falling pins}
|
|
|
|
|
|
|
|
|
|
proc set_case_analysis { value pins } {
|
|
|
|
|
if { !($value == "0" \
|
|
|
|
|
|| $value == "1" \
|
|
|
|
|
|| $value == "zero" \
|
|
|
|
|
|| $value == "one" \
|
|
|
|
|
|| $value == "rise" \
|
|
|
|
|
|| $value == "rising" \
|
|
|
|
|
|| $value == "fall" \
|
|
|
|
|
|| $value == "falling") } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 571 "value must be 0, zero, 1, one, rise, rising, fall, or falling."
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
set pins1 [get_port_pins_error "pins" $pins]
|
|
|
|
|
foreach pin $pins1 {
|
|
|
|
|
set_case_analysis_cmd $pin $value
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_drive" {[-rise] [-fall] [-min] [-max] \
|
|
|
|
|
resistance ports}
|
|
|
|
|
|
|
|
|
|
proc set_drive { args } {
|
|
|
|
|
parse_key_args "set_drive" args keys {} flags {-rise -fall -min -max}
|
|
|
|
|
set tr [parse_rise_fall_flags flags]
|
|
|
|
|
set min_max [parse_min_max_all_check_flags flags]
|
|
|
|
|
|
|
|
|
|
check_argc_eq2 "set_drive" $args
|
|
|
|
|
|
|
|
|
|
set res [lindex $args 0]
|
|
|
|
|
check_positive_float "resistance" $res
|
|
|
|
|
set res [resistance_ui_sta $res]
|
|
|
|
|
set ports [get_ports_error "ports" [lindex $args 1]]
|
|
|
|
|
foreach port $ports {
|
|
|
|
|
set_drive_resistance_cmd $port $tr $min_max $res
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_driving_cell" \
|
|
|
|
|
{[-lib_cell cell] [-library library]\
|
|
|
|
|
[-rise] [-fall] [-min] [-max]\
|
|
|
|
|
[-pin pin] [-from_pin from_pin]\
|
|
|
|
|
[-input_transition_rise trans_rise] [-input_transition_fall trans_fall]\
|
|
|
|
|
[-multiply_by factor] [-dont_scale] [-no_design_rule] ports}
|
|
|
|
|
|
|
|
|
|
proc set_driving_cell { args } {
|
|
|
|
|
parse_key_args "set_driving_cell" args \
|
|
|
|
|
keys {-lib_cell -cell -library -pin -from_pin -multiply_by \
|
|
|
|
|
-input_transition_rise -input_transition_fall} \
|
|
|
|
|
flags {-rise -fall -min -max -dont_scale -no_design_rule}
|
|
|
|
|
|
|
|
|
|
set tr [parse_rise_fall_flags flags]
|
|
|
|
|
set min_max [parse_min_max_all_flags flags]
|
|
|
|
|
|
|
|
|
|
# -cell is an undocumented non-sdc alias for -lib_cell.
|
|
|
|
|
if { [info exists keys(-cell)] } {
|
|
|
|
|
set keys(-lib_cell) $keys(-cell)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if { [info exists keys(-lib_cell)] } {
|
|
|
|
|
set cell_name $keys(-lib_cell)
|
|
|
|
|
if { [info exists keys(-library)] } {
|
|
|
|
|
set library [get_liberty_error "library" $keys(-library)]
|
|
|
|
|
set cell [$library find_liberty_cell $cell_name]
|
|
|
|
|
if { $cell == "NULL" } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 572 "cell '$lib_name:$cell_name' not found."
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
|
|
|
|
set library "NULL"
|
|
|
|
|
set cell [find_liberty_cell $cell_name]
|
|
|
|
|
if { $cell == "NULL" } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 573 "'$cell_name' not found."
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 574 "missing -lib_cell argument."
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set to_port "NULL"
|
|
|
|
|
if [info exists keys(-pin)] {
|
|
|
|
|
set to_port_name $keys(-pin)
|
|
|
|
|
set to_port [$cell find_liberty_port $to_port_name]
|
|
|
|
|
if { $to_port == "NULL" } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 575 "port '$to_port_name' not found."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
|
|
|
|
set port_iter [$cell liberty_port_iterator]
|
|
|
|
|
set output_count 0
|
|
|
|
|
while {[$port_iter has_next]} {
|
|
|
|
|
set port [$port_iter next]
|
|
|
|
|
set dir [liberty_port_direction $port]
|
|
|
|
|
if { [port_direction_any_output $dir] } {
|
|
|
|
|
incr output_count
|
|
|
|
|
if { $output_count > 1 } {
|
|
|
|
|
$port_iter finish
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 576 "-pin argument required for cells with multiple outputs."
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
set to_port $port
|
|
|
|
|
# No break. Keep looking for output ports to make sure there
|
|
|
|
|
# is only one.
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
$port_iter finish
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set from_port "NULL"
|
|
|
|
|
if [info exists keys(-from_pin)] {
|
|
|
|
|
set from_port_name $keys(-from_pin)
|
|
|
|
|
set from_port [$cell find_liberty_port $from_port_name]
|
|
|
|
|
if { $from_port == "NULL" } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 577 "port '$from_port_name' not found."
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set from_slew_rise 0
|
|
|
|
|
if [info exists keys(-input_transition_rise)] {
|
|
|
|
|
set from_slew_rise $keys(-input_transition_rise)
|
|
|
|
|
check_positive_float "-input_transition_rise" $from_slew_rise
|
|
|
|
|
set from_slew_rise [time_ui_sta $from_slew_rise]
|
|
|
|
|
}
|
|
|
|
|
set from_slew_fall 0
|
|
|
|
|
if [info exists keys(-input_transition_fall)] {
|
|
|
|
|
set from_slew_fall $keys(-input_transition_fall)
|
|
|
|
|
check_positive_float "-input_transition_fall" $from_slew_fall
|
|
|
|
|
set from_slew_fall [time_ui_sta $from_slew_fall]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if [info exists keys(-multiply_by)] {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 358 "-multiply_by ignored."
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
if [info exists flags(-dont_scale)] {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 359 "-dont_scale ignored."
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
if [info exists flags(-no_design_rule)] {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 360 "-no_design_rule ignored."
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
check_argc_eq1 "set_driving_cell" $args
|
|
|
|
|
|
|
|
|
|
set ports [get_ports_error "ports" [lindex $args 0]]
|
|
|
|
|
foreach port $ports {
|
|
|
|
|
set_drive_cell_cmd $library $cell $port $from_port \
|
|
|
|
|
$from_slew_rise $from_slew_fall $to_port $tr $min_max
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_fanout_load" {fanout ports}
|
|
|
|
|
|
|
|
|
|
proc set_fanout_load { fanout port_list } {
|
2020-12-20 19:21:50 +01:00
|
|
|
sta_warn 601 "set_fanout_load not supported."
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_input_transition" \
|
|
|
|
|
{[-rise] [-fall] [-min] [-max] transition ports}
|
|
|
|
|
|
|
|
|
|
proc set_input_transition { args } {
|
|
|
|
|
parse_key_args "set_input_transition" args keys {-clock -clock_fall} \
|
|
|
|
|
flags {-rise -fall -max -min}
|
|
|
|
|
|
|
|
|
|
set tr [parse_rise_fall_flags flags]
|
|
|
|
|
set min_max [parse_min_max_all_flags flags]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
check_argc_eq2 "set_input_transition" $args
|
|
|
|
|
|
|
|
|
|
set slew [lindex $args 0]
|
|
|
|
|
check_positive_float "transition" $slew
|
|
|
|
|
set slew [time_ui_sta $slew]
|
|
|
|
|
set ports [get_ports_error "ports" [lindex $args 1]]
|
|
|
|
|
|
|
|
|
|
if [info exists keys(-clock)] {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 361 "-clock not supported."
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
if [info exists keys(-clock_fall)] {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 362 "-clock_fall not supported."
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach port $ports {
|
|
|
|
|
set_input_slew_cmd $port $tr $min_max $slew
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_load" \
|
|
|
|
|
{[-rise] [-fall] [-max] [-min] [-subtract_pin_load]\
|
|
|
|
|
[-pin_load] [-wire_load] capacitance objects}
|
|
|
|
|
|
|
|
|
|
proc set_load { args } {
|
|
|
|
|
parse_key_args "set_load" args keys {-corner} \
|
|
|
|
|
flags {-rise -fall -min -max -subtract_pin_load -pin_load -wire_load}\
|
2019-06-24 06:38:01 +02:00
|
|
|
|
2019-06-27 00:58:23 +02:00
|
|
|
check_argc_eq2 "set_load" $args
|
|
|
|
|
|
|
|
|
|
set pin_load [info exists flags(-pin_load)]
|
|
|
|
|
set wire_load [info exists flags(-wire_load)]
|
|
|
|
|
set subtract_pin_load [info exists flags(-subtract_pin_load)]
|
2021-03-30 18:27:32 +02:00
|
|
|
set corner [parse_corner_or_all keys]
|
2019-06-27 00:58:23 +02:00
|
|
|
set min_max [parse_min_max_all_check_flags flags]
|
|
|
|
|
set tr [parse_rise_fall_flags flags]
|
|
|
|
|
|
|
|
|
|
set cap [lindex $args 0]
|
|
|
|
|
check_positive_float "capacitance" $cap
|
|
|
|
|
set cap [capacitance_ui_sta $cap]
|
|
|
|
|
parse_port_net_args [lindex $args 1] ports nets
|
|
|
|
|
|
|
|
|
|
if { $ports != {} } {
|
|
|
|
|
# -pin_load is the default.
|
|
|
|
|
if { $pin_load || (!$pin_load && !$wire_load) } {
|
|
|
|
|
foreach port $ports {
|
|
|
|
|
set_port_pin_cap $port $tr $min_max $cap
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
} elseif { $wire_load } {
|
|
|
|
|
foreach port $ports {
|
|
|
|
|
set_port_wire_cap $port $subtract_pin_load $tr $min_max $cap
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
if { $nets != {} } {
|
|
|
|
|
if { $pin_load } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 363 "-pin_load not allowed for net objects."
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
if { $wire_load } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 364 "-wire_load not allowed for net objects."
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
if { $tr != "rise_fall" } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 365 "-rise/-fall not allowed for net objects."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
foreach net $nets {
|
|
|
|
|
set_net_wire_cap $net $subtract_pin_load $corner $min_max $cap
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_logic_dc" {port_list}
|
|
|
|
|
|
|
|
|
|
proc set_logic_dc { port_list } {
|
|
|
|
|
set_logic_value $port_list "X"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# OT supports set_logic cmds on pins.
|
|
|
|
|
# OC only supports them on ports.
|
|
|
|
|
proc set_logic_value { port_list value } {
|
|
|
|
|
set pins [get_port_pins_error "pins" $port_list]
|
|
|
|
|
foreach pin $pins {
|
|
|
|
|
set_logic_value_cmd $pin $value
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_logic_one" {port_list}
|
|
|
|
|
|
|
|
|
|
proc set_logic_one { port_list } {
|
|
|
|
|
set_logic_value $port_list "1"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_logic_zero" {port_list}
|
|
|
|
|
|
|
|
|
|
proc set_logic_zero { port_list } {
|
|
|
|
|
set_logic_value $port_list "0"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_max_area" {area}
|
|
|
|
|
|
|
|
|
|
proc set_max_area { area } {
|
|
|
|
|
check_positive_float "area" $area
|
|
|
|
|
set_max_area_cmd $area
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_max_capacitance" {cap objects}
|
|
|
|
|
|
|
|
|
|
proc set_max_capacitance { cap objects } {
|
|
|
|
|
set_capacitance_limit $cap "max" $objects
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc set_capacitance_limit { cap min_max objects } {
|
|
|
|
|
parse_cell_port_pin_args $objects cells ports pins
|
|
|
|
|
check_positive_float "limit" $cap
|
|
|
|
|
set cap [capacitance_ui_sta $cap]
|
|
|
|
|
foreach cell $cells {
|
|
|
|
|
set_cell_capacitance_limit $cell $min_max $cap
|
|
|
|
|
}
|
|
|
|
|
foreach port $ports {
|
|
|
|
|
set_port_capacitance_limit $port $min_max $cap
|
|
|
|
|
}
|
|
|
|
|
foreach pin $pins {
|
|
|
|
|
set_pin_capacitance_limit $pin $min_max $cap
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_max_fanout" {fanout objects}
|
|
|
|
|
|
|
|
|
|
proc set_max_fanout { fanout objects } {
|
|
|
|
|
set_fanout_limit $fanout "max" $objects
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc set_fanout_limit { fanout min_max objects } {
|
|
|
|
|
check_positive_float "limit" $fanout
|
|
|
|
|
parse_cell_port_args $objects cells ports
|
|
|
|
|
foreach port $ports {
|
|
|
|
|
set dir [port_direction $port]
|
|
|
|
|
if { !($dir == "input" || $dir == "bidirect") } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 578 "port '[get_name $port]' is not an input."
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
set_port_fanout_limit $port $min_max $fanout
|
|
|
|
|
}
|
|
|
|
|
foreach cell $cells {
|
|
|
|
|
set_cell_fanout_limit $cell $min_max $fanout
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_max_transition" \
|
|
|
|
|
{[-clock_path] [-data_path] [-rise] [-fall] slew objects}
|
|
|
|
|
|
|
|
|
|
proc set_max_transition { args } {
|
|
|
|
|
parse_key_args "set_max_transition" args keys {} \
|
|
|
|
|
flags {-clock_path -data_path -rise -fall}
|
|
|
|
|
check_argc_eq2 "set_max_transition" $args
|
|
|
|
|
|
|
|
|
|
set slew [lindex $args 0]
|
|
|
|
|
check_positive_float "transition" $slew
|
|
|
|
|
set slew [time_ui_sta $slew]
|
|
|
|
|
|
|
|
|
|
set objects [lindex $args 1]
|
2020-06-09 02:16:15 +02:00
|
|
|
parse_clk_cell_port_args $objects clks cells ports
|
2019-06-27 00:58:23 +02:00
|
|
|
|
|
|
|
|
set tr [parse_rise_fall_flags flags]
|
|
|
|
|
|
|
|
|
|
set path_types {}
|
|
|
|
|
if { ![info exists flags(-clock_path)] \
|
|
|
|
|
&& ![info exists flags(-data_path)] } {
|
|
|
|
|
# Derate clk and data if neither -clock_path or -data_path.
|
|
|
|
|
set path_types {"clk" "data"}
|
|
|
|
|
}
|
|
|
|
|
if { [info exists flags(-clock_path)] } {
|
|
|
|
|
lappend path_types "clk"
|
|
|
|
|
}
|
|
|
|
|
if { [info exists flags(-data_path)] } {
|
|
|
|
|
lappend path_types "data"
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-09 02:16:15 +02:00
|
|
|
if { ($ports != {} || $cells != {}) \
|
2019-06-27 00:58:23 +02:00
|
|
|
&& ([info exists flags(-clock_path)] \
|
|
|
|
|
|| [info exists flags(-data_path)]
|
|
|
|
|
|| [info exists flags(-rise)]
|
|
|
|
|
|| [info exists flags(-fall)]) } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 366 "-data_path, -clock_path, -rise, -fall ignored for ports and designs."
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# -clock_path/-data_path and transition only apply to clock objects.
|
|
|
|
|
foreach path_type $path_types {
|
|
|
|
|
foreach clk $clks {
|
|
|
|
|
set_slew_limit_clk $clk $tr $path_type "max" $slew
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
foreach cell $cells {
|
|
|
|
|
set_slew_limit_cell $cell "max" $slew
|
|
|
|
|
}
|
|
|
|
|
foreach port $ports {
|
|
|
|
|
set_slew_limit_port $port "max" $slew
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_port_fanout_number" \
|
|
|
|
|
{[-max] [-min] fanout ports}
|
|
|
|
|
|
|
|
|
|
proc set_port_fanout_number { args } {
|
|
|
|
|
parse_key_args "set_port_fanout_number" args keys {} flags {-max -min}
|
|
|
|
|
set min_max [parse_min_max_all_check_flags flags]
|
|
|
|
|
|
|
|
|
|
check_argc_eq2 "set_port_fanout_number" $args
|
|
|
|
|
|
|
|
|
|
set fanout [lindex $args 0]
|
|
|
|
|
check_positive_integer "fanout" $fanout
|
|
|
|
|
set ports [get_ports_error "ports" [lindex $args 1]]
|
|
|
|
|
foreach port $ports {
|
|
|
|
|
set_port_ext_fanout_cmd $port $fanout $min_max
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_resistance" {[-min] [-max] resistance nets}
|
|
|
|
|
|
|
|
|
|
proc set_resistance { args } {
|
|
|
|
|
parse_key_args "set_resistance" args keys {} flags {-max -min}
|
|
|
|
|
set min_max [parse_min_max_all_check_flags flags]
|
|
|
|
|
|
|
|
|
|
check_argc_eq2 "set_resistance" $args
|
|
|
|
|
|
|
|
|
|
set res [lindex $args 0]
|
|
|
|
|
check_positive_float "resistance" $res
|
|
|
|
|
set res [resistance_ui_sta $res]
|
|
|
|
|
set nets [get_nets_error "nets" [lindex $args 1]]
|
|
|
|
|
foreach net $nets {
|
|
|
|
|
set_net_resistance $net $min_max $res
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_timing_derate" \
|
|
|
|
|
{-early|-late [-rise] [-fall] [-clock] [-data] \
|
|
|
|
|
[-net_delay] [-cell_delay] [-cell_check] derate [objects]}
|
|
|
|
|
|
|
|
|
|
proc set_timing_derate { args } {
|
|
|
|
|
parse_key_args "set_timing_derate" args keys {} \
|
|
|
|
|
flags {-rise -fall -early -late -clock -data \
|
|
|
|
|
-net_delay -cell_delay -cell_check}
|
|
|
|
|
check_argc_eq1or2 "set_timing_derate" $args
|
|
|
|
|
|
|
|
|
|
set derate [lindex $args 0]
|
|
|
|
|
check_float "derate" $derate
|
|
|
|
|
if { $derate > 2.0 } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 367 "derating factor greater than 2.0."
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set tr [parse_rise_fall_flags flags]
|
|
|
|
|
set early_late [parse_early_late_flags flags]
|
|
|
|
|
|
|
|
|
|
set path_types {}
|
|
|
|
|
if { ![info exists flags(-clock)] \
|
|
|
|
|
&& ![info exists flags(-data)] } {
|
|
|
|
|
# Derate clk and data if neither -clock or -data.
|
|
|
|
|
lappend path_types "clk"
|
|
|
|
|
lappend path_types "data"
|
|
|
|
|
}
|
|
|
|
|
if { [info exists flags(-clock)] } {
|
|
|
|
|
lappend path_types "clk"
|
|
|
|
|
}
|
|
|
|
|
if { [info exists flags(-data)] } {
|
|
|
|
|
lappend path_types "data"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set derate_types {}
|
|
|
|
|
if { [info exists flags(-net_delay)] } {
|
|
|
|
|
lappend derate_types "net_delay"
|
|
|
|
|
}
|
|
|
|
|
if { [info exists flags(-cell_delay)] } {
|
|
|
|
|
lappend derate_types "cell_delay"
|
|
|
|
|
}
|
|
|
|
|
if { [info exists flags(-cell_check)] } {
|
|
|
|
|
lappend derate_types "cell_check"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if { [llength $args] == 2 } {
|
|
|
|
|
set objects [lindex $args 1]
|
|
|
|
|
parse_libcell_inst_net_arg $objects libcells insts nets
|
|
|
|
|
if { $nets != {} } {
|
|
|
|
|
if { [info exists flags(-cell_delay)] \
|
|
|
|
|
|| [info exists flags(-cell_check)] } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 368 "-cell_delay and -cell_check flags ignored for net objects."
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
foreach net $nets {
|
|
|
|
|
foreach path_type $path_types {
|
|
|
|
|
set_timing_derate_net_cmd $net $path_type $tr $early_late $derate
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
if { ![info exists flags(-cell_delay)] \
|
|
|
|
|
&& ![info exists flags(-cell_check)] } {
|
|
|
|
|
# Cell checks are not derated if no flags are specified.
|
|
|
|
|
set derate_types {cell_delay}
|
|
|
|
|
}
|
|
|
|
|
foreach derate_type $derate_types {
|
|
|
|
|
foreach path_type $path_types {
|
|
|
|
|
foreach inst $insts {
|
|
|
|
|
set_timing_derate_inst_cmd $inst $derate_type $path_type \
|
|
|
|
|
$tr $early_late $derate
|
|
|
|
|
}
|
|
|
|
|
foreach libcell $libcells {
|
|
|
|
|
set_timing_derate_cell_cmd $libcell $derate_type $path_type \
|
|
|
|
|
$tr $early_late $derate
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
|
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
|
|
|
|
if { ![info exists flags(-net_delay)] \
|
|
|
|
|
&& ![info exists flags(-cell_delay)] \
|
|
|
|
|
&& ![info exists flags(-cell_check)] } {
|
|
|
|
|
# Cell checks are not derated if no flags are specified.
|
|
|
|
|
set derate_types {net_delay cell_delay}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
foreach derate_type $derate_types {
|
|
|
|
|
foreach path_type $path_types {
|
|
|
|
|
set_timing_derate_cmd $derate_type $path_type $tr $early_late $derate
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc parse_from_arg { keys_var arg_error_var } {
|
|
|
|
|
upvar 1 $keys_var keys
|
|
|
|
|
|
|
|
|
|
if [info exists keys(-from)] {
|
|
|
|
|
set key "-from"
|
|
|
|
|
set tr "rise_fall"
|
|
|
|
|
} elseif [info exists keys(-rise_from)] {
|
|
|
|
|
set key "-rise_from"
|
|
|
|
|
set tr "rise"
|
|
|
|
|
} elseif [info exists keys(-fall_from)] {
|
|
|
|
|
set key "-fall_from"
|
|
|
|
|
set tr "fall"
|
|
|
|
|
} else {
|
|
|
|
|
return "NULL"
|
|
|
|
|
}
|
|
|
|
|
parse_clk_inst_port_pin_arg $keys($key) from_clks from_insts from_pins
|
|
|
|
|
if {$from_pins == {} && $from_insts == {} && $from_clks == {}} {
|
|
|
|
|
upvar 1 $arg_error_var arg_error
|
|
|
|
|
set arg_error 1
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 369 "no valid objects specified for $key."
|
2019-06-27 00:58:23 +02:00
|
|
|
return "NULL"
|
|
|
|
|
}
|
|
|
|
|
return [make_exception_from $from_pins $from_clks $from_insts $tr]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# "arg_error" is set to notify the caller to cleanup and post error.
|
|
|
|
|
proc parse_thrus_arg { args_var arg_error_var } {
|
|
|
|
|
upvar 1 $args_var args
|
|
|
|
|
|
|
|
|
|
set thrus {}
|
|
|
|
|
set args_rtn {}
|
|
|
|
|
while { $args != {} } {
|
|
|
|
|
set arg [lindex $args 0]
|
|
|
|
|
set tr ""
|
|
|
|
|
if { $arg == "-through" } {
|
|
|
|
|
set tr "rise_fall"
|
2020-04-25 04:53:22 +02:00
|
|
|
set key "-through"
|
2019-06-27 00:58:23 +02:00
|
|
|
} elseif { $arg == "-rise_through" } {
|
|
|
|
|
set tr "rise"
|
2020-04-25 04:53:22 +02:00
|
|
|
set key "-rise_through"
|
2019-06-27 00:58:23 +02:00
|
|
|
} elseif { $arg == "-fall_through" } {
|
|
|
|
|
set tr "fall"
|
2020-04-25 04:53:22 +02:00
|
|
|
set key "-fall_through"
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
if { $tr != "" } {
|
|
|
|
|
if { [llength $args] > 1 } {
|
|
|
|
|
set args [lrange $args 1 end]
|
|
|
|
|
set arg [lindex $args 0]
|
|
|
|
|
parse_inst_port_pin_net_arg $arg insts pins nets
|
|
|
|
|
if {$pins == {} && $insts == {} && $nets == {}} {
|
|
|
|
|
upvar 1 $arg_error_var arg_error
|
|
|
|
|
set arg_error 1
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 370 "no valid objects specified for $key"
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
|
|
|
|
lappend thrus [make_exception_thru $pins $nets $insts $tr]
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
|
|
|
|
lappend args_rtn $arg
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
set args [lrange $args 1 end]
|
|
|
|
|
}
|
|
|
|
|
set args $args_rtn
|
|
|
|
|
return $thrus
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Parse -to|-rise_to|-fall_to keywords.
|
|
|
|
|
proc parse_to_arg { keys_var flags_var arg_error_var } {
|
|
|
|
|
upvar 1 $keys_var keys
|
|
|
|
|
upvar 1 $flags_var flags
|
|
|
|
|
upvar 1 $arg_error_var arg_error
|
|
|
|
|
|
2019-11-11 23:30:19 +01:00
|
|
|
set end_rf [parse_rise_fall_flags flags]
|
|
|
|
|
return [parse_to_arg1 keys $end_rf arg_error]
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
|
2019-11-11 23:30:19 +01:00
|
|
|
proc parse_to_arg1 { keys_var end_rf arg_error_var } {
|
2019-06-27 00:58:23 +02:00
|
|
|
upvar 1 $keys_var keys
|
|
|
|
|
upvar 1 $arg_error_var arg_error
|
|
|
|
|
|
|
|
|
|
if [info exists keys(-to)] {
|
|
|
|
|
set key "-to"
|
2019-11-11 23:30:19 +01:00
|
|
|
set to_rf "rise_fall"
|
2019-06-27 00:58:23 +02:00
|
|
|
} elseif [info exists keys(-rise_to)] {
|
|
|
|
|
set key "-rise_to"
|
2019-11-11 23:30:19 +01:00
|
|
|
set to_rf "rise"
|
2019-06-27 00:58:23 +02:00
|
|
|
} elseif [info exists keys(-fall_to)] {
|
|
|
|
|
set key "-fall_to"
|
2019-11-11 23:30:19 +01:00
|
|
|
set to_rf "fall"
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
|
|
|
|
# -rise/-fall without -to/-rise_to/-fall_to (no objects).
|
2019-11-11 23:30:19 +01:00
|
|
|
if { $end_rf != "rise_fall" } {
|
|
|
|
|
return [make_exception_to {} {} {} "rise_fall" $end_rf]
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
|
|
|
|
return "NULL"
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
parse_clk_inst_port_pin_arg $keys($key) to_clks to_insts to_pins
|
|
|
|
|
if {$to_pins == {} && $to_insts == {} && $to_clks == {}} {
|
|
|
|
|
upvar 1 $arg_error_var arg_error
|
|
|
|
|
set arg_error 1
|
2020-12-20 19:21:50 +01:00
|
|
|
sta_warn 602 "no valid objects specified for $key."
|
2019-06-27 00:58:23 +02:00
|
|
|
return "NULL"
|
|
|
|
|
}
|
2019-11-11 23:30:19 +01:00
|
|
|
return [make_exception_to $to_pins $to_clks $to_insts $to_rf $end_rf]
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc delete_from_thrus_to { from thrus to } {
|
|
|
|
|
if { $from != "NULL" } {
|
|
|
|
|
delete_exception_from $from
|
|
|
|
|
}
|
|
|
|
|
if { $thrus != {} } {
|
|
|
|
|
foreach thru $thrus {
|
|
|
|
|
delete_exception_thru $thru
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
if { $to != "NULL" } {
|
|
|
|
|
delete_exception_to $to
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc parse_comment_key { keys_var } {
|
|
|
|
|
upvar 1 $keys_var keys
|
|
|
|
|
|
|
|
|
|
set comment ""
|
|
|
|
|
if { [info exists keys(-comment)] } {
|
|
|
|
|
set comment $keys(-comment)
|
|
|
|
|
}
|
|
|
|
|
return $comment
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_min_capacitance" {cap objects}
|
|
|
|
|
|
|
|
|
|
proc set_min_capacitance { cap objects } {
|
|
|
|
|
set_capacitance_limit $cap "min" $objects
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_operating_conditions" \
|
|
|
|
|
{[-analysis_type single|bc_wc|on_chip_variation] [-library lib]\
|
|
|
|
|
[condition] [-min min_condition] [-max max_condition]\
|
|
|
|
|
[-min_library min_lib] [-max_library max_lib]}
|
|
|
|
|
|
|
|
|
|
proc set_operating_conditions { args } {
|
|
|
|
|
parse_key_args "set_operating_conditions" args \
|
|
|
|
|
keys {-analysis_type -library -min -max -min_library -max_library} flags {}
|
|
|
|
|
parse_op_cond_analysis_type keys
|
|
|
|
|
check_argc_eq0or1 set_operating_conditions $args
|
|
|
|
|
if { [llength $args] == 1 } {
|
|
|
|
|
set op_cond_name $args
|
|
|
|
|
parse_op_cond $op_cond_name "-library" "all" keys
|
|
|
|
|
}
|
|
|
|
|
if [info exists keys(-min)] {
|
|
|
|
|
parse_op_cond $keys(-min) "-min_library" "min" keys
|
|
|
|
|
}
|
|
|
|
|
if [info exists keys(-max)] {
|
|
|
|
|
parse_op_cond $keys(-max) "-max_library" "max" keys
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc parse_op_cond { op_cond_name lib_key min_max key_var } {
|
|
|
|
|
upvar 1 $key_var keys
|
|
|
|
|
if [info exists keys($lib_key)] {
|
|
|
|
|
set liberty [get_liberty_error $lib_key $keys($lib_key)]
|
|
|
|
|
set op_cond [$liberty find_operating_conditions $op_cond_name]
|
|
|
|
|
if { $op_cond == "NULL" } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 579 "operating condition '$op_cond_name' not found."
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
|
|
|
|
set_operating_conditions_cmd $op_cond $min_max
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
} else {
|
|
|
|
|
set found 0
|
|
|
|
|
set lib_iter [liberty_library_iterator]
|
|
|
|
|
while {[$lib_iter has_next]} {
|
|
|
|
|
set lib [$lib_iter next]
|
|
|
|
|
set op_cond [$lib find_operating_conditions $op_cond_name]
|
|
|
|
|
if { $op_cond != "NULL" } {
|
|
|
|
|
set_operating_conditions_cmd $op_cond $min_max
|
|
|
|
|
set found 1
|
|
|
|
|
break
|
|
|
|
|
}
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
$lib_iter finish
|
|
|
|
|
if { !$found } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 580 "operating condition '$op_cond_name' not found."
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc parse_op_cond_analysis_type { key_var } {
|
|
|
|
|
upvar 1 $key_var keys
|
|
|
|
|
if [info exists keys(-analysis_type)] {
|
|
|
|
|
set analysis_type $keys(-analysis_type)
|
|
|
|
|
if { $analysis_type == "single" \
|
|
|
|
|
|| $analysis_type == "bc_wc" \
|
|
|
|
|
|| $analysis_type == "on_chip_variation" } {
|
|
|
|
|
set_analysis_type_cmd $analysis_type
|
|
|
|
|
} else {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 581 "-analysis_type must be single, bc_wc or on_chip_variation."
|
2019-06-24 06:38:01 +02:00
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
} elseif { [info exists keys(-min)] && [info exists keys(-max)] } {
|
|
|
|
|
set_analysis_type_cmd "bc_wc"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_wire_load_min_block_size" {block_size}
|
|
|
|
|
|
|
|
|
|
proc set_wire_load_min_block_size { block_size } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_warn 371 "set_wire_load_min_block_size not supported."
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_wire_load_mode" "top|enclosed|segmented"
|
|
|
|
|
|
|
|
|
|
proc set_wire_load_mode { mode } {
|
|
|
|
|
if { $mode == "top" \
|
|
|
|
|
|| $mode == "enclosed" \
|
|
|
|
|
|| $mode == "segmented" } {
|
|
|
|
|
set_wire_load_mode_cmd $mode
|
|
|
|
|
} else {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 582 "mode must be top, enclosed or segmented."
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_wire_load_model" \
|
|
|
|
|
{-name model_name [-library lib_name] [-min] [-max] [objects]}
|
|
|
|
|
|
|
|
|
|
proc set_wire_load_model { args } {
|
|
|
|
|
parse_key_args "set_wire_load_model" args keys {-name -library} \
|
|
|
|
|
flags {-min -max}
|
|
|
|
|
|
|
|
|
|
check_argc_eq0or1 "set_wire_load_model" $args
|
|
|
|
|
if { ![info exists keys(-name)] } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 583 "no wire load model specified."
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set model_name $keys(-name)
|
|
|
|
|
set min_max [parse_min_max_all_check_flags flags]
|
|
|
|
|
|
|
|
|
|
set wireload "NULL"
|
|
|
|
|
if [info exists keys(-library)] {
|
|
|
|
|
set library [get_liberty_error "library" $keys(-library)]
|
|
|
|
|
set wireload [$library find_wireload $model_name]
|
|
|
|
|
} else {
|
|
|
|
|
set lib_iter [liberty_library_iterator]
|
|
|
|
|
while {[$lib_iter has_next]} {
|
|
|
|
|
set lib [$lib_iter next]
|
|
|
|
|
set wireload [$lib find_wireload $model_name]
|
|
|
|
|
if {$wireload != "NULL"} {
|
|
|
|
|
break;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
$lib_iter finish
|
|
|
|
|
}
|
|
|
|
|
if {$wireload == "NULL"} {
|
2020-12-20 19:21:50 +01:00
|
|
|
sta_error 605 "wire load model '$model_name' not found."
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
set objects $args
|
|
|
|
|
set_wire_load_cmd $wireload $min_max
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_wire_load_selection_group" \
|
|
|
|
|
{[-library lib] [-min] [-max] group_name [objects]}
|
|
|
|
|
|
|
|
|
|
proc set_wire_load_selection_group { args } {
|
|
|
|
|
parse_key_args "set_wire_load_selection_group" args keys {-library} \
|
|
|
|
|
flags {-min -max}
|
|
|
|
|
|
|
|
|
|
set argc [llength $args]
|
|
|
|
|
check_argc_eq1or2 "wire_load_selection_group" $args
|
|
|
|
|
|
|
|
|
|
set selection_name [lindex $args 0]
|
|
|
|
|
set objects [lindex $args 1]
|
|
|
|
|
|
|
|
|
|
set min_max [parse_min_max_all_check_flags flags]
|
|
|
|
|
|
|
|
|
|
set selection "NULL"
|
|
|
|
|
if [info exists keys(-library)] {
|
|
|
|
|
set library [get_liberty_error "library" $keys(-library)]
|
|
|
|
|
set selection [$library find_wireload_selection $selection_name]
|
|
|
|
|
} else {
|
|
|
|
|
set lib_iter [liberty_library_iterator]
|
|
|
|
|
while {[$lib_iter has_next]} {
|
|
|
|
|
set lib [$lib_iter next]
|
|
|
|
|
set selection [$lib find_wireload_selection $selection_name]
|
|
|
|
|
if {$selection != "NULL"} {
|
|
|
|
|
break;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
$lib_iter finish
|
|
|
|
|
}
|
|
|
|
|
if {$selection == "NULL"} {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 584 "wire load selection group '$selection_name' not found."
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
set_wire_load_selection_group_cmd $selection $min_max
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
#
|
|
|
|
|
# Multivoltage and Power Optimization Commands
|
|
|
|
|
#
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "create_voltage_area" \
|
|
|
|
|
{[-name name] [-coordinate coordinates] [-guard_band_x guard_x]\
|
|
|
|
|
[-guard_band_y guard_y] cells }
|
|
|
|
|
|
|
|
|
|
proc create_voltage_area { args } {
|
|
|
|
|
# ignored
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_level_shifter_strategy" {[-rule rule_type]}
|
|
|
|
|
|
|
|
|
|
proc set_level_shifter_strategy { args } {
|
|
|
|
|
# ignored
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_level_shifter_threshold" {[-voltage volt]}
|
|
|
|
|
|
|
|
|
|
proc set_level_shifter_threshold { args } {
|
|
|
|
|
# ignored
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_max_dynamic_power" {power [unit]}
|
|
|
|
|
|
|
|
|
|
proc set_max_dynamic_power { power {unit {}} } {
|
|
|
|
|
# ignored
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_max_leakage_power" {power [unit]}
|
|
|
|
|
|
|
|
|
|
proc set_max_leakage_power { power {unit {}} } {
|
|
|
|
|
# ignored
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
#
|
|
|
|
|
# Non-SDC commands
|
|
|
|
|
#
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "define_corners" { corner1 [corner2]... }
|
|
|
|
|
|
|
|
|
|
proc define_corners { args } {
|
2021-12-23 00:11:54 +01:00
|
|
|
if { [get_libs -quiet *] != {} } {
|
|
|
|
|
sta_error 373 "define_corners must be called before read_liberty."
|
|
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
define_corners_cmd $args
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
define_cmd_args "set_pvt"\
|
|
|
|
|
{insts [-min] [-max] [-process process] [-voltage voltage]\
|
|
|
|
|
[-temperature temperature]}
|
|
|
|
|
|
|
|
|
|
proc set_pvt { args } {
|
|
|
|
|
parse_key_args "set_pvt" args \
|
|
|
|
|
keys {-process -voltage -temperature} flags {-min -max}
|
|
|
|
|
|
|
|
|
|
set min_max [parse_min_max_all_flags flags]
|
|
|
|
|
check_argc_eq1 "set_pvt" $args
|
|
|
|
|
set insts [get_instances_error "instances" [lindex $args 0]]
|
|
|
|
|
|
|
|
|
|
if { $min_max == "all" } {
|
|
|
|
|
set_pvt_min_max $insts "min" keys
|
|
|
|
|
set_pvt_min_max $insts "max" keys
|
|
|
|
|
} else {
|
|
|
|
|
set_pvt_min_max $insts $min_max keys
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc set_pvt_min_max { insts min_max keys_var } {
|
|
|
|
|
upvar 1 $keys_var keys
|
|
|
|
|
set op_cond [operating_conditions $min_max]
|
|
|
|
|
if { $op_cond == "NULL" } {
|
|
|
|
|
set op_cond [default_operating_conditions]
|
|
|
|
|
}
|
|
|
|
|
if [info exists keys(-process)] {
|
|
|
|
|
set process $keys(-process)
|
|
|
|
|
check_float "-process" $process
|
|
|
|
|
} else {
|
|
|
|
|
set process [$op_cond process]
|
|
|
|
|
}
|
|
|
|
|
if [info exists keys(-voltage)] {
|
|
|
|
|
set voltage $keys(-voltage)
|
|
|
|
|
check_float "-voltage" $voltage
|
|
|
|
|
} else {
|
|
|
|
|
set voltage [$op_cond voltage]
|
|
|
|
|
}
|
|
|
|
|
if [info exists keys(-temperature)] {
|
|
|
|
|
set temperature $keys(-temperature)
|
|
|
|
|
check_float "-temperature" $temperature
|
|
|
|
|
} else {
|
|
|
|
|
set temperature [$op_cond temperature]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach inst $insts {
|
|
|
|
|
set_instance_pvt $inst $min_max $process $voltage $temperature
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc default_operating_conditions {} {
|
|
|
|
|
set found 0
|
|
|
|
|
set lib_iter [liberty_library_iterator]
|
|
|
|
|
while {[$lib_iter has_next]} {
|
|
|
|
|
set lib [$lib_iter next]
|
|
|
|
|
set op_cond [$lib default_operating_conditions]
|
|
|
|
|
if { $op_cond != "NULL" } {
|
|
|
|
|
set found 1
|
|
|
|
|
break
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-06-27 00:58:23 +02:00
|
|
|
$lib_iter finish
|
|
|
|
|
if { !$found } {
|
2020-12-16 06:31:08 +01:00
|
|
|
sta_error 585 "no default operating conditions found."
|
2019-06-27 00:58:23 +02:00
|
|
|
}
|
|
|
|
|
return $op_cond
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-10 07:32:51 +02:00
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
proc cell_regexp {} {
|
|
|
|
|
global hierarchy_separator
|
|
|
|
|
return [cell_regexp_hsc $hierarchy_separator]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc cell_regexp_hsc { hsc } {
|
|
|
|
|
return "^(\[^${hsc}\]+)${hsc}(\[^${hsc}\]+)$"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc port_regexp {} {
|
|
|
|
|
global hierarchy_separator
|
|
|
|
|
return [port_regexp_hsc $hierarchy_separator]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc port_regexp_hsc { hsc } {
|
|
|
|
|
return "^(\[^${hsc}\]+)${hsc}(\[^${hsc}\]+)${hsc}(\[^${hsc}\]+)$"
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-27 00:58:23 +02:00
|
|
|
# sta namespace end.
|
|
|
|
|
}
|