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