From 65cb29123304880a6aeacfa2c3f93792ac9aed0e Mon Sep 17 00:00:00 2001 From: James Cherry Date: Thu, 4 Nov 2021 10:30:23 -0700 Subject: [PATCH] latch dcalc with threads Signed-off-by: James Cherry --- dcalc/GraphDelayCalc1.cc | 159 +++++++++++++++++++++++++------------- dcalc/GraphDelayCalc1.hh | 13 ++-- include/sta/TimingRole.hh | 1 + liberty/TimingRole.cc | 6 ++ 4 files changed, 119 insertions(+), 60 deletions(-) diff --git a/dcalc/GraphDelayCalc1.cc b/dcalc/GraphDelayCalc1.cc index b33c06cf..5926103e 100644 --- a/dcalc/GraphDelayCalc1.cc +++ b/dcalc/GraphDelayCalc1.cc @@ -294,14 +294,14 @@ GraphDelayCalc1::delaysInvalid() iter_->clear(); // No need to keep track of incremental updates any more. invalid_delays_.clear(); - invalid_checks_.clear(); + invalid_check_edges_.clear(); + invalid_latch_edges_.clear(); } void GraphDelayCalc1::delayInvalid(const Pin *pin) { - if (graph_ - && incremental_) { + if (graph_ && incremental_) { if (network_->isHierarchical(pin)) { EdgesThruHierPinIterator edge_iter(pin, network_, graph_); while (edge_iter.hasNext()) { @@ -421,9 +421,13 @@ GraphDelayCalc1::findDelays(Level level) // Timing checks require slews at both ends of the arc, // so find their delays after all slews are known. - for (Vertex *check_vertex : invalid_checks_) - findCheckDelays(check_vertex, arc_delay_calc_); - invalid_checks_.clear(); + for (Edge *check_edge : invalid_check_edges_) + findCheckEdgeDelays(check_edge, arc_delay_calc_); + invalid_check_edges_.clear(); + + for (Edge *latch_edge : invalid_latch_edges_) + findLatchEdgeDelays(latch_edge); + invalid_latch_edges_.clear(); delays_exist_ = true; incremental_ = true; @@ -880,10 +884,34 @@ GraphDelayCalc1::findVertexDelay(Vertex *vertex, void GraphDelayCalc1::enqueueTimingChecksEdges(Vertex *vertex) { - if (vertex->hasChecks() - || vertex->isCheckClk()) { - UniqueLock lock(check_vertices_lock_); - invalid_checks_.insert(vertex); + if (vertex->hasChecks()) { + VertexInEdgeIterator edge_iter(vertex, graph_); + UniqueLock lock(invalid_edge_lock_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + if (edge->role()->isTimingCheck()) + invalid_check_edges_.insert(edge); + } + } + if (vertex->isCheckClk()) { + VertexOutEdgeIterator edge_iter(vertex, graph_); + UniqueLock lock(invalid_edge_lock_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + if (edge->role()->isTimingCheck()) + invalid_check_edges_.insert(edge); + } + } + if (network_->isLatchData(vertex->pin())) { + // Latch D->Q arcs have to be re-evaled if level(D) > level(E) + // because levelization does not traverse D->Q arcs to break loops. + VertexOutEdgeIterator edge_iter(vertex, graph_); + UniqueLock lock(invalid_edge_lock_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + if (edge->role() == TimingRole::latchDtoQ()) + invalid_latch_edges_.insert(edge); + } } } @@ -926,17 +954,23 @@ GraphDelayCalc1::findDriverDelays1(Vertex *drvr_vertex, initSlew(drvr_vertex); initWireDelays(drvr_vertex, init_load_slews); bool delay_changed = false; + bool has_delays = false; VertexInEdgeIterator edge_iter(drvr_vertex, graph_); while (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); Vertex *from_vertex = edge->from(graph_); // Don't let disabled edges set slews that influence downstream delays. if (search_pred_->searchFrom(from_vertex) - && search_pred_->searchThru(edge)) + && search_pred_->searchThru(edge) + && !edge->role()->isLatchDtoQ()) { delay_changed |= findDriverEdgeDelays(drvr_cell, drvr_inst, drvr_pin, drvr_vertex, multi_drvr, edge, arc_delay_calc); + has_delays = true; + } } + if (!has_delays) + zeroSlewAndWireDelays(drvr_vertex); if (delay_changed && observer_) observer_->delayChangedTo(drvr_vertex); return delay_changed; @@ -957,6 +991,21 @@ GraphDelayCalc1::initRootSlews(Vertex *vertex) } } +void +GraphDelayCalc1::findLatchEdgeDelays(Edge *edge) +{ + Vertex *drvr_vertex = edge->to(graph_); + const Pin *drvr_pin = drvr_vertex->pin(); + Instance *drvr_inst = network_->instance(drvr_pin); + LibertyCell *drvr_cell = network_->libertyCell(drvr_inst); + debugPrint(debug_, "delay_calc", 2, "find latch D->Q %s", + sdc_network_->pathName(drvr_inst)); + bool delay_changed = findDriverEdgeDelays(drvr_cell, drvr_inst, drvr_pin, + drvr_vertex, nullptr, edge, arc_delay_calc_); + if (delay_changed && observer_) + observer_->delayChangedTo(drvr_vertex); +} + bool GraphDelayCalc1::findDriverEdgeDelays(LibertyCell *drvr_cell, Instance *drvr_inst, @@ -1146,6 +1195,36 @@ GraphDelayCalc1::initSlew(Vertex *vertex) } } +void +GraphDelayCalc1::zeroSlewAndWireDelays(Vertex *drvr_vertex) +{ + for (auto dcalc_ap : corners_->dcalcAnalysisPts()) { + DcalcAPIndex ap_index = dcalc_ap->index(); + const MinMax *slew_min_max = dcalc_ap->slewMinMax(); + for (auto tr : RiseFall::range()) { + // Init drvr slew. + if (!drvr_vertex->slewAnnotated(tr, slew_min_max)) { + DcalcAPIndex ap_index = dcalc_ap->index(); + graph_->setSlew(drvr_vertex, tr, ap_index, slew_min_max->initValue()); + } + + // Init wire delays and slews. + VertexOutEdgeIterator edge_iter(drvr_vertex, graph_); + while (edge_iter.hasNext()) { + Edge *wire_edge = edge_iter.next(); + if (wire_edge->isWire()) { + Vertex *load_vertex = wire_edge->to(graph_); + if (!graph_->wireDelayAnnotated(wire_edge, tr, ap_index)) + graph_->setWireArcDelay(wire_edge, tr, ap_index, 0.0); + // Init load vertex slew. + if (!load_vertex->slewAnnotated(tr, slew_min_max)) + graph_->setSlew(load_vertex, tr, ap_index, 0.0); + } + } + } + } +} + // Init wire delays and load slews. void GraphDelayCalc1::initWireDelays(Vertex *drvr_vertex, @@ -1162,13 +1241,13 @@ GraphDelayCalc1::initWireDelays(Vertex *drvr_vertex, Delay delay_init_value(delay_min_max->initValue()); Slew slew_init_value(slew_min_max->initValue()); DcalcAPIndex ap_index = dcalc_ap->index(); - for (auto tr : RiseFall::range()) { - if (!graph_->wireDelayAnnotated(wire_edge, tr, ap_index)) - graph_->setWireArcDelay(wire_edge, tr, ap_index, delay_init_value); + for (auto rf : RiseFall::range()) { + if (!graph_->wireDelayAnnotated(wire_edge, rf, ap_index)) + graph_->setWireArcDelay(wire_edge, rf, ap_index, delay_init_value); // Init load vertex slew. if (init_load_slews - && !load_vertex->slewAnnotated(tr, slew_min_max)) - graph_->setSlew(load_vertex, tr, ap_index, slew_init_value); + && !load_vertex->slewAnnotated(rf, slew_min_max)) + graph_->setSlew(load_vertex, rf, ap_index, slew_init_value); } } } @@ -1235,7 +1314,8 @@ GraphDelayCalc1::findArcDelay(LibertyCell *drvr_cell, const Slew &drvr_slew = graph_->slew(drvr_vertex, drvr_rf, ap_index); const MinMax *slew_min_max = dcalc_ap->slewMinMax(); if (delayGreater(gate_slew, drvr_slew, dcalc_ap->slewMinMax(), this) - && !drvr_vertex->slewAnnotated(drvr_rf, slew_min_max)) + && !drvr_vertex->slewAnnotated(drvr_rf, slew_min_max) + && !edge->role()->isLatchDtoQ()) graph_->setSlew(drvr_vertex, drvr_rf, ap_index, gate_slew); if (!graph_->arcDelayAnnotated(edge, arc, ap_index)) { const ArcDelay &prev_gate_delay = graph_->arcDelay(edge,arc,ap_index); @@ -1247,8 +1327,9 @@ GraphDelayCalc1::findArcDelay(LibertyCell *drvr_cell, delay_changed = true; graph_->setArcDelay(edge, arc, ap_index, gate_delay); } - annotateLoadDelays(drvr_vertex, drvr_rf, delay_zero, true, dcalc_ap, - arc_delay_calc); + if (!edge->role()->isLatchDtoQ()) + annotateLoadDelays(drvr_vertex, drvr_rf, delay_zero, true, dcalc_ap, + arc_delay_calc); } return delay_changed; } @@ -1445,42 +1526,6 @@ GraphDelayCalc1::annotateLoadDelays(Vertex *drvr_vertex, } } -void -GraphDelayCalc1::findCheckDelays(Vertex *vertex, - ArcDelayCalc *arc_delay_calc) -{ - debugPrint(debug_, "delay_calc", 2, "find checks %s (%s)", - vertex->name(sdc_network_), - network_->cellName(network_->instance(vertex->pin()))); - if (vertex->hasChecks()) { - VertexInEdgeIterator edge_iter(vertex, graph_); - while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - if (edge->role()->isTimingCheck()) - findCheckEdgeDelays(edge, arc_delay_calc); - } - if (network_->isLatchData(vertex->pin())) { - // Latch D->Q arcs have to be re-evaled if level(D) > level(E) - // because levelization does not traverse D->Q arcs to break loops. - VertexOutEdgeIterator edge_iter(vertex, graph_); - while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - Vertex *to_vertex = edge->to(graph_); - if (edge->role() == TimingRole::latchDtoQ()) - findVertexDelay(to_vertex, arc_delay_calc_, false); - } - } - } - if (vertex->isCheckClk()) { - VertexOutEdgeIterator edge_iter(vertex, graph_); - while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - if (edge->role()->isTimingCheck()) - findCheckEdgeDelays(edge, arc_delay_calc); - } - } -} - void GraphDelayCalc1::findCheckEdgeDelays(Edge *edge, ArcDelayCalc *arc_delay_calc) @@ -1491,6 +1536,10 @@ GraphDelayCalc1::findCheckEdgeDelays(Edge *edge, const Pin *to_pin = to_vertex->pin(); Instance *inst = network_->instance(to_pin); const LibertyCell *cell = network_->libertyCell(inst); + debugPrint(debug_, "delay_calc", 2, "find check %s %s -> %s", + sdc_network_->pathName(inst), + network_->portName(from_vertex->pin()), + network_->portName(to_pin)); bool delay_changed = false; TimingArcSetArcIterator arc_iter(arc_set); while (arc_iter.hasNext()) { diff --git a/dcalc/GraphDelayCalc1.hh b/dcalc/GraphDelayCalc1.hh index c95b9de2..e3da6db8 100644 --- a/dcalc/GraphDelayCalc1.hh +++ b/dcalc/GraphDelayCalc1.hh @@ -138,6 +138,7 @@ protected: void initWireDelays(Vertex *drvr_vertex, bool init_load_slews); void initRootSlews(Vertex *vertex); + void zeroSlewAndWireDelays(Vertex *drvr_vertex); void findVertexDelay(Vertex *vertex, ArcDelayCalc *arc_delay_calc, bool propagate); @@ -160,8 +161,7 @@ protected: bool merge, const DcalcAnalysisPt *dcalc_ap, ArcDelayCalc *arc_delay_calc); - void findCheckDelays(Vertex *vertex, - ArcDelayCalc *arc_delay_calc); + void findLatchEdgeDelays(Edge *edge); void findCheckEdgeDelays(Edge *edge, ArcDelayCalc *arc_delay_calc); void findMultiDrvrGateDelay(MultiDrvrNet *multi_drvr, @@ -213,9 +213,12 @@ protected: bool delays_exist_; // Vertices with invalid -to delays. VertexSet invalid_delays_; - // Vertices with invalid -from/-to timing checks. - VertexSet invalid_checks_; - std::mutex check_vertices_lock_; + // Timing check edges with invalid delays. + EdgeSet invalid_check_edges_; + // Latch D->Q edges with invalid delays. + EdgeSet invalid_latch_edges_; + // shared by invalid_check_edges_ and invalid_latch_edges_ + std::mutex invalid_edge_lock_; SearchPred *search_pred_; SearchPred *search_non_latch_pred_; SearchPred *clk_pred_; diff --git a/include/sta/TimingRole.hh b/include/sta/TimingRole.hh index 720c51c1..3a7781be 100644 --- a/include/sta/TimingRole.hh +++ b/include/sta/TimingRole.hh @@ -67,6 +67,7 @@ public: bool isAsyncTimingCheck() const; bool isNonSeqTimingCheck() const { return is_non_seq_check_; } bool isDataCheck() const; + bool isLatchDtoQ() const; const TimingRole *genericRole() const; const TimingRole *sdfRole() const; // Timing check data path min/max. diff --git a/liberty/TimingRole.cc b/liberty/TimingRole.cc index cb89bb16..5fc87d82 100644 --- a/liberty/TimingRole.cc +++ b/liberty/TimingRole.cc @@ -241,6 +241,12 @@ TimingRole::isDataCheck() const || this == data_check_hold_; } +bool +TimingRole::isLatchDtoQ() const +{ + return this == latch_d_q_; +} + bool TimingRole::less(const TimingRole *role1, const TimingRole *role2)