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# SDC commands.
20# Alphabetical within groups as in the SDC spec.
21#
22# Argument parsing and checking is done in TCL before calling a
23# SWIG interface function.
24#
25################################################################
26
27namespace eval sta {
28
29define_cmd_args "read_sdc" {[-echo] filename}
30
31proc_redirect read_sdc {
32  parse_key_args "read_sdc" args keys {} flags {-echo}
33
34  check_argc_eq1 "read_sdc" $args
35  set echo [info exists flags(-echo)]
36  set filename [file nativename [lindex $args 0]]
37  source_ $filename $echo 0
38}
39
40################################################################
41
42set ::sta_continue_on_error 0
43
44define_cmd_args "source" \
45  {[-echo] [-verbose] filename [> filename] [>> filename]}
46
47# Override source to support -echo and return codes.
48proc_redirect source {
49  parse_key_args "source" args keys {-encoding} flags {-echo -verbose}
50  if { [llength $args] != 1 } {
51    cmd_usage_error "source"
52  }
53  set echo [info exists flags(-echo)]
54  set verbose [info exists flags(-verbose)]
55  set filename [file nativename [lindex $args 0]]
56  source_ $filename $echo $verbose
57}
58
59proc source_ { filename echo verbose } {
60  global sta_continue_on_error
61  variable sdc_file
62  variable sdc_line
63  if [catch {open $filename r} stream] {
64    sta_error 511 "cannot open '$filename'."
65  } else {
66    # Save file and line in recursive call to source.
67    if { [info exists sdc_file] } {
68      set sdc_file_save $sdc_file
69      set sdc_line_save $sdc_line
70    }
71    set sdc_file $filename
72    set sdc_line 1
73    set cmd ""
74    set error {}
75    while {![eof $stream]} {
76      gets $stream line
77      if { $line != "" } {
78	if {$echo} {
79	  report_line $line
80	}
81      }
82      append cmd $line "\n"
83      if { [string index $line end] != "\\" \
84	     && [info complete $cmd] } {
85	set error {}
86	set error_code [catch {uplevel \#0 $cmd} result]
87	# cmd consumed
88	set cmd ""
89	# Flush results printed outside tcl to stdout/stderr.
90	fflush
91	switch $error_code {
92	  0 { if { $verbose && $result != "" } { report_line $result } }
93	  1 { set error $result }
94	  2 { set error {invoked "return" outside of a proc.} }
95	  3 { set error {invoked "break" outside of a loop.} }
96	  4 { set error {invoked "continue" outside of a loop.} }
97	}
98	if { $error != {} } {
99	  if { $sta_continue_on_error } {
100	    # Only prepend error message with file/line once.
101	    if { [string first "Error" $error] == 0 } {
102	      report_line $error
103	    } else {
104	      report_line "Error: [file tail $sdc_file], $sdc_line $error"
105	    }
106            set error {}
107          } else {
108	    break
109	  }
110	}
111      }
112      incr sdc_line
113    }
114    close $stream
115    if { $cmd != {} } {
116      sta_error 512 "incomplete command at end of file."
117    }
118    set error_sdc_file $sdc_file
119    set error_sdc_line $sdc_line
120    if { [info exists sdc_file_save] } {
121      set sdc_file $sdc_file_save
122      set sdc_line $sdc_line_save
123    } else {
124      unset sdc_file
125      unset sdc_line
126    }
127    if { $error != {} } {
128      # Only prepend error message with file/line once.
129      if { [string first "Error" $error] == 0 } {
130	error $error
131      } else {
132	error "Error: [file tail $error_sdc_file], $error_sdc_line $error"
133      }
134    }
135  }
136}
137
138################################################################
139
140define_cmd_args "write_sdc" \
141  {[-map_hpins] [-no_timestamp] [-digits digits] filename}
142
143proc write_sdc { args } {
144  parse_key_args "write_sdc" args keys {-digits -significant_digits} \
145    flags {-map_hpins -compatible -no_timestamp}
146  check_argc_eq1 "write_sdc" $args
147
148  set digits 4
149  if { [info exists keys(-digits)] } {
150    set digits $keys(-digits)
151  }
152  if { [info exists keys(-significant_digits)] } {
153    set digits $keys(-significant_digits)
154  }
155  check_positive_integer "-digits" $digits
156
157  set filename [file nativename [lindex $args 0]]
158  set no_timestamp [info exists flags(-no_timestamp)]
159  set map_hpins [info exists flags(-map_hpins)]
160  set native [expr ![info exists flags(-compatible)]]
161  write_sdc_cmd $filename $map_hpins $native $no_timestamp $digits
162}
163
164################################################################
165#
166# General Purpose Commands
167#
168################################################################
169
170define_cmd_args "current_instance" {[instance]}
171
172proc current_instance { {inst ""} } {
173  if { $inst == "" } {
174    set current_instance [top_instance]
175  } else {
176    set current_instance [get_instance_error "instance" $inst]
177  }
178  set cell [get_name [$current_instance cell]]
179  report_line "Current instance is $cell."
180  # Current instance state variable must be part of the sta state so
181  # the tcl interpreter can be shared by multiple sdc files.
182  set_current_instance $current_instance
183}
184
185################################################################
186
187define_cmd_args "set_hierarchy_separator" { seperator }
188
189set ::hierarchy_separator "/"
190
191proc set_hierarchy_separator { separator } {
192  global hierarchy_separator
193  check_path_divider $separator
194  set_path_divider $separator
195  set hierarchy_separator $separator
196}
197
198proc check_path_divider { divider } {
199  set sdc_dividers "/@^#.|"
200  if { !([string length $divider] == 1
201	 && [string first $divider $sdc_dividers] != -1)} {
202    sta_error 513 "hierarchy separator must be one of '$sdc_dividers'."
203  }
204}
205
206################################################################
207
208define_cmd_args "set_units" \
209  {[-time time_unit] [-capacitance cap_unit] [-resistance res_unit]\
210     [-voltage voltage_unit] [-current current_unit] [-power power_unit]\
211     [-distance distance_unit]}
212
213# Note that the set_units command does NOT actually set the units.
214# It merely checks that the current units are the same as the
215# units in the set_units command.
216proc set_units { args } {
217  parse_key_args "set_units" args \
218    keys {-capacitance -resistance -time -voltage -current -power -distance} \
219    flags {}
220  check_argc_eq0 "set_units" $args
221  check_unit "time" -time "s" keys
222  check_unit "capacitance" -capacitance "f" keys
223  check_unit "resistance" -resistance "ohm" keys
224  check_unit "voltage" -voltage "v" keys
225  check_unit "current" -current "A" keys
226  check_unit "power" -power "W" keys
227  check_unit "distance" -distance "m" keys
228}
229
230proc check_unit { unit key unit_name key_var } {
231  upvar 1 $key_var keys
232  if { [info exists keys($key)] } {
233    set value $keys($key)
234    if { [string equal -nocase $value $unit_name] } {
235      check_unit_scale $unit 1.0
236    } else {
237      set prefix [string index $value 0]
238      set suffix [string range $value 1 end]
239      # unit includes "1" prefix
240      if { [string is digit $prefix] } {
241	set prefix [string index $value 1]
242	set suffix [string range $value 2 end]
243      }
244      if { [string equal -nocase $suffix $unit_name] } {
245	set scale [unit_prefix_scale $unit $prefix]
246	check_unit_scale $unit $scale
247      } else {
248	sta_error 514 "unknown unit $unit '$suffix'."
249      }
250    }
251  }
252}
253
254proc unit_prefix_scale { unit prefix } {
255  if { [string equal $prefix "M"] } {
256    return 1E+6
257  } elseif { [string equal $prefix "k"] } {
258    return 1E+3
259  } elseif { [string equal $prefix "m"] } {
260    return 1E-3
261  } elseif { [string equal $prefix "u"] } {
262    return 1E-6
263  } elseif { [string equal $prefix "n"] } {
264    return 1E-9
265  } elseif { [string equal $prefix "p"] } {
266    return 1E-12
267  } elseif { [string equal $prefix "f"] } {
268    return 1E-15
269  } else {
270    sta_error 604 "unknown $unit prefix '$prefix'."
271  }
272}
273
274proc check_unit_scale { unit scale } {
275  set unit_scale [unit_scale $unit]
276  if { ![fuzzy_equal $scale $unit_scale] } {
277    sta_warn 319 "$unit scale [format %.0e $scale] does not match library scale [format %.0e $unit_scale]."
278  }
279}
280
281################################################################
282
283define_cmd_args "set_cmd_units" \
284  {[-capacitance cap_unit] [-resistance res_unit] [-time time_unit]\
285     [-voltage voltage_unit] [-current current_unit] [-power power_unit]\
286     [-distance distance_unit]}
287
288proc set_cmd_units { args } {
289  parse_key_args "set_cmd_units" args \
290    keys {-capacitance -resistance -time -voltage -current -power \
291	    -distance -digits -suffix} \
292    flags {}
293
294  check_argc_eq0 "set_cmd_units" $args
295  set_unit_values "capacitance" -capacitance "f" keys
296  set_unit_values "time" -time "s" keys
297  set_unit_values "voltage" -voltage "v" keys
298  set_unit_values "current" -current "A" keys
299  set_unit_values "resistance" -resistance "ohm" keys
300  set_unit_values "distance" -distance "m" keys
301}
302
303proc set_unit_values { unit key unit_name key_var } {
304  upvar 1 $key_var keys
305  if { [info exists keys($key)] } {
306    set value $keys($key)
307    if { [string equal -nocase $value $unit_name] } {
308      set_cmd_unit_scale $unit 1.0
309    } else {
310      set prefix [string index $value 0]
311      set suffix [string range $value 1 end]
312      # unit includes "1" prefix
313      if { [string is digit $prefix] } {
314	set prefix [string index $value 1]
315	set suffix [string range $value 2 end]
316      }
317      if { [string equal -nocase $suffix $unit_name] } {
318	set scale [unit_prefix_scale $unit $prefix]
319	set_cmd_unit_scale $unit $scale
320      } else {
321	sta_error 515 "unknown $unit unit '$suffix'."
322      }
323    }
324    if [info exists keys(-digits)] {
325      set_cmd_unit_digits $unit $keys(-digits)
326    }
327    if [info exists keys(-suffix)] {
328      set_cmd_unit_suffix $unit $keys(-suffix)
329    }
330  }
331}
332
333################################################################
334#
335# Object Access Commands
336#
337################################################################
338
339define_cmd_args "all_clocks" {}
340
341proc all_clocks { } {
342  set clks {}
343  set clk_iter [clock_iterator]
344  while {[$clk_iter has_next]} {
345    set clk [$clk_iter next]
346    lappend clks $clk
347  }
348  $clk_iter finish
349  return $clks
350}
351
352################################################################
353
354define_cmd_args "all_inputs" {}
355
356proc all_inputs { } {
357  return [all_ports_for_direction "input"]
358}
359
360################################################################
361
362define_cmd_args "all_outputs" {}
363
364proc all_outputs { } {
365  return [all_ports_for_direction "output"]
366}
367
368proc all_ports_for_direction { direction } {
369  set top_instance [top_instance]
370  set top_cell [$top_instance cell]
371  set ports {}
372  set iter [$top_cell port_iterator]
373  while {[$iter has_next]} {
374    set port [$iter next]
375    set port_dir [port_direction $port]
376    if { $port_dir == $direction || $port_dir == "bidirect" } {
377      set ports [concat $ports [port_members $port]]
378    }
379  }
380  $iter finish
381  return $ports
382}
383
384proc port_members { port } {
385  if [$port is_bus] {
386    # Expand bus ports.
387    set ports {}
388    set member_iter [$port member_iterator]
389    while {[$member_iter has_next]} {
390      set bit_port [$member_iter next]
391      lappend ports $bit_port
392    }
393    $member_iter finish
394    return $ports
395  } else {
396    return $port
397  }
398}
399
400################################################################
401
402define_cmd_args all_registers \
403  {[-clock clocks] [-rise_clock clocks] [-fall_clock clocks] [-cells] [-data_pins] [-clock_pins]\
404     [-async_pins] [-output_pins] [-level_sensitive] [-edge_triggered]}
405
406proc all_registers { args } {
407  parse_key_args "all_registers" args keys {-clock -rise_clock -fall_clock} \
408    flags {-cells -data_pins -clock_pins -async_pins -output_pins -level_sensitive -edge_triggered}
409  check_argc_eq0 "all_registers" $args
410
411  set clks {}
412  set clk_rf "rise_fall"
413  if [info exists keys(-clock)] {
414    set clks [get_clocks_warn "clocks" $keys(-clock)]
415  }
416  if [info exists keys(-rise_clock)] {
417    set clks [get_clocks_warn "clocks" $keys(-rise_clock)]
418    set clk_rf "rise"
419  }
420  if [info exists keys(-fall_clock)] {
421    set clks [get_clocks_warn "clocks" $keys(-fall_clock)]
422    set clk_rf "fall"
423  }
424
425  if {[info exists flags(-edge_triggered)] \
426	&& ![info exists flags(-level_sensitive)]} {
427    set edge_triggered 1
428    set level_sensitive 0
429  } elseif {[info exists flags(-level_sensitive)] \
430	      && ![info exists flags(-edge_triggered)]} {
431    set level_sensitive 1
432    set edge_triggered 0
433  } else {
434    set edge_triggered 1
435    set level_sensitive 1
436  }
437  if [info exists flags(-cells)] {
438    return [find_register_instances $clks $clk_rf \
439	      $edge_triggered $level_sensitive]
440  } elseif [info exists flags(-data_pins)] {
441    return [find_register_data_pins $clks $clk_rf \
442	      $edge_triggered $level_sensitive]
443  } elseif [info exists flags(-clock_pins)] {
444    return [find_register_clk_pins $clks $clk_rf \
445	      $edge_triggered $level_sensitive]
446  } elseif [info exists flags(-async_pins)] {
447    return [find_register_async_pins $clks $clk_rf \
448	      $edge_triggered $level_sensitive]
449  } elseif [info exists flags(-output_pins)] {
450    return [find_register_output_pins $clks $clk_rf \
451	      $edge_triggered $level_sensitive]
452  } else {
453    # -cells is the default.
454    return [find_register_instances $clks $clk_rf \
455	      $edge_triggered $level_sensitive]
456  }
457}
458
459################################################################
460
461define_cmd_args "current_design" {[design]}
462
463variable current_design_name ""
464
465proc current_design { {design ""} } {
466  variable current_design_name
467
468  if { $design == "" } {
469    # top_instance errors if the network has not been linked.
470    set current_design_name [get_name [get_object_property [top_instance] cell]]
471  } elseif { ![network_is_linked] } {
472    set current_design_name $design
473    return $design
474  } elseif { [network_is_linked] && $design == [get_name [get_object_property [top_instance] cell]] } {
475    set current_design_name $design
476    return $design
477  } else {
478    sta_warn 320 "current_design for other than top cell not supported."
479    set current_design_name $design
480    return $design
481  }
482}
483
484################################################################
485
486define_cmd_args "get_cells" \
487  {[-hierarchical] [-hsc separator] [-filter expr]\
488     [-regexp] [-nocase] [-quiet] [-of_objects objects] [patterns]}
489
490define_cmd_alias "get_cell" "get_cells"
491
492# Really get_instances, but SDC calls instances "cells".
493proc get_cells { args } {
494  global hierarchy_separator
495
496  parse_key_args "get_cells" args keys {-hsc -filter -of_objects} \
497    flags {-hierarchical -regexp -nocase -quiet}
498  check_argc_eq0or1 "get_cells" $args
499  check_nocase_flag flags
500
501  set regexp [info exists flags(-regexp)]
502  set nocase [info exists flags(-nocase)]
503  set hierarchical [info exists flags(-hierarchical)]
504  set quiet [info exists flags(-quiet)]
505  # Copy backslashes that will be removed by foreach.
506  set patterns [string map {\\ \\\\} [lindex $args 0]]
507  set divider $hierarchy_separator
508  if [info exists keys(-hsc)] {
509    set divider $keys(-hsc)
510    check_path_divider $divider
511  }
512  set insts {}
513  if [info exists keys(-of_objects)] {
514    if { $args != {} } {
515      sta_warn 321 "patterns argument not supported with -of_objects."
516    }
517    parse_port_pin_net_arg $keys(-of_objects) pins nets
518    foreach pin $pins {
519      if { [$pin is_top_level_port] } {
520	set net [get_nets [get_name $pin]]
521	if { $net != "NULL" } {
522	  lappend nets $net
523	}
524      } else {
525	lappend insts [$pin instance]
526      }
527    }
528    foreach net $nets {
529      set pin_iter [$net pin_iterator]
530      while { [$pin_iter has_next] } {
531	set pin [$pin_iter next]
532	lappend insts [$pin instance]
533      }
534      $pin_iter finish
535    }
536  } else {
537    if { $args == {} } {
538      set insts [network_leaf_instances]
539    } else {
540      foreach pattern $patterns {
541	if { $divider != $hierarchy_separator } {
542	  regsub $divider $pattern $hierarchy_separator pattern
543	}
544	if { $hierarchical } {
545	  set matches [find_instances_hier_matching $pattern $regexp $nocase]
546	} else {
547	  set matches [find_instances_matching $pattern $regexp $nocase]
548	}
549	if { $matches == {} && !$quiet} {
550	  sta_warn 322 "instance '$pattern' not found."
551	}
552	set insts [concat $insts $matches]
553      }
554    }
555    if [info exists keys(-filter)] {
556      set insts [filter_insts1 $keys(-filter) $insts]
557    }
558  }
559  return $insts
560}
561
562proc filter_insts1 { filter objects } {
563  variable filter_regexp1
564  variable filter_or_regexp
565  variable filter_and_regexp
566  set filtered_objects {}
567  # Ignore sub-exprs in filter_regexp1 for expr2 match var.
568  if { [regexp $filter_or_regexp $filter ignore expr1 \
569	  ignore ignore ignore expr2] } {
570    regexp $filter_regexp1 $expr1 ignore attr_name op arg
571    set filtered_objects1 [filter_insts $attr_name $op $arg $objects]
572    regexp $filter_regexp1 $expr2 ignore attr_name op arg
573    set filtered_objects2 [filter_insts $attr_name $op $arg $objects]
574    set filtered_objects [concat $filtered_objects1 $filtered_objects2]
575  } elseif { [regexp $filter_and_regexp $filter ignore expr1 \
576		ignore ignore ignore expr2] } {
577    regexp $filter_regexp1 $expr1 ignore attr_name op arg
578    set filtered_objects [filter_insts $attr_name $op $arg $objects]
579    regexp $filter_regexp1 $expr2 ignore attr_name op arg
580    set filtered_objects [filter_insts $attr_name $op $arg $filtered_objects]
581  } elseif { [regexp $filter_regexp1 $filter ignore attr_name op arg] } {
582    set filtered_objects [filter_insts $attr_name $op $arg $objects]
583  } else {
584    sta_error 516 "unsupported -filter expression."
585  }
586  return $filtered_objects
587}
588
589################################################################
590
591define_cmd_args "get_clocks" {[-regexp] [-nocase] [-quiet] patterns}
592
593define_cmd_alias "get_clock" "get_clocks"
594
595proc get_clocks { args } {
596  parse_key_args "get_clocks" args keys {} flags {-regexp -nocase -quiet}
597  check_argc_eq1 "get_clocks" $args
598  check_nocase_flag flags
599
600  # Copy backslashes that will be removed by foreach.
601  set patterns [string map {\\ \\\\} [lindex $args 0]]
602  set regexp [info exists flags(-regexp)]
603  set nocase [info exists flags(-nocase)]
604  set clocks {}
605  foreach pattern $patterns {
606    set matches [find_clocks_matching $pattern $regexp $nocase]
607    if { $matches != {} } {
608      set clocks [concat $clocks $matches]
609    } else {
610      if {![info exists flags(-quiet)]} {
611	sta_warn 323 "clock '$pattern' not found."
612      }
613    }
614  }
615  return $clocks
616}
617
618################################################################
619
620define_cmd_args "get_lib_cells" \
621  {[-hsc separator] [-regexp] [-nocase] [-quiet]\
622     [-of_objects objects] [patterns]}
623
624define_cmd_alias "get_lib_cell" "get_lib_cells"
625
626proc get_lib_cells { args } {
627  global hierarchy_separator
628  parse_key_args "get_lib_cells" args keys {-hsc -of_objects} \
629    flags {-regexp -nocase -quiet}
630  check_argc_eq0or1 "get_lib_cells" $args
631  check_nocase_flag flags
632
633  set regexp [info exists flags(-regexp)]
634  set nocase [info exists flags(-nocase)]
635  set cells {}
636  if [info exists keys(-of_objects)] {
637    if { $args != {} } {
638      sta_warn 324 "positional arguments not supported with -of_objects."
639    }
640    set insts [get_instances_error "objects" $keys(-of_objects)]
641    foreach inst $insts {
642      lappend cells [$inst liberty_cell]
643    }
644  } else {
645    # Copy backslashes that will be removed by foreach.
646    set patterns [string map {\\ \\\\} [lindex $args 0]]
647    # Parse library_name/pattern.
648    set divider $hierarchy_separator
649    if [info exists keys(-hsc)] {
650      set divider $keys(-hsc)
651      check_path_divider $divider
652    }
653    set cell_regexp [cell_regexp_hsc $divider]
654    set quiet [info exists flags(-quiet)]
655    foreach pattern $patterns {
656      if { ![regexp $cell_regexp $pattern ignore lib_name cell_pattern]} {
657	set lib_name "*"
658	set cell_pattern $pattern
659      }
660      # Allow wildcards in the library name (incompatible).
661      set libs [get_libs -quiet $lib_name]
662      if { $libs == {} } {
663	if {!$quiet} {
664	  sta_warn 325 "library '$lib_name' not found."
665	}
666      } else {
667	foreach lib $libs {
668	  set matches [$lib find_liberty_cells_matching $cell_pattern \
669			 $regexp $nocase]
670	  if {$matches != {}} {
671	    set cells [concat $cells $matches]
672	  }
673	}
674	if { $cells == {} } {
675	  if {!$quiet} {
676	    sta_warn 326 "cell '$cell_pattern' not found."
677	  }
678	}
679      }
680    }
681  }
682  return $cells
683}
684
685################################################################
686
687define_cmd_args "get_lib_pins" \
688  {[-hsc separator] [-regexp] [-nocase] [-quiet] patterns}
689
690define_cmd_alias "get_lib_pin" "get_lib_pins"
691
692# "get_lib_ports" in sta terminology.
693proc get_lib_pins { args } {
694  global hierarchy_separator
695  parse_key_args "get_lib_pins" args keys {-hsc} flags {-regexp -nocase -quiet}
696  check_argc_eq1 "get_lib_pins" $args
697  check_nocase_flag flags
698
699  set regexp [info exists flags(-regexp)]
700  set nocase [info exists flags(-nocase)]
701  set quiet [info exists flags(-quiet)]
702  # Copy backslashes that will be removed by foreach.
703  set patterns [string map {\\ \\\\} [lindex $args 0]]
704  # Parse library_name/cell_name/pattern.
705  set divider $hierarchy_separator
706  if [info exists keys(-hsc)] {
707    set divider $keys(-hsc)
708    check_path_divider $divider
709  }
710  set port_regexp1 [port_regexp_hsc $divider]
711  set port_regexp2 [cell_regexp_hsc $divider]
712  set ports {}
713  foreach pattern $patterns {
714    # match library/cell/port
715    set libs {}
716    if { [regexp $port_regexp1 $pattern ignore lib_name cell_name port_pattern] } {
717      set libs [get_libs -quiet $lib_name]
718      # match cell/port
719    } elseif { [regexp $port_regexp2 $pattern ignore cell_name port_pattern] } {
720      set libs [get_libs *]
721    } else {
722      if { !$quiet } {
723	sta_warn 327 "library/cell/port '$pattern' not found."
724      }
725      return {}
726    }
727    if { $libs != {} } {
728      set found_match 0
729      set cells {}
730      foreach lib $libs {
731	set cells [$lib find_liberty_cells_matching $cell_name $regexp $nocase]
732	foreach cell $cells {
733	  set matches [$cell find_liberty_ports_matching $port_pattern \
734			 $regexp $nocase]
735	  foreach match $matches {
736	    lappend ports $match
737	    set found_match 1
738	  }
739	}
740      }
741      if { !$found_match } {
742	if { !$quiet } {
743	  sta_warn 328 "port '$port_pattern' not found."
744	}
745      }
746    } else {
747      if { !$quiet } {
748	sta_warn 329 "library '$lib_name' not found."
749      }
750    }
751  }
752  return $ports
753}
754
755proc check_nocase_flag { flags_var } {
756  upvar 1 $flags_var flags
757  if { [info exists flags(-nocase)] && ![info exists flags(-regexp)] } {
758    sta_warn 330 "-nocase ignored without -regexp."
759  }
760}
761
762################################################################
763
764define_cmd_args "get_libs" {[-regexp] [-nocase] [-quiet] patterns}
765
766define_cmd_alias "get_lib" "get_libs"
767
768proc get_libs { args } {
769  parse_key_args "get_libs" args keys {} flags {-regexp -nocase -quiet}
770  check_argc_eq1 "get_libs" $args
771  check_nocase_flag flags
772
773  # Copy backslashes that will be removed by foreach.
774  set patterns [string map {\\ \\\\} [lindex $args 0]]
775  set regexp [info exists flags(-regexp)]
776  set nocase [info exists flags(-nocase)]
777  set libs {}
778  foreach pattern $patterns {
779    set matches [find_liberty_libraries_matching $pattern $regexp $nocase]
780    if {$matches != {}} {
781      set libs [concat $libs $matches]
782    } else {
783      if {![info exists flags(-quiet)]} {
784	sta_warn 331 "library '$pattern' not found."
785      }
786    }
787  }
788  return $libs
789}
790
791proc find_liberty_libraries_matching { pattern regexp nocase } {
792  # Remove "lib.db:" reference from the library name.
793  set ix [string last ".db:" $pattern]
794  if { $ix != -1 } {
795    set pattern2 [string range $pattern [expr $ix + 4] end]
796  } else {
797    set pattern2 $pattern
798  }
799  if { $regexp } {
800    # Anchor the regexp pattern.
801    set pattern2 "^${pattern}$"
802  }
803  set lib_iter [liberty_library_iterator]
804  set matches {}
805  while { [$lib_iter has_next] } {
806    set lib [$lib_iter next]
807    set lib_name [get_name $lib]
808    if { (!$regexp && [string match $pattern2 $lib_name]) \
809	   || ($regexp && $nocase && [regexp -nocase $pattern2 $lib_name]) \
810	   || ($regexp && !$nocase && [regexp $pattern2 $lib_name]) } {
811      lappend matches $lib
812    }
813  }
814  $lib_iter finish
815  return $matches
816}
817
818################################################################
819
820define_cmd_args "get_nets" \
821  {[-hierarchical] [-hsc separator] [-regexp] [-nocase] [-quiet]\
822     [-of_objects objects] [patterns]}
823
824define_cmd_alias "get_net" "get_nets"
825
826proc get_nets { args } {
827  global hierarchy_separator
828
829  parse_key_args get_nets args keys {-hsc -of_objects} \
830    flags {-hierarchical -regexp -nocase -quiet}
831  check_nocase_flag flags
832
833  set regexp [info exists flags(-regexp)]
834  set nocase [info exists flags(-nocase)]
835  set hierarchical [info exists flags(-hierarchical)]
836  set quiet [info exists flags(-quiet)]
837  # Copy backslashes that will be removed by foreach.
838  set patterns [string map {\\ \\\\} [lindex $args 0]]
839  if [info exists keys(-hsc)] {
840    set divider $keys(-hsc)
841    check_path_divider $divider
842    set patterns [string map "$divider $hierarchy_separator" $patterns]
843  }
844  set nets {}
845  if [info exists keys(-of_objects)] {
846    if { $args != {} } {
847      sta_warn 332 "patterns argument not supported with -of_objects."
848    }
849    parse_inst_pin_arg $keys(-of_objects) insts pins
850    foreach inst $insts {
851      set pin_iter [$inst pin_iterator]
852      while { [$pin_iter has_next] } {
853	set pin [$pin_iter next]
854	lappend nets [$pin net]
855      }
856      $pin_iter finish
857    }
858    foreach pin $pins {
859      lappend nets [$pin net]
860    }
861  } else {
862    check_argc_eq1 "get_nets" $args
863    foreach pattern $patterns {
864      if { $hierarchical } {
865	set matches [find_nets_hier_matching $pattern $regexp $nocase]
866      } else {
867	set matches [find_nets_matching $pattern $regexp $nocase]
868      }
869      set nets [concat $nets $matches]
870      if { $matches == {} && !$quiet } {
871	sta_warn 333 "net '$pattern' not found."
872      }
873    }
874  }
875  return $nets
876}
877
878################################################################
879
880define_cmd_args "get_pins" \
881  {[-hierarchical] [-hsc separator] [-quiet] [-filter expr]\
882     [-regexp] [-nocase] [-of_objects objects] patterns}
883
884define_cmd_alias "get_pin" "get_pins"
885
886proc get_pins { args } {
887  global hierarchy_separator
888
889  parse_key_args "get_pins" args keys {-hsc -of_objects -filter} \
890    flags {-hierarchical -regexp -nocase -quiet}
891  check_nocase_flag flags
892
893  set regexp [info exists flags(-regexp)]
894  set nocase [info exists flags(-nocase)]
895  set hierarchical [info exists flags(-hierarchical)]
896  set quiet [info exists flags(-quiet)]
897  set pins {}
898  if [info exists keys(-of_objects)] {
899    if { $args != {} } {
900      sta_warn 334 "patterns argument not supported with -of_objects."
901    }
902    parse_inst_net_arg $keys(-of_objects) insts nets
903    foreach inst $insts {
904      set pin_iter [$inst pin_iterator]
905      while { [$pin_iter has_next] } {
906	set pin [$pin_iter next]
907	lappend pins $pin
908      }
909      $pin_iter finish
910    }
911    foreach net $nets {
912      set pin_iter [$net pin_iterator]
913      while { [$pin_iter has_next] } {
914	set pin [$pin_iter next]
915	lappend pins $pin
916      }
917      $pin_iter finish
918    }
919  } else {
920    check_argc_eq1 "get_pins" $args
921    set patterns [lindex $args 0]
922    if [info exists keys(-hsc)] {
923      set divider $keys(-hsc)
924      check_path_divider $divider
925      set patterns [string map "$divider $hierarchy_separator" $patterns]
926    }
927    # Copy backslashes that will be removed by foreach.
928    set patterns [string map {\\ \\\\} $patterns]
929    foreach pattern $patterns {
930      if { $hierarchical } {
931	set matches [find_pins_hier_matching $pattern $regexp $nocase]
932      } else {
933	set matches [find_pins_matching $pattern $regexp $nocase]
934      }
935      set pins [concat $pins $matches]
936      if { $matches == {} && !$quiet } {
937	sta_warn 335 "pin '$pattern' not found."
938      }
939    }
940  }
941  if [info exists keys(-filter)] {
942    set pins [filter_pins1 $keys(-filter) $pins]
943  }
944  return $pins
945}
946
947proc filter_pins1 { filter objects } {
948  variable filter_regexp1
949  variable filter_or_regexp
950  variable filter_and_regexp
951  set filtered_objects {}
952  # Ignore sub-exprs in filter_regexp1 for expr2 match var.
953  if { [regexp $filter_or_regexp $filter ignore expr1 \
954	  ignore ignore ignore expr2] } {
955    regexp $filter_regexp1 $expr1 ignore attr_name op arg
956    set filtered_objects1 [filter_pins $attr_name $op $arg $objects]
957    regexp $filter_regexp1 $expr2 ignore attr_name op arg
958    set filtered_objects2 [filter_pins $attr_name $op $arg $objects]
959    set filtered_objects [concat $filtered_objects1 $filtered_objects2]
960  } elseif { [regexp $filter_and_regexp $filter ignore expr1 \
961		ignore ignore ignore expr2] } {
962    regexp $filter_regexp1 $expr1 ignore attr_name op arg
963    set filtered_objects [filter_pins $attr_name $op $arg $objects]
964    regexp $filter_regexp1 $expr2 ignore attr_name op arg
965    set filtered_objects [filter_pins $attr_name $op $arg $filtered_objects]
966  } elseif { [regexp $filter_regexp1 $filter ignore attr_name op arg] } {
967    set filtered_objects [filter_pins $attr_name $op $arg $objects]
968  } else {
969    sta_error 517 "unsupported -filter expression."
970  }
971  return $filtered_objects
972}
973
974################################################################
975
976define_cmd_args "get_ports" \
977  {[-quiet] [-filter expr] [-regexp] [-nocase] [-of_objects objects] [patterns]}
978
979define_cmd_alias "get_port" "get_ports"
980
981# Find top level design ports matching pattern.
982proc get_ports { args } {
983  parse_key_args "get_ports" args keys {-of_objects -filter} \
984    flags {-regexp -nocase -quiet}
985  check_nocase_flag flags
986
987  set regexp [info exists flags(-regexp)]
988  set nocase [info exists flags(-nocase)]
989  # Copy backslashes that will be removed by foreach.
990  set patterns [string map {\\ \\\\} [lindex $args 0]]
991  set ports {}
992  if [info exists keys(-of_objects)] {
993    if { $args != {} } {
994      sta_warn 336 "patterns argument not supported with -of_objects."
995    }
996    set nets [get_nets_warn "objects" $keys(-of_objects)]
997    foreach net $nets {
998      set ports [concat $ports [$net ports]]
999    }
1000  } else {
1001    check_argc_eq1 "get_ports" $args
1002    foreach pattern $patterns {
1003      set matches [find_ports_matching $pattern $regexp $nocase]
1004      if { $matches != {} } {
1005	set ports [concat $ports $matches]
1006      } else {
1007	if {![info exists flags(-quiet)]} {
1008	  sta_warn 337 "port '$pattern' not found."
1009	}
1010      }
1011    }
1012  }
1013  if [info exists keys(-filter)] {
1014    set ports [filter_ports1 $keys(-filter) $ports]
1015  }
1016  return $ports
1017}
1018
1019variable filter_regexp1 {@?([a-zA-Z_]+) *(==|=~) *([0-9a-zA-Z_\*]+)}
1020variable filter_or_regexp "($filter_regexp1) +\\|\\| +($filter_regexp1)"
1021variable filter_and_regexp "($filter_regexp1) +&& +($filter_regexp1)"
1022
1023proc filter_ports1 { filter objects } {
1024  variable filter_regexp1
1025  variable filter_or_regexp
1026  variable filter_and_regexp
1027  set filtered_objects {}
1028  # Ignore sub-exprs in filter_regexp1 for expr2 match var.
1029  if { [regexp $filter_or_regexp $filter ignore expr1 \
1030	  ignore ignore ignore expr2] } {
1031    regexp $filter_regexp1 $expr1 ignore attr_name op arg
1032    set filtered_objects1 [filter_ports $attr_name $op $arg $objects]
1033    regexp $filter_regexp1 $expr2 ignore attr_name op arg
1034    set filtered_objects2 [filter_ports $attr_name $op $arg $objects]
1035    set filtered_objects [concat $filtered_objects1 $filtered_objects2]
1036  } elseif { [regexp $filter_and_regexp $filter ignore expr1 \
1037		ignore ignore ignore expr2] } {
1038    regexp $filter_regexp1 $expr1 ignore attr_name op arg
1039    set filtered_objects [filter_ports $attr_name $op $arg $objects]
1040    regexp $filter_regexp1 $expr2 ignore attr_name op arg
1041    set filtered_objects [filter_ports $attr_name $op $arg $filtered_objects]
1042  } elseif { [regexp $filter_regexp1 $filter ignore attr_name op arg] } {
1043    set filtered_objects [filter_ports $attr_name $op $arg $objects]
1044  } else {
1045    sta_error 518 "unsupported -filter expression."
1046  }
1047  return $filtered_objects
1048}
1049
1050################################################################
1051#
1052# Timing Constraints
1053#
1054################################################################
1055
1056define_cmd_args "create_clock" \
1057  {[-name name] [-period period] [-waveform waveform] [-add]\
1058     [-comment comment] [pins]}
1059
1060proc create_clock { args } {
1061  parse_key_args "create_clock" args \
1062    keys {-name -period -waveform -comment} \
1063    flags {-add}
1064
1065  check_argc_eq0or1 "create_clock" $args
1066  set argc [llength $args]
1067  if { $argc == 0 } {
1068    set pins {}
1069  } elseif { $argc == 1 } {
1070    set pins [get_port_pins_error "pins" [lindex $args 0]]
1071  }
1072
1073  set add [info exists flags(-add)]
1074  if [info exists keys(-name)] {
1075    set name $keys(-name)
1076  } elseif { $pins != {} } {
1077    if { $add } {
1078      sta_error 519 "-add requires -name."
1079    }
1080    # Default clock name is the first pin name.
1081    set name [get_full_name [lindex $pins 0]]
1082  } else {
1083    sta_error 520 "-name or port_pin_list must be specified."
1084  }
1085
1086  if [info exists keys(-period)] {
1087    set period $keys(-period)
1088    check_positive_float "period" $period
1089    set period [time_ui_sta $period]
1090  } else {
1091    sta_error 521 "missing -period argument."
1092  }
1093
1094  if [info exists keys(-waveform)] {
1095    set wave_arg $keys(-waveform)
1096    if { [expr [llength $wave_arg] % 2] != 0 } {
1097      sta_error 522 "-waveform edge_list must have an even number of edge times."
1098    }
1099    set first_edge 1
1100    set prev_edge 0
1101    set waveform {}
1102    foreach edge $wave_arg {
1103      check_float "-waveform edge" $edge
1104      set edge [time_ui_sta $edge]
1105      if { $first_edge && $edge > $period } {
1106	set edge [expr $edge - $period]
1107      }
1108      if { !$first_edge && $edge < $prev_edge } {
1109	sta_warn 338 "adjusting non-increasing clock -waveform edge times."
1110	set edge [expr $edge + $period]
1111      }
1112      if { $edge > [expr $period * 2] } {
1113	sta_warn 339 "-waveform time greater than two periods."
1114      }
1115      lappend waveform $edge
1116      set prev_edge $edge
1117      set first_edge 0
1118    }
1119  } else {
1120    set waveform [list 0 [expr $period / 2.0]]
1121  }
1122
1123  set comment [parse_comment_key keys]
1124
1125  make_clock $name $pins $add $period $waveform $comment
1126}
1127
1128################################################################
1129
1130define_cmd_args "create_generated_clock" \
1131  {[-name clock_name] -source master_pin [-master_clock clock]\
1132     [-divide_by divisor | -multiply_by multiplier]\
1133     [-duty_cycle duty_cycle] [-invert] [-edges edge_list]\
1134     [-edge_shift edge_shift_list] [-combinational] [-add]\
1135     [-pll_output pll_out_pin] [-pll_feedback pll_fdbk_pin]\
1136     [-comment comment] port_pin_list}
1137
1138proc create_generated_clock { args } {
1139  parse_key_args "create_generated_clock" args keys \
1140    {-name -source -master_clock -divide_by -multiply_by \
1141       -duty_cycle -edges -edge_shift -pll_output -pll_feedback -comment} \
1142    flags {-invert -combinational -add}
1143
1144  check_argc_eq1 "create_generated_clock" $args
1145  parse_port_pin_net_arg [lindex $args 0] pins nets
1146  # Convert net args to net driver pin.
1147  foreach net $nets {
1148    set drivers [net_driver_pins $net]
1149    if { $drivers != {} } {
1150      lappend pins [lindex $drivers 0]
1151    }
1152  }
1153  if { $pins == {} } {
1154    sta_error 523 "empty ports/pins/nets argument."
1155  }
1156  set add [info exists flags(-add)]
1157
1158  if [info exists keys(-name)] {
1159    set name $keys(-name)
1160  } elseif { $pins != {} } {
1161    if { $add } {
1162      sta_error 524 "-add requires -name."
1163    }
1164    # Default clock name is the first pin name.
1165    set name [get_full_name [lindex $pins 0]]
1166  } else {
1167    sta_error 525 "name or port_pin_list must be specified."
1168  }
1169
1170  if [info exists keys(-source)] {
1171    set source $keys(-source)
1172    set source_pin [get_port_pin_error "master_pin" $source]
1173  } else {
1174    sta_error 526 "missing -source argument."
1175  }
1176
1177  set master_clk "NULL"
1178  set divide_by 0
1179  set multiply_by 0
1180  set duty_cycle 0
1181  set edges {}
1182  set edge_shifts {}
1183  set pll_out "NULL"
1184  set pll_feedback "NULL"
1185
1186  set combinational [info exists flags(-combinational)]
1187
1188  if {[info exists keys(-master_clock)]} {
1189    set master_clk [get_clock_error "-master_clk" $keys(-master_clock)]
1190    if { $master_clk == "NULL" } {
1191      sta_error 527 "-master_clock argument empty."
1192    }
1193  } elseif { $add } {
1194    sta_error 528 "-add requireds -master_clock."
1195  }
1196
1197  if {[info exists keys(-divide_by)] && [info exists keys(-multiply_by)]} {
1198    sta_error 529 "-multiply_by and -divide_by options are exclusive."
1199  } elseif {[info exists keys(-divide_by)]} {
1200    set divide_by $keys(-divide_by)
1201    if {![string is integer $divide_by] || $divide_by < 1} {
1202      sta_error 530 "-divide_by is not an integer greater than one."
1203    }
1204    if {$combinational && $divide_by != 1} {
1205      sta_error 531 "-combinational implies -divide_by 1."
1206    }
1207  } elseif {[info exists keys(-multiply_by)]} {
1208    set multiply_by $keys(-multiply_by)
1209    if {![string is integer $multiply_by] || $multiply_by < 1} {
1210      sta_error 532 "-multiply_by is not an integer greater than one."
1211    }
1212    if {[info exists keys(-duty_cycle)]} {
1213      set duty_cycle $keys(-duty_cycle)
1214      if {![string is double $duty_cycle] \
1215	    || $duty_cycle < 0.0 || $duty_cycle > 100.0} {
1216	sta_error 533 "-duty_cycle is not a float between 0 and 100."
1217      }
1218    }
1219  } elseif {[info exists keys(-edges)]} {
1220    set edges $keys(-edges)
1221    if { [llength $edges] != 3 } {
1222      sta_error 534 "-edges only supported for three edges."
1223    }
1224    set prev_edge [expr [lindex $edges 0] - 1]
1225    foreach edge $edges {
1226      check_cardinal "-edges" $edge
1227      if { $edge <= $prev_edge } {
1228	sta_error 535 "edges times are not monotonically increasing."
1229      }
1230    }
1231    if [info exists keys(-edge_shift)] {
1232      foreach shift $keys(-edge_shift) {
1233	check_float "-edge_shift" $shift
1234	lappend edge_shifts [time_ui_sta $shift]
1235      }
1236      if { [llength $edge_shifts] != [llength $edges] } {
1237	sta_error 536 "-edge_shift length does not match -edges length."
1238      }
1239    }
1240  } elseif { $combinational } {
1241    set divide_by 1
1242  } else {
1243    sta_error 537 "missing -multiply_by, -divide_by, -combinational or -edges argument."
1244  }
1245
1246  set invert 0
1247  if {[info exists flags(-invert)]} {
1248    if {!([info exists keys(-divide_by)] \
1249	    || [info exists keys(-multiply_by)] \
1250	    || [info exists flags(-combinational)])} {
1251      sta_error 538 "cannot specify -invert without -multiply_by, -divide_by or -combinational."
1252    }
1253    set invert 1
1254  }
1255
1256  if {[info exists keys(-duty_cycle)] && ![info exists keys(-multiply_by)]} {
1257    sta_error 539 "-duty_cycle requires -multiply_by value."
1258  }
1259
1260  if { [info exists keys(-pll_feedback)] || [info exists keys(-pll_output)] } {
1261    if {![info exists keys(-pll_output)] } {
1262      sta_error 540 "missing -pll_output argument."
1263    }
1264    if { ![info exists keys(-pll_feedback)] } {
1265      sta_error 541 "missing -pll_feedback argument."
1266    }
1267    set pll_feedback [get_pin_error "-pll_feedback" $keys(-pll_feedback)]
1268    set pll_out [get_pin_error "-pll_output" $keys(-pll_output)]
1269    set pll_inst [$pll_out instance]
1270    if { [$pll_feedback instance] != $pll_inst } {
1271      sta_error 542 "PLL output and feedback pins must be on the same instance."
1272    }
1273    if { [$source_pin instance] != $pll_inst } {
1274      sta_error 543 "source pin must be on the same instance as the PLL output pin."
1275    }
1276    if { [lsearch $pins $pll_out] == -1 } {
1277      sta_error 544 "PLL output must be one of the clock pins."
1278    }
1279  }
1280
1281  set comment [parse_comment_key keys]
1282
1283  make_generated_clock $name $pins $add $source_pin $master_clk \
1284    $pll_out $pll_feedback \
1285    $divide_by $multiply_by $duty_cycle $invert $combinational \
1286    $edges $edge_shifts $comment
1287}
1288
1289################################################################
1290
1291define_cmd_args "group_path" \
1292  {-name group_name [-weight weight] [-critical_range range]\
1293     [-default] [-comment comment]\
1294     [-from from_list] [-rise_from from_list] [-fall_from from_list]\
1295     [-through through_list] [-rise_through through_list]\
1296     [-fall_through through_list] [-to to_list] [-rise_to to_list]\
1297     [-fall_to to_list]}
1298
1299# The -weight and -critical_range arguments are ignored.
1300proc group_path { args } {
1301  parse_key_args "group_path" args \
1302    keys {-name -weight -critical_range \
1303	    -from -rise_from -fall_from \
1304	    -to -rise_to -fall_to -comment} \
1305    flags {-default} 0
1306
1307  set cmd "group_path"
1308  set arg_error 0
1309  set from [parse_from_arg keys arg_error]
1310  set thrus [parse_thrus_arg args arg_error]
1311  set to [parse_to_arg1 keys "rise_fall" arg_error]
1312  check_exception_pins $from $to
1313  if { $arg_error } {
1314    delete_from_thrus_to $from $thrus $to
1315    sta_error 545 "group_path command failed."
1316    return 0
1317  }
1318
1319  check_for_key_args $cmd args
1320  if { $args != {} } {
1321    delete_from_thrus_to $from $thrus $to
1322    sta_error 546 "positional arguments not supported."
1323  }
1324  if { ($from == "NULL" && $thrus == "" && $to == "NULL") } {
1325    delete_from_thrus_to $from $thrus $to
1326    sta_error 547 "-from, -through or -to required."
1327  }
1328
1329  set default [info exists flags(-default)]
1330  set name_exists [info exists keys(-name)]
1331  if { $default && $name_exists } {
1332    sta_error 548 "-name and -default are mutually exclusive."
1333  } elseif { !$name_exists && !$default } {
1334    sta_error 549 "-name or -default option is required."
1335  } elseif { $default } {
1336    set name ""
1337  } else {
1338    set name $keys(-name)
1339  }
1340
1341  set comment [parse_comment_key keys]
1342
1343  make_group_path $name $default $from $thrus $to $comment
1344}
1345
1346proc check_exception_pins { from to } {
1347  variable sdc_file
1348  variable sdc_line
1349  if { [info exists sdc_file] } {
1350    set file $sdc_file
1351    set line $sdc_line
1352  } else {
1353    set file ""
1354    set line 0
1355  }
1356  check_exception_from_pins $from $file $line
1357  check_exception_to_pins $to $file $line
1358}
1359
1360################################################################
1361
1362define_cmd_args "set_clock_gating_check" \
1363  {[-setup setup_time] [-hold hold_time] [-rise] [-fall]\
1364     [-low] [-high] [objects]}
1365
1366proc set_clock_gating_check { args } {
1367  parse_key_args "set_clock_gating_check" args keys {-setup -hold } \
1368    flags {-rise -fall -high -low}
1369
1370  check_argc_eq0or1 "set_clock_gating_check" $args
1371  set tr [parse_rise_fall_flags flags]
1372
1373  set active_value ""
1374  if {[info exists flags(-high)] && [info exists flags(-low)]} {
1375    sta_error 550 "cannot specify both -high and -low."
1376  } elseif [info exists flags(-low)] {
1377    set active_value "0"
1378  } elseif [info exists flags(-high)] {
1379    set active_value "1"
1380  }
1381
1382  if { !([info exists keys(-hold)] || [info exists keys(-setup)]) } {
1383    sta_error 551 "missing -setup or -hold argument."
1384  }
1385  if [info exists keys(-hold)] {
1386    set_clock_gating_check1 $args $tr "min" $keys(-hold) $active_value
1387  }
1388  if [info exists keys(-setup)] {
1389    set_clock_gating_check1 $args $tr "max" $keys(-setup) $active_value
1390  }
1391}
1392
1393proc set_clock_gating_check1 { args tr setup_hold margin active_value } {
1394  set margin [time_ui_sta $margin]
1395  if { [llength $args] == 0 } {
1396    if { $active_value != "" } {
1397      sta_error 552 "-high and -low only permitted for pins and instances."
1398    }
1399    set_clock_gating_check_cmd $tr $setup_hold $margin
1400  } elseif { [llength $args] == 1 } {
1401    parse_clk_inst_port_pin_arg [lindex $args 0] clks insts pins
1402
1403    if { $clks != {} && $active_value != "" } {
1404      sta_error 553 "-high and -low only permitted for pins and instances."
1405    }
1406    foreach clk $clks {
1407      set_clock_gating_check_clk_cmd $clk $tr $setup_hold $margin
1408    }
1409
1410    if { $active_value == "" } {
1411      set active_value "X"
1412    }
1413    foreach pin $pins {
1414      set_clock_gating_check_pin_cmd $pin $tr $setup_hold \
1415	$margin $active_value
1416    }
1417    foreach inst $insts {
1418      set_clock_gating_check_instance_cmd $inst $tr $setup_hold \
1419	$margin $active_value
1420    }
1421  }
1422}
1423
1424################################################################
1425
1426define_cmd_args "set_clock_groups" \
1427  {[-name name] [-logically_exclusive] [-physically_exclusive]\
1428     [-asynchronous] [-allow_paths] [-comment comment] -group clocks}
1429
1430proc set_clock_groups { args } {
1431  parse_key_args "set_clock_groups" args \
1432    keys {-name -comment} \
1433    flags {-logically_exclusive -physically_exclusive \
1434	     -asynchronous -allow_paths} 0
1435
1436  if {[info exists keys(-name)]} {
1437    set name $keys(-name)
1438  } else {
1439    set name ""
1440  }
1441  set logically_exclusive [info exists flags(-logically_exclusive)]
1442  set physically_exclusive [info exists flags(-physically_exclusive)]
1443  set asynchronous [info exists flags(-asynchronous)]
1444  set allow_paths [info exists flags(-allow_paths)]
1445
1446  if { ($logically_exclusive+$physically_exclusive+$asynchronous) == 0 } {
1447    sta_error 554 "one of -logically_exclusive, -physically_exclusive or -asynchronous is required."
1448  }
1449  if { ($logically_exclusive+$physically_exclusive+$asynchronous) > 1 } {
1450    sta_error 555 "the keywords -logically_exclusive, -physically_exclusive and -asynchronous are mutually exclusive."
1451  }
1452
1453  set comment [parse_comment_key keys]
1454
1455  set clk_groups [make_clock_groups $name $logically_exclusive \
1456		    $physically_exclusive $asynchronous $allow_paths \
1457		    $comment]
1458
1459  while { $args != "" } {
1460    set arg [lindex $args 0]
1461    if {[string match $arg "-group"]} {
1462      set group_clks [get_clocks_warn "clocks" [lindex $args 1]]
1463      if { $group_clks != {} } {
1464	clock_groups_make_group $clk_groups $group_clks
1465      }
1466      set args [lrange $args 2 end]
1467    } else {
1468      if {[is_keyword_arg $arg]} {
1469	sta_warn 349 "unknown keyword argument $arg."
1470      } else {
1471	sta_warn 341 "extra positional argument $arg."
1472      }
1473      set args [lrange $args 1 end]
1474    }
1475  }
1476}
1477
1478################################################################
1479
1480define_cmd_args "set_clock_latency" \
1481  {[-source] [-clock clock] [-rise] [-fall] [-min] [-max]\
1482     [-early] [-late] delay objects}
1483
1484proc set_clock_latency { args } {
1485  parse_key_args "set_clock_latency" args keys {-clock} \
1486    flags {-rise -fall -min -max -source -late -early}
1487
1488  check_argc_eq2 "set_clock_latency" $args
1489
1490  set delay [lindex $args 0]
1491  check_float "delay" $delay
1492  set delay [time_ui_sta $delay]
1493  set objects [lindex $args 1]
1494
1495  parse_clk_port_pin_arg $objects clks pins
1496
1497  set tr [parse_rise_fall_flags flags]
1498  set min_max [parse_min_max_all_flags flags]
1499
1500  set pin_clk "NULL"
1501  if { [info exists keys(-clock)] } {
1502    set pin_clk [get_clock_warn "clock" $keys(-clock)]
1503    if { $clks != {} } {
1504      sta_warn 342 "-clock ignored for clock objects."
1505    }
1506  }
1507
1508  if {[info exists flags(-source)]} {
1509    # Insertion delay (source latency).
1510    set early_late [parse_early_late_all_flags flags]
1511
1512    foreach clk $clks {
1513      set_clock_insertion_cmd $clk "NULL" $tr $min_max $early_late $delay
1514    }
1515    foreach pin $pins {
1516      # Source only allowed on clocks and clock pins.
1517      if { ![is_clock_src $pin] } {
1518	sta_error 556 "-source '[get_full_name $pin]' is not a clock pin."
1519      }
1520      set_clock_insertion_cmd $pin_clk $pin $tr $min_max $early_late $delay
1521    }
1522  } else {
1523    # Latency.
1524    if {[info exists flags(-early)] || [info exists flags(-late)]} {
1525      sta_error 557 "-early/-late is only allowed with -source."
1526    }
1527
1528    foreach clk $clks {
1529      set_clock_latency_cmd $clk "NULL" $tr $min_max $delay
1530    }
1531    foreach pin $pins {
1532      set_clock_latency_cmd $pin_clk $pin $tr $min_max $delay
1533    }
1534  }
1535}
1536
1537################################################################
1538
1539define_cmd_args "set_sense" \
1540  {[-type clock|data] [-positive] [-negative] [-pulse pulse_type]\
1541     [-stop_propagation] [-clocks clocks] pins}
1542
1543proc set_sense { args } {
1544  parse_key_args "set_sense" args keys {-type} flags {} 0
1545
1546  set type "clock"
1547  if { [info exists keys(-type)] } {
1548    set type $keys(-type)
1549    if { $type == "data" } {
1550      sta_warn 343 "set_sense -type data not supported."
1551    } elseif { $type == "clock" } {
1552      set_clock_sense_cmd1 "set_sense" $args
1553    } else {
1554      sta_error 558 "set_sense -type clock|data"
1555    }
1556  }
1557}
1558
1559# deprecated in SDC 2.1
1560define_cmd_args "set_clock_sense" \
1561  {[-positive] [-negative] [-pulse pulse_type] [-stop_propagation] \
1562     [-clock clocks] pins}
1563
1564proc set_clock_sense { args } {
1565  sta_warn 344 "set_clock_sense is deprecated as of SDC 2.1. Use set_sense -type clock."
1566  set_clock_sense_cmd1 "set_clock_sense" $args
1567}
1568
1569proc set_clock_sense_cmd1 { cmd cmd_args } {
1570  # SDC uses -clock, OT, OC use -clocks
1571  parse_key_args $cmd cmd_args keys {-clock -clocks -pulse} \
1572    flags {-positive -negative -stop_propagation} 0
1573  check_argc_eq1 $cmd $cmd_args
1574
1575  set pulse [info exists keys(-pulse)]
1576  if { $pulse } {
1577    sta_warn 345 "-pulse argument not supported."
1578  }
1579  set positive [info exists flags(-positive)]
1580  set negative [info exists flags(-negative)]
1581  set stop_propagation [info exists flags(-stop_propagation)]
1582  if { ($positive && ($negative || $stop_propagation || $pulse)) \
1583	 || ($negative && ($positive || $stop_propagation || $pulse)) \
1584	 || ($stop_propagation && ($positive || $negative || $pulse))
1585       || ($pulse && ($positive || $negative || $stop_propagation)) } {
1586    sta_warn 346 "-positive, -negative, -stop_propagation and -pulse are mutually exclusive."
1587  }
1588
1589  set pins [get_port_pins_error "pins" [lindex $cmd_args 0]]
1590  set clks {}
1591  if {[info exists keys(-clock)]} {
1592    set clks [get_clocks_warn "clock" $keys(-clock)]
1593  }
1594  if {[info exists keys(-clocks)]} {
1595    set clks [get_clocks_warn "clocks" $keys(-clocks)]
1596  }
1597  foreach pin $pins {
1598    if {[$pin is_hierarchical]} {
1599      sta_warn 347 "hierarchical pin '[get_full_name $pin]' not supported."
1600    }
1601  }
1602  set_clock_sense_cmd $pins $clks $positive $negative $stop_propagation
1603}
1604
1605################################################################
1606
1607define_cmd_args "set_clock_transition" \
1608  {[-rise] [-fall] [-min] [-max] transition clocks}
1609
1610proc set_clock_transition { args } {
1611  parse_key_args "set_clock_transition" args keys {} \
1612    flags {-rise -fall -max -min}
1613
1614  set tr [parse_rise_fall_flags flags]
1615  set min_max [parse_min_max_all_flags flags]
1616  check_argc_eq2 "set_clock_transition" $args
1617
1618  set slew [lindex $args 0]
1619  set clks [get_clocks_warn "clocks" [lindex $args 1]]
1620
1621  foreach clk $clks {
1622    if { [$clk is_virtual] } {
1623      sta_warn 559 "transition time can not be specified for virtual clocks."
1624    } else {
1625      set_clock_slew_cmd $clk $tr $min_max [time_ui_sta $slew]
1626    }
1627  }
1628}
1629
1630################################################################
1631
1632# -rise/-fall are obsolete.
1633define_cmd_args "set_clock_uncertainty" \
1634  {[-from|-rise_from|-fall_from from_clock]\
1635     [-to|-rise_to|-fall_to to_clock] [-rise] [-fall]\
1636     [-setup] [-hold] uncertainty [objects]}
1637
1638proc set_clock_uncertainty { args } {
1639  parse_key_args "set_clock_uncertainty" args \
1640    keys {-from -rise_from -fall_from -to -rise_to -fall_to} \
1641    flags {-rise -fall -setup -hold}
1642
1643  if { [llength $args] == 0 } {
1644    sta_error 560 "missing uncertainty value."
1645  }
1646  set uncertainty [lindex $args 0]
1647  check_float "uncertainty" $uncertainty
1648  set uncertainty [time_ui_sta $uncertainty]
1649
1650  set min_max "min_max"
1651  if { [info exists flags(-setup)] && ![info exists flags(-hold)] } {
1652    set min_max "max"
1653  }
1654  if { [info exists flags(-hold)] && ![info exists flags(-setup)] } {
1655    set min_max "min"
1656  }
1657
1658  if { [info exists keys(-from)] } {
1659    set from_key "-from"
1660    set from_rf "rise_fall"
1661  } elseif { [info exists keys(-rise_from)] } {
1662    set from_key "-rise_from"
1663    set from_rf "rise"
1664  } elseif { [info exists keys(-fall_from)] } {
1665    set from_key "-fall_from"
1666    set from_rf "fall"
1667  } else {
1668    set from_key "none"
1669  }
1670
1671  if { [info exists keys(-to)] } {
1672    set to_key "-to"
1673    set to_rf "rise_fall"
1674  } elseif { [info exists keys(-rise_to)] } {
1675    set to_key "-rise_to"
1676    set to_rf "rise"
1677  } elseif { [info exists keys(-fall_to)] } {
1678    set to_key "-fall_to"
1679    set to_rf "fall"
1680  } else {
1681    set to_key "none"
1682  }
1683
1684  if { $from_key != "none" && $to_key == "none" \
1685	 || $from_key == "none" && $to_key != "none" } {
1686    sta_error 561 "-from/-to must be used together."
1687  } elseif { $from_key != "none" && $to_key != "none" } {
1688    # Inter-clock uncertainty.
1689    check_argc_eq1 "-from/-to" $args
1690
1691    # -from/-to can be lists.
1692    set from_clks [get_clocks_warn "from_clocks" $keys($from_key)]
1693    set to_clks [get_clocks_warn "to_clocks" $keys($to_key)]
1694
1695    foreach from_clk $from_clks {
1696      foreach to_clk $to_clks {
1697	set_inter_clock_uncertainty $from_clk $from_rf \
1698	  $to_clk $to_rf $min_max $uncertainty
1699      }
1700    }
1701  } else {
1702    # Single clock uncertainty.
1703    check_argc_eq2 "set_clock_uncertainty" $args
1704    if { [info exists flags(-rise)] \
1705	   || [info exists flags(-fall)] } {
1706      sta_error 562 "-rise, -fall options not allowed for single clock uncertainty."
1707    }
1708    set objects [lindex $args 1]
1709    parse_clk_port_pin_arg $objects clks pins
1710
1711    foreach clk $clks {
1712      set_clock_uncertainty_clk $clk $min_max $uncertainty
1713    }
1714    foreach pin $pins {
1715      set_clock_uncertainty_pin $pin $min_max $uncertainty
1716    }
1717  }
1718}
1719
1720################################################################
1721
1722define_cmd_args "set_data_check" \
1723  {[-from from_pin] [-rise_from from_pin] [-fall_from from_pin]\
1724     [-to to_pin] [-rise_to to_pin] [-fall_to to_pin]\
1725     [-setup | -hold] [-clock clock] margin}
1726
1727proc set_data_check { args } {
1728  parse_key_args "set_data_check" args \
1729    keys {-from -rise_from -fall_from -to -rise_to -fall_to -clock} \
1730    flags {-setup -hold}
1731  check_argc_eq1 "set_data_check" $args
1732
1733  set margin [time_ui_sta $args]
1734  set from_rf "rise_fall"
1735  set to_rf "rise_fall"
1736  set clk "NULL"
1737
1738  if [info exists keys(-from)] {
1739    set from [get_port_pin_error "from_pin" $keys(-from)]
1740  } elseif [info exists keys(-rise_from)] {
1741    set from [get_port_pin_error "from_pin" $keys(-rise_from)]
1742    set from_rf "rise"
1743  } elseif [info exists keys(-fall_from)] {
1744    set from [get_port_pin_error "from_pin" $keys(-fall_from)]
1745    set from_rf "fall"
1746  } else {
1747    sta_error 563 "missing -from, -rise_from or -fall_from argument."
1748  }
1749
1750  if [info exists keys(-to)] {
1751    set to [get_port_pin_error "to_pin" $keys(-to)]
1752  } elseif [info exists keys(-rise_to)] {
1753    set to [get_port_pin_error "to_pin" $keys(-rise_to)]
1754    set to_rf "rise"
1755  } elseif [info exists keys(-fall_to)] {
1756    set to [get_port_pin_error "to_pin" $keys(-fall_to)]
1757    set to_rf "fall"
1758  } else {
1759    sta_error 564 "missing -to, -rise_to or -fall_to argument."
1760  }
1761
1762  if [info exists keys(-clock)] {
1763    set clk [get_clock_warn "clock" $keys(-clock)]
1764  }
1765
1766  if { [info exists flags(-setup)] && ![info exists flags(-hold)] } {
1767    set setup_hold "setup"
1768  } elseif { [info exists flags(-hold)] && ![info exists flags(-setup)] } {
1769    set setup_hold "hold"
1770  } else {
1771    set setup_hold "setup_hold"
1772  }
1773
1774  set_data_check_cmd $from $from_rf $to $to_rf $clk $setup_hold $margin
1775}
1776
1777################################################################
1778
1779define_cmd_args "set_disable_timing" \
1780  {[-from from_port] [-to to_port] objects}
1781
1782# Parallax supports -from or -to alone.
1783# OT requires both -from and -to args.
1784proc set_disable_timing { args } {
1785  parse_key_args "set_disable_timing" args keys {-from -to} flags {}
1786  check_argc_eq1 "set_disable_timing" $args
1787
1788  set from {}
1789  if { [info exists keys(-from)] } {
1790    set from $keys(-from)
1791  }
1792  set to {}
1793  if { [info exists keys(-to)] } {
1794    set to $keys(-to)
1795  }
1796  parse_libcell_libport_inst_port_pin_edge_timing_arc_set_arg $args \
1797    libcells libports insts ports pins edges timing_arc_sets
1798
1799  if { ([info exists keys(-from)] || [info exists keys(-to)]) \
1800	 && ($libports != {} || $pins != {} || $ports != {}) } {
1801    sta_warn 348 "-from/-to keywords ignored for lib_pin, port and pin arguments."
1802  }
1803
1804  foreach libcell $libcells {
1805    set_disable_timing_cell $libcell $from $to
1806  }
1807  foreach libport $libports {
1808    disable_lib_port $libport
1809  }
1810  foreach inst $insts {
1811    set_disable_timing_instance $inst $from $to
1812  }
1813  foreach pin $pins {
1814    disable_pin $pin
1815  }
1816  foreach port $ports {
1817    disable_port $port
1818  }
1819  foreach edge $edges {
1820    disable_edge $edge
1821  }
1822  foreach timing_arc_set $timing_arc_sets {
1823    disable_timing_arc_set $timing_arc_set
1824  }
1825}
1826
1827proc set_disable_timing_instance { inst from to } {
1828  set from_ports [parse_disable_inst_ports $inst $from]
1829  set to_ports [parse_disable_inst_ports $inst $to]
1830  if { ![$inst is_leaf] } {
1831    sta_error 565 "-from/-to hierarchical instance not supported."
1832  }
1833  if { $from_ports == "NULL" && $to_ports == "NULL" } {
1834    disable_instance $inst "NULL" "NULL"
1835  } elseif { $from_ports == "NULL" } {
1836    foreach to_port $to_ports {
1837      disable_instance $inst "NULL" $to_port
1838    }
1839  } elseif { $to_ports == "NULL" } {
1840    foreach from_port $from_ports {
1841      disable_instance $inst $from_port "NULL"
1842    }
1843  } else {
1844    foreach from_port $from_ports {
1845      foreach to_port $to_ports {
1846	disable_instance $inst $from_port $to_port
1847      }
1848    }
1849  }
1850}
1851
1852# Find ports in inst's cell that have pins.
1853# Bus ports are expanded into a list.
1854proc parse_disable_inst_ports { inst port_name } {
1855  global hierarchy_separator
1856
1857  if { $port_name == "" } {
1858    set ports "NULL"
1859  } else {
1860    set cell [instance_property $inst cell]
1861    set port [$cell find_port $port_name]
1862    if { $port == "NULL" } {
1863      sta_error 566 "pin '[get_full_name $inst]${hierarchy_separator}${port_name}' not found."
1864    } else {
1865      set lib_port [get_property $port liberty_port]
1866      set ports [port_members $lib_port]
1867    }
1868  }
1869  return $ports
1870}
1871
1872proc set_disable_timing_cell { cell from to } {
1873  set from_ports [parse_disable_cell_ports $cell $from]
1874  set to_ports [parse_disable_cell_ports $cell $to]
1875  if { $from_ports == "NULL" && $to_ports == "NULL" } {
1876    disable_cell $cell "NULL" "NULL"
1877  } elseif { $from_ports == "NULL" } {
1878    foreach to_port $to_ports {
1879      disable_cell $cell "NULL" $to_port
1880    }
1881  } elseif { $to_ports == "NULL" } {
1882    foreach from_port $from_ports {
1883      disable_cell $cell $from_port "NULL"
1884    }
1885  } else {
1886    foreach from_port $from_ports {
1887      foreach to_port $to_ports {
1888	disable_cell $cell $from_port $to_port
1889      }
1890    }
1891  }
1892}
1893
1894# Find cell ports.
1895# Bus ports are expanded into a list.
1896proc parse_disable_cell_ports { cell port_name } {
1897  global hierarchy_separator
1898
1899  if { $port_name == "" } {
1900    set ports "NULL"
1901  } else {
1902    set port [$cell find_liberty_port $port_name]
1903    if { $port == "NULL" } {
1904      sta_error 567 "pin '[get_name $cell]${hierarchy_separator}${port_name}' not found."
1905    } else {
1906      set ports [port_members $port]
1907    }
1908  }
1909  return $ports
1910}
1911
1912################################################################
1913
1914define_cmd_args "set_false_path" \
1915  {[-setup] [-hold] [-rise] [-fall] [-reset_path] [-comment comment]\
1916     [-from from_list] [-rise_from from_list] [-fall_from from_list]\
1917     [-through through_list] [-rise_through through_list]\
1918     [-fall_through through_list] [-to to_list] [-rise_to to_list]\
1919     [-fall_to to_list]}
1920
1921proc set_false_path { args } {
1922  parse_key_args "set_false_path" args \
1923    keys {-from -rise_from -fall_from -to -rise_to -fall_to -comment} \
1924    flags {-setup -hold -rise -fall -reset_path} 0
1925
1926  set min_max "min_max"
1927  if { [info exists flags(-setup)] && ![info exists flags(-hold)] } {
1928    set min_max "max"
1929  }
1930  if { [info exists flags(-hold)] && ![info exists flags(-setup)] } {
1931    set min_max "min"
1932  }
1933
1934  set cmd "set_false_path"
1935  set arg_error 0
1936  set from [parse_from_arg keys arg_error]
1937  set thrus [parse_thrus_arg args arg_error]
1938  set to [parse_to_arg keys flags arg_error]
1939  check_exception_pins $from $to
1940  if { $arg_error } {
1941    delete_from_thrus_to $from $thrus $to
1942  } else {
1943    check_for_key_args $cmd args
1944    if { $args != {} } {
1945      sta_warn 600 "'$args' ignored."
1946    }
1947    if { ($from == "NULL" && $thrus == "" && $to == "NULL") } {
1948      delete_from_thrus_to $from $thrus $to
1949      sta_warn 350 "-from, -through or -to required."
1950    } else {
1951      if [info exists flags(-reset_path)] {
1952	reset_path_cmd $from $thrus $to $min_max
1953      }
1954
1955      set comment [parse_comment_key keys]
1956
1957      make_false_path $from $thrus $to $min_max $comment
1958    }
1959  }
1960}
1961
1962################################################################
1963
1964define_cmd_args "set_ideal_latency" \
1965  {[-rise] [-fall] [-min] [-max] delay objects}
1966
1967proc set_ideal_latency { args } {
1968  # ignored
1969}
1970
1971################################################################
1972
1973# Specifies net has zero weight for placement.
1974define_cmd_args "set_ideal_net" { nets }
1975
1976################################################################
1977
1978define_cmd_args "set_ideal_network" {[-no_propagation] objects}
1979
1980proc set_ideal_network { args } {
1981  # ignored
1982}
1983
1984################################################################
1985
1986define_cmd_args "set_ideal_transition" \
1987  {[-rise] [-fall] [-min] [-max] transition_time objects}
1988
1989proc set_ideal_transition { args } {
1990  # ignored
1991}
1992
1993################################################################
1994
1995define_cmd_args "set_input_delay" \
1996  {[-rise] [-fall] [-max] [-min]\
1997     [-clock clock] [-clock_fall]\
1998     [-reference_pin ref_pin]\
1999     [-source_latency_included] [-network_latency_included]\
2000     [-add_delay] delay port_pin_list}
2001
2002proc set_input_delay { args } {
2003  set_port_delay "set_input_delay" "set_input_delay_cmd" $args \
2004    {"input" "bidirect"}
2005}
2006
2007proc set_port_delay { cmd sta_cmd cmd_args port_dirs } {
2008  parse_key_args $cmd cmd_args \
2009    keys {-clock -reference_pin} \
2010    flags {-rise -fall -max -min -clock_fall -add_delay \
2011	     -source_latency_included -network_latency_included}
2012  check_argc_eq2 $cmd $cmd_args
2013
2014  set delay_arg [lindex $cmd_args 0]
2015  check_float "delay" $delay_arg
2016  set delay [time_ui_sta $delay_arg]
2017  set pins [get_port_pins_error "pins" [lindex $cmd_args 1]]
2018
2019  set clk "NULL"
2020  if [info exists keys(-clock)] {
2021    set clk [get_clock_warn "clock" $keys(-clock)]
2022  }
2023
2024  set ref_pin "NULL"
2025  if [info exists keys(-reference_pin)] {
2026    set ref_pin [get_port_pin_error "ref_pin" $keys(-reference_pin)]
2027    if { [info exists flags(-source_latency_included)] } {
2028      sta_warn 351 "-source_latency_included ignored with -reference_pin."
2029    }
2030    if { [info exists flags(-network_latency_included)] } {
2031      sta_warn 352 "-network_latency_included ignored with -reference_pin."
2032    }
2033  }
2034
2035  if [info exists flags(-clock_fall)] {
2036    set clk_rf "fall"
2037  } else {
2038    set clk_rf "rise"
2039  }
2040
2041  set tr [parse_rise_fall_flags flags]
2042  set min_max [parse_min_max_all_flags flags]
2043  set add [info exists flags(-add_delay)]
2044  set source_latency_included [info exists flags(-source_latency_included)]
2045  set network_latency_included [info exists flags(-network_latency_included)]
2046
2047  foreach pin $pins {
2048    if { [$pin is_top_level_port] \
2049	   && [lsearch $port_dirs [pin_direction $pin]] == -1 } {
2050      sta_warn 353 "$cmd not allowed on [pin_direction $pin] port '[get_full_name $pin]'."
2051    } elseif { $clk != "NULL" && [lsearch [$clk sources] $pin] != -1 } {
2052      sta_warn 354 "$cmd relative to a clock defined on the same port/pin not allowed."
2053    } else {
2054      $sta_cmd $pin $tr $clk $clk_rf $ref_pin\
2055	$source_latency_included $network_latency_included \
2056	$min_max $add $delay
2057    }
2058  }
2059}
2060
2061################################################################
2062
2063define_cmd_args "set_max_delay" \
2064  {[-rise] [-fall] [-ignore_clock_latency] [-reset_path] [-comment comment]\
2065     [-from from_list] [-rise_from from_list] [-fall_from from_list]\
2066     [-through through_list] [-rise_through through_list]\
2067     [-fall_through through_list]\
2068     [-to to_list] [-rise_to to_list] [-fall_to to_list] delay}
2069
2070proc set_max_delay { args } {
2071  set_path_delay "set_max_delay" $args max
2072}
2073
2074proc set_path_delay { cmd args min_max } {
2075  parse_key_args $cmd args \
2076    keys {-from -rise_from -fall_from -to -rise_to -fall_to -comment} \
2077    flags {-rise -fall -ignore_clock_latency -reset_path} 0
2078
2079  set arg_error 0
2080  set from [parse_from_arg keys arg_error]
2081  set thrus [parse_thrus_arg args arg_error]
2082  set to [parse_to_arg keys flags arg_error]
2083  if { $arg_error } {
2084    delete_from_thrus_to $from $thrus $to
2085  } else {
2086    check_for_key_args $cmd args
2087    if { [llength $args] == 0 } {
2088      delete_from_thrus_to $from $thrus $to
2089      sta_error 568 "missing delay argument."
2090    } elseif { [llength $args] == 1 } {
2091      set delay $args
2092      check_float "$cmd delay" $delay
2093      set delay [time_ui_sta $delay]
2094    } else {
2095      sta_warn 355 "'$args' ignored."
2096    }
2097
2098    set ignore_clk_latency [info exists flags(-ignore_clock_latency)]
2099
2100    if [info exists flags(-reset_path)] {
2101      reset_path_cmd $from $thrus $to "all"
2102    }
2103
2104    set comment [parse_comment_key keys]
2105
2106    make_path_delay $from $thrus $to $min_max $ignore_clk_latency \
2107      $delay $comment
2108  }
2109}
2110
2111################################################################
2112
2113define_cmd_args "set_max_time_borrow" {limit objects}
2114
2115proc set_max_time_borrow { limit objects } {
2116  check_positive_float "borrow_limit" $limit
2117  set limit [time_ui_sta $limit]
2118  parse_clk_inst_pin_arg $objects clks insts pins
2119  foreach pin $pins {
2120    set_latch_borrow_limit_pin $pin $limit
2121  }
2122  foreach inst $insts {
2123    set_latch_borrow_limit_inst $inst $limit
2124  }
2125  foreach clk $clks {
2126    set_latch_borrow_limit_clk $clk $limit
2127  }
2128}
2129
2130################################################################
2131
2132define_cmd_args "set_min_delay" \
2133  {[-rise] [-fall] [-ignore_clock_latency] [-reset_path] [-comment comment]\
2134     [-from from_list] [-rise_from from_list] [-fall_from from_list]\
2135     [-through through_list] [-rise_through through_list]\
2136     [-fall_through through_list]\
2137     [-to to_list] [-rise_to to_list] [-fall_to to_list] delay}
2138
2139proc set_min_delay { args } {
2140  set_path_delay "set_min_delay" $args min
2141}
2142
2143################################################################
2144
2145define_cmd_args "set_min_pulse_width" {[-low] [-high] value [objects]}
2146
2147proc set_min_pulse_width { args } {
2148  parse_key_args "set_min_pulse_width" args keys {} flags {-low -high}
2149  check_argc_eq1or2 "set_min_pulse_width" $args
2150
2151  if { [info exists flags(-low)] } {
2152    set hi_low "fall"
2153  } elseif { [info exists flags(-high)] } {
2154    set hi_low "rise"
2155  } else {
2156    set hi_low "rise_fall"
2157  }
2158
2159  set min_width [lindex $args 0]
2160  check_positive_float "min pulse width" $min_width
2161  set min_width [time_ui_sta $min_width]
2162
2163  if { [llength $args] == 2 } {
2164    set objects [lindex $args 1]
2165    parse_clk_inst_pin_arg $objects clks insts pins
2166    foreach pin $pins {
2167      set_min_pulse_width_pin $pin $hi_low $min_width
2168    }
2169    foreach inst $insts {
2170      set_min_pulse_width_inst $inst $hi_low $min_width
2171    }
2172    foreach clk $clks {
2173      set_min_pulse_width_clk $clk $hi_low $min_width
2174    }
2175  } else {
2176    set_min_pulse_width_global $hi_low $min_width
2177  }
2178}
2179
2180################################################################
2181
2182define_cmd_args "set_multicycle_path" \
2183  {[-setup] [-hold] [-rise] [-fall] [-start] [-end]\
2184     [-reset_path] [-comment comment]\
2185     [-from from_list] [-rise_from from_list]\
2186     [-fall_from from_list] [-through through_list]\
2187     [-rise_through through_list] [-fall_through through_list]\
2188     [-to to_list] [-rise_to to_list] [-fall_to to_list] path_multiplier}
2189
2190proc set_multicycle_path { args } {
2191  parse_key_args "set_multicycle_path" args \
2192    keys {-from -rise_from -fall_from -to -rise_to -fall_to -comment} \
2193    flags {-setup -hold -rise -fall -start -end -reset_path} 0
2194
2195  set min_max "min_max"
2196  set use_end_clk 1
2197  if { [info exists flags(-setup)] && ![info exists flags(-hold)] } {
2198    # -setup
2199    set min_max "max"
2200    set use_end_clk 1
2201  }
2202  if { [info exists flags(-hold)] && ![info exists flags(-setup)] } {
2203    # -hold
2204    set min_max "min"
2205    set use_end_clk 0
2206  }
2207
2208  set cmd "set_multicycle_path"
2209  set arg_error 0
2210  set from [parse_from_arg keys arg_error]
2211  set thrus [parse_thrus_arg args arg_error]
2212  set to [parse_to_arg keys flags arg_error]
2213  check_exception_pins $from $to
2214  if { $arg_error } {
2215    delete_from_thrus_to $from $thrus $to
2216  } else {
2217    check_for_key_args $cmd args
2218    if { [llength $args] == 0 } {
2219      delete_from_thrus_to $from $thrus $to
2220      sta_error 569 "missing path multiplier argument."
2221    } elseif { [llength $args] == 1 } {
2222      set path_multiplier $args
2223      check_integer "path multiplier" $path_multiplier
2224    } else {
2225      sta_warn 356 "'$args' ignored."
2226    }
2227
2228    set start [info exists flags(-start)]
2229    set end [info exists flags(-end)]
2230    if { $start && $end } {
2231      delete_from_thrus_to $from $thrus $to
2232      sta_error 570 "cannot use -start with -end."
2233    } elseif { $start } {
2234      set use_end_clk 0
2235    } elseif { $end } {
2236      set use_end_clk 1
2237    }
2238
2239    if [info exists flags(-reset_path)] {
2240      reset_path_cmd $from $thrus $to $min_max
2241    }
2242
2243    set comment [parse_comment_key keys]
2244
2245    make_multicycle_path $from $thrus $to $min_max $use_end_clk \
2246      $path_multiplier $comment
2247  }
2248}
2249
2250################################################################
2251
2252define_cmd_args "set_output_delay" \
2253  {[-rise] [-fall] [-max] [-min]\
2254     [-clock clock] [-clock_fall]\
2255     [-reference_pin ref_pin]\
2256     [-source_latency_included] [-network_latency_included]\
2257     [-add_delay] delay port_pin_list}
2258
2259proc set_output_delay { args } {
2260  set_port_delay "set_output_delay" "set_output_delay_cmd" $args \
2261    {"output" "tristate" "bidirect"}
2262}
2263
2264################################################################
2265
2266define_cmd_args "set_propagated_clock" {objects}
2267
2268proc set_propagated_clock { objects } {
2269  parse_clk_port_pin_arg $objects clks pins
2270  foreach clk $clks {
2271    if { [$clk is_virtual] } {
2272      sta_warn 357 "virtual clock [get_name $clk] can not be propagated."
2273    } else {
2274      set_propagated_clock_cmd $clk
2275    }
2276  }
2277  foreach pin $pins {
2278    set_propagated_clock_pin_cmd $pin
2279  }
2280}
2281
2282################################################################
2283#
2284# Environment Commands
2285#
2286################################################################
2287
2288define_cmd_args "set_case_analysis" \
2289  {0|1|zero|one|rise|rising|fall|falling pins}
2290
2291proc set_case_analysis { value pins } {
2292  if { !($value == "0" \
2293	   || $value == "1" \
2294	   || $value == "zero" \
2295	   || $value == "one" \
2296	   || $value == "rise" \
2297	   || $value == "rising" \
2298	   || $value == "fall" \
2299	   || $value == "falling") } {
2300    sta_error 571 "value must be 0, zero, 1, one, rise, rising, fall, or falling."
2301  }
2302  set pins1 [get_port_pins_error "pins" $pins]
2303  foreach pin $pins1 {
2304    set_case_analysis_cmd $pin $value
2305  }
2306}
2307
2308################################################################
2309
2310define_cmd_args "set_drive" {[-rise] [-fall] [-min] [-max] \
2311			       resistance ports}
2312
2313proc set_drive { args } {
2314  parse_key_args "set_drive" args keys {} flags {-rise -fall -min -max}
2315  set tr [parse_rise_fall_flags flags]
2316  set min_max [parse_min_max_all_check_flags flags]
2317
2318  check_argc_eq2 "set_drive" $args
2319
2320  set res [lindex $args 0]
2321  check_positive_float "resistance" $res
2322  set res [resistance_ui_sta $res]
2323  set ports [get_ports_error "ports" [lindex $args 1]]
2324  foreach port $ports {
2325    set_drive_resistance_cmd $port $tr $min_max $res
2326  }
2327}
2328
2329################################################################
2330
2331define_cmd_args "set_driving_cell" \
2332  {[-lib_cell cell] [-library library]\
2333     [-rise] [-fall] [-min] [-max]\
2334     [-pin pin] [-from_pin from_pin]\
2335     [-input_transition_rise trans_rise] [-input_transition_fall trans_fall]\
2336     [-multiply_by factor] [-dont_scale] [-no_design_rule] ports}
2337
2338proc set_driving_cell { args } {
2339  parse_key_args "set_driving_cell" args \
2340    keys {-lib_cell -cell -library -pin -from_pin -multiply_by \
2341	    -input_transition_rise -input_transition_fall} \
2342    flags {-rise -fall -min -max -dont_scale -no_design_rule}
2343
2344  set tr [parse_rise_fall_flags flags]
2345  set min_max [parse_min_max_all_flags flags]
2346
2347  # -cell is an undocumented non-sdc alias for -lib_cell.
2348  if { [info exists keys(-cell)] } {
2349    set keys(-lib_cell) $keys(-cell)
2350  }
2351
2352  if { [info exists keys(-lib_cell)] } {
2353    set cell_name $keys(-lib_cell)
2354    if { [info exists keys(-library)] } {
2355      set library [get_liberty_error "library" $keys(-library)]
2356      set cell [$library find_liberty_cell $cell_name]
2357      if { $cell == "NULL" } {
2358	sta_error 572 "cell '$lib_name:$cell_name' not found."
2359      }
2360    } else {
2361      set library "NULL"
2362      set cell [find_liberty_cell $cell_name]
2363      if { $cell == "NULL" } {
2364	sta_error 573 "'$cell_name' not found."
2365      }
2366    }
2367  } else {
2368    sta_error 574 "missing -lib_cell argument."
2369  }
2370
2371  set to_port "NULL"
2372  if [info exists keys(-pin)] {
2373    set to_port_name $keys(-pin)
2374    set to_port [$cell find_liberty_port $to_port_name]
2375    if { $to_port == "NULL" } {
2376      sta_error 575 "port '$to_port_name' not found."
2377    }
2378  } else {
2379    set port_iter [$cell liberty_port_iterator]
2380    set output_count 0
2381    while {[$port_iter has_next]} {
2382      set port [$port_iter next]
2383      set dir [liberty_port_direction $port]
2384      if { [port_direction_any_output $dir] } {
2385	incr output_count
2386	if { $output_count > 1 } {
2387	  $port_iter finish
2388	  sta_error 576 "-pin argument required for cells with multiple outputs."
2389	}
2390	set to_port $port
2391	# No break.  Keep looking for output ports to make sure there
2392	# is only one.
2393      }
2394    }
2395    $port_iter finish
2396  }
2397
2398  set from_port "NULL"
2399  if [info exists keys(-from_pin)] {
2400    set from_port_name $keys(-from_pin)
2401    set from_port [$cell find_liberty_port $from_port_name]
2402    if { $from_port == "NULL" } {
2403      sta_error 577 "port '$from_port_name' not found."
2404    }
2405  }
2406
2407  set from_slew_rise 0
2408  if [info exists keys(-input_transition_rise)] {
2409    set from_slew_rise $keys(-input_transition_rise)
2410    check_positive_float "-input_transition_rise" $from_slew_rise
2411    set from_slew_rise [time_ui_sta $from_slew_rise]
2412  }
2413  set from_slew_fall 0
2414  if [info exists keys(-input_transition_fall)] {
2415    set from_slew_fall $keys(-input_transition_fall)
2416    check_positive_float "-input_transition_fall" $from_slew_fall
2417    set from_slew_fall [time_ui_sta $from_slew_fall]
2418  }
2419
2420  if [info exists keys(-multiply_by)] {
2421    sta_warn 358 "-multiply_by ignored."
2422  }
2423  if [info exists flags(-dont_scale)] {
2424    sta_warn 359 "-dont_scale ignored."
2425  }
2426  if [info exists flags(-no_design_rule)] {
2427    sta_warn 360 "-no_design_rule ignored."
2428  }
2429
2430  check_argc_eq1 "set_driving_cell" $args
2431
2432  set ports [get_ports_error "ports" [lindex $args 0]]
2433  foreach port $ports {
2434    set_drive_cell_cmd $library $cell $port $from_port \
2435      $from_slew_rise $from_slew_fall $to_port $tr $min_max
2436  }
2437}
2438
2439################################################################
2440
2441define_cmd_args "set_fanout_load" {fanout ports}
2442
2443proc set_fanout_load { fanout port_list } {
2444  sta_warn 601 "set_fanout_load not supported."
2445}
2446
2447################################################################
2448
2449define_cmd_args "set_input_transition" \
2450  {[-rise] [-fall] [-min] [-max] transition ports}
2451
2452proc set_input_transition { args } {
2453  parse_key_args "set_input_transition" args keys {-clock -clock_fall} \
2454    flags {-rise -fall -max -min}
2455
2456  set tr [parse_rise_fall_flags flags]
2457  set min_max [parse_min_max_all_flags flags]
2458
2459
2460  check_argc_eq2 "set_input_transition" $args
2461
2462  set slew [lindex $args 0]
2463  check_positive_float "transition" $slew
2464  set slew [time_ui_sta $slew]
2465  set ports [get_ports_error "ports" [lindex $args 1]]
2466
2467  if [info exists keys(-clock)] {
2468    sta_warn 361 "-clock not supported."
2469  }
2470  if [info exists keys(-clock_fall)] {
2471    sta_warn 362 "-clock_fall not supported."
2472  }
2473
2474  foreach port $ports {
2475    set_input_slew_cmd $port $tr $min_max $slew
2476  }
2477}
2478
2479################################################################
2480
2481define_cmd_args "set_load" \
2482  {[-rise] [-fall] [-max] [-min] [-subtract_pin_load]\
2483     [-pin_load] [-wire_load] capacitance objects}
2484
2485proc set_load { args } {
2486  parse_key_args "set_load" args keys {-corner} \
2487    flags {-rise -fall -min -max -subtract_pin_load -pin_load -wire_load}\
2488
2489  check_argc_eq2 "set_load" $args
2490
2491  set pin_load [info exists flags(-pin_load)]
2492  set wire_load [info exists flags(-wire_load)]
2493  set subtract_pin_load [info exists flags(-subtract_pin_load)]
2494  set corner [parse_corner_or_all keys]
2495  set min_max [parse_min_max_all_check_flags flags]
2496  set tr [parse_rise_fall_flags flags]
2497
2498  set cap [lindex $args 0]
2499  check_positive_float "capacitance" $cap
2500  set cap [capacitance_ui_sta $cap]
2501  parse_port_net_args [lindex $args 1] ports nets
2502
2503  if { $ports != {} } {
2504    # -pin_load is the default.
2505    if { $pin_load || (!$pin_load && !$wire_load) } {
2506      foreach port $ports {
2507	set_port_pin_cap $port $tr $min_max $cap
2508      }
2509    } elseif { $wire_load } {
2510      foreach port $ports {
2511	set_port_wire_cap $port $subtract_pin_load $tr $min_max $cap
2512      }
2513    }
2514  }
2515  if { $nets != {} } {
2516    if { $pin_load } {
2517      sta_warn 363 "-pin_load not allowed for net objects."
2518    }
2519    if { $wire_load } {
2520      sta_warn 364 "-wire_load not allowed for net objects."
2521    }
2522    if { $tr != "rise_fall" } {
2523      sta_warn 365 "-rise/-fall not allowed for net objects."
2524    }
2525    foreach net $nets {
2526      set_net_wire_cap $net $subtract_pin_load $corner $min_max $cap
2527    }
2528  }
2529}
2530
2531################################################################
2532
2533define_cmd_args "set_logic_dc" {port_list}
2534
2535proc set_logic_dc { port_list } {
2536  set_logic_value $port_list "X"
2537}
2538
2539# OT supports set_logic cmds on pins.
2540# OC only supports them on ports.
2541proc set_logic_value { port_list value } {
2542  set pins [get_port_pins_error "pins" $port_list]
2543  foreach pin $pins {
2544    set_logic_value_cmd $pin $value
2545  }
2546}
2547
2548################################################################
2549
2550define_cmd_args "set_logic_one" {port_list}
2551
2552proc set_logic_one { port_list } {
2553  set_logic_value $port_list "1"
2554}
2555
2556################################################################
2557
2558define_cmd_args "set_logic_zero" {port_list}
2559
2560proc set_logic_zero { port_list } {
2561  set_logic_value $port_list "0"
2562}
2563
2564################################################################
2565
2566define_cmd_args "set_max_area" {area}
2567
2568proc set_max_area { area } {
2569  check_positive_float "area" $area
2570  set_max_area_cmd $area
2571}
2572
2573################################################################
2574
2575define_cmd_args "set_max_capacitance" {cap objects}
2576
2577proc set_max_capacitance { cap objects } {
2578  set_capacitance_limit $cap "max" $objects
2579}
2580
2581proc set_capacitance_limit { cap min_max objects } {
2582  parse_cell_port_pin_args $objects cells ports pins
2583  check_positive_float "limit" $cap
2584  set cap [capacitance_ui_sta $cap]
2585  foreach cell $cells {
2586    set_cell_capacitance_limit $cell $min_max $cap
2587  }
2588  foreach port $ports {
2589    set_port_capacitance_limit $port $min_max $cap
2590  }
2591  foreach pin $pins {
2592    set_pin_capacitance_limit $pin $min_max $cap
2593  }
2594}
2595
2596################################################################
2597
2598define_cmd_args "set_max_fanout" {fanout objects}
2599
2600proc set_max_fanout { fanout objects } {
2601  set_fanout_limit $fanout "max" $objects
2602}
2603
2604proc set_fanout_limit { fanout min_max objects } {
2605  check_positive_float "limit" $fanout
2606  parse_cell_port_args $objects cells ports
2607  foreach port $ports {
2608    set dir [port_direction $port]
2609    if { !($dir == "input" || $dir == "bidirect") } {
2610      sta_error 578 "port '[get_name $port]' is not an input."
2611    }
2612    set_port_fanout_limit $port $min_max $fanout
2613  }
2614  foreach cell $cells {
2615    set_cell_fanout_limit $cell $min_max $fanout
2616  }
2617}
2618
2619################################################################
2620
2621define_cmd_args "set_max_transition" \
2622  {[-clock_path] [-data_path] [-rise] [-fall] slew objects}
2623
2624proc set_max_transition { args } {
2625  parse_key_args "set_max_transition" args keys {} \
2626    flags {-clock_path -data_path -rise -fall}
2627  check_argc_eq2 "set_max_transition" $args
2628
2629  set slew [lindex $args 0]
2630  check_positive_float "transition" $slew
2631  set slew [time_ui_sta $slew]
2632
2633  set objects [lindex $args 1]
2634  parse_clk_cell_port_args $objects clks cells ports
2635
2636  set tr [parse_rise_fall_flags flags]
2637
2638  set path_types {}
2639  if { ![info exists flags(-clock_path)] \
2640	 && ![info exists flags(-data_path)] } {
2641    # Derate clk and data if neither -clock_path or -data_path.
2642    set path_types {"clk" "data"}
2643  }
2644  if { [info exists flags(-clock_path)] } {
2645    lappend path_types "clk"
2646  }
2647  if { [info exists flags(-data_path)] } {
2648    lappend path_types "data"
2649  }
2650
2651  if { ($ports != {} || $cells != {}) \
2652	 && ([info exists flags(-clock_path)] \
2653	       || [info exists flags(-data_path)]
2654	     || [info exists flags(-rise)]
2655	     || [info exists flags(-fall)]) } {
2656    sta_warn 366 "-data_path, -clock_path, -rise, -fall ignored for ports and designs."
2657  }
2658
2659  # -clock_path/-data_path and transition only apply to clock objects.
2660  foreach path_type $path_types {
2661    foreach clk $clks {
2662      set_slew_limit_clk $clk $tr $path_type "max" $slew
2663    }
2664  }
2665  foreach cell $cells {
2666    set_slew_limit_cell $cell "max" $slew
2667  }
2668  foreach port $ports {
2669    set_slew_limit_port $port "max" $slew
2670  }
2671}
2672
2673################################################################
2674
2675define_cmd_args "set_port_fanout_number" \
2676  {[-max] [-min] fanout ports}
2677
2678proc set_port_fanout_number { args } {
2679  parse_key_args "set_port_fanout_number" args keys {} flags {-max -min}
2680  set min_max [parse_min_max_all_check_flags flags]
2681
2682  check_argc_eq2 "set_port_fanout_number" $args
2683
2684  set fanout [lindex $args 0]
2685  check_positive_integer "fanout" $fanout
2686  set ports [get_ports_error "ports" [lindex $args 1]]
2687  foreach port $ports {
2688    set_port_ext_fanout_cmd $port $fanout $min_max
2689  }
2690}
2691
2692################################################################
2693
2694define_cmd_args "set_resistance" {[-min] [-max] resistance nets}
2695
2696proc set_resistance { args } {
2697  parse_key_args "set_resistance" args keys {} flags {-max -min}
2698  set min_max [parse_min_max_all_check_flags flags]
2699
2700  check_argc_eq2 "set_resistance" $args
2701
2702  set res [lindex $args 0]
2703  check_positive_float "resistance" $res
2704  set res [resistance_ui_sta $res]
2705  set nets [get_nets_error "nets" [lindex $args 1]]
2706  foreach net $nets {
2707    set_net_resistance $net $min_max $res
2708  }
2709}
2710
2711################################################################
2712
2713define_cmd_args "set_timing_derate" \
2714  {-early|-late [-rise] [-fall] [-clock] [-data] \
2715     [-net_delay] [-cell_delay] [-cell_check] derate [objects]}
2716
2717proc set_timing_derate { args } {
2718  parse_key_args "set_timing_derate" args keys {} \
2719    flags {-rise -fall -early -late -clock -data \
2720	     -net_delay -cell_delay -cell_check}
2721  check_argc_eq1or2 "set_timing_derate" $args
2722
2723  set derate [lindex $args 0]
2724  check_float "derate" $derate
2725  if { $derate > 2.0 } {
2726    sta_warn 367 "derating factor greater than 2.0."
2727  }
2728
2729  set tr [parse_rise_fall_flags flags]
2730  set early_late [parse_early_late_flags flags]
2731
2732  set path_types {}
2733  if { ![info exists flags(-clock)] \
2734	 && ![info exists flags(-data)] } {
2735    # Derate clk and data if neither -clock or -data.
2736    lappend path_types "clk"
2737    lappend path_types "data"
2738  }
2739  if { [info exists flags(-clock)] } {
2740    lappend path_types "clk"
2741  }
2742  if { [info exists flags(-data)] } {
2743    lappend path_types "data"
2744  }
2745
2746  set derate_types {}
2747  if { [info exists flags(-net_delay)] } {
2748    lappend derate_types "net_delay"
2749  }
2750  if { [info exists flags(-cell_delay)] } {
2751    lappend derate_types "cell_delay"
2752  }
2753  if { [info exists flags(-cell_check)] } {
2754    lappend derate_types "cell_check"
2755  }
2756
2757  if { [llength $args] == 2 } {
2758    set objects [lindex $args 1]
2759    parse_libcell_inst_net_arg $objects libcells insts nets
2760    if { $nets != {} } {
2761      if { [info exists flags(-cell_delay)] \
2762	     || [info exists flags(-cell_check)] } {
2763	sta_warn 368 "-cell_delay and -cell_check flags ignored for net objects."
2764      }
2765      foreach net $nets {
2766	foreach path_type $path_types {
2767	  set_timing_derate_net_cmd $net $path_type $tr $early_late $derate
2768	}
2769      }
2770    }
2771    if { ![info exists flags(-cell_delay)] \
2772	   && ![info exists flags(-cell_check)] } {
2773      # Cell checks are not derated if no flags are specified.
2774      set derate_types {cell_delay}
2775    }
2776    foreach derate_type $derate_types {
2777      foreach path_type $path_types {
2778	foreach inst $insts {
2779	  set_timing_derate_inst_cmd $inst $derate_type $path_type \
2780	    $tr $early_late $derate
2781	}
2782	foreach libcell $libcells {
2783	  set_timing_derate_cell_cmd $libcell $derate_type $path_type \
2784	    $tr $early_late $derate
2785	}
2786      }
2787    }
2788  } else {
2789    if { ![info exists flags(-net_delay)] \
2790	   && ![info exists flags(-cell_delay)] \
2791	   && ![info exists flags(-cell_check)] } {
2792      # Cell checks are not derated if no flags are specified.
2793      set derate_types {net_delay cell_delay}
2794    }
2795    foreach derate_type $derate_types {
2796      foreach path_type $path_types {
2797	set_timing_derate_cmd $derate_type $path_type $tr $early_late $derate
2798      }
2799    }
2800  }
2801}
2802
2803proc parse_from_arg { keys_var arg_error_var } {
2804  upvar 1 $keys_var keys
2805
2806  if [info exists keys(-from)] {
2807    set key "-from"
2808    set tr "rise_fall"
2809  } elseif [info exists keys(-rise_from)] {
2810    set key "-rise_from"
2811    set tr "rise"
2812  } elseif [info exists keys(-fall_from)] {
2813    set key "-fall_from"
2814    set tr "fall"
2815  } else {
2816    return "NULL"
2817  }
2818  parse_clk_inst_port_pin_arg $keys($key) from_clks from_insts from_pins
2819  if {$from_pins == {} && $from_insts == {} && $from_clks == {}} {
2820    upvar 1 $arg_error_var arg_error
2821    set arg_error 1
2822    sta_warn 369 "no valid objects specified for $key."
2823    return "NULL"
2824  }
2825  return [make_exception_from $from_pins $from_clks $from_insts $tr]
2826}
2827
2828# "arg_error" is set to notify the caller to cleanup and post error.
2829proc parse_thrus_arg { args_var arg_error_var } {
2830  upvar 1 $args_var args
2831
2832  set thrus {}
2833  set args_rtn {}
2834  while { $args != {} } {
2835    set arg [lindex $args 0]
2836    set tr ""
2837    if { $arg == "-through" } {
2838      set tr "rise_fall"
2839      set key "-through"
2840    } elseif { $arg == "-rise_through" } {
2841      set tr "rise"
2842      set key "-rise_through"
2843    } elseif { $arg == "-fall_through" } {
2844      set tr "fall"
2845      set key "-fall_through"
2846    }
2847    if { $tr != "" } {
2848      if { [llength $args] > 1 } {
2849	set args [lrange $args 1 end]
2850	set arg [lindex $args 0]
2851	parse_inst_port_pin_net_arg $arg insts pins nets
2852	if {$pins == {} && $insts == {} && $nets == {}} {
2853	  upvar 1 $arg_error_var arg_error
2854	  set arg_error 1
2855	  sta_warn 370 "no valid objects specified for $key"
2856	} else {
2857	  lappend thrus [make_exception_thru $pins $nets $insts $tr]
2858	}
2859      }
2860    } else {
2861      lappend args_rtn $arg
2862    }
2863    set args [lrange $args 1 end]
2864  }
2865  set args $args_rtn
2866  return $thrus
2867}
2868
2869# Parse -to|-rise_to|-fall_to keywords.
2870proc parse_to_arg { keys_var flags_var arg_error_var } {
2871  upvar 1 $keys_var keys
2872  upvar 1 $flags_var flags
2873  upvar 1 $arg_error_var arg_error
2874
2875  set end_rf [parse_rise_fall_flags flags]
2876  return [parse_to_arg1 keys $end_rf arg_error]
2877}
2878
2879proc parse_to_arg1 { keys_var end_rf arg_error_var } {
2880  upvar 1 $keys_var keys
2881  upvar 1 $arg_error_var arg_error
2882
2883  if [info exists keys(-to)] {
2884    set key "-to"
2885    set to_rf "rise_fall"
2886  } elseif [info exists keys(-rise_to)] {
2887    set key "-rise_to"
2888    set to_rf "rise"
2889  } elseif [info exists keys(-fall_to)] {
2890    set key "-fall_to"
2891    set to_rf "fall"
2892  } else {
2893    # -rise/-fall without -to/-rise_to/-fall_to (no objects).
2894    if { $end_rf != "rise_fall" } {
2895      return [make_exception_to {} {} {} "rise_fall" $end_rf]
2896    } else {
2897      return "NULL"
2898    }
2899  }
2900  parse_clk_inst_port_pin_arg $keys($key) to_clks to_insts to_pins
2901  if {$to_pins == {} && $to_insts == {} && $to_clks == {}} {
2902    upvar 1 $arg_error_var arg_error
2903    set arg_error 1
2904    sta_warn 602 "no valid objects specified for $key."
2905    return "NULL"
2906  }
2907  return [make_exception_to $to_pins $to_clks $to_insts $to_rf $end_rf]
2908}
2909
2910proc delete_from_thrus_to { from thrus to } {
2911  if { $from != "NULL" } {
2912    delete_exception_from $from
2913  }
2914  if { $thrus != {} } {
2915    foreach thru $thrus {
2916      delete_exception_thru $thru
2917    }
2918  }
2919  if { $to != "NULL" } {
2920    delete_exception_to $to
2921  }
2922}
2923
2924proc parse_comment_key { keys_var } {
2925  upvar 1 $keys_var keys
2926
2927  set comment ""
2928  if { [info exists keys(-comment)] } {
2929    set comment $keys(-comment)
2930  }
2931  return $comment
2932}
2933
2934################################################################
2935
2936define_cmd_args "set_min_capacitance" {cap objects}
2937
2938proc set_min_capacitance { cap objects } {
2939  set_capacitance_limit $cap "min" $objects
2940}
2941
2942################################################################
2943
2944define_cmd_args "set_operating_conditions" \
2945  {[-analysis_type single|bc_wc|on_chip_variation] [-library lib]\
2946     [condition] [-min min_condition] [-max max_condition]\
2947     [-min_library min_lib] [-max_library max_lib]}
2948
2949proc set_operating_conditions { args } {
2950  parse_key_args "set_operating_conditions" args \
2951    keys {-analysis_type -library -min -max -min_library -max_library} flags {}
2952  parse_op_cond_analysis_type keys
2953  check_argc_eq0or1 set_operating_conditions $args
2954  if { [llength $args] == 1 } {
2955    set op_cond_name $args
2956    parse_op_cond $op_cond_name "-library" "all" keys
2957  }
2958  if [info exists keys(-min)] {
2959    parse_op_cond $keys(-min) "-min_library" "min" keys
2960  }
2961  if [info exists keys(-max)] {
2962    parse_op_cond $keys(-max) "-max_library" "max" keys
2963  }
2964}
2965
2966proc parse_op_cond { op_cond_name lib_key min_max key_var } {
2967  upvar 1 $key_var keys
2968  if [info exists keys($lib_key)] {
2969    set liberty [get_liberty_error $lib_key $keys($lib_key)]
2970    set op_cond [$liberty find_operating_conditions $op_cond_name]
2971    if { $op_cond == "NULL" } {
2972      sta_error 579 "operating condition '$op_cond_name' not found."
2973    } else {
2974      set_operating_conditions_cmd $op_cond $min_max
2975    }
2976  } else {
2977    set found 0
2978    set lib_iter [liberty_library_iterator]
2979    while {[$lib_iter has_next]} {
2980      set lib [$lib_iter next]
2981      set op_cond [$lib find_operating_conditions $op_cond_name]
2982      if { $op_cond != "NULL" } {
2983	set_operating_conditions_cmd $op_cond $min_max
2984	set found 1
2985	break
2986      }
2987    }
2988    $lib_iter finish
2989    if { !$found } {
2990      sta_error 580 "operating condition '$op_cond_name' not found."
2991    }
2992  }
2993}
2994
2995proc parse_op_cond_analysis_type { key_var } {
2996  upvar 1 $key_var keys
2997  if [info exists keys(-analysis_type)] {
2998    set analysis_type $keys(-analysis_type)
2999    if { $analysis_type == "single" \
3000	   || $analysis_type == "bc_wc" \
3001	   || $analysis_type == "on_chip_variation" } {
3002      set_analysis_type_cmd $analysis_type
3003    } else {
3004      sta_error 581 "-analysis_type must be single, bc_wc or on_chip_variation."
3005    }
3006  } elseif { [info exists keys(-min)] && [info exists keys(-max)] } {
3007    set_analysis_type_cmd "bc_wc"
3008  }
3009}
3010
3011################################################################
3012
3013define_cmd_args "set_wire_load_min_block_size" {block_size}
3014
3015proc set_wire_load_min_block_size { block_size } {
3016  sta_warn 371 "set_wire_load_min_block_size not supported."
3017}
3018
3019################################################################
3020
3021define_cmd_args "set_wire_load_mode" "top|enclosed|segmented"
3022
3023proc set_wire_load_mode { mode } {
3024  if { $mode == "top" \
3025	 || $mode == "enclosed" \
3026	 || $mode == "segmented" } {
3027    set_wire_load_mode_cmd $mode
3028  } else {
3029    sta_error 582 "mode must be top, enclosed or segmented."
3030  }
3031}
3032
3033################################################################
3034
3035define_cmd_args "set_wire_load_model" \
3036  {-name model_name [-library lib_name] [-min] [-max] [objects]}
3037
3038proc set_wire_load_model { args } {
3039  parse_key_args "set_wire_load_model" args keys {-name -library} \
3040    flags {-min -max}
3041
3042  check_argc_eq0or1 "set_wire_load_model" $args
3043  if { ![info exists keys(-name)] } {
3044    sta_error 583 "no wire load model specified."
3045  }
3046
3047  set model_name $keys(-name)
3048  set min_max [parse_min_max_all_check_flags flags]
3049
3050  set wireload "NULL"
3051  if [info exists keys(-library)] {
3052    set library [get_liberty_error "library" $keys(-library)]
3053    set wireload [$library find_wireload $model_name]
3054  } else {
3055    set lib_iter [liberty_library_iterator]
3056    while {[$lib_iter has_next]} {
3057      set lib [$lib_iter next]
3058      set wireload [$lib find_wireload $model_name]
3059      if {$wireload != "NULL"} {
3060	break;
3061      }
3062    }
3063    $lib_iter finish
3064  }
3065  if {$wireload == "NULL"} {
3066    sta_error 605 "wire load model '$model_name' not found."
3067  }
3068  set objects $args
3069  set_wire_load_cmd $wireload $min_max
3070}
3071
3072################################################################
3073
3074define_cmd_args "set_wire_load_selection_group" \
3075  {[-library lib] [-min] [-max] group_name [objects]}
3076
3077proc set_wire_load_selection_group { args } {
3078  parse_key_args "set_wire_load_selection_group" args keys {-library} \
3079    flags {-min -max}
3080
3081  set argc [llength $args]
3082  check_argc_eq1or2 "wire_load_selection_group" $args
3083
3084  set selection_name [lindex $args 0]
3085  set objects [lindex $args 1]
3086
3087  set min_max [parse_min_max_all_check_flags flags]
3088
3089  set selection "NULL"
3090  if [info exists keys(-library)] {
3091    set library [get_liberty_error "library" $keys(-library)]
3092    set selection [$library find_wireload_selection $selection_name]
3093  } else {
3094    set lib_iter [liberty_library_iterator]
3095    while {[$lib_iter has_next]} {
3096      set lib [$lib_iter next]
3097      set selection [$lib find_wireload_selection $selection_name]
3098      if {$selection != "NULL"} {
3099	break;
3100      }
3101    }
3102    $lib_iter finish
3103  }
3104  if {$selection == "NULL"} {
3105    sta_error 584 "wire load selection group '$selection_name' not found."
3106  }
3107  set_wire_load_selection_group_cmd $selection $min_max
3108}
3109
3110################################################################
3111#
3112# Multivoltage and Power Optimization Commands
3113#
3114################################################################
3115
3116define_cmd_args "create_voltage_area" \
3117  {[-name name] [-coordinate coordinates] [-guard_band_x guard_x]\
3118     [-guard_band_y guard_y] cells }
3119
3120proc create_voltage_area { args } {
3121  # ignored
3122}
3123
3124################################################################
3125
3126define_cmd_args "set_level_shifter_strategy" {[-rule rule_type]}
3127
3128proc set_level_shifter_strategy { args } {
3129  # ignored
3130}
3131
3132################################################################
3133
3134define_cmd_args "set_level_shifter_threshold" {[-voltage volt]}
3135
3136proc set_level_shifter_threshold { args } {
3137  # ignored
3138}
3139
3140################################################################
3141
3142define_cmd_args "set_max_dynamic_power" {power [unit]}
3143
3144proc set_max_dynamic_power { power {unit {}} } {
3145  # ignored
3146}
3147
3148################################################################
3149
3150define_cmd_args "set_max_leakage_power" {power [unit]}
3151
3152proc set_max_leakage_power { power {unit {}} } {
3153  # ignored
3154}
3155
3156################################################################
3157#
3158# Non-SDC commands
3159#
3160################################################################
3161
3162define_cmd_args "define_corners" { corner1 [corner2]... }
3163
3164proc define_corners { args } {
3165  define_corners_cmd $args
3166}
3167
3168################################################################
3169
3170define_cmd_args "set_pvt"\
3171  {insts [-min] [-max] [-process process] [-voltage voltage]\
3172     [-temperature temperature]}
3173
3174proc set_pvt { args } {
3175  parse_key_args "set_pvt" args \
3176    keys {-process -voltage -temperature} flags {-min -max}
3177
3178  set min_max [parse_min_max_all_flags flags]
3179  check_argc_eq1 "set_pvt" $args
3180  set insts [get_instances_error "instances" [lindex $args 0]]
3181
3182  if { $min_max == "all" } {
3183    set_pvt_min_max $insts "min" keys
3184    set_pvt_min_max $insts "max" keys
3185  } else {
3186    set_pvt_min_max $insts $min_max keys
3187  }
3188}
3189
3190proc set_pvt_min_max { insts min_max keys_var } {
3191  upvar 1 $keys_var keys
3192  set op_cond [operating_conditions $min_max]
3193  if { $op_cond == "NULL" } {
3194    set op_cond [default_operating_conditions]
3195  }
3196  if [info exists keys(-process)] {
3197    set process $keys(-process)
3198    check_float "-process" $process
3199  } else {
3200    set process [$op_cond process]
3201  }
3202  if [info exists keys(-voltage)] {
3203    set voltage $keys(-voltage)
3204    check_float "-voltage" $voltage
3205  } else {
3206    set voltage [$op_cond voltage]
3207  }
3208  if [info exists keys(-temperature)] {
3209    set temperature $keys(-temperature)
3210    check_float "-temperature" $temperature
3211  } else {
3212    set temperature [$op_cond temperature]
3213  }
3214
3215  foreach inst $insts {
3216    set_instance_pvt $inst $min_max $process $voltage $temperature
3217  }
3218}
3219
3220proc default_operating_conditions {} {
3221  set found 0
3222  set lib_iter [liberty_library_iterator]
3223  while {[$lib_iter has_next]} {
3224    set lib [$lib_iter next]
3225    set op_cond [$lib default_operating_conditions]
3226    if { $op_cond != "NULL" } {
3227      set found 1
3228      break
3229    }
3230  }
3231  $lib_iter finish
3232  if { !$found } {
3233    sta_error 585 "no default operating conditions found."
3234  }
3235  return $op_cond
3236}
3237
3238################################################################
3239
3240proc cell_regexp {} {
3241  global hierarchy_separator
3242  return [cell_regexp_hsc $hierarchy_separator]
3243}
3244
3245proc cell_regexp_hsc { hsc } {
3246  return "^(\[^${hsc}\]+)${hsc}(\[^${hsc}\]+)$"
3247}
3248
3249proc port_regexp {} {
3250  global hierarchy_separator
3251  return [port_regexp_hsc $hierarchy_separator]
3252}
3253
3254proc port_regexp_hsc { hsc } {
3255  return "^(\[^${hsc}\]+)${hsc}(\[^${hsc}\]+)${hsc}(\[^${hsc}\]+)$"
3256}
3257
3258# sta namespace end.
3259}
3260