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
17namespace eval sta {
18
19################################################################
20#
21# Non-SDC commands
22#
23################################################################
24
25define_cmd_args "delete_clock" {[-all] clocks}
26
27proc delete_clock { args } {
28  parse_key_args "delete_clock" args keys {} flags {-all}
29  if { [info exists flags(-all)] } {
30    check_argc_eq0 "delete_clock" $args
31    set clks [all_clocks]
32  } else {
33    check_argc_eq1 "delete_clock" $args
34    set clks [get_clocks_warn "clocks" [lindex $args 0]]
35  }
36  foreach clk $clks {
37    remove_clock_cmd $clk
38  }
39}
40
41################################################################
42
43define_cmd_args "delete_generated_clock" {[-all] clocks}
44
45proc delete_generated_clock { args } {
46  remove_gclk_cmd "delete_generated_clock" $args
47}
48
49################################################################
50
51define_cmd_args "set_disable_inferred_clock_gating" { objects }
52
53proc set_disable_inferred_clock_gating { objects } {
54  set_disable_inferred_clock_gating_cmd $objects
55}
56
57proc set_disable_inferred_clock_gating_cmd { objects } {
58  parse_inst_port_pin_arg $objects insts pins
59  foreach inst $insts {
60    disable_clock_gating_check_inst $inst
61  }
62  foreach pin $pins {
63    disable_clock_gating_check_pin $pin
64  }
65}
66
67################################################################
68
69define_cmd_args "unset_case_analysis" {pins}
70
71proc unset_case_analysis { pins } {
72  set pins1 [get_port_pins_error "pins" $pins]
73  foreach pin $pins1 {
74    unset_case_analysis_cmd $pin
75  }
76}
77
78################################################################
79
80define_cmd_args "unset_clock_groups" \
81  {[-logically_exclusive] [-physically_exclusive]\
82     [-asynchronous] [-name names] [-all]}
83
84proc unset_clock_groups { args } {
85  unset_clk_groups_cmd "unset_clock_groups" $args
86}
87
88proc unset_clk_groups_cmd { cmd cmd_args } {
89  parse_key_args $cmd cmd_args \
90    keys {-name} \
91    flags {-logically_exclusive -physically_exclusive -asynchronous -all}
92
93  set all [info exists flags(-all)]
94  set names {}
95  if {[info exists keys(-name)]} {
96    set names $keys(-name)
97  }
98
99  if { $all && $names != {} } {
100    sta_error 454 "the -all and -name options are mutually exclusive."
101  }
102  if { !$all && $names == {} } {
103    sta_error 455 "either -all or -name options must be specified."
104  }
105
106  set logically_exclusive [info exists flags(-logically_exclusive)]
107  set physically_exclusive [info exists flags(-physically_exclusive)]
108  set asynchronous [info exists flags(-asynchronous)]
109
110  if { ($logically_exclusive+$physically_exclusive+$asynchronous) == 0 } {
111    sta_error 456 "one of -logically_exclusive, -physically_exclusive or -asynchronous is required."
112  }
113  if { ($logically_exclusive+$physically_exclusive+$asynchronous) > 1 } {
114    sta_error 457 "the keywords -logically_exclusive, -physically_exclusive and -asynchronous are mutually exclusive."
115  }
116
117  if { $all } {
118    if { $logically_exclusive } {
119      unset_clock_groups_logically_exclusive "NULL"
120    } elseif { $physically_exclusive } {
121      unset_clock_groups_physically_exclusive "NULL"
122    } elseif { $asynchronous } {
123      unset_clock_groups_asynchronous "NULL"
124    }
125  } else {
126    foreach name $names {
127      if { $logically_exclusive } {
128	unset_clock_groups_logically_exclusive $name
129      } elseif { $physically_exclusive } {
130	unset_clock_groups_physically_exclusive $name
131      } elseif { $asynchronous } {
132	unset_clock_groups_asynchronous $name
133      }
134    }
135  }
136}
137
138################################################################
139
140define_cmd_args "unset_clock_latency" {[-source] [-clock clock] objects}
141
142proc unset_clock_latency { args } {
143  unset_clk_latency_cmd "unset_clock_latency" $args
144}
145
146proc unset_clk_latency_cmd { cmd cmd_args } {
147  parse_key_args $cmd cmd_args keys {-clock} flags {-source}
148  check_argc_eq1 $cmd $cmd_args
149  set objects [lindex $cmd_args 0]
150  parse_clk_port_pin_arg $objects clks pins
151  set pin_clk "NULL"
152  if { [info exists keys(-clock)] } {
153    set pin_clk [get_clock_warn "clock" $keys(-clock)]
154    if { $clks != {} } {
155      sta_warn 303 "-clock ignored for clock objects."
156    }
157  }
158
159  if {[info exists flags(-source)]} {
160    # Source latency.
161    foreach clk $clks {
162      unset_clock_insertion_cmd $clk "NULL"
163    }
164    foreach pin $pins {
165      # Source only allowed on clocks and clock pins.
166      if { ![is_clock_pin $pin] } {
167	sta_error 458 "-source '[$pin path_name]' is not a clock pin."
168      }
169      unset_clock_insertion_cmd $pin_clk $pin
170    }
171  } else {
172    # Latency.
173    foreach clk $clks {
174      unset_clock_latency_cmd $clk "NULL"
175    }
176    foreach pin $pins {
177      unset_clock_latency_cmd $pin_clk $pin
178    }
179  }
180}
181
182################################################################
183
184define_cmd_args "unset_clock_transition" {clocks}
185
186proc unset_clock_transition { args } {
187  check_argc_eq1 "unset_clock_transition" $args
188  set clks [get_clocks_warn "clocks" [lindex $args 0]]
189  foreach clk $clks {
190    unset_clock_slew_cmd $clk
191  }
192}
193
194################################################################
195
196define_cmd_args "unset_clock_uncertainty" \
197  {[-from|-rise_from|-fall_from from_clock]\
198     [-to|-rise_to|-fall_to to_clock] [-rise] [-fall]\
199     [-setup] [-hold] [objects]}
200
201proc unset_clock_uncertainty { args } {
202  unset_clk_uncertainty_cmd "unset_clock_uncertainty" $args
203}
204
205proc unset_clk_uncertainty_cmd { cmd cmd_args } {
206  parse_key_args $cmd cmd_args \
207    keys {-from -rise_from -fall_from -to -rise_to -fall_to} \
208    flags {-rise -fall -setup -hold}
209
210  set min_max "min_max"
211  if { [info exists flags(-setup)] && ![info exists flags(-hold)] } {
212    set min_max "max"
213  }
214  if { [info exists flags(-hold)] && ![info exists flags(-setup)] } {
215    set min_max "min"
216  }
217
218  if { [info exists keys(-from)] } {
219    set from_key "-from"
220    set from_rf "rise_fall"
221  } elseif { [info exists keys(-rise_from)] } {
222    set from_key "-rise_from"
223    set from_rf "rise"
224  } elseif { [info exists keys(-fall_from)] } {
225    set from_key "-fall_from"
226    set from_rf "fall"
227  } else {
228    set from_key "none"
229  }
230
231  if { [info exists keys(-to)] } {
232    set to_key "-to"
233    set to_rf "rise_fall"
234  } elseif { [info exists keys(-rise_to)] } {
235    set to_key "-rise_to"
236    set to_rf "rise"
237  } elseif { [info exists keys(-fall_to)] } {
238    set to_key "-fall_to"
239    set to_rf "fall"
240  } else {
241    set to_key "none"
242  }
243
244  if { $from_key != "none" && $to_key == "none" \
245	 || $from_key == "none" && $to_key != "none" } {
246    sta_error 459 "-from/-to must be used together."
247  } elseif { $from_key != "none" && $to_key != "none" } {
248    # Inter-clock uncertainty.
249    check_argc_eq0 "unset_clock_uncertainty" $cmd_args
250
251    # -from/-to can be lists.
252    set from_clks [get_clocks_warn "from_clocks" $keys($from_key)]
253    set to_clks [get_clocks_warn "to_clocks" $keys($to_key)]
254
255    foreach from_clk $from_clks {
256      foreach to_clk $to_clks {
257	unset_inter_clock_uncertainty $from_clk $from_rf \
258	  $to_clk $to_rf $min_max
259      }
260    }
261  } else {
262    # Single clock uncertainty.
263    check_argc_eq1 $cmd $cmd_args
264    if { [info exists keys(-rise)] \
265	   || [info exists keys(-fall)] } {
266      sta_error 460 "-rise, -fall options not allowed for single clock uncertainty."
267    }
268    set objects [lindex $cmd_args 0]
269    parse_clk_port_pin_arg $objects clks pins
270
271    foreach clk $clks {
272      unset_clock_uncertainty_clk $clk $min_max
273    }
274    foreach pin $pins {
275      unset_clock_uncertainty_pin $pin $min_max
276    }
277  }
278}
279
280################################################################
281
282define_cmd_args "unset_data_check" \
283  {[-from from_pin] [-rise_from from_pin] [-fall_from from_pin]\
284     [-to to_pin] [-rise_to to_pin] [-fall_to to_pin]\
285     [-setup | -hold] [-clock clock]}
286
287proc unset_data_check { args } {
288  unset_data_checks_cmd "unset_data_check" $args
289}
290
291proc unset_data_checks_cmd { cmd cmd_args } {
292  parse_key_args cmd cmd_args \
293    keys {-from -rise_from -fall_from -to -rise_to -fall_to -clock} \
294    flags {-setup -hold}
295  check_argc_eq0 $cmd $cmd_args
296
297  set from_rf "rise_fall"
298  set to_rf "rise_fall"
299  set clk "NULL"
300  set setup_hold "max"
301  if [info exists keys(-from)] {
302    set from [get_port_pin_error "from_pin" $keys(-from)]
303  } elseif [info exists keys(-rise_from)] {
304    set from [get_port_pin_error "from_pin" $keys(-rise_from)]
305    set from_rf "rise"
306  } elseif [info exists keys(-fall_from)] {
307    set from [get_port_pin_error "from_pin" $keys(-fall_from)]
308    set from_rf "fall"
309  } else {
310    sta_error 461 "missing -from, -rise_from or -fall_from argument."
311  }
312
313  if [info exists keys(-to)] {
314    set to [get_port_pin_error "to_pin" $keys(-to)]
315  } elseif [info exists keys(-rise_to)] {
316    set to [get_port_pin_error "to_pin" $keys(-rise_to)]
317    set to_rf "rise"
318  } elseif [info exists keys(-fall_to)] {
319    set to [get_port_pin_error "to_pin" $keys(-fall_to)]
320    set to_rf "fall"
321  } else {
322    sta_error 462 "missing -to, -rise_to or -fall_to argument."
323  }
324
325  if [info exists keys(-clock)] {
326    set clk [get_clock_warn "clock" $keys(-clock)]
327  }
328
329  if { [info exists flags(-setup)] && ![info exists flags(-hold)] } {
330    set setup_hold "setup"
331  } elseif { [info exists flags(-hold)] && ![info exists flags(-setup)] } {
332    set setup_hold "hold"
333  } else {
334    set setup_hold "setup_hold"
335  }
336
337  unset_data_check_cmd $from $from_rf $to $to_rf $clk $setup_hold
338}
339
340################################################################
341
342define_cmd_args "unset_disable_inferred_clock_gating" { objects }
343
344proc unset_disable_inferred_clock_gating { objects } {
345  unset_disable_inferred_clock_gating_cmd $objects
346}
347
348proc unset_disable_inferred_clock_gating_cmd { objects } {
349  parse_inst_port_pin_arg $objects insts pins
350  foreach inst $insts {
351    unset_disable_clock_gating_check_inst $inst
352  }
353  foreach pin $pins {
354    unset_disable_clock_gating_check_pin $pin
355  }
356}
357
358################################################################
359
360define_cmd_args "unset_disable_timing" \
361  {[-from from_port] [-to to_port] objects}
362
363proc unset_disable_timing { args } {
364  unset_disable_cmd "unset_disable_timing" $args
365}
366
367proc unset_disable_cmd { cmd cmd_args } {
368  parse_key_args $cmd cmd_args keys {-from -to} flags {}
369  check_argc_eq1 $cmd $cmd_args
370
371  set from ""
372  if { [info exists keys(-from)] } {
373    set from $keys(-from)
374  }
375  set to ""
376  if { [info exists keys(-to)] } {
377    set to $keys(-to)
378  }
379  parse_libcell_libport_inst_port_pin_edge_timing_arc_set_arg $cmd_args \
380    libcells libports insts ports pins edges timing_arc_sets
381
382  if { ([info exists keys(-from)] || [info exists keys(-to)]) \
383	 && ($libports != {} || $pins != {} || $ports != {}) } {
384    sta_warn 304 "-from/-to keywords ignored for lib_pin, port and pin arguments."
385  }
386
387  foreach libcell $libcells {
388    unset_disable_timing_cell $libcell $from $to
389  }
390  foreach libport $libports {
391    unset_disable_lib_port $libport
392  }
393  foreach inst $insts {
394    unset_disable_timing_instance $inst $from $to
395  }
396  foreach pin $pins {
397    unset_disable_pin $pin
398  }
399  foreach port $ports {
400    unset_disable_port $port
401  }
402  foreach edge $edges {
403    unset_disable_edge $edge
404  }
405  foreach timing_arc_set $timing_arc_sets {
406    unset_disable_timing_arc_set $timing_arc_set
407  }
408}
409
410proc unset_disable_timing_cell { cell from to } {
411  set from_ports [parse_disable_cell_ports $cell $from]
412  set to_ports [parse_disable_cell_ports $cell $to]
413  if { $from_ports == "NULL" && $to_ports == "NULL" } {
414    unset_disable_cell $cell "NULL" "NULL"
415  } elseif { $from_ports == "NULL" } {
416    foreach to_port $to_ports {
417      unset_disable_cell $cell "NULL" $to_port
418    }
419  } elseif { $to_ports == "NULL" } {
420    foreach from_port $from_ports {
421      unset_disable_cell $cell $from_port "NULL"
422    }
423  } else {
424    foreach from_port $from_ports {
425      foreach to_port $to_ports {
426	unset_disable_cell $cell $from_port $to_port
427      }
428    }
429  }
430}
431
432proc unset_disable_timing_instance { inst from to } {
433  set from_ports [parse_disable_inst_ports $inst $from]
434  set to_ports [parse_disable_inst_ports $inst $to]
435  if { ![$inst is_leaf] } {
436    sta_error 463 "-from/-to hierarchical instance not supported."
437  }
438  if { $from_ports == "NULL" && $to_ports == "NULL" } {
439    unset_disable_instance $inst "NULL" "NULL"
440  } elseif { $from_ports == "NULL" } {
441    foreach to_port $to_ports {
442      unset_disable_instance $inst "NULL" $to_port
443    }
444  } elseif { $to_ports == "NULL" } {
445    foreach from_port $from_ports {
446      unset_disable_instance $inst $from_port "NULL"
447    }
448  } else {
449    foreach from_port $from_ports {
450      foreach to_port $to_ports {
451	unset_disable_instance $inst $from_port $to_port
452      }
453    }
454  }
455}
456
457################################################################
458
459define_cmd_args "unset_generated_clock" {[-all] clocks}
460
461proc unset_generated_clock { args } {
462  unset_gclk_cmd "unset_generated_clock" $args
463}
464
465proc remove_gclk_cmd { cmd cmd_args } {
466  parse_key_args $cmd cmd_args keys {} flags {-all}
467  if { [info exists flags(-all)] } {
468    check_argc_eq0 $cmd $cmd_args
469    set clks [all_clocks]
470  } else {
471    check_argc_eq1 $cmd $cmd_args
472    set clks [get_clocks_warn "clocks" [lindex $cmd_args 0]]
473  }
474  foreach clk $clks {
475    if { [$clk is_generated] } {
476      remove_clock_cmd $clk
477    }
478  }
479}
480
481################################################################
482
483define_cmd_args "unset_input_delay" \
484  {[-rise] [-fall] [-max] [-min]\
485     [-clock clock] [-clock_fall]\
486     port_pin_list}
487
488proc unset_input_delay { args } {
489  unset_port_delay "unset_input_delay" "unset_input_delay_cmd" $args
490}
491
492################################################################
493
494define_cmd_args "unset_output_delay" \
495  {[-rise] [-fall] [-max] [-min]\
496     [-clock clock] [-clock_fall]\
497     port_pin_list}
498
499proc unset_output_delay { args } {
500  unset_port_delay "unset_output_delay" "unset_output_delay_cmd" $args
501}
502
503proc unset_port_delay { cmd swig_cmd cmd_args } {
504  parse_key_args $cmd cmd_args \
505    keys {-clock -reference_pin} \
506    flags {-rise -fall -max -min -clock_fall }
507  check_argc_eq1 $cmd $cmd_args
508
509  set pins [get_port_pins_error "pins" [lindex $cmd_args 0]]
510
511  set clk "NULL"
512  if [info exists keys(-clock)] {
513    set clk [get_clock_warn "clock" $keys(-clock)]
514  }
515
516  if [info exists flags(-clock_fall)] {
517    set clk_rf "fall"
518  } else {
519    set clk_rf "rise"
520  }
521
522  set tr [parse_rise_fall_flags flags]
523  set min_max [parse_min_max_all_flags flags]
524
525  foreach pin $pins {
526    $swig_cmd $pin $tr $clk $clk_rf $min_max
527  }
528}
529
530################################################################
531
532define_cmd_args "unset_path_exceptions" \
533  {[-setup] [-hold] [-rise] [-fall] [-from from_list]\
534     [-rise_from from_list] [-fall_from from_list]\
535     [-through through_list] [-rise_through through_list]\
536     [-fall_through through_list] [-to to_list] [-rise_to to_list]\
537     [-fall_to to_list]}
538
539proc unset_path_exceptions { args } {
540  unset_path_exceptions_cmd "unset_path_exceptions" $args
541}
542
543proc unset_path_exceptions_cmd { cmd cmd_args } {
544  parse_key_args $cmd cmd_args \
545    keys {-from -rise_from -fall_from -to -rise_to -fall_to} \
546    flags {-setup -hold -rise -fall} 0
547
548  set min_max "min_max"
549  if { [info exists flags(-setup)] && ![info exists flags(-hold)] } {
550    set min_max "max"
551  }
552  if { [info exists flags(-hold)] && ![info exists flags(-setup)] } {
553    set min_max "min"
554  }
555
556  set arg_error 0
557  set from [parse_from_arg keys arg_error]
558  set thrus [parse_thrus_arg cmd_args arg_error]
559  set to [parse_to_arg keys flags arg_error]
560  if { $arg_error } {
561    delete_from_thrus_to $from $thrus $to
562    sta_error 464 "$cmd command failed."
563    return 0
564  }
565
566  check_for_key_args $cmd cmd_args
567  if { $cmd_args != {} } {
568    delete_from_thrus_to $from $thrus $to
569    sta_error 465 "positional arguments not supported."
570  }
571  if { ($from == "NULL" && $thrus == "" && $to == "NULL") } {
572    delete_from_thrus_to $from $thrus $to
573    sta_error 466 "-from, -through or -to required."
574  }
575
576  reset_path_cmd $from $thrus $to $min_max
577  delete_from_thrus_to $from $thrus $to
578}
579
580################################################################
581
582define_cmd_args "unset_propagated_clock" {objects}
583
584proc unset_propagated_clock { objects } {
585  parse_clk_port_pin_arg $objects clks pins
586  foreach clk $clks {
587    unset_propagated_clock_cmd $clk
588  }
589  foreach pin $pins {
590    unset_propagated_clock_pin_cmd $pin
591  }
592}
593
594################################################################
595
596define_cmd_args "unset_timing_derate" {}
597
598proc unset_timing_derate { args } {
599  check_argc_eq0 "unset_timing_derate" $args
600  reset_timing_derate_cmd
601}
602
603################################################################
604#
605# Network editing commands
606#
607################################################################
608
609define_cmd_args "connect_pin" {net pin}
610# deprecated 2.0.16 05/02/2019
611define_cmd_args "connect_pins" {net pins}
612
613define_cmd_args "delete_instance" {inst}
614
615define_cmd_args "delete_net" {net}
616
617define_cmd_args "disconnect_pin" {net -all|pin}
618# deprecated 2.0.16 05/02/2019
619define_cmd_args "disconnect_pins" {net -all|pins}
620
621define_cmd_args "make_instance" {inst_path lib_cell}
622
623define_cmd_args "make_net" {}
624
625define_cmd_args "replace_cell" {instance lib_cell}
626
627define_cmd_args "insert_buffer" {buffer_name buffer_cell net load_pins\
628				       buffer_out_net_name}
629
630################################################################
631#
632# Delay calculation commands
633#
634################################################################
635
636define_cmd_args "set_assigned_delay" \
637  {-cell|-net [-rise] [-fall] [-corner corner_name] [-min] [-max]\
638     [-from from_pins] [-to to_pins] delay}
639
640# Change the delay for timing arcs between from_pins and to_pins matching
641# on cell (instance) or net.
642proc set_assigned_delay { args } {
643  set_assigned_delay_cmd "set_assigned_delay" $args
644}
645
646proc set_assigned_delay_cmd { cmd cmd_args } {
647  parse_key_args $cmd cmd_args keys {-corner -from -to} \
648    flags {-cell -net -rise -fall -max -min}
649  check_argc_eq1 $cmd $cmd_args
650  set corner [parse_corner keys]
651  set min_max [parse_min_max_all_check_flags flags]
652  set to_rf [parse_rise_fall_flags flags]
653
654  if [info exists keys(-from)] {
655    set from_pins [get_port_pins_error "from_pins" $keys(-from)]
656  } else {
657    sta_error 442 "$cmd missing -from argument."
658  }
659  if [info exists keys(-to)] {
660    set to_pins [get_port_pins_error "to_pins" $keys(-to)]
661  } else {
662    sta_error 443 "$cmd missing -to argument."
663  }
664
665  set delay [lindex $cmd_args 0]
666  if {![string is double $delay]} {
667    sta_error 444 "$cmd delay is not a float."
668  }
669  set delay [time_ui_sta $delay]
670
671  if {[info exists flags(-cell)] && [info exists flags(-net)]} {
672    sta_error 445 "set_annotated_delay -cell and -net options are mutually excluive."
673  } elseif {[info exists flags(-cell)]} {
674    if { $from_pins != {} } {
675      set inst [[lindex $from_pins 0] instance]
676      foreach pin $from_pins {
677	if {[$pin instance] != $inst} {
678	  sta_error 446 "$cmd pin [get_full_name $pin] is not attached to instance [get_full_name $inst]."
679	}
680      }
681      foreach pin $to_pins {
682	if {[$pin instance] != $inst} {
683	  sta_error 447 "$cmd pin [get_full_name $pin] is not attached to instance [get_full_name $inst]"
684	}
685      }
686    }
687  } elseif {![info exists flags(-net)]} {
688    sta_error 448 "$cmd -cell or -net required."
689  }
690  foreach from_pin $from_pins {
691    set from_vertices [$from_pin vertices]
692    set_assigned_delay1 [lindex $from_vertices 0] \
693      $to_pins $to_rf $corner $min_max $delay
694    if { [llength $from_vertices] == 2 } {
695      set_assigned_delay1 [lindex $from_vertices 1] \
696	$to_pins $to_rf $corner $min_max $delay
697    }
698  }
699}
700
701proc set_assigned_delay1 { from_vertex to_pins to_rf corner min_max delay } {
702  foreach to_pin $to_pins {
703    set to_vertices [$to_pin vertices]
704    set_assigned_delay2 $from_vertex [lindex $to_vertices 0] \
705      $to_rf $corner $min_max $delay
706    if { [llength $to_vertices] == 2 } {
707      # Bidirect driver.
708      set_assigned_delay2 $from_vertex [lindex $to_vertices 1] \
709	$to_rf $corner $min_max $delay
710    }
711  }
712}
713
714proc set_assigned_delay2 {from_vertex to_vertex to_rf corner min_max delay} {
715  set edge_iter [$from_vertex out_edge_iterator]
716  while {[$edge_iter has_next]} {
717    set edge [$edge_iter next]
718    if { [$edge to] == $to_vertex \
719	   && ![timing_role_is_check [$edge role]] } {
720      set arc_iter [$edge timing_arc_iterator]
721      while {[$arc_iter has_next]} {
722	set arc [$arc_iter next]
723	if { $to_rf == "rise_fall" \
724	       || $to_rf eq [$arc to_trans_name] } {
725	  set_arc_delay $edge $arc $corner $min_max $delay
726	}
727      }
728      $arc_iter finish
729    }
730  }
731  $edge_iter finish
732}
733
734################################################################
735
736define_cmd_args "set_assigned_check" \
737  {-setup|-hold|-recovery|-removal [-rise] [-fall]\
738     [-corner corner_name] [-min] [-max]\
739     [-from from_pins] [-to to_pins] [-clock rise|fall]\
740     [-cond sdf_cond] [-worst] check_value}
741
742# -worst is ignored.
743proc set_assigned_check { args } {
744  set_assigned_check_cmd "set_assigned_check" $args
745}
746
747# -worst is ignored.
748proc set_assigned_check_cmd { cmd cmd_args } {
749  parse_key_args $cmd cmd_args \
750    keys {-from -to -corner -clock -cond} \
751    flags {-setup -hold -recovery -removal -rise -fall -max -min -worst}
752  check_argc_eq1 $cmd $cmd_args
753
754  if { [info exists keys(-from)] } {
755    set from_pins [get_port_pins_error "from_pins" $keys(-from)]
756  } else {
757    sta_error 449 "$cmd missing -from argument."
758  }
759  set from_rf "rise_fall"
760  if { [info exists keys(-clock)] } {
761    set clk_arg $keys(-clock)
762    if { $clk_arg eq "rise" \
763	   || $clk_arg eq "fall" } {
764      set from_rf $clk_arg
765    } else {
766      sta_error 450 "$cmd -clock must be rise or fall."
767    }
768  }
769
770  if { [info exists keys(-to)] } {
771    set to_pins [get_port_pins_error "to_pins" $keys(-to)]
772  } else {
773    sta_error 451 "$cmd missing -to argument."
774  }
775  set to_rf [parse_rise_fall_flags flags]
776  set corner [parse_corner keys]
777  set min_max [parse_min_max_all_check_flags flags]
778
779  if { [info exists flags(-setup)] } {
780    set role "setup"
781  } elseif { [info exists flags(-hold)] } {
782    set role "hold"
783  } elseif { [info exists flags(-recovery)] } {
784    set role "recovery"
785  } elseif { [info exists flags(-removal)] } {
786    set role "removal"
787  } else {
788    sta_error 452 "$cmd missing -setup|-hold|-recovery|-removal check type.."
789  }
790  set cond ""
791  if { [info exists key(-cond)] } {
792    set cond $key(-cond)
793  }
794  set check_value [lindex $cmd_args 0]
795  if { ![string is double $check_value] } {
796    sta_error 453 "$cmd check_value is not a float."
797  }
798  set check_value [time_ui_sta $check_value]
799
800  foreach from_pin $from_pins {
801    set from_vertices [$from_pin vertices]
802    set_assigned_check1 [lindex $from_vertices 0] $from_rf \
803      $to_pins $to_rf $role $corner $min_max $cond $check_value
804    if { [llength $from_vertices] == 2 } {
805      set_assigned_check1 [lindex $from_vertices 1] $from_rf \
806	$to_pins $to_rf $role $corner $min_max $cond $check_value
807    }
808  }
809}
810
811proc set_assigned_check1 { from_vertex from_rf to_pins to_rf \
812			     role corner min_max cond check_value } {
813  foreach to_pin $to_pins {
814    set to_vertices [$to_pin vertices]
815    set_assigned_check2 $from_vertex $from_rf [lindex $to_vertices 0] \
816      $to_rf $role $corner $min_max $cond $check_value
817    if { [llength $to_vertices] == 2 } {
818      # Bidirect driver.
819      set_assigned_check2 $from_vertex $from_rf \
820	[lindex $to_vertices 1] $to_rf $role $corner $min_max \
821	$cond $check_value
822    }
823  }
824}
825
826proc set_assigned_check2 { from_vertex from_rf to_vertex to_rf \
827			     role corner min_max cond check_value } {
828  set edge_iter [$from_vertex out_edge_iterator]
829  while {[$edge_iter has_next]} {
830    set edge [$edge_iter next]
831    if { [$edge to] == $to_vertex } {
832      set arc_iter [$edge timing_arc_iterator]
833      while {[$arc_iter has_next]} {
834	set arc [$arc_iter next]
835	if { ($from_rf eq "rise_fall" \
836		|| $from_rf eq [$arc from_trans_name]) \
837	       && ($to_rf eq "rise_fall" \
838		     || $to_rf eq [$arc to_trans_name]) \
839	       && [$arc role] eq $role \
840	       && ($cond eq "" || [$arc sdf_cond] eq $cond) } {
841	  set_arc_delay $edge $arc $corner $min_max $check_value
842	}
843      }
844      $arc_iter finish
845    }
846  }
847  $edge_iter finish
848}
849
850################################################################a
851
852define_cmd_args "set_assigned_transition" \
853  {[-rise] [-fall] [-corner corner_name] [-min] [-max] slew pins}
854
855# Change the slew on a list of ports.
856proc set_assigned_transition { args } {
857  parse_key_args "set_assigned_transition" args keys {-corner} \
858    flags {-rise -fall -max -min}
859
860  set corner [parse_corner keys]
861  set min_max [parse_min_max_all_check_flags flags]
862  set tr [parse_rise_fall_flags flags]
863  check_argc_eq2 "set_assigned_transition" $args
864
865  set slew [lindex $args 0]
866  if {![string is double $slew]} {
867    sta_error 428 "set_assigned_transition transition is not a float."
868  }
869  set slew [time_ui_sta $slew]
870  set pins [get_port_pins_error "pins" [lindex $args 1]]
871  foreach pin $pins {
872    set vertices [$pin vertices]
873    set vertex [lindex $vertices 0]
874    set_annotated_slew $vertex $corner $min_max $tr $slew
875    if { [llength $vertices] == 2 } {
876      # Bidirect driver.
877      set vertex [lindex $vertices 1]
878      set_annotated_slew $vertex $min_max $tr $slew
879    }
880  }
881}
882
883################################################################a
884
885# compatibility
886define_cmd_args "read_parasitics" \
887  {[-min]\
888     [-max]\
889     [-elmore]\
890     [-path path]\
891     [-increment]\
892     [-pin_cap_included]\
893     [-keep_capacitive_coupling]\
894     [-coupling_reduction_factor factor]\
895     [-reduce_to pi_elmore|pi_pole_residue2]\
896     [-delete_after_reduce]\
897     [-quiet]\
898     [-save]\
899     filename}
900
901################################################################
902#
903# Utility commands
904#
905################################################################
906
907define_cmd_args "delete_from_list" {list objs}
908
909proc delete_from_list { list objects } {
910  delete_objects_from_list_cmd $list $objects
911}
912
913proc delete_objects_from_list_cmd { list objects } {
914  set list0 [lindex $list 0]
915  set list_is_object [is_object $list0]
916  set list_type [object_type $list0]
917  foreach obj $objects {
918    # If the list is a collection of tcl objects (returned by get_*),
919    # convert the obj to be removed from a name to an object of the same
920    # type.
921    if {$list_is_object && ![is_object $obj]} {
922      if {$list_type == "Clock"} {
923	set obj [find_clock $obj]
924      } elseif {$list_type == "Port"} {
925	set top_instance [top_instance]
926	set top_cell [$top_instance cell]
927	set obj [$top_cell find_port $obj]
928      } elseif {$list_type == "Pin"} {
929	set obj [find_pin $obj]
930      } elseif {$list_type == "Instance"} {
931	set obj [find_instance $obj]
932      } elseif {$list_type == "Net"} {
933	set obj [find_net $obj]
934      } elseif {$list_type == "LibertyLibrary"} {
935	set obj [find_liberty $obj]
936      } elseif {$list_type == "LibertyCell"} {
937	set obj [find_liberty_cell $obj]
938      } elseif {$list_type == "LibertyPort"} {
939	set obj [get_lib_pins $obj]
940      } else {
941	sta_error 439 "unsupported object type $list_type."
942      }
943    }
944    set index [lsearch $list $obj]
945    if { $index != -1 } {
946      set list [lreplace $list $index $index]
947    }
948  }
949  return $list
950}
951
952################################################################
953
954define_cmd_args "get_fanin" \
955  {-to sink_list [-flat] [-only_cells] [-startpoints_only]\
956     [-levels level_count] [-pin_levels pin_count]\
957     [-trace_arcs timing|enabled|all]}
958
959proc get_fanin { args } {
960  parse_key_args "get_fanin" args \
961    keys {-to -levels -pin_levels -trace_arcs} \
962    flags {-flat -only_cells -startpoints_only}
963  if { [llength $args] != 0 } {
964    cmd_usage_error "get_fanin"
965  }
966  if { ![info exists keys(-to)] } {
967    cmd_usage_error "get_fanin"
968  }
969  parse_port_pin_net_arg $keys(-to) pins nets
970  foreach net $nets {
971    lappend pins [net_driver_pins $net]
972  }
973  set flat [info exists flags(-flat)]
974  set only_insts [info exists flags(-only_cells)]
975  set startpoints_only [info exists flags(-startpoints_only)]
976  set inst_levels 0
977  if { [info exists keys(-levels)] } {
978    set inst_levels $keys(-levels)
979  }
980  set pin_levels 0
981  if { [info exists keys(-pin_levels)] } {
982    set pin_levels $keys(-pin_levels)
983  }
984
985  set thru_disabled 0
986  set thru_constants 0
987  if { [info exists keys(-trace_arcs)] } {
988    set trace_arcs $keys(-trace_arcs)
989    if { $trace_arcs == "timing" } {
990      set thru_disabled 0
991      set thru_constants 0
992    } elseif { $trace_arcs == "enabled" } {
993      set thru_disabled 0
994      set thru_constants 0
995    } elseif { $trace_arcs == "all" } {
996      set thru_disabled 1
997      set thru_constants 1
998    } else {
999      cmd_usage_error "get_fanin"
1000    }
1001  }
1002  if { $only_insts } {
1003    return [find_fanin_insts $pins $flat $startpoints_only \
1004	      $inst_levels $pin_levels $thru_disabled $thru_constants]
1005 } else {
1006    return [find_fanin_pins $pins $flat $startpoints_only \
1007	      $inst_levels $pin_levels $thru_disabled $thru_constants]
1008  }
1009}
1010
1011################################################################
1012
1013define_cmd_args "get_fanout" \
1014  {-from source_list [-flat] [-only_cells] [-endpoints_only]\
1015     [-levels level_count] [-pin_levels pin_count]\
1016     [-trace_arcs timing|enabled|all]}
1017
1018proc get_fanout { args } {
1019  parse_key_args "get_fanout" args \
1020    keys {-from -levels -pin_levels -trace_arcs} \
1021    flags {-flat -only_cells -endpoints_only}
1022  if { [llength $args] != 0 } {
1023    cmd_usage_error "get_fanout"
1024  }
1025  parse_port_pin_net_arg $keys(-from) pins nets
1026  foreach net $nets {
1027    lappend pins [net_load_pins $net]
1028  }
1029  set flat [info exists flags(-flat)]
1030  set only_insts [info exists flags(-only_cells)]
1031  set endpoints_only [info exists flags(-endpoints_only)]
1032
1033  set inst_levels 0
1034  if { [info exists keys(-levels)] } {
1035    set inst_levels $keys(-levels)
1036  }
1037
1038  set pin_levels 0
1039  if { [info exists keys(-pin_levels)] } {
1040    set pin_levels $keys(-pin_levels)
1041  }
1042
1043  set thru_disabled 0
1044  set thru_constants 0
1045  if { [info exists keys(-trace_arcs)] } {
1046    set trace_arcs $keys(-trace_arcs)
1047    if { $trace_arcs == "timing" } {
1048      set thru_disabled 0
1049      set thru_constants 0
1050    } elseif { $trace_arcs == "enabled" } {
1051      set thru_disabled 0
1052      set thru_constants 0
1053    } elseif { $trace_arcs == "all" } {
1054      set thru_disabled 1
1055      set thru_constants 1
1056    } else {
1057      cmd_usage_error "get_fanout"
1058    }
1059  }
1060  if { $only_insts } {
1061    return [find_fanout_insts $pins $flat $endpoints_only \
1062	      $inst_levels $pin_levels $thru_disabled $thru_constants]
1063  } else {
1064    return [find_fanout_pins $pins $flat $endpoints_only \
1065	      $inst_levels $pin_levels $thru_disabled $thru_constants]
1066  }
1067}
1068
1069################################################################
1070
1071define_cmd_args "get_name" {objects}
1072define_cmd_args "get_full_name" {objects}
1073
1074################################################################
1075
1076define_cmd_args "get_property" \
1077  {[-object_type cell|pin|net|port|clock|timing_arc] object property}
1078
1079proc get_property { args } {
1080  return [get_property_cmd "get_property" "-object_type" $args]
1081}
1082
1083################################################################
1084
1085proc get_property_cmd { cmd type_key cmd_args } {
1086  parse_key_args $cmd cmd_args keys $type_key flags {-quiet}
1087  set quiet [info exists flags(-quiet)]
1088  check_argc_eq2 $cmd $cmd_args
1089  set object [lindex $cmd_args 0]
1090  if { $object == "" } {
1091    sta_error 491 "$cmd object is null."
1092  } elseif { ![is_object $object] } {
1093    if [info exists keys($type_key)] {
1094      set object_type $keys($type_key)
1095    } else {
1096      sta_error 492 "$cmd $type_key must be specified with object name argument."
1097    }
1098    set object [get_property_object_type $object_type $object $quiet]
1099  }
1100  set prop [lindex $cmd_args 1]
1101  return [get_object_property $object $prop]
1102}
1103
1104proc get_object_property { object prop } {
1105  if { [is_object $object] } {
1106    set object_type [object_type $object]
1107    if { $object_type == "Instance" } {
1108      return [instance_property $object $prop]
1109    } elseif { $object_type == "Pin" } {
1110      return [pin_property $object $prop]
1111    } elseif { $object_type == "Net" } {
1112      return [net_property $object $prop]
1113    } elseif { $object_type == "Clock" } {
1114      return [clock_property $object $prop]
1115    } elseif { $object_type == "Port" } {
1116      return [port_property $object $prop]
1117    } elseif { $object_type == "LibertyPort" } {
1118      return [liberty_port_property $object $prop]
1119    } elseif { $object_type == "LibertyCell" } {
1120      return [liberty_cell_property $object $prop]
1121    } elseif { $object_type == "Cell" } {
1122      return [cell_property $object $prop]
1123    } elseif { $object_type == "Library" } {
1124      return [library_property $object $prop]
1125    } elseif { $object_type == "LibertyLibrary" } {
1126      return [liberty_library_property $object $prop]
1127    } elseif { $object_type == "Edge" } {
1128      return [edge_property $object $prop]
1129    } elseif { $object_type == "PathEnd" } {
1130      return [path_end_property $object $prop]
1131    } elseif { $object_type == "PathRef" } {
1132      return [path_ref_property $object $prop]
1133    } elseif { $object_type == "TimingArcSet" } {
1134      return [timing_arc_set_property $object $prop]
1135    } else {
1136      sta_error 606 "get_property unsupported object type $object_type."
1137    }
1138  } else {
1139    sta_error 493 "get_property $object is not an object."
1140  }
1141}
1142
1143proc get_property_object_type { object_type object_name quiet } {
1144  set object "NULL"
1145  if { $object_type == "cell" } {
1146    set object [get_cells -quiet $object_name]
1147  } elseif { $object_type == "pin" } {
1148    set object [get_pins -quiet $object_name]
1149  } elseif { $object_type == "net" } {
1150    set object [get_nets -quiet $object_name]
1151  } elseif { $object_type == "port" } {
1152    set object [get_ports -quiet $object_name]
1153  } elseif { $object_type == "clock" } {
1154    set object [get_clocks -quiet $object_name]
1155  } elseif { $object_type == "lib_cell" } {
1156    set object [get_lib_cells -quiet $object_name]
1157  } elseif { $object_type == "lib_pin" } {
1158    set object [get_lib_pins -quiet $object_name]
1159  } elseif { $object_type == "lib" } {
1160    set object [get_libs -quiet $object_name]
1161  } else {
1162    sta_error 494 "$object_type not supported."
1163  }
1164  if { $object == "NULL" && !$quiet } {
1165    sta_error 495 "$object_type '$object_name' not found."
1166  }
1167  return [lindex $object 0]
1168}
1169
1170proc get_object_type { obj } {
1171  set object_type [object_type $obj]
1172  if { $object_type == "Clock" } {
1173    return "clock"
1174  } elseif { $object_type == "LibertyCell" } {
1175    return "libcell"
1176  } elseif { $object_type == "LibertyPort" } {
1177    return "libpin"
1178  } elseif { $object_type == "Cell" } {
1179    return "design"
1180  } elseif { $object_type == "Instance" } {
1181    return "cell"
1182  } elseif { $object_type == "Port" } {
1183    return "port"
1184  } elseif { $object_type == "Pin" } {
1185    return "pin"
1186  } elseif { $object_type == "Net" } {
1187    return "net"
1188  } elseif { $object_type == "Edge" } {
1189    return "timing_arc"
1190  } elseif { $object_type == "TimingArcSet" } {
1191    return "timing_arc"
1192  } else {
1193    return "?"
1194  }
1195}
1196
1197proc get_name { object } {
1198  return [get_object_property $object "name"]
1199}
1200
1201proc get_full_name { object } {
1202  return [get_object_property $object "full_name"]
1203}
1204
1205proc sort_by_name { objects } {
1206  return [lsort -command name_cmp $objects]
1207}
1208
1209proc name_cmp { obj1 obj2 } {
1210  return [string compare [get_name $obj1] [get_name $obj2]]
1211}
1212
1213proc sort_by_full_name { objects } {
1214  return [lsort -command full_name_cmp $objects]
1215}
1216
1217proc full_name_cmp { obj1 obj2 } {
1218  return [string compare [get_full_name $obj1] [get_full_name $obj2]]
1219}
1220
1221################################################################
1222
1223define_cmd_args "get_timing_edges" \
1224  {[-from from_pin] [-to to_pin] [-of_objects objects] [-filter expr]}
1225
1226proc get_timing_edges { args } {
1227  return [get_timing_edges_cmd "get_timing_edges" $args]
1228}
1229
1230proc get_timing_edges_cmd { cmd cmd_args } {
1231  parse_key_args $cmd cmd_args \
1232    keys {-from -to -of_objects -filter} flags {}
1233  check_argc_eq0 $cmd $cmd_args
1234
1235  set arcs {}
1236  if { [info exists keys(-of_objects)] } {
1237    if { [info exists keys(-from)] \
1238	   || [info exists keys(-from)] } {
1239      sta_error 440 "-from/-to arguments not supported with -of_objects."
1240    }
1241    set arcs [get_timing_arcs_objects $keys(-of_objects)]
1242  } elseif { [info exists keys(-from)] \
1243	   && [info exists keys(-to)] } {
1244    set arcs [get_timing_arcs_from_to \
1245	      [get_port_pin_error "from" $keys(-from)] \
1246	      [get_port_pin_error "to" $keys(-to)]]
1247  } elseif { [info exists keys(-from)] } {
1248    set arcs [get_timing_arcs_from $keys(-from)]
1249  } elseif { [info exists keys(-to)] } {
1250    set arcs [get_timing_arcs_to $keys(-to)]
1251  } else {
1252    cmd_usage_error $cmd
1253  }
1254  if [info exists keys(-filter)] {
1255    set arcs [filter_timing_arcs1 $keys(-filter) $arcs]
1256  }
1257  return $arcs
1258}
1259
1260proc get_timing_arcs_objects { object_arg } {
1261  parse_libcell_inst_arg $object_arg libcells insts
1262  if { $insts != {} } {
1263    set edges {}
1264    foreach inst $insts {
1265      lappend edges [instance_edges $inst]
1266    }
1267    return $edges
1268  } elseif { $libcells != {} } {
1269    set arc_sets {}
1270    foreach libcell $libcells {
1271      lappend arc_sets [libcell_timing_arc_sets $libcell]
1272    }
1273    return $arc_sets
1274  }
1275}
1276
1277proc instance_edges { inst } {
1278  set edges {}
1279  set pin_iter [$inst pin_iterator]
1280  while {[$pin_iter has_next]} {
1281    set pin [$pin_iter next]
1282    foreach vertex [$pin vertices] {
1283      set edge_iter [$vertex out_edge_iterator]
1284      while {[$edge_iter has_next]} {
1285	set edge [$edge_iter next]
1286	if { [$edge role] != "wire" } {
1287	  lappend edges $edge
1288	}
1289      }
1290      $edge_iter finish
1291    }
1292  }
1293  $pin_iter finish
1294  return $edges
1295}
1296
1297proc libcell_timing_arc_sets { libcell } {
1298  set arc_sets {}
1299  set arc_iter [$libcell timing_arc_set_iterator]
1300  while { [$arc_iter has_next] } {
1301    lappend arc_sets [$arc_iter next]
1302  }
1303  $arc_iter finish
1304  return $arc_sets
1305}
1306
1307proc get_timing_arcs_from_to { from_pin_arg to_pin_arg } {
1308  set edges {}
1309  set from_pin [get_port_pin_error "from" $from_pin_arg]
1310  set to_pin [get_port_pin_error "to" $to_pin_arg]
1311  foreach from_vertex [$from_pin vertices] {
1312    foreach to_vertex [$to_pin vertices] {
1313      set edge_iter [$from_vertex out_edge_iterator]
1314      while {[$edge_iter has_next]} {
1315	set edge [$edge_iter next]
1316	if { [$edge to] == $to_vertex } {
1317	  lappend edges $edge
1318	}
1319      }
1320      $edge_iter finish
1321    }
1322  }
1323  return $edges
1324}
1325
1326proc get_timing_arcs_from { from_pin_arg } {
1327  set from_pin [get_port_pin_error "from" $from_pin_arg]
1328  set edges {}
1329  foreach from_vertex [$from_pin vertices] {
1330    set edge_iter [$from_vertex out_edge_iterator]
1331    while {[$edge_iter has_next]} {
1332      set edge [$edge_iter next]
1333      lappend edges $edge
1334    }
1335    $edge_iter finish
1336  }
1337  return $edges
1338}
1339
1340proc get_timing_arcs_to { to_pin_arg } {
1341  set to_pin [get_port_pin_error "to" $to_pin_arg]
1342  set edges {}
1343  foreach to_vertex [$to_pin vertices] {
1344    set edge_iter [$to_vertex in_edge_iterator]
1345    while {[$edge_iter has_next]} {
1346      set edge [$edge_iter next]
1347      lappend edges $edge
1348    }
1349    $edge_iter finish
1350  }
1351  return $edges
1352}
1353
1354proc filter_timing_arcs1 { filter objects } {
1355  variable filter_regexp1
1356  variable filter_or_regexp
1357  variable filter_and_regexp
1358  set filtered_objects {}
1359  # Ignore sub-exprs in filter_regexp1 for expr2 match var.
1360  if { [regexp $filter_or_regexp $filter ignore expr1 \
1361	  ignore ignore ignore expr2] } {
1362    regexp $filter_regexp1 $expr1 ignore attr_name op arg
1363    set filtered_objects1 [filter_timing_arcs $attr_name $op $arg $objects]
1364    regexp $filter_regexp1 $expr2 ignore attr_name op arg
1365    set filtered_objects2 [filter_timing_arcs $attr_name $op $arg $objects]
1366    set filtered_objects [concat $filtered_objects1 $filtered_objects2]
1367  } elseif { [regexp $filter_and_regexp $filter ignore expr1 \
1368		ignore ignore ignore expr2] } {
1369    regexp $filter_regexp1 $expr1 ignore attr_name op arg
1370    set filtered_objects [filter_timing_arcs $attr_name $op $arg $objects]
1371    regexp $filter_regexp1 $expr2 ignore attr_name op arg
1372    set filtered_objects [filter_timing_arcs $attr_name $op \
1373			    $arg $filtered_objects]
1374  } elseif { [regexp $filter_regexp1 $filter ignore attr_name op arg] } {
1375    set filtered_objects [filter_timing_arcs $attr_name $op $arg $objects]
1376  } else {
1377    sta_error 441 "unsupported -filter expression."
1378  }
1379  return $filtered_objects
1380}
1381
1382################################################################
1383
1384define_cmd_args "report_clock_properties" {[clocks]}
1385
1386proc_redirect report_clock_properties {
1387  check_argc_eq0or1 "report_clock_properties" $args
1388  update_generated_clks
1389  report_line "Clock                   Period          Waveform"
1390  report_line "----------------------------------------------------"
1391  if { [llength $args] == 0 } {
1392    set clk_iter [clock_iterator]
1393    while {[$clk_iter has_next]} {
1394      set clk [$clk_iter next]
1395      report_clock1 $clk
1396    }
1397    $clk_iter finish
1398  } else {
1399    foreach clk [get_clocks_warn "clock_name" [lindex $args 0]] {
1400      report_clock1 $clk
1401    }
1402  }
1403}
1404
1405proc report_clock1 { clk } {
1406  global sta_report_default_digits
1407
1408  if { [$clk waveform_valid] } {
1409    set digits $sta_report_default_digits
1410    set waveform [$clk waveform]
1411    if { $waveform == {} } {
1412      set wave "                    "
1413    } else {
1414      set wave ""
1415      foreach edge $waveform {
1416	set wave "$wave[format "%10s" [format_time $edge $digits]]"
1417      }
1418    }
1419    if {[$clk is_generated]} {
1420      set generated " (generated)"
1421    } else {
1422      set generated ""
1423    }
1424    report_line "[format %-20s [get_name $clk]][format %10s [format_time [$clk period] $digits]]  $wave$generated"
1425  }
1426}
1427
1428################################################################
1429
1430define_cmd_args "report_object_full_names" {objects}
1431
1432proc report_object_full_names { objects } {
1433  foreach obj [sort_by_full_name $objects] {
1434    report_line [get_full_name $obj]
1435  }
1436}
1437
1438define_cmd_args "report_object_names" {objects}
1439
1440proc report_object_names { objects } {
1441  foreach obj [sort_by_name $objects] {
1442    report_line [get_name $obj]
1443  }
1444}
1445
1446################################################################
1447
1448define_cmd_args "report_units" {}
1449
1450proc report_units { args } {
1451  check_argc_eq0 "report_units" $args
1452  foreach unit {"time" "capacitance" "resistance" "voltage" "current" "power" "distance"} {
1453    report_line " $unit 1[unit_scale_abreviation $unit][unit_suffix $unit]"
1454  }
1455}
1456
1457################################################################
1458
1459define_cmd_args "with_output_to_variable" { var { cmds }}
1460
1461# with_output_to_variable variable { command args... }
1462proc with_output_to_variable { var_name args } {
1463  upvar 1 $var_name var
1464
1465  set body [lindex $args 0]
1466  sta::redirect_string_begin;
1467  catch $body ret
1468  set var [sta::redirect_string_end]
1469  return $ret
1470}
1471
1472define_cmd_args "set_pocv_sigma_factor" { factor }
1473
1474################################################################
1475
1476define_cmd_args "write_path_spice" { -path_args path_args\
1477				       -spice_directory spice_directory\
1478				       -lib_subckt_file lib_subckts_file\
1479				       -model_file model_file\
1480				       -power power\
1481				       -ground ground}
1482
1483proc write_path_spice { args } {
1484  parse_key_args "write_path_spice" args \
1485    keys {-spice_directory -lib_subckt_file -model_file \
1486	    -power -ground -path_args} \
1487    flags {}
1488
1489  if { [info exists keys(-spice_directory)] } {
1490    set spice_dir [file nativename $keys(-spice_directory)]
1491    if { ![file exists $spice_dir] } {
1492      sta_error 496 "Directory $spice_dir not found."
1493    }
1494    if { ![file isdirectory $spice_dir] } {
1495      sta_error 497 "$spice_dir is not a directory."
1496    }
1497    if { ![file writable $spice_dir] } {
1498      sta_error 498 "Cannot write in $spice_dir."
1499    }
1500  } else {
1501    sta_error 499 "No -spice_directory specified."
1502  }
1503
1504  if { [info exists keys(-lib_subckt_file)] } {
1505    set lib_subckt_file [file nativename $keys(-lib_subckt_file)]
1506    if { ![file readable $lib_subckt_file] } {
1507      sta_error 500 "-lib_subckt_file $lib_subckt_file is not readable."
1508    }
1509  } else {
1510    sta_error 501 "No -lib_subckt_file specified."
1511  }
1512
1513  if { [info exists keys(-model_file)] } {
1514    set model_file [file nativename $keys(-model_file)]
1515    if { ![file readable $model_file] } {
1516      sta_error 502 "-model_file $model_file is not readable."
1517    }
1518  } else {
1519    sta_error 503 "No -model_file specified."
1520  }
1521
1522  if { [info exists keys(-power)] } {
1523    set power $keys(-power)
1524  } else {
1525    sta_error 504 "No -power specified."
1526  }
1527
1528  if { [info exists keys(-ground)] } {
1529    set ground $keys(-ground)
1530  } else {
1531    sta_error 505 "No -ground specified."
1532  }
1533
1534  if { ![info exists keys(-path_args)] } {
1535    sta_error 506 "No -path_args specified."
1536  }
1537  set path_args $keys(-path_args)
1538  set path_ends [eval [concat find_timing_paths $path_args]]
1539  if { $path_ends == {} } {
1540    sta_error 507 "No paths found for -path_args $path_args."
1541  } else {
1542    set path_index 1
1543    foreach path_end $path_ends {
1544      set path [$path_end path]
1545      set path_name "path_$path_index"
1546      set spice_file [file join $spice_dir "$path_name.sp"]
1547      set subckt_file [file join $spice_dir "$path_name.subckt"]
1548      write_path_spice_cmd $path $spice_file $subckt_file \
1549	$lib_subckt_file $model_file $power $ground
1550      incr path_index
1551    }
1552  }
1553}
1554
1555# sta namespace end.
1556}
1557