From 606c666180f6d0c5ee2cc246024d1cd47dff6019 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Thu, 3 Jul 2025 17:08:44 -0700 Subject: [PATCH 1/8] set_min/max_delay -from reg/D startpoint warning resolves #265 Signed-off-by: James Cherry --- include/sta/Liberty.hh | 7 ++++++- include/sta/Sdc.hh | 10 +++++---- include/sta/Sta.hh | 1 - liberty/Liberty.cc | 27 +++++++++++++++++-------- network/Network.cc | 2 +- sdc/Sdc.cc | 28 +++++++++++++++++-------- sdc/Sdc.tcl | 1 + search/Search.cc | 46 +++++++++++++++++++----------------------- search/Sta.cc | 20 +----------------- 9 files changed, 75 insertions(+), 67 deletions(-) diff --git a/include/sta/Liberty.hh b/include/sta/Liberty.hh index 4794c30e..f642f0f3 100644 --- a/include/sta/Liberty.hh +++ b/include/sta/Liberty.hh @@ -489,7 +489,6 @@ public: // timing arcs. bool hasInferedRegTimingArcs() const { return has_infered_reg_timing_arcs_; } TestCell *testCell() const { return test_cell_; } - bool isLatchData(LibertyPort *port); void latchEnable(const TimingArcSet *arc_set, // Return values. const LibertyPort *&enable_port, @@ -803,6 +802,10 @@ public: // Has register/latch rise/fall edges from pin. bool isRegClk() const { return is_reg_clk_; } void setIsRegClk(bool is_clk); + bool isRegOutput() const { return is_reg_output_; } + void setIsRegOutput(bool is_reg_out); + bool isLatchData() const { return is_latch_data_; } + void setIsLatchData(bool is_latch_data); // Is the clock for timing checks. bool isCheckClk() const { return is_check_clk_; } void setIsCheckClk(bool is_clk); @@ -899,6 +902,8 @@ protected: bool min_period_exists_:1; bool is_clk_:1; bool is_reg_clk_:1; + bool is_reg_output_:1; + bool is_latch_data_: 1; bool is_check_clk_:1; bool is_clk_gate_clk_:1; bool is_clk_gate_enable_:1; diff --git a/include/sta/Sdc.hh b/include/sta/Sdc.hh index 86eb6cd1..c8aabae9 100644 --- a/include/sta/Sdc.hh +++ b/include/sta/Sdc.hh @@ -771,6 +771,7 @@ public: ClockSet *from_clks, InstanceSet *from_insts, const RiseFallBoth *from_rf); + bool isExceptionStartpoint(const Pin *pin) const; // Make an exception -through specification. ExceptionThru *makeExceptionThru(PinSet *pins, NetSet *nets, @@ -972,10 +973,11 @@ public: ExceptionStateSet *&states) const; // Return hierarchical -thru exceptions that start between // from_pin and to_pin. - ExceptionStateSet *exceptionThruStates(const Pin *from_pin, - const Pin *to_pin, - const RiseFall *to_rf, - const MinMax *min_max) const; + void exceptionThruStates(const Pin *from_pin, + const Pin *to_pin, + const RiseFall *to_rf, + const MinMax *min_max, + ExceptionStateSet *&states) const; // Find the highest priority exception with first exception pt at // pin/clk end. void exceptionTo(ExceptionPathType type, diff --git a/include/sta/Sta.hh b/include/sta/Sta.hh index f4cc39b6..9707a1c4 100644 --- a/include/sta/Sta.hh +++ b/include/sta/Sta.hh @@ -531,7 +531,6 @@ public: void checkExceptionFromPins(ExceptionFrom *from, const char *file, int line) const; - bool exceptionFromInvalid(const Pin *pin) const; void deleteExceptionFrom(ExceptionFrom *from); // Make an exception -through specification. ExceptionThru *makeExceptionThru(PinSet *pins, diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index 364e5dae..9eeb9536 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -1244,10 +1244,13 @@ LibertyCell::addTimingArcSet(TimingArcSet *arc_set) timing_arc_sets_.push_back(arc_set); LibertyPort *from = arc_set->from(); + LibertyPort *to = arc_set->to(); const TimingRole *role = arc_set->role(); if (role == TimingRole::regClkToQ() - || role == TimingRole::latchEnToQ()) + || role == TimingRole::latchEnToQ()) { from->setIsRegClk(true); + to->setIsRegOutput(true); + } if (role->isTimingCheck()) from->setIsCheckClk(true); return set_index; @@ -1881,7 +1884,7 @@ LibertyCell::makeLatchEnable(LibertyPort *d, latch_enables_.push_back(latch_enable); latch_d_to_q_map_[d_to_q] = latch_enable; latch_check_map_[setup_check] = latch_enable; - latch_data_ports_.insert(d); + d->setIsLatchData(true); debugPrint(debug, "liberty_latch", 1, "latch %s -> %s | %s %s -> %s | %s %s -> %s setup", d->name(), @@ -1933,12 +1936,6 @@ LibertyCell::inferLatchRoles(Report *report, } } -bool -LibertyCell::isLatchData(LibertyPort *port) -{ - return latch_data_ports_.hasKey(port); -} - void LibertyCell::latchEnable(const TimingArcSet *d_to_q_set, // Return values. @@ -2100,6 +2097,8 @@ LibertyPort::LibertyPort(LibertyCell *cell, min_period_exists_(false), is_clk_(false), is_reg_clk_(false), + is_reg_output_(false), + is_latch_data_(false), is_check_clk_(false), is_clk_gate_clk_(false), is_clk_gate_enable_(false), @@ -2547,6 +2546,18 @@ LibertyPort::setIsRegClk(bool is_clk) is_reg_clk_ = is_clk; } +void +LibertyPort::setIsRegOutput(bool is_reg_out) +{ + is_reg_output_ = is_reg_out; +} + +void +LibertyPort::setIsLatchData(bool is_latch_data) +{ + is_latch_data_ = is_latch_data; +} + void LibertyPort::setIsCheckClk(bool is_clk) { diff --git a/network/Network.cc b/network/Network.cc index d80b21ef..578c0664 100644 --- a/network/Network.cc +++ b/network/Network.cc @@ -655,7 +655,7 @@ Network::isLatchData(const Pin *pin) const { LibertyPort *port = libertyPort(pin); if (port) - return port->libertyCell()->isLatchData(port); + return port->isLatchData(); else return false; } diff --git a/sdc/Sdc.cc b/sdc/Sdc.cc index a63c2348..11078100 100644 --- a/sdc/Sdc.cc +++ b/sdc/Sdc.cc @@ -3914,8 +3914,7 @@ Sdc::recordPathDelayInternalFrom(ExceptionPath *exception) if (from && from->hasPins()) { for (const Pin *pin : *from->pins()) { - if (!(network_->isRegClkPin(pin) - || network_->isTopLevelPort(pin))) { + if (!isExceptionStartpoint(pin)) { path_delay_internal_from_.insert(pin); if (exception->breakPath()) path_delay_internal_from_break_.insert(pin); @@ -3932,8 +3931,7 @@ Sdc::unrecordPathDelayInternalFrom(ExceptionPath *exception) && from->hasPins() && !path_delay_internal_from_.empty()) { for (const Pin *pin : *from->pins()) { - if (!(network_->isRegClkPin(pin) - || network_->isTopLevelPort(pin)) + if (!isExceptionStartpoint(pin) && !pathDelayFrom(pin)) { path_delay_internal_from_.erase(pin); if (exception->breakPath()) @@ -3943,6 +3941,21 @@ Sdc::unrecordPathDelayInternalFrom(ExceptionPath *exception) } } +bool +Sdc::isExceptionStartpoint(const Pin *pin) const +{ + Net *net = network_->net(pin); + const LibertyPort *port = network_->libertyPort(pin); + return ((network_->isTopLevelPort(pin) + && network_->direction(pin)->isAnyInput()) + || (port && port->isRegClk()) + || (port && port->isLatchData())) + // Pins connected to power/ground are invalid. + && !(net + && (network_->isPower(net) + || network_->isGround(net))); +} + bool Sdc::pathDelayFrom(const Pin *pin) { @@ -5304,13 +5317,13 @@ Sdc::filterRegQStates(const Pin *to_pin, } } -ExceptionStateSet * +void Sdc::exceptionThruStates(const Pin *from_pin, const Pin *to_pin, const RiseFall *to_rf, - const MinMax *min_max) const + const MinMax *min_max, + ExceptionStateSet *&states) const { - ExceptionStateSet *states = nullptr; exceptionThruStates(first_thru_pin_exceptions_.findKey(to_pin), to_rf, min_max, states); if (!first_thru_edge_exceptions_.empty()) { @@ -5325,7 +5338,6 @@ Sdc::exceptionThruStates(const Pin *from_pin, exceptionThruStates(first_thru_inst_exceptions_.findKey(to_inst), to_rf, min_max, states); } - return states; } void diff --git a/sdc/Sdc.tcl b/sdc/Sdc.tcl index 9a4f0f73..b5616f38 100644 --- a/sdc/Sdc.tcl +++ b/sdc/Sdc.tcl @@ -2355,6 +2355,7 @@ proc set_path_delay { cmd args min_max } { set from [parse_from_arg keys arg_error] set thrus [parse_thrus_arg args arg_error] set to [parse_to_arg keys flags arg_error] + check_exception_pins $from $to if { $arg_error } { delete_from_thrus_to $from $thrus $to } else { diff --git a/search/Search.cc b/search/Search.cc index 290643f1..5c0d22cd 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -980,11 +980,9 @@ Search::visitStartpoints(VertexVisitor *visitor) visitor->visit(vertex); const PinSet &startpoints = sdc_->pathDelayInternalFrom(); - if (!startpoints.empty()) { - for (const Pin *pin : startpoints) { - Vertex *vertex = graph_->pinDrvrVertex(pin); - visitor->visit(vertex); - } + for (const Pin *pin : startpoints) { + Vertex *vertex = graph_->pinDrvrVertex(pin); + visitor->visit(vertex); } } @@ -2176,8 +2174,7 @@ PathVisitor::visitFromPath(const Pin *from_pin, to_tag = search_->thruClkTag(from_path, from_vertex, from_tag, true, edge, to_rf, arc_delay_min_max_eq, min_max, path_ap); - if (to_tag) - to_arrival = from_arrival + arc_delay; + to_arrival = from_arrival + arc_delay; } } } @@ -2272,11 +2269,10 @@ PathVisitor::visitFromPath(const Pin *from_pin, else { if (!(sdc_->isPathDelayInternalFromBreak(to_pin) || sdc_->isPathDelayInternalToBreak(from_pin))) { + to_tag = search_->thruTag(from_tag, edge, to_rf, min_max, path_ap); arc_delay = search_->deratedDelay(from_vertex, arc, edge, false, path_ap); - if (!delayInf(arc_delay)) { + if (!delayInf(arc_delay)) to_arrival = from_arrival + arc_delay; - to_tag = search_->thruTag(from_tag, edge, to_rf, min_max, path_ap); - } } } if (to_tag) @@ -2643,7 +2639,7 @@ Search::mutateTag(Tag *from_tag, // Kill path delay tags past the -to pin. if ((exception->isPathDelay() - && sdc_->isCompleteTo(state, from_pin, from_rf, min_max)) + && sdc_->isCompleteTo(state, to_pin, to_rf, min_max)) // Kill loop tags at register clock pins. || (exception->isLoop() && to_is_reg_clk)) { @@ -2653,7 +2649,7 @@ Search::mutateTag(Tag *from_tag, } // Get the set of -thru exceptions starting at to_pin/edge. - new_states = sdc_->exceptionThruStates(from_pin, to_pin, to_rf, min_max); + sdc_->exceptionThruStates(from_pin, to_pin, to_rf, min_max, new_states); if (new_states || state_change) { // Second pass to apply state changes and add updated existing // states to new states. @@ -2666,18 +2662,18 @@ Search::mutateTag(Tag *from_tag, // Found a -thru that we've been waiting for. state = state->nextState(); - // Don't propagate a completed false path -thru unless it is a - // clock. Clocks carry the completed false path to disable - // downstream paths that use the clock as data. - if ((state->isComplete() - && exception->isFalse() - && !from_is_clk) - // to_pin/edge completes a loop path. - || (exception->isLoop() - && state->isComplete())) { - delete new_states; - return nullptr; - } + // Don't propagate a completed false path -thru unless it is a + // clock. Clocks carry the completed false path to disable + // downstream paths that use the clock as data. + if ((state->isComplete() + && exception->isFalse() + && !from_is_clk) + // to_pin/edge completes a loop path. + || (exception->isLoop() + && state->isComplete())) { + delete new_states; + return nullptr; + } // Kill path delay tags past the -to pin. if (!((exception->isPathDelay() @@ -2691,7 +2687,7 @@ Search::mutateTag(Tag *from_tag, } else // Get the set of -thru exceptions starting at to_pin/edge. - new_states = sdc_->exceptionThruStates(from_pin, to_pin, to_rf, min_max); + sdc_->exceptionThruStates(from_pin, to_pin, to_rf, min_max, new_states); if (new_states) return findTag(to_rf, path_ap, to_clk_info, to_is_clk, diff --git a/search/Sta.cc b/search/Sta.cc index 5ae35760..f885f134 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -2027,7 +2027,7 @@ Sta::checkExceptionFromPins(ExceptionFrom *from, PinSet::ConstIterator pin_iter(from->pins()); while (pin_iter.hasNext()) { const Pin *pin = pin_iter.next(); - if (exceptionFromInvalid(pin)) { + if (!sdc_->isExceptionStartpoint(pin)) { if (line) report_->fileWarn(1554, file, line, "'%s' is not a valid start point.", cmd_network_->pathName(pin)); @@ -2039,24 +2039,6 @@ Sta::checkExceptionFromPins(ExceptionFrom *from, } } -bool -Sta::exceptionFromInvalid(const Pin *pin) const -{ - Net *net = network_->net(pin); - // Floating pins are invalid. - return (net == nullptr - && !network_->isTopLevelPort(pin)) - || (net - // Pins connected to power/ground are invalid. - && (network_->isPower(net) - || network_->isGround(net))) - || !((network_->isTopLevelPort(pin) - && network_->direction(pin)->isAnyInput()) - || network_->isRegClkPin(pin) - || network_->isLatchData(pin) - || network_->direction(pin)->isInternal()); -} - void Sta::deleteExceptionFrom(ExceptionFrom *from) { From 6df4cdc794275c1a97a517aedf27d6617af3b6b1 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Thu, 3 Jul 2025 18:43:50 -0700 Subject: [PATCH 2/8] Vertex::to_string use sdc network Signed-off-by: James Cherry --- graph/Graph.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graph/Graph.cc b/graph/Graph.cc index 1902f485..b3bb0260 100644 --- a/graph/Graph.cc +++ b/graph/Graph.cc @@ -999,7 +999,7 @@ Vertex::setObjectIdx(ObjectIdx idx) string Vertex::to_string(const StaState *sta) const { - const Network *network = sta->network(); + const Network *network = sta->sdcNetwork(); if (network->direction(pin_)->isBidirect()) { string str = network->pathName(pin_); str += ' '; From 1c45b898793b42831740c93f7eedbfd76e0c54b4 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Fri, 4 Jul 2025 16:43:21 -0700 Subject: [PATCH 3/8] set_min/max_delay illegal endpoint warning Signed-off-by: James Cherry --- graph/Graph.tcl | 2 +- include/sta/Sdc.hh | 2 +- sdc/Sdc.cc | 67 +++++++++++++++++++++-------------------- search/Sta.cc | 2 +- search/VisitPathEnds.cc | 8 ++--- 5 files changed, 40 insertions(+), 41 deletions(-) diff --git a/graph/Graph.tcl b/graph/Graph.tcl index bc59cbb8..331fcc73 100644 --- a/graph/Graph.tcl +++ b/graph/Graph.tcl @@ -186,7 +186,7 @@ proc edge_disable_reason { edge } { } if { [$edge is_disabled_preset_clear] } { if { $disables != "" } { append disables ", " } - append disables "timing_enable_preset_clear_arcs" + append disables "sta_preset_clear_arcs_enabled" } return $disables } diff --git a/include/sta/Sdc.hh b/include/sta/Sdc.hh index c8aabae9..4cfd24ac 100644 --- a/include/sta/Sdc.hh +++ b/include/sta/Sdc.hh @@ -777,7 +777,7 @@ public: NetSet *nets, InstanceSet *insts, const RiseFallBoth *rf); - bool exceptionToInvalid(const Pin *pin); + bool isExceptionEndpoint(const Pin *pin); // Make an exception -to specification. ExceptionTo *makeExceptionTo(PinSet *pins, ClockSet *clks, diff --git a/sdc/Sdc.cc b/sdc/Sdc.cc index 11078100..d26def4c 100644 --- a/sdc/Sdc.cc +++ b/sdc/Sdc.cc @@ -3799,6 +3799,22 @@ Sdc::makeExceptionFrom(PinSet *from_pins, return nullptr; } +bool +Sdc::isExceptionStartpoint(const Pin *pin) const +{ + Net *net = network_->net(pin); + const LibertyPort *port = network_->libertyPort(pin); + return ((network_->isTopLevelPort(pin) + && network_->direction(pin)->isAnyInput()) + || (port && port->isRegClk()) + || (port && port->isLatchData())) + // Pins connected to power/ground are invalid. + && !(net + && (network_->isPower(net) + || network_->isGround(net))) + && !network_->isHierarchical(pin); +} + ExceptionThru * Sdc::makeExceptionThru(PinSet *pins, NetSet *nets, @@ -3833,31 +3849,31 @@ Sdc::makeExceptionTo(PinSet *pins, // Valid endpoints include gated clock enables which are not // known until clock arrivals are determined. bool -Sdc::exceptionToInvalid(const Pin *pin) +Sdc::isExceptionEndpoint(const Pin *pin) { Net *net = network_->net(pin); - // Floating pins are invalid. - if ((net == nullptr - && !(network_->isTopLevelPort(pin) - || network_->direction(pin)->isInternal())) - || (net - // Pins connected to power/ground are invalid. - && (network_->isPower(net) - || network_->isGround(net))) - // Hierarchical pins are invalid. - || network_->isHierarchical(pin)) - return true; - // Register/latch Q pins are invalid. - LibertyPort *port = network_->libertyPort(pin); + bool has_checks = false; + const LibertyPort *port = network_->libertyPort(pin); if (port) { + // Look for timing checks to the pin witihout using the graph because + // it may not exist. LibertyCell *cell = port->libertyCell(); for (TimingArcSet *arc_set : cell->timingArcSets(nullptr, port)) { - const TimingRole *role = arc_set->role(); - if (role->genericRole() == TimingRole::regClkToQ()) - return true; + if (arc_set->role()->isTimingCheck()) { + has_checks = true; + break; + } } } - return false; + return ((network_->isTopLevelPort(pin) + && network_->direction(pin)->isAnyOutput()) + || has_checks + || (port && port->isLatchData())) + // Pins connected to power/ground are invalid. + && !(net + && (network_->isPower(net) + || network_->isGround(net))) + && !network_->isHierarchical(pin); } void @@ -3941,21 +3957,6 @@ Sdc::unrecordPathDelayInternalFrom(ExceptionPath *exception) } } -bool -Sdc::isExceptionStartpoint(const Pin *pin) const -{ - Net *net = network_->net(pin); - const LibertyPort *port = network_->libertyPort(pin); - return ((network_->isTopLevelPort(pin) - && network_->direction(pin)->isAnyInput()) - || (port && port->isRegClk()) - || (port && port->isLatchData())) - // Pins connected to power/ground are invalid. - && !(net - && (network_->isPower(net) - || network_->isGround(net))); -} - bool Sdc::pathDelayFrom(const Pin *pin) { diff --git a/search/Sta.cc b/search/Sta.cc index f885f134..8028a716 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -2085,7 +2085,7 @@ Sta::checkExceptionToPins(ExceptionTo *to, PinSet::Iterator pin_iter(to->pins()); while (pin_iter.hasNext()) { const Pin *pin = pin_iter.next(); - if (sdc_->exceptionToInvalid(pin)) { + if (!sdc_->isExceptionEndpoint(pin)) { if (line) report_->fileWarn(1551, file, line, "'%s' is not a valid endpoint.", cmd_network_->pathName(pin)); diff --git a/search/VisitPathEnds.cc b/search/VisitPathEnds.cc index 5345627f..effc22b9 100644 --- a/search/VisitPathEnds.cc +++ b/search/VisitPathEnds.cc @@ -113,9 +113,8 @@ VisitPathEnds::visitClkedPathEnds(const Pin *pin, else if (vertex->hasChecks()) visitCheckEnd(pin, vertex, path, end_rf, path_ap, filtered, visitor, is_constrained); - else if (!sdc_->exceptionToInvalid(pin) - && (!filtered - || search_->matchesFilter(path, nullptr))) { + else if (!filtered + || search_->matchesFilter(path, nullptr)) { PathDelay *path_delay = pathDelayTo(path, pin, end_rf, path_min_max); if (path_delay) { PathEndPathDelay path_end(path_delay, path, this); @@ -231,8 +230,7 @@ VisitPathEnds::visitCheckEnd(const Pin *pin, } } } - if (!check_clked - && !sdc_->exceptionToInvalid(pin)) + if (!check_clked) visitCheckEndUnclked(pin, vertex, path, end_rf, path_ap, filtered, visitor, is_constrained); } From 2c6ee711117cd60bc6a5f066db290b83597883a7 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Fri, 4 Jul 2025 17:03:10 -0700 Subject: [PATCH 4/8] rm Genclks::updateSrcPathPrevs Signed-off-by: James Cherry --- search/Genclks.cc | 27 --------------------------- search/Genclks.hh | 1 - search/Search.cc | 3 --- 3 files changed, 31 deletions(-) diff --git a/search/Genclks.cc b/search/Genclks.cc index a6eb014a..299345fc 100644 --- a/search/Genclks.cc +++ b/search/Genclks.cc @@ -1041,33 +1041,6 @@ Genclks::srcPath(const Clock *gclk, return nullptr; } -void -Genclks::updateSrcPathPrevs() -{ - for (auto const & [clk_pin, src_paths] : genclk_src_paths_) { - for (const Path &src_path : src_paths) { - if (!src_path.isNull()) { - const Path *p = &src_path; - while (p) { - Path *src_vpath = Path::vertexPath(p, this); - if (src_vpath) { - Path *prev_path = p->prevPath(); - if (prev_path) { - Path *prev_vpath = Path::vertexPath(prev_path, this); - src_vpath->setPrevPath(prev_vpath); - src_vpath->setPrevEdgeArc(p->prevEdge(this), - p->prevArc(this), this); - } - } - p = p->prevPath(); - } - debugPrint(debug_, "genclk", 3, "repaired src path prev %s", - src_path.to_string(this).c_str()); - } - } - } -} - Arrival Genclks::insertionDelay(const Clock *clk, const Pin *pin, diff --git a/search/Genclks.hh b/search/Genclks.hh index 29f5ccae..32752043 100644 --- a/search/Genclks.hh +++ b/search/Genclks.hh @@ -85,7 +85,6 @@ public: Level clkPinMaxLevel(const Clock *clk) const; void copyGenClkSrcPaths(Vertex *vertex, TagGroupBldr *tag_bldr); - void updateSrcPathPrevs(); private: void findInsertionDelays(); diff --git a/search/Search.cc b/search/Search.cc index 5c0d22cd..ffc28ccf 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -610,7 +610,6 @@ Search::findFilteredArrivals(bool thru_latches) int arrival_count = arrival_iter_->visitParallel(max_level, arrival_visitor_); deleteTagsPrev(); - genclks_->updateSrcPathPrevs(); debugPrint(debug_, "search", 1, "found %d arrivals", arrival_count); } arrivals_exist_ = true; @@ -889,7 +888,6 @@ Search::findClkArrivals() arrival_visitor_->init(false, &search_clk); arrival_iter_->visitParallel(levelize_->maxLevel(), arrival_visitor_); deleteTagsPrev(); - genclks_->updateSrcPathPrevs(); arrivals_exist_ = true; stats.report("Find clk arrivals"); } @@ -1059,7 +1057,6 @@ Search::findArrivals1(Level level) Stats stats(debug_, report_); int arrival_count = arrival_iter_->visitParallel(level, arrival_visitor_); deleteTagsPrev(); - genclks_->updateSrcPathPrevs(); stats.report("Find arrivals"); if (arrival_iter_->empty() && invalid_arrivals_->empty()) { From 51368ecaccd96bc8d19ac5e69e0f62d6cfbfd2d2 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Fri, 4 Jul 2025 17:29:56 -0700 Subject: [PATCH 5/8] critical missing from messages.txt Signed-off-by: James Cherry --- etc/FindMessages.tcl | 2 +- search/Sta.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/FindMessages.tcl b/etc/FindMessages.tcl index 24dcc3ad..bf60754b 100755 --- a/etc/FindMessages.tcl +++ b/etc/FindMessages.tcl @@ -61,7 +61,7 @@ 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)\(|tclArgError\(interp,\s*)([0-9]+),.*(".+")} +set warn_regexp_c {(?:(?:->critical|->warn|->fileWarn|->error|->fileError|libWarn|libError| warn)\(|tclArgError\(interp,\s*)([0-9]+),.*(".+")} set files_tcl {} foreach subdir $subdirs { diff --git a/search/Sta.cc b/search/Sta.cc index 8028a716..c9e632cf 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -4240,7 +4240,7 @@ Sta::replaceEquivCellBefore(const Instance *inst, if (to_set) edge->setTimingArcSet(to_set); else - report_->critical(1553, "corresponding timing arc set not found in equiv cells"); + report_->critical(1555, "corresponding timing arc set not found in equiv cells"); } } } From 610fba0d1560e505421b0ce3999e7d9a075f8a94 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Fri, 4 Jul 2025 17:35:34 -0700 Subject: [PATCH 6/8] use -Werror=misleading-indentation Signed-off-by: James Cherry --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3043c6ab..baa4e582 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -532,7 +532,8 @@ if (TCL_READLINE) endif() # common to gcc/clang -set(CXX_FLAGS -Wall -Wextra -pedantic -Wcast-qual -Wredundant-decls -Wformat-security) +set(CXX_FLAGS -Wall -Wextra -pedantic -Wcast-qual -Wredundant-decls + -Wformat-security -Werror=misleading-indentation) if(ENABLE_TSAN) message(STATUS "Thread sanitizer: ${ENABLE_TSAN}") From cda30445d652c6d41f68732675ddbf28b5efeeab Mon Sep 17 00:00:00 2001 From: James Cherry Date: Fri, 4 Jul 2025 17:39:10 -0700 Subject: [PATCH 7/8] rm Sta::setMinLibrary Signed-off-by: James Cherry --- include/sta/Sta.hh | 2 -- search/Sta.cc | 14 -------------- 2 files changed, 16 deletions(-) diff --git a/include/sta/Sta.hh b/include/sta/Sta.hh index 9707a1c4..a07192f1 100644 --- a/include/sta/Sta.hh +++ b/include/sta/Sta.hh @@ -118,8 +118,6 @@ public: Corner *corner, const MinMaxAll *min_max, bool infer_latches); - bool setMinLibrary(const char *min_filename, - const char *max_filename); bool readVerilog(const char *filename); // Network readers call this to notify the Sta to delete any previously // linked network. diff --git a/search/Sta.cc b/search/Sta.cc index c9e632cf..d88c5a07 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -735,20 +735,6 @@ Sta::readLibertyAfter(LibertyLibrary *liberty, network_, report_); } -bool -Sta::setMinLibrary(const char *min_filename, - const char *max_filename) -{ - LibertyLibrary *max_lib = network_->findLibertyFilename(max_filename); - if (max_lib) { - LibertyLibrary *min_lib = readLibertyFile(min_filename, cmd_corner_, - MinMaxAll::min(), false); - return min_lib != nullptr; - } - else - return false; -} - bool Sta::readVerilog(const char *filename) { From 5e4ce2fd233977f705f2696f3e6096bf997c5e8c Mon Sep 17 00:00:00 2001 From: James Cherry Date: Wed, 9 Jul 2025 11:50:36 -0700 Subject: [PATCH 8/8] replace_cell equiv funcs, diff arcs resolves #267 Signed-off-by: James Cherry --- include/sta/EquivCells.hh | 8 +++++++- liberty/EquivCells.cc | 13 +++++++++++++ search/Sta.cc | 4 +++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/include/sta/EquivCells.hh b/include/sta/EquivCells.hh index 2b201d2b..4a337b0c 100644 --- a/include/sta/EquivCells.hh +++ b/include/sta/EquivCells.hh @@ -57,11 +57,17 @@ protected: }; // Predicate that is true when the ports, functions, sequentials and -// timing arcs match. +// functions or timing arcs match. bool equivCells(const LibertyCell *cell1, const LibertyCell *cell2); +// Predicate that is true when the ports, functions, sequentials and +// timing arcs match. +bool +equivCellsArcs(const LibertyCell *cell1, + const LibertyCell *cell2); + // Predicate that is true when the ports match. bool equivCellPorts(const LibertyCell *cell1, diff --git a/liberty/EquivCells.cc b/liberty/EquivCells.cc index 84e57cc0..da960f9c 100644 --- a/liberty/EquivCells.cc +++ b/liberty/EquivCells.cc @@ -341,6 +341,19 @@ equivCells(const LibertyCell *cell1, || equivCellTimingArcSets(cell1, cell2)); } +bool +equivCellsArcs(const LibertyCell *cell1, + const LibertyCell *cell2) +{ + return equivCellPorts(cell1, cell2) + && equivCellFuncs(cell1, cell2) + && equivCellPgPorts(cell1, cell2) + && equivCellSequentials(cell1, cell2) + && equivCellStatetables(cell1, cell2) + // Reqwuire timing arc equivalence if there are no functions. + && equivCellTimingArcSets(cell1, cell2); +} + static bool cellHasFuncs(const LibertyCell *cell) { diff --git a/search/Sta.cc b/search/Sta.cc index d88c5a07..d86434af 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -4089,7 +4089,9 @@ Sta::replaceCell(Instance *inst, { NetworkEdit *network = networkCmdEdit(); LibertyCell *from_lib_cell = network->libertyCell(inst); - if (sta::equivCells(from_lib_cell, to_lib_cell)) { + if (sta::equivCellsArcs(from_lib_cell, to_lib_cell)) { + // Replace celll optimized for less disruption to graph + // when ports and timing arcs are equivalent. replaceEquivCellBefore(inst, to_lib_cell); network->replaceCell(inst, to_cell); replaceEquivCellAfter(inst);