From 0fe167a80dd32c3fce0bc7f4c4cb85dc2a1eced1 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Mon, 15 Jun 2026 17:02:58 -0700 Subject: [PATCH] sta_internal_bidirect_instance_paths_enabled use load->driver edges Signed-off-by: James Cherry --- dcalc/GraphDelayCalc.cc | 15 +++++++-------- graph/Graph.cc | 14 ++++++++++++++ graph/Graph.i | 1 + include/sta/Graph.hh | 5 +++++ include/sta/Sta.hh | 2 -- include/sta/StaState.hh | 2 ++ search/Levelize.cc | 12 +++++++----- search/Search.cc | 21 ++++++++++++--------- search/SearchPred.cc | 1 + search/Sta.cc | 18 ++++++++---------- search/StaState.cc | 9 +++++++++ 11 files changed, 66 insertions(+), 34 deletions(-) diff --git a/dcalc/GraphDelayCalc.cc b/dcalc/GraphDelayCalc.cc index 3bf51343..c61ebfed 100644 --- a/dcalc/GraphDelayCalc.cc +++ b/dcalc/GraphDelayCalc.cc @@ -107,8 +107,7 @@ DcalcPred::searchThru(Edge *edge, || edge->isDisabledLoop() || sdc->isDisabledConstraint(edge) || sdc->isDisabledCondDefault(edge) - || (edge->isBidirectInstPath() - && !variables->bidirectInstPathsEnabled())); + || sta_->isDisabledBidirectInstPath(edge)); } bool @@ -1011,13 +1010,13 @@ GraphDelayCalc::findDriverEdgeDelays(Vertex *drvr_vertex, if (search_pred_->searchFrom(from_vertex, mode) && search_pred_->searchThru(edge, mode)) { for (const MinMax *min_max : MinMax::range()) { - for (const TimingArc *arc : arc_set->arcs()) { - delay_changed |= findDriverArcDelays(drvr_vertex, multi_drvr, edge, arc, + for (const TimingArc *arc : arc_set->arcs()) { + delay_changed |= findDriverArcDelays(drvr_vertex, multi_drvr, edge, arc, scene, min_max, arc_delay_calc, - load_pin_index_map); - delay_exists[arc->toEdge()->asRiseFall()->index()] = true; - } - } + load_pin_index_map); + delay_exists[arc->toEdge()->asRiseFall()->index()] = true; + } + } } } if (delay_changed && observer_) { diff --git a/graph/Graph.cc b/graph/Graph.cc index f19927ff..6c9d47e8 100644 --- a/graph/Graph.cc +++ b/graph/Graph.cc @@ -250,6 +250,13 @@ Graph::makeInstDrvrWireEdges(const Instance *inst, if (network_->isDriver(pin) && !visited_drvrs.contains(pin)) makeWireEdgesFromPin(pin, visited_drvrs); + if (network_->isTopInstance(inst) + && network_->direction(pin)->isBidirect()) { + Vertex *bidir_load, *bidir_drvr; + pinVertices(pin, bidir_load, bidir_drvr); + Edge *edge = makeEdge(bidir_load, bidir_drvr, TimingArcSet::wireTimingArcSet()); + edge->setIsBidirectPortPath(true); + } } delete pin_iter; } @@ -1211,6 +1218,7 @@ Edge::init(VertexId from, vertex_out_prev_ = edge_id_null; is_bidirect_inst_path_ = false; is_bidirect_net_path_ = false; + is_bidirect_port_path_ = false; arc_delays_ = nullptr; arc_delay_annotated_is_bits_ = true; @@ -1368,6 +1376,12 @@ Edge::setIsBidirectNetPath(bool is_bidir) is_bidirect_net_path_ = is_bidir; } +void +Edge::setIsBidirectPortPath(bool is_bidir) +{ + is_bidirect_port_path_ = is_bidir; +} + void Edge::setHasSimSense(bool has_sense) { diff --git a/graph/Graph.i b/graph/Graph.i index d6fb1769..9c41e431 100644 --- a/graph/Graph.i +++ b/graph/Graph.i @@ -128,6 +128,7 @@ remove_delay_slew_annotations() Pin *pin() { return self->pin(); } bool is_bidirect_driver() { return self->isBidirectDriver(); } int level() { return Sta::sta()->vertexLevel(self); } +bool is_root() { return self->isRoot(); } int tag_group_index() { return self->tagGroupIndex(); } float diff --git a/include/sta/Graph.hh b/include/sta/Graph.hh index 572d95a7..1f6e7ce2 100644 --- a/include/sta/Graph.hh +++ b/include/sta/Graph.hh @@ -364,6 +364,9 @@ public: void setIsBidirectInstPath(bool is_bidir); bool isBidirectNetPath() const { return is_bidirect_net_path_; } void setIsBidirectNetPath(bool is_bidir); + bool isBidirectPortPath() const { return is_bidirect_port_path_; } + void setIsBidirectPortPath(bool is_bidir); + void removeDelayAnnotated(); [[nodiscard]] bool hasSimSense() const { return has_sim_sense_; } void setHasSimSense(bool has_sense); @@ -403,6 +406,8 @@ protected: bool delay_annotation_is_incremental_:1; bool is_bidirect_inst_path_:1; bool is_bidirect_net_path_:1; + // Bidirect load -> driver edge. + bool is_bidirect_port_path_:1; bool is_disabled_loop_:1; bool has_sim_sense_:1; bool has_disabled_cond_:1; diff --git a/include/sta/Sta.hh b/include/sta/Sta.hh index 913608aa..4f0701ff 100644 --- a/include/sta/Sta.hh +++ b/include/sta/Sta.hh @@ -567,8 +567,6 @@ public: const Sdc *sdc); // Edge is disabled to break combinational loops. [[nodiscard]] bool isDisabledLoop(Edge *edge) const; - // Edge is disabled internal bidirect output path. - [[nodiscard]] bool isDisabledBidirectInstPath(Edge *edge) const; // Edge is disabled bidirect net path. [[nodiscard]] bool isDisabledBidirectNetPath(Edge *edge) const; [[nodiscard]] bool isDisabledPresetClr(Edge *edge) const; diff --git a/include/sta/StaState.hh b/include/sta/StaState.hh index c0da5998..d0062d7c 100644 --- a/include/sta/StaState.hh +++ b/include/sta/StaState.hh @@ -106,6 +106,8 @@ public: const Variables *variables() const { return variables_; } // Edge is default cond disabled by timing_disable_cond_default_arcs var. [[nodiscard]] bool isDisabledCondDefault(const Edge *edge) const; + // Edge is disabled internal bidirect output path. + [[nodiscard]] bool isDisabledBidirectInstPath(Edge *edge) const; const SceneSeq &scenes() { return scenes_; } const SceneSeq &scenes() const { return scenes_; } diff --git a/search/Levelize.cc b/search/Levelize.cc index f6deee0a..baacfdb3 100644 --- a/search/Levelize.cc +++ b/search/Levelize.cc @@ -196,11 +196,13 @@ bool Levelize::searchThru(Edge *edge) { const TimingRole *role = edge->role(); - return !role->isTimingCheck() && role != TimingRole::latchDtoQ() - && !edge->isDisabledLoop() - // Register/latch preset/clr edges are disabled by default. - && !(role == TimingRole::regSetClr() && !variables_->presetClrArcsEnabled()) - && !(edge->isBidirectInstPath() && !variables_->bidirectInstPathsEnabled()); + return !(role->isTimingCheck() + || role == TimingRole::latchDtoQ() + || edge->isDisabledLoop() + // Register/latch preset/clr edges are disabled by default. + || (role == TimingRole::regSetClr() + && !variables_->presetClrArcsEnabled()) + || isDisabledBidirectInstPath(edge)); } bool diff --git a/search/Search.cc b/search/Search.cc index 7868108d..8e78f358 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -184,13 +184,14 @@ SearchAdj::searchThru(Edge *edge, { const TimingRole *role = edge->role(); const Variables *variables = sta_->variables(); - return !role->isTimingCheck() - && !role->isLatchDtoQ() - // Register/latch preset/clr edges are disabled by default. - && !(role == TimingRole::regSetClr() && !variables->presetClrArcsEnabled()) - && !(edge->isBidirectInstPath() && !variables->bidirectInstPathsEnabled()) - && (!edge->isDisabledLoop() - || (variables->dynamicLoopBreaking() && hasPendingLoopPaths(edge))); + return !(role->isTimingCheck() + || role->isLatchDtoQ() + // Register/latch preset/clr edges are disabled by default. + || (role == TimingRole::regSetClr() + && !variables->presetClrArcsEnabled()) + || sta_->isDisabledBidirectInstPath(edge) + || (edge->isDisabledLoop() + && !(variables->dynamicLoopBreaking() && hasPendingLoopPaths(edge)))); } bool @@ -3228,8 +3229,10 @@ Search::isEndpoint(Vertex *vertex, const Pin *pin = vertex->pin(); const Sdc *sdc = mode->sdc(); return hasFanin(vertex, pred, graph_, mode) - && ((vertex->hasChecks() && hasEnabledChecks(vertex, mode)) - || sdc->isConstrainedEnd(pin) || !hasFanout(vertex, pred, graph_, mode) + && ((vertex->hasChecks() + && hasEnabledChecks(vertex, mode)) + || sdc->isConstrainedEnd(pin) + || !hasFanout(vertex, pred, graph_, mode) || sdc->isPathDelayInternalTo(pin) // Unconstrained paths at register clk pins. || (unconstrained_paths_ && vertex->isRegClk()) diff --git a/search/SearchPred.cc b/search/SearchPred.cc index 77279374..4a0a8304 100644 --- a/search/SearchPred.cc +++ b/search/SearchPred.cc @@ -184,6 +184,7 @@ ClkTreeSearchPred::searchThru(Edge *edge, || sdc->isDisabledConstraint(edge) || sdc->isDisabledCondDefault(edge) || edge->isBidirectInstPath() + || edge->isBidirectPortPath() || edge->isDisabledLoop()); } diff --git a/search/Sta.cc b/search/Sta.cc index 75d3d730..87a3f7d1 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -1702,8 +1702,10 @@ Sta::disabledEdges(const Mode *mode) VertexOutEdgeIterator edge_iter(vertex, graph_); while (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); - if (isDisabledConstant(edge, mode) || isDisabledCondDefault(edge) - || isDisabledConstraint(edge, sdc) || edge->isDisabledLoop() + if (isDisabledConstant(edge, mode) + || isDisabledCondDefault(edge) + || isDisabledConstraint(edge, sdc) + || edge->isDisabledLoop() || isDisabledPresetClr(edge)) disabled_edges.push_back(edge); } @@ -1841,12 +1843,6 @@ Sta::exprConstantPins(FuncExpr *expr, } } -bool -Sta::isDisabledBidirectInstPath(Edge *edge) const -{ - return !variables_->bidirectInstPathsEnabled() && edge->isBidirectInstPath(); -} - bool Sta::isDisabledPresetClr(Edge *edge) const { @@ -5217,8 +5213,10 @@ FanInOutSrchPred::searchThru(Edge *edge, const Sim *sim = mode->sim(); return searchThruRole(edge) && (thru_disabled_ - || !(sdc->isDisabledConstraint(edge) || sim->isDisabledCond(edge) - || sta_->isDisabledCondDefault(edge))) + || !(sdc->isDisabledConstraint(edge) + || sim->isDisabledCond(edge) + || sta_->isDisabledCondDefault(edge) + || sta_->isDisabledBidirectInstPath(edge))) && (thru_constants_ || sim->simTimingSense(edge) != TimingSense::none); } diff --git a/search/StaState.cc b/search/StaState.cc index ea673b38..95d33060 100644 --- a/search/StaState.cc +++ b/search/StaState.cc @@ -31,6 +31,7 @@ #include "Graph.hh" #include "Mode.hh" #include "Network.hh" +#include "PortDirection.hh" #include "Scene.hh" #include "Sdc.hh" #include "TimingArc.hh" @@ -124,6 +125,14 @@ StaState::isDisabledCondDefault(const Edge *edge) const && edge->timingArcSet()->isCondDefault(); } +bool +StaState::isDisabledBidirectInstPath(Edge *edge) const +{ + return (edge->isBidirectInstPath() + || edge->isBidirectPortPath()) + && !variables_->bidirectInstPathsEnabled(); +} + //////////////////////////////////////////////////////////////// size_t