From bbffa9b4939bafc55da8b2a75cdcda151aecaa46 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Wed, 11 Dec 2024 11:09:35 -0800 Subject: [PATCH 1/5] crpr for clk paths Signed-off-by: James Cherry --- include/sta/Search.hh | 37 +++++++++++++++++++------------------ search/ClkInfo.hh | 4 ++-- search/Crpr.cc | 17 +++++++++++++---- search/Search.cc | 10 ++++++---- 4 files changed, 40 insertions(+), 28 deletions(-) diff --git a/include/sta/Search.hh b/include/sta/Search.hh index 2c1f2504..5b3d6772 100644 --- a/include/sta/Search.hh +++ b/include/sta/Search.hh @@ -238,25 +238,26 @@ public: const RiseFall *to_rf, const MinMax *min_max, const PathAnalysisPt *path_ap); - virtual Tag *thruTag(Tag *from_tag, - Edge *edge, - const RiseFall *to_rf, - const MinMax *min_max, - const PathAnalysisPt *path_ap); - virtual Tag *thruClkTag(PathVertex *from_path, - Tag *from_tag, - bool to_propagates_clk, - Edge *edge, - const RiseFall *to_rf, - const MinMax *min_max, - const PathAnalysisPt *path_ap); + Tag *thruTag(Tag *from_tag, + Edge *edge, + const RiseFall *to_rf, + const MinMax *min_max, + const PathAnalysisPt *path_ap); + Tag *thruClkTag(PathVertex *from_path, + Tag *from_tag, + bool to_propagates_clk, + Edge *edge, + const RiseFall *to_rf, + const MinMax *min_max, + const PathAnalysisPt *path_ap); ClkInfo *thruClkInfo(PathVertex *from_path, - ClkInfo *from_tag_clk, - Edge *edge, - Vertex *to_vertex, - const Pin *to_pin, - const MinMax *min_max, - const PathAnalysisPt *path_ap); + ClkInfo *from_clk_info, + bool from_is_clk, + Edge *edge, + const Pin *to_pin, + bool to_is_clk, + const MinMax *min_max, + const PathAnalysisPt *path_ap); ClkInfo *clkInfoWithCrprClkPath(ClkInfo *from_clk_info, PathVertex *from_path, const PathAnalysisPt *path_ap); diff --git a/search/ClkInfo.hh b/search/ClkInfo.hh index 2e4c198e..3989f368 100644 --- a/search/ClkInfo.hh +++ b/search/ClkInfo.hh @@ -54,8 +54,8 @@ public: const Arrival &insertion() const { return insertion_; } ClockUncertainties *uncertainties() const { return uncertainties_; } PathAPIndex pathAPIndex() const { return path_ap_index_; } - // Clock path for the last driver in the clock network used for - // crpr resolution. + // 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_; } VertexId crprClkVertexId() const; diff --git a/search/Crpr.cc b/search/Crpr.cc index af1b14e8..7aa9605b 100644 --- a/search/Crpr.cc +++ b/search/Crpr.cc @@ -152,13 +152,22 @@ CheckCrpr::checkCrpr1(const Path *src_path, { crpr = 0.0; crpr_pin = nullptr; - ClkInfo *src_clk_info = src_path->tag(this)->clkInfo(); + const Tag *src_tag = src_path->tag(this); + ClkInfo *src_clk_info = src_tag->clkInfo(); ClkInfo *tgt_clk_info = tgt_clk_path->tag(this)->clkInfo(); const Clock *src_clk = src_clk_info->clock(); const Clock *tgt_clk = tgt_clk_info->clock(); - const PathVertex src_clk_path1(src_clk_info->crprClkPath(), this); - const PathVertex *src_clk_path = - src_clk_path1.isNull() ? nullptr : &src_clk_path1; + PathVertex src_clk_path1; + PathVertexRep &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); + src_clk_path = &src_clk_path1; + } + else if (!src_crpr_clk_path.isNull()) { + src_clk_path1.init(src_crpr_clk_path, this); + src_clk_path = &src_clk_path1; + } const MinMax *src_clk_min_max = src_clk_path ? src_clk_path->minMax(this) : src_path->minMax(this); if (src_clk && tgt_clk diff --git a/search/Search.cc b/search/Search.cc index 0a22323e..9cc3d1df 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -2417,8 +2417,9 @@ Search::thruClkTag(PathVertex *from_path, && to_propagates_clk && (role->isWire() || role == TimingRole::combinational())); - ClkInfo *to_clk_info = thruClkInfo(from_path, from_clk_info, - edge, to_vertex, to_pin, min_max, path_ap); + ClkInfo *to_clk_info = thruClkInfo(from_path, from_clk_info, from_is_clk, + edge, to_pin, to_is_clk, + min_max, path_ap); Tag *to_tag = mutateTag(from_tag,from_pin,from_rf,from_is_clk,from_clk_info, to_pin, to_rf, to_is_clk, to_is_reg_clk, false, to_clk_info, nullptr, min_max, path_ap); @@ -2429,9 +2430,10 @@ Search::thruClkTag(PathVertex *from_path, ClkInfo * Search::thruClkInfo(PathVertex *from_path, ClkInfo *from_clk_info, + bool from_is_clk, Edge *edge, - Vertex *to_vertex, const Pin *to_pin, + bool to_is_clk, const MinMax *min_max, const PathAnalysisPt *path_ap) { @@ -2462,7 +2464,7 @@ Search::thruClkInfo(PathVertex *from_path, PathVertex *to_crpr_clk_path = nullptr; if (sdc_->crprActive() - && to_vertex->isRegClk()) { + && from_is_clk && !to_is_clk) { to_crpr_clk_path = from_path; changed = true; } From fc1a7499ea5c1888842b8a4dab956ec0151b3b71 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Wed, 11 Dec 2024 16:31:21 -0800 Subject: [PATCH 2/5] merge OR OpenSTA PR 211, 213 with tweeks Signed-off-by: James Cherry --- search/Crpr.cc | 44 +++++++++++++++++++++++++++----------------- search/Crpr.hh | 4 ++-- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/search/Crpr.cc b/search/Crpr.cc index 7aa9605b..92bae4b9 100644 --- a/search/Crpr.cc +++ b/search/Crpr.cc @@ -46,20 +46,20 @@ CheckCrpr::CheckCrpr(StaState *sta) : { } -PathVertex * +void CheckCrpr::clkPathPrev(const PathVertex *path, - PathVertex &tmp) + PathVertex &prev) { Vertex *vertex = path->vertex(this); int arrival_index; bool exists; path->arrivalIndex(arrival_index, exists); - tmp = clkPathPrev(vertex, arrival_index); - if (tmp.isNull()) - return nullptr; + PathVertexRep *prevs = graph_->prevPaths(vertex); + if (prevs) + prev.init(prevs[arrival_index], this); else - return &tmp; + criticalError(2200, "missing prev paths"); } PathVertex @@ -70,7 +70,7 @@ CheckCrpr::clkPathPrev(Vertex *vertex, if (prevs) return PathVertex(prevs[arrival_index], this); else { - criticalError(248, "missing prev paths"); + criticalError(2201, "missing prev paths"); return PathVertex(); } } @@ -251,20 +251,30 @@ CheckCrpr::findCrpr(const PathVertex *src_clk_path, } const PathVertex *src_clk_path2 = src_clk_path1; const PathVertex *tgt_clk_path2 = tgt_clk_path1; - PathVertex tmp1, tmp2; + PathVertex src_prev, tgt_prev; // src_clk_path and tgt_clk_path are now in the same (gen)clk src path. // Use the vertex levels to back up the deeper path to see if they // overlap. - while (src_clk_path2 && tgt_clk_path2 - && src_clk_path2->pin(this) != tgt_clk_path2->pin(this)) { - Level src_level = src_clk_path2->vertex(this)->level(); - Level tgt_level = tgt_clk_path2->vertex(this)->level(); - if (src_level >= tgt_level) - src_clk_path2 = clkPathPrev(src_clk_path2, tmp1); - if (tgt_level >= src_level) - tgt_clk_path2 = clkPathPrev(tgt_clk_path2, tmp2); + int src_level = src_clk_path2->vertex(this)->level(); + int tgt_level = tgt_clk_path2->vertex(this)->level(); + while (src_clk_path2->pin(this) != tgt_clk_path2->pin(this)) { + int level_diff = src_level - tgt_level; + if (level_diff >= 0) { + clkPathPrev(src_clk_path2, src_prev); + if (src_prev.isNull()) + break; + src_clk_path2 = &src_prev; + src_level = src_clk_path2->vertex(this)->level(); + } + if (level_diff <= 0) { + clkPathPrev(tgt_clk_path2, tgt_prev); + if (tgt_prev.isNull()) + break; + tgt_clk_path2 = &tgt_prev; + tgt_level = tgt_clk_path2->vertex(this)->level(); + } } - if (src_clk_path2 && tgt_clk_path2 + if (!src_clk_path2->isNull() && !tgt_clk_path2->isNull() && (src_clk_path2->transition(this) == tgt_clk_path2->transition(this) || same_pin)) { debugPrint(debug_, "crpr", 2, "crpr pin %s", diff --git a/search/Crpr.hh b/search/Crpr.hh index 62999a33..114a362c 100644 --- a/search/Crpr.hh +++ b/search/Crpr.hh @@ -56,8 +56,8 @@ public: int arrival_index); private: - PathVertex *clkPathPrev(const PathVertex *path, - PathVertex &tmp); + void clkPathPrev(const PathVertex *path, + PathVertex &prev); Arrival otherMinMaxArrival(const PathVertex *path); void checkCrpr1(const Path *src_path, const PathVertex *tgt_clk_path, From 49a931b0d1889890ef914caa62fd6fd6ff9917ab Mon Sep 17 00:00:00 2001 From: Ethan Mahintorabi Date: Fri, 13 Dec 2024 09:44:30 -0800 Subject: [PATCH 3/5] Adds default liberty check to Sta::writeTimingModel (#144) Signed-off-by: Ethan Mahintorabi --- search/Sta.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/search/Sta.cc b/search/Sta.cc index 05bd3dcc..2fdf228b 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -5600,6 +5600,9 @@ Sta::writeTimingModel(const char *lib_name, const char *filename, const Corner *corner) { + if (network()->defaultLibertyLibrary() == nullptr) { + report_->error(2141, "No liberty libraries found."); + } LibertyLibrary *library = makeTimingModel(lib_name, cell_name, filename, corner, this); writeLiberty(library, filename, this); From 2d11aa9c5ec29ec217a40fb39d90a3635325ed05 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Sun, 15 Dec 2024 18:16:22 -0800 Subject: [PATCH 4/5] dcalc use load slew changes to stop propagation Signed-off-by: James Cherry --- dcalc/GraphDelayCalc.cc | 77 +++++++++++++++++++++++++---------- graph/Graph.cc | 14 +++++++ include/sta/Graph.hh | 1 + include/sta/GraphClass.hh | 4 ++ include/sta/GraphDelayCalc.hh | 25 ++++++++---- 5 files changed, 90 insertions(+), 31 deletions(-) diff --git a/dcalc/GraphDelayCalc.cc b/dcalc/GraphDelayCalc.cc index 25405f34..a93ccd8f 100644 --- a/dcalc/GraphDelayCalc.cc +++ b/dcalc/GraphDelayCalc.cc @@ -579,13 +579,17 @@ GraphDelayCalc::findVertexDelay(Vertex *vertex, else { if (network_->isLeaf(pin)) { if (vertex->isDriver(network_)) { - bool delay_changed = findDriverDelays(vertex, arc_delay_calc); + LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(vertex); + DrvrLoadSlews prev_load_slews = loadSlews(load_pin_index_map); + findDriverDelays(vertex, arc_delay_calc, load_pin_index_map); if (propagate) { if (network_->direction(pin)->isInternal()) enqueueTimingChecksEdges(vertex); - // Enqueue adjacent vertices even if the delays did not + bool load_slews_changed = loadSlewsChanged(prev_load_slews, + load_pin_index_map); + // Enqueue adjacent vertices even if the load slews did not // change when non-incremental to stride past annotations. - if (delay_changed || !incremental_) + if (load_slews_changed || !incremental_) iter_->enqueueAdjacentVertices(vertex); } } @@ -605,6 +609,33 @@ GraphDelayCalc::findVertexDelay(Vertex *vertex, } } +DrvrLoadSlews +GraphDelayCalc::loadSlews(LoadPinIndexMap &load_pin_index_map) +{ + DrvrLoadSlews load_slews(load_pin_index_map.size()); + for (auto const [pin, index] : load_pin_index_map) { + Vertex *load_vertex = graph_->pinLoadVertex(pin); + load_slews[index] = graph_->slews(load_vertex); + } + return load_slews; +} + +bool +GraphDelayCalc::loadSlewsChanged(DrvrLoadSlews &prev_load_slews, + LoadPinIndexMap &load_pin_index_map) +{ + for (auto const [pin, index] : load_pin_index_map) { + Vertex *load_vertex = graph_->pinLoadVertex(pin); + const SlewSeq load_slews = graph_->slews(load_vertex); + const SlewSeq &prev_slews = prev_load_slews[index]; + for (size_t i = 0; i < load_slews.size(); i++) { + if (!delayEqual(load_slews[i], prev_slews[i])) + return true; + } + } + return false; +} + void GraphDelayCalc::enqueueTimingChecksEdges(Vertex *vertex) { @@ -639,21 +670,20 @@ GraphDelayCalc::enqueueTimingChecksEdges(Vertex *vertex) } } -bool +void GraphDelayCalc::findDriverDelays(Vertex *drvr_vertex, - ArcDelayCalc *arc_delay_calc) + ArcDelayCalc *arc_delay_calc, + LoadPinIndexMap &load_pin_index_map) { - bool delay_changed = false; MultiDrvrNet *multi_drvr = findMultiDrvrNet(drvr_vertex); if (multi_drvr == nullptr || (multi_drvr && (!multi_drvr->parallelGates(network_) || drvr_vertex == multi_drvr->dcalcDrvr()))) { initLoadSlews(drvr_vertex); - delay_changed |= findDriverDelays1(drvr_vertex, multi_drvr, arc_delay_calc); + findDriverDelays1(drvr_vertex, multi_drvr, arc_delay_calc, load_pin_index_map); } arc_delay_calc_->finishDrvrPin(); - return delay_changed; } MultiDrvrNet * @@ -782,7 +812,8 @@ GraphDelayCalc::initLoadSlews(Vertex *drvr_vertex) bool GraphDelayCalc::findDriverDelays1(Vertex *drvr_vertex, MultiDrvrNet *multi_drvr, - ArcDelayCalc *arc_delay_calc) + ArcDelayCalc *arc_delay_calc, + LoadPinIndexMap &load_pin_index_map) { initSlew(drvr_vertex); if (multi_drvr @@ -806,7 +837,8 @@ GraphDelayCalc::findDriverDelays1(Vertex *drvr_vertex, && search_pred_->searchThru(edge) && !edge->role()->isLatchDtoQ()) delay_changed |= findDriverEdgeDelays(drvr_vertex, multi_drvr, edge, - arc_delay_calc, delay_exists); + arc_delay_calc, load_pin_index_map, + delay_exists); } for (auto rf : RiseFall::range()) { if (!delay_exists[rf->index()]) @@ -841,10 +873,10 @@ GraphDelayCalc::findLatchEdgeDelays(Edge *edge) debugPrint(debug_, "delay_calc", 2, "find latch D->Q %s", sdc_network_->pathName(drvr_inst)); array delay_exists = {false, false}; - bool delay_changed = findDriverEdgeDelays(drvr_vertex, nullptr, edge, - arc_delay_calc_, delay_exists); - if (delay_changed && observer_) - observer_->delayChangedTo(drvr_vertex); + LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex); + findDriverEdgeDelays(drvr_vertex, nullptr, edge, + arc_delay_calc_, load_pin_index_map, + delay_exists); } bool @@ -852,17 +884,18 @@ GraphDelayCalc::findDriverEdgeDelays(Vertex *drvr_vertex, const MultiDrvrNet *multi_drvr, Edge *edge, ArcDelayCalc *arc_delay_calc, + LoadPinIndexMap &load_pin_index_map, + // Return value. array &delay_exists) { Vertex *from_vertex = edge->from(graph_); const TimingArcSet *arc_set = edge->timingArcSet(); bool delay_changed = false; - LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex); for (auto dcalc_ap : corners_->dcalcAnalysisPts()) { for (const TimingArc *arc : arc_set->arcs()) { delay_changed |= findDriverArcDelays(drvr_vertex, multi_drvr, edge, arc, - load_pin_index_map, dcalc_ap, - arc_delay_calc); + dcalc_ap, arc_delay_calc, + load_pin_index_map); delay_exists[arc->toEdge()->asRiseFall()->index()] = true; } } @@ -873,6 +906,7 @@ GraphDelayCalc::findDriverEdgeDelays(Vertex *drvr_vertex, return delay_changed; } +// External API. void GraphDelayCalc::findDriverArcDelays(Vertex *drvr_vertex, Edge *edge, @@ -882,9 +916,8 @@ GraphDelayCalc::findDriverArcDelays(Vertex *drvr_vertex, { MultiDrvrNet *multi_drvr = multiDrvrNet(drvr_vertex); LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex); - findDriverArcDelays(drvr_vertex, multi_drvr, edge, arc, - load_pin_index_map, dcalc_ap, - arc_delay_calc); + findDriverArcDelays(drvr_vertex, multi_drvr, edge, arc, dcalc_ap, + arc_delay_calc, load_pin_index_map); } bool @@ -892,9 +925,9 @@ GraphDelayCalc::findDriverArcDelays(Vertex *drvr_vertex, const MultiDrvrNet *multi_drvr, Edge *edge, const TimingArc *arc, - LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap, - ArcDelayCalc *arc_delay_calc) + ArcDelayCalc *arc_delay_calc, + LoadPinIndexMap &load_pin_index_map) { bool delay_changed = false; const RiseFall *from_rf = arc->fromEdge()->asRiseFall(); diff --git a/graph/Graph.cc b/graph/Graph.cc index 3db3e4da..c341434d 100644 --- a/graph/Graph.cc +++ b/graph/Graph.cc @@ -741,6 +741,20 @@ Graph::setSlew(Vertex *vertex, } } +SlewSeq +Graph::slews(Vertex *vertex) +{ + SlewSeq slews; + VertexId vertex_id = id(vertex); + DcalcAPIndex rf_ap_count = slew_rf_count_ * ap_count_; + for (DcalcAPIndex i = 0; i < rf_ap_count; i++) { + DelayTable *table = slew_tables_[i]; + Slew &slew = table->ref(vertex_id); + slews.push_back(slew); + } + return slews; +} + //////////////////////////////////////////////////////////////// Edge * diff --git a/include/sta/Graph.hh b/include/sta/Graph.hh index 3ac640f4..812fdbb7 100644 --- a/include/sta/Graph.hh +++ b/include/sta/Graph.hh @@ -130,6 +130,7 @@ public: const RiseFall *rf, DcalcAPIndex ap_index, const Slew &slew); + SlewSeq slews(Vertex *vertex); // Edge functions. virtual Edge *edge(EdgeId edge_index) const; diff --git a/include/sta/GraphClass.hh b/include/sta/GraphClass.hh index 834ee2aa..0cde7b59 100644 --- a/include/sta/GraphClass.hh +++ b/include/sta/GraphClass.hh @@ -23,9 +23,12 @@ #include "Vector.hh" #include "MinMax.hh" #include "Transition.hh" +#include "Delay.hh" namespace sta { +using std::vector; + // Class declarations for pointer references. class Graph; class Vertex; @@ -46,6 +49,7 @@ typedef int Level; typedef int DcalcAPIndex; typedef int TagGroupIndex; typedef Vector GraphLoopSeq; +typedef vector SlewSeq; static constexpr int level_max = std::numeric_limits::max(); diff --git a/include/sta/GraphDelayCalc.hh b/include/sta/GraphDelayCalc.hh index 1ed9bea3..e34a2f55 100644 --- a/include/sta/GraphDelayCalc.hh +++ b/include/sta/GraphDelayCalc.hh @@ -26,7 +26,6 @@ #include "SearchClass.hh" #include "DcalcAnalysisPt.hh" #include "StaState.hh" -#include "Delay.hh" #include "ArcDelayCalc.hh" namespace sta { @@ -41,6 +40,7 @@ class FindVertexDelays; class NetCaps; typedef Map MultiDrvrNetMap; +typedef vector DrvrLoadSlews; // This class traverses the graph calling the arc delay calculator and // annotating delays on graph edges. @@ -163,8 +163,9 @@ protected: const TimingArc *arc, float from_slew, const DcalcAnalysisPt *dcalc_ap); - bool findDriverDelays(Vertex *drvr_vertex, - ArcDelayCalc *arc_delay_calc); + void findDriverDelays(Vertex *drvr_vertex, + ArcDelayCalc *arc_delay_calc, + LoadPinIndexMap &load_pin_index_map); MultiDrvrNet *multiDrvrNet(const Vertex *drvr_vertex) const; MultiDrvrNet *findMultiDrvrNet(Vertex *drvr_pin); MultiDrvrNet *makeMultiDrvrNet(Vertex *drvr_vertex); @@ -172,20 +173,23 @@ protected: Vertex *firstLoad(Vertex *drvr_vertex); bool findDriverDelays1(Vertex *drvr_vertex, MultiDrvrNet *multi_drvr, - ArcDelayCalc *arc_delay_calc); + ArcDelayCalc *arc_delay_calc, + LoadPinIndexMap &load_pin_index_map); void initLoadSlews(Vertex *drvr_vertex); bool findDriverEdgeDelays(Vertex *drvr_vertex, - const MultiDrvrNet *multi_drvr, - Edge *edge, - ArcDelayCalc *arc_delay_calc, + const MultiDrvrNet *multi_drvr, + Edge *edge, + ArcDelayCalc *arc_delay_calc, + LoadPinIndexMap &load_pin_index_map, + // Return value. array &delay_exists); bool findDriverArcDelays(Vertex *drvr_vertex, const MultiDrvrNet *multi_drvr, Edge *edge, const TimingArc *arc, - LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap, - ArcDelayCalc *arc_delay_calc); + ArcDelayCalc *arc_delay_calc, + LoadPinIndexMap &load_pin_index_map); ArcDcalcArgSeq makeArcDcalcArgs(Vertex *drvr_vertex, const MultiDrvrNet *multi_drvr, Edge *edge, @@ -205,6 +209,9 @@ protected: void findVertexDelay(Vertex *vertex, ArcDelayCalc *arc_delay_calc, bool propagate); + DrvrLoadSlews loadSlews(LoadPinIndexMap &load_pin_index_map); + bool loadSlewsChanged(DrvrLoadSlews &prev_load_slews, + LoadPinIndexMap &load_pin_index_map); void enqueueTimingChecksEdges(Vertex *vertex); bool annotateDelaysSlews(Edge *edge, const TimingArc *arc, From fded1f247dd3b1d6db524a7eeda7f941160e33a3 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Sun, 15 Dec 2024 19:47:17 -0800 Subject: [PATCH 5/5] dcalc slew tolerance Signed-off-by: James Cherry --- dcalc/GraphDelayCalc.cc | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/dcalc/GraphDelayCalc.cc b/dcalc/GraphDelayCalc.cc index a93ccd8f..9b34acbe 100644 --- a/dcalc/GraphDelayCalc.cc +++ b/dcalc/GraphDelayCalc.cc @@ -629,7 +629,11 @@ GraphDelayCalc::loadSlewsChanged(DrvrLoadSlews &prev_load_slews, const SlewSeq load_slews = graph_->slews(load_vertex); const SlewSeq &prev_slews = prev_load_slews[index]; for (size_t i = 0; i < load_slews.size(); i++) { - if (!delayEqual(load_slews[i], prev_slews[i])) + const Slew &slew = delayAsFloat(load_slews[i]); + const Slew &prev_slew = delayAsFloat(prev_slews[i]); + if ((prev_slew == 0.0 && slew != 0.0) + || (prev_slew != 0.0 + && abs((slew - prev_slew) / prev_slew) > incremental_delay_tolerance_)) return true; } } @@ -874,9 +878,11 @@ GraphDelayCalc::findLatchEdgeDelays(Edge *edge) sdc_network_->pathName(drvr_inst)); array delay_exists = {false, false}; LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex); - findDriverEdgeDelays(drvr_vertex, nullptr, edge, - arc_delay_calc_, load_pin_index_map, - delay_exists); + bool delay_changed = findDriverEdgeDelays(drvr_vertex, nullptr, edge, + arc_delay_calc_, load_pin_index_map, + delay_exists); + if (delay_changed && observer_) + observer_->delayChangedTo(drvr_vertex); } bool