1# OpenSTA, Static Timing Analyzer 2# Copyright (c) 2021, Parallax Software, Inc. 3# 4# This program is free software: you can redistribute it and/or modify 5# it under the terms of the GNU General Public License as published by 6# the Free Software Foundation, either version 3 of the License, or 7# (at your option) any later version. 8# 9# This program is distributed in the hope that it will be useful, 10# but WITHOUT ANY WARRANTY; without even the implied warranty of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12# GNU General Public License for more details. 13# 14# You should have received a copy of the GNU General Public License 15# along with this program. If not, see <https://www.gnu.org/licenses/>. 16 17################################################################ 18# 19# Command helper functions. 20# 21################################################################ 22 23namespace eval sta { 24 25################################################################# 26# 27# Argument parsing functions. 28# 29################################################################ 30 31# Parse multiple object type args. 32# For object name args the search order is as follows: 33# clk 34# liberty_cell 35# liberty_port 36# cell 37# inst 38# port 39# pin 40# net 41 42proc get_object_args { objects clks_var libcells_var libports_var \ 43 cells_var insts_var ports_var pins_var nets_var \ 44 edges_var timing_arc_sets_var } { 45 if { $clks_var != {} } { 46 upvar 1 $clks_var clks 47 } 48 if { $libcells_var != {} } { 49 upvar 1 $libcells_var libcells 50 } 51 if { $libports_var != {} } { 52 upvar 1 $libports_var libports 53 } 54 if { $cells_var != {} } { 55 upvar 1 $cells_var cells 56 } 57 if { $insts_var != {} } { 58 upvar 1 $insts_var insts 59 } 60 if { $ports_var != {} } { 61 upvar 1 $ports_var ports 62 } 63 if { $pins_var != {} } { 64 upvar 1 $pins_var pins 65 } 66 if { $nets_var != {} } { 67 upvar 1 $nets_var nets 68 } 69 if { $edges_var != {} } { 70 upvar 1 $edges_var edges 71 } 72 if { $timing_arc_sets_var != {} } { 73 upvar 1 $timing_arc_sets_var timing_arc_sets 74 } 75 76 # Copy backslashes that will be removed by foreach. 77 set objects [string map {\\ \\\\} $objects] 78 foreach obj $objects { 79 if { [llength $obj] > 1 } { 80 # List arg. Recursive call without initing objects. 81 get_object_args $obj clks libcells libports cells insts \ 82 ports pins nets edges timing_arc_sets 83 } elseif { [is_object $obj] } { 84 # Explicit object arg. 85 set object_type [object_type $obj] 86 if { $pins_var != {} && $object_type == "Pin" } { 87 lappend pins $obj 88 } elseif { $insts_var != {} && $object_type == "Instance" } { 89 lappend insts $obj 90 } elseif { $nets_var != {} && $object_type == "Net" } { 91 lappend nets $obj 92 } elseif { $ports_var != {} && $object_type == "Port" } { 93 lappend ports $obj 94 } elseif { $edges_var != {} && $object_type == "Edge" } { 95 lappend edges $obj 96 } elseif { $clks_var != {} && $object_type == "Clock" } { 97 lappend clks $obj 98 } elseif { $libcells_var != {} && $object_type == "LibertyCell" } { 99 lappend libcells $obj 100 } elseif { $libports_var != {} && $object_type == "LibertyPort" } { 101 lappend libports $obj 102 } elseif { $cells_var != {} && $object_type == "Cell" } { 103 lappend cells $obj 104 } elseif { $timing_arc_sets_var != {} \ 105 && $object_type == "TimingArcSet" } { 106 lappend timing_arc_sets $obj 107 } else { 108 sta_error 467 "unsupported object type $object_type." 109 } 110 } elseif { $obj != {} } { 111 # Check for implicit arg. 112 # Search for most general object type first. 113 set matches {} 114 if { $clks_var != {} } { 115 set matches [get_clocks -quiet $obj] 116 } 117 if { $matches != {} } { 118 set clks [concat $clks $matches] 119 } else { 120 121 if { $libcells_var != {} } { 122 set matches [get_lib_cells -quiet $obj] 123 } 124 if { $matches != {} } { 125 set libcells [concat $libcells $matches] 126 } else { 127 128 if { $libports_var != {} } { 129 set matches [get_lib_pins -quiet $obj] 130 } 131 if { $matches != {} } { 132 set libports [concat $libports $matches] 133 } else { 134 135 if { $cells_var != {} } { 136 set matches [find_cells_matching $obj 0 0] 137 } 138 if { $matches != {} } { 139 set cells [concat $cells $matches] 140 } else { 141 142 if { $insts_var != {} } { 143 set matches [get_cells -quiet $obj] 144 } 145 if { $matches != {} } { 146 set insts [concat $insts $matches] 147 } else { 148 if { $ports_var != {} } { 149 set matches [get_ports -quiet $obj] 150 } 151 if { $matches != {} } { 152 set ports [concat $ports $matches] 153 } else { 154 if { $pins_var != {} } { 155 set matches [get_pins -quiet $obj] 156 } 157 if { $matches != {} } { 158 set pins [concat $pins $matches] 159 } else { 160 if { $nets_var != {} } { 161 set matches [get_nets -quiet $obj] 162 } 163 if { $matches != {} } { 164 set nets [concat $nets $matches] 165 } else { 166 sta_warn 305 "object '$obj' not found." 167 } 168 } 169 } 170 } 171 } 172 } 173 } 174 } 175 } 176 } 177} 178 179proc parse_clk_cell_port_args { objects clks_var cells_var ports_var } { 180 upvar 1 $clks_var clks 181 upvar 1 $cells_var cells 182 upvar 1 $ports_var ports 183 set clks {} 184 set cells {} 185 set ports {} 186 get_object_args $objects clks {} {} cells {} ports {} {} {} {} 187} 188 189proc parse_clk_cell_port_pin_args { objects clks_var cells_var ports_var \ 190 pins_arg } { 191 upvar 1 $clks_var clks 192 upvar 1 $cells_var cells 193 upvar 1 $ports_var ports 194 upvar 1 $pins_arg pins 195 set clks {} 196 set cells {} 197 set ports {} 198 set pins {} 199 get_object_args $objects clks {} {} cells {} ports pins {} {} {} 200} 201 202proc parse_clk_inst_pin_arg { objects clks_var insts_var pins_var } { 203 upvar 1 $clks_var clks 204 upvar 1 $insts_var insts 205 upvar 1 $pins_var pins 206 set clks {} 207 set insts {} 208 set pins {} 209 get_object_args $objects clks {} {} {} insts {} pins {} {} {} 210} 211 212proc parse_clk_inst_port_pin_arg { objects clks_var insts_var pins_var } { 213 upvar 1 $clks_var clks 214 upvar 1 $insts_var insts 215 upvar 1 $pins_var pins 216 set clks {} 217 set insts {} 218 set pins {} 219 set ports {} 220 get_object_args $objects clks {} {} {} insts ports pins {} {} {} 221 foreach port $ports { 222 lappend pins [[top_instance] find_pin [get_name $port]] 223 } 224} 225 226proc parse_clk_port_pin_arg { objects clks_var pins_var } { 227 upvar 1 $clks_var clks 228 upvar 1 $pins_var pins 229 set clks {} 230 set pins {} 231 set ports {} 232 get_object_args $objects clks {} {} {} {} ports pins {} {} {} 233 foreach port $ports { 234 lappend pins [[top_instance] find_pin [get_name $port]] 235 } 236} 237 238proc parse_libcell_libport_inst_port_pin_edge_timing_arc_set_arg { objects \ 239 libcells_var \ 240 libports_var \ 241 insts_var \ 242 ports_var \ 243 pins_var \ 244 edges_var \ 245 timing_arc_sets_var } { 246 upvar 1 $libcells_var libcells 247 upvar 1 $libports_var libports 248 upvar 1 $insts_var insts 249 upvar 1 $ports_var ports 250 upvar 1 $pins_var pins 251 upvar 1 $edges_var edges 252 upvar 1 $timing_arc_sets_var timing_arc_sets 253 254 set libcells {} 255 set libports {} 256 set insts {} 257 set ports {} 258 set pins {} 259 set edges {} 260 set timing_arc_sets {} 261 get_object_args $objects {} libcells libports {} insts ports pins {} \ 262 edges timing_arc_sets 263} 264 265proc parse_libcell_arg { objects } { 266 set libcells {} 267 get_object_args $objects {} libcells {} {} {} {} {} {} {} {} 268 return $libcells 269} 270 271proc parse_libcell_inst_arg { objects libcells_var insts_var } { 272 upvar 1 $libcells_var libcells 273 upvar 1 $insts_var insts 274 set libcells {} 275 set insts {} 276 get_object_args $objects {} libcells {} {} insts {} {} {} {} {} 277} 278 279proc parse_libcell_inst_net_arg { objects libcells_var insts_var nets_var } { 280 upvar 1 $libcells_var libcells 281 upvar 1 $insts_var insts 282 upvar 1 $nets_var nets 283 set libcells {} 284 set insts {} 285 set nets {} 286 get_object_args $objects {} libcells {} {} insts {} {} nets {} {} 287} 288 289proc parse_cell_port_args { objects cells_var ports_var } { 290 upvar 1 $cells_var cells 291 upvar 1 $ports_var ports 292 set cells {} 293 set ports {} 294 get_object_args $objects {} {} {} cells {} ports {} {} {} {} 295} 296 297proc parse_cell_port_pin_args { objects cells_var ports_var pins_var } { 298 upvar 1 $cells_var cells 299 upvar 1 $ports_var ports 300 upvar 1 $pins_var pins 301 set cells {} 302 set ports {} 303 set pins {} 304 get_object_args $objects {} {} {} cells {} ports pins {} {} {} 305} 306 307proc parse_inst_port_pin_arg { objects insts_var pins_var } { 308 upvar 1 $insts_var insts 309 upvar 1 $pins_var pins 310 set insts {} 311 set pins {} 312 set ports {} 313 get_object_args $objects {} {} {} {} insts ports pins {} {} {} 314 foreach port $ports { 315 lappend pins [[top_instance] find_pin [get_name $port]] 316 } 317} 318 319proc parse_inst_pin_arg { objects insts_var pins_var } { 320 upvar 1 $insts_var insts 321 upvar 1 $pins_var pins 322 set insts {} 323 set pins {} 324 get_object_args $objects {} {} {} {} insts {} pins {} {} {} 325} 326 327proc parse_inst_port_pin_net_arg { objects insts_var pins_var nets_var } { 328 upvar 1 $insts_var insts 329 upvar 1 $pins_var pins 330 upvar 1 $nets_var nets 331 set insts {} 332 set ports {} 333 set pins {} 334 set nets {} 335 get_object_args $objects {} {} {} {} insts ports pins nets {} {} 336 foreach port $ports { 337 lappend pins [[top_instance] find_pin [get_name $port]] 338 } 339} 340 341proc parse_inst_net_arg { objects insts_var nets_var } { 342 upvar 1 $insts_var insts 343 upvar 1 $nets_var nets 344 set insts {} 345 set nets {} 346 get_object_args $objects {} {} {} {} insts {} {} nets {} {} 347} 348 349proc parse_port_pin_net_arg { objects pins_var nets_var } { 350 upvar 1 $pins_var pins 351 upvar 1 $nets_var nets 352 set ports {} 353 set pins {} 354 set nets {} 355 get_object_args $objects {} {} {} {} {} ports pins nets {} {} 356 357 foreach port $ports { 358 lappend pins [[top_instance] find_pin [get_name $port]] 359 } 360} 361 362proc parse_port_net_args { objects ports_var nets_var } { 363 upvar 1 $ports_var ports 364 upvar 1 $nets_var nets 365 set ports {} 366 set nets {} 367 get_object_args $objects {} {} {} {} {} ports {} nets {} {} 368} 369 370proc parse_pin_net_args { objects pins_var nets_var } { 371 upvar 1 $pins_var pins 372 upvar 1 $nets_var nets 373 set pins {} 374 set nets {} 375 get_object_args $objects {} {} {} {} {} {} pins nets {} {} 376} 377 378proc get_ports_or_pins { pattern } { 379 set matches [find_port_pins_matching $pattern 0 0] 380 if { $matches != {} } { 381 return $matches 382 } else { 383 return [find_pins_matching $pattern 0 0] 384 } 385} 386 387################################################################ 388 389# If -corner keyword is missing: 390# one corner: return default 391# multiple corners: error 392proc parse_corner { keys_var } { 393 upvar 1 $keys_var keys 394 395 if { [info exists keys(-corner)] } { 396 set corner_name $keys(-corner) 397 set corner [find_corner $corner_name] 398 if { $corner == "NULL" } { 399 sta_error 468 "$corner_name is not the name of process corner." 400 } else { 401 return $corner 402 } 403 } elseif { [multi_corner] } { 404 sta_error 469 "-corner keyword required with multi-corner analysis." 405 } else { 406 return [cmd_corner] 407 } 408} 409 410# -corner keyword is required. 411# Assumes caller checks for existence of -corner keyword arg. 412proc parse_corner_required { keys_var } { 413 upvar 1 $keys_var keys 414 415 if { [info exists keys(-corner)] } { 416 set corner_name $keys(-corner) 417 set corner [find_corner $corner_name] 418 if { $corner == "NULL" } { 419 sta_error 470 "$corner_name is not the name of process corner." 420 } else { 421 return $corner 422 } 423 } else { 424 sta_error 471 "missing -corner arg." 425 } 426} 427 428proc parse_corner_or_default { keys_var } { 429 upvar 1 $keys_var keys 430 431 if { [info exists keys(-corner)] } { 432 set corner_name $keys(-corner) 433 set corner [find_corner $corner_name] 434 if { $corner == "NULL" } { 435 sta_error 472 "$corner_name is not the name of process corner." 436 } else { 437 return $corner 438 } 439 } else { 440 return [cmd_corner] 441 } 442} 443 444proc parse_corner_or_all { keys_var } { 445 upvar 1 $keys_var keys 446 447 if { [info exists keys(-corner)] } { 448 set corner_name $keys(-corner) 449 set corner [find_corner $corner_name] 450 if { $corner == "NULL" } { 451 sta_error 473 "$corner_name is not the name of process corner." 452 } else { 453 return $corner 454 } 455 } else { 456 return "NULL" 457 } 458} 459 460################################################################ 461 462proc parse_rise_fall_flags { flags_var } { 463 upvar 1 $flags_var flags 464 if { [info exists flags(-rise)] && ![info exists flags(-fall)] } { 465 return "rise" 466 } elseif { [info exists flags(-fall)] && ![info exists flags(-rise)] } { 467 return "fall" 468 } else { 469 return "rise_fall" 470 } 471} 472 473proc parse_min_max_flags { flags_var } { 474 upvar 1 $flags_var flags 475 if { [info exists flags(-min)] && [info exists flags(-max)] } { 476 sta_error 474 "both -min and -max specified." 477 } elseif { [info exists flags(-min)] && ![info exists flags(-max)] } { 478 return "min" 479 } elseif { [info exists flags(-max)] && ![info exists flags(-min)] } { 480 return "max" 481 } else { 482 # Default. 483 return "max" 484 } 485} 486 487proc parse_min_max_all_flags { flags_var } { 488 upvar 1 $flags_var flags 489 if { [info exists flags(-min)] && [info exists flags(-max)] } { 490 sta_error 475 "both -min and -max specified." 491 } elseif { [info exists flags(-min)] && ![info exists flags(-max)] } { 492 return "min" 493 } elseif { [info exists flags(-max)] && ![info exists flags(-min)] } { 494 return "max" 495 } else { 496 return "all" 497 } 498} 499 500# parse_min_max_all_flags and require analysis type to be min/max. 501proc parse_min_max_all_check_flags { flags_var } { 502 upvar 1 $flags_var flags 503 if { [info exists flags(-min)] && [info exists flags(-max)] } { 504 return "all" 505 } elseif { [info exists flags(-min)] && ![info exists flags(-max)] } { 506 return "min" 507 } elseif { [info exists flags(-max)] && ![info exists flags(-min)] } { 508 return "max" 509 } else { 510 return "all" 511 } 512} 513 514proc parse_early_late_flags { flags_var } { 515 upvar 1 $flags_var flags 516 if { [info exists flags(-early)] && [info exists flags(-late)] } { 517 sta_error 476 "only one of -early and -late can be specified." 518 } elseif { [info exists flags(-early)] } { 519 return "min" 520 } elseif { [info exists flags(-late)] } { 521 return "max" 522 } else { 523 sta_error 477 "-early or -late must be specified." 524 } 525} 526 527proc parse_early_late_all_flags { flags_var } { 528 upvar 1 $flags_var flags 529 if { [info exists flags(-early)] && [info exists flags(-late)] } { 530 sta_error 478 "both -early and -late specified." 531 } elseif { [info exists flags(-early)] && ![info exists flags(-late)] } { 532 return "min" 533 } elseif { [info exists flags(-late)] && ![info exists flags(-early)] } { 534 return "max" 535 } else { 536 return "all" 537 } 538} 539 540################################################################ 541 542proc get_liberty_error { arg_name arg } { 543 set lib "NULL" 544 if {[llength $arg] > 1} { 545 sta_error 479 "$arg_name must be a single library." 546 } elseif { [is_object $arg] } { 547 set object_type [object_type $arg] 548 if { $object_type == "LibertyLibrary" } { 549 set lib $arg 550 } else { 551 sta_error 480 "$arg_name type '$object_type' is not a library." 552 } 553 } else { 554 set lib [find_liberty $arg] 555 if { $lib == "NULL" } { 556 sta_error 481 "library '$arg' not found." 557 } 558 } 559 return $lib 560} 561 562proc get_lib_cell_warn { arg_name arg } { 563 return [get_lib_cell_arg $arg_name $arg sta_warn] 564} 565 566proc get_lib_cell_error { arg_name arg } { 567 return [get_lib_cell_arg $arg_name $arg sta_error] 568} 569 570proc get_lib_cell_arg { arg_name arg error_proc } { 571 set lib_cell "NULL" 572 if { [llength $arg] > 1 } { 573 sta_error 482 "$arg_name must be a single lib cell." 574 } elseif { [is_object $arg] } { 575 set object_type [object_type $arg] 576 if { $object_type == "LibertyCell" } { 577 set lib_cell $arg 578 } else { 579 $error_proc 700 "$arg_name type '$object_type' is not a liberty cell." 580 } 581 # Parse library_name/cell_name. 582 } elseif {[regexp [cell_regexp] $arg ignore lib_name cell_name]} { 583 set library [find_liberty $lib_name] 584 if { $library != "NULL" } { 585 set lib_cell [$library find_liberty_cell $cell_name] 586 if { $lib_cell == "NULL" } { 587 $error_proc 701 "liberty cell '$arg' not found." 588 } 589 } else { 590 $error_proc 702 "library '$lib_name' not found." 591 } 592 } else { 593 set lib_cell [find_liberty_cell $arg] 594 if { $lib_cell == "NULL" } { 595 $error_proc 703 "liberty cell '$arg' not found." 596 } 597 } 598 return $lib_cell 599} 600 601proc get_lib_cells_arg { arg_name arglist error_proc } { 602 set lib_cells {} 603 # Copy backslashes that will be removed by foreach. 604 set arglist [string map {\\ \\\\} $arglist] 605 foreach arg $arglist { 606 if {[llength $arg] > 1} { 607 # Embedded list. 608 set lib_cells [concat $lib_cells [get_lib_cells_arg $arg_name $arg $warn_error]] 609 } elseif { [is_object $arg] } { 610 set object_type [object_type $arg] 611 if { $object_type == "LibertyCell" } { 612 lappend lib_cells $arg 613 } else { 614 sta_warn_error 306 $warn_error "unsupported object type $object_type." 615 } 616 } elseif { $arg != {} } { 617 set arg_lib_cells [get_lib_cells -quiet $arg] 618 if { $arg_lib_cells != {} } { 619 set lib_cells [concat $lib_cells $arg_lib_cells] 620 } 621 } 622 } 623 return $lib_cells 624} 625 626proc get_instance_error { arg_name arg } { 627 set inst "NULL" 628 if {[llength $arg] > 1} { 629 sta_error 483 "$arg_name must be a single instance." 630 } elseif { [is_object $arg] } { 631 set object_type [object_type $arg] 632 if { $object_type == "Instance" } { 633 set inst $arg 634 } else { 635 sta_error 484 "$arg_name type '$object_type' is not an instance." 636 } 637 } else { 638 set inst [find_instance $arg] 639 if { $inst == "NULL" } { 640 sta_error 485 "instance '$arg' not found." 641 } 642 } 643 return $inst 644} 645 646proc get_instances_error { arg_name arglist } { 647 set insts {} 648 # Copy backslashes that will be removed by foreach. 649 set arglist [string map {\\ \\\\} $arglist] 650 foreach arg $arglist { 651 if {[llength $arg] > 1} { 652 # Embedded list. 653 set insts [concat $insts [get_instances_error $arg_name $arg]] 654 } elseif { [is_object $arg] } { 655 set object_type [object_type $arg] 656 if { $object_type == "Instance" } { 657 lappend insts $arg 658 } else { 659 sta_error 486 "$arg_name type '$object_type' is not an instance." 660 } 661 } elseif { $arg != {} } { 662 set arg_insts [get_cells -quiet $arg] 663 if { $arg_insts != {} } { 664 set insts [concat $insts $arg_insts] 665 } else { 666 sta_error 487 "instance '$arg' not found." 667 } 668 } 669 } 670 return $insts 671} 672 673proc get_port_pin_warn { arg_name arg } { 674 return [get_port_pin_arg $arg_name $arg "warn"] 675} 676 677proc get_port_pin_error { arg_name arg } { 678 return [get_port_pin_arg $arg_name $arg "error"] 679} 680 681proc get_port_pin_arg { arg_name arg warn_error } { 682 set pin "NULL" 683 if {[llength $arg] > 1} { 684 sta_warn_error 307 $warn_error "$arg_name must be a single port or pin." 685 } elseif { [is_object $arg] } { 686 set object_type [object_type $arg] 687 if { $object_type == "Pin" } { 688 set pin $arg 689 } elseif { $object_type == "Port" } { 690 # Explicit port arg - convert to pin. 691 set pin [find_pin [get_name $arg]] 692 } else { 693 sta_warn_error 308 $warn_error "$arg_name type '$object_type' is not a pin or port." 694 } 695 } else { 696 set top_instance [top_instance] 697 set top_cell [$top_instance cell] 698 set port [$top_cell find_port $arg] 699 if { $port == "NULL" } { 700 set pin [find_pin $arg] 701 } else { 702 set pin [$top_instance find_pin [get_name $port]] 703 } 704 if { $pin == "NULL" } { 705 sta_warn_error 309 $warn_error "pin $arg not found." 706 } 707 } 708 return $pin 709} 710 711proc get_port_pins_error { arg_name arglist } { 712 set pins {} 713 # Copy backslashes that will be removed by foreach. 714 set arglilst [string map {\\ \\\\} $arglist] 715 foreach arg $arglist { 716 if {[llength $arg] > 1} { 717 # Embedded list. 718 set pins [concat $pins [get_port_pins_error $arg_name $arg]] 719 } elseif { [is_object $arg] } { 720 set object_type [object_type $arg] 721 if { $object_type == "Pin" } { 722 lappend pins $arg 723 } elseif { $object_type == "Port" } { 724 # Convert port to pin. 725 lappend pins [find_pin [get_name $arg]] 726 } else { 727 sta_error 488 "$arg_name type '$object_type' is not a pin or port." 728 } 729 } elseif { $arg != {} } { 730 set arg_pins [get_ports_or_pins $arg] 731 if { $arg_pins != {} } { 732 set pins [concat $pins $arg_pins] 733 } else { 734 sta_error 489 "pin '$arg' not found." 735 } 736 } 737 } 738 return $pins 739} 740 741proc get_ports_error { arg_name arglist } { 742 set ports {} 743 # Copy backslashes that will be removed by foreach. 744 set arglist [string map {\\ \\\\} $arglist] 745 foreach arg $arglist { 746 if {[llength $arg] > 1} { 747 # Embedded list. 748 set ports [concat $ports [get_ports_error $arg_name $arg]] 749 } elseif { [is_object $arg] } { 750 set object_type [object_type $arg] 751 if { $object_type == "Port" } { 752 lappend ports $arg 753 } else { 754 sta_error 490 "$arg_name type '$object_type' is not a port." 755 } 756 } elseif { $arg != {} } { 757 set arg_ports [get_ports $arg] 758 if { $arg_ports != {} } { 759 set ports [concat $ports $arg_ports] 760 } 761 } 762 } 763 return $ports 764} 765 766proc get_pin_error { arg_name arg } { 767 return [get_pin_arg $arg_name $arg "error"] 768} 769 770proc get_pin_warn { arg_name arg } { 771 return [get_pin_arg $arg_name $arg "warn"] 772} 773 774proc get_pin_arg { arg_name arg warn_error } { 775 set pin "NULL" 776 if {[llength $arg] > 1} { 777 sta_warn_error 310 $warn_error "$arg_name must be a single pin." 778 } elseif { [is_object $arg] } { 779 set object_type [object_type $arg] 780 if { $object_type == "Pin" } { 781 set pin $arg 782 } else { 783 sta_warn_error 311 $warn_error "$arg_name type '$object_type' is not a pin." 784 } 785 } else { 786 set pin [find_pin $arg] 787 if { $pin == "NULL" } { 788 sta_warn_error 312 $warn_error "$arg_name pin $arg not found." 789 } 790 } 791 return $pin 792} 793 794proc get_clock_warn { arg_name arg } { 795 return [get_clock_arg $arg_name $arg sta_warn] 796} 797 798proc get_clock_error { arg_name arg } { 799 return [get_clock_arg $arg_name $arg sta_error] 800} 801 802proc get_clock_arg { arg_name arg error_proc } { 803 set clk "NULL" 804 if {[llength $arg] > 1} { 805 $error_proc 597 "$arg_name arg must be a single clock, not a list." 806 } elseif { [is_object $arg] } { 807 set object_type [object_type $arg] 808 if { $object_type == "Clock" } { 809 set clk $arg 810 } else { 811 $error_proc 598 "$arg_name arg value is a $object_type, not a clock." 812 } 813 } elseif { $arg != {} } { 814 set clk [find_clock $arg] 815 if { $clk == "NULL" } { 816 $error_proc 599 "$arg_name arg '$arg' clock not found." 817 } 818 } 819 return $clk 820} 821 822proc get_clocks_warn { arg_name arglist } { 823 set clks {} 824 # Copy backslashes that will be removed by foreach. 825 set arglist [string map {\\ \\\\} $arglist] 826 foreach arg $arglist { 827 if {[llength $arg] > 1} { 828 # Embedded list. 829 set clks [concat $clks [get_clocks_warn $arg_name $arg]] 830 } elseif { [is_object $arg] } { 831 set object_type [object_type $arg] 832 if { $object_type == "Clock" } { 833 lappend clks $arg 834 } else { 835 sta_warn 313 "unsupported object type $object_type." 836 } 837 } elseif { $arg != {} } { 838 set arg_clocks [get_clocks $arg] 839 if { $arg_clocks != {} } { 840 set clks [concat $clks $arg_clocks] 841 } 842 } 843 } 844 return $clks 845} 846 847proc get_net_warn { arg_name arg } { 848 set net "NULL" 849 if {[llength $arg] > 1} { 850 sta_warn 314 "$arg_name must be a single net." 851 } elseif { [is_object $arg] } { 852 set object_type [object_type $arg] 853 if { $object_type == "Net" } { 854 set net $arg 855 } else { 856 sta_warn 315 "$arg_name '$object_type' is not a net." 857 } 858 } else { 859 set net [find_net $arg] 860 if { $net == "NULL" } { 861 sta_warn 316 "$arg_name '$arg' not found." 862 } 863 } 864 return $net 865} 866 867proc get_nets_error { arg_name arglist } { 868 return [get_nets_arg $arg_name $arglist "error"] 869} 870 871proc get_nets_warn { arg_name arglist } { 872 return [get_nets_arg $arg_name $arglist "warn"] 873} 874 875proc get_nets_arg { arg_name arglist warn_error } { 876 set nets {} 877 # Copy backslashes that will be removed by foreach. 878 set arglist [string map {\\ \\\\} $arglist] 879 foreach arg $arglist { 880 if {[llength $arg] > 1} { 881 # Embedded list. 882 set nets [concat $nets [get_nets_arg $arg_name $arg $warn_error]] 883 } elseif { [is_object $arg] } { 884 set object_type [object_type $arg] 885 if { $object_type == "Net" } { 886 lappend nets $arg 887 } else { 888 sta_warn_error 317 $warn_error "unsupported object type $object_type." 889 } 890 } elseif { $arg != {} } { 891 set arg_nets [get_nets -quiet $arg] 892 if { $arg_nets != {} } { 893 set nets [concat $nets $arg_nets] 894 } 895 } 896 } 897 return $nets 898} 899 900# sta namespace end. 901} 902