From c1ebbb90b11366f6df297e27efcaa2d210006ffd Mon Sep 17 00:00:00 2001 From: James Cherry Date: Sat, 2 May 2026 10:36:07 -0700 Subject: [PATCH 01/17] Vertex::has_sim_value_ Signed-off-by: James Cherry --- include/sta/Graph.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sta/Graph.hh b/include/sta/Graph.hh index 233d363c..a3553048 100644 --- a/include/sta/Graph.hh +++ b/include/sta/Graph.hh @@ -327,7 +327,7 @@ protected: bool has_downstream_clk_pin_:1; bool visited1_:1; bool visited2_:1; - bool has_sim_value_; + bool has_sim_value_:1; private: friend class Graph; From bfbbe0d90e4d29f0d5a1a6a1ff5276fc3f985212 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Tue, 5 May 2026 14:27:30 -0700 Subject: [PATCH 02/17] rm blank Signed-off-by: James Cherry --- search/GatedClk.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/search/GatedClk.cc b/search/GatedClk.cc index 11880d02..ad79dbdb 100644 --- a/search/GatedClk.cc +++ b/search/GatedClk.cc @@ -107,7 +107,6 @@ GatedClk::isGatedClkEnable(Vertex *enable_vertex, } } } - } } From 5b9d0f3aa8a2f005238f849b81ff7baca64f6916 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Tue, 5 May 2026 15:02:51 -0700 Subject: [PATCH 03/17] is_object cleanup Signed-off-by: James Cherry --- tcl/CmdUtil.tcl | 242 +++++++++++++++++++++++----------------------- tcl/StaTclTypes.i | 46 ++++++++- util/Util.i | 31 ------ 3 files changed, 165 insertions(+), 154 deletions(-) diff --git a/tcl/CmdUtil.tcl b/tcl/CmdUtil.tcl index 74fda26f..f2cc1223 100644 --- a/tcl/CmdUtil.tcl +++ b/tcl/CmdUtil.tcl @@ -191,136 +191,138 @@ proc set_unit_values { unit key suffix key_var } { ################################################################ -define_cmd_args "delete_from_list" {list objs} +define_cmd_args "delete_from_list" {list delete} -proc delete_from_list { list objects } { - delete_objects_from_list_cmd $list $objects +proc delete_from_list { list delete } { + delete_objects_from_list_cmd $list $delete } -proc delete_objects_from_list_cmd { list objects } { - set list0 [lindex $list 0] - set list_is_object [is_object $list0] - set list_type [object_type $list0] - foreach obj $objects { - # If the list is a collection of tcl objects (returned by get_*), - # convert the obj to be removed from a name to an object of the same - # type. - if {$list_is_object && ![is_object $obj]} { - if {$list_type == "Clock"} { - set obj [find_clock $obj] - } elseif {$list_type == "Port"} { - set top_instance [top_instance] - set top_cell [$top_instance cell] - set obj [$top_cell find_port $obj] - } elseif {$list_type == "Pin"} { - set obj [find_pin $obj] - } elseif {$list_type == "Instance"} { - set obj [find_instance $obj] - } elseif {$list_type == "Net"} { - set obj [find_net $obj] - } elseif {$list_type == "LibertyLibrary"} { - set obj [find_liberty $obj] - } elseif {$list_type == "LibertyCell"} { - set obj [find_liberty_cell $obj] - } elseif {$list_type == "LibertyPort"} { - set obj [get_lib_pins $obj] - } else { - sta_error 164 "unsupported object type $list_type." +proc delete_objects_from_list_cmd { list delete } { + if { $list != {} } { + set list0 [lindex $list 0] + set list_is_objects [is_object $list0] + foreach obj $delete { + # If the list is a collection of tcl objects (returned by get_*), + # convert the obj to be removed from a name to an object of the same + # type. + if {$list_is_objects && ![is_object $obj]} { + set list_type [object_type $list0] + if {$list_type == "Clock"} { + set obj [find_clock $obj] + } elseif {$list_type == "Port"} { + set top_instance [top_instance] + set top_cell [$top_instance cell] + set obj [$top_cell find_port $obj] + } elseif {$list_type == "Pin"} { + set obj [find_pin $obj] + } elseif {$list_type == "Instance"} { + set obj [find_instance $obj] + } elseif {$list_type == "Net"} { + set obj [find_net $obj] + } elseif {$list_type == "LibertyLibrary"} { + set obj [find_liberty $obj] + } elseif {$list_type == "LibertyCell"} { + set obj [find_liberty_cell $obj] + } elseif {$list_type == "LibertyPort"} { + set obj [get_lib_pins $obj] + } else { + sta_error 164 "unsupported object type $list_type." + } + } + set index [lsearch $list $obj] + if { $index != -1 } { + set list [lreplace $list $index $index] } - } - set index [lsearch $list $obj] - if { $index != -1 } { - set list [lreplace $list $index $index] } } return $list } - -################################################################ - -proc set_cmd_namespace { namespc } { - if { $namespc == "sdc" || $namespc == "sta" } { - set_cmd_namespace_cmd $namespc - } else { - sta_error 165 "unknown namespace $namespc." + + ################################################################ + + proc set_cmd_namespace { namespc } { + if { $namespc == "sdc" || $namespc == "sta" } { + set_cmd_namespace_cmd $namespc + } else { + sta_error 165 "unknown namespace $namespc." + } } -} - -################################################################ - -define_cmd_args "report_object_full_names" {objects} - -proc report_object_full_names { objects } { - foreach obj [sort_by_full_name $objects] { - report_line [get_full_name $obj] + + ################################################################ + + define_cmd_args "report_object_full_names" {objects} + + proc report_object_full_names { objects } { + foreach obj [sort_by_full_name $objects] { + report_line [get_full_name $obj] + } } -} - -define_cmd_args "report_object_names" {objects} - -proc report_object_names { objects } { - foreach obj [sort_by_name $objects] { - report_line [get_name $obj] + + define_cmd_args "report_object_names" {objects} + + proc report_object_names { objects } { + foreach obj [sort_by_name $objects] { + report_line [get_name $obj] + } } -} - -################################################################ - -define_cmd_args "get_name" {object} -define_cmd_args "get_full_name" {object} - -################################################################ - -proc get_name { object } { - return [get_object_property $object "name"] -} - -proc get_full_name { object } { - return [get_object_property $object "full_name"] -} - -proc sort_by_name { objects } { - return [lsort -command name_cmp $objects] -} - -proc name_cmp { obj1 obj2 } { - return [string compare [get_name $obj1] [get_name $obj2]] -} - -proc sort_by_full_name { objects } { - return [lsort -command full_name_cmp $objects] -} - -proc full_name_cmp { obj1 obj2 } { - return [string compare [get_full_name $obj1] [get_full_name $obj2]] -} - -proc get_object_type { obj } { - set object_type [object_type $obj] - if { $object_type == "Clock" } { - return "clock" - } elseif { $object_type == "LibertyCell" } { - return "lib_cell" - } elseif { $object_type == "LibertyPort" } { - return "lib_pin" - } elseif { $object_type == "Cell" } { - return "cell" - } elseif { $object_type == "Instance" } { - return "instance" - } elseif { $object_type == "Port" } { - return "port" - } elseif { $object_type == "Pin" } { - return "pin" - } elseif { $object_type == "Net" } { - return "net" - } elseif { $object_type == "Edge" } { - return "timing_arc" - } elseif { $object_type == "TimingArcSet" } { - return "timing_arc" - } else { - return "?" + + ################################################################ + + define_cmd_args "get_name" {object} + define_cmd_args "get_full_name" {object} + + ################################################################ + + proc get_name { object } { + return [get_object_property $object "name"] } -} - -# sta namespace end. + + proc get_full_name { object } { + return [get_object_property $object "full_name"] + } + + proc sort_by_name { objects } { + return [lsort -command name_cmp $objects] + } + + proc name_cmp { obj1 obj2 } { + return [string compare [get_name $obj1] [get_name $obj2]] + } + + proc sort_by_full_name { objects } { + return [lsort -command full_name_cmp $objects] + } + + proc full_name_cmp { obj1 obj2 } { + return [string compare [get_full_name $obj1] [get_full_name $obj2]] + } + + proc get_object_type { obj } { + set object_type [object_type $obj] + if { $object_type == "Clock" } { + return "clock" + } elseif { $object_type == "LibertyCell" } { + return "lib_cell" + } elseif { $object_type == "LibertyPort" } { + return "lib_pin" + } elseif { $object_type == "Cell" } { + return "cell" + } elseif { $object_type == "Instance" } { + return "instance" + } elseif { $object_type == "Port" } { + return "port" + } elseif { $object_type == "Pin" } { + return "pin" + } elseif { $object_type == "Net" } { + return "net" + } elseif { $object_type == "Edge" } { + return "timing_arc" + } elseif { $object_type == "TimingArcSet" } { + return "timing_arc" + } else { + return "?" + } + } + + # sta namespace end. } diff --git a/tcl/StaTclTypes.i b/tcl/StaTclTypes.i index 65a6b0f3..8136bd60 100644 --- a/tcl/StaTclTypes.i +++ b/tcl/StaTclTypes.i @@ -30,6 +30,9 @@ %{ +#include +#include + #include "Network.hh" #include "Liberty.hh" #include "FuncExpr.hh" @@ -52,7 +55,7 @@ namespace sta { typedef MinMaxAll MinMaxAllNull; #if TCL_MAJOR_VERSION < 9 - typedef int Tcl_Size; +typedef int Tcl_Size; #endif template @@ -256,14 +259,51 @@ setPtrTclList(SET_TYPE *set, Tcl_SetObjResult(interp, list); } -//////////////////////////////////////////////////////////////// - } // namespace sta using namespace sta; %} +//////////////////////////////////////////////////////////////// + +%inline %{ + +bool +is_object(const char *obj) +{ + // _hexaddress_p_type + const std::string s(obj); + if (s.empty() || s[0] != '_') + return false; + const size_t hex_digits = sizeof(void *) * 2; + if (s.size() < 1 + hex_digits + 3) + return false; + for (size_t i = 1; i < 1 + hex_digits; i++) { + if (!std::isxdigit(static_cast(s[i]))) + return false; + } + if (s.compare(1 + hex_digits, 3, "_p_") != 0) + return false; + for (size_t i = 1 + hex_digits + 3; i < s.size(); i++) { + char ch = s[i]; + if (!(std::isalnum(ch) || ch == '_')) + return false; + } + return true; +} + +// Assumes is_object is true. +const char * +object_type(const char *obj) +{ + if (is_object(obj)) + return &obj[1 + sizeof(void*) * 2 + 3]; + return ""; +} + +%} + //////////////////////////////////////////////////////////////// // // SWIG type definitions. diff --git a/util/Util.i b/util/Util.i index cb08647a..ce128f5e 100644 --- a/util/Util.i +++ b/util/Util.i @@ -224,37 +224,6 @@ set_debug(const char *what, Sta::sta()->setDebugLevel(what, level); } -//////////////////////////////////////////////////////////////// - -bool -is_object(const char *obj) -{ - // _hexaddress_p_type - const char *s = obj; - char ch = *s++; - if (ch != '_') - return false; - while (*s && isxdigit(*s)) - s++; - if ((s - obj - 1) == sizeof(void*) * 2 - && *s && *s++ == '_' - && *s && *s++ == 'p' - && *s && *s++ == '_') { - while (*s && *s != ' ') - s++; - return *s == '\0'; - } - else - return false; -} - -// Assumes is_object is true. -const char * -object_type(const char *obj) -{ - return &obj[1 + sizeof(void*) * 2 + 3]; -} - //////////////////////////////////////////////////////////////// // // Units From 20af8fdaf61353a9e079b393b1f4ffe2a017ffdd Mon Sep 17 00:00:00 2001 From: James Cherry Date: Tue, 5 May 2026 15:35:18 -0700 Subject: [PATCH 04/17] rm get_object_type Signed-off-by: James Cherry --- tcl/CmdUtil.tcl | 143 ++++++++++++++++++++---------------------------- 1 file changed, 58 insertions(+), 85 deletions(-) diff --git a/tcl/CmdUtil.tcl b/tcl/CmdUtil.tcl index f2cc1223..80d9b3e0 100644 --- a/tcl/CmdUtil.tcl +++ b/tcl/CmdUtil.tcl @@ -238,91 +238,64 @@ proc delete_objects_from_list_cmd { list delete } { return $list } - ################################################################ +################################################################ - proc set_cmd_namespace { namespc } { - if { $namespc == "sdc" || $namespc == "sta" } { - set_cmd_namespace_cmd $namespc - } else { - sta_error 165 "unknown namespace $namespc." - } +proc set_cmd_namespace { namespc } { + if { $namespc == "sdc" || $namespc == "sta" } { + set_cmd_namespace_cmd $namespc + } else { + sta_error 165 "unknown namespace $namespc." } - - ################################################################ - - define_cmd_args "report_object_full_names" {objects} - - proc report_object_full_names { objects } { - foreach obj [sort_by_full_name $objects] { - report_line [get_full_name $obj] - } - } - - define_cmd_args "report_object_names" {objects} - - proc report_object_names { objects } { - foreach obj [sort_by_name $objects] { - report_line [get_name $obj] - } - } - - ################################################################ - - define_cmd_args "get_name" {object} - define_cmd_args "get_full_name" {object} - - ################################################################ - - proc get_name { object } { - return [get_object_property $object "name"] - } - - proc get_full_name { object } { - return [get_object_property $object "full_name"] - } - - proc sort_by_name { objects } { - return [lsort -command name_cmp $objects] - } - - proc name_cmp { obj1 obj2 } { - return [string compare [get_name $obj1] [get_name $obj2]] - } - - proc sort_by_full_name { objects } { - return [lsort -command full_name_cmp $objects] - } - - proc full_name_cmp { obj1 obj2 } { - return [string compare [get_full_name $obj1] [get_full_name $obj2]] - } - - proc get_object_type { obj } { - set object_type [object_type $obj] - if { $object_type == "Clock" } { - return "clock" - } elseif { $object_type == "LibertyCell" } { - return "lib_cell" - } elseif { $object_type == "LibertyPort" } { - return "lib_pin" - } elseif { $object_type == "Cell" } { - return "cell" - } elseif { $object_type == "Instance" } { - return "instance" - } elseif { $object_type == "Port" } { - return "port" - } elseif { $object_type == "Pin" } { - return "pin" - } elseif { $object_type == "Net" } { - return "net" - } elseif { $object_type == "Edge" } { - return "timing_arc" - } elseif { $object_type == "TimingArcSet" } { - return "timing_arc" - } else { - return "?" - } - } - - # sta namespace end. +} + +################################################################ + +define_cmd_args "report_object_full_names" {objects} + +proc report_object_full_names { objects } { + foreach obj [sort_by_full_name $objects] { + report_line [get_full_name $obj] + } +} + +define_cmd_args "report_object_names" {objects} + +proc report_object_names { objects } { + foreach obj [sort_by_name $objects] { + report_line [get_name $obj] + } +} + +################################################################ + +define_cmd_args "get_name" {object} +define_cmd_args "get_full_name" {object} + +################################################################ + +proc get_name { object } { + return [get_object_property $object "name"] +} + +proc get_full_name { object } { + return [get_object_property $object "full_name"] +} + +proc sort_by_name { objects } { + return [lsort -command name_cmp $objects] +} + +proc name_cmp { obj1 obj2 } { + return [string compare [get_name $obj1] [get_name $obj2]] +} + +proc sort_by_full_name { objects } { + return [lsort -command full_name_cmp $objects] +} + +proc full_name_cmp { obj1 obj2 } { + return [string compare [get_full_name $obj1] [get_full_name $obj2]] +} + +# namespace sta } From c74dac5825f1314049e25bbfe8ab4287b5086be9 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Tue, 5 May 2026 15:37:23 -0700 Subject: [PATCH 05/17] clear_network clear sta Signed-off-by: James Cherry --- search/Search.i | 1 + 1 file changed, 1 insertion(+) diff --git a/search/Search.i b/search/Search.i index d3eb7455..659fff0c 100644 --- a/search/Search.i +++ b/search/Search.i @@ -113,6 +113,7 @@ void clear_network() { Sta *sta = Sta::sta(); + sta->clear(); sta->network()->clear(); } From e0ddce76ac557aeaecc51e840007ccef2b9ad953 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Tue, 5 May 2026 15:39:09 -0700 Subject: [PATCH 06/17] mv Variables.tcl to sdc Signed-off-by: James Cherry --- CMakeLists.txt | 2 +- {tcl => sdc}/Variables.tcl | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename {tcl => sdc}/Variables.tcl (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index cf46f844..bcf99591 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -257,7 +257,6 @@ set(STA_TCL_FILES tcl/Property.tcl tcl/Sta.tcl tcl/Splash.tcl - tcl/Variables.tcl dcalc/DelayCalc.tcl graph/Graph.tcl liberty/Liberty.tcl @@ -267,6 +266,7 @@ set(STA_TCL_FILES parasitics/Parasitics.tcl power/Power.tcl sdc/Sdc.tcl + sdc/Variables.tcl sdf/Sdf.tcl search/Search.tcl spice/WriteSpice.tcl diff --git a/tcl/Variables.tcl b/sdc/Variables.tcl similarity index 100% rename from tcl/Variables.tcl rename to sdc/Variables.tcl From afa2286edc1587213be9b610f6b1628302825fae Mon Sep 17 00:00:00 2001 From: James Cherry Date: Tue, 5 May 2026 16:35:40 -0700 Subject: [PATCH 07/17] copy() use copy constructors Signed-off-by: James Cherry --- dcalc/GraphDelayCalc.cc | 8 +++++++- include/sta/Search.hh | 8 ++------ power/Power.cc | 8 +++++++- search/Genclks.cc | 35 +++++++++++------------------------ search/PathEnum.cc | 10 ++++++++-- search/PathGroup.cc | 2 +- search/Search.cc | 27 ++++++++++++--------------- 7 files changed, 48 insertions(+), 50 deletions(-) diff --git a/dcalc/GraphDelayCalc.cc b/dcalc/GraphDelayCalc.cc index 741353bf..3bf51343 100644 --- a/dcalc/GraphDelayCalc.cc +++ b/dcalc/GraphDelayCalc.cc @@ -292,6 +292,7 @@ class FindVertexDelays : public VertexVisitor { public: FindVertexDelays(GraphDelayCalc *graph_delay_calc1); + FindVertexDelays(const FindVertexDelays &find_vertex_delays); ~FindVertexDelays() override; void visit(Vertex *vertex) override; VertexVisitor *copy() const override; @@ -308,6 +309,11 @@ FindVertexDelays::FindVertexDelays(GraphDelayCalc *graph_delay_calc) : { } +FindVertexDelays::FindVertexDelays(const FindVertexDelays &find_vertex_delays) : + FindVertexDelays(find_vertex_delays.graph_delay_calc_) +{ +} + FindVertexDelays::~FindVertexDelays() { delete arc_delay_calc_; @@ -318,7 +324,7 @@ FindVertexDelays::copy() const { // Copy StaState::arc_delay_calc_ because it needs separate state // for each thread. - return new FindVertexDelays(graph_delay_calc_); + return new FindVertexDelays(*this); } void diff --git a/include/sta/Search.hh b/include/sta/Search.hh index 58506e1f..2db5b6d5 100644 --- a/include/sta/Search.hh +++ b/include/sta/Search.hh @@ -770,6 +770,7 @@ class ArrivalVisitor : public PathVisitor { public: ArrivalVisitor(const StaState *sta); + ArrivalVisitor(const ArrivalVisitor &arrival_visitor); ~ArrivalVisitor() override; // Initialize the visitor. void init(bool always_to_endpoints, @@ -797,9 +798,6 @@ public: TagGroupBldr *tagBldr() const { return tag_bldr_; } protected: - ArrivalVisitor(bool always_to_endpoints, - SearchPred *pred, - const StaState *sta); void init0(); void enqueueRefPinInputDelays(const Pin *ref_pin, const Sdc *sdc); @@ -842,6 +840,7 @@ class RequiredVisitor : public PathVisitor { public: RequiredVisitor(const StaState *sta); + RequiredVisitor(const RequiredVisitor &required_visitor); ~RequiredVisitor() override; VertexVisitor *copy() const override; void visit(Vertex *vertex) override; @@ -862,9 +861,6 @@ public: const MinMax *min_max) override; protected: - RequiredVisitor(bool make_tag_cache, - const StaState *sta); - RequiredCmp *required_cmp_; VisitPathEnds *visit_path_ends_; }; diff --git a/power/Power.cc b/power/Power.cc index f5333f62..c5075522 100644 --- a/power/Power.cc +++ b/power/Power.cc @@ -575,6 +575,7 @@ public: PropActivityVisitor(Power *power, const Mode *mode, BfsFwdIterator *bfs); + PropActivityVisitor(const PropActivityVisitor &visitor); VertexVisitor *copy() const override; void visit(Vertex *vertex) override; InstanceSet &visitedRegs() { return visited_regs_; } @@ -606,10 +607,15 @@ PropActivityVisitor::PropActivityVisitor(Power *power, { } +PropActivityVisitor::PropActivityVisitor(const PropActivityVisitor &visitor) : + PropActivityVisitor(visitor.power_, visitor.mode_, visitor.bfs_) +{ +} + VertexVisitor * PropActivityVisitor::copy() const { - return new PropActivityVisitor(power_, mode_, bfs_); + return new PropActivityVisitor(*this); } void diff --git a/search/Genclks.cc b/search/Genclks.cc index 2123ea1b..6e8a39b7 100644 --- a/search/Genclks.cc +++ b/search/Genclks.cc @@ -693,17 +693,11 @@ public: BfsFwdIterator *insert_iter, GenclkInfo *genclk_info, const Mode *mode); + GenclkSrcArrivalVisitor(const GenclkSrcArrivalVisitor &visitor); VertexVisitor *copy() const override; void visit(Vertex *vertex) override; protected: - GenclkSrcArrivalVisitor(Clock *gclk, - BfsFwdIterator *insert_iter, - GenclkInfo *genclk_info, - bool always_to_endpoints, - SearchPred *pred, - const Mode *mode); - Clock *gclk_; BfsFwdIterator *insert_iter_; GenclkInfo *genclk_info_; @@ -728,29 +722,22 @@ GenclkSrcArrivalVisitor::GenclkSrcArrivalVisitor(Clock *gclk, { } -// Copy constructor. -GenclkSrcArrivalVisitor::GenclkSrcArrivalVisitor(Clock *gclk, - BfsFwdIterator *insert_iter, - GenclkInfo *genclk_info, - bool always_to_endpoints, - SearchPred *pred, - const Mode *mode) : - ArrivalVisitor(always_to_endpoints, pred, this), - gclk_(gclk), - insert_iter_(insert_iter), - genclk_info_(genclk_info), - srch_pred_(gclk, genclk_info, this), - mode_(mode), - sdc_(mode->sdc()), - genclks_(mode->genclks()) +GenclkSrcArrivalVisitor::GenclkSrcArrivalVisitor(const GenclkSrcArrivalVisitor &visitor) : + ArrivalVisitor(static_cast(visitor)), + gclk_(visitor.gclk_), + insert_iter_(visitor.insert_iter_), + genclk_info_(visitor.genclk_info_), + srch_pred_(visitor.gclk_, visitor.genclk_info_, this), + mode_(visitor.mode_), + sdc_(visitor.sdc_), + genclks_(visitor.genclks_) { } VertexVisitor * GenclkSrcArrivalVisitor::copy() const { - return new GenclkSrcArrivalVisitor(gclk_, insert_iter_, genclk_info_, - always_to_endpoints_, pred_, mode_); + return new GenclkSrcArrivalVisitor(*this); } void diff --git a/search/PathEnum.cc b/search/PathEnum.cc index c285b8f9..7c65f26e 100644 --- a/search/PathEnum.cc +++ b/search/PathEnum.cc @@ -246,6 +246,7 @@ public: bool unique_pins, bool unique_edges, PathEnum *path_enum); + PathEnumFaninVisitor(const PathEnumFaninVisitor &visitor); VertexVisitor *copy() const override; void visitFaninPathsThru(Path *before_div, Vertex *prev_vertex, @@ -327,11 +328,16 @@ PathEnumFaninVisitor::PathEnumFaninVisitor(PathEnd *path_end, { } +PathEnumFaninVisitor::PathEnumFaninVisitor(const PathEnumFaninVisitor &visitor) : + PathEnumFaninVisitor(visitor.path_end_, visitor.before_div_, visitor.unique_pins_, + visitor.unique_edges_, visitor.path_enum_) +{ +} + VertexVisitor * PathEnumFaninVisitor::copy() const { - return new PathEnumFaninVisitor(path_end_, before_div_, unique_pins_, - unique_edges_, path_enum_); + return new PathEnumFaninVisitor(*this); } void diff --git a/search/PathGroup.cc b/search/PathGroup.cc index 6750613c..725b52c7 100644 --- a/search/PathGroup.cc +++ b/search/PathGroup.cc @@ -995,7 +995,7 @@ MakeEndpointPathEnds::~MakeEndpointPathEnds() VertexVisitor * MakeEndpointPathEnds::copy() const { - return new MakeEndpointPathEnds(path_end_visitor_, scenes_, min_max_, sta_); + return new MakeEndpointPathEnds(*this); } void diff --git a/search/Search.cc b/search/Search.cc index 081daac8..0bc491f3 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -1090,14 +1090,11 @@ ArrivalVisitor::ArrivalVisitor(const StaState *sta) : init(true, false, nullptr); } -// Copy constructor. -ArrivalVisitor::ArrivalVisitor(bool always_to_endpoints, - SearchPred *pred, - const StaState *sta) : - PathVisitor(pred, true, sta) +ArrivalVisitor::ArrivalVisitor(const ArrivalVisitor &arrival_visitor) : + PathVisitor(arrival_visitor.pred_, true, &arrival_visitor) { init0(); - init(always_to_endpoints, false, pred); + init(arrival_visitor.always_to_endpoints_, false, arrival_visitor.pred_); } void @@ -1122,7 +1119,7 @@ ArrivalVisitor::init(bool always_to_endpoints, VertexVisitor * ArrivalVisitor::copy() const { - return new ArrivalVisitor(always_to_endpoints_, pred_, this); + return new ArrivalVisitor(*this); } void @@ -1966,7 +1963,10 @@ PathVisitor::PathVisitor(SearchPred *pred, { } -PathVisitor::~PathVisitor() { delete tag_cache_; } +PathVisitor::~PathVisitor() +{ + delete tag_cache_; +} void PathVisitor::visitFaninPaths(Vertex *to_vertex) @@ -3447,13 +3447,10 @@ RequiredVisitor::RequiredVisitor(const StaState *sta) : { } -RequiredVisitor::RequiredVisitor(bool make_tag_cache, - const StaState *sta) : - PathVisitor(sta->search()->evalPred(), - make_tag_cache, - sta), +RequiredVisitor::RequiredVisitor(const RequiredVisitor &required_visitor) : + PathVisitor(required_visitor.search()->evalPred(), true, &required_visitor), required_cmp_(new RequiredCmp), - visit_path_ends_(new VisitPathEnds(sta)) + visit_path_ends_(new VisitPathEnds(&required_visitor)) { } @@ -3466,7 +3463,7 @@ RequiredVisitor::~RequiredVisitor() VertexVisitor * RequiredVisitor::copy() const { - return new RequiredVisitor(true, this); + return new RequiredVisitor(*this); } void From 0968c3f9018af5c0a3f90aca9cfe3ed5d318f36e Mon Sep 17 00:00:00 2001 From: James Cherry Date: Tue, 5 May 2026 16:41:14 -0700 Subject: [PATCH 08/17] comments Signed-off-by: James Cherry --- include/sta/BoundedHeap.hh | 1 - include/sta/Property.hh | 2 -- 2 files changed, 3 deletions(-) diff --git a/include/sta/BoundedHeap.hh b/include/sta/BoundedHeap.hh index 6ae23ce0..eaebc9ef 100644 --- a/include/sta/BoundedHeap.hh +++ b/include/sta/BoundedHeap.hh @@ -63,7 +63,6 @@ public: { } - // Copy constructor BoundedHeap(const BoundedHeap& other) : heap_(other.heap_), max_size_(other.max_size_), diff --git a/include/sta/Property.hh b/include/sta/Property.hh index adeee3cc..1bb1e149 100644 --- a/include/sta/Property.hh +++ b/include/sta/Property.hh @@ -199,9 +199,7 @@ public: PropertyValue(ClockSet *value); PropertyValue(ConstPathSeq *value); PropertyValue(PwrActivity *value); - // Copy constructor. PropertyValue(const PropertyValue &value); - // Move constructor. PropertyValue(PropertyValue &&value) noexcept; ~PropertyValue(); Type type() const { return type_; } From 7fca3186111c3bcc3ca785ce53b9a5f3833b74c2 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Tue, 5 May 2026 16:58:59 -0700 Subject: [PATCH 09/17] copy() use copy constructors Signed-off-by: James Cherry --- dcalc/UnitDelayCalc.cc | 2 +- search/Search.cc | 2 +- search/Sta.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dcalc/UnitDelayCalc.cc b/dcalc/UnitDelayCalc.cc index f376ec7b..8f3d9cc8 100644 --- a/dcalc/UnitDelayCalc.cc +++ b/dcalc/UnitDelayCalc.cc @@ -42,7 +42,7 @@ UnitDelayCalc::UnitDelayCalc(StaState *sta) : ArcDelayCalc * UnitDelayCalc::copy() { - return new UnitDelayCalc(this); + return new UnitDelayCalc(*this); } Parasitic * diff --git a/search/Search.cc b/search/Search.cc index 0bc491f3..b4d8f7fe 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -3334,7 +3334,7 @@ FindEndRequiredVisitor::~FindEndRequiredVisitor() PathEndVisitor * FindEndRequiredVisitor::copy() const { - return new FindEndRequiredVisitor(sta_); + return new FindEndRequiredVisitor(*this); } void diff --git a/search/Sta.cc b/search/Sta.cc index 357256d0..286a73c8 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -3277,7 +3277,7 @@ EndpointPathEndVisitor::EndpointPathEndVisitor(std::string_view path_group_name, PathEndVisitor * EndpointPathEndVisitor::copy() const { - return new EndpointPathEndVisitor(path_group_name_, min_max_, sta_); + return new EndpointPathEndVisitor(*this); } void From 801d621d6b235130c46f40137d1dcecdc3a22aa5 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Tue, 5 May 2026 17:08:16 -0700 Subject: [PATCH 10/17] Dmp delay calc inline algs Signed-off-by: James Cherry --- dcalc/DmpCeff.cc | 317 ++++-------------------------------------- dcalc/DmpCeff.hh | 273 ++++++++++++++++++++++++++++++++++-- dcalc/DmpDelayCalc.cc | 4 +- 3 files changed, 292 insertions(+), 302 deletions(-) diff --git a/dcalc/DmpCeff.cc b/dcalc/DmpCeff.cc index 7ce3e903..5d0aef1d 100644 --- a/dcalc/DmpCeff.cc +++ b/dcalc/DmpCeff.cc @@ -68,6 +68,17 @@ static const char *dmp_func_index_strings[] = {"y20", "y50", "Ipi"}; static double exp2(double x); +static double +gateModelRd(const LibertyCell *cell, + const GateTableModel *gate_model, + const RiseFall *rf, + double in_slew, + double c2, + double c1, + const Pvt *pvt); + +//////////////////////////////////////////////////////////////// + class DmpError : public Exception { public: @@ -78,156 +89,13 @@ private: std::string what_; }; -static double -gateModelRd(const LibertyCell *cell, - const GateTableModel *gate_model, - const RiseFall *rf, - double in_slew, - double c2, - double c1, - const Pvt *pvt); -//////////////////////////////////////////////////////////////// - -// Base class for Dartu/Menezes/Pileggi algorithm. -// Derived classes handle different cases of zero values in the Pi model. -class DmpAlg : public StaState +DmpError::DmpError(std::string_view what) : + what_(what) { -public: - DmpAlg(int nr_order, - StaState *sta); - ~DmpAlg() override = default; - virtual std::string_view name() = 0; - // Set driver model and pi model parameters for delay calculation. - virtual void init(const LibertyLibrary *library, - const LibertyCell *drvr_cell, - const Pvt *pvt, - const GateTableModel *gate_model, - const RiseFall *rf, - double rd, - double in_slew, - double c2, - double rpi, - double c1); - virtual std::pair gateDelaySlew() = 0; - virtual std::pair loadDelaySlew(const Pin *load_pin, - double elmore); - double ceff() { return ceff_; } + //sta::print(stdout, "DmpError {}\n", what); +} - // Given x_ as a vector of input parameters, fill fvec_ with the - // equations evaluated at x_ and fjac_ with the jabobian evaluated at x_. - virtual void evalDmpEqns() = 0; - // Output response to vs(t) ramp driving pi model load (vo, dvo_dt). - std::pair Vo(double t); - // Load response to driver waveform (vl, dvl/dt). - std::pair Vl(double t); - -protected: - void luDecomp(); - void luSolve(); - void newtonRaphson(); - // Find driver parameters t0, delta_t, Ceff. - void findDriverParams(double ceff); - std::pair gateCapDelaySlew(double ceff); - std::tuple gateDelays(double ceff); - // Partial derivatives of y(t) jacobian (dydt0, dyddt, dydcl). - std::tuple dy(double t, - double t0, - double dt, - double cl); - double y0dt(double t, - double cl); - double y0dcl(double t, - double cl); - void showX(); - void showFvec(); - void showJacobian(); - std::pair findDriverDelaySlew(); - double findVoCrossing(double vth, - double t_lower, - double t_upper); - void showVo(); - double findVlCrossing(double vth, - double t_lower, - double t_upper); - void showVl(); - void fail(std::string_view reason); - - // Output response to vs(t) ramp driving capacitive load (y, t1). - std::pair y(double t, - double t0, - double dt, - double cl); - // Output response to unit ramp driving capacitive load. - double y0(double t, - double cl); - // Output response to unit ramp driving pi model load. - // Unit ramp output at pi load (vo, dvo_dt). - virtual std::pair V0(double t) = 0; - // Upper bound on time that vo crosses vh. - virtual double voCrossingUpperBound() = 0; - // Load responce to driver unit ramp. - // Unit ramp load response (vl, dvl_dt). - virtual std::pair Vl0(double t) = 0; - // Upper bound on time that vl crosses vh. - double vlCrossingUpperBound(); - - // Inputs to the delay calculator. - const LibertyCell *drvr_cell_; - const LibertyLibrary *drvr_library_; - const Pvt *pvt_; - const GateTableModel *gate_model_; - double in_slew_; - double c2_{0.0}; - double rpi_{0.0}; - double c1_{0.0}; - - double rd_; - // Logic threshold (percentage of supply voltage). - double vth_; - // Slew lower limit (percentage of supply voltage). - double vl_; - // Slew upper limit (percentage of supply voltage). - double vh_; - // Table slews are scaled by slew_derate to get - // measured slews from vl to vh. - double slew_derate_; - - // Driver parameters calculated by this algorithm. - double t0_; - double dt_; - double ceff_; - - // Driver parameter Newton-Raphson state. - int nr_order_; - - static constexpr int max_nr_order_ = 3; - - std::array x_; - std::array fvec_; - std::array, max_nr_order_> fjac_; - std::array scale_; - std::array p_; - std::array index_; - - // Driver slew used to check load delay. - double drvr_slew_; - double vo_delay_; - // True if the driver parameters are valid for finding the load delays. - bool driver_valid_; - // Load rspf elmore delay. - double elmore_; - double p3_; - - // Tolerance (as a scale of value) for driver parameters (Ceff, delta t, t0). - static constexpr double driver_param_tol_ = .01; - // Waveform threshold crossing time tolerance (1.0 = 100%). - static constexpr double vth_time_tol_ = .01; - // Max iterations for findRoot. - static constexpr int find_root_max_iter_ = 20; - static inline int newton_raphson_max_iter_ = 100; - // A small number used by luDecomp. - static constexpr double tiny_double_ = 1.0e-20; -}; +//////////////////////////////////////////////////////////////// DmpAlg::DmpAlg(int nr_order, StaState *sta) : @@ -593,33 +461,6 @@ DmpAlg::fail(std::string_view reason) //////////////////////////////////////////////////////////////// -// Capacitive load. -class DmpCap : public DmpAlg -{ -public: - DmpCap(StaState *sta); - std::string_view name() override { return "cap"; } - void init(const LibertyLibrary *library, - const LibertyCell *drvr_cell, - const Pvt *pvt, - const GateTableModel *gate_model, - const RiseFall *rf, - double rd, - double in_slew, - double c2, - double rpi, - double c1) override; - std::pair gateDelaySlew() override; - std::pair loadDelaySlew(const Pin *, - double elmore) override; - void evalDmpEqns() override; - -protected: - double voCrossingUpperBound() override; - std::pair V0(double t) override; - std::pair Vl0(double t) override; -}; - DmpCap::DmpCap(StaState *sta) : DmpAlg(1, sta) @@ -692,53 +533,6 @@ DmpCap::Vl0(double) //////////////////////////////////////////////////////////////// -// No non-zero pi model parameters, two poles, one zero -class DmpPi : public DmpAlg -{ -public: - DmpPi(StaState *sta); - std::string_view name() override { return "Pi"; } - void init(const LibertyLibrary *library, - const LibertyCell *drvr_cell, - const Pvt *pvt, - const GateTableModel *gate_model, - const RiseFall *rf, - double rd, - double in_slew, - double c2, - double rpi, - double c1) override; - std::pair gateDelaySlew() override; - void evalDmpEqns() override; - -protected: - double voCrossingUpperBound() override; - std::pair V0(double t) override; - std::pair Vl0(double t) override; - -private: - void findDriverParamsPi(); - double ipiIceff(double t0, - double dt, - double ceff_time, - double ceff); - - // Poles/zero. - double p1_{0.0}; - double p2_{0.0}; - double z1_{0.0}; - // Residues. - double k0_{0.0}; - double k1_{0.0}; - double k2_{0.0}; - double k3_{0.0}; - double k4_{0.0}; - // Ipi coefficients. - double A_{0.0}; - double B_{0.0}; - double D_{0.0}; -}; - DmpPi::DmpPi(StaState *sta) : DmpAlg(3, sta) @@ -940,18 +734,6 @@ DmpPi::voCrossingUpperBound() //////////////////////////////////////////////////////////////// -// Capacitive load, so Ceff is known. -// Solve for t0, delta t. -class DmpOnePole : public DmpAlg -{ -public: - DmpOnePole(StaState *sta); - void evalDmpEqns() override; - -protected: - double voCrossingUpperBound() override; -}; - DmpOnePole::DmpOnePole(StaState *sta) : DmpAlg(2, sta) @@ -1000,40 +782,6 @@ DmpOnePole::voCrossingUpperBound() //////////////////////////////////////////////////////////////// -// C2 = 0, one pole, one zero. -class DmpZeroC2 : public DmpOnePole -{ -public: - DmpZeroC2(StaState *sta); - std::string_view name() override { return "c2=0"; } - void init(const LibertyLibrary *drvr_library, - const LibertyCell *drvr_cell, - const Pvt *pvt, - const GateTableModel *gate_model, - const RiseFall *rf, - double rd, - double in_slew, - double c2, - double rpi, - double c1) override; - std::pair gateDelaySlew() override; - -protected: - std::pair V0(double t) override; - std::pair Vl0(double t) override; - double voCrossingUpperBound() override; - -private: - // Pole/zero. - double p1_{0.0}; - double z1_{0.0}; - // Residues. - double k0_{0.0}; - double k1_{0.0}; - double k2_{0.0}; - double k3_{0.0}; -}; - DmpZeroC2::DmpZeroC2(StaState *sta) : DmpOnePole(sta) { @@ -1260,19 +1008,12 @@ bool DmpCeffDelayCalc::unsuppored_model_warned_ = false; DmpCeffDelayCalc::DmpCeffDelayCalc(StaState *sta) : LumpedCapDelayCalc(sta), - dmp_cap_(new DmpCap(sta)), - dmp_pi_(new DmpPi(sta)), - dmp_zero_c2_(new DmpZeroC2(sta)) + dmp_cap_(sta), + dmp_pi_(sta), + dmp_zero_c2_(sta) { } -DmpCeffDelayCalc::~DmpCeffDelayCalc() -{ - delete dmp_cap_; - delete dmp_pi_; - delete dmp_zero_c2_; -} - ArcDcalcResult DmpCeffDelayCalc::gateDelay(const Pin *drvr_pin, const TimingArc *arc, @@ -1362,15 +1103,15 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library, || rpi < rd * 1e-3 // c1/Rpi can be ignored. || (c1 == 0.0 || c1 < c2 * 1e-3 || rpi == 0.0)) - dmp_alg_ = dmp_cap_; + dmp_alg_ = &dmp_cap_; else if (c2 < c1 * 1e-3) - dmp_alg_ = dmp_zero_c2_; + dmp_alg_ = &dmp_zero_c2_; else // The full monty. - dmp_alg_ = dmp_pi_; + dmp_alg_ = &dmp_pi_; } else - dmp_alg_ = dmp_cap_; + dmp_alg_ = &dmp_cap_; dmp_alg_->init(drvr_library, drvr_cell, pvt, gate_model, rf, rd, in_slew, c2, rpi, c1); debugPrint(debug_, "dmp_ceff", 3, @@ -1473,15 +1214,9 @@ void DmpCeffDelayCalc::copyState(const StaState *sta) { StaState::copyState(sta); - dmp_cap_->copyState(sta); - dmp_pi_->copyState(sta); - dmp_zero_c2_->copyState(sta); -} - -DmpError::DmpError(std::string_view what) : - what_(what) -{ - //sta::print(stdout, "DmpError {}\n", what); + dmp_cap_.copyState(sta); + dmp_pi_.copyState(sta); + dmp_zero_c2_.copyState(sta); } // This saves about 2.5% in overall run time on designs with SPEF. diff --git a/dcalc/DmpCeff.hh b/dcalc/DmpCeff.hh index 1ca6209e..a2e8a144 100644 --- a/dcalc/DmpCeff.hh +++ b/dcalc/DmpCeff.hh @@ -32,19 +32,275 @@ namespace sta { -class DmpAlg; -class DmpCap; -class DmpPi; -class DmpZeroC2; class GateTableModel; +// Base class for Dartu/Menezes/Pileggi algorithm. +// Derived classes handle different cases of zero values in the Pi model. +class DmpAlg : public StaState +{ +public: + DmpAlg(int nr_order, + StaState *sta); + ~DmpAlg() override = default; + virtual std::string_view name() = 0; + // Set driver model and pi model parameters for delay calculation. + virtual void init(const LibertyLibrary *library, + const LibertyCell *drvr_cell, + const Pvt *pvt, + const GateTableModel *gate_model, + const RiseFall *rf, + double rd, + double in_slew, + double c2, + double rpi, + double c1); + virtual std::pair gateDelaySlew() = 0; + virtual std::pair loadDelaySlew(const Pin *load_pin, + double elmore); + double ceff() { return ceff_; } + + // Given x_ as a vector of input parameters, fill fvec_ with the + // equations evaluated at x_ and fjac_ with the jabobian evaluated at x_. + virtual void evalDmpEqns() = 0; + // Output response to vs(t) ramp driving pi model load (vo, dvo_dt). + std::pair Vo(double t); + // Load response to driver waveform (vl, dvl/dt). + std::pair Vl(double t); + +protected: + void luDecomp(); + void luSolve(); + void newtonRaphson(); + // Find driver parameters t0, delta_t, Ceff. + void findDriverParams(double ceff); + std::pair gateCapDelaySlew(double ceff); + std::tuple gateDelays(double ceff); + // Partial derivatives of y(t) jacobian (dydt0, dyddt, dydcl). + std::tuple dy(double t, + double t0, + double dt, + double cl); + double y0dt(double t, + double cl); + double y0dcl(double t, + double cl); + void showX(); + void showFvec(); + void showJacobian(); + std::pair findDriverDelaySlew(); + double findVoCrossing(double vth, + double t_lower, + double t_upper); + void showVo(); + double findVlCrossing(double vth, + double t_lower, + double t_upper); + void showVl(); + void fail(std::string_view reason); + + // Output response to vs(t) ramp driving capacitive load (y, t1). + std::pair y(double t, + double t0, + double dt, + double cl); + // Output response to unit ramp driving capacitive load. + double y0(double t, + double cl); + // Output response to unit ramp driving pi model load. + // Unit ramp output at pi load (vo, dvo_dt). + virtual std::pair V0(double t) = 0; + // Upper bound on time that vo crosses vh. + virtual double voCrossingUpperBound() = 0; + // Load responce to driver unit ramp. + // Unit ramp load response (vl, dvl_dt). + virtual std::pair Vl0(double t) = 0; + // Upper bound on time that vl crosses vh. + double vlCrossingUpperBound(); + + // Inputs to the delay calculator. + const LibertyCell *drvr_cell_; + const LibertyLibrary *drvr_library_; + const Pvt *pvt_; + const GateTableModel *gate_model_; + double in_slew_; + double c2_{0.0}; + double rpi_{0.0}; + double c1_{0.0}; + + double rd_; + // Logic threshold (percentage of supply voltage). + double vth_; + // Slew lower limit (percentage of supply voltage). + double vl_; + // Slew upper limit (percentage of supply voltage). + double vh_; + // Table slews are scaled by slew_derate to get + // measured slews from vl to vh. + double slew_derate_; + + // Driver parameters calculated by this algorithm. + double t0_; + double dt_; + double ceff_; + + // Driver parameter Newton-Raphson state. + int nr_order_; + + static constexpr int max_nr_order_ = 3; + + std::array x_; + std::array fvec_; + std::array, max_nr_order_> fjac_; + std::array scale_; + std::array p_; + std::array index_; + + // Driver slew used to check load delay. + double drvr_slew_; + double vo_delay_; + // True if the driver parameters are valid for finding the load delays. + bool driver_valid_; + // Load rspf elmore delay. + double elmore_; + double p3_; + + // Tolerance (as a scale of value) for driver parameters (Ceff, delta t, t0). + static constexpr double driver_param_tol_ = .01; + // Waveform threshold crossing time tolerance (1.0 = 100%). + static constexpr double vth_time_tol_ = .01; + // Max iterations for findRoot. + static constexpr int find_root_max_iter_ = 20; + static inline int newton_raphson_max_iter_ = 100; + // A small number used by luDecomp. + static constexpr double tiny_double_ = 1.0e-20; +}; + +// Capacitive load. +class DmpCap : public DmpAlg +{ +public: + DmpCap(StaState *sta); + std::string_view name() override { return "cap"; } + void init(const LibertyLibrary *library, + const LibertyCell *drvr_cell, + const Pvt *pvt, + const GateTableModel *gate_model, + const RiseFall *rf, + double rd, + double in_slew, + double c2, + double rpi, + double c1) override; + std::pair gateDelaySlew() override; + std::pair loadDelaySlew(const Pin *, + double elmore) override; + void evalDmpEqns() override; + +protected: + double voCrossingUpperBound() override; + std::pair V0(double t) override; + std::pair Vl0(double t) override; +}; + +// No non-zero pi model parameters, two poles, one zero +class DmpPi : public DmpAlg +{ +public: + DmpPi(StaState *sta); + std::string_view name() override { return "Pi"; } + void init(const LibertyLibrary *library, + const LibertyCell *drvr_cell, + const Pvt *pvt, + const GateTableModel *gate_model, + const RiseFall *rf, + double rd, + double in_slew, + double c2, + double rpi, + double c1) override; + std::pair gateDelaySlew() override; + void evalDmpEqns() override; + +protected: + double voCrossingUpperBound() override; + std::pair V0(double t) override; + std::pair Vl0(double t) override; + +private: + void findDriverParamsPi(); + double ipiIceff(double t0, + double dt, + double ceff_time, + double ceff); + + // Poles/zero. + double p1_{0.0}; + double p2_{0.0}; + double z1_{0.0}; + // Residues. + double k0_{0.0}; + double k1_{0.0}; + double k2_{0.0}; + double k3_{0.0}; + double k4_{0.0}; + // Ipi coefficients. + double A_{0.0}; + double B_{0.0}; + double D_{0.0}; +}; + +// Capacitive load, so Ceff is known. +// Solve for t0, delta t. +class DmpOnePole : public DmpAlg +{ +public: + DmpOnePole(StaState *sta); + void evalDmpEqns() override; + +protected: + double voCrossingUpperBound() override; +}; + +// C2 = 0, one pole, one zero. +class DmpZeroC2 : public DmpOnePole +{ +public: + DmpZeroC2(StaState *sta); + std::string_view name() override { return "c2=0"; } + void init(const LibertyLibrary *drvr_library, + const LibertyCell *drvr_cell, + const Pvt *pvt, + const GateTableModel *gate_model, + const RiseFall *rf, + double rd, + double in_slew, + double c2, + double rpi, + double c1) override; + std::pair gateDelaySlew() override; + +protected: + std::pair V0(double t) override; + std::pair Vl0(double t) override; + double voCrossingUpperBound() override; + +private: + // Pole/zero. + double p1_{0.0}; + double z1_{0.0}; + // Residues. + double k0_{0.0}; + double k1_{0.0}; + double k2_{0.0}; + double k3_{0.0}; +}; + // Delay calculator using Dartu/Menezes/Pileggi effective capacitance // algorithm for RSPF loads. class DmpCeffDelayCalc : public LumpedCapDelayCalc { public: DmpCeffDelayCalc(StaState *sta); - ~DmpCeffDelayCalc() override; bool reduceSupported() const override { return true; } ArcDcalcResult gateDelay(const Pin *drvr_pin, const TimingArc *arc, @@ -94,10 +350,9 @@ protected: private: // Dmp algorithms for each special pi model case. - // These objects are reused to minimize make/deletes. - DmpCap *dmp_cap_; - DmpPi *dmp_pi_; - DmpZeroC2 *dmp_zero_c2_; + DmpCap dmp_cap_; + DmpPi dmp_pi_; + DmpZeroC2 dmp_zero_c2_; DmpAlg *dmp_alg_{nullptr}; }; diff --git a/dcalc/DmpDelayCalc.cc b/dcalc/DmpDelayCalc.cc index f94d2086..03fbe83e 100644 --- a/dcalc/DmpDelayCalc.cc +++ b/dcalc/DmpDelayCalc.cc @@ -77,7 +77,7 @@ DmpCeffElmoreDelayCalc::DmpCeffElmoreDelayCalc(StaState *sta) : ArcDelayCalc * DmpCeffElmoreDelayCalc::copy() { - return new DmpCeffElmoreDelayCalc(this); + return new DmpCeffElmoreDelayCalc(*this); } ArcDcalcResult @@ -213,7 +213,7 @@ DmpCeffTwoPoleDelayCalc::DmpCeffTwoPoleDelayCalc(StaState *sta) : ArcDelayCalc * DmpCeffTwoPoleDelayCalc::copy() { - return new DmpCeffTwoPoleDelayCalc(this); + return new DmpCeffTwoPoleDelayCalc(*this); } Parasitic * From 9065d915db21f2ffde324a05b6f51f5086764eb7 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Tue, 5 May 2026 17:25:09 -0700 Subject: [PATCH 11/17] copy() use copy constructors Signed-off-by: James Cherry --- dcalc/ArnoldiDelayCalc.cc | 13 ++++++++++++- dcalc/CcsCeffDelayCalc.cc | 15 +++++++++++++-- dcalc/CcsCeffDelayCalc.hh | 1 + dcalc/LumpedCapDelayCalc.cc | 2 +- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/dcalc/ArnoldiDelayCalc.cc b/dcalc/ArnoldiDelayCalc.cc index 502a73eb..0fda825f 100644 --- a/dcalc/ArnoldiDelayCalc.cc +++ b/dcalc/ArnoldiDelayCalc.cc @@ -127,6 +127,7 @@ class ArnoldiDelayCalc : public LumpedCapDelayCalc { public: ArnoldiDelayCalc(StaState *sta); + ArnoldiDelayCalc(const ArnoldiDelayCalc &dcalc); ~ArnoldiDelayCalc() override; ArcDelayCalc *copy() override; std::string_view name() const override { return "arnoldi"; } @@ -262,10 +263,20 @@ ArnoldiDelayCalc::ArnoldiDelayCalc(StaState *sta) : _slewV = (double*)malloc(_pinNmax * sizeof(double)); } +ArnoldiDelayCalc::ArnoldiDelayCalc(const ArnoldiDelayCalc &dcalc) : + LumpedCapDelayCalc(dcalc), + reduce_(new ArnoldiReduce(this)), + delay_work_(delay_work_create()) +{ + _pinNmax = dcalc._pinNmax; + _delayV = (double*)malloc(_pinNmax * sizeof(double)); + _slewV = (double*)malloc(_pinNmax * sizeof(double)); +} + ArcDelayCalc * ArnoldiDelayCalc::copy() { - return new ArnoldiDelayCalc(this); + return new ArnoldiDelayCalc(*this); } ArnoldiDelayCalc::~ArnoldiDelayCalc() diff --git a/dcalc/CcsCeffDelayCalc.cc b/dcalc/CcsCeffDelayCalc.cc index 848ac227..9de98d81 100644 --- a/dcalc/CcsCeffDelayCalc.cc +++ b/dcalc/CcsCeffDelayCalc.cc @@ -60,12 +60,23 @@ CcsCeffDelayCalc::CcsCeffDelayCalc(StaState *sta) : { } -CcsCeffDelayCalc::~CcsCeffDelayCalc() { delete table_dcalc_; } +CcsCeffDelayCalc::CcsCeffDelayCalc(const CcsCeffDelayCalc &dcalc) : + LumpedCapDelayCalc(dcalc), + watch_pin_values_(dcalc.network_), + capacitance_unit_(dcalc.capacitance_unit_), + table_dcalc_(makeDmpCeffElmoreDelayCalc(this)) +{ +} + +CcsCeffDelayCalc::~CcsCeffDelayCalc() +{ + delete table_dcalc_; +} ArcDelayCalc * CcsCeffDelayCalc::copy() { - return new CcsCeffDelayCalc(this); + return new CcsCeffDelayCalc(*this); } ArcDcalcResult diff --git a/dcalc/CcsCeffDelayCalc.hh b/dcalc/CcsCeffDelayCalc.hh index 07a659b9..90f27561 100644 --- a/dcalc/CcsCeffDelayCalc.hh +++ b/dcalc/CcsCeffDelayCalc.hh @@ -39,6 +39,7 @@ class CcsCeffDelayCalc : public LumpedCapDelayCalc, { public: CcsCeffDelayCalc(StaState *sta); + CcsCeffDelayCalc(const CcsCeffDelayCalc &dcalc); ~CcsCeffDelayCalc() override; ArcDelayCalc *copy() override; std::string_view name() const override { return "ccs_ceff"; } diff --git a/dcalc/LumpedCapDelayCalc.cc b/dcalc/LumpedCapDelayCalc.cc index 41ef4250..3e8c989b 100644 --- a/dcalc/LumpedCapDelayCalc.cc +++ b/dcalc/LumpedCapDelayCalc.cc @@ -54,7 +54,7 @@ LumpedCapDelayCalc::LumpedCapDelayCalc(StaState *sta) : ArcDelayCalc * LumpedCapDelayCalc::copy() { - return new LumpedCapDelayCalc(this); + return new LumpedCapDelayCalc(*this); } Parasitic * From 9ccaa8c9bff880f35499a8eeb3bb46051cc176bf Mon Sep 17 00:00:00 2001 From: James Cherry Date: Tue, 5 May 2026 17:28:25 -0700 Subject: [PATCH 12/17] rm report_arrival_entries Signed-off-by: James Cherry --- search/Search.i | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/search/Search.i b/search/Search.i index 659fff0c..c378a5e8 100644 --- a/search/Search.i +++ b/search/Search.i @@ -1099,32 +1099,6 @@ set_use_default_arrival_clock(bool enable) Sta::sta()->setUseDefaultArrivalClock(enable); } -// For regression tests. -void -report_arrival_entries() -{ - Sta *sta = Sta::sta(); - Search *search = sta->search(); - search->arrivalIterator()->reportEntries(); -} - -// For regression tests. -void -report_required_entries() -{ - Sta *sta = Sta::sta(); - Search *search = sta->search(); - search->requiredIterator()->reportEntries(); -} - -// For regression tests. -void -levelize() -{ - Sta *sta = Sta::sta(); - sta->levelize()->findLevels(); -} - %} // inline //////////////////////////////////////////////////////////////// From b31ae3cdbb909bc7b2bfcd9fc63442d32fe25b78 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Tue, 5 May 2026 17:33:02 -0700 Subject: [PATCH 13/17] Search::reportArrivals Signed-off-by: James Cherry --- search/Search.cc | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/search/Search.cc b/search/Search.cc index b4d8f7fe..42309866 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -2775,23 +2775,19 @@ Search::reportArrivals(Vertex *vertex, bool report_prev = false; std::string prev_str; if (report_prev) { - prev_str = "prev "; Path *prev_path = path->prevPath(); if (prev_path) { - prev_str += prev_path->to_string(this); - prev_str += " "; const Edge *prev_edge = path->prevEdge(this); TimingArc *arc = path->prevArc(this); - prev_str += prev_edge->from(graph_)->to_string(this); - prev_str += " "; - prev_str += arc->fromEdge()->to_string(); - prev_str += " -> "; - prev_str += prev_edge->to(graph_)->to_string(this); - prev_str += " "; - prev_str += arc->toEdge()->to_string(); + prev_str = sta::format("prev {} {} {} -> {} {}", + prev_path->to_string(this), + prev_edge->from(graph_)->to_string(this), + arc->fromEdge()->to_string(), + prev_edge->to(graph_)->to_string(this), + arc->toEdge()->to_string()); } else - prev_str += "NULL"; + prev_str = "prev NULL"; } report_->report(" {} {} {} / {} {}{}", rf->shortName(), path->minMax(this)->to_string(), From 4ec11fedbae01e6b8da4fd990d9019d851eb08b7 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Tue, 5 May 2026 17:39:08 -0700 Subject: [PATCH 14/17] Sta::clockDomains Signed-off-by: James Cherry --- search/Sta.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/search/Sta.cc b/search/Sta.cc index 286a73c8..c5a40139 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -5069,7 +5069,8 @@ Sta::clockDomains(const Pin *pin, const Mode *mode) { searchPreamble(); - search_->findAllArrivals(); + Vertex *vertex = graph_->pinLoadVertex(pin); + search_->findArrivals(vertex->level()); return search_->clockDomains(pin, mode); } From 2290ed97c0c8ade91dafa83ae89ea96c72330b00 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Tue, 5 May 2026 18:20:46 -0700 Subject: [PATCH 15/17] rm cast Signed-off-by: James Cherry --- include/sta/Search.hh | 18 +++++++++--------- search/Genclks.cc | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/sta/Search.hh b/include/sta/Search.hh index 2db5b6d5..153463e2 100644 --- a/include/sta/Search.hh +++ b/include/sta/Search.hh @@ -738,15 +738,15 @@ protected: Vertex *to_vertex); // Return false to stop visiting. [[nodiscard]] bool visitArc(const Pin *from_pin, - Vertex *from_vertex, - const RiseFall *from_rf, - Path *from_path, - Edge *edge, - TimingArc *arc, - const Pin *to_pin, - Vertex *to_vertex, - const MinMax *min_max, - const Mode *mode); + Vertex *from_vertex, + const RiseFall *from_rf, + Path *from_path, + Edge *edge, + TimingArc *arc, + const Pin *to_pin, + Vertex *to_vertex, + const MinMax *min_max, + const Mode *mode); // This calls visit below with everything required to make to_path. // Return false to stop visiting. virtual bool visitFromPath(const Pin *from_pin, diff --git a/search/Genclks.cc b/search/Genclks.cc index 6e8a39b7..851a601a 100644 --- a/search/Genclks.cc +++ b/search/Genclks.cc @@ -723,7 +723,7 @@ GenclkSrcArrivalVisitor::GenclkSrcArrivalVisitor(Clock *gclk, } GenclkSrcArrivalVisitor::GenclkSrcArrivalVisitor(const GenclkSrcArrivalVisitor &visitor) : - ArrivalVisitor(static_cast(visitor)), + ArrivalVisitor(visitor), gclk_(visitor.gclk_), insert_iter_(visitor.insert_iter_), genclk_info_(visitor.genclk_info_), From fa3c89f436206ee8d3dc7c4fe18f84885f724914 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Tue, 5 May 2026 19:37:43 -0700 Subject: [PATCH 16/17] RequiredVistor integrate RequiredCmp Signed-off-by: James Cherry --- include/sta/Search.hh | 2 +- search/Search.cc | 45 +++++++++++++------------------------------ 2 files changed, 14 insertions(+), 33 deletions(-) diff --git a/include/sta/Search.hh b/include/sta/Search.hh index 153463e2..841dbe6b 100644 --- a/include/sta/Search.hh +++ b/include/sta/Search.hh @@ -861,7 +861,7 @@ public: const MinMax *min_max) override; protected: - RequiredCmp *required_cmp_; + RequiredCmp required_cmp_; VisitPathEnds *visit_path_ends_; }; diff --git a/search/Search.cc b/search/Search.cc index 42309866..ee735a0c 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -3293,40 +3293,24 @@ Search::seedInvalidRequireds() class FindEndRequiredVisitor : public PathEndVisitor { public: - FindEndRequiredVisitor(RequiredCmp *required_cmp, + FindEndRequiredVisitor(RequiredCmp &required_cmp, const StaState *sta); FindEndRequiredVisitor(const StaState *sta); - ~FindEndRequiredVisitor() override; PathEndVisitor *copy() const override; void visit(PathEnd *path_end) override; protected: const StaState *sta_; - RequiredCmp *required_cmp_; - bool own_required_cmp_; + RequiredCmp &required_cmp_; }; -FindEndRequiredVisitor::FindEndRequiredVisitor(RequiredCmp *required_cmp, +FindEndRequiredVisitor::FindEndRequiredVisitor(RequiredCmp &required_cmp, const StaState *sta) : sta_(sta), - required_cmp_(required_cmp), - own_required_cmp_(false) + required_cmp_(required_cmp) { } -FindEndRequiredVisitor::FindEndRequiredVisitor(const StaState *sta) : - sta_(sta), - required_cmp_(new RequiredCmp), - own_required_cmp_(true) -{ -} - -FindEndRequiredVisitor::~FindEndRequiredVisitor() -{ - if (own_required_cmp_) - delete required_cmp_; -} - PathEndVisitor * FindEndRequiredVisitor::copy() const { @@ -3341,7 +3325,7 @@ FindEndRequiredVisitor::visit(PathEnd *path_end) const MinMax *min_max = path->minMax(sta_)->opposite(); size_t path_index = path->pathIndex(sta_); Required required = path_end->requiredTime(sta_); - required_cmp_->requiredSet(path_index, required, min_max, sta_); + required_cmp_.requiredSet(path_index, required, min_max, sta_); } } @@ -3351,7 +3335,7 @@ Search::seedRequired(Vertex *vertex) debugPrint(debug_, "search", 2, "required seed {}", vertex->to_string(this)); RequiredCmp required_cmp; - FindEndRequiredVisitor seeder(&required_cmp, this); + FindEndRequiredVisitor seeder(required_cmp, this); required_cmp.requiredsInit(vertex, this); visit_path_ends_->visitPathEnds(vertex, &seeder); // Enqueue fanin vertices for back-propagating required times. @@ -3363,7 +3347,7 @@ void Search::seedRequiredEnqueueFanin(Vertex *vertex) { RequiredCmp required_cmp; - FindEndRequiredVisitor seeder(&required_cmp, this); + FindEndRequiredVisitor seeder(required_cmp, this); required_cmp.requiredsInit(vertex, this); visit_path_ends_->visitPathEnds(vertex, &seeder); // Enqueue fanin vertices for back-propagating required times. @@ -3438,21 +3422,18 @@ RequiredCmp::required(size_t path_index) RequiredVisitor::RequiredVisitor(const StaState *sta) : PathVisitor(sta), - required_cmp_(new RequiredCmp), visit_path_ends_(new VisitPathEnds(sta)) { } RequiredVisitor::RequiredVisitor(const RequiredVisitor &required_visitor) : PathVisitor(required_visitor.search()->evalPred(), true, &required_visitor), - required_cmp_(new RequiredCmp), visit_path_ends_(new VisitPathEnds(&required_visitor)) { } RequiredVisitor::~RequiredVisitor() { - delete required_cmp_; delete visit_path_ends_; } @@ -3467,7 +3448,7 @@ RequiredVisitor::visit(Vertex *vertex) { debugPrint(debug_, "search", 2, "find required {}", vertex->to_string(this)); - required_cmp_->requiredsInit(vertex, this); + required_cmp_.requiredsInit(vertex, this); // Back propagate requireds from fanout. visitFanoutPaths(vertex); // Check for constraints at endpoints that set required times. @@ -3475,7 +3456,7 @@ RequiredVisitor::visit(Vertex *vertex) FindEndRequiredVisitor seeder(required_cmp_, this); visit_path_ends_->visitPathEnds(vertex, &seeder); } - bool changed = required_cmp_->requiredsSave(vertex, this); + bool changed = required_cmp_.requiredsSave(vertex, this); search_->tnsInvalid(vertex); if (changed) @@ -3521,8 +3502,8 @@ RequiredVisitor::visitFromToPath(const Pin *, delayAsString(arc_delay, this), delayAsString(from_required, this), min_max == MinMax::max() ? "<" : ">", - delayAsString(required_cmp_->required(path_index), this)); - required_cmp_->requiredSet(path_index, from_required, req_min, this); + delayAsString(required_cmp_.required(path_index), this)); + required_cmp_.requiredSet(path_index, from_required, req_min, this); } else { if (search_->crprApproxMissingRequireds()) { @@ -3545,8 +3526,8 @@ RequiredVisitor::visitFromToPath(const Pin *, delayAsString(arc_delay, this), delayAsString(from_required, this), min_max == MinMax::max() ? "<" : ">", - delayAsString(required_cmp_->required(path_index), this)); - required_cmp_->requiredSet(path_index, from_required, req_min, this); + delayAsString(required_cmp_.required(path_index), this)); + required_cmp_.requiredSet(path_index, from_required, req_min, this); break; } } From 2a2450f4b78d817075563a34b82ab0fe63feed47 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Tue, 5 May 2026 20:31:39 -0700 Subject: [PATCH 17/17] read_sdc use cmd_mode Signed-off-by: James Cherry --- doc/ChangeLog.txt | 2 +- sdc/Sdc.tcl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/ChangeLog.txt b/doc/ChangeLog.txt index 496aab91..f4ab5751 100644 --- a/doc/ChangeLog.txt +++ b/doc/ChangeLog.txt @@ -9,7 +9,7 @@ See ApiChangeLog.txt for changes to the STA api. The write_sdc command supports a -mode argument. - read_sdc [-mode mode] + write_sdc [-mode mode] 2026/03/23 ---------- diff --git a/sdc/Sdc.tcl b/sdc/Sdc.tcl index ead9a778..5588c8f1 100644 --- a/sdc/Sdc.tcl +++ b/sdc/Sdc.tcl @@ -45,7 +45,7 @@ proc_redirect read_sdc { if { [info exists keys(-mode)] } { set mode_name $keys(-mode) - set prev_mode [cmd_mode_name] + set prev_mode [cmd_mode] try { set_cmd_mode $mode_name include_file $filename $echo 0