2018-09-28 17:54:21 +02:00
|
|
|
# OpenSTA, Static Timing Analyzer
|
2025-01-22 02:54:33 +01:00
|
|
|
# Copyright (c) 2025, 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/>.
|
2025-01-22 02:54:33 +01:00
|
|
|
#
|
|
|
|
|
# The origin of this software must not be misrepresented; you must not
|
|
|
|
|
# claim that you wrote the original software.
|
|
|
|
|
#
|
|
|
|
|
# Altered source versions must be plainly marked as such, and must not be
|
|
|
|
|
# misrepresented as being the original software.
|
|
|
|
|
#
|
|
|
|
|
# This notice may not be removed or altered from any source distribution.
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
#
|
|
|
|
|
# Command helper functions.
|
|
|
|
|
#
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
namespace eval sta {
|
|
|
|
|
|
|
|
|
|
#################################################################
|
|
|
|
|
#
|
|
|
|
|
# Argument parsing functions.
|
|
|
|
|
#
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
# Parse multiple object type args.
|
|
|
|
|
# For object name args the search order is as follows:
|
|
|
|
|
# clk
|
|
|
|
|
# liberty_cell
|
|
|
|
|
# liberty_port
|
|
|
|
|
# cell
|
|
|
|
|
# inst
|
|
|
|
|
# port
|
|
|
|
|
# pin
|
|
|
|
|
# net
|
|
|
|
|
|
|
|
|
|
proc get_object_args { objects clks_var libcells_var libports_var \
|
|
|
|
|
cells_var insts_var ports_var pins_var nets_var \
|
|
|
|
|
edges_var timing_arc_sets_var } {
|
|
|
|
|
if { $clks_var != {} } {
|
|
|
|
|
upvar 1 $clks_var clks
|
|
|
|
|
}
|
|
|
|
|
if { $libcells_var != {} } {
|
|
|
|
|
upvar 1 $libcells_var libcells
|
|
|
|
|
}
|
|
|
|
|
if { $libports_var != {} } {
|
|
|
|
|
upvar 1 $libports_var libports
|
|
|
|
|
}
|
|
|
|
|
if { $cells_var != {} } {
|
|
|
|
|
upvar 1 $cells_var cells
|
|
|
|
|
}
|
|
|
|
|
if { $insts_var != {} } {
|
|
|
|
|
upvar 1 $insts_var insts
|
|
|
|
|
}
|
|
|
|
|
if { $ports_var != {} } {
|
|
|
|
|
upvar 1 $ports_var ports
|
|
|
|
|
}
|
|
|
|
|
if { $pins_var != {} } {
|
|
|
|
|
upvar 1 $pins_var pins
|
|
|
|
|
}
|
|
|
|
|
if { $nets_var != {} } {
|
|
|
|
|
upvar 1 $nets_var nets
|
|
|
|
|
}
|
|
|
|
|
if { $edges_var != {} } {
|
|
|
|
|
upvar 1 $edges_var edges
|
|
|
|
|
}
|
|
|
|
|
if { $timing_arc_sets_var != {} } {
|
|
|
|
|
upvar 1 $timing_arc_sets_var timing_arc_sets
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Copy backslashes that will be removed by foreach.
|
|
|
|
|
set objects [string map {\\ \\\\} $objects]
|
|
|
|
|
foreach obj $objects {
|
|
|
|
|
if { [llength $obj] > 1 } {
|
|
|
|
|
# List arg. Recursive call without initing objects.
|
2024-09-25 02:44:46 +02:00
|
|
|
get_object_args $obj $clks_var $libcells_var $libports_var $cells_var $insts_var \
|
|
|
|
|
$ports_var $pins_var $nets_var $edges_var $timing_arc_sets_var
|
2018-09-28 17:54:21 +02:00
|
|
|
} elseif { [is_object $obj] } {
|
|
|
|
|
# Explicit object arg.
|
|
|
|
|
set object_type [object_type $obj]
|
|
|
|
|
if { $pins_var != {} && $object_type == "Pin" } {
|
|
|
|
|
lappend pins $obj
|
|
|
|
|
} elseif { $insts_var != {} && $object_type == "Instance" } {
|
|
|
|
|
lappend insts $obj
|
|
|
|
|
} elseif { $nets_var != {} && $object_type == "Net" } {
|
|
|
|
|
lappend nets $obj
|
|
|
|
|
} elseif { $ports_var != {} && $object_type == "Port" } {
|
|
|
|
|
lappend ports $obj
|
|
|
|
|
} elseif { $edges_var != {} && $object_type == "Edge" } {
|
|
|
|
|
lappend edges $obj
|
|
|
|
|
} elseif { $clks_var != {} && $object_type == "Clock" } {
|
|
|
|
|
lappend clks $obj
|
|
|
|
|
} elseif { $libcells_var != {} && $object_type == "LibertyCell" } {
|
|
|
|
|
lappend libcells $obj
|
|
|
|
|
} elseif { $libports_var != {} && $object_type == "LibertyPort" } {
|
|
|
|
|
lappend libports $obj
|
|
|
|
|
} elseif { $cells_var != {} && $object_type == "Cell" } {
|
|
|
|
|
lappend cells $obj
|
|
|
|
|
} elseif { $timing_arc_sets_var != {} \
|
|
|
|
|
&& $object_type == "TimingArcSet" } {
|
|
|
|
|
lappend timing_arc_sets $obj
|
|
|
|
|
} else {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 100 "unsupported object type $object_type."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
} elseif { $obj != {} } {
|
|
|
|
|
# Check for implicit arg.
|
|
|
|
|
# Search for most general object type first.
|
|
|
|
|
set matches {}
|
|
|
|
|
if { $clks_var != {} } {
|
|
|
|
|
set matches [get_clocks -quiet $obj]
|
|
|
|
|
}
|
|
|
|
|
if { $matches != {} } {
|
|
|
|
|
set clks [concat $clks $matches]
|
|
|
|
|
} else {
|
|
|
|
|
if { $libcells_var != {} } {
|
|
|
|
|
set matches [get_lib_cells -quiet $obj]
|
|
|
|
|
}
|
|
|
|
|
if { $matches != {} } {
|
|
|
|
|
set libcells [concat $libcells $matches]
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
if { $libports_var != {} } {
|
|
|
|
|
set matches [get_lib_pins -quiet $obj]
|
|
|
|
|
}
|
|
|
|
|
if { $matches != {} } {
|
|
|
|
|
set libports [concat $libports $matches]
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
if { $cells_var != {} } {
|
|
|
|
|
set matches [find_cells_matching $obj 0 0]
|
|
|
|
|
}
|
|
|
|
|
if { $matches != {} } {
|
|
|
|
|
set cells [concat $cells $matches]
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
if { $insts_var != {} } {
|
|
|
|
|
set matches [get_cells -quiet $obj]
|
|
|
|
|
}
|
|
|
|
|
if { $matches != {} } {
|
|
|
|
|
set insts [concat $insts $matches]
|
|
|
|
|
} else {
|
|
|
|
|
if { $ports_var != {} } {
|
|
|
|
|
set matches [get_ports -quiet $obj]
|
|
|
|
|
}
|
|
|
|
|
if { $matches != {} } {
|
|
|
|
|
set ports [concat $ports $matches]
|
|
|
|
|
} else {
|
|
|
|
|
if { $pins_var != {} } {
|
|
|
|
|
set matches [get_pins -quiet $obj]
|
|
|
|
|
}
|
|
|
|
|
if { $matches != {} } {
|
|
|
|
|
set pins [concat $pins $matches]
|
|
|
|
|
} else {
|
|
|
|
|
if { $nets_var != {} } {
|
|
|
|
|
set matches [get_nets -quiet $obj]
|
|
|
|
|
}
|
|
|
|
|
if { $matches != {} } {
|
|
|
|
|
set nets [concat $nets $matches]
|
|
|
|
|
} else {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_warn 101 "object '$obj' not found."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc parse_clk_cell_port_args { objects clks_var cells_var ports_var } {
|
|
|
|
|
upvar 1 $clks_var clks
|
|
|
|
|
upvar 1 $cells_var cells
|
|
|
|
|
upvar 1 $ports_var ports
|
|
|
|
|
set clks {}
|
|
|
|
|
set cells {}
|
|
|
|
|
set ports {}
|
|
|
|
|
get_object_args $objects clks {} {} cells {} ports {} {} {} {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc parse_clk_cell_port_pin_args { objects clks_var cells_var ports_var \
|
|
|
|
|
pins_arg } {
|
|
|
|
|
upvar 1 $clks_var clks
|
|
|
|
|
upvar 1 $cells_var cells
|
|
|
|
|
upvar 1 $ports_var ports
|
|
|
|
|
upvar 1 $pins_arg pins
|
|
|
|
|
set clks {}
|
|
|
|
|
set cells {}
|
|
|
|
|
set ports {}
|
|
|
|
|
set pins {}
|
|
|
|
|
get_object_args $objects clks {} {} cells {} ports pins {} {} {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc parse_clk_inst_pin_arg { objects clks_var insts_var pins_var } {
|
|
|
|
|
upvar 1 $clks_var clks
|
|
|
|
|
upvar 1 $insts_var insts
|
|
|
|
|
upvar 1 $pins_var pins
|
|
|
|
|
set clks {}
|
|
|
|
|
set insts {}
|
|
|
|
|
set pins {}
|
|
|
|
|
get_object_args $objects clks {} {} {} insts {} pins {} {} {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc parse_clk_inst_port_pin_arg { objects clks_var insts_var pins_var } {
|
|
|
|
|
upvar 1 $clks_var clks
|
|
|
|
|
upvar 1 $insts_var insts
|
|
|
|
|
upvar 1 $pins_var pins
|
|
|
|
|
set clks {}
|
|
|
|
|
set insts {}
|
|
|
|
|
set pins {}
|
|
|
|
|
set ports {}
|
|
|
|
|
get_object_args $objects clks {} {} {} insts ports pins {} {} {}
|
|
|
|
|
foreach port $ports {
|
2019-01-17 00:37:31 +01:00
|
|
|
lappend pins [[top_instance] find_pin [get_name $port]]
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc parse_clk_port_pin_arg { objects clks_var pins_var } {
|
|
|
|
|
upvar 1 $clks_var clks
|
|
|
|
|
upvar 1 $pins_var pins
|
|
|
|
|
set clks {}
|
|
|
|
|
set pins {}
|
|
|
|
|
set ports {}
|
|
|
|
|
get_object_args $objects clks {} {} {} {} ports pins {} {} {}
|
|
|
|
|
foreach port $ports {
|
2019-01-17 00:37:31 +01:00
|
|
|
lappend pins [[top_instance] find_pin [get_name $port]]
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc parse_libcell_libport_inst_port_pin_edge_timing_arc_set_arg { objects \
|
|
|
|
|
libcells_var \
|
|
|
|
|
libports_var \
|
|
|
|
|
insts_var \
|
|
|
|
|
ports_var \
|
|
|
|
|
pins_var \
|
|
|
|
|
edges_var \
|
|
|
|
|
timing_arc_sets_var } {
|
|
|
|
|
upvar 1 $libcells_var libcells
|
|
|
|
|
upvar 1 $libports_var libports
|
|
|
|
|
upvar 1 $insts_var insts
|
|
|
|
|
upvar 1 $ports_var ports
|
|
|
|
|
upvar 1 $pins_var pins
|
|
|
|
|
upvar 1 $edges_var edges
|
|
|
|
|
upvar 1 $timing_arc_sets_var timing_arc_sets
|
|
|
|
|
|
|
|
|
|
set libcells {}
|
|
|
|
|
set libports {}
|
|
|
|
|
set insts {}
|
|
|
|
|
set ports {}
|
|
|
|
|
set pins {}
|
|
|
|
|
set edges {}
|
|
|
|
|
set timing_arc_sets {}
|
|
|
|
|
get_object_args $objects {} libcells libports {} insts ports pins {} \
|
|
|
|
|
edges timing_arc_sets
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-15 16:56:34 +02:00
|
|
|
proc parse_libcell_arg { objects } {
|
|
|
|
|
set libcells {}
|
|
|
|
|
get_object_args $objects {} libcells {} {} {} {} {} {} {} {}
|
|
|
|
|
return $libcells
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
proc parse_libcell_inst_arg { objects libcells_var insts_var } {
|
|
|
|
|
upvar 1 $libcells_var libcells
|
|
|
|
|
upvar 1 $insts_var insts
|
|
|
|
|
set libcells {}
|
|
|
|
|
set insts {}
|
|
|
|
|
get_object_args $objects {} libcells {} {} insts {} {} {} {} {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc parse_libcell_inst_net_arg { objects libcells_var insts_var nets_var } {
|
|
|
|
|
upvar 1 $libcells_var libcells
|
|
|
|
|
upvar 1 $insts_var insts
|
|
|
|
|
upvar 1 $nets_var nets
|
|
|
|
|
set libcells {}
|
|
|
|
|
set insts {}
|
|
|
|
|
set nets {}
|
|
|
|
|
get_object_args $objects {} libcells {} {} insts {} {} nets {} {}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-04 19:22:23 +01:00
|
|
|
proc parse_cell_arg { objects } {
|
|
|
|
|
set cells {}
|
|
|
|
|
get_object_args $objects {} {} {} cells {} {} {} {} {} {}
|
|
|
|
|
return $cells
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
proc parse_cell_port_args { objects cells_var ports_var } {
|
|
|
|
|
upvar 1 $cells_var cells
|
|
|
|
|
upvar 1 $ports_var ports
|
|
|
|
|
set cells {}
|
|
|
|
|
set ports {}
|
|
|
|
|
get_object_args $objects {} {} {} cells {} ports {} {} {} {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc parse_cell_port_pin_args { objects cells_var ports_var pins_var } {
|
|
|
|
|
upvar 1 $cells_var cells
|
|
|
|
|
upvar 1 $ports_var ports
|
|
|
|
|
upvar 1 $pins_var pins
|
|
|
|
|
set cells {}
|
|
|
|
|
set ports {}
|
|
|
|
|
set pins {}
|
|
|
|
|
get_object_args $objects {} {} {} cells {} ports pins {} {} {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc parse_inst_port_pin_arg { objects insts_var pins_var } {
|
|
|
|
|
upvar 1 $insts_var insts
|
|
|
|
|
upvar 1 $pins_var pins
|
|
|
|
|
set insts {}
|
|
|
|
|
set pins {}
|
|
|
|
|
set ports {}
|
|
|
|
|
get_object_args $objects {} {} {} {} insts ports pins {} {} {}
|
|
|
|
|
foreach port $ports {
|
2019-01-17 00:37:31 +01:00
|
|
|
lappend pins [[top_instance] find_pin [get_name $port]]
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc parse_inst_pin_arg { objects insts_var pins_var } {
|
|
|
|
|
upvar 1 $insts_var insts
|
|
|
|
|
upvar 1 $pins_var pins
|
|
|
|
|
set insts {}
|
|
|
|
|
set pins {}
|
|
|
|
|
get_object_args $objects {} {} {} {} insts {} pins {} {} {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc parse_inst_port_pin_net_arg { objects insts_var pins_var nets_var } {
|
|
|
|
|
upvar 1 $insts_var insts
|
|
|
|
|
upvar 1 $pins_var pins
|
|
|
|
|
upvar 1 $nets_var nets
|
|
|
|
|
set insts {}
|
|
|
|
|
set ports {}
|
|
|
|
|
set pins {}
|
|
|
|
|
set nets {}
|
|
|
|
|
get_object_args $objects {} {} {} {} insts ports pins nets {} {}
|
|
|
|
|
foreach port $ports {
|
2019-01-17 00:37:31 +01:00
|
|
|
lappend pins [[top_instance] find_pin [get_name $port]]
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc parse_inst_net_arg { objects insts_var nets_var } {
|
|
|
|
|
upvar 1 $insts_var insts
|
|
|
|
|
upvar 1 $nets_var nets
|
|
|
|
|
set insts {}
|
|
|
|
|
set nets {}
|
|
|
|
|
get_object_args $objects {} {} {} {} insts {} {} nets {} {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc parse_port_pin_net_arg { objects pins_var nets_var } {
|
|
|
|
|
upvar 1 $pins_var pins
|
|
|
|
|
upvar 1 $nets_var nets
|
|
|
|
|
set ports {}
|
|
|
|
|
set pins {}
|
|
|
|
|
set nets {}
|
|
|
|
|
get_object_args $objects {} {} {} {} {} ports pins nets {} {}
|
2019-01-17 00:37:31 +01:00
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
foreach port $ports {
|
2019-01-17 00:37:31 +01:00
|
|
|
lappend pins [[top_instance] find_pin [get_name $port]]
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc parse_port_net_args { objects ports_var nets_var } {
|
|
|
|
|
upvar 1 $ports_var ports
|
|
|
|
|
upvar 1 $nets_var nets
|
|
|
|
|
set ports {}
|
|
|
|
|
set nets {}
|
|
|
|
|
get_object_args $objects {} {} {} {} {} ports {} nets {} {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc parse_pin_net_args { objects pins_var nets_var } {
|
|
|
|
|
upvar 1 $pins_var pins
|
|
|
|
|
upvar 1 $nets_var nets
|
|
|
|
|
set pins {}
|
|
|
|
|
set nets {}
|
|
|
|
|
get_object_args $objects {} {} {} {} {} {} pins nets {} {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc get_ports_or_pins { pattern } {
|
|
|
|
|
set matches [find_port_pins_matching $pattern 0 0]
|
|
|
|
|
if { $matches != {} } {
|
|
|
|
|
return $matches
|
|
|
|
|
} else {
|
|
|
|
|
return [find_pins_matching $pattern 0 0]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
2024-02-08 21:54:52 +01:00
|
|
|
# -corner keyword is optional.
|
2018-12-05 23:18:41 +01:00
|
|
|
# If -corner keyword is missing:
|
2018-12-11 19:47:04 +01:00
|
|
|
# one corner: return default
|
|
|
|
|
# multiple corners: error
|
2018-09-28 17:54:21 +02:00
|
|
|
proc parse_corner { keys_var } {
|
|
|
|
|
upvar 1 $keys_var keys
|
|
|
|
|
|
|
|
|
|
if { [info exists keys(-corner)] } {
|
2024-06-27 22:57:58 +02:00
|
|
|
set corner_arg $keys(-corner)
|
|
|
|
|
if { [is_object $corner_arg] } {
|
|
|
|
|
set object_type [object_type $corner_arg]
|
|
|
|
|
if { $object_type == "Corner" } {
|
|
|
|
|
return $corner_arg
|
|
|
|
|
} else {
|
|
|
|
|
sta_error 144 "corner object type '$object_type' is not a corner."
|
|
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
} else {
|
2024-06-27 22:57:58 +02:00
|
|
|
set corner [find_corner $corner_arg]
|
|
|
|
|
if { $corner == "NULL" } {
|
|
|
|
|
sta_error 102 "$corner_arg is not the name of process corner."
|
|
|
|
|
} else {
|
|
|
|
|
return $corner
|
|
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
} elseif { [multi_corner] } {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 103 "-corner keyword required with multi-corner analysis."
|
2018-09-28 17:54:21 +02:00
|
|
|
} else {
|
2019-04-01 18:05:07 +02:00
|
|
|
return [cmd_corner]
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-11 19:47:04 +01:00
|
|
|
# -corner keyword is required.
|
2018-12-05 23:18:41 +01:00
|
|
|
proc parse_corner_required { keys_var } {
|
|
|
|
|
upvar 1 $keys_var keys
|
|
|
|
|
|
|
|
|
|
if { [info exists keys(-corner)] } {
|
|
|
|
|
set corner_name $keys(-corner)
|
|
|
|
|
set corner [find_corner $corner_name]
|
|
|
|
|
if { $corner == "NULL" } {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 104 "$corner_name is not the name of process corner."
|
2018-12-05 23:18:41 +01:00
|
|
|
} else {
|
|
|
|
|
return $corner
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 105 "missing -corner arg."
|
2018-12-05 23:18:41 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-26 18:15:52 +01:00
|
|
|
proc parse_corner_or_default { keys_var } {
|
|
|
|
|
upvar 1 $keys_var keys
|
|
|
|
|
|
|
|
|
|
if { [info exists keys(-corner)] } {
|
|
|
|
|
set corner_name $keys(-corner)
|
|
|
|
|
set corner [find_corner $corner_name]
|
|
|
|
|
if { $corner == "NULL" } {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 106 "$corner_name is not the name of process corner."
|
2018-11-26 18:15:52 +01:00
|
|
|
} else {
|
|
|
|
|
return $corner
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2019-04-01 18:05:07 +02:00
|
|
|
return [cmd_corner]
|
2018-11-26 18:15:52 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-19 19:23:45 +01:00
|
|
|
# Return NULL for all.
|
2018-09-28 17:54:21 +02:00
|
|
|
proc parse_corner_or_all { keys_var } {
|
|
|
|
|
upvar 1 $keys_var keys
|
|
|
|
|
|
|
|
|
|
if { [info exists keys(-corner)] } {
|
|
|
|
|
set corner_name $keys(-corner)
|
|
|
|
|
set corner [find_corner $corner_name]
|
|
|
|
|
if { $corner == "NULL" } {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 107 "$corner_name is not the name of process corner."
|
2018-09-28 17:54:21 +02:00
|
|
|
} else {
|
|
|
|
|
return $corner
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return "NULL"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
proc parse_rise_fall_flags { flags_var } {
|
|
|
|
|
upvar 1 $flags_var flags
|
|
|
|
|
if { [info exists flags(-rise)] && ![info exists flags(-fall)] } {
|
|
|
|
|
return "rise"
|
|
|
|
|
} elseif { [info exists flags(-fall)] && ![info exists flags(-rise)] } {
|
|
|
|
|
return "fall"
|
|
|
|
|
} else {
|
|
|
|
|
return "rise_fall"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-27 18:00:48 +01:00
|
|
|
proc parse_rise_fall_arg { arg } {
|
|
|
|
|
if { $arg eq "r" || $arg eq "^" || $arg eq "rise" } {
|
|
|
|
|
return "rise"
|
|
|
|
|
} elseif { $arg eq "f" || $arg eq "v" || $arg eq "fall" } {
|
|
|
|
|
return "fall"
|
|
|
|
|
} else {
|
|
|
|
|
error "unknown rise/fall transition name."
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
proc parse_min_max_flags { flags_var } {
|
|
|
|
|
upvar 1 $flags_var flags
|
|
|
|
|
if { [info exists flags(-min)] && [info exists flags(-max)] } {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 108 "both -min and -max specified."
|
2018-09-28 17:54:21 +02:00
|
|
|
} elseif { [info exists flags(-min)] && ![info exists flags(-max)] } {
|
|
|
|
|
return "min"
|
|
|
|
|
} elseif { [info exists flags(-max)] && ![info exists flags(-min)] } {
|
|
|
|
|
return "max"
|
|
|
|
|
} else {
|
|
|
|
|
# Default.
|
|
|
|
|
return "max"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc parse_min_max_all_flags { flags_var } {
|
|
|
|
|
upvar 1 $flags_var flags
|
|
|
|
|
if { [info exists flags(-min)] && [info exists flags(-max)] } {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 109 "both -min and -max specified."
|
2018-09-28 17:54:21 +02:00
|
|
|
} elseif { [info exists flags(-min)] && ![info exists flags(-max)] } {
|
|
|
|
|
return "min"
|
|
|
|
|
} elseif { [info exists flags(-max)] && ![info exists flags(-min)] } {
|
|
|
|
|
return "max"
|
|
|
|
|
} else {
|
2024-06-27 22:57:58 +02:00
|
|
|
return "min_max"
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# parse_min_max_all_flags and require analysis type to be min/max.
|
|
|
|
|
proc parse_min_max_all_check_flags { flags_var } {
|
|
|
|
|
upvar 1 $flags_var flags
|
|
|
|
|
if { [info exists flags(-min)] && [info exists flags(-max)] } {
|
2024-06-27 22:57:58 +02:00
|
|
|
return "min_max"
|
2018-09-28 17:54:21 +02:00
|
|
|
} elseif { [info exists flags(-min)] && ![info exists flags(-max)] } {
|
|
|
|
|
return "min"
|
|
|
|
|
} elseif { [info exists flags(-max)] && ![info exists flags(-min)] } {
|
|
|
|
|
return "max"
|
|
|
|
|
} else {
|
2024-06-27 22:57:58 +02:00
|
|
|
return "min_max"
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc parse_early_late_flags { flags_var } {
|
|
|
|
|
upvar 1 $flags_var flags
|
|
|
|
|
if { [info exists flags(-early)] && [info exists flags(-late)] } {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 110 "only one of -early and -late can be specified."
|
2018-09-28 17:54:21 +02:00
|
|
|
} elseif { [info exists flags(-early)] } {
|
|
|
|
|
return "min"
|
|
|
|
|
} elseif { [info exists flags(-late)] } {
|
|
|
|
|
return "max"
|
|
|
|
|
} else {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 111 "-early or -late must be specified."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc parse_early_late_all_flags { flags_var } {
|
|
|
|
|
upvar 1 $flags_var flags
|
|
|
|
|
if { [info exists flags(-early)] && [info exists flags(-late)] } {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 112 "both -early and -late specified."
|
2018-09-28 17:54:21 +02:00
|
|
|
} elseif { [info exists flags(-early)] && ![info exists flags(-late)] } {
|
|
|
|
|
return "min"
|
|
|
|
|
} elseif { [info exists flags(-late)] && ![info exists flags(-early)] } {
|
|
|
|
|
return "max"
|
|
|
|
|
} else {
|
2024-06-27 22:57:58 +02:00
|
|
|
return "min_max"
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
################################################################
|
|
|
|
|
|
|
|
|
|
proc get_liberty_error { arg_name arg } {
|
|
|
|
|
set lib "NULL"
|
|
|
|
|
if {[llength $arg] > 1} {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 113 "$arg_name must be a single library."
|
2018-09-28 17:54:21 +02:00
|
|
|
} elseif { [is_object $arg] } {
|
|
|
|
|
set object_type [object_type $arg]
|
|
|
|
|
if { $object_type == "LibertyLibrary" } {
|
|
|
|
|
set lib $arg
|
|
|
|
|
} else {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 114 "$arg_name type '$object_type' is not a library."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
set lib [find_liberty $arg]
|
|
|
|
|
if { $lib == "NULL" } {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 115 "library '$arg' not found."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $lib
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc get_lib_cell_warn { arg_name arg } {
|
2019-06-13 17:43:38 +02:00
|
|
|
return [get_lib_cell_arg $arg_name $arg sta_warn]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc get_lib_cell_error { arg_name arg } {
|
|
|
|
|
return [get_lib_cell_arg $arg_name $arg sta_error]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc get_lib_cell_arg { arg_name arg error_proc } {
|
2018-09-28 17:54:21 +02:00
|
|
|
set lib_cell "NULL"
|
|
|
|
|
if { [llength $arg] > 1 } {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 116 "$arg_name must be a single lib cell."
|
2018-09-28 17:54:21 +02:00
|
|
|
} elseif { [is_object $arg] } {
|
|
|
|
|
set object_type [object_type $arg]
|
|
|
|
|
if { $object_type == "LibertyCell" } {
|
|
|
|
|
set lib_cell $arg
|
|
|
|
|
} else {
|
2024-01-08 03:23:53 +01:00
|
|
|
$error_proc 116 "$arg_name type '$object_type' is not a liberty cell."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
# Parse library_name/cell_name.
|
|
|
|
|
} elseif {[regexp [cell_regexp] $arg ignore lib_name cell_name]} {
|
|
|
|
|
set library [find_liberty $lib_name]
|
|
|
|
|
if { $library != "NULL" } {
|
|
|
|
|
set lib_cell [$library find_liberty_cell $cell_name]
|
|
|
|
|
if { $lib_cell == "NULL" } {
|
2024-01-08 03:23:53 +01:00
|
|
|
$error_proc 117 "liberty cell '$arg' not found."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
2024-01-08 03:23:53 +01:00
|
|
|
$error_proc 118 "library '$lib_name' not found."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
set lib_cell [find_liberty_cell $arg]
|
|
|
|
|
if { $lib_cell == "NULL" } {
|
2024-01-08 03:23:53 +01:00
|
|
|
$error_proc 119 "liberty cell '$arg' not found."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $lib_cell
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-14 21:38:24 +02:00
|
|
|
# Not used by OpenSTA
|
2020-04-26 17:49:09 +02:00
|
|
|
proc get_lib_cells_arg { arg_name arglist error_proc } {
|
|
|
|
|
set lib_cells {}
|
|
|
|
|
# Copy backslashes that will be removed by foreach.
|
|
|
|
|
set arglist [string map {\\ \\\\} $arglist]
|
|
|
|
|
foreach arg $arglist {
|
|
|
|
|
if {[llength $arg] > 1} {
|
|
|
|
|
# Embedded list.
|
2023-07-14 21:38:24 +02:00
|
|
|
set lib_cells [concat $lib_cells [get_lib_cells_arg $arg_name $arg $error_proc]]
|
2020-04-26 17:49:09 +02:00
|
|
|
} elseif { [is_object $arg] } {
|
|
|
|
|
set object_type [object_type $arg]
|
|
|
|
|
if { $object_type == "LibertyCell" } {
|
|
|
|
|
lappend lib_cells $arg
|
|
|
|
|
} else {
|
2024-01-08 03:23:53 +01:00
|
|
|
$error_proc 120 "unsupported object type $object_type."
|
2020-04-26 17:49:09 +02:00
|
|
|
}
|
|
|
|
|
} elseif { $arg != {} } {
|
2023-07-14 21:38:24 +02:00
|
|
|
set arg_lib_cells [get_lib_cells1 $arg $error_proc]
|
2020-04-26 17:49:09 +02:00
|
|
|
if { $arg_lib_cells != {} } {
|
|
|
|
|
set lib_cells [concat $lib_cells $arg_lib_cells]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $lib_cells
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-14 21:38:24 +02:00
|
|
|
# Based on get_lib_cells
|
|
|
|
|
proc get_lib_cells1 { patterns error_proc } {
|
|
|
|
|
global hierarchy_separator
|
|
|
|
|
|
|
|
|
|
set cells {}
|
|
|
|
|
set cell_regexp [cell_regexp_hsc $hierarchy_separator]
|
|
|
|
|
foreach pattern $patterns {
|
|
|
|
|
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 == {} } {
|
2024-01-08 03:23:53 +01:00
|
|
|
$error_proc 121 "library '$lib_name' not found."
|
2023-07-14 21:38:24 +02:00
|
|
|
} else {
|
|
|
|
|
foreach lib $libs {
|
|
|
|
|
set matches [$lib find_liberty_cells_matching $cell_pattern 0 0]
|
|
|
|
|
if {$matches != {}} {
|
|
|
|
|
set cells [concat $cells $matches]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if { $cells == {} } {
|
2024-01-08 03:23:53 +01:00
|
|
|
$error_proc 122 "cell '$cell_pattern' not found."
|
2023-07-14 21:38:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $cells
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
proc get_instance_error { arg_name arg } {
|
|
|
|
|
set inst "NULL"
|
|
|
|
|
if {[llength $arg] > 1} {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 123 "$arg_name must be a single instance."
|
2018-09-28 17:54:21 +02:00
|
|
|
} elseif { [is_object $arg] } {
|
|
|
|
|
set object_type [object_type $arg]
|
|
|
|
|
if { $object_type == "Instance" } {
|
2019-06-02 03:41:09 +02:00
|
|
|
set inst $arg
|
2018-09-28 17:54:21 +02:00
|
|
|
} else {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 124 "$arg_name type '$object_type' is not an instance."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
set inst [find_instance $arg]
|
|
|
|
|
if { $inst == "NULL" } {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 125 "instance '$arg' not found."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $inst
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc get_instances_error { arg_name arglist } {
|
|
|
|
|
set insts {}
|
|
|
|
|
# Copy backslashes that will be removed by foreach.
|
|
|
|
|
set arglist [string map {\\ \\\\} $arglist]
|
|
|
|
|
foreach arg $arglist {
|
|
|
|
|
if {[llength $arg] > 1} {
|
|
|
|
|
# Embedded list.
|
|
|
|
|
set insts [concat $insts [get_instances_error $arg_name $arg]]
|
|
|
|
|
} elseif { [is_object $arg] } {
|
|
|
|
|
set object_type [object_type $arg]
|
|
|
|
|
if { $object_type == "Instance" } {
|
2023-07-14 21:38:24 +02:00
|
|
|
lappend insts $arg
|
2018-09-28 17:54:21 +02:00
|
|
|
} else {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 126 "$arg_name type '$object_type' is not an instance."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
} elseif { $arg != {} } {
|
|
|
|
|
set arg_insts [get_cells -quiet $arg]
|
|
|
|
|
if { $arg_insts != {} } {
|
2023-07-14 21:38:24 +02:00
|
|
|
set insts [concat $insts $arg_insts]
|
2018-09-28 17:54:21 +02:00
|
|
|
} else {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 127 "instance '$arg' not found."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $insts
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-16 23:05:34 +01:00
|
|
|
proc get_libcells_error { arg_name arglist } {
|
|
|
|
|
set libcells {}
|
|
|
|
|
# Copy backslashes that will be removed by foreach.
|
|
|
|
|
set arglist [string map {\\ \\\\} $arglist]
|
|
|
|
|
foreach arg $arglist {
|
|
|
|
|
if {[llength $arg] > 1} {
|
|
|
|
|
# Embedded list.
|
|
|
|
|
set libcells [concat $libcells [get_libcells_error $arg_name $arg]]
|
|
|
|
|
} elseif { [is_object $arg] } {
|
|
|
|
|
set object_type [object_type $arg]
|
|
|
|
|
if { $object_type == "LibertyCell" } {
|
|
|
|
|
lappend libcells $arg
|
|
|
|
|
} else {
|
|
|
|
|
sta_error 128 "$arg_name type '$object_type' is not a liberty cell."
|
|
|
|
|
}
|
|
|
|
|
} elseif { $arg != {} } {
|
|
|
|
|
set arg_libcells [get_lib_cells -quiet $arg]
|
|
|
|
|
if { $arg_libcells != {} } {
|
|
|
|
|
set libcells [concat $libcells $arg_libcells]
|
|
|
|
|
} else {
|
|
|
|
|
sta_error 129 "liberty cell '$arg' not found."
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $libcells
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
proc get_port_pin_warn { arg_name arg } {
|
|
|
|
|
return [get_port_pin_arg $arg_name $arg "warn"]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc get_port_pin_error { arg_name arg } {
|
|
|
|
|
return [get_port_pin_arg $arg_name $arg "error"]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc get_port_pin_arg { arg_name arg warn_error } {
|
|
|
|
|
set pin "NULL"
|
|
|
|
|
if {[llength $arg] > 1} {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_warn_error 128 $warn_error "$arg_name must be a single port or pin."
|
2018-09-28 17:54:21 +02:00
|
|
|
} elseif { [is_object $arg] } {
|
|
|
|
|
set object_type [object_type $arg]
|
|
|
|
|
if { $object_type == "Pin" } {
|
|
|
|
|
set pin $arg
|
|
|
|
|
} elseif { $object_type == "Port" } {
|
|
|
|
|
# Explicit port arg - convert to pin.
|
2019-01-17 00:37:31 +01:00
|
|
|
set pin [find_pin [get_name $arg]]
|
2018-09-28 17:54:21 +02:00
|
|
|
} else {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_warn_error 129 $warn_error "$arg_name type '$object_type' is not a pin or port."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
set top_instance [top_instance]
|
|
|
|
|
set top_cell [$top_instance cell]
|
|
|
|
|
set port [$top_cell find_port $arg]
|
|
|
|
|
if { $port == "NULL" } {
|
|
|
|
|
set pin [find_pin $arg]
|
|
|
|
|
} else {
|
2019-01-17 00:37:31 +01:00
|
|
|
set pin [$top_instance find_pin [get_name $port]]
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
if { $pin == "NULL" } {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_warn_error 130 $warn_error "pin $arg not found."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $pin
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc get_port_pins_error { arg_name arglist } {
|
|
|
|
|
set pins {}
|
|
|
|
|
# Copy backslashes that will be removed by foreach.
|
|
|
|
|
set arglilst [string map {\\ \\\\} $arglist]
|
|
|
|
|
foreach arg $arglist {
|
|
|
|
|
if {[llength $arg] > 1} {
|
|
|
|
|
# Embedded list.
|
|
|
|
|
set pins [concat $pins [get_port_pins_error $arg_name $arg]]
|
|
|
|
|
} elseif { [is_object $arg] } {
|
|
|
|
|
set object_type [object_type $arg]
|
|
|
|
|
if { $object_type == "Pin" } {
|
2023-07-14 21:38:24 +02:00
|
|
|
lappend pins $arg
|
2018-09-28 17:54:21 +02:00
|
|
|
} elseif { $object_type == "Port" } {
|
2023-07-14 21:38:24 +02:00
|
|
|
# Convert port to pin.
|
|
|
|
|
lappend pins [find_pin [get_name $arg]]
|
2018-09-28 17:54:21 +02:00
|
|
|
} else {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 131 "$arg_name type '$object_type' is not a pin or port."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
} elseif { $arg != {} } {
|
|
|
|
|
set arg_pins [get_ports_or_pins $arg]
|
|
|
|
|
if { $arg_pins != {} } {
|
2023-07-14 21:38:24 +02:00
|
|
|
set pins [concat $pins $arg_pins]
|
2018-09-28 17:54:21 +02:00
|
|
|
} else {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 132 "pin '$arg' not found."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $pins
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc get_ports_error { arg_name arglist } {
|
|
|
|
|
set ports {}
|
|
|
|
|
# Copy backslashes that will be removed by foreach.
|
|
|
|
|
set arglist [string map {\\ \\\\} $arglist]
|
|
|
|
|
foreach arg $arglist {
|
|
|
|
|
if {[llength $arg] > 1} {
|
|
|
|
|
# Embedded list.
|
|
|
|
|
set ports [concat $ports [get_ports_error $arg_name $arg]]
|
|
|
|
|
} elseif { [is_object $arg] } {
|
|
|
|
|
set object_type [object_type $arg]
|
|
|
|
|
if { $object_type == "Port" } {
|
2023-07-14 21:38:24 +02:00
|
|
|
lappend ports $arg
|
2018-09-28 17:54:21 +02:00
|
|
|
} else {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_error 133 "$arg_name type '$object_type' is not a port."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
} elseif { $arg != {} } {
|
|
|
|
|
set arg_ports [get_ports $arg]
|
|
|
|
|
if { $arg_ports != {} } {
|
2023-07-14 21:38:24 +02:00
|
|
|
set ports [concat $ports $arg_ports]
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $ports
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc get_pin_error { arg_name arg } {
|
|
|
|
|
return [get_pin_arg $arg_name $arg "error"]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc get_pin_warn { arg_name arg } {
|
|
|
|
|
return [get_pin_arg $arg_name $arg "warn"]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc get_pin_arg { arg_name arg warn_error } {
|
|
|
|
|
set pin "NULL"
|
|
|
|
|
if {[llength $arg] > 1} {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_warn_error 134 $warn_error "$arg_name must be a single pin."
|
2018-09-28 17:54:21 +02:00
|
|
|
} elseif { [is_object $arg] } {
|
|
|
|
|
set object_type [object_type $arg]
|
|
|
|
|
if { $object_type == "Pin" } {
|
|
|
|
|
set pin $arg
|
|
|
|
|
} else {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_warn_error 135 $warn_error "$arg_name type '$object_type' is not a pin."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
set pin [find_pin $arg]
|
|
|
|
|
if { $pin == "NULL" } {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_warn_error 136 $warn_error "$arg_name pin $arg not found."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $pin
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc get_clock_warn { arg_name arg } {
|
|
|
|
|
return [get_clock_arg $arg_name $arg sta_warn]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc get_clock_error { arg_name arg } {
|
|
|
|
|
return [get_clock_arg $arg_name $arg sta_error]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc get_clock_arg { arg_name arg error_proc } {
|
|
|
|
|
set clk "NULL"
|
|
|
|
|
if {[llength $arg] > 1} {
|
2024-01-08 03:23:53 +01:00
|
|
|
$error_proc 137 "$arg_name arg must be a single clock, not a list."
|
2018-09-28 17:54:21 +02:00
|
|
|
} elseif { [is_object $arg] } {
|
|
|
|
|
set object_type [object_type $arg]
|
|
|
|
|
if { $object_type == "Clock" } {
|
|
|
|
|
set clk $arg
|
|
|
|
|
} else {
|
2024-01-08 03:23:53 +01:00
|
|
|
$error_proc 138 "$arg_name arg value is a $object_type, not a clock."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
} elseif { $arg != {} } {
|
|
|
|
|
set clk [find_clock $arg]
|
|
|
|
|
if { $clk == "NULL" } {
|
2024-01-08 03:23:53 +01:00
|
|
|
$error_proc 138 "$arg_name arg '$arg' clock not found."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $clk
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
proc get_clocks_warn { arg_name arglist } {
|
|
|
|
|
set clks {}
|
|
|
|
|
# Copy backslashes that will be removed by foreach.
|
|
|
|
|
set arglist [string map {\\ \\\\} $arglist]
|
|
|
|
|
foreach arg $arglist {
|
|
|
|
|
if {[llength $arg] > 1} {
|
|
|
|
|
# Embedded list.
|
|
|
|
|
set clks [concat $clks [get_clocks_warn $arg_name $arg]]
|
|
|
|
|
} elseif { [is_object $arg] } {
|
|
|
|
|
set object_type [object_type $arg]
|
|
|
|
|
if { $object_type == "Clock" } {
|
2023-07-14 21:38:24 +02:00
|
|
|
lappend clks $arg
|
2018-09-28 17:54:21 +02:00
|
|
|
} else {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_warn 139 "unsupported object type $object_type."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
} elseif { $arg != {} } {
|
|
|
|
|
set arg_clocks [get_clocks $arg]
|
|
|
|
|
if { $arg_clocks != {} } {
|
2023-07-14 21:38:24 +02:00
|
|
|
set clks [concat $clks $arg_clocks]
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $clks
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-09 02:51:21 +02:00
|
|
|
proc get_net_arg { arg_name arg } {
|
2018-09-28 17:54:21 +02:00
|
|
|
set net "NULL"
|
|
|
|
|
if {[llength $arg] > 1} {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_warn 140 "$arg_name must be a single net."
|
2018-09-28 17:54:21 +02:00
|
|
|
} elseif { [is_object $arg] } {
|
|
|
|
|
set object_type [object_type $arg]
|
|
|
|
|
if { $object_type == "Net" } {
|
|
|
|
|
set net $arg
|
|
|
|
|
} else {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_warn 141 "$arg_name '$object_type' is not a net."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
set net [find_net $arg]
|
|
|
|
|
if { $net == "NULL" } {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_warn 143 "$arg_name '$arg' not found."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $net
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-09 02:51:21 +02:00
|
|
|
proc get_nets_arg { arg_name arglist } {
|
2018-09-28 17:54:21 +02:00
|
|
|
set nets {}
|
|
|
|
|
# Copy backslashes that will be removed by foreach.
|
|
|
|
|
set arglist [string map {\\ \\\\} $arglist]
|
|
|
|
|
foreach arg $arglist {
|
|
|
|
|
if {[llength $arg] > 1} {
|
|
|
|
|
# Embedded list.
|
2023-09-09 02:51:21 +02:00
|
|
|
set nets [concat $nets [get_nets_arg $arg_name $arg]]
|
2018-09-28 17:54:21 +02:00
|
|
|
} elseif { [is_object $arg] } {
|
|
|
|
|
set object_type [object_type $arg]
|
|
|
|
|
if { $object_type == "Net" } {
|
2023-07-14 21:38:24 +02:00
|
|
|
lappend nets $arg
|
2018-09-28 17:54:21 +02:00
|
|
|
} else {
|
2024-01-08 03:23:53 +01:00
|
|
|
sta_warn 142 "unsupported object type $object_type."
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
} elseif { $arg != {} } {
|
2023-09-09 02:51:21 +02:00
|
|
|
set arg_nets [get_nets $arg]
|
2018-09-28 17:54:21 +02:00
|
|
|
if { $arg_nets != {} } {
|
2023-07-14 21:38:24 +02:00
|
|
|
set nets [concat $nets $arg_nets]
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $nets
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# sta namespace end.
|
|
|
|
|
}
|