diff --git a/.gitignore b/.gitignore index 2013c841..3d0ac7c1 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,5 @@ doc/._Sta.docx test/results # ngspice turd test/b3v3_1check.log + +doc/messages.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index d6773d91..530b3b0e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -189,9 +189,10 @@ set(STA_SOURCE search/PathEnumed.cc search/PathExpanded.cc search/PathGroup.cc + search/PathPrev.cc search/PathRef.cc search/PathVertex.cc - search/PathVertexRep.cc + search/PathVertexPtr.cc search/Property.cc search/ReportPath.cc search/Search.cc @@ -596,3 +597,10 @@ add_custom_target(sta_tags etags -o TAGS ${SWIG_TCL_FILES} WORKING_DIRECTORY ${STA_HOME} ) + +add_custom_command( + TARGET OpenSTA + POST_BUILD + COMMAND ${CMAKE_SOURCE_DIR}/etc/FindMessages.tcl > ${CMAKE_SOURCE_DIR}/doc/messages.txt || true + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} +) diff --git a/README.md b/README.md index 00576da6..97b08cc8 100644 --- a/README.md +++ b/README.md @@ -214,11 +214,13 @@ Use Homebrew to install them. Set these variables before using cmake to cirumvent the Xcode versions. +``` # flex/bison override apple version export PATH="$(brew --prefix bison)/bin:${PATH}" export PATH="$(brew --prefix flex)/bin:${PATH}" export CMAKE_INCLUDE_PATH="$(brew --prefix flex)/include" export CMAKE_LIBRARY_PATH="$(brew --prefix flex)/lib;$(brew --prefix bison)/lib" +``` Homebrew does not support tclreadline, but the macports system does (see https://www.macports.org). diff --git a/dcalc/DelayCalc.tcl b/dcalc/DelayCalc.tcl index 89ea0862..b920e4b0 100644 --- a/dcalc/DelayCalc.tcl +++ b/dcalc/DelayCalc.tcl @@ -131,7 +131,7 @@ proc set_delay_calculator { alg } { if { [is_delay_calc_name $alg] } { set_delay_calculator_cmd $alg } else { - sta_error 180 "delay calculator $alg not found." + sta_error 195 "delay calculator $alg not found." } } @@ -156,7 +156,7 @@ proc set_assigned_delay { args } { if [info exists keys(-from)] { set from_pins [get_port_pins_error "from_pins" $keys(-from)] } else { - sta_error 181 "set_assigned_delay missing -from argument." + sta_error 196 "set_assigned_delay missing -from argument." } if [info exists keys(-to)] { set to_pins [get_port_pins_error "to_pins" $keys(-to)] diff --git a/doc/OpenSTA.odt b/doc/OpenSTA.odt index 437b600d..ed627906 100644 Binary files a/doc/OpenSTA.odt and b/doc/OpenSTA.odt differ diff --git a/doc/OpenSTA.pdf b/doc/OpenSTA.pdf index 2949d32f..6c9590d8 100644 Binary files a/doc/OpenSTA.pdf and b/doc/OpenSTA.pdf differ diff --git a/doc/messages.txt b/doc/messages.txt deleted file mode 100644 index ea0fb51a..00000000 --- a/doc/messages.txt +++ /dev/null @@ -1,581 +0,0 @@ -0100 CmdArgs.tcl:108 unsupported object type $object_type. -0101 CmdArgs.tcl:165 object '$obj' not found. -0102 CmdArgs.tcl:413 $corner_arg is not the name of process corner. -0103 CmdArgs.tcl:419 -corner keyword required with multi-corner analysis. -0104 CmdArgs.tcl:433 $corner_name is not the name of process corner. -0105 CmdArgs.tcl:438 missing -corner arg. -0106 CmdArgs.tcl:449 $corner_name is not the name of process corner. -0107 CmdArgs.tcl:466 $corner_name is not the name of process corner. -0108 CmdArgs.tcl:501 both -min and -max specified. -0109 CmdArgs.tcl:515 both -min and -max specified. -0110 CmdArgs.tcl:542 only one of -early and -late can be specified. -0111 CmdArgs.tcl:548 -early or -late must be specified. -0112 CmdArgs.tcl:555 both -early and -late specified. -0113 CmdArgs.tcl:570 $arg_name must be a single library. -0114 CmdArgs.tcl:576 $arg_name type '$object_type' is not a library. -0115 CmdArgs.tcl:581 library '$arg' not found. -0116 CmdArgs.tcl:598 $arg_name must be a single lib cell. -0123 CmdArgs.tcl:685 $arg_name must be a single instance. -0124 CmdArgs.tcl:691 $arg_name type '$object_type' is not an instance. -0125 CmdArgs.tcl:696 instance '$arg' not found. -0126 CmdArgs.tcl:715 $arg_name type '$object_type' is not an instance. -0127 CmdArgs.tcl:722 instance '$arg' not found. -0128 CmdArgs.tcl:742 $arg_name type '$object_type' is not a liberty cell. -0129 CmdArgs.tcl:749 liberty cell '$arg' not found. -0131 CmdArgs.tcl:810 $arg_name type '$object_type' is not a pin or port. -0132 CmdArgs.tcl:817 pin '$arg' not found. -0133 CmdArgs.tcl:837 $arg_name type '$object_type' is not a port. -0139 CmdArgs.tcl:918 unsupported object type $object_type. -0141 CmdArgs.tcl:939 $arg_name '$object_type' is not a net. -0142 CmdArgs.tcl:963 unsupported object type $object_type. -0143 CmdArgs.tcl:944 $arg_name '$arg' not found. -0144 CmdArgs.tcl:408 corner object type '$object_type' is not a corner. -0160 CmdUtil.tcl:44 no commands match '$pattern'. -0161 CmdUtil.tcl:89 Usage: $cmd $cmd_args($cmd) -0162 CmdUtil.tcl:91 Usage: $cmd argument error -0164 CmdUtil.tcl:220 unsupported object type $list_type. -0165 CmdUtil.tcl:237 unknown namespace $namespc. -0166 CmdUtil.tcl:170 unknown unit $unit prefix '${arg_prefix}'. -0167 CmdUtil.tcl:173 incorrect unit suffix '$arg_suffix'. -0180 DelayCalc.tcl:126 delay calculator $alg not found. -0181 DelayCalc.tcl:151 set_assigned_delay missing -from argument. -0182 DelayCalc.tcl:156 set_assigned_delay missing -to argument. -0183 DelayCalc.tcl:161 set_assigned_delay delay is not a float. -0184 DelayCalc.tcl:166 set_annotated_delay -cell and -net options are mutually excluive. -0185 DelayCalc.tcl:172 set_assigned_delay pin [get_full_name $pin] is not attached to instance [get_full_name $inst]. -0186 DelayCalc.tcl:177 set_assigned_delay pin [get_full_name $pin] is not attached to instance [get_full_name $inst] -0187 DelayCalc.tcl:182 set_assigned_delay -cell or -net required. -0188 DelayCalc.tcl:247 set_assigned_check missing -from argument. -0189 DelayCalc.tcl:256 set_assigned_check -clock must be rise or fall. -0190 DelayCalc.tcl:263 set_assigned_check missing -to argument. -0191 DelayCalc.tcl:278 set_assigned_check missing -setup|-hold|-recovery|-removal check type.. -0192 DelayCalc.tcl:286 set_assigned_check check_value is not a float. -0193 DelayCalc.tcl:226 set_assigned_delay no timing arcs found between from/to pins. -0194 DelayCalc.tcl:338 set_assigned_check no check arcs found between from/to pins. -0204 ArnoldiDelayCalc.cc:607 arnoldi delay calc failed. -0210 DelayCalc.tcl:359 set_assigned_transition transition is not a float. -0220 Link.tcl:36 missing top_cell_name argument and no current_design. -0225 InternalPower.cc:192 unsupported table order -0226 InternalPower.cc:207 unsupported table axes -0230 Network.tcl:41 instance $instance_path not found. -0231 Network.tcl:217 net $net_path not found. -0232 Network.tcl:220 net $net_path not found. -0233 Network.tcl:30 report_instance -connections is deprecated. -0234 Network.tcl:34 report_instance -verbose is deprecated. -0235 Network.tcl:189 report_net -connections is deprecated. -0236 Network.tcl:193 report_net -verbose is deprecated. -0237 Network.tcl:197 report_net -hier_pins is deprecated. -0239 TableModel.cc:265 unsupported table order -0240 TableModel.cc:328 unsupported table axes -0241 TableModel.cc:545 unsupported table order -0242 TableModel.cc:563 unsupported table axes -0243 TimingArc.cc:242 timing arc max index exceeded - -0244 Clock.cc:474 generated clock edges size is not three. -0245 CheckTiming.cc:428 unknown print flag -0246 Corner.cc:377 unknown parasitic analysis point count -0247 Corner.cc:421 unknown analysis point count -0249 GatedClk.cc:247 illegal gated clock active value -0250 NetworkEdit.tcl:107 unsupported object type $object_type. -0252 NetworkEdit.tcl:174 unsupported object type $object_type. -0253 NetworkEdit.tcl:192 unsupported object type $object_type. -0266 VertexVisitor.cc:32 VertexPinCollector::copy not supported. -0267 WriteSpice.cc:1217 out of memory -0268 VerilogWriter.cc:258 unknown port direction -0272 Parasitics.tcl:41 read_spef -quiet is deprecated. -0273 Parasitics.tcl:45 read_spef -reduce_to is deprecated. Use -reduce instead. -0274 Parasitics.tcl:50 read_spef -delete_after_reduce is deprecated. -0275 Parasitics.tcl:54 read_spef -save is deprecated. -0276 Parasitics.tcl:62 path instance '$path' not found. -0280 PathEnum.cc:574 diversion path not found -0301 Power.tcl:234 activity should be 0.0 to 1.0 or 2.0 -0302 Power.tcl:242 duty should be 0.0 to 1.0 -0303 Power.tcl:257 activity cannot be set on clock ports. -0304 Power.tcl:40 No liberty libraries have been read. -0305 Power.tcl:286 read_power_activities is deprecated. Use read_vcd. -0320 Property.tcl:32 $cmd object is null. -0321 Property.tcl:37 $cmd $type_key must be specified with object name argument. -0322 Property.tcl:77 get_property unsupported object type $object_type. -0323 Property.tcl:80 get_property $object is not an object. -0324 Property.tcl:107 $object_type not supported. -0325 Property.tcl:110 $object_type '$object_name' not found. -0326 Sdc.tcl:494 object '$pattern' is not an instance. -0327 Sdc.tcl:542 object '$pattern' is not an clock. -0328 Sdc.tcl:606 object '$pattern' is not a liberty cell. -0329 Sdc.tcl:689 object '$pattern' is not a liberty pin. -0330 Sdc.tcl:769 object '$pattern' is not a liberty library. -0331 Sdc.tcl:868 object '$pattern' is not a net. -0332 Sdc.tcl:948 object '$pattern' is not a pin. -0333 Sdc.tcl:1005 object '$pattern' is not a port. -0334 Sdc.tcl:2860 object '$cell_name' is not a liberty cell. -0335 Sdc.tcl:679 positional arguments not supported with -of_objects. -0340 Sdc.tcl:73 cannot open '$filename'. -0341 Sdc.tcl:128 incomplete command at end of file. -0342 Sdc.tcl:212 hierarchy separator must be one of '$sdc_dividers'. -0343 Sdc.tcl:256 unknown unit $unit prefix '${arg_prefix}'. -0344 Sdc.tcl:275 unknown $unit prefix '$prefix'. -0345 Sdc.tcl:281 $unit scale [format %.0e $scale] does not match library scale [format %.0e $unit_scale]. -0346 Sdc.tcl:358 only one of -cells, -data_pins, -clock_pins, -async_pins, -output_pins are suppported. -0347 Sdc.tcl:401 current_design for other than top cell not supported. -0348 Sdc.tcl:468 patterns argument not supported with -of_objects. -0349 Sdc.tcl:507 instance '$pattern' not found. -0350 Sdc.tcl:429 unsupported $object_type -filter expression. -0351 Sdc.tcl:551 clock '$pattern' not found. -0352 Sdc.tcl:581 positional arguments not supported with -of_objects. -0353 Sdc.tcl:618 library '$lib_name' not found. -0354 Sdc.tcl:630 cell '$cell_pattern' not found. -0355 Sdc.tcl:702 library/cell/port '$pattern' not found. -0356 Sdc.tcl:722 port '$port_pattern' not found. -0357 Sdc.tcl:727 library '$lib_name' not found. -0358 Sdc.tcl:742 -nocase ignored without -regexp. -0359 Sdc.tcl:778 library '$pattern' not found. -0360 Sdc.tcl:849 patterns argument not supported with -of_objects. -0361 Sdc.tcl:879 net '$pattern' not found. -0362 Sdc.tcl:912 patterns argument not supported with -of_objects. -0363 Sdc.tcl:959 pin '$pattern' not found. -0365 Sdc.tcl:994 patterns argument not supported with -of_objects. -0366 Sdc.tcl:1014 port '$pattern' not found. -0368 Sdc.tcl:1054 -add requires -name. -0369 Sdc.tcl:1059 -name or port_pin_list must be specified. -0370 Sdc.tcl:1067 missing -period argument. -0371 Sdc.tcl:1073 -waveform edge_list must have an even number of edge times. -0372 Sdc.tcl:1082 non-increasing clock -waveform edge times. -0373 Sdc.tcl:1085 -waveform time greater than two periods. -0374 Sdc.tcl:1143 empty ports/pins/nets argument. -0375 Sdc.tcl:1151 -add requires -name. -0376 Sdc.tcl:1156 name or port_pin_list must be specified. -0377 Sdc.tcl:1163 missing -source argument. -0378 Sdc.tcl:1178 -master_clock argument empty. -0379 Sdc.tcl:1181 -add requireds -master_clock. -0380 Sdc.tcl:1185 -multiply_by and -divide_by options are exclusive. -0381 Sdc.tcl:1189 -divide_by is not an integer greater than one. -0382 Sdc.tcl:1192 -combinational implies -divide_by 1. -0383 Sdc.tcl:1197 -multiply_by is not an integer greater than one. -0384 Sdc.tcl:1203 -duty_cycle is not a float between 0 and 100. -0385 Sdc.tcl:1209 -edges only supported for three edges. -0386 Sdc.tcl:1215 edges times are not monotonically increasing. -0387 Sdc.tcl:1224 -edge_shift length does not match -edges length. -0388 Sdc.tcl:1230 missing -multiply_by, -divide_by, -combinational or -edges argument. -0389 Sdc.tcl:1238 cannot specify -invert without -multiply_by, -divide_by or -combinational. -0390 Sdc.tcl:1244 -duty_cycle requires -multiply_by value. -0391 Sdc.tcl:1304 group_path command failed. -0392 Sdc.tcl:1311 positional arguments not supported. -0393 Sdc.tcl:1315 -from, -through or -to required. -0394 Sdc.tcl:1321 -name and -default are mutually exclusive. -0395 Sdc.tcl:1323 -name or -default option is required. -0396 Sdc.tcl:1364 cannot specify both -high and -low. -0397 Sdc.tcl:1372 missing -setup or -hold argument. -0398 Sdc.tcl:1386 -high and -low only permitted for pins and instances. -0399 Sdc.tcl:1393 -high and -low only permitted for pins and instances. -0400 Sdc.tcl:1436 one of -logically_exclusive, -physically_exclusive or -asynchronous is required. -0401 Sdc.tcl:1439 the keywords -logically_exclusive, -physically_exclusive and -asynchronous are mutually exclusive. -0402 Sdc.tcl:1458 unknown keyword argument $arg. -0403 Sdc.tcl:1460 extra positional argument $arg. -0404 Sdc.tcl:1489 the -all and -name options are mutually exclusive. -0405 Sdc.tcl:1492 either -all or -name options must be specified. -0406 Sdc.tcl:1500 one of -logically_exclusive, -physically_exclusive or -asynchronous is required. -0407 Sdc.tcl:1503 the keywords -logically_exclusive, -physically_exclusive and -asynchronous are mutually exclusive. -0408 Sdc.tcl:1553 -clock ignored for clock objects. -0409 Sdc.tcl:1567 -source '[get_full_name $pin]' is not a clock pin. -0410 Sdc.tcl:1574 -early/-late is only allowed with -source. -0411 Sdc.tcl:1603 -clock ignored for clock objects. -0412 Sdc.tcl:1615 -source '[$pin path_name]' is not a clock pin. -0413 Sdc.tcl:1643 set_sense -type data not supported. -0414 Sdc.tcl:1647 set_sense -type clock|data -0415 Sdc.tcl:1658 set_clock_sense is deprecated as of SDC 2.1. Use set_sense -type clock. -0416 Sdc.tcl:1670 -pulse argument not supported. -0417 Sdc.tcl:1679 -positive, -negative, -stop_propagation and -pulse are mutually exclusive. -0418 Sdc.tcl:1692 hierarchical pin '[get_full_name $pin]' not supported. -0419 Sdc.tcl:1716 transition time can not be specified for virtual clocks. -0420 Sdc.tcl:1749 missing uncertainty value. -0421 Sdc.tcl:1797 -from/-to must be used together. -0422 Sdc.tcl:1817 -rise, -fall options not allowed for single clock uncertainty. -0423 Sdc.tcl:1883 -from/-to must be used together. -0424 Sdc.tcl:1903 -rise, -fall options not allowed for single clock uncertainty. -0425 Sdc.tcl:1944 missing -from, -rise_from or -fall_from argument. -0426 Sdc.tcl:1956 missing -to, -rise_to or -fall_to argument. -0427 Sdc.tcl:2004 missing -from, -rise_from or -fall_from argument. -0428 Sdc.tcl:2016 missing -to, -rise_to or -fall_to argument. -0429 Sdc.tcl:2058 -from/-to keywords ignored for lib_pin, port and pin arguments. -0430 Sdc.tcl:2088 -from/-to hierarchical instance not supported. -0431 Sdc.tcl:2120 pin '[get_full_name $inst]${hierarchy_separator}${port_name}' not found. -0432 Sdc.tcl:2177 pin '[get_name $cell]${hierarchy_separator}${port_name}' not found. -0434 Sdc.tcl:2211 -from/-to keywords ignored for lib_pin, port and pin arguments. -0435 Sdc.tcl:2263 -from/-to hierarchical instance not supported. -0436 Sdc.tcl:2317 '$args' ignored. -0437 Sdc.tcl:2321 -from, -through or -to required. -0438 Sdc.tcl:2400 -source_latency_included ignored with -reference_pin. -0439 Sdc.tcl:2403 -network_latency_included ignored with -reference_pin. -0440 Sdc.tcl:2422 $cmd not allowed on [pin_direction $pin] port '[get_full_name $pin]'. -0441 Sdc.tcl:2424 $cmd relative to a clock defined on the same port/pin not allowed. -0442 Sdc.tcl:2472 missing delay argument. -0443 Sdc.tcl:2478 '$args' ignored. -0444 Sdc.tcl:2603 missing path multiplier argument. -0445 Sdc.tcl:2608 '$args' ignored. -0446 Sdc.tcl:2615 cannot use -start with -end. -0447 Sdc.tcl:2665 $cmd command failed. -0448 Sdc.tcl:2672 positional arguments not supported. -0449 Sdc.tcl:2676 -from, -through or -to required. -0450 Sdc.tcl:2743 virtual clock [get_name $clk] can not be propagated. -0451 Sdc.tcl:2785 value must be 0, zero, 1, one, rise, rising, fall, or falling. -0452 Sdc.tcl:2854 cell '$lib_name:$cell_name' not found. -0453 Sdc.tcl:2867 '$cell_name' not found. -0454 Sdc.tcl:2871 missing -lib_cell argument. -0455 Sdc.tcl:2879 port '$to_port_name' not found. -0456 Sdc.tcl:2891 -pin argument required for cells with multiple outputs. -0457 Sdc.tcl:2906 port '$from_port_name' not found. -0458 Sdc.tcl:2924 -multiply_by ignored. -0459 Sdc.tcl:2927 -dont_scale ignored. -0460 Sdc.tcl:2930 -no_design_rule ignored. -0461 Sdc.tcl:2953 set_fanout_load not supported. -0462 Sdc.tcl:2977 -clock not supported. -0463 Sdc.tcl:2980 -clock_fall not supported. -0464 Sdc.tcl:3030 -pin_load not allowed for net objects. -0465 Sdc.tcl:3033 -wire_load not allowed for net objects. -0466 Sdc.tcl:3036 -rise/-fall not allowed for net objects. -0467 Sdc.tcl:3123 port '[get_name $port]' is not an input. -0468 Sdc.tcl:3169 -data_path, -clock_path, -rise, -fall ignored for ports and designs. -0469 Sdc.tcl:3240 derating factor greater than 2.0. -0470 Sdc.tcl:3277 -cell_delay and -cell_check flags ignored for net objects. -0471 Sdc.tcl:3347 no valid objects specified for $key. -0472 Sdc.tcl:3380 no valid objects specified for $key -0473 Sdc.tcl:3429 no valid objects specified for $key. -0474 Sdc.tcl:3497 operating condition '$op_cond_name' not found. -0475 Sdc.tcl:3515 operating condition '$op_cond_name' not found. -0476 Sdc.tcl:3529 -analysis_type must be single, bc_wc or on_chip_variation. -0477 Sdc.tcl:3541 set_wire_load_min_block_size not supported. -0478 Sdc.tcl:3554 mode must be top, enclosed or segmented. -0479 Sdc.tcl:3569 no wire load model specified. -0480 Sdc.tcl:3591 wire load model '$model_name' not found. -0481 Sdc.tcl:3630 wire load selection group '$selection_name' not found. -0482 Sdc.tcl:3718 define_corners must be called before read_liberty. -0500 Sdc.tcl:3791 no default operating conditions found. -0501 Sdc.tcl:259 incorrect unit suffix '$arg_suffix'. -0502 Search.tcl:165 $cmd -endpoint_count is deprecated. Use -endpoint_path_count instead. -0503 Search.tcl:178 $cmd -group_count is deprecated. Use -group_path_count instead. -0510 Search.tcl:137 $cmd -path_delay must be min, min_rise, min_fall, max, max_rise, max_fall or min_max. -0511 Search.tcl:147 $cmd command failed. -0512 Search.tcl:172 -endpoint_path_count must be a positive integer. -0513 Search.tcl:186 -group_path_count must be >= 1. -0514 Search.tcl:216 '$arg' is not a known keyword or flag. -0515 Search.tcl:218 positional arguments not supported. -0516 Search.tcl:339 report_clock_skew -setup and -hold are mutually exclusive options. -0520 Search.tcl:543 analysis type single is not consistent with doing both setup/max and hold/min checks. -0521 Search.tcl:548 positional arguments not supported. -0522 Search.tcl:802 -min and -max cannot both be specified. -0523 Search.tcl:822 pin '$pin_arg' is hierarchical. -0524 Search.tcl:878 -format $format not recognized. -0526 Search.tcl:1026 specify one of -setup and -hold. -0527 Search.tcl:1076 unknown path group '$name'. -0540 Sta.tcl:158 -from/-to arguments not supported with -of_objects. -0560 Util.tcl:44 $cmd $key missing value. -0561 Util.tcl:61 $cmd $key missing value. -0562 Util.tcl:71 $cmd $arg is not a known keyword or flag. -0563 Util.tcl:93 $cmd $arg is not a known keyword or flag. -0564 Util.tcl:241 $cmd positional arguments not supported. -0565 Util.tcl:247 $cmd requires one positional argument. -0566 Util.tcl:254 $cmd requires zero or one positional arguments. -0567 Util.tcl:260 $cmd requires two positional arguments. -0568 Util.tcl:267 $cmd requires one or two positional arguments. -0569 Util.tcl:273 $cmd requires three positional arguments. -0570 Util.tcl:279 $cmd requires four positional arguments. -0571 Util.tcl:287 $cmd_arg '$arg' is not a float. -0572 Util.tcl:293 $cmd_arg '$arg' is not a positive float. -0573 Util.tcl:299 $cmd_arg '$arg' is not an integer. -0574 Util.tcl:305 $cmd_arg '$arg' is not a positive integer. -0575 Util.tcl:311 $cmd_arg '$arg' is not an integer greater than or equal to one. -0576 Util.tcl:317 $cmd_arg '$arg' is not between 0 and 100. -0577 Sdc.tcl:3721 define_corners must define at least one corner. -0590 Variables.tcl:37 sta_report_default_digits must be a positive integer. -0591 Variables.tcl:62 sta_crpr_mode must be pin or transition. -0592 Variables.tcl:179 $var_name value must be 0 or 1. -0616 Levelize.cc:220 maximum logic level exceeded -0620 Sdf.tcl:41 -cond_use must be min, max or min_max. -0621 Sdf.tcl:46 -cond_use min_max cannot be used with analysis type single. -0623 Sdf.tcl:154 SDF -divider must be / or . -0800 VcdReader.cc:112 unhandled vcd command. -0801 VcdReader.cc:151 timescale syntax error. -0802 VcdReader.cc:165 Unknown timescale unit. -0804 VcdReader.cc:222 Variable syntax error. -1000 ConcreteNetwork.cc:1973 cell type %s can not be linked. -1010 CycleAccting.cc:87 No common period was found between clocks %s and %s. -1040 DmpCeff.cc:1510 parasitic Pi model has NaNs. -1041 DmpCeff.cc:1536 cell %s delay model not supported on SPF parasitics by DMP delay calculator -1060 Genclks.cc:275 no master clock found for generated clock %s. -1062 Genclks.cc:939 generated clock %s source pin %s missing paths from master clock %s. -1100 Power.cc:559 unknown cudd constant -1110 Liberty.cc:763 cell %s/%s port %s not found in cell %s/%s. -1111 Liberty.cc:789 cell %s/%s %s -> %s timing group %s not found in cell %s/%s. -1112 Liberty.cc:808 Liberty cell %s/%s for corner %s/%s not found. -1113 Liberty.cc:1824 cell %s/%s %s -> %s latch enable %s_edge is inconsistent with %s -> %s setup_%s check. -1114 Liberty.cc:1765 cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function positive sense. -1115 Liberty.cc:1773 cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function negative sense. -1116 Liberty.cc:362 unsupported slew degradation table axes -1117 Liberty.cc:378 unsupported slew degradation table axes -1118 Liberty.cc:383 unsupported slew degradation table order -1119 Liberty.cc:413 unsupported slew degradation table axes -1120 Liberty.cc:1979 library missing vdd -1121 Liberty.cc:1391 timing arc count mismatch -1125 LibertyParser.cc:310 valueIterator called for LibertySimpleAttribute -1126 LibertyParser.cc:390 LibertyStringAttrValue called for float value -1127 LibertyParser.cc:420 LibertyStringAttrValue called for float value -1130 LibertyExpr.cc:82 %s references unknown port %s. -1131 LibertyExpr.cc:175 %s %s. -1140 LibertyReader.cc:632 library %s already exists. -1141 LibertyReader.cc:665 library missing name. -1142 LibertyReader.cc:691 default_wire_load %s not found. -1143 LibertyReader.cc:702 default_wire_selection %s not found. -1144 LibertyReader.cc:714 default_operating_condition %s not found. -1145 LibertyReader.cc:724 input_threshold_pct_%s not found. -1146 LibertyReader.cc:728 output_threshold_pct_%s not found. -1147 LibertyReader.cc:732 slew_lower_threshold_pct_%s not found. -1148 LibertyReader.cc:736 slew_upper_threshold_pct_%s not found. -1149 LibertyReader.cc:741 Library %s is missing one or more thresholds. -1150 LibertyReader.cc:820 unknown unit multiplier %s. -1151 LibertyReader.cc:843 unknown unit scale %c. -1152 LibertyReader.cc:846 unknown unit suffix %s. -1153 LibertyReader.cc:849 unknown unit suffix %s. -1154 LibertyReader.cc:874 capacitive_load_units are not ff or pf. -1155 LibertyReader.cc:877 capacitive_load_units are not a string. -1156 LibertyReader.cc:880 capacitive_load_units missing suffix. -1157 LibertyReader.cc:883 capacitive_load_units scale is not a float. -1158 LibertyReader.cc:886 capacitive_load_units missing scale and suffix. -1159 LibertyReader.cc:889 capacitive_load_unit missing values suffix. -1160 LibertyReader.cc:907 delay_model %s not supported. -1161 LibertyReader.cc:911 delay_model %s not supported. -1162 LibertyReader.cc:915 delay_model %s not supported. -1163 LibertyReader.cc:920 delay_model %s not supported.. -1164 LibertyReader.cc:923 unknown delay_model %s. -1165 LibertyReader.cc:942 unknown bus_naming_style format. -1166 LibertyReader.cc:963 voltage_map voltage is not a float. -1167 LibertyReader.cc:966 voltage_map missing voltage. -1168 LibertyReader.cc:969 voltage_map supply name is not a string. -1169 LibertyReader.cc:972 voltage_map missing supply name and voltage. -1170 LibertyReader.cc:975 voltage_map missing values suffix. -1171 LibertyReader.cc:1060 default_max_transition is 0.0. -1172 LibertyReader.cc:1075 default_max_fanout is 0.0. -1173 LibertyReader.cc:1165 default_fanout_load is 0.0. -1174 LibertyReader.cc:1193 default_wire_load_mode %s not found. -1175 LibertyReader.cc:1379 table template missing name. -1176 LibertyReader.cc:1424 missing variable_%d attribute. -1177 LibertyReader.cc:1500 missing table index values. -1178 LibertyReader.cc:1506 non-increasing table index values. -1179 LibertyReader.cc:1538 bus type %s missing bit_from. -1180 LibertyReader.cc:1540 bus type %s missing bit_to. -1181 LibertyReader.cc:1544 type missing name. -1182 LibertyReader.cc:1571 scaling_factors do not have a name. -1183 LibertyReader.cc:1740 operating_conditions missing name. -1184 LibertyReader.cc:1811 wire_load missing name. -1185 LibertyReader.cc:1854 fanout_length is missing length and fanout. -1186 LibertyReader.cc:1869 wire_load_selection missing name. -1187 LibertyReader.cc:1900 wireload %s not found. -1189 LibertyReader.cc:1907 wire_load_from_area min not a float. -1190 LibertyReader.cc:1910 wire_load_from_area max not a float. -1191 LibertyReader.cc:1913 wire_load_from_area missing parameters. -1192 LibertyReader.cc:1916 wire_load_from_area missing parameters. -1193 LibertyReader.cc:1935 cell missing name. -1194 LibertyReader.cc:1959 cell %s ocv_derate_group %s not found. -1195 LibertyReader.cc:1992 port %s function size does not match port size. -1196 LibertyReader.cc:2089 %s %s bus width mismatch. -1197 LibertyReader.cc:2100 %s %s bus width mismatch. -1198 LibertyReader.cc:2110 clear -1199 LibertyReader.cc:2120 preset -1200 LibertyReader.cc:2156 latch enable function is non-unate for port %s. -1201 LibertyReader.cc:2161 latch enable function is unknown for port %s. -1202 LibertyReader.cc:2263 operating conditions %s not found. -1203 LibertyReader.cc:2266 scaled_cell missing operating condition. -1204 LibertyReader.cc:2269 scaled_cell cell %s has not been defined. -1205 LibertyReader.cc:2272 scaled_cell missing name. -1206 LibertyReader.cc:2298 scaled_cell %s, %s port functions do not match cell port functions. -1207 LibertyReader.cc:2303 scaled_cell ports do not match cell ports. -1208 LibertyReader.cc:2305 scaled_cell %s, %s timing does not match cell timing. -1209 LibertyReader.cc:2324 combinational timing to an input port. -1210 LibertyReader.cc:2419 missing %s_transition. -1211 LibertyReader.cc:2421 missing cell_%s. -1212 LibertyReader.cc:2442 timing group from output port. -1213 LibertyReader.cc:2452 timing group from output port. -1214 LibertyReader.cc:2462 timing group from output port. -1215 LibertyReader.cc:2497 timing group from output port. -1217 LibertyReader.cc:2507 timing group from output port. -1218 LibertyReader.cc:2608 receiver_capacitance group not in timing or pin group. -1219 LibertyReader.cc:2626 unsupported model axis. -1220 LibertyReader.cc:2654 output_current_%s group not in timing group. -1221 LibertyReader.cc:2696 output current waveform %.2e %.2e not found. -1222 LibertyReader.cc:2717 unsupported model axis. -1223 LibertyReader.cc:2759 vector index_1 and index_2 must have exactly one value. -1224 LibertyReader.cc:2761 vector reference_time not found. -1225 LibertyReader.cc:2794 normalized_driver_waveform variable_2 must be normalized_voltage -1226 LibertyReader.cc:2797 normalized_driver_waveform variable_1 must be input_net_transition -1228 LibertyReader.cc:3019 level_shifter_type must be HL, LH, or HL_LH -1229 LibertyReader.cc:3055 switch_cell_type must be coarse_grain or fine_grain -1230 LibertyReader.cc:3079 scaling_factors %s not found. -1231 LibertyReader.cc:3140 pin name is not a string. -1232 LibertyReader.cc:3157 pin name is not a string. -1233 LibertyReader.cc:3171 pin name is not a string. -1234 LibertyReader.cc:3243 bus %s bus_type not found. -1235 LibertyReader.cc:3295 bus_type %s not found. -1236 LibertyReader.cc:3298 bus_type is not a string. -1237 LibertyReader.cc:3316 bundle %s member not found. -1238 LibertyReader.cc:3339 member is not a string. -1239 LibertyReader.cc:3346 members attribute is missing values. -1240 LibertyReader.cc:3397 unknown port direction. -1241 LibertyReader.cc:3644 max_transition is 0.0. -1242 LibertyReader.cc:3750 pulse_latch unknown pulse type. -1243 LibertyReader.cc:4202 timing group missing related_pin/related_bus_pin. -1244 LibertyReader.cc:4301 unknown timing_type %s. -1245 LibertyReader.cc:4321 unknown timing_sense %s. -1246 LibertyReader.cc:4361 mode value is not a string. -1247 LibertyReader.cc:4364 missing mode value. -1248 LibertyReader.cc:4367 mode name is not a string. -1249 LibertyReader.cc:4370 mode missing values. -1250 LibertyReader.cc:4373 mode missing mode name and value. -1251 LibertyReader.cc:4449 unsupported model axis. -1252 LibertyReader.cc:4476 unsupported model axis. -1253 LibertyReader.cc:4505 unsupported model axis. -1254 LibertyReader.cc:4540 unsupported model axis. -1255 LibertyReader.cc:4556 %s group not in timing group. -1256 LibertyReader.cc:4595 table template %s not found. -1257 LibertyReader.cc:4679 %s is missing values. -1258 LibertyReader.cc:4702 %s is not a list of floats. -1259 LibertyReader.cc:4704 table row has %u columns but axis has %d. -1260 LibertyReader.cc:4714 table has %u rows but axis has %d. -1261 LibertyReader.cc:4765 lut output is not a string. -1262 LibertyReader.cc:4781 cell %s test_cell redefinition. -1263 LibertyReader.cc:4829 mode definition missing name. -1264 LibertyReader.cc:4846 mode value missing name. -1265 LibertyReader.cc:4860 when attribute inside table model. -1266 LibertyReader.cc:4909 %s attribute is not a string. -1267 LibertyReader.cc:4912 %s is not a simple attribute. -1268 LibertyReader.cc:4932 %s attribute is not an integer. -1269 LibertyReader.cc:4935 %s is not a simple attribute. -1270 LibertyReader.cc:4948 %s is not a simple attribute. -1271 LibertyReader.cc:4974 %s value %s is not a float. -1272 LibertyReader.cc:5003 %s missing values. -1273 LibertyReader.cc:5007 %s missing values. -1274 LibertyReader.cc:5010 %s is not a complex attribute. -1275 LibertyReader.cc:5036 %s is not a float. -1276 LibertyReader.cc:5059 %s is missing values. -1277 LibertyReader.cc:5062 %s has more than one string. -1278 LibertyReader.cc:5071 %s is missing values. -1279 LibertyReader.cc:5096 %s attribute is not boolean. -1280 LibertyReader.cc:5099 %s attribute is not boolean. -1281 LibertyReader.cc:5102 %s is not a simple attribute. -1282 LibertyReader.cc:5118 attribute %s value %s not recognized. -1283 LibertyReader.cc:5149 unknown early/late value. -1284 LibertyReader.cc:5369 OCV derate group named %s not found. -1285 LibertyReader.cc:5385 ocv_derate missing name. -1286 LibertyReader.cc:5438 unknown rise/fall. -1287 LibertyReader.cc:5458 unknown derate type. -1288 LibertyReader.cc:5490 unsupported model axis. -1289 LibertyReader.cc:5522 unsupported model axis. -1290 LibertyReader.cc:5554 unsupported model axis. -1291 LibertyReader.cc:5625 unknown pg_type. -1292 LibertyReader.cc:6039 port %s subscript out of range. -1293 LibertyReader.cc:6043 port range %s of non-bus port %s. -1294 LibertyReader.cc:6057 port %s not found. -1295 LibertyReader.cc:6127 port %s not found. -1297 LibertyReader.cc:1466 axis type %s not supported. -1298 LibertyReader.cc:2180 statetable input port %s not found. -1299 LibertyReader.cc:3809 unknown signal_type %s. -1300 LibertyReader.cc:4076 table row must have 3 groups separated by ':'. -1301 LibertyReader.cc:4081 table row has %zu input values but %zu are required. -1302 LibertyReader.cc:4088 table row has %zu current values but %zu are required. -1303 LibertyReader.cc:4095 table row has %zu next values but %zu are required. -1304 LibertyReader.cc:4141 table input value '%s' not recognized. -1305 LibertyReader.cc:4160 table internal value '%s' not recognized. -1340 LibertyWriter.cc:308 %s/%s bundled ports not supported. -1341 LibertyWriter.cc:456 %s/%s/%s timing model not supported. -1342 LibertyWriter.cc:476 3 axis table models not supported. -1343 LibertyWriter.cc:625 %s/%s/%s timing arc type %s not supported. -1350 LumpedCapDelayCalc.cc:138 gate delay input variable is NaN -1355 MakeTimingModel.cc:227 clock %s pin %s is inside model block. -1360 Vcd.cc:172 Unknown variable %s ID %s -1370 PathEnum.cc:478 path diversion missing edge. -1398 VerilogReader.cc:1860 %s is not a verilog module. -1399 VerilogReader.cc:1865 %s is not a verilog module. -1400 PathVertex.cc:236 missing arrivals. -1401 PathVertex.cc:250 missing arrivals. -1402 PathVertex.cc:279 missing requireds. -1422 PathVertexRep.cc:153 missing arrivals. -1450 ReadVcdActivities.cc:107 VCD max time is zero. -1451 ReadVcdActivities.cc:174 problem parsing bus %s. -1452 ReadVcdActivities.cc:250 clock %s vcd period %s differs from SDC clock period %s -1521 Sim.cc:511 propagated logic value %c differs from constraint value of %c on pin %s. -1525 SpefParse.yy:805 %d is not positive. -1526 SpefParse.yy:814 %.4f is not positive. -1527 SpefParse.yy:820 %.4f is not positive. -1550 Sta.cc:2000 '%s' is not a valid start point. -1551 Sta.cc:2073 '%s' is not a valid endpoint. -1552 Sta.cc:2076 '%s' is not a valid endpoint. -1553 Sta.cc:2393 maximum corner count exceeded -1554 Sta.cc:1997 '%s' is not a valid start point. -1570 Sta.cc:3413 No network has been linked. -1574 Search.i:1026 POCV support requires compilation with SSTA=1. -1575 Search.i:465 unknown report path field %s -1576 Search.i:477 unknown report path field %s -1602 WriteSpice.cc:458 Liberty pg_port %s/%s missing voltage_name attribute, -1603 WriteSpice.cc:428 %s pg_port %s not found, -1604 WriteSpice.cc:1019 no register/latch found for path from %s to %s, -1605 WriteSpice.cc:241 The subkct file %s is missing definitions for %s -1606 WriteSpice.cc:270 subckt %s port %s has no corresponding liberty port, pg_port and is not power or ground. -1640 SpefReader.cc:157 illegal bus delimiters. -1641 SpefReader.cc:241 unknown units %s. -1642 SpefReader.cc:254 unknown units %s. -1643 SpefReader.cc:267 unknown units %s. -1644 SpefReader.cc:282 unknown units %s. -1645 SpefReader.cc:303 no name map entry for %d. -1646 SpefReader.cc:322 unknown port direction %s. -1647 SpefReader.cc:349 pin %s not found. -1648 SpefReader.cc:352 instance %s not found. -1650 SpefReader.cc:372 net %s not found. -1651 SpefReader.cc:486 %s not connected to net %s. -1652 SpefReader.cc:492 pin %s not found. -1653 SpefReader.cc:506 %s not connected to net %s. -1654 SpefReader.cc:512 node %s not a pin or net:number -1655 SpefReader.cc:524 %s not connected to net %s. -1656 SpefReader.cc:528 pin %s not found. -1657 SpefReader.cc:645 %s. -1658 SpefReader.cc:61 Delay calculator %s does not support reduction. -1700 CcsCeffDelayCalc.cc:102 VDD not defined in library %s -1701 CcsCeffDelayCalc.cc:273 unsupported ccs region count. -1720 PrimaDelayCalc.cc:229 VDD not defined in library %s -1751 ArcDcalcWaveforms.cc:56 VDD not defined in library %s -1752 PrimaDelayCalc.cc:765 G matrix is singular. -1903 WriteSpice.tcl:145 Cannot write $spice_dir. -1904 WriteSpice.tcl:148 No -spice_filename specified. -1905 WriteSpice.tcl:154 -lib_subckt_file $lib_subckt_file is not readable. -1906 WriteSpice.tcl:157 No -lib_subckt_file specified. -1907 WriteSpice.tcl:163 -model_file $model_file is not readable. -1908 WriteSpice.tcl:166 No -model_file specified. -1909 WriteSpice.tcl:172 No -power specified. -1910 WriteSpice.tcl:111 Unknown circuit simulator -1913 WriteSpice.tcl:244 Cannot write $plot_dir. -1914 WriteSpice.tcl:247 No -plot_basename specified. -1915 WriteSpice.tcl:178 No -ground specified. -1920 WriteSpice.tcl:36 Directory $spice_dir not found. -1921 WriteSpice.tcl:39 $spice_dir is not a directory. -1922 WriteSpice.tcl:42 Cannot write in $spice_dir. -1923 WriteSpice.tcl:45 No -spice_directory specified. -1924 WriteSpice.tcl:51 -lib_subckt_file $lib_subckt_file is not readable. -1925 WriteSpice.tcl:54 No -lib_subckt_file specified. -1926 WriteSpice.tcl:60 -model_file $model_file is not readable. -1927 WriteSpice.tcl:63 No -model_file specified. -1928 WriteSpice.tcl:69 No -power specified. -1929 WriteSpice.tcl:75 No -ground specified. -1930 WriteSpice.tcl:81 No -path_args specified. -1931 WriteSpice.tcl:86 No paths found for -path_args $path_args. -1932 WriteSpice.tcl:139 Missing -gates argument. -1933 WriteSpice.tcl:212 Missing -gates argument. -2100 ArcDelayCalc.cc:86 no timing arc for %s input/driver pins. -2101 ArcDelayCalc.cc:91 %s not a valid rise/fall. -2102 ArcDelayCalc.cc:94 Pin %s/%s not found. -2103 ArcDelayCalc.cc:97 %s not a valid rise/fall. -2104 ArcDelayCalc.cc:100 Pin %s/%s not found. -2105 ArcDelayCalc.cc:103 Instance %s not found. -2120 Network.i:255 unknown namespace -2121 Sdc.i:104 unknown analysis type -2122 Sdc.i:227 unknown wire load mode -2140 StaTclTypes.i:424 Delay calc arg requires 5 or 6 args. -2141 Sta.cc:3417 No liberty libraries found. -2200 Crpr.cc:62 missing prev paths -2201 Crpr.cc:73 missing prev paths diff --git a/etc/FindMessages.tcl b/etc/FindMessages.tcl index a844de79..24dcc3ad 100755 --- a/etc/FindMessages.tcl +++ b/etc/FindMessages.tcl @@ -29,8 +29,11 @@ exec tclsh $0 ${1+"$@"} # Find warning/error message IDs and detect collisions. # Usage: FindMessages.tcl > doc/messages.txt +set has_error 0 + proc scan_file { file warn_regexp } { global msgs + global has_error if { [file exists $file] } { set in_stream [open $file r] @@ -38,7 +41,7 @@ proc scan_file { file warn_regexp } { set file_line 1 while { ![eof $in_stream] } { - if { [regexp -- $warn_regexp $line ignore1 ignore2 msg_id msg] } { + if { [regexp -- $warn_regexp $line ignore msg_id msg] } { lappend msgs "$msg_id $file $file_line $msg" } gets $in_stream line @@ -46,7 +49,8 @@ proc scan_file { file warn_regexp } { } close $in_stream } else { - puts "Warning: file $file not found." + puts stderr "Warning: Source file $file not found during message scanning" + set has_error 1 } } @@ -57,13 +61,13 @@ foreach subdir $subdirs { set files [glob -nocomplain [file join $subdir "*.{cc,hh,yy,ll,i}"]] set files_c [concat $files_c $files] } -set warn_regexp_c {(criticalError|->warn|->fileWarn|->error|->fileError|libWarn|libError| warn)\(([0-9]+),.*(".+")} +set warn_regexp_c {(?:(?:criticalError|->warn|->fileWarn|->error|->fileError|libWarn|libError| warn)\(|tclArgError\(interp,\s*)([0-9]+),.*(".+")} set files_tcl {} foreach subdir $subdirs { set files_tcl [concat $files_tcl [glob -nocomplain [file join $subdir "*.tcl"]]] } -set warn_regexp_tcl {(sta_warn|sta_error|sta_warn_error) ([0-9]+) (".+")} +set warn_regexp_tcl {(?:sta_warn|sta_error|sta_warn_error) ([0-9]+) (".+")} proc scan_files {files warn_regexp } { foreach file $files { @@ -73,13 +77,15 @@ proc scan_files {files warn_regexp } { proc check_msgs { } { global msgs + global has_error set msgs [lsort -index 0 -integer $msgs] set prev_id -1 foreach msg $msgs { set msg_id [lindex $msg 0] if { $msg_id == $prev_id } { - puts "Warning: $msg_id duplicated" + puts stderr "Warning: Message id $msg_id duplicated" + set has_error 1 } set prev_id $msg_id } @@ -99,3 +105,7 @@ scan_files $files_c $warn_regexp_c scan_files $files_tcl $warn_regexp_tcl check_msgs report_msgs + +if {$has_error} { + exit 1 +} diff --git a/graph/Graph.cc b/graph/Graph.cc index 091c1a58..c0961f05 100644 --- a/graph/Graph.cc +++ b/graph/Graph.cc @@ -613,17 +613,17 @@ Graph::deleteRequireds(Vertex *vertex) vertex->setRequireds(nullptr); } -PathVertexRep * +PathPrev * Graph::prevPaths(const Vertex *vertex) const { return vertex->prevPaths(); } -PathVertexRep * +PathPrev * Graph::makePrevPaths(Vertex *vertex, uint32_t count) { - PathVertexRep *prev_paths = new PathVertexRep[count]; + PathPrev *prev_paths = new PathPrev[count]; vertex->setPrevPaths(prev_paths); return prev_paths; } @@ -1023,7 +1023,6 @@ Vertex::init(Pin *pin, level_ = 0; bfs_in_queue_ = 0; crpr_path_pruning_disabled_ = false; - requireds_pruned_ = false; } Vertex::~Vertex() @@ -1141,12 +1140,6 @@ Vertex::setCrprPathPruningDisabled(bool disabled) crpr_path_pruning_disabled_ = disabled; } -void -Vertex::setRequiredsPruned(bool pruned) -{ - requireds_pruned_ = pruned; -} - TagGroupIndex Vertex::tagGroupIndex() const { @@ -1174,7 +1167,7 @@ Vertex::setRequireds(Required *requireds) } void -Vertex::setPrevPaths(PathVertexRep *prev_paths) +Vertex::setPrevPaths(PathPrev *prev_paths) { delete [] prev_paths_; prev_paths_ = prev_paths; diff --git a/include/sta/Graph.hh b/include/sta/Graph.hh index d718e725..4aa2313a 100644 --- a/include/sta/Graph.hh +++ b/include/sta/Graph.hh @@ -36,7 +36,7 @@ #include "Delay.hh" #include "GraphClass.hh" #include "VertexId.hh" -#include "PathVertexRep.hh" +#include "PathPrev.hh" #include "StaState.hh" namespace sta { @@ -55,7 +55,7 @@ typedef ObjectId EdgeId; static constexpr EdgeId edge_id_null = object_id_null; static constexpr ObjectIdx edge_idx_null = object_id_null; -static constexpr ObjectIdx vertex_idx_null = object_id_null; +static constexpr ObjectIdx vertex_idx_null = object_idx_null; // The graph acts as a BUILDER for the graph vertices and edges. class Graph : public StaState @@ -104,9 +104,9 @@ public: uint32_t count); Required *requireds(const Vertex *vertex) const; void deleteRequireds(Vertex *vertex); - PathVertexRep *makePrevPaths(Vertex *vertex, + PathPrev *makePrevPaths(Vertex *vertex, uint32_t count); - PathVertexRep *prevPaths(const Vertex *vertex) const; + PathPrev *prevPaths(const Vertex *vertex) const; void deletePrevPaths(Vertex *vertex); // Private to Search::deletePaths(Vertex). void deletePaths(Vertex *vertex); @@ -271,8 +271,8 @@ public: const Slew *slews() const { return slews_; } Arrival *arrivals() const { return arrivals_; } Arrival *requireds() const { return requireds_; } - PathVertexRep *prevPaths() const { return prev_paths_; } - void setPrevPaths(PathVertexRep *prev_paths); + PathPrev *prevPaths() const { return prev_paths_; } + void setPrevPaths(PathPrev *prev_paths); TagGroupIndex tagGroupIndex() const; void setTagGroupIndex(TagGroupIndex tag_index); // Slew is annotated by sdc set_annotated_transition cmd. @@ -312,8 +312,6 @@ public: bool crprPathPruningDisabled() const { return crpr_path_pruning_disabled_;} void setCrprPathPruningDisabled(bool disabled); bool hasRequireds() const { return requireds_ != nullptr; } - bool requiredsPruned() const { return requireds_pruned_; } - void setRequiredsPruned(bool pruned); // ObjectTable interface. ObjectIdx objectIdx() const { return object_idx_; } @@ -339,13 +337,13 @@ protected: // Search Arrival *arrivals_; Arrival *requireds_; - PathVertexRep *prev_paths_; + PathPrev *prev_paths_; // These fields are written by multiple threads, so they // cannot share the same word as the following bit fields. uint32_t tag_group_index_; // Each bit corresponds to a different BFS queue. - std::atomic bfs_in_queue_; // 4 + std::atomic bfs_in_queue_; // 8 unsigned int level_:Graph::vertex_level_bits; // 24 unsigned int slew_annotated_:slew_annotated_bits; // 4 @@ -367,7 +365,6 @@ protected: bool is_constrained_:1; bool has_downstream_clk_pin_:1; bool crpr_path_pruning_disabled_:1; - bool requireds_pruned_:1; unsigned object_idx_:VertexTable::idx_bits; // 7 private: @@ -385,7 +382,9 @@ public: Edge(); ~Edge(); Vertex *to(const Graph *graph) const { return graph->vertex(to_); } + VertexId to() const { return to_; } Vertex *from(const Graph *graph) const { return graph->vertex(from_); } + VertexId from() const { return from_; } TimingRole *role() const; bool isWire() const; TimingSense sense() const; diff --git a/include/sta/PathPrev.hh b/include/sta/PathPrev.hh new file mode 100644 index 00000000..3643bef1 --- /dev/null +++ b/include/sta/PathPrev.hh @@ -0,0 +1,75 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2025, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. +// +// Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// This notice may not be removed or altered from any source distribution. + +#pragma once + +#include "SdcClass.hh" +#include "SearchClass.hh" + +namespace sta { + +// "Pointer" to a previous path on a vertex (PathVertex) thru an edge/arc. +class PathPrev +{ +public: + PathPrev(); + PathPrev(const PathVertex *path, + const Edge *prev_edge, + const TimingArc *prev_arc, + const StaState *sta); + void init(); + void init(const PathPrev *path); + void init(const PathPrev &path); + void init(const PathVertex *path, + const Edge *prev_edge, + const TimingArc *prev_arc, + const StaState *sta); + bool isNull() const; + const char *name(const StaState *sta) const; + Vertex *vertex(const StaState *sta) const; + VertexId vertexId(const StaState *sta) const; + Edge *prevEdge(const StaState *sta) const; + TimingArc *prevArc(const StaState *sta) const; + Tag *tag(const StaState *sta) const; + TagIndex tagIndex() const { return prev_tag_index_; } + Arrival arrival(const StaState *sta) const; + void prevPath(const StaState *sta, + // Return values. + PathRef &prev_path, + TimingArc *&prev_arc) const; + + static bool equal(const PathPrev *path1, + const PathPrev *path2); + static bool equal(const PathPrev &path1, + const PathPrev &path2); + static int cmp(const PathPrev &path1, + const PathPrev &path2); + +protected: + EdgeId prev_edge_id_; + TagIndex prev_tag_index_:tag_index_bit_count; + unsigned prev_arc_idx_:2; +}; + +} // namespace diff --git a/include/sta/PathRef.hh b/include/sta/PathRef.hh index cec7b89a..50288e28 100644 --- a/include/sta/PathRef.hh +++ b/include/sta/PathRef.hh @@ -49,6 +49,8 @@ public: void init(const PathRef *path); void init(const PathVertex &path); void init(const PathVertex *path); + void init(const PathPrev &path, + const StaState *sta); void init(Vertex *vertex, Tag *tag, int arrival_index); diff --git a/include/sta/PathVertex.hh b/include/sta/PathVertex.hh index d8726d24..9d21140f 100644 --- a/include/sta/PathVertex.hh +++ b/include/sta/PathVertex.hh @@ -29,7 +29,8 @@ namespace sta { -class PathVertexRep; +class PathPrev; +class PathVertexPtr; // Implements Path API for a vertex. class PathVertex : public Path @@ -38,9 +39,11 @@ public: PathVertex(); PathVertex(const PathVertex &path); PathVertex(const PathVertex *path); - PathVertex(const PathVertexRep *path, + PathVertex(const PathPrev *path, const StaState *sta); - PathVertex(const PathVertexRep &path, + PathVertex(const PathPrev &path, + const StaState *sta); + PathVertex(const PathVertexPtr &path, const StaState *sta); // If tag is not in the vertex tag group isNull() is true. PathVertex(Vertex *vertex, @@ -50,9 +53,11 @@ public: Tag *tag, int arrival_index); void init(); - void init(const PathVertexRep *path, + void init(const PathPrev *path, const StaState *sta); - void init(const PathVertexRep &path, + void init(const PathPrev &path, + const StaState *sta); + void init(const PathVertexPtr &path, const StaState *sta); void init(Vertex *vertex, Tag *tag, diff --git a/include/sta/PathVertexPtr.hh b/include/sta/PathVertexPtr.hh new file mode 100644 index 00000000..80c89649 --- /dev/null +++ b/include/sta/PathVertexPtr.hh @@ -0,0 +1,63 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2025, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. +// +// Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// This notice may not be removed or altered from any source distribution. + +#pragma once + +#include "SearchClass.hh" + +namespace sta { + +// "Pointer" to a vertex path because there is no real path object to point to. +class PathVertexPtr +{ +public: + PathVertexPtr(); + PathVertexPtr(const PathVertex *path, + const StaState *sta); + void init(); + void init(const PathVertexPtr *path); + void init(const PathVertexPtr &path); + void init(const PathVertex *path, + const StaState *sta); + bool isNull() const; + const char *name(const StaState *sta) const; + Vertex *vertex(const StaState *sta) const; + VertexId vertexId() const { return vertex_id_; } + Tag *tag(const StaState *sta) const; + TagIndex tagIndex() const { return tag_index_; } + Arrival arrival(const StaState *sta) const; + + static bool equal(const PathVertexPtr *path1, + const PathVertexPtr *path2); + static bool equal(const PathVertexPtr &path1, + const PathVertexPtr &path2); + static int cmp(const PathVertexPtr &path1, + const PathVertexPtr &path2); + +protected: + VertexId vertex_id_; + TagIndex tag_index_; +}; + +} // namespace diff --git a/include/sta/PathVertexRep.hh b/include/sta/PathVertexRep.hh index b31c4ce6..d6249426 100644 --- a/include/sta/PathVertexRep.hh +++ b/include/sta/PathVertexRep.hh @@ -29,34 +29,30 @@ namespace sta { -// Path representation that references a vertex arrival via a tag. -// This does not implement the Path API which uses virtual functions -// that would make it larger. +// "Pointer" to a previous path on a vertex (PathVertex) thru an edge/arc. class PathVertexRep { public: - explicit PathVertexRep(); - explicit PathVertexRep(const PathVertexRep *path); - PathVertexRep(const PathVertexRep &path); - explicit PathVertexRep(const PathVertex *path, - const StaState *sta); - explicit PathVertexRep(const PathVertex &path, - const StaState *sta); - explicit PathVertexRep(VertexId vertex_id, - TagIndex tag_index, - bool is_enum); + PathVertexRep(); + PathVertexRep(const PathVertex *path, + const Edge *prev_edge, + const TimingArc *prev_arc, + const StaState *sta); void init(); void init(const PathVertexRep *path); void init(const PathVertexRep &path); void init(const PathVertex *path, + const Edge *prev_edge, + const TimingArc *prev_arc, const StaState *sta); - void init(const PathVertex &path, - const StaState *sta); - bool isNull() const { return vertex_id_ == 0; } - Vertex *vertex(const StaState *) const; - VertexId vertexId() const { return vertex_id_; } + bool isNull() const; + const char *name(const StaState *sta) const; + Vertex *vertex(const StaState *sta) const; + VertexId vertexId(const StaState *sta) const; + Edge *prevEdge(const StaState *sta) const; + TimingArc *prevArc(const StaState *sta) const; Tag *tag(const StaState *sta) const; - TagIndex tagIndex() const { return tag_index_; } + TagIndex tagIndex() const { return prev_tag_index_; } Arrival arrival(const StaState *sta) const; void prevPath(const StaState *sta, // Return values. @@ -67,15 +63,13 @@ public: const PathVertexRep *path2); static bool equal(const PathVertexRep &path1, const PathVertexRep &path2); - static int cmp(const PathVertexRep *path1, - const PathVertexRep *path2); static int cmp(const PathVertexRep &path1, const PathVertexRep &path2); protected: - VertexId vertex_id_; - TagIndex tag_index_; - bool is_enum_:1; + EdgeId prev_edge_id_; + TagIndex prev_tag_index_:tag_index_bit_count; + unsigned prev_arc_idx_:2; }; } // namespace diff --git a/include/sta/Sdc.hh b/include/sta/Sdc.hh index 7cd7540d..80c4e823 100644 --- a/include/sta/Sdc.hh +++ b/include/sta/Sdc.hh @@ -201,7 +201,7 @@ findLeafDriverPins(const Pin *pin, class Sdc : public StaState { public: - explicit Sdc(StaState *sta); + Sdc(StaState *sta); ~Sdc(); // Note that Search may reference a Filter exception removed by clear(). void clear(); @@ -377,31 +377,29 @@ public: float fanout); void setMaxArea(float area); float maxArea() const; - virtual Clock *makeClock(const char *name, - PinSet *pins, - bool add_to_pins, - float period, - FloatSeq *waveform, - const char *comment); + Clock *makeClock(const char *name, + PinSet *pins, + bool add_to_pins, + float period, + FloatSeq *waveform, + const char *comment); // edges size must be 3. - virtual Clock *makeGeneratedClock(const char *name, - PinSet *pins, - bool add_to_pins, - Pin *src_pin, - Clock *master_clk, - int divide_by, - int multiply_by, - float duty_cycle, - bool invert, - bool combinational, - IntSeq *edges, - FloatSeq *edge_shifts, - const char *comment); + Clock *makeGeneratedClock(const char *name, + PinSet *pins, + bool add_to_pins, + Pin *src_pin, + Clock *master_clk, + int divide_by, + int multiply_by, + float duty_cycle, + bool invert, + bool combinational, + IntSeq *edges, + FloatSeq *edge_shifts, + const char *comment); // Invalidate all generated clock waveforms. void invalidateGeneratedClks() const; - virtual void removeClock(Clock *clk); - virtual void clockDeletePin(Clock *clk, - Pin *pin); + void removeClock(Clock *clk); // Clock used for inputs without defined arrivals. ClockEdge *defaultArrivalClockEdge() const; Clock *defaultArrivalClock() const { return default_arrival_clk_; } @@ -485,22 +483,22 @@ public: bool &exists) const; const ClockInsertions &clockInsertions() const { return clk_insertions_; } // Clock uncertainty. - virtual void setClockUncertainty(Pin *pin, - const SetupHoldAll *setup_hold, - float uncertainty); - virtual void removeClockUncertainty(Pin *pin, - const SetupHoldAll *setup_hold); - virtual void setClockUncertainty(Clock *from_clk, - const RiseFallBoth *from_rf, - Clock *to_clk, - const RiseFallBoth *to_rf, - const SetupHoldAll *setup_hold, - float uncertainty); - virtual void removeClockUncertainty(Clock *from_clk, - const RiseFallBoth *from_rf, - Clock *to_clk, - const RiseFallBoth *to_rf, - const SetupHoldAll *setup_hold); + void setClockUncertainty(Pin *pin, + const SetupHoldAll *setup_hold, + float uncertainty); + void removeClockUncertainty(Pin *pin, + const SetupHoldAll *setup_hold); + void setClockUncertainty(Clock *from_clk, + const RiseFallBoth *from_rf, + Clock *to_clk, + const RiseFallBoth *to_rf, + const SetupHoldAll *setup_hold, + float uncertainty); + void removeClockUncertainty(Clock *from_clk, + const RiseFallBoth *from_rf, + Clock *to_clk, + const RiseFallBoth *to_rf, + const SetupHoldAll *setup_hold); ClockGroups *makeClockGroups(const char *name, bool logically_exclusive, bool physically_exclusive, @@ -873,7 +871,7 @@ public: float voltage); InputDrive *findInputDrive(Port *port); Clock *findClock(const char *name) const; - virtual ClockSeq findClocksMatching(PatternMatch *pattern) const; + ClockSeq findClocksMatching(PatternMatch *pattern) const; // True if pin is defined as a clock source (pin may be hierarchical). bool isClock(const Pin *pin) const; // True if pin is a clock source vertex. @@ -1036,13 +1034,13 @@ public: // Return values. ExceptionPath *&hi_priority_exception, int &hi_priority) const; - virtual bool exceptionMatchesTo(ExceptionPath *exception, - const Pin *pin, - const RiseFall *rf, - const ClockEdge *clk_edge, - const MinMax *min_max, - bool match_min_max_exactly, - bool require_to_pin) const; + bool exceptionMatchesTo(ExceptionPath *exception, + const Pin *pin, + const RiseFall *rf, + const ClockEdge *clk_edge, + const MinMax *min_max, + bool match_min_max_exactly, + bool require_to_pin) const; bool isCompleteTo(ExceptionState *state, const Pin *pin, const RiseFall *rf, @@ -1085,8 +1083,8 @@ protected: void deleteClkPinMappings(Clock *clk); void deleteExceptionPtHashMapSets(ExceptionPathPtHash &map); void makeClkPinMappings(Clock *clk); - virtual void deletePinClocks(Clock *defining_clk, - PinSet *pins); + void deletePinClocks(Clock *defining_clk, + PinSet *pins); void makeDefaultArrivalClock(); InputDrive *ensureInputDrive(const Port *port); PortExtCap *ensurePortExtPinCap(const Port *port, @@ -1097,8 +1095,8 @@ protected: void recordPathDelayInternalStartpoints(ExceptionPath *exception); void unrecordPathDelayInternalStartpoints(ExceptionFrom *from); bool pathDelayFrom(const Pin *pin); - virtual void recordPathDelayInternalEndpoints(ExceptionPath *exception); - virtual void unrecordPathDelayInternalEndpoints(ExceptionPath *exception); + void recordPathDelayInternalEndpoints(ExceptionPath *exception); + void unrecordPathDelayInternalEndpoints(ExceptionPath *exception); bool pathDelayTo(const Pin *pin); bool hasLibertyCheckTo(const Pin *pin); void deleteMatchingExceptions(ExceptionPath *exception); diff --git a/include/sta/Search.hh b/include/sta/Search.hh index efa08c19..d59e9fa5 100644 --- a/include/sta/Search.hh +++ b/include/sta/Search.hh @@ -117,7 +117,6 @@ public: void arrivalsInvalid(); // Invalidate vertex arrival time. void arrivalInvalid(Vertex *vertex); - void arrivalInvalidDelete(Vertex *vertex); void arrivalInvalid(const Pin *pin); // Invalidate all required times. void requiredsInvalid(); @@ -373,6 +372,7 @@ public: bool unconstrained, bool thru_latches); VertexSeq filteredEndpoints(); + bool alwaysSavePrevPaths() const { return always_save_prev_paths_; } protected: void init(StaState *sta); @@ -613,6 +613,7 @@ protected: std::mutex pending_latch_outputs_lock_; VertexSet *endpoints_; VertexSet *invalid_endpoints_; + bool always_save_prev_paths_; // Filter exception to tag arrivals for // report_timing -from pin|inst -through. // -to is always nullptr. @@ -760,6 +761,7 @@ protected: void constrainedRequiredsInvalid(Vertex *vertex, bool is_clk); bool always_to_endpoints_; + bool always_save_prev_paths_; TagGroupBldr *tag_bldr_; TagGroupBldr *tag_bldr_no_crpr_; SearchPred *adj_pred_; diff --git a/include/sta/SearchClass.hh b/include/sta/SearchClass.hh index fb207de5..ac558426 100644 --- a/include/sta/SearchClass.hh +++ b/include/sta/SearchClass.hh @@ -43,7 +43,8 @@ class Corner; class Path; class PathRep; class PathVertex; -class PathVertexRep; +class PathPrev; +class PathVertexPtr; class PathRef; class PathEnumed; class PathEnd; @@ -136,7 +137,8 @@ enum class ReportPathFormat { full, json }; -static const TagIndex tag_index_max = std::numeric_limits::max(); +static const TagIndex tag_index_bit_count = 28; +static const TagIndex tag_index_max = (1 << tag_index_bit_count) - 1; static const TagIndex tag_index_null = tag_index_max; static const int path_ap_index_bit_count = 8; // One path analysis point per corner min/max. diff --git a/include/sta/TclTypeHelpers.hh b/include/sta/TclTypeHelpers.hh index 506d3a0c..a70f8400 100644 --- a/include/sta/TclTypeHelpers.hh +++ b/include/sta/TclTypeHelpers.hh @@ -48,6 +48,7 @@ tclListSetStdString(Tcl_Obj *const source, void tclArgError(Tcl_Interp *interp, + int id, const char *msg, const char *arg); diff --git a/parasitics/SpefReader.cc b/parasitics/SpefReader.cc index 049928b1..88dadf2e 100644 --- a/parasitics/SpefReader.cc +++ b/parasitics/SpefReader.cc @@ -502,7 +502,7 @@ SpefReader::findParasiticNode(char *name, warn(1656, "pin %s not found.", name1); } else - warn(1656, "pin %s not found.", name); + warn(1657, "pin %s not found.", name); } } return nullptr; @@ -624,7 +624,7 @@ SpefScanner::SpefScanner(std::istream *stream, void SpefScanner::error(const char *msg) { - report_->fileError(1866, filename_.c_str(), lineno(), "%s", msg); + report_->fileError(1867, filename_.c_str(), lineno(), "%s", msg); } } // namespace diff --git a/power/Power.cc b/power/Power.cc index d944408e..cd564c3f 100644 --- a/power/Power.cc +++ b/power/Power.cc @@ -664,7 +664,9 @@ Power::ensureActivities() // unless it has been set by command. if (input_activity_.density() == 0.0) { float min_period = clockMinPeriod(); - float density = 0.1 / (min_period != 0.0 ? min_period : 0.0); + float density = 0.1 / (min_period != 0.0 + ? min_period + : units_->timeUnit()->scale()); input_activity_.set(density, 0.5, PwrActivityOrigin::input); } ActivitySrchPred activity_srch_pred(this); diff --git a/power/Power.tcl b/power/Power.tcl index dca43217..feebc7c1 100644 --- a/power/Power.tcl +++ b/power/Power.tcl @@ -266,7 +266,7 @@ proc set_power_activity { args } { check_positive_float "density" $density set density [expr $density / [time_ui_sta 1.0]] if { [info exists keys(-clock)] } { - sta_warn 302 "-clock ignored for -density" + sta_warn 308 "-clock ignored for -density" } } set duty 0.5 @@ -274,7 +274,7 @@ proc set_power_activity { args } { set duty $keys(-duty) check_float "duty" $duty if { $duty < 0.0 || $duty > 1.0 } {i - sta_error 302 "duty should be 0.0 to 1.0" + sta_error 309 "duty should be 0.0 to 1.0" } } diff --git a/power/SaifParse.yy b/power/SaifParse.yy index 15cfd08b..03076627 100644 --- a/power/SaifParse.yy +++ b/power/SaifParse.yy @@ -42,7 +42,7 @@ void sta::SaifParse::error(const location_type &loc, const string &msg) { - reader->report()->fileError(164,reader->filename(),loc.begin.line,"%s",msg.c_str()); + reader->report()->fileError(169,reader->filename(),loc.begin.line,"%s",msg.c_str()); } %} diff --git a/power/SaifReader.cc b/power/SaifReader.cc index 629e6008..2e717799 100644 --- a/power/SaifReader.cc +++ b/power/SaifReader.cc @@ -222,7 +222,7 @@ SaifScanner::SaifScanner(std::istream *stream, void SaifScanner::error(const char *msg) { - report_->fileError(1866, filename_.c_str(), lineno(), "%s", msg); + report_->fileError(1868, filename_.c_str(), lineno(), "%s", msg); } } // namespace diff --git a/sdc/Sdc.cc b/sdc/Sdc.cc index f15c4f9d..95a34e60 100644 --- a/sdc/Sdc.cc +++ b/sdc/Sdc.cc @@ -1176,19 +1176,6 @@ Sdc::deleteMasterClkRefs(Clock *clk) } } -void -Sdc::clockDeletePin(Clock *clk, - Pin *pin) -{ - ClockSet *pin_clks = clock_pin_map_.findKey(pin); - pin_clks->erase(clk); - if (pin_clks->empty()) - clock_pin_map_.erase(pin); - clk->deletePin(pin); - clk->makeLeafPins(network_); - makeClkPinMappings(clk); -} - Clock * Sdc::findClock(const char *name) const { diff --git a/sdc/Sdc.i b/sdc/Sdc.i index c03a8165..4291dcb4 100644 --- a/sdc/Sdc.i +++ b/sdc/Sdc.i @@ -1323,6 +1323,17 @@ filter_timing_arcs(const char *property, //////////////////////////////////////////////////////////////// +StringSeq +path_group_names() +{ + StringSeq pg_names; + for (auto const& [name, group] : Sta::sta()->sdc()->groupPaths()) + pg_names.push_back(name); + return pg_names; +} + +//////////////////////////////////////////////////////////////// + void set_voltage_global(const MinMax *min_max, float voltage) diff --git a/sdf/SdfReader.cc b/sdf/SdfReader.cc index 963db575..d3f8a6dc 100644 --- a/sdf/SdfReader.cc +++ b/sdf/SdfReader.cc @@ -1100,7 +1100,7 @@ SdfScanner::SdfScanner(std::istream *stream, void SdfScanner::error(const char *msg) { - report_->fileError(1866, filename_.c_str(), lineno(), "%s", msg); + report_->fileError(1869, filename_.c_str(), lineno(), "%s", msg); } } // namespace diff --git a/search/ClkInfo.cc b/search/ClkInfo.cc index 89b10471..ca7559e9 100644 --- a/search/ClkInfo.cc +++ b/search/ClkInfo.cc @@ -53,7 +53,7 @@ ClkInfo::ClkInfo(const ClockEdge *clk_edge, float latency, ClockUncertainties *uncertainties, PathAPIndex path_ap_index, - PathVertexRep &crpr_clk_path, + PathVertexPtr &crpr_clk_path, const StaState *sta) : clk_edge_(clk_edge), clk_src_(clk_src), @@ -128,6 +128,7 @@ ClkInfo::asString(const StaState *sta) const result += "/"; result += std::to_string(path_ap_index_); + result += " "; if (clk_edge_) result += clk_edge_->name(); else @@ -212,7 +213,7 @@ clkInfoEqual(const ClkInfo *clk_info1, && clk_info1->clkSrc() == clk_info2->clkSrc() && clk_info1->genClkSrc() == clk_info2->genClkSrc() && (!crpr_on - || (PathVertexRep::equal(clk_info1->crprClkPath(), + || (PathVertexPtr::equal(clk_info1->crprClkPath(), clk_info2->crprClkPath()))) && ((uncertainties1 == nullptr && uncertainties2 == nullptr) @@ -278,9 +279,9 @@ clkInfoCmp(const ClkInfo *clk_info1, bool crpr_on = sta->sdc()->crprActive(); if (crpr_on) { - const PathVertexRep &crpr_path1 = clk_info1->crprClkPath(); - const PathVertexRep &crpr_path2 = clk_info2->crprClkPath(); - int path_cmp = PathVertexRep::cmp(crpr_path1, crpr_path2); + const PathVertexPtr &crpr_path1 = clk_info1->crprClkPath(); + const PathVertexPtr &crpr_path2 = clk_info2->crprClkPath(); + int path_cmp = PathVertexPtr::cmp(crpr_path1, crpr_path2); if (path_cmp != 0) return path_cmp; } diff --git a/search/ClkInfo.hh b/search/ClkInfo.hh index 977f77d6..e7a548fd 100644 --- a/search/ClkInfo.hh +++ b/search/ClkInfo.hh @@ -26,7 +26,8 @@ #include "Transition.hh" #include "SearchClass.hh" -#include "PathVertexRep.hh" +#include "PathVertexPtr.hh" +#include "Sdc.hh" namespace sta { @@ -45,7 +46,7 @@ public: float latency, ClockUncertainties *uncertainties, PathAPIndex path_ap_index, - PathVertexRep &crpr_clk_path, + PathVertexPtr &crpr_clk_path, const StaState *sta); ~ClkInfo(); const char *asString(const StaState *sta) const; @@ -64,8 +65,8 @@ public: PathAPIndex pathAPIndex() const { return path_ap_index_; } // Clock path used for crpr resolution. // Null for clocks because the path cannot point to itself. - PathVertexRep &crprClkPath() { return crpr_clk_path_; } - const PathVertexRep &crprClkPath() const { return crpr_clk_path_; } + PathVertexPtr &crprClkPath() { return crpr_clk_path_; } + const PathVertexPtr &crprClkPath() const { return crpr_clk_path_; } VertexId crprClkVertexId() const; bool hasCrprClkPin() const { return !crpr_clk_path_.isNull(); } bool refsFilter(const StaState *sta) const; @@ -80,7 +81,7 @@ private: const ClockEdge *clk_edge_; const Pin *clk_src_; const Pin *gen_clk_src_; - PathVertexRep crpr_clk_path_; + PathVertexPtr crpr_clk_path_; ClockUncertainties *uncertainties_; Arrival insertion_; float latency_; diff --git a/search/Crpr.cc b/search/Crpr.cc index 898a21d6..ef35c772 100644 --- a/search/Crpr.cc +++ b/search/Crpr.cc @@ -33,7 +33,7 @@ #include "Graph.hh" #include "Sdc.hh" #include "PathVertex.hh" -#include "PathVertexRep.hh" +#include "PathPrev.hh" #include "Path.hh" #include "PathAnalysisPt.hh" #include "ClkInfo.hh" @@ -63,7 +63,7 @@ CheckCrpr::clkPathPrev(const PathVertex *path, int arrival_index; bool exists; path->arrivalIndex(arrival_index, exists); - PathVertexRep *prevs = graph_->prevPaths(vertex); + PathPrev *prevs = graph_->prevPaths(vertex); if (prevs) prev.init(prevs[arrival_index], this); else @@ -74,7 +74,7 @@ PathVertex CheckCrpr::clkPathPrev(Vertex *vertex, int arrival_index) { - PathVertexRep *prevs = graph_->prevPaths(vertex); + PathPrev *prevs = graph_->prevPaths(vertex); if (prevs) return PathVertex(prevs[arrival_index], this); else { @@ -90,7 +90,7 @@ CheckCrpr::clkPathPrev(Vertex *vertex, Arrival CheckCrpr::maxCrpr(ClkInfo *clk_info) { - const PathVertexRep &crpr_clk_path = clk_info->crprClkPath(); + const PathVertexPtr &crpr_clk_path = clk_info->crprClkPath(); if (!crpr_clk_path.isNull()) { PathVertex crpr_clk_vpath(crpr_clk_path, this); if (!crpr_clk_vpath.isNull()) { @@ -166,7 +166,7 @@ CheckCrpr::checkCrpr1(const Path *src_path, const Clock *src_clk = src_clk_info->clock(); const Clock *tgt_clk = tgt_clk_info->clock(); PathVertex src_clk_path1; - PathVertexRep &src_crpr_clk_path = src_clk_info->crprClkPath(); + const PathVertexPtr &src_crpr_clk_path = src_clk_info->crprClkPath(); const PathVertex *src_clk_path = nullptr; if (src_tag->isClock()) { src_clk_path1.init(src_path->vertex(this), src_path->tag(this), this); @@ -302,8 +302,8 @@ CheckCrpr::genClkSrcPaths(const PathVertex *path, PathAnalysisPt *path_ap = path->pathAnalysisPt(this); gclk_paths.push_back(path); while (clk_edge->clock()->isGenerated()) { - PathVertex genclk_path; - search_->genclks()->srcPath(clk_edge, clk_src, path_ap, genclk_path); + PathVertex genclk_path = + search_->genclks()->srcPath(clk_edge, clk_src, path_ap); if (genclk_path.isNull()) break; clk_info = genclk_path.clkInfo(this); diff --git a/search/Genclks.cc b/search/Genclks.cc index c0cebf84..573dcf0f 100644 --- a/search/Genclks.cc +++ b/search/Genclks.cc @@ -40,7 +40,7 @@ #include "Corner.hh" #include "PathAnalysisPt.hh" #include "Levelize.hh" -#include "PathVertexRep.hh" +#include "PathVertexPtr.hh" #include "Search.hh" namespace sta { @@ -856,7 +856,7 @@ Genclks::copyGenClkSrcPaths(Vertex *vertex, { Arrival *arrivals = graph_->arrivals(vertex); if (arrivals) { - PathVertexRep *prev_paths = graph_->prevPaths(vertex); + PathPrev *prev_paths = graph_->prevPaths(vertex); TagGroup *tag_group = search_->tagGroup(vertex); if (tag_group) { ArrivalMap::Iterator arrival_iter(tag_group->arrivalMap()); @@ -866,7 +866,7 @@ Genclks::copyGenClkSrcPaths(Vertex *vertex, arrival_iter.next(tag, arrival_index); if (tag->isGenClkSrcPath()) { Arrival arrival = arrivals[arrival_index]; - PathVertexRep *prev_path = prev_paths + PathPrev *prev_path = prev_paths ? &prev_paths[arrival_index] : nullptr; tag_bldr->setArrival(tag, arrival, prev_path); @@ -903,7 +903,7 @@ Genclks::recordSrcPaths(Clock *gclk) bool has_edges = gclk->edges() != nullptr; for (const Pin *gclk_pin : gclk->leafPins()) { - PathVertexRep *src_paths = new PathVertexRep[path_count]; + PathVertexPtr *src_paths = new PathVertexPtr[path_count]; genclk_src_paths_.insert(ClockPinPair(gclk, gclk_pin), src_paths); Vertex *gclk_vertex = srcPathVertex(gclk_pin); @@ -920,7 +920,7 @@ Genclks::recordSrcPaths(Clock *gclk) bool inverting_path = (rf != src_clk_rf); const PathAnalysisPt *path_ap = path->pathAnalysisPt(this); int path_index = srcPathIndex(rf, path_ap); - PathVertexRep &src_path = src_paths[path_index]; + PathVertexPtr &src_path = src_paths[path_index]; if ((!divide_by_1 || (inverting_path == invert)) && (!has_edges @@ -973,47 +973,40 @@ Genclks::matchesSrcFilter(Path *path, return false; } -void -Genclks::srcPath(Path *clk_path, - // Return value. - PathVertex &src_path) const +PathVertex +Genclks::srcPath(Path *clk_path) const { const Pin *src_pin = clk_path->pin(this); const ClockEdge *clk_edge = clk_path->clkEdge(this); const PathAnalysisPt *path_ap = clk_path->pathAnalysisPt(this); const EarlyLate *early_late = clk_path->minMax(this); PathAnalysisPt *insert_ap = path_ap->insertionAnalysisPt(early_late); - srcPath(clk_edge->clock(), src_pin, clk_edge->transition(), - insert_ap, src_path); + return srcPath(clk_edge->clock(), src_pin, clk_edge->transition(), + insert_ap); } -void +PathVertex Genclks::srcPath(const ClockEdge *clk_edge, const Pin *src_pin, - const PathAnalysisPt *path_ap, - // Return value. - PathVertex &src_path) const + const PathAnalysisPt *path_ap) const { - srcPath(clk_edge->clock(), src_pin, clk_edge->transition(), - path_ap, src_path); + return srcPath(clk_edge->clock(), src_pin, clk_edge->transition(), path_ap); } -void +PathVertex Genclks::srcPath(const Clock *gclk, const Pin *src_pin, const RiseFall *rf, - const PathAnalysisPt *path_ap, - // Return value. - PathVertex &src_path) const + const PathAnalysisPt *path_ap) const { - PathVertexRep *src_paths = + PathVertexPtr *src_paths = genclk_src_paths_.findKey(ClockPinPair(gclk, src_pin)); if (src_paths) { int path_index = srcPathIndex(rf, path_ap); - src_path.init(src_paths[path_index], this); + return PathVertex(src_paths[path_index], this); } else - src_path.init(); + return PathVertex(); } Arrival @@ -1023,9 +1016,8 @@ Genclks::insertionDelay(const Clock *clk, const EarlyLate *early_late, const PathAnalysisPt *path_ap) const { - PathVertex src_path; PathAnalysisPt *insert_ap = path_ap->insertionAnalysisPt(early_late); - srcPath(clk, pin, rf, insert_ap, src_path); + PathVertex src_path = srcPath(clk, pin, rf, insert_ap); if (!src_path.isNull()) return src_path.arrival(this); else diff --git a/search/Genclks.hh b/search/Genclks.hh index 4b76b06d..7d662e1b 100644 --- a/search/Genclks.hh +++ b/search/Genclks.hh @@ -50,7 +50,7 @@ public: }; typedef Map GenclkInfoMap; -typedef Map GenclkSrcPathMap; +typedef Map GenclkSrcPathMap; class Genclks : public StaState { @@ -71,21 +71,15 @@ public: const EarlyLate *early_late, const PathAnalysisPt *path_ap) const; // Generated clock source path for a clock path root. - void srcPath(Path *clk_path, - // Return value. - PathVertex &src_path) const; + PathVertex srcPath(Path *clk_path) const; // Generated clock source path. - void srcPath(const ClockEdge *clk_edge, - const Pin *src_pin, - const PathAnalysisPt *path_ap, - // Return value. - PathVertex &src_path) const; - void srcPath(const Clock *clk, - const Pin *src_pin, - const RiseFall *rf, - const PathAnalysisPt *path_ap, - // Return value. - PathVertex &src_path) const; + PathVertex srcPath(const ClockEdge *clk_edge, + const Pin *src_pin, + const PathAnalysisPt *path_ap) const; + PathVertex srcPath(const Clock *clk, + const Pin *src_pin, + const RiseFall *rf, + const PathAnalysisPt *path_ap) const; Vertex *srcPathVertex(const Pin *pin) const; Level clkPinMaxLevel(const Clock *clk) const; void copyGenClkSrcPaths(Vertex *vertex, diff --git a/search/PathEnum.cc b/search/PathEnum.cc index 0b151b07..a8dd572c 100644 --- a/search/PathEnum.cc +++ b/search/PathEnum.cc @@ -354,13 +354,15 @@ PathEnumFaninVisitor::visitFromToPath(const Pin *, PathEnumed *after_div_copy; // Make the diverted path end to check slack with from_path crpr. makeDivertedPathEnd(from_path, arc, div_end, after_div_copy); - // Only enumerate paths with greater slack. - if (delayGreaterEqual(div_end->slack(this), path_end_slack_, this)) { - reportDiversion(arc, from_path); - path_enum_->makeDiversion(div_end, after_div_copy); + if (div_end) { + // Only enumerate paths with greater slack. + if (delayGreaterEqual(div_end->slack(this), path_end_slack_, this)) { + reportDiversion(arc, from_path); + path_enum_->makeDiversion(div_end, after_div_copy); + } + else + delete div_end; } - else - delete div_end; } // Only enumerate slower/faster paths. else if (delayLessEqual(to_arrival, before_div_arrival_, min_max, this)) { @@ -384,8 +386,12 @@ PathEnumFaninVisitor::makeDivertedPathEnd(Path *after_div, PathEnumed *div_path; path_enum_->makeDivertedPath(path_end_->path(), &before_div_, after_div, div_arc, div_path, after_div_copy); - div_end = path_end_->copy(); - div_end->setPath(div_path); + if (after_div_copy) { + div_end = path_end_->copy(); + div_end->setPath(div_path); + } + else + div_end = nullptr; } void @@ -539,17 +545,15 @@ PathEnum::makeDivertedPath(Path *path, PathEnumed *&div_path, PathEnumed *&after_div_copy) { + div_path = nullptr; + after_div_copy = nullptr; // Copy the diversion path. bool found_div = false; PathEnumedSeq copies; PathRef p(path); bool first = true; PathEnumed *prev_copy = nullptr; - VertexSet visited(graph_); - while (!p.isNull() - // Break latch loops. - && !visited.hasKey(p.vertex(this))) { - visited.insert(p.vertex(this)); + while (!p.isNull()) { PathRef prev; TimingArc *prev_arc; p.prevPath(this, prev, prev_arc); @@ -562,10 +566,12 @@ PathEnum::makeDivertedPath(Path *path, prev_copy->setPrevPath(copy); copies.push_back(copy); - if (first) - div_path = copy; if (Path::equal(&p, after_div, this)) after_div_copy = copy; + if (first) + div_path = copy; + else if (network_->isLatchData(p.pin(this))) + break; if (Path::equal(&p, before_div, this)) { copy->setPrevArc(div_arc); // Update the delays forward from before_div to the end of the path. @@ -598,7 +604,7 @@ PathEnum::updatePathHeadDelays(PathEnumedSeq &paths, ArcDelay arc_delay = search_->deratedDelay(edge->from(graph_), arc, edge, false, path_ap); Arrival arrival = prev_arrival + arc_delay; - debugPrint(debug_, "path_enum", 3, "update arrival %s %s %s -> %s", + debugPrint(debug_, "path_enum", 5, "update arrival %s %s %s -> %s", path->vertex(this)->name(network_), path->tag(this)->asString(this), delayAsString(path->arrival(this), this), diff --git a/search/PathExpanded.cc b/search/PathExpanded.cc index 6eb2c578..93c54946 100644 --- a/search/PathExpanded.cc +++ b/search/PathExpanded.cc @@ -115,8 +115,7 @@ PathExpanded::expandGenclk(PathRef *clk_path) if (!clk_path->isNull()) { const Clock *src_clk = clk_path->clock(sta_); if (src_clk && src_clk->isGenerated()) { - PathVertex src_path; - sta_->search()->genclks()->srcPath(clk_path, src_path); + PathVertex src_path = sta_->search()->genclks()->srcPath(clk_path); if (!src_path.isNull()) { // The head of the genclk src path is already in paths_, // so skip past it. diff --git a/search/PathGroup.cc b/search/PathGroup.cc index 119a21c6..482936cb 100644 --- a/search/PathGroup.cc +++ b/search/PathGroup.cc @@ -132,7 +132,7 @@ PathGroup::saveable(PathEnd *path_end) // endpoint_path_count > 1 with slack_min requires // saving endpoints with slack > slack_min so that -// path enumeration can find them. Use the patg end +// path enumeration can find them. Use the path end // with the min(max) delay to prune ends that cannot // onion peel down to slack_min. bool diff --git a/search/PathPrev.cc b/search/PathPrev.cc new file mode 100644 index 00000000..8de8d78a --- /dev/null +++ b/search/PathPrev.cc @@ -0,0 +1,246 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2025, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. +// +// Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// This notice may not be removed or altered from any source distribution. + +#include "PathPrev.hh" + +#include "Graph.hh" +#include "TimingArc.hh" +#include "SearchClass.hh" +#include "Tag.hh" +#include "TagGroup.hh" +#include "Search.hh" +#include "PathAnalysisPt.hh" +#include "PathVertex.hh" + +namespace sta { + +PathPrev::PathPrev() +{ + init(); +} + +void +PathPrev::init() +{ + prev_edge_id_ = edge_id_null; + prev_arc_idx_ = 0; + prev_tag_index_ = tag_index_null; +} + +void +PathPrev::init(const PathPrev *path) +{ + if (path) { + prev_edge_id_ = path->prev_edge_id_; + prev_arc_idx_ = path->prev_arc_idx_; + prev_tag_index_ = path->prev_tag_index_; + } + else + init(); +} + +void +PathPrev::init(const PathPrev &path) +{ + prev_edge_id_ = path.prev_edge_id_; + prev_arc_idx_ = path.prev_arc_idx_; + prev_tag_index_ = path.prev_tag_index_; +} + +void +PathPrev::init(const PathVertex *path, + const Edge *prev_edge, + const TimingArc *prev_arc, + const StaState *sta) +{ + if (path == nullptr || path->isNull()) + init(); + else { + const Graph *graph = sta->graph(); + prev_edge_id_ = graph->id(prev_edge); + prev_arc_idx_ = prev_arc->index(); + prev_tag_index_ = path->tag(sta)->index(); + } +} + +const char * +PathPrev::name(const StaState *sta) const +{ + const Network *network = sta->network(); + const Search *search = sta->search(); + Vertex *vertex = this->vertex(sta); + if (vertex) { + const char *vertex_name = vertex->name(network); + const Tag *tag = this->tag(search); + const RiseFall *rf = tag->transition(); + const char *rf_str = rf->asString(); + const PathAnalysisPt *path_ap = tag->pathAnalysisPt(sta); + int ap_index = path_ap->index(); + const char *min_max = path_ap->pathMinMax()->asString(); + TagIndex tag_index = tag->index(); + return stringPrintTmp("%s %s %s/%d %d", + vertex_name, rf_str, min_max, + ap_index, tag_index); + } + else + return "NULL"; +} + +bool +PathPrev::isNull() const +{ + return prev_edge_id_ == edge_id_null; +} + +VertexId +PathPrev::vertexId(const StaState *sta) const +{ + if (prev_edge_id_ == edge_id_null) + return vertex_id_null; + else { + const Graph *graph = sta->graph(); + const Edge *edge = graph->edge(prev_edge_id_); + return edge->from(); + } +} + +Vertex * +PathPrev::vertex(const StaState *sta) const +{ + if (prev_edge_id_ == edge_id_null) + return nullptr; + else { + const Graph *graph = sta->graph(); + const Edge *edge = graph->edge(prev_edge_id_); + return edge->from(graph); + } +} + +Edge * +PathPrev::prevEdge(const StaState *sta) const +{ + if (prev_edge_id_ == edge_id_null) + return nullptr; + else { + const Graph *graph = sta->graph(); + return graph->edge(prev_edge_id_); + } +} + +TimingArc * +PathPrev::prevArc(const StaState *sta) const +{ + if (prev_edge_id_ == edge_id_null) + return nullptr; + else { + const Graph *graph = sta->graph(); + const Edge *edge = graph->edge(prev_edge_id_); + TimingArcSet *arc_set = edge->timingArcSet(); + return arc_set->findTimingArc(prev_arc_idx_); + } +} + +Tag * +PathPrev::tag(const StaState *sta) const +{ + const Search *search = sta->search(); + return search->tag(prev_tag_index_); +} + +Arrival +PathPrev::arrival(const StaState *sta) const +{ + Graph *graph = sta->graph(); + const Search *search = sta->search(); + Tag *tag = search->tag(prev_tag_index_); + Vertex *vertex = this->vertex(sta); + TagGroup *tag_group = search->tagGroup(vertex); + if (tag_group) { + int arrival_index; + bool arrival_exists; + tag_group->arrivalIndex(tag, arrival_index, arrival_exists); + if (!arrival_exists) + sta->report()->critical(1420, "tag group missing tag"); + Arrival *arrivals = graph->arrivals(vertex); + if (arrivals) + return arrivals[arrival_index]; + else + sta->report()->critical(1421, "missing arrivals"); + } + else + sta->report()->error(1422, "missing arrivals."); + return 0.0; +} + +void +PathPrev::prevPath(const StaState *sta, + // Return values. + PathRef &prev_path, + TimingArc *&prev_arc) const +{ + PathVertex path_vertex(this, sta); + path_vertex.prevPath(sta, prev_path, prev_arc); +} + +//////////////////////////////////////////////////////////////// + +bool +PathPrev::equal(const PathPrev *path1, + const PathPrev *path2) +{ + return path1->prev_edge_id_ == path2->prev_edge_id_ + && path1->prev_tag_index_ == path2->prev_tag_index_; +} + +bool +PathPrev::equal(const PathPrev &path1, + const PathPrev &path2) +{ + return path1.prev_edge_id_ == path2.prev_edge_id_ + && path1.prev_tag_index_ == path2.prev_tag_index_; +} + +int +PathPrev::cmp(const PathPrev &path1, + const PathPrev &path2) +{ + EdgeId edge_id1 = path1.prev_edge_id_; + EdgeId edge_id2 = path2.prev_edge_id_; + if (edge_id1 == edge_id2) { + TagIndex tag_index1 = path1.prev_tag_index_; + TagIndex tag_index2 = path2.prev_tag_index_; + if (tag_index1 == tag_index2) + return 0; + else if (tag_index1 < tag_index2) + return -1; + else + return 1; + } + else if (edge_id1 < edge_id2) + return -1; + else + return 1; +} + +} // namespace diff --git a/search/PathRef.cc b/search/PathRef.cc index 70401ef6..74bb0aae 100644 --- a/search/PathRef.cc +++ b/search/PathRef.cc @@ -96,6 +96,26 @@ PathRef::init(const PathVertex &path) path_vertex_ = path; } +void +PathRef::init(const PathPrev &path, + const StaState *sta) +{ + int arrival_index = 0; + TagIndex tag_index = path.tagIndex(); + Tag *tag = nullptr; + if (tag_index != tag_index_null) { + const Search *search = sta->search(); + tag = search->tag(tag_index); + Vertex *vertex = path.vertex(sta); + TagGroup *tag_group = search->tagGroup(vertex); + if (tag_group) { + bool arrival_exists; + tag_group->arrivalIndex(tag, arrival_index, arrival_exists); + } + } + path_vertex_.init(path.vertex(sta), tag, arrival_index); +} + void PathRef::init(Vertex *vertex, Tag *tag, diff --git a/search/PathVertex.cc b/search/PathVertex.cc index 5bb20a57..9efcc03e 100644 --- a/search/PathVertex.cc +++ b/search/PathVertex.cc @@ -36,7 +36,8 @@ #include "TagGroup.hh" #include "PathAnalysisPt.hh" #include "PathRef.hh" -#include "PathVertexRep.hh" +#include "PathPrev.hh" +#include "PathVertexPtr.hh" #include "Search.hh" namespace sta { @@ -83,7 +84,7 @@ PathVertex::PathVertex(Vertex *vertex, { } -PathVertex::PathVertex(const PathVertexRep *path, +PathVertex::PathVertex(const PathPrev *path, const StaState *sta) { if (path) @@ -92,7 +93,16 @@ PathVertex::PathVertex(const PathVertexRep *path, init(); } -PathVertex::PathVertex(const PathVertexRep &path, +PathVertex::PathVertex(const PathPrev &path, + const StaState *sta) +{ + if (path.isNull()) + init(); + else + init(path.vertex(sta), path.tag(sta), sta); +} + +PathVertex::PathVertex(const PathVertexPtr &path, const StaState *sta) { if (path.isNull()) @@ -140,7 +150,7 @@ PathVertex::init(Vertex *vertex, } void -PathVertex::init(const PathVertexRep *path, +PathVertex::init(const PathPrev *path, const StaState *sta) { if (path) @@ -150,7 +160,17 @@ PathVertex::init(const PathVertexRep *path, } void -PathVertex::init(const PathVertexRep &path, +PathVertex::init(const PathPrev &path, + const StaState *sta) +{ + if (!path.isNull()) + init(path.vertex(sta), path.tag(sta), sta); + else + init(); +} + +void +PathVertex::init(const PathVertexPtr &path, const StaState *sta) { if (!path.isNull()) @@ -481,9 +501,19 @@ PathVertex::prevPath(const StaState *sta, PathRef &prev_path, TimingArc *&prev_arc) const { - PathVertex prev; - prevPath(sta, prev, prev_arc); - prev.setRef(prev_path); + const Graph *graph = sta->graph(); + Vertex *vertex = this->vertex(graph); + PathPrev *prev_paths = vertex->prevPaths(); + if (prev_paths) { + PathPrev &prev = prev_paths[arrival_index_]; + prev_path.init(prev, sta); + prev_arc = prev.isNull() ? nullptr : prev.prevArc(sta); + } + else { + PathVertex prev; + prevPath(sta, prev, prev_arc); + prev.setRef(prev_path); + } } //////////////////////////////////////////////////////////////// diff --git a/search/PathVertexPtr.cc b/search/PathVertexPtr.cc new file mode 100644 index 00000000..16fc7d9d --- /dev/null +++ b/search/PathVertexPtr.cc @@ -0,0 +1,201 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2025, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. +// +// Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// This notice may not be removed or altered from any source distribution. + +#include "PathVertexPtr.hh" + +#include "Graph.hh" +#include "TimingArc.hh" +#include "SearchClass.hh" +#include "Tag.hh" +#include "TagGroup.hh" +#include "Search.hh" +#include "PathAnalysisPt.hh" +#include "PathVertex.hh" + +namespace sta { + +PathVertexPtr::PathVertexPtr() : + vertex_id_(vertex_id_null), + tag_index_(tag_index_null) +{ +} + +PathVertexPtr::PathVertexPtr(const PathVertex *path, + const StaState *sta) +{ + init(path, sta); +} + +void +PathVertexPtr::init() +{ + vertex_id_ = vertex_id_null; + tag_index_ = tag_index_null; +} + +void +PathVertexPtr::init(const PathVertexPtr *path) +{ + if (path) { + vertex_id_ = path->vertex_id_; + tag_index_ = path->tag_index_; + } + else { + vertex_id_ = vertex_id_null; + tag_index_ = tag_index_null; + } +} + +void +PathVertexPtr::init(const PathVertexPtr &path) +{ + vertex_id_ = path.vertex_id_; + tag_index_ = path.tag_index_; +} + +void +PathVertexPtr::init(const PathVertex *path, + const StaState *sta) +{ + if (path == nullptr || path->isNull()) + init(); + else { + vertex_id_ = path->vertexId(sta); + tag_index_ = path->tagIndex(sta); + } +} + +const char * +PathVertexPtr::name(const StaState *sta) const +{ + const Network *network = sta->network(); + const Search *search = sta->search(); + Vertex *vertex = this->vertex(sta); + if (vertex) { + const char *vertex_name = vertex->name(network); + const Tag *tag = this->tag(search); + const RiseFall *rf = tag->transition(); + const char *rf_str = rf->asString(); + const PathAnalysisPt *path_ap = tag->pathAnalysisPt(sta); + int ap_index = path_ap->index(); + const char *min_max = path_ap->pathMinMax()->asString(); + TagIndex tag_index = tag->index(); + return stringPrintTmp("%s %s %s/%d %d", + vertex_name, rf_str, min_max, + ap_index, tag_index); + } + else + return "NULL"; +} + +bool +PathVertexPtr::isNull() const +{ + return vertex_id_ == vertex_id_null; +} + +Vertex * +PathVertexPtr::vertex(const StaState *sta) const +{ + if (vertex_id_ == vertex_id_null) + return nullptr; + else { + const Graph *graph = sta->graph(); + return graph->vertex(vertex_id_); + } +} + +Tag * +PathVertexPtr::tag(const StaState *sta) const +{ + const Search *search = sta->search(); + return search->tag(tag_index_); +} + +Arrival +PathVertexPtr::arrival(const StaState *sta) const +{ + const Vertex *vertex = this->vertex(sta); + Arrival *arrivals = sta->graph()->arrivals(vertex); + if (arrivals) { + const Search *search = sta->search(); + TagGroup *tag_group = search->tagGroup(vertex); + Tag *tag = this->tag(sta); + int arrival_index; + bool arrival_exists; + tag_group->arrivalIndex(tag, arrival_index, arrival_exists); + if (arrival_exists) + return arrivals[arrival_index]; + else { + sta->report()->error(1403, "missing arrival."); + return 0.0; + } + } + else { + sta->report()->error(1404, "missing arrivals."); + return 0.0; + } +} + +//////////////////////////////////////////////////////////////// + +bool +PathVertexPtr::equal(const PathVertexPtr *path1, + const PathVertexPtr *path2) +{ + return path1->vertex_id_ == path2->vertex_id_ + && path1->tag_index_ == path2->tag_index_; +} + +bool +PathVertexPtr::equal(const PathVertexPtr &path1, + const PathVertexPtr &path2) +{ + return path1.vertex_id_ == path2.vertex_id_ + && path1.tag_index_ == path2.tag_index_; +} + +int +PathVertexPtr::cmp(const PathVertexPtr &path1, + const PathVertexPtr &path2) +{ + VertexId vertex_id1 = path1.vertex_id_; + VertexId vertex_id2 = path2.vertex_id_; + if (vertex_id1 == vertex_id2) { + TagIndex tag_index1 = path1.tagIndex(); + TagIndex tag_index2 = path2.tagIndex(); + if (tag_index1 == tag_index2) + return 0; + else if (tag_index1 < tag_index2) + return -1; + else + return 1; + } + else if (vertex_id1 < vertex_id2) + return -1; + else + return 1; +} + +} // namespace diff --git a/search/PathVertexRep.cc b/search/PathVertexRep.cc deleted file mode 100644 index ebb3cd53..00000000 --- a/search/PathVertexRep.cc +++ /dev/null @@ -1,246 +0,0 @@ -// OpenSTA, Static Timing Analyzer -// Copyright (c) 2025, Parallax Software, Inc. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -// The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. -// -// Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// -// This notice may not be removed or altered from any source distribution. - -#include "PathVertexRep.hh" - -#include "Graph.hh" -#include "SearchClass.hh" -#include "Tag.hh" -#include "TagGroup.hh" -#include "Search.hh" -#include "PathVertex.hh" - -namespace sta { - -PathVertexRep::PathVertexRep() -{ - init(); -} - -PathVertexRep::PathVertexRep(const PathVertexRep *path) -{ - init(path); -} - -PathVertexRep::PathVertexRep(const PathVertexRep &path) -{ - init(path); -} - -PathVertexRep::PathVertexRep(const PathVertex *path, - const StaState *sta) -{ - init(path, sta); -} - -PathVertexRep::PathVertexRep(const PathVertex &path, - const StaState *sta) -{ - init(path, sta); -} - -PathVertexRep::PathVertexRep(VertexId vertex_id, - TagIndex tag_index, - bool is_enum) : - vertex_id_(vertex_id), - tag_index_(tag_index), - is_enum_(is_enum) -{ -} - -void -PathVertexRep::init() -{ - vertex_id_ = 0; - tag_index_ = tag_index_null; - is_enum_ = false; -} - -void -PathVertexRep::init(const PathVertexRep *path) -{ - if (path) { - vertex_id_ = path->vertex_id_; - tag_index_ = path->tag_index_; - is_enum_ = false; - } - else - init(); -} - -void -PathVertexRep::init(const PathVertexRep &path) -{ - vertex_id_ = path.vertex_id_; - tag_index_ = path.tag_index_; - is_enum_ = false; -} - -void -PathVertexRep::init(const PathVertex *path, - const StaState *sta) -{ - if (path == nullptr || path->isNull()) - init(); - else { - vertex_id_ = sta->graph()->id(path->vertex(sta)); - tag_index_ = path->tag(sta)->index(); - is_enum_ = false; - } -} - -void -PathVertexRep::init(const PathVertex &path, - const StaState *sta) -{ - if (path.isNull()) - init(); - else { - vertex_id_ = sta->graph()->id(path.vertex(sta)); - tag_index_ = path.tag(sta)->index(); - is_enum_ = false; - } -} - -Vertex * -PathVertexRep::vertex(const StaState *sta) const -{ - const Graph *graph = sta->graph(); - return graph->vertex(vertex_id_); -} - -Tag * -PathVertexRep::tag(const StaState *sta) const -{ - const Search *search = sta->search(); - return search->tag(tag_index_); -} - -Arrival -PathVertexRep::arrival(const StaState *sta) const -{ - Graph *graph = sta->graph(); - const Search *search = sta->search(); - Tag *tag = search->tag(tag_index_); - Vertex *vertex = graph->vertex(vertex_id_); - TagGroup *tag_group = search->tagGroup(vertex); - if (tag_group) { - int arrival_index; - bool arrival_exists; - tag_group->arrivalIndex(tag, arrival_index, arrival_exists); - if (!arrival_exists) - sta->report()->critical(1420, "tag group missing tag"); - Arrival *arrivals = graph->arrivals(vertex); - if (arrivals) - return arrivals[arrival_index]; - else - sta->report()->critical(1421, "missing arrivals"); - } - else - sta->report()->error(1422, "missing arrivals."); - return 0.0; -} - -void -PathVertexRep::prevPath(const StaState *sta, - // Return values. - PathRef &prev_path, - TimingArc *&prev_arc) const -{ - PathVertex path_vertex(this, sta); - path_vertex.prevPath(sta, prev_path, prev_arc); -} - -//////////////////////////////////////////////////////////////// - -bool -PathVertexRep::equal(const PathVertexRep *path1, - const PathVertexRep *path2) -{ - return path1->vertex_id_ == path2->vertex_id_ - && path1->tag_index_ == path2->tag_index_; -} - -bool -PathVertexRep::equal(const PathVertexRep &path1, - const PathVertexRep &path2) -{ - return path1.vertex_id_ == path2.vertex_id_ - && path1.tag_index_ == path2.tag_index_; -} - -int -PathVertexRep::cmp(const PathVertexRep *path1, - const PathVertexRep *path2) -{ - if (path1 && path2) { - VertexId vertex_id1 = path1->vertexId(); - VertexId vertex_id2 = path2->vertexId(); - if (vertex_id1 == vertex_id2) { - TagIndex tag_index1 = path1->tagIndex(); - TagIndex tag_index2 = path2->tagIndex(); - if (tag_index1 == tag_index2) - return 0; - else if (tag_index1 < tag_index2) - return -1; - else - return 1; - } - else if (vertex_id1 < vertex_id2) - return -1; - else - return 1; - } - else if (path1 == nullptr - && path2 == nullptr) - return 0; - else if (path1 == nullptr) - return -1; - else - return 1; -} - -int -PathVertexRep::cmp(const PathVertexRep &path1, - const PathVertexRep &path2) -{ - VertexId vertex_id1 = path1.vertexId(); - VertexId vertex_id2 = path2.vertexId(); - if (vertex_id1 == vertex_id2) { - TagIndex tag_index1 = path1.tagIndex(); - TagIndex tag_index2 = path2.tagIndex(); - if (tag_index1 == tag_index2) - return 0; - else if (tag_index1 < tag_index2) - return -1; - else - return 1; - } - else if (vertex_id1 < vertex_id2) - return -1; - else - return 1; -} - -} // namespace diff --git a/search/ReportPath.cc b/search/ReportPath.cc index 401301c5..bd23c47d 100644 --- a/search/ReportPath.cc +++ b/search/ReportPath.cc @@ -2394,9 +2394,9 @@ ReportPath::reportGenClkSrcPath1(const Clock *clk, bool clk_used_as_data) const { PathAnalysisPt *insert_ap = path_ap->insertionAnalysisPt(early_late); - PathVertex src_path; const MinMax *min_max = path_ap->pathMinMax(); - search_->genclks()->srcPath(clk, clk_pin, clk_rf, insert_ap, src_path); + PathVertex src_path = + search_->genclks()->srcPath(clk, clk_pin, clk_rf, insert_ap); if (!src_path.isNull()) { ClkInfo *src_clk_info = src_path.clkInfo(search_); const ClockEdge *src_clk_edge = src_clk_info->clkEdge(); diff --git a/search/Search.cc b/search/Search.cc index 2d633a14..97acec66 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -55,7 +55,7 @@ #include "Corner.hh" #include "Sim.hh" #include "PathVertex.hh" -#include "PathVertexRep.hh" +#include "PathPrev.hh" #include "PathRef.hh" #include "ClkInfo.hh" #include "Tag.hh" @@ -255,6 +255,7 @@ Search::init(StaState *sta) path_groups_ = nullptr; endpoints_ = nullptr; invalid_endpoints_ = nullptr; + always_save_prev_paths_ = true; filter_ = nullptr; filter_from_ = nullptr; filter_to_ = nullptr; @@ -786,13 +787,6 @@ Search::arrivalInvalid(Vertex *vertex) } } -void -Search::arrivalInvalidDelete(Vertex *vertex) -{ - arrivalInvalid(vertex); - deletePaths(vertex); -} - void Search::levelChangedBefore(Vertex *vertex) { @@ -1072,7 +1066,8 @@ Search::findArrivalsSeed() //////////////////////////////////////////////////////////////// ArrivalVisitor::ArrivalVisitor(const StaState *sta) : - PathVisitor(nullptr, sta) + PathVisitor(nullptr, sta), + always_save_prev_paths_(true) { init0(); init(true); @@ -1109,6 +1104,8 @@ ArrivalVisitor::init(bool always_to_endpoints, always_to_endpoints_ = always_to_endpoints; pred_ = pred; crpr_active_ = sdc_->crprActive(); + if (search_) + always_save_prev_paths_ = search_->alwaysSavePrevPaths(); } @@ -1241,6 +1238,7 @@ Search::arrivalsChanged(Vertex *vertex, TagGroupBldr *tag_bldr) { Arrival *arrivals1 = graph_->arrivals(vertex); + PathPrev *prev_paths1 = graph_->prevPaths(vertex); if (arrivals1) { TagGroup *tag_group = tagGroup(vertex); if (tag_group == nullptr @@ -1257,7 +1255,10 @@ Search::arrivalsChanged(Vertex *vertex, int arrival_index2; tag_bldr->tagMatchArrival(tag1, tag2, arrival2, arrival_index2); if (tag2 != tag1 - || !delayEqual(arrival1, arrival2)) + || !delayEqual(arrival1, arrival2) + || (prev_paths1 + && !PathPrev::equal(prev_paths1[arrival_index1], + tag_bldr->prevPath(arrival_index2)))) return true; } return false; @@ -1273,10 +1274,10 @@ ArrivalVisitor::visitFromToPath(const Pin *, Tag *from_tag, PathVertex *from_path, const Arrival &from_arrival, - Edge *, - TimingArc *, + Edge *edge, + TimingArc *arc, ArcDelay arc_delay, - Vertex *, + Vertex * /* to_vertex */, const RiseFall *to_rf, Tag *to_tag, Arrival &to_arrival, @@ -1307,9 +1308,13 @@ ArrivalVisitor::visitFromToPath(const Pin *, delayAsString(to_arrival, this), min_max == MinMax::max() ? ">" : "<", tag_match ? delayAsString(arrival, this) : "MIA"); - PathVertexRep prev_path; - if (to_tag->isClock() || to_tag->isGenClkSrcPath()) - prev_path.init(from_path, this); + PathPrev prev_path; + bool always_save_prev_paths = true; + bool save_prev = always_save_prev_paths + || to_tag->isClock() + || to_tag->isGenClkSrcPath(); + if (save_prev) + prev_path.init(from_path, edge, arc, this); tag_bldr_->setMatchArrival(to_tag, tag_match, to_arrival, arrival_index, &prev_path); @@ -1333,13 +1338,13 @@ ArrivalVisitor::visitFromToPath(const Pin *, void ArrivalVisitor::pruneCrprArrivals() { - ArrivalMap::Iterator arrival_iter(tag_bldr_->arrivalMap()); CheckCrpr *crpr = search_->checkCrpr(); - while (arrival_iter.hasNext()) { - Tag *tag; - int arrival_index; - arrival_iter.next(tag, arrival_index); + ArrivalMap *arrival_map = tag_bldr_->arrivalMap(); + for (auto arrival_itr = arrival_map->cbegin(); arrival_itr != arrival_map->cend(); ) { + Tag *tag = arrival_itr->first; + int arrival_index = arrival_itr->second; ClkInfo *clk_info = tag->clkInfo(); + bool deleted_tag = false; if (!tag->isClock() && clk_info->hasCrprClkPin()) { PathAnalysisPt *path_ap = tag->pathAnalysisPt(this); @@ -1364,10 +1369,13 @@ ArrivalVisitor::pruneCrprArrivals() if (delayGreater(max_arrival_max_crpr, arrival, min_max, this)) { debugPrint(debug_, "search", 3, " pruned %s", tag->asString(this)); - tag_bldr_->deleteArrival(tag); + arrival_itr = arrival_map->erase(arrival_itr); + deleted_tag = true; } } } + if (!deleted_tag) + arrival_itr++; } } @@ -2710,7 +2718,10 @@ Search::setVertexArrivals(Vertex *vertex, else { TagGroup *prev_tag_group = tagGroup(vertex); Arrival *prev_arrivals = graph_->arrivals(vertex); - PathVertexRep *prev_paths = graph_->prevPaths(vertex); + PathPrev *prev_paths = graph_->prevPaths(vertex); + bool save_prev = always_save_prev_paths_ + || tag_bldr->hasClkTag() + || tag_bldr->hasGenClkSrcTag(); TagGroup *tag_group = findTagGroup(tag_bldr); int arrival_count = tag_group->arrivalCount(); @@ -2718,7 +2729,7 @@ Search::setVertexArrivals(Vertex *vertex, // Reuse arrival array if it is the same size. if (prev_tag_group && arrival_count == prev_tag_group->arrivalCount()) { - if (tag_bldr->hasClkTag() || tag_bldr->hasGenClkSrcTag()) { + if (save_prev) { if (prev_paths == nullptr) prev_paths = graph_->makePrevPaths(vertex, arrival_count); } @@ -2751,7 +2762,7 @@ Search::setVertexArrivals(Vertex *vertex, } Arrival *arrivals = graph_->makeArrivals(vertex, arrival_count); prev_paths = nullptr; - if (tag_bldr->hasClkTag() || tag_bldr->hasGenClkSrcTag()) + if (save_prev) prev_paths = graph_->makePrevPaths(vertex, arrival_count); tag_bldr->copyArrivals(tag_group, arrivals, prev_paths); @@ -2771,6 +2782,7 @@ Search::reportArrivals(Vertex *vertex) const TagGroup *tag_group = tagGroup(vertex); Arrival *arrivals = graph_->arrivals(vertex); Required *requireds = graph_->requireds(vertex); + PathPrev *prev_paths = graph_->prevPaths(vertex); if (tag_group) { report_->reportLine("Group %u", tag_group->index()); ArrivalMap::Iterator arrival_iter(tag_group->arrivalMap()); @@ -2791,14 +2803,34 @@ Search::reportArrivals(Vertex *vertex) const if (!prev.isNull()) clk_prev = prev.name(this); } - report_->reportLine(" %d %s %s %s / %s %s %s", + string prev_str; + if (prev_paths) { + PathPrev &prev = prev_paths[arrival_index]; + if (!prev.isNull()) { + prev_str += prev.name(this); + prev_str += " "; + const Edge *prev_edge = prev.prevEdge(this); + TimingArc *arc = prev.prevArc(this); + prev_str += prev_edge->from(graph_)->name(network_); + prev_str += " "; + prev_str += arc->fromEdge()->asString(); + prev_str += " -> "; + prev_str += prev_edge->to(graph_)->name(network_); + prev_str += " "; + prev_str += arc->toEdge()->asString(); + } + else + prev_str = "NULL"; + } + report_->reportLine(" %d %s %s %s / %s %s %s prev %s", arrival_index, rf->asString(), path_ap->pathMinMax()->asString(), delayAsString(arrivals[arrival_index], this), req, tag->asString(true, false, this), - clk_prev); + clk_prev, + prev_str.c_str()); } } else @@ -2966,7 +2998,7 @@ Search::reportClkInfos() const clk_infos.push_back(clk_info); sort(clk_infos, ClkInfoLess(this)); for (ClkInfo *clk_info : clk_infos) - report_->reportLine("ClkInfo %s", clk_info->asString(this)); + report_->reportLine("%s", clk_info->asString(this)); report_->reportLine("%zu clk infos", clk_info_set_->size()); } @@ -2983,17 +3015,17 @@ Search::findClkInfo(const ClockEdge *clk_edge, const PathAnalysisPt *path_ap, PathVertex *crpr_clk_path) { - PathVertexRep crpr_clk_path_rep(crpr_clk_path, this); + PathVertexPtr crpr_clk_path_ptr(crpr_clk_path, this); ClkInfo probe(clk_edge, clk_src, is_propagated, gen_clk_src, gen_clk_src_path, pulse_clk_sense, insertion, latency, uncertainties, - path_ap->index(), crpr_clk_path_rep, this); + path_ap->index(), crpr_clk_path_ptr, this); LockGuard lock(clk_info_lock_); ClkInfo *clk_info = clk_info_set_->findKey(&probe); if (clk_info == nullptr) { clk_info = new ClkInfo(clk_edge, clk_src, is_propagated, gen_clk_src, gen_clk_src_path, pulse_clk_sense, insertion, latency, uncertainties, - path_ap->index(), crpr_clk_path_rep, this); + path_ap->index(), crpr_clk_path_ptr, this); clk_info_set_->insert(clk_info); } return clk_info; @@ -3497,7 +3529,6 @@ RequiredVisitor::visit(Vertex *vertex) debugPrint(debug_, "search", 2, "find required %s", vertex->name(network_)); required_cmp_->requiredsInit(vertex, this); - vertex->setRequiredsPruned(false); // Back propagate requireds from fanout. visitFanoutPaths(vertex); // Check for constraints at endpoints that set required times. @@ -3514,7 +3545,7 @@ RequiredVisitor::visit(Vertex *vertex) bool RequiredVisitor::visitFromToPath(const Pin *, - Vertex *from_vertex, + Vertex *, const RiseFall *from_rf, Tag *from_tag, PathVertex *from_path, @@ -3586,11 +3617,7 @@ RequiredVisitor::visitFromToPath(const Pin *, } } } - from_vertex->setRequiredsPruned(true); } - // Propagate requireds pruned flag backwards. - if (to_vertex->requiredsPruned()) - from_vertex->setRequiredsPruned(true); } return true; } diff --git a/search/Search.tcl b/search/Search.tcl index 1e960ad6..4a9aefb5 100644 --- a/search/Search.tcl +++ b/search/Search.tcl @@ -934,7 +934,7 @@ proc parse_report_path_options { cmd args_var default_format } elseif { [string match "src*" $field] } { set report_src_attr 1 } else { - sta_warn 166 "unknown field $field." + sta_warn 168 "unknown field $field." } } } diff --git a/search/Sta.cc b/search/Sta.cc index 35e2e644..48ad81b4 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -3210,11 +3210,10 @@ Sta::findRequired(Vertex *vertex) if (sdc_->crprEnabled() && search_->crprPathPruningEnabled() && !search_->crprApproxMissingRequireds() - // Clocks invariably have requireds that are pruned but isn't + // Clocks invariably have requireds that are pruned but it isn't // worth finding arrivals and requireds all over again for // the entire fanout of the clock. - && !search_->isClock(vertex) - && vertex->requiredsPruned()) { + && !search_->isClock(vertex)) { // Invalidate arrivals and requireds and disable // path pruning on fanout vertices with DFS. int fanout = 0; @@ -3451,7 +3450,7 @@ Network * Sta::ensureLibLinked() { if (network_ == nullptr || !network_->isLinked()) - report_->error(1570, "No network has been linked."); + report_->error(1571, "No network has been linked."); // OpenROAD db is inherently linked but may not have associated // liberty files so check for them here. if (network_->defaultLibertyLibrary() == nullptr) @@ -4610,8 +4609,7 @@ Sta::deletePinBefore(const Pin *pin) if (edge->role()->isWire()) { // Only notify to vertex (from will be deleted). Vertex *to = edge->to(graph_); - // to->prev_paths point to vertex, so delete them. - search_->arrivalInvalidDelete(to); + search_->arrivalInvalid(to); graph_delay_calc_->delayInvalid(to); levelize_->relevelizeFrom(to); } diff --git a/search/TagGroup.cc b/search/TagGroup.cc index b00ed4c6..14d6bb89 100644 --- a/search/TagGroup.cc +++ b/search/TagGroup.cc @@ -32,7 +32,7 @@ #include "Tag.hh" #include "Corner.hh" #include "Search.hh" -#include "PathVertexRep.hh" +#include "PathPrev.hh" namespace sta { @@ -200,7 +200,7 @@ TagGroupBldr::arrival(int arrival_index) const void TagGroupBldr::setArrival(Tag *tag, const Arrival &arrival, - PathVertexRep *prev_path) + PathPrev *prev_path) { Tag *tag_match; Arrival ignore; @@ -215,7 +215,7 @@ TagGroupBldr::setMatchArrival(Tag *tag, Tag *tag_match, const Arrival &arrival, int arrival_index, - PathVertexRep *prev_path) + PathPrev *prev_path) { if (tag_match) { // If the group_tag exists there has to be an arrival map entry for it. @@ -234,7 +234,7 @@ TagGroupBldr::setMatchArrival(Tag *tag, if (prev_path) prev_paths_.push_back(*prev_path); else - prev_paths_.push_back(PathVertexRep()); + prev_paths_.push_back(PathPrev()); if (tag->isClock()) has_clk_tag_ = true; @@ -248,12 +248,6 @@ TagGroupBldr::setMatchArrival(Tag *tag, } } -void -TagGroupBldr::deleteArrival(Tag *tag) -{ - arrival_map_.erase(tag); -} - TagGroup * TagGroupBldr::makeTagGroup(TagGroupIndex index, const StaState *sta) @@ -285,7 +279,7 @@ TagGroupBldr::makeArrivalMap(const StaState *sta) void TagGroupBldr::copyArrivals(TagGroup *tag_group, Arrival *arrivals, - PathVertexRep *prev_paths) + PathPrev *prev_paths) { ArrivalMap::Iterator arrival_iter1(arrival_map_); while (arrival_iter1.hasNext()) { @@ -297,7 +291,7 @@ TagGroupBldr::copyArrivals(TagGroup *tag_group, if (exists2) { arrivals[arrival_index2] = arrivals_[arrival_index1]; if (prev_paths) { - PathVertexRep *prev_path = &prev_paths_[arrival_index1]; + PathPrev *prev_path = &prev_paths_[arrival_index1]; prev_paths[arrival_index2].init(prev_path); } } @@ -306,6 +300,12 @@ TagGroupBldr::copyArrivals(TagGroup *tag_group, } } +PathPrev & +TagGroupBldr::prevPath(int arrival_index) +{ + return prev_paths_[arrival_index]; +} + //////////////////////////////////////////////////////////////// size_t diff --git a/search/TagGroup.hh b/search/TagGroup.hh index eca1d26a..64082d80 100644 --- a/search/TagGroup.hh +++ b/search/TagGroup.hh @@ -37,7 +37,7 @@ namespace sta { class TagGroupBldr; -typedef Vector PathVertexRepSeq; +typedef Vector PathPrevSeq; class TagGroup { @@ -110,7 +110,6 @@ public: bool hasGenClkSrcTag() const { return has_genclk_src_tag_; } bool hasFilterTag() const { return has_filter_tag_; } bool hasLoopTag() const { return has_loop_tag_; } - void deleteArrival(Tag *tag); void tagMatchArrival(Tag *tag, // Return values. Tag *&tag_match, @@ -119,16 +118,17 @@ public: Arrival arrival(int arrival_index) const; void setArrival(Tag *tag, const Arrival &arrival, - PathVertexRep *prev_path); + PathPrev *prev_path); void setMatchArrival(Tag *tag, Tag *tag_match, const Arrival &arrival, int arrival_index, - PathVertexRep *prev_path); + PathPrev *prev_path); ArrivalMap *arrivalMap() { return &arrival_map_; } + PathPrev &prevPath(int arrival_index); void copyArrivals(TagGroup *tag_group, Arrival *arrivals, - PathVertexRep *prev_paths); + PathPrev *prev_paths); protected: int tagMatchIndex(); @@ -138,7 +138,7 @@ protected: int default_arrival_count_; ArrivalMap arrival_map_; ArrivalSeq arrivals_; - PathVertexRepSeq prev_paths_; + PathPrevSeq prev_paths_; bool has_clk_tag_; bool has_genclk_src_tag_:1; bool has_filter_tag_; diff --git a/tcl/StaTclTypes.i b/tcl/StaTclTypes.i index b5f6b5e5..dd3f1c63 100644 --- a/tcl/StaTclTypes.i +++ b/tcl/StaTclTypes.i @@ -441,8 +441,7 @@ using namespace sta; const char *arg = Tcl_GetStringFromObj($input, &length); Transition *tr = Transition::find(arg); if (tr == nullptr) { - Tcl_SetResult(interp,const_cast("Error: transition not found."), - TCL_STATIC); + tclArgError(interp, 2150, "Unknown transition '%s'.", arg); return TCL_ERROR; } else @@ -462,8 +461,7 @@ using namespace sta; const char *arg = Tcl_GetStringFromObj($input, &length); RiseFall *rf = RiseFall::find(arg); if (rf == nullptr) { - Tcl_SetResult(interp,const_cast("Error: unknown rise/fall edge."), - TCL_STATIC); + tclArgError(interp, 2151, "Unknown rise/fall edge '%s'.", arg); return TCL_ERROR; } $1 = rf; @@ -482,8 +480,7 @@ using namespace sta; const char *arg = Tcl_GetStringFromObj($input, &length); RiseFallBoth *tr = RiseFallBoth::find(arg); if (tr == nullptr) { - Tcl_SetResult(interp,const_cast("Error: unknown transition name."), - TCL_STATIC); + tclArgError(interp, 2152, "Unknown transition name '%s'.", arg); return TCL_ERROR; } $1 = tr; @@ -502,8 +499,7 @@ using namespace sta; const char *arg = Tcl_GetStringFromObj($input, &length); PortDirection *dir = PortDirection::find(arg); if (dir == nullptr) { - Tcl_SetResult(interp,const_cast("Error: port direction not found."), - TCL_STATIC); + tclArgError(interp, 2153, "Unknown port direction '%s'.", arg); return TCL_ERROR; } else @@ -517,8 +513,7 @@ using namespace sta; if (role) $1 = TimingRole::find(arg); else { - Tcl_SetResult(interp,const_cast("Error: unknown timing role."), - TCL_STATIC); + tclArgError(interp, 2154, "Unknown timing role '%s'.", arg); return TCL_ERROR; } } @@ -541,8 +536,7 @@ using namespace sta; else if (stringEq(arg, "fall") || stringEq(arg, "falling")) $1 = LogicValue::fall; else { - Tcl_SetResult(interp,const_cast("Error: unknown logic value."), - TCL_STATIC); + tclArgError(interp, 2155, "Unknown logic value '%s'.", arg); return TCL_ERROR; } } @@ -557,9 +551,7 @@ using namespace sta; else if (stringEq(arg, "on_chip_variation")) $1 = AnalysisType::ocv; else { - Tcl_SetResult(interp,const_cast("Error: unknown analysis type."), - TCL_STATIC); - + tclArgError(interp, 2156, "Unknown analysis type '%s'.", arg); return TCL_ERROR; } } @@ -757,11 +749,11 @@ using namespace sta; char *arg = Tcl_GetString(argv[i]); double value; if (Tcl_GetDouble(interp, arg, &value) == TCL_OK) - floats->push_back(static_cast(value)); + floats->push_back(static_cast(value)); else { - delete floats; - tclArgError(interp, "%s is not a floating point number.", arg); - return TCL_ERROR; + delete floats; + tclArgError(interp, 2157, "%s is not a floating point number.", arg); + return TCL_ERROR; } } } @@ -802,11 +794,11 @@ using namespace sta; char *arg = Tcl_GetString(argv[i]); int value; if (Tcl_GetInt(interp, arg, &value) == TCL_OK) - ints->push_back(value); + ints->push_back(value); else { - delete ints; - tclArgError(interp, "%s is not an integer.", arg); - return TCL_ERROR; + delete ints; + tclArgError(interp, 2158, "%s is not an integer.", arg); + return TCL_ERROR; } } } @@ -860,7 +852,7 @@ using namespace sta; if (min_max) $1 = min_max; else { - tclArgError(interp, "%s not min or max.", arg); + tclArgError(interp, 2159, "%s not min or max.", arg); return TCL_ERROR; } } @@ -880,7 +872,7 @@ using namespace sta; if (min_max) $1 = min_max; else { - tclArgError(interp, "%s not min, max or min_max.", arg); + tclArgError(interp, 2160, "%s not min, max or min_max.", arg); return TCL_ERROR; } } @@ -895,7 +887,7 @@ using namespace sta; if (min_max) $1 = min_max; else { - tclArgError(interp, "%s not min, max or min_max.", arg); + tclArgError(interp, 2161, "%s not min, max or min_max.", arg); return TCL_ERROR; } } @@ -916,7 +908,7 @@ using namespace sta; || stringEqual(arg, "max")) $1 = MinMax::max(); else { - tclArgError(interp, "%s not setup, hold, min or max.", arg); + tclArgError(interp, 2162, "%s not setup, hold, min or max.", arg); return TCL_ERROR; } } @@ -935,7 +927,7 @@ using namespace sta; || stringEqual(arg, "min_max")) $1 = SetupHoldAll::all(); else { - tclArgError(interp, "%s not setup, hold, setup_hold, min, max or min_max.", arg); + tclArgError(interp, 2163, "%s not setup, hold, setup_hold, min, max or min_max.", arg); return TCL_ERROR; } } @@ -948,7 +940,7 @@ using namespace sta; if (early_late) $1 = early_late; else { - tclArgError(interp, "%s not early/min, late/max or early_late/min_max.", arg); + tclArgError(interp, 2164, "%s not early/min, late/max or early_late/min_max.", arg); return TCL_ERROR; } } @@ -961,7 +953,7 @@ using namespace sta; if (early_late) $1 = early_late; else { - tclArgError(interp, "%s not early/min, late/max or early_late/min_max.", arg); + tclArgError(interp, 2165, "%s not early/min, late/max or early_late/min_max.", arg); return TCL_ERROR; } } @@ -976,7 +968,7 @@ using namespace sta; else if (stringEq(arg, "cell_check")) $1 = TimingDerateType::cell_check; else { - tclArgError(interp, "%s not net_delay, cell_delay or cell_check.", arg); + tclArgError(interp, 2166, "%s not net_delay, cell_delay or cell_check.", arg); return TCL_ERROR; } } @@ -989,7 +981,7 @@ using namespace sta; else if (stringEq(arg, "cell_check")) $1 = TimingDerateCellType::cell_check; else { - tclArgError(interp, "%s not cell_delay or cell_check.", arg); + tclArgError(interp, 2167, "%s not cell_delay or cell_check.", arg); return TCL_ERROR; } } @@ -1002,7 +994,7 @@ using namespace sta; else if (stringEq(arg, "data")) $1 = PathClkOrData::data; else { - tclArgError(interp, "%s not clk or data.", arg); + tclArgError(interp, 2168, "%s not clk or data.", arg); return TCL_ERROR; } } @@ -1015,7 +1007,7 @@ using namespace sta; else if (stringEq(arg, "slack")) $1 = sort_by_slack; else { - tclArgError(interp, "%s not group or slack.", arg); + tclArgError(interp, 2169, "%s not group or slack.", arg); return TCL_ERROR; } } @@ -1040,7 +1032,7 @@ using namespace sta; else if (stringEq(arg, "json")) $1 = ReportPathFormat::json; else { - tclArgError(interp, "unknown path type %s.", arg); + tclArgError(interp, 2170, "unknown path type %s.", arg); return TCL_ERROR; } } @@ -1406,7 +1398,7 @@ using namespace sta; else if (stringEq(arg, "xyce")) $1 = CircuitSim::xyce; else { - tclArgError(interp, "unknown circuit simulator %s.", arg); + tclArgError(interp, 2171, "unknown circuit simulator %s.", arg); return TCL_ERROR; } } diff --git a/tcl/TclTypeHelpers.cc b/tcl/TclTypeHelpers.cc index d8da8e44..228ab083 100644 --- a/tcl/TclTypeHelpers.cc +++ b/tcl/TclTypeHelpers.cc @@ -93,15 +93,16 @@ tclListSetStdString(Tcl_Obj *const source, void tclArgError(Tcl_Interp *interp, + int id, const char *msg, const char *arg) { // Swig does not add try/catch around arg parsing so this cannot use Report::error. - string error_msg = "Error: "; - error_msg += msg; - char *error = stringPrint(error_msg.c_str(), arg); - Tcl_SetResult(interp, error, TCL_VOLATILE); - stringDelete(error); + try { + Sta::sta()->report()->error(id, msg, arg); + } catch (const std::exception &e) { + Tcl_SetResult(interp, const_cast(e.what()), TCL_STATIC); + } } void diff --git a/test/path_group_names.ok b/test/path_group_names.ok new file mode 100644 index 00000000..6209a2fc --- /dev/null +++ b/test/path_group_names.ok @@ -0,0 +1,2 @@ +Initial path groups: +Final path groups: In2Out In2Reg Reg2Out Reg2Reg diff --git a/test/path_group_names.tcl b/test/path_group_names.tcl new file mode 100644 index 00000000..40fefb27 --- /dev/null +++ b/test/path_group_names.tcl @@ -0,0 +1,14 @@ +# path_group_names + +read_liberty asap7_small.lib.gz +read_verilog reg1_asap7.v +link_design top +create_clock -name clk -period 500 {clk1 clk2 clk3} +set_input_delay -clock clk 0 [all_inputs -no_clocks] +set_output_delay -clock clk 0 [all_outputs] +puts "Initial path groups: [sta::path_group_names]" +group_path -name In2Reg -from [all_inputs] -to [all_registers -data_pins] +group_path -name In2Out -from [all_inputs] -to [all_outputs] +group_path -name Reg2Out -from [all_registers -clock_pins] -to [all_outputs] +group_path -name Reg2Reg -from [all_registers -clock_pins] -to [all_registers -data_pins] +puts "Final path groups: [sta::path_group_names]" diff --git a/test/regression_vars.tcl b/test/regression_vars.tcl index 2d8ccbe1..5818e4c2 100644 --- a/test/regression_vars.tcl +++ b/test/regression_vars.tcl @@ -147,6 +147,7 @@ record_sta_tests { liberty_arcs_one2one_2 liberty_ccsn liberty_latch3 + path_group_names prima3 report_checks_src_attr report_json1 diff --git a/verilog/VerilogReader.cc b/verilog/VerilogReader.cc index dc80c1f5..3baea0e5 100644 --- a/verilog/VerilogReader.cc +++ b/verilog/VerilogReader.cc @@ -2263,7 +2263,7 @@ VerilogScanner::VerilogScanner(std::istream *stream, void VerilogScanner::error(const char *msg) { - report_->fileError(1866, filename_, lineno(), "%s", msg); + report_->fileError(1870, filename_, lineno(), "%s", msg); } } // namespace diff --git a/verilog/VerilogWriter.cc b/verilog/VerilogWriter.cc index 57bece2a..6fe3485a 100644 --- a/verilog/VerilogWriter.cc +++ b/verilog/VerilogWriter.cc @@ -508,19 +508,15 @@ VerilogWriter::findPortNCcount(const Instance *inst, const Port *port) { int nc_count = 0; - LibertyPort *lib_port = network_->libertyPort(port); - if (lib_port) { - Cell *cell = network_->cell(inst); - LibertyPortMemberIterator member_iter(lib_port); - while (member_iter.hasNext()) { - LibertyPort *lib_member = member_iter.next(); - Port *member = network_->findPort(cell, lib_member->name()); - Pin *pin = network_->findPin(inst, member); - if (pin == nullptr - || network_->net(pin) == nullptr) - nc_count++; - } + PortMemberIterator *member_iter = network_->memberIterator(port); + while (member_iter->hasNext()) { + Port *member = member_iter->next(); + Pin *pin = network_->findPin(inst, member); + if (pin == nullptr + || network_->net(pin) == nullptr) + nc_count++; } + delete member_iter; return nc_count; }