From 042f1f84d108e4f1396f3c5e993556c159e85c21 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Sat, 11 Nov 2023 12:33:55 -0700 Subject: [PATCH] rm GraphDelayCalc1 Signed-off-by: James Cherry --- CMakeLists.txt | 1 - dcalc/GraphDelayCalc.cc | 1697 +++++++++++++++++++++++++++++++-- dcalc/GraphDelayCalc1.cc | 1690 -------------------------------- dcalc/GraphDelayCalc1.hh | 236 ----- include/sta/GraphDelayCalc.hh | 225 ++++- include/sta/SearchClass.hh | 2 + search/MakeTimingModel.cc | 2 +- search/Sta.cc | 4 +- 8 files changed, 1828 insertions(+), 2029 deletions(-) delete mode 100644 dcalc/GraphDelayCalc1.cc delete mode 100644 dcalc/GraphDelayCalc1.hh diff --git a/CMakeLists.txt b/CMakeLists.txt index 9900ea38..2c2f1615 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,7 +69,6 @@ set(STA_SOURCE dcalc/DmpCeff.cc dcalc/DmpDelayCalc.cc dcalc/GraphDelayCalc.cc - dcalc/GraphDelayCalc1.cc dcalc/LumpedCapDelayCalc.cc dcalc/NetCaps.cc dcalc/RCDelayCalc.cc diff --git a/dcalc/GraphDelayCalc.cc b/dcalc/GraphDelayCalc.cc index d559e29d..3af4a330 100644 --- a/dcalc/GraphDelayCalc.cc +++ b/dcalc/GraphDelayCalc.cc @@ -16,100 +16,1677 @@ #include "GraphDelayCalc.hh" +#include "Debug.hh" +#include "Stats.hh" +#include "MinMax.hh" +#include "Mutex.hh" +#include "TimingRole.hh" +#include "TimingArc.hh" #include "Liberty.hh" +#include "PortDirection.hh" #include "Network.hh" -#include "Graph.hh" +#include "InputDrive.hh" #include "Sdc.hh" +#include "Graph.hh" +#include "Parasitics.hh" +#include "search/Levelize.hh" #include "Corner.hh" +#include "SearchPred.hh" +#include "Bfs.hh" +#include "ArcDelayCalc.hh" +#include "DcalcAnalysisPt.hh" +#include "NetCaps.hh" +#include "ClkNetwork.hh" namespace sta { -GraphDelayCalc::GraphDelayCalc(StaState *sta) : - StaState(sta) +using std::abs; + +static const Slew default_slew = 0.0; + +typedef Set MultiDrvrNetSet; + +static bool +isLeafDriver(const Pin *pin, + const Network *network); + +// Cache parallel delay/slew values for nets with multiple drivers. +class MultiDrvrNet { +public: + MultiDrvrNet(VertexSet *drvrs); + ~MultiDrvrNet(); + const VertexSet *drvrs() const { return drvrs_; } + VertexSet *drvrs() { return drvrs_; } + Vertex *dcalcDrvr() const { return dcalc_drvr_; } + void setDcalcDrvr(Vertex *drvr); + void parallelDelaySlew(const RiseFall *drvr_rf, + const DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc, + GraphDelayCalc *dcalc, + // Return values. + ArcDelay ¶llel_delay, + Slew ¶llel_slew); + void netCaps(const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap, + // Return values. + float &pin_cap, + float &wire_cap, + float &fanout, + bool &has_net_load); + void findCaps(const GraphDelayCalc *dcalc, + const Sdc *sdc); + +private: + void findDelaysSlews(ArcDelayCalc *arc_delay_calc, + GraphDelayCalc *dcalc); + + // Driver that triggers delay calculation for all the drivers on the net. + Vertex *dcalc_drvr_; + VertexSet *drvrs_; + // [drvr_rf->index][dcalc_ap->index] + ArcDelay *parallel_delays_; + // [drvr_rf->index][dcalc_ap->index] + Slew *parallel_slews_; + // [drvr_rf->index][dcalc_ap->index] + NetCaps *net_caps_; + bool delays_valid_:1; +}; + +MultiDrvrNet::MultiDrvrNet(VertexSet *drvrs) : + dcalc_drvr_(nullptr), + drvrs_(drvrs), + parallel_delays_(nullptr), + parallel_slews_(nullptr), + net_caps_(nullptr), + delays_valid_(false) +{ +} + +MultiDrvrNet::~MultiDrvrNet() +{ + delete drvrs_; + if (delays_valid_) { + delete [] parallel_delays_; + delete [] parallel_slews_; + } + delete [] net_caps_; } void -GraphDelayCalc::setObserver(DelayCalcObserver *observer) +MultiDrvrNet::parallelDelaySlew(const RiseFall *drvr_rf, + const DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc, + GraphDelayCalc *dcalc, + // Return values. + ArcDelay ¶llel_delay, + Slew ¶llel_slew) { - // Observer not needed by GraphDelayCalc. - delete observer; + if (!delays_valid_) { + findDelaysSlews(arc_delay_calc, dcalc); + delays_valid_ = true; + } + + int index = dcalc_ap->index() * RiseFall::index_count + + drvr_rf->index(); + parallel_delay = parallel_delays_[index]; + parallel_slew = parallel_slews_[index]; } -string -GraphDelayCalc::reportDelayCalc(Edge *, - TimingArc *, - const Corner *, - const MinMax *, - int) +void +MultiDrvrNet::findDelaysSlews(ArcDelayCalc *arc_delay_calc, + GraphDelayCalc *dcalc) { - return ""; + Corners *corners = dcalc->corners(); + int count = RiseFall::index_count * corners->dcalcAnalysisPtCount(); + parallel_delays_ = new ArcDelay[count]; + parallel_slews_ = new Slew[count]; + for (auto dcalc_ap : corners->dcalcAnalysisPts()) { + DcalcAPIndex ap_index = dcalc_ap->index(); + const Pvt *pvt = dcalc_ap->operatingConditions(); + for (auto drvr_rf : RiseFall::range()) { + int drvr_rf_index = drvr_rf->index(); + int index = ap_index*RiseFall::index_count+drvr_rf_index; + dcalc->findMultiDrvrGateDelay(this, drvr_rf, pvt, dcalc_ap, + arc_delay_calc, + parallel_delays_[index], + parallel_slews_[index]); + } + } +} + +void +MultiDrvrNet::netCaps(const RiseFall *drvr_rf, + const DcalcAnalysisPt *dcalc_ap, + // Return values. + float &pin_cap, + float &wire_cap, + float &fanout, + bool &has_net_load) +{ + int index = dcalc_ap->index() * RiseFall::index_count + + drvr_rf->index(); + NetCaps &net_caps = net_caps_[index]; + pin_cap = net_caps.pinCap(); + wire_cap = net_caps.wireCap(); + fanout = net_caps.fanout(); + has_net_load = net_caps.hasNetLoad(); +} + +void +MultiDrvrNet::findCaps(const GraphDelayCalc *dcalc, + const Sdc *sdc) +{ + Corners *corners = dcalc->corners(); + int count = RiseFall::index_count * corners->dcalcAnalysisPtCount(); + net_caps_ = new NetCaps[count]; + const Pin *drvr_pin = dcalc_drvr_->pin(); + for (auto dcalc_ap : corners->dcalcAnalysisPts()) { + DcalcAPIndex ap_index = dcalc_ap->index(); + const Corner *corner = dcalc_ap->corner(); + const OperatingConditions *op_cond = dcalc_ap->operatingConditions(); + const MinMax *min_max = dcalc_ap->constraintMinMax(); + for (auto drvr_rf : RiseFall::range()) { + int drvr_rf_index = drvr_rf->index(); + int index = ap_index * RiseFall::index_count + drvr_rf_index; + NetCaps &net_caps = net_caps_[index]; + float pin_cap, wire_cap, fanout; + bool has_net_load; + // Find pin and external pin/wire capacitance. + sdc->connectedCap(drvr_pin, drvr_rf, op_cond, corner, min_max, + pin_cap, wire_cap, fanout, has_net_load); + net_caps.init(pin_cap, wire_cap, fanout, has_net_load); + } + } +} + +void +MultiDrvrNet::setDcalcDrvr(Vertex *drvr) +{ + dcalc_drvr_ = drvr; +} + +//////////////////////////////////////////////////////////////// + +GraphDelayCalc::GraphDelayCalc(StaState *sta) : + StaState(sta), + observer_(nullptr), + delays_seeded_(false), + incremental_(false), + delays_exist_(false), + invalid_delays_(new VertexSet(graph_)), + search_pred_(new SearchPred1(sta)), + search_non_latch_pred_(new SearchPredNonLatch2(sta)), + clk_pred_(new ClkTreeSearchPred(sta)), + iter_(new BfsFwdIterator(BfsIndex::dcalc, search_non_latch_pred_, sta)), + multi_drvr_nets_found_(false), + incremental_delay_tolerance_(0.0) +{ +} + +GraphDelayCalc::~GraphDelayCalc() +{ + delete search_pred_; + delete invalid_delays_; + delete search_non_latch_pred_; + delete clk_pred_; + delete iter_; + deleteMultiDrvrNets(); + delete observer_; +} + +void +GraphDelayCalc::deleteMultiDrvrNets() +{ + MultiDrvrNetSet drvr_nets; + MultiDrvrNetMap::Iterator multi_iter(multi_drvr_net_map_); + while (multi_iter.hasNext()) { + MultiDrvrNet *multi_drvr = multi_iter.next(); + // Multiple drvr pins point to the same drvr PinSet, + // so collect them into a set. + drvr_nets.insert(multi_drvr); + } + multi_drvr_net_map_.clear(); + drvr_nets.deleteContents(); +} + +void +GraphDelayCalc::copyState(const StaState *sta) +{ + StaState::copyState(sta); + // Notify sub-components. + iter_->copyState(sta); +} + +void +GraphDelayCalc::clear() +{ + delaysInvalid(); + deleteMultiDrvrNets(); + multi_drvr_nets_found_ = false; } float GraphDelayCalc::incrementalDelayTolerance() { - return 0.0; + return incremental_delay_tolerance_; } void -GraphDelayCalc::loadCap(const Pin *, - const Parasitic *, - const RiseFall *, - const DcalcAnalysisPt *, - // Return values. - float &pin_cap, - float &wire_cap) const +GraphDelayCalc::setIncrementalDelayTolerance(float tol) { - pin_cap = wire_cap = 0.0F; -} - -float -GraphDelayCalc::loadCap(const Pin *, - const RiseFall *, - const DcalcAnalysisPt *) const -{ - return 0.0F; -} - -float -GraphDelayCalc::loadCap(const Pin *, - const Parasitic *, - const RiseFall *, - const DcalcAnalysisPt *) const -{ - return 0.0F; -} - -float -GraphDelayCalc::loadCap(const Pin *, - const DcalcAnalysisPt *) const -{ - return 0.0F; + incremental_delay_tolerance_ = tol; } void -GraphDelayCalc::netCaps(const Pin *, - const RiseFall *, - const DcalcAnalysisPt *, - // Return values. - float &pin_cap, - float &wire_cap, - float &fanout, - bool &has_set_load) const +GraphDelayCalc::setObserver(DelayCalcObserver *observer) { - pin_cap = wire_cap = fanout = 0.0F; - has_set_load = false; + delete observer_; + observer_ = observer; +} + +void +GraphDelayCalc::delaysInvalid() +{ + debugPrint(debug_, "delay_calc", 1, "delays invalid"); + delays_exist_ = false; + delays_seeded_ = false; + incremental_ = false; + iter_->clear(); + // No need to keep track of incremental updates any more. + invalid_delays_->clear(); + invalid_check_edges_.clear(); + invalid_latch_edges_.clear(); +} + +void +GraphDelayCalc::delayInvalid(const Pin *pin) +{ + if (graph_ && incremental_) { + if (network_->isHierarchical(pin)) { + EdgesThruHierPinIterator edge_iter(pin, network_, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + delayInvalid(edge->from(graph_)); + } + } + else { + Vertex *vertex, *bidirect_drvr_vertex; + graph_->pinVertices(pin, vertex, bidirect_drvr_vertex); + if (vertex) + delayInvalid(vertex); + if (bidirect_drvr_vertex) + delayInvalid(bidirect_drvr_vertex); + } + } +} + +void +GraphDelayCalc::delayInvalid(Vertex *vertex) +{ + debugPrint(debug_, "delay_calc", 2, "delay invalid %s", + vertex->name(sdc_network_)); + if (graph_ && incremental_) { + invalid_delays_->insert(vertex); + // Invalidate driver that triggers dcalc for multi-driver nets. + MultiDrvrNet *multi_drvr = multiDrvrNet(vertex); + if (multi_drvr) + invalid_delays_->insert(multi_drvr->dcalcDrvr()); + } +} + +void +GraphDelayCalc::deleteVertexBefore(Vertex *vertex) +{ + iter_->deleteVertexBefore(vertex); + if (incremental_) + invalid_delays_->erase(vertex); + MultiDrvrNet *multi_drvr = multiDrvrNet(vertex); + if (multi_drvr) { + multi_drvr->drvrs()->erase(vertex); + multi_drvr_net_map_.erase(vertex); + } +} + +//////////////////////////////////////////////////////////////// + +class FindVertexDelays : public VertexVisitor +{ +public: + FindVertexDelays(GraphDelayCalc *graph_delay_calc1); + virtual ~FindVertexDelays(); + virtual void visit(Vertex *vertex); + virtual VertexVisitor *copy() const; + +protected: + GraphDelayCalc *graph_delay_calc1_; + ArcDelayCalc *arc_delay_calc_; +}; + +FindVertexDelays::FindVertexDelays(GraphDelayCalc *graph_delay_calc1) : + VertexVisitor(), + graph_delay_calc1_(graph_delay_calc1), + arc_delay_calc_(graph_delay_calc1_->arc_delay_calc_->copy()) +{ +} + +FindVertexDelays::~FindVertexDelays() +{ + delete arc_delay_calc_; +} + +VertexVisitor * +FindVertexDelays::copy() const +{ + // Copy StaState::arc_delay_calc_ because it needs separate state + // for each thread. + return new FindVertexDelays(graph_delay_calc1_); +} + +void +FindVertexDelays::visit(Vertex *vertex) +{ + graph_delay_calc1_->findVertexDelay(vertex, arc_delay_calc_, true); +} + +// The logical structure of incremental delay calculation closely +// resembles the incremental search arrival time algorithm +// (Search::findArrivals). +void +GraphDelayCalc::findDelays(Level level) +{ + if (arc_delay_calc_) { + Stats stats(debug_, report_); + int dcalc_count = 0; + debugPrint(debug_, "delay_calc", 1, "find delays to level %d", level); + if (!delays_seeded_) { + iter_->clear(); + ensureMultiDrvrNetsFound(); + seedRootSlews(); + delays_seeded_ = true; + } + else + iter_->ensureSize(); + if (incremental_) + seedInvalidDelays(); + + FindVertexDelays visitor(this); + dcalc_count += iter_->visitParallel(level, &visitor); + + // Timing checks require slews at both ends of the arc, + // so find their delays after all slews are known. + 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; + debugPrint(debug_, "delay_calc", 1, "found %d delays", dcalc_count); + stats.report("Delay calc"); + } +} + +void +GraphDelayCalc::seedInvalidDelays() +{ + for (Vertex *vertex : *invalid_delays_) { + if (vertex->isRoot()) + seedRootSlew(vertex, arc_delay_calc_); + else { + if (search_non_latch_pred_->searchFrom(vertex)) + iter_->enqueue(vertex); + } + } + invalid_delays_->clear(); +} + +class FindNetDrvrs : public PinVisitor +{ +public: + FindNetDrvrs(PinSet &drvr_pins, + const Network *network, + const Graph *graph); + virtual void operator()(const Pin *pin); + +protected: + PinSet &drvr_pins_; + const Network *network_; + const Graph *graph_; +}; + +FindNetDrvrs::FindNetDrvrs(PinSet &drvr_pins, + const Network *network, + const Graph *graph) : + drvr_pins_(drvr_pins), + network_(network), + graph_(graph) +{ +} + +void +FindNetDrvrs::operator()(const Pin *pin) +{ + Vertex *vertex = graph_->pinDrvrVertex(pin); + if (isLeafDriver(pin, network_) + && !(vertex && vertex->isRoot())) + drvr_pins_.insert(pin); +} + +void +GraphDelayCalc::ensureMultiDrvrNetsFound() +{ + if (!multi_drvr_nets_found_) { + LeafInstanceIterator *inst_iter = network_->leafInstanceIterator(); + while (inst_iter->hasNext()) { + Instance *inst = inst_iter->next(); + InstancePinIterator *pin_iter = network_->pinIterator(inst); + while (pin_iter->hasNext()) { + Pin *pin = pin_iter->next(); + Vertex *drvr_vertex = graph_->pinDrvrVertex(pin); + if (network_->isDriver(pin) + && !multi_drvr_net_map_.hasKey(drvr_vertex)) { + PinSet drvr_pins(network_); + FindNetDrvrs visitor(drvr_pins, network_, graph_); + network_->visitConnectedPins(pin, visitor); + if (drvr_pins.size() > 1) + makeMultiDrvrNet(drvr_pins); + } + } + delete pin_iter; + } + delete inst_iter; + multi_drvr_nets_found_ = true; + } +} + +void +GraphDelayCalc::makeMultiDrvrNet(PinSet &drvr_pins) +{ + debugPrint(debug_, "delay_calc", 3, "multi-driver net"); + VertexSet *drvr_vertices = new VertexSet(graph_); + MultiDrvrNet *multi_drvr = new MultiDrvrNet(drvr_vertices); + Level max_drvr_level = 0; + Vertex *max_drvr = nullptr; + PinSet::Iterator pin_iter(drvr_pins); + while (pin_iter.hasNext()) { + const Pin *pin = pin_iter.next(); + Vertex *drvr_vertex = graph_->pinDrvrVertex(pin); + debugPrint(debug_, "delay_calc", 3, " %s", + network_->pathName(pin)); + multi_drvr_net_map_[drvr_vertex] = multi_drvr; + drvr_vertices->insert(drvr_vertex); + Level drvr_level = drvr_vertex->level(); + if (max_drvr == nullptr + || drvr_level > max_drvr_level) { + max_drvr = drvr_vertex; + max_drvr_level = drvr_level; + } + } + multi_drvr->setDcalcDrvr(max_drvr); + multi_drvr->findCaps(this, sdc_); +} + +static bool +isLeafDriver(const Pin *pin, + const Network *network) +{ + PortDirection *dir = network->direction(pin); + const Instance *inst = network->instance(pin); + return network->isLeaf(inst) && dir->isAnyOutput(); +} + +MultiDrvrNet * +GraphDelayCalc::multiDrvrNet(const Vertex *drvr_vertex) const +{ + return multi_drvr_net_map_.findKey(drvr_vertex); +} + +void +GraphDelayCalc::seedRootSlews() +{ + for (Vertex *vertex : *levelize_->roots()) + seedRootSlew(vertex, arc_delay_calc_); +} + +void +GraphDelayCalc::seedRootSlew(Vertex *vertex, + ArcDelayCalc *arc_delay_calc) +{ + if (vertex->isDriver(network_)) + seedDrvrSlew(vertex, arc_delay_calc); + else + seedLoadSlew(vertex); + iter_->enqueueAdjacentVertices(vertex); +} + +void +GraphDelayCalc::seedDrvrSlew(Vertex *drvr_vertex, + ArcDelayCalc *arc_delay_calc) +{ + const Pin *drvr_pin = drvr_vertex->pin(); + debugPrint(debug_, "delay_calc", 2, "seed driver slew %s", + drvr_vertex->name(sdc_network_)); + InputDrive *drive = 0; + if (network_->isTopLevelPort(drvr_pin)) { + Port *port = network_->port(drvr_pin); + drive = sdc_->findInputDrive(port); + } + for (auto rf : RiseFall::range()) { + for (auto dcalc_ap : corners_->dcalcAnalysisPts()) { + if (drive) { + const MinMax *cnst_min_max = dcalc_ap->constraintMinMax(); + const LibertyCell *drvr_cell; + const LibertyPort *from_port, *to_port; + float *from_slews; + drive->driveCell(rf, cnst_min_max, drvr_cell, from_port, + from_slews, to_port); + if (drvr_cell) { + if (from_port == nullptr) + from_port = driveCellDefaultFromPort(drvr_cell, to_port); + findInputDriverDelay(drvr_cell, drvr_pin, drvr_vertex, rf, + from_port, from_slews, to_port, dcalc_ap); + } + else + seedNoDrvrCellSlew(drvr_vertex, drvr_pin, rf, drive, dcalc_ap, + arc_delay_calc); + } + else + seedNoDrvrSlew(drvr_vertex, drvr_pin, rf, dcalc_ap, arc_delay_calc); + } + } +} + +void +GraphDelayCalc::seedNoDrvrCellSlew(Vertex *drvr_vertex, + const Pin *drvr_pin, + const RiseFall *rf, + InputDrive *drive, + DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc) +{ + DcalcAPIndex ap_index = dcalc_ap->index(); + const MinMax *cnst_min_max = dcalc_ap->constraintMinMax(); + Slew slew = default_slew; + float drive_slew; + bool exists; + drive->slew(rf, cnst_min_max, drive_slew, exists); + if (exists) + slew = drive_slew; + else { + // Top level bidirect driver uses load slew unless + // bidirect instance paths are disabled. + if (sdc_->bidirectDrvrSlewFromLoad(drvr_pin)) { + Vertex *load_vertex = graph_->pinLoadVertex(drvr_pin); + slew = graph_->slew(load_vertex, rf, ap_index); + } + } + Delay drive_delay = delay_zero; + float drive_res; + drive->driveResistance(rf, cnst_min_max, drive_res, exists); + Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin, rf, dcalc_ap); + if (exists) { + float cap = loadCap(drvr_pin, parasitic, rf, dcalc_ap); + drive_delay = cap * drive_res; + slew = cap * drive_res; + } + const MinMax *slew_min_max = dcalc_ap->slewMinMax(); + if (!drvr_vertex->slewAnnotated(rf, slew_min_max)) + graph_->setSlew(drvr_vertex, rf, ap_index, slew); + arc_delay_calc->inputPortDelay(drvr_pin, delayAsFloat(slew), rf, + parasitic, dcalc_ap); + annotateLoadDelays(drvr_vertex, rf, drive_delay, false, dcalc_ap, + arc_delay_calc); + arc_delay_calc->finishDrvrPin(); +} + +void +GraphDelayCalc::seedNoDrvrSlew(Vertex *drvr_vertex, + const Pin *drvr_pin, + const RiseFall *rf, + DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc) +{ + const MinMax *slew_min_max = dcalc_ap->slewMinMax(); + DcalcAPIndex ap_index = dcalc_ap->index(); + Slew slew(default_slew); + // Top level bidirect driver uses load slew unless + // bidirect instance paths are disabled. + if (sdc_->bidirectDrvrSlewFromLoad(drvr_pin)) { + Vertex *load_vertex = graph_->pinLoadVertex(drvr_pin); + slew = graph_->slew(load_vertex, rf, ap_index); + } + if (!drvr_vertex->slewAnnotated(rf, slew_min_max)) + graph_->setSlew(drvr_vertex, rf, ap_index, slew); + Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin, rf, dcalc_ap); + arc_delay_calc->inputPortDelay(drvr_pin, delayAsFloat(slew), rf, + parasitic, dcalc_ap); + annotateLoadDelays(drvr_vertex, rf, delay_zero, false, dcalc_ap, + arc_delay_calc); + arc_delay_calc->finishDrvrPin(); +} + +void +GraphDelayCalc::seedLoadSlew(Vertex *vertex) +{ + const Pin *pin = vertex->pin(); + debugPrint(debug_, "delay_calc", 2, "seed load slew %s", + vertex->name(sdc_network_)); + ClockSet *clks = sdc_->findLeafPinClocks(pin); + initSlew(vertex); + for (auto rf : RiseFall::range()) { + for (auto dcalc_ap : corners_->dcalcAnalysisPts()) { + const MinMax *slew_min_max = dcalc_ap->slewMinMax(); + if (!vertex->slewAnnotated(rf, slew_min_max)) { + float slew = 0.0; + if (clks) { + slew = slew_min_max->initValue(); + ClockSet::Iterator clk_iter(clks); + while (clk_iter.hasNext()) { + Clock *clk = clk_iter.next(); + float clk_slew = clk->slew(rf, slew_min_max); + if (slew_min_max->compare(clk_slew, slew)) + slew = clk_slew; + } + } + DcalcAPIndex ap_index = dcalc_ap->index(); + graph_->setSlew(vertex, rf, ap_index, slew); + } + } + } +} + +// If a driving cell does not specify a -from_pin, the first port +// defined in the cell that has a timing group to the output port +// is used. Not exactly reasonable, but it's compatible. +LibertyPort * +GraphDelayCalc::driveCellDefaultFromPort(const LibertyCell *cell, + const LibertyPort *to_port) +{ + LibertyPort *from_port = 0; + int from_port_index = 0; + for (TimingArcSet *arc_set : cell->timingArcSets(nullptr, to_port)) { + LibertyPort *set_from_port = arc_set->from(); + int set_from_port_index = findPortIndex(cell, set_from_port); + if (from_port == nullptr + || set_from_port_index < from_port_index) { + from_port = set_from_port; + from_port_index = set_from_port_index; + } + } + return from_port; +} + +// Find the index that port is defined in cell. +int +GraphDelayCalc::findPortIndex(const LibertyCell *cell, + const LibertyPort *port) +{ + int index = 0; + LibertyCellPortIterator port_iter(cell); + while (port_iter.hasNext()) { + LibertyPort *cell_port = port_iter.next(); + if (cell_port == port) + return index; + index++; + } + report_->critical(207, "port not found in cell"); + return 0; +} + +void +GraphDelayCalc::findInputDriverDelay(const LibertyCell *drvr_cell, + const Pin *drvr_pin, + Vertex *drvr_vertex, + const RiseFall *rf, + const LibertyPort *from_port, + float *from_slews, + const LibertyPort *to_port, + const DcalcAnalysisPt *dcalc_ap) +{ + debugPrint(debug_, "delay_calc", 2, " driver cell %s %s", + drvr_cell->name(), + rf->asString()); + for (TimingArcSet *arc_set : drvr_cell->timingArcSets(from_port, to_port)) { + for (TimingArc *arc : arc_set->arcs()) { + if (arc->toEdge()->asRiseFall() == rf) { + float from_slew = from_slews[arc->fromEdge()->index()]; + findInputArcDelay(drvr_cell, drvr_pin, drvr_vertex, + arc, from_slew, dcalc_ap); + } + } + } +} + +// Driving cell delay is the load dependent delay, which is the gate +// delay minus the intrinsic delay. Driving cell delays are annotated +// to the wire arcs from the input port pin to the load pins. +void +GraphDelayCalc::findInputArcDelay(const LibertyCell *drvr_cell, + const Pin *drvr_pin, + Vertex *drvr_vertex, + const TimingArc *arc, + float from_slew, + const DcalcAnalysisPt *dcalc_ap) +{ + debugPrint(debug_, "delay_calc", 3, " %s %s -> %s %s (%s)", + arc->from()->name(), + arc->fromEdge()->asString(), + arc->to()->name(), + arc->toEdge()->asString(), + arc->role()->asString()); + RiseFall *drvr_rf = arc->toEdge()->asRiseFall(); + if (drvr_rf) { + DcalcAPIndex ap_index = dcalc_ap->index(); + const Pvt *pvt = dcalc_ap->operatingConditions(); + Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, + dcalc_ap); + float load_cap = loadCap(drvr_pin, drvr_parasitic, drvr_rf, dcalc_ap); + + ArcDelay intrinsic_delay; + Slew intrinsic_slew; + arc_delay_calc_->gateDelay(drvr_cell, arc, Slew(from_slew), + 0.0, 0, 0.0, pvt, dcalc_ap, + intrinsic_delay, intrinsic_slew); + + // For input drivers there is no instance to find a related_output_pin. + ArcDelay gate_delay; + Slew gate_slew; + arc_delay_calc_->gateDelay(drvr_cell, arc, + Slew(from_slew), load_cap, + drvr_parasitic, 0.0, pvt, dcalc_ap, + gate_delay, gate_slew); + ArcDelay load_delay = gate_delay - intrinsic_delay; + debugPrint(debug_, "delay_calc", 3, + " gate delay = %s intrinsic = %s slew = %s", + delayAsString(gate_delay, this), + delayAsString(intrinsic_delay, this), + delayAsString(gate_slew, this)); + graph_->setSlew(drvr_vertex, drvr_rf, ap_index, gate_slew); + annotateLoadDelays(drvr_vertex, drvr_rf, load_delay, false, dcalc_ap, + arc_delay_calc_); + } +} + +void +GraphDelayCalc::findDelays(Vertex *drvr_vertex) +{ + findVertexDelay(drvr_vertex, arc_delay_calc_, true); +} + +void +GraphDelayCalc::findVertexDelay(Vertex *vertex, + ArcDelayCalc *arc_delay_calc, + bool propagate) +{ + const Pin *pin = vertex->pin(); + debugPrint(debug_, "delay_calc", 2, "find delays %s (%s)", + vertex->name(sdc_network_), + network_->cellName(network_->instance(pin))); + if (vertex->isRoot()) { + seedRootSlew(vertex, arc_delay_calc); + if (propagate) + iter_->enqueueAdjacentVertices(vertex); + } + else { + if (network_->isLeaf(pin)) { + if (vertex->isDriver(network_)) { + bool delay_changed = findDriverDelays(vertex, arc_delay_calc); + if (propagate) { + if (network_->direction(pin)->isInternal()) + enqueueTimingChecksEdges(vertex); + // Enqueue adjacent vertices even if the delays did not + // change when non-incremental to stride past annotations. + if (delay_changed || !incremental_) + iter_->enqueueAdjacentVertices(vertex); + } + } + else { + // Load vertex. + enqueueTimingChecksEdges(vertex); + // Enqueue driver vertices from this input load. + if (propagate) + iter_->enqueueAdjacentVertices(vertex); + } + } + // Bidirect port drivers are enqueued by their load vertex in + // annotateLoadDelays. + else if (vertex->isBidirectDriver() + && network_->isTopLevelPort(pin)) + seedRootSlew(vertex, arc_delay_calc); + } +} + +void +GraphDelayCalc::enqueueTimingChecksEdges(Vertex *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); + } + } +} + +bool +GraphDelayCalc::findDriverDelays(Vertex *drvr_vertex, + ArcDelayCalc *arc_delay_calc) +{ + bool delay_changed = false; + MultiDrvrNet *multi_drvr = multiDrvrNet(drvr_vertex); + if (multi_drvr) { + Vertex *dcalc_drvr = multi_drvr->dcalcDrvr(); + if (drvr_vertex == dcalc_drvr) { + bool init_load_slews = true; + for (Vertex *drvr_vertex : *multi_drvr->drvrs()) { + // Only init load slews once so previous driver dcalc results + // aren't clobbered. + delay_changed |= findDriverDelays1(drvr_vertex, init_load_slews, + multi_drvr, arc_delay_calc); + init_load_slews = false; + } + } + } + else + delay_changed = findDriverDelays1(drvr_vertex, true, nullptr, arc_delay_calc); + arc_delay_calc->finishDrvrPin(); + return delay_changed; +} + +bool +GraphDelayCalc::findDriverDelays1(Vertex *drvr_vertex, + bool init_load_slews, + MultiDrvrNet *multi_drvr, + ArcDelayCalc *arc_delay_calc) +{ + const Pin *drvr_pin = drvr_vertex->pin(); + Instance *drvr_inst = network_->instance(drvr_pin); + LibertyCell *drvr_cell = network_->libertyCell(drvr_inst); + 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) + && !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; +} + +// Init slews to zero on root vertices that are not inputs, such as +// floating input pins. +void +GraphDelayCalc::initRootSlews(Vertex *vertex) +{ + for (auto dcalc_ap : corners_->dcalcAnalysisPts()) { + const MinMax *slew_min_max = dcalc_ap->slewMinMax(); + DcalcAPIndex ap_index = dcalc_ap->index(); + for (auto rf : RiseFall::range()) { + if (!vertex->slewAnnotated(rf, slew_min_max)) + graph_->setSlew(vertex, rf, ap_index, default_slew); + } + } +} + +void +GraphDelayCalc::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 +GraphDelayCalc::findDriverEdgeDelays(LibertyCell *drvr_cell, + Instance *drvr_inst, + const Pin *drvr_pin, + Vertex *drvr_vertex, + MultiDrvrNet *multi_drvr, + Edge *edge, + ArcDelayCalc *arc_delay_calc) +{ + Vertex *in_vertex = edge->from(graph_); + TimingArcSet *arc_set = edge->timingArcSet(); + const LibertyPort *related_out_port = arc_set->relatedOut(); + const Pin *related_out_pin = 0; + bool delay_changed = false; + if (related_out_port) + related_out_pin = network_->findPin(drvr_inst, related_out_port); + for (auto dcalc_ap : corners_->dcalcAnalysisPts()) { + const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax()); + if (pvt == nullptr) + pvt = dcalc_ap->operatingConditions(); + for (TimingArc *arc : arc_set->arcs()) { + const RiseFall *rf = arc->toEdge()->asRiseFall(); + Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin, rf, + dcalc_ap); + float related_out_cap = 0.0; + if (related_out_pin) { + Parasitic *related_out_parasitic = + arc_delay_calc->findParasitic(related_out_pin, rf, dcalc_ap); + related_out_cap = loadCap(related_out_pin, + related_out_parasitic, + rf, dcalc_ap); + } + delay_changed |= findArcDelay(drvr_cell, drvr_pin, drvr_vertex, + multi_drvr, arc, parasitic, + related_out_cap, + in_vertex, edge, pvt, dcalc_ap, + arc_delay_calc); + } + } + + if (delay_changed && observer_) { + observer_->delayChangedFrom(in_vertex); + observer_->delayChangedFrom(drvr_vertex); + } + return delay_changed; } float -GraphDelayCalc::ceff(Edge *, - TimingArc *, - const DcalcAnalysisPt *) +GraphDelayCalc::loadCap(const Pin *drvr_pin, + const DcalcAnalysisPt *dcalc_ap) const { - return 0.0; + const MinMax *min_max = dcalc_ap->constraintMinMax(); + float load_cap = 0.0; + for (auto drvr_rf : RiseFall::range()) { + Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, + dcalc_ap); + float cap = loadCap(drvr_pin, nullptr, drvr_parasitic, drvr_rf, dcalc_ap); + arc_delay_calc_->finishDrvrPin(); + if (min_max->compare(cap, load_cap)) + load_cap = cap; + } + return load_cap; } +float +GraphDelayCalc::loadCap(const Pin *drvr_pin, + const RiseFall *drvr_rf, + const DcalcAnalysisPt *dcalc_ap) const +{ + Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, + dcalc_ap); + float cap = loadCap(drvr_pin, nullptr, drvr_parasitic, drvr_rf, dcalc_ap); + return cap; +} + +float +GraphDelayCalc::loadCap(const Pin *drvr_pin, + const Parasitic *drvr_parasitic, + const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap) const +{ + return loadCap(drvr_pin, nullptr, drvr_parasitic, rf, dcalc_ap); +} + +float +GraphDelayCalc::loadCap(const Pin *drvr_pin, + MultiDrvrNet *multi_drvr, + const Parasitic *drvr_parasitic, + const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap) const +{ + float pin_cap, wire_cap; + bool has_net_load; + float fanout; + if (multi_drvr) + multi_drvr->netCaps(rf, dcalc_ap, + pin_cap, wire_cap, fanout, has_net_load); + else + netCaps(drvr_pin, rf, dcalc_ap, + pin_cap, wire_cap, fanout, has_net_load); + loadCap(drvr_parasitic, has_net_load, pin_cap, wire_cap); + return wire_cap + pin_cap; +} + +void +GraphDelayCalc::loadCap(const Pin *drvr_pin, + const Parasitic *drvr_parasitic, + const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap, + // Return values. + float &pin_cap, + float &wire_cap) const +{ + bool has_net_load; + float fanout; + // Find pin and external pin/wire capacitance. + netCaps(drvr_pin, rf, dcalc_ap, + pin_cap, wire_cap, fanout, has_net_load); + loadCap(drvr_parasitic, has_net_load, pin_cap, wire_cap); +} + +void +GraphDelayCalc::loadCap(const Parasitic *drvr_parasitic, + bool has_net_load, + // Return values. + float &pin_cap, + float &wire_cap) const +{ + // set_load net has precidence over parasitics. + if (!has_net_load && drvr_parasitic) { + if (parasitics_->isParasiticNetwork(drvr_parasitic)) + wire_cap += parasitics_->capacitance(drvr_parasitic); + else { + // PiModel includes both pin and external caps. + float cap = parasitics_->capacitance(drvr_parasitic); + if (pin_cap > cap) { + pin_cap = 0.0; + wire_cap = cap; + } + else + wire_cap = cap - pin_cap; + } + } +} + +void +GraphDelayCalc::netCaps(const Pin *drvr_pin, + const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap, + // Return values. + float &pin_cap, + float &wire_cap, + float &fanout, + bool &has_net_load) const +{ + MultiDrvrNet *multi_drvr = nullptr; + if (graph_) { + Vertex *drvr_vertex = graph_->pinDrvrVertex(drvr_pin); + multi_drvr = multiDrvrNet(drvr_vertex); + } + if (multi_drvr) + multi_drvr->netCaps(rf, dcalc_ap, + pin_cap, wire_cap, fanout, has_net_load); + else { + const OperatingConditions *op_cond = dcalc_ap->operatingConditions(); + const Corner *corner = dcalc_ap->corner(); + const MinMax *min_max = dcalc_ap->constraintMinMax(); + // Find pin and external pin/wire capacitance. + sdc_->connectedCap(drvr_pin, rf, op_cond, corner, min_max, + pin_cap, wire_cap, fanout, has_net_load); + } +} + +void +GraphDelayCalc::initSlew(Vertex *vertex) +{ + for (auto rf : RiseFall::range()) { + for (auto dcalc_ap : corners_->dcalcAnalysisPts()) { + const MinMax *slew_min_max = dcalc_ap->slewMinMax(); + if (!vertex->slewAnnotated(rf, slew_min_max)) { + DcalcAPIndex ap_index = dcalc_ap->index(); + graph_->setSlew(vertex, rf, ap_index, slew_min_max->initValue()); + } + } + } +} + +void +GraphDelayCalc::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 rf : RiseFall::range()) { + // Init drvr slew. + if (!drvr_vertex->slewAnnotated(rf, slew_min_max)) { + DcalcAPIndex ap_index = dcalc_ap->index(); + graph_->setSlew(drvr_vertex, rf, 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, rf, ap_index)) + graph_->setWireArcDelay(wire_edge, rf, ap_index, 0.0); + // Init load vertex slew. + if (!load_vertex->slewAnnotated(rf, slew_min_max)) + graph_->setSlew(load_vertex, rf, ap_index, 0.0); + } + } + } + } +} + +// Init wire delays and load slews. +void +GraphDelayCalc::initWireDelays(Vertex *drvr_vertex, + bool init_load_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_); + for (auto dcalc_ap : corners_->dcalcAnalysisPts()) { + const MinMax *delay_min_max = dcalc_ap->delayMinMax(); + const MinMax *slew_min_max = dcalc_ap->slewMinMax(); + Delay delay_init_value(delay_min_max->initValue()); + Slew slew_init_value(slew_min_max->initValue()); + DcalcAPIndex ap_index = dcalc_ap->index(); + 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(rf, slew_min_max)) + graph_->setSlew(load_vertex, rf, ap_index, slew_init_value); + } + } + } + } +} + +// Call the arc delay calculator to find the delay thru a single gate +// input to output timing arc, the wire delays from the gate output to +// each load pin, and the slew at each load pin. Annotate the graph +// with the results. +bool +GraphDelayCalc::findArcDelay(LibertyCell *drvr_cell, + const Pin *drvr_pin, + Vertex *drvr_vertex, + MultiDrvrNet *multi_drvr, + TimingArc *arc, + Parasitic *drvr_parasitic, + float related_out_cap, + Vertex *from_vertex, + Edge *edge, + const Pvt *pvt, + const DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc) +{ + bool delay_changed = false; + RiseFall *from_rf = arc->fromEdge()->asRiseFall(); + RiseFall *drvr_rf = arc->toEdge()->asRiseFall(); + if (from_rf && drvr_rf) { + DcalcAPIndex ap_index = dcalc_ap->index(); + debugPrint(debug_, "delay_calc", 3, + " %s %s -> %s %s (%s) corner:%s/%s", + arc->from()->name(), + arc->fromEdge()->asString(), + arc->to()->name(), + arc->toEdge()->asString(), + arc->role()->asString(), + dcalc_ap->corner()->name(), + dcalc_ap->delayMinMax()->asString()); + // Delay calculation is done even when the gate delays/slews are + // annotated because the wire delays may not be annotated. + const Slew from_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap); + ArcDelay gate_delay; + Slew gate_slew; + if (multi_drvr + && arc->to()->direction()->isOutput()) + parallelGateDelay(multi_drvr, drvr_cell, drvr_pin, arc, + pvt, dcalc_ap, from_slew, drvr_parasitic, + related_out_cap, + arc_delay_calc, + gate_delay, gate_slew); + else { + float load_cap = loadCap(drvr_pin, multi_drvr, drvr_parasitic, + drvr_rf, dcalc_ap); + arc_delay_calc->gateDelay(drvr_cell, arc, + from_slew, load_cap, drvr_parasitic, + related_out_cap, pvt, dcalc_ap, + gate_delay, gate_slew); + } + debugPrint(debug_, "delay_calc", 3, + " gate delay = %s slew = %s", + delayAsString(gate_delay, this), + delayAsString(gate_slew, this)); + // Merge slews. + 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) + && !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); + float gate_delay1 = delayAsFloat(gate_delay); + float prev_gate_delay1 = delayAsFloat(prev_gate_delay); + if (prev_gate_delay1 == 0.0 + || (abs(gate_delay1 - prev_gate_delay1) / prev_gate_delay1 + > incremental_delay_tolerance_)) + delay_changed = true; + graph_->setArcDelay(edge, arc, ap_index, gate_delay); + } + if (!edge->role()->isLatchDtoQ()) + annotateLoadDelays(drvr_vertex, drvr_rf, delay_zero, true, dcalc_ap, + arc_delay_calc); + } + return delay_changed; +} + +void +GraphDelayCalc::parallelGateDelay(MultiDrvrNet *multi_drvr, + LibertyCell *drvr_cell, + const Pin *drvr_pin, + TimingArc *arc, + const Pvt *pvt, + const DcalcAnalysisPt *dcalc_ap, + const Slew from_slew, + Parasitic *drvr_parasitic, + float related_out_cap, + ArcDelayCalc *arc_delay_calc, + // Return values. + ArcDelay &gate_delay, + Slew &gate_slew) +{ + ArcDelay intrinsic_delay; + Slew intrinsic_slew; + arc_delay_calc->gateDelay(drvr_cell, arc, from_slew, + 0.0, 0, 0.0, pvt, dcalc_ap, + intrinsic_delay, intrinsic_slew); + ArcDelay parallel_delay; + Slew parallel_slew; + const RiseFall *drvr_rf = arc->toEdge()->asRiseFall(); + multi_drvr->parallelDelaySlew(drvr_rf, dcalc_ap, arc_delay_calc, this, + parallel_delay, parallel_slew); + + gate_delay = parallel_delay + intrinsic_delay; + gate_slew = parallel_slew; + + float load_cap = loadCap(drvr_pin, multi_drvr, drvr_parasitic, + drvr_rf, dcalc_ap); + Delay gate_delay1; + Slew gate_slew1; + arc_delay_calc->gateDelay(drvr_cell, arc, + from_slew, load_cap, drvr_parasitic, + related_out_cap, pvt, dcalc_ap, + gate_delay1, gate_slew1); + float factor = delayRatio(gate_slew, gate_slew1); + arc_delay_calc->setMultiDrvrSlewFactor(factor); +} + +void +GraphDelayCalc::findMultiDrvrGateDelay(MultiDrvrNet *multi_drvr, + const RiseFall *drvr_rf, + const Pvt *pvt, + const DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc, + // Return values. + ArcDelay ¶llel_delay, + Slew ¶llel_slew) +{ + ArcDelay delay_sum = 1.0; + Slew slew_sum = 1.0; + for (Vertex *drvr_vertex1 : *multi_drvr->drvrs()) { + Pin *drvr_pin1 = drvr_vertex1->pin(); + Instance *drvr_inst1 = network_->instance(drvr_pin1); + LibertyCell *drvr_cell1 = network_->libertyCell(drvr_inst1); + if (network_->isDriver(drvr_pin1)) { + VertexInEdgeIterator edge_iter(drvr_vertex1, graph_); + while (edge_iter.hasNext()) { + Edge *edge1 = edge_iter.next(); + TimingArcSet *arc_set1 = edge1->timingArcSet(); + const LibertyPort *related_out_port = arc_set1->relatedOut(); + for (TimingArc *arc1 : arc_set1->arcs()) { + RiseFall *drvr_rf1 = arc1->toEdge()->asRiseFall(); + if (drvr_rf1 == drvr_rf) { + Vertex *from_vertex1 = edge1->from(graph_); + RiseFall *from_rf1 = arc1->fromEdge()->asRiseFall(); + Slew from_slew1 = edgeFromSlew(from_vertex1, from_rf1, edge1, dcalc_ap); + ArcDelay intrinsic_delay1; + Slew intrinsic_slew1; + arc_delay_calc->gateDelay(drvr_cell1, arc1, from_slew1, + 0.0, 0, 0.0, pvt, dcalc_ap, + intrinsic_delay1, intrinsic_slew1); + Parasitic *parasitic1 = + arc_delay_calc->findParasitic(drvr_pin1, drvr_rf1, dcalc_ap); + const Pin *related_out_pin1 = 0; + float related_out_cap1 = 0.0; + if (related_out_port) { + Instance *inst1 = network_->instance(drvr_pin1); + related_out_pin1 = network_->findPin(inst1, related_out_port); + if (related_out_pin1) { + Parasitic *related_out_parasitic1 = + arc_delay_calc->findParasitic(related_out_pin1, drvr_rf, + dcalc_ap); + related_out_cap1 = loadCap(related_out_pin1, + related_out_parasitic1, + drvr_rf, dcalc_ap); + } + } + float load_cap1 = loadCap(drvr_pin1, parasitic1, + drvr_rf, dcalc_ap); + ArcDelay gate_delay1; + Slew gate_slew1; + arc_delay_calc->gateDelay(drvr_cell1, arc1, + from_slew1, load_cap1, parasitic1, + related_out_cap1, pvt, dcalc_ap, + gate_delay1, gate_slew1); + delay_sum += 1.0F / (gate_delay1 - intrinsic_delay1); + slew_sum += 1.0F / gate_slew1; + } + } + } + } + } + parallel_delay = 1.0F / delay_sum; + parallel_slew = 1.0F / slew_sum; +} + +// Use clock slew for register/latch clk->q edges. +Slew +GraphDelayCalc::edgeFromSlew(const Vertex *from_vertex, + const RiseFall *from_rf, + const Edge *edge, + const DcalcAnalysisPt *dcalc_ap) +{ + const TimingRole *role = edge->role(); + if (role->genericRole() == TimingRole::regClkToQ() + && clk_network_->isIdealClock(from_vertex->pin())) + return clk_network_->idealClkSlew(from_vertex->pin(), from_rf, + dcalc_ap->slewMinMax()); + else + return graph_->slew(from_vertex, from_rf, dcalc_ap->index()); +} + +// Annotate wire arc delays and load pin slews. +// extra_delay is additional wire delay to add to delay returned +// by the delay calculator. +void +GraphDelayCalc::annotateLoadDelays(Vertex *drvr_vertex, + const RiseFall *drvr_rf, + const ArcDelay &extra_delay, + bool merge, + const DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc) +{ + DcalcAPIndex ap_index = dcalc_ap->index(); + const MinMax *slew_min_max = dcalc_ap->slewMinMax(); + 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_); + Pin *load_pin = load_vertex->pin(); + ArcDelay wire_delay; + Slew load_slew; + arc_delay_calc->loadDelay(load_pin, wire_delay, load_slew); + debugPrint(debug_, "delay_calc", 3, + " %s load delay = %s slew = %s", + load_vertex->name(sdc_network_), + delayAsString(wire_delay, this), + delayAsString(load_slew, this)); + if (!load_vertex->slewAnnotated(drvr_rf, slew_min_max)) { + if (drvr_vertex->slewAnnotated(drvr_rf, slew_min_max)) { + // Copy the driver slew to the load if it is annotated. + const Slew &drvr_slew = graph_->slew(drvr_vertex,drvr_rf,ap_index); + graph_->setSlew(load_vertex, drvr_rf, ap_index, drvr_slew); + } + else { + const Slew &slew = graph_->slew(load_vertex, drvr_rf, ap_index); + if (!merge + || delayGreater(load_slew, slew, slew_min_max, this)) + graph_->setSlew(load_vertex, drvr_rf, ap_index, load_slew); + } + } + if (!graph_->wireDelayAnnotated(wire_edge, drvr_rf, ap_index)) { + // Multiple timing arcs with the same output transition + // annotate the same wire edges so they must be combined + // rather than set. + const ArcDelay &delay = graph_->wireArcDelay(wire_edge, drvr_rf, + ap_index); + Delay wire_delay_extra = extra_delay + wire_delay; + const MinMax *delay_min_max = dcalc_ap->delayMinMax(); + if (!merge + || delayGreater(wire_delay_extra, delay, delay_min_max, this)) { + graph_->setWireArcDelay(wire_edge, drvr_rf, ap_index, + wire_delay_extra); + if (observer_) + observer_->delayChangedTo(load_vertex); + } + } + // Enqueue bidirect driver from load vertex. + if (sdc_->bidirectDrvrSlewFromLoad(load_pin)) + iter_->enqueue(graph_->pinDrvrVertex(load_pin)); + } + } +} + +void +GraphDelayCalc::findCheckEdgeDelays(Edge *edge, + ArcDelayCalc *arc_delay_calc) +{ + Vertex *from_vertex = edge->from(graph_); + Vertex *to_vertex = edge->to(graph_); + TimingArcSet *arc_set = edge->timingArcSet(); + 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; + for (TimingArc *arc : arc_set->arcs()) { + RiseFall *from_rf = arc->fromEdge()->asRiseFall(); + RiseFall *to_rf = arc->toEdge()->asRiseFall(); + if (from_rf && to_rf) { + const LibertyPort *related_out_port = arc_set->relatedOut(); + const Pin *related_out_pin = 0; + if (related_out_port) + related_out_pin = network_->findPin(inst, related_out_port); + for (auto dcalc_ap : corners_->dcalcAnalysisPts()) { + DcalcAPIndex ap_index = dcalc_ap->index(); + if (!graph_->arcDelayAnnotated(edge, arc, ap_index)) { + const Pvt *pvt = sdc_->pvt(inst,dcalc_ap->constraintMinMax()); + if (pvt == nullptr) + pvt = dcalc_ap->operatingConditions(); + const Slew &from_slew = checkEdgeClkSlew(from_vertex, from_rf, + dcalc_ap); + int slew_index = dcalc_ap->checkDataSlewIndex(); + const Slew &to_slew = graph_->slew(to_vertex, to_rf, slew_index); + debugPrint(debug_, "delay_calc", 3, + " %s %s -> %s %s (%s)", + arc_set->from()->name(), + arc->fromEdge()->asString(), + arc_set->to()->name(), + arc->toEdge()->asString(), + arc_set->role()->asString()); + debugPrint(debug_, "delay_calc", 3, + " from_slew = %s to_slew = %s", + delayAsString(from_slew, this), + delayAsString(to_slew, this)); + float related_out_cap = 0.0; + if (related_out_pin) { + Parasitic *related_out_parasitic = + arc_delay_calc->findParasitic(related_out_pin, to_rf, dcalc_ap); + related_out_cap = loadCap(related_out_pin, + related_out_parasitic, + to_rf, dcalc_ap); + } + ArcDelay check_delay; + arc_delay_calc->checkDelay(cell, arc, + from_slew, to_slew, + related_out_cap, + pvt, dcalc_ap, + check_delay); + debugPrint(debug_, "delay_calc", 3, + " check_delay = %s", + delayAsString(check_delay, this)); + graph_->setArcDelay(edge, arc, ap_index, check_delay); + delay_changed = true; + } + } + } + } + + if (delay_changed && observer_) + observer_->checkDelayChangedTo(to_vertex); +} + +// Use clock slew for timing check clock edges. +Slew +GraphDelayCalc::checkEdgeClkSlew(const Vertex *from_vertex, + const RiseFall *from_rf, + const DcalcAnalysisPt *dcalc_ap) +{ + if (clk_network_->isIdealClock(from_vertex->pin())) + return clk_network_->idealClkSlew(from_vertex->pin(), from_rf, + dcalc_ap->checkClkSlewMinMax()); + else + return graph_->slew(from_vertex, from_rf, dcalc_ap->checkClkSlewIndex()); +} + +//////////////////////////////////////////////////////////////// + +float +GraphDelayCalc::ceff(Edge *edge, + TimingArc *arc, + const DcalcAnalysisPt *dcalc_ap) +{ + Vertex *from_vertex = edge->from(graph_); + Vertex *to_vertex = edge->to(graph_); + Pin *to_pin = to_vertex->pin(); + Instance *inst = network_->instance(to_pin); + LibertyCell *cell = network_->libertyCell(inst); + TimingArcSet *arc_set = edge->timingArcSet(); + float ceff = 0.0; + const Pvt *pvt = sdc_->pvt(inst, dcalc_ap->constraintMinMax()); + if (pvt == nullptr) + pvt = dcalc_ap->operatingConditions(); + RiseFall *from_rf = arc->fromEdge()->asRiseFall(); + RiseFall *to_rf = arc->toEdge()->asRiseFall(); + if (from_rf && to_rf) { + const LibertyPort *related_out_port = arc_set->relatedOut(); + const Pin *related_out_pin = 0; + if (related_out_port) + related_out_pin = network_->findPin(inst, related_out_port); + float related_out_cap = 0.0; + if (related_out_pin) { + Parasitic *related_out_parasitic = + arc_delay_calc_->findParasitic(related_out_pin, to_rf, dcalc_ap); + related_out_cap = loadCap(related_out_pin, related_out_parasitic, + to_rf, dcalc_ap); + } + Parasitic *to_parasitic = arc_delay_calc_->findParasitic(to_pin, to_rf, + dcalc_ap); + const Slew &from_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap); + float load_cap = loadCap(to_pin, to_parasitic, to_rf, dcalc_ap); + ceff = arc_delay_calc_->ceff(cell, arc, + from_slew, load_cap, to_parasitic, + related_out_cap, pvt, dcalc_ap); + arc_delay_calc_->finishDrvrPin(); + } + return ceff; +} + +//////////////////////////////////////////////////////////////// + +string +GraphDelayCalc::reportDelayCalc(Edge *edge, + TimingArc *arc, + const Corner *corner, + const MinMax *min_max, + int digits) +{ + Vertex *from_vertex = edge->from(graph_); + Vertex *to_vertex = edge->to(graph_); + Pin *to_pin = to_vertex->pin(); + TimingRole *role = arc->role(); + Instance *inst = network_->instance(to_pin); + LibertyCell *cell = network_->libertyCell(inst); + TimingArcSet *arc_set = edge->timingArcSet(); + string result; + DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); + const Pvt *pvt = sdc_->pvt(inst, dcalc_ap->constraintMinMax()); + if (pvt == nullptr) + pvt = dcalc_ap->operatingConditions(); + RiseFall *from_rf = arc->fromEdge()->asRiseFall(); + RiseFall *to_rf = arc->toEdge()->asRiseFall(); + if (from_rf && to_rf) { + const LibertyPort *related_out_port = arc_set->relatedOut(); + const Pin *related_out_pin = 0; + if (related_out_port) + related_out_pin = network_->findPin(inst, related_out_port); + float related_out_cap = 0.0; + if (related_out_pin) { + Parasitic *related_out_parasitic = + arc_delay_calc_->findParasitic(related_out_pin, to_rf, dcalc_ap); + related_out_cap = loadCap(related_out_pin, related_out_parasitic, + to_rf, dcalc_ap); + } + if (role->isTimingCheck()) { + const Slew &from_slew = checkEdgeClkSlew(from_vertex, from_rf, dcalc_ap); + int slew_index = dcalc_ap->checkDataSlewIndex(); + const Slew &to_slew = graph_->slew(to_vertex, to_rf, slew_index); + bool from_ideal_clk = clk_network_->isIdealClock(from_vertex->pin()); + const char *from_slew_annotation = from_ideal_clk ? " (ideal clock)" : nullptr; + result = arc_delay_calc_->reportCheckDelay(cell, arc, from_slew, + from_slew_annotation, to_slew, + related_out_cap, pvt, dcalc_ap, + digits); + } + else { + Parasitic *to_parasitic = + arc_delay_calc_->findParasitic(to_pin, to_rf, dcalc_ap); + const Slew &from_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap); + float load_cap = loadCap(to_pin, to_parasitic, to_rf, dcalc_ap); + result = arc_delay_calc_->reportGateDelay(cell, arc, + from_slew, load_cap, to_parasitic, + related_out_cap, pvt, dcalc_ap, digits); + } + arc_delay_calc_->finishDrvrPin(); + } + return result; +} + +//////////////////////////////////////////////////////////////// + void GraphDelayCalc::minPulseWidth(const Pin *pin, const RiseFall *hi_low, diff --git a/dcalc/GraphDelayCalc1.cc b/dcalc/GraphDelayCalc1.cc deleted file mode 100644 index 53566b45..00000000 --- a/dcalc/GraphDelayCalc1.cc +++ /dev/null @@ -1,1690 +0,0 @@ -// OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#include "GraphDelayCalc1.hh" - -#include "Debug.hh" -#include "Stats.hh" -#include "MinMax.hh" -#include "Mutex.hh" -#include "TimingRole.hh" -#include "TimingArc.hh" -#include "Liberty.hh" -#include "PortDirection.hh" -#include "Network.hh" -#include "InputDrive.hh" -#include "Sdc.hh" -#include "Graph.hh" -#include "Parasitics.hh" -#include "search/Levelize.hh" -#include "Corner.hh" -#include "SearchPred.hh" -#include "Bfs.hh" -#include "ArcDelayCalc.hh" -#include "DcalcAnalysisPt.hh" -#include "NetCaps.hh" -#include "ClkNetwork.hh" - -namespace sta { - -using std::abs; - -static const Slew default_slew = 0.0; - -typedef Set MultiDrvrNetSet; - -static bool -isLeafDriver(const Pin *pin, - const Network *network); - -// Cache parallel delay/slew values for nets with multiple drivers. -class MultiDrvrNet -{ -public: - MultiDrvrNet(VertexSet *drvrs); - ~MultiDrvrNet(); - const VertexSet *drvrs() const { return drvrs_; } - VertexSet *drvrs() { return drvrs_; } - Vertex *dcalcDrvr() const { return dcalc_drvr_; } - void setDcalcDrvr(Vertex *drvr); - void parallelDelaySlew(const RiseFall *drvr_rf, - const DcalcAnalysisPt *dcalc_ap, - ArcDelayCalc *arc_delay_calc, - GraphDelayCalc1 *dcalc, - // Return values. - ArcDelay ¶llel_delay, - Slew ¶llel_slew); - void netCaps(const RiseFall *rf, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - float &pin_cap, - float &wire_cap, - float &fanout, - bool &has_net_load); - void findCaps(const GraphDelayCalc1 *dcalc, - const Sdc *sdc); - -private: - void findDelaysSlews(ArcDelayCalc *arc_delay_calc, - GraphDelayCalc1 *dcalc); - - // Driver that triggers delay calculation for all the drivers on the net. - Vertex *dcalc_drvr_; - VertexSet *drvrs_; - // [drvr_rf->index][dcalc_ap->index] - ArcDelay *parallel_delays_; - // [drvr_rf->index][dcalc_ap->index] - Slew *parallel_slews_; - // [drvr_rf->index][dcalc_ap->index] - NetCaps *net_caps_; - bool delays_valid_:1; -}; - -MultiDrvrNet::MultiDrvrNet(VertexSet *drvrs) : - dcalc_drvr_(nullptr), - drvrs_(drvrs), - parallel_delays_(nullptr), - parallel_slews_(nullptr), - net_caps_(nullptr), - delays_valid_(false) -{ -} - -MultiDrvrNet::~MultiDrvrNet() -{ - delete drvrs_; - if (delays_valid_) { - delete [] parallel_delays_; - delete [] parallel_slews_; - } - delete [] net_caps_; -} - -void -MultiDrvrNet::parallelDelaySlew(const RiseFall *drvr_rf, - const DcalcAnalysisPt *dcalc_ap, - ArcDelayCalc *arc_delay_calc, - GraphDelayCalc1 *dcalc, - // Return values. - ArcDelay ¶llel_delay, - Slew ¶llel_slew) -{ - if (!delays_valid_) { - findDelaysSlews(arc_delay_calc, dcalc); - delays_valid_ = true; - } - - int index = dcalc_ap->index() * RiseFall::index_count - + drvr_rf->index(); - parallel_delay = parallel_delays_[index]; - parallel_slew = parallel_slews_[index]; -} - -void -MultiDrvrNet::findDelaysSlews(ArcDelayCalc *arc_delay_calc, - GraphDelayCalc1 *dcalc) -{ - Corners *corners = dcalc->corners(); - int count = RiseFall::index_count * corners->dcalcAnalysisPtCount(); - parallel_delays_ = new ArcDelay[count]; - parallel_slews_ = new Slew[count]; - for (auto dcalc_ap : corners->dcalcAnalysisPts()) { - DcalcAPIndex ap_index = dcalc_ap->index(); - const Pvt *pvt = dcalc_ap->operatingConditions(); - for (auto drvr_rf : RiseFall::range()) { - int drvr_rf_index = drvr_rf->index(); - int index = ap_index*RiseFall::index_count+drvr_rf_index; - dcalc->findMultiDrvrGateDelay(this, drvr_rf, pvt, dcalc_ap, - arc_delay_calc, - parallel_delays_[index], - parallel_slews_[index]); - } - } -} - -void -MultiDrvrNet::netCaps(const RiseFall *drvr_rf, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - float &pin_cap, - float &wire_cap, - float &fanout, - bool &has_net_load) -{ - int index = dcalc_ap->index() * RiseFall::index_count - + drvr_rf->index(); - NetCaps &net_caps = net_caps_[index]; - pin_cap = net_caps.pinCap(); - wire_cap = net_caps.wireCap(); - fanout = net_caps.fanout(); - has_net_load = net_caps.hasNetLoad(); -} - -void -MultiDrvrNet::findCaps(const GraphDelayCalc1 *dcalc, - const Sdc *sdc) -{ - Corners *corners = dcalc->corners(); - int count = RiseFall::index_count * corners->dcalcAnalysisPtCount(); - net_caps_ = new NetCaps[count]; - const Pin *drvr_pin = dcalc_drvr_->pin(); - for (auto dcalc_ap : corners->dcalcAnalysisPts()) { - DcalcAPIndex ap_index = dcalc_ap->index(); - const Corner *corner = dcalc_ap->corner(); - const OperatingConditions *op_cond = dcalc_ap->operatingConditions(); - const MinMax *min_max = dcalc_ap->constraintMinMax(); - for (auto drvr_rf : RiseFall::range()) { - int drvr_rf_index = drvr_rf->index(); - int index = ap_index * RiseFall::index_count + drvr_rf_index; - NetCaps &net_caps = net_caps_[index]; - float pin_cap, wire_cap, fanout; - bool has_net_load; - // Find pin and external pin/wire capacitance. - sdc->connectedCap(drvr_pin, drvr_rf, op_cond, corner, min_max, - pin_cap, wire_cap, fanout, has_net_load); - net_caps.init(pin_cap, wire_cap, fanout, has_net_load); - } - } -} - -void -MultiDrvrNet::setDcalcDrvr(Vertex *drvr) -{ - dcalc_drvr_ = drvr; -} - -//////////////////////////////////////////////////////////////// - - -GraphDelayCalc1::GraphDelayCalc1(StaState *sta) : - GraphDelayCalc(sta), - observer_(nullptr), - delays_seeded_(false), - incremental_(false), - delays_exist_(false), - invalid_delays_(new VertexSet(graph_)), - search_pred_(new SearchPred1(sta)), - search_non_latch_pred_(new SearchPredNonLatch2(sta)), - clk_pred_(new ClkTreeSearchPred(sta)), - iter_(new BfsFwdIterator(BfsIndex::dcalc, search_non_latch_pred_, sta)), - multi_drvr_nets_found_(false), - incremental_delay_tolerance_(0.0) -{ -} - -GraphDelayCalc1::~GraphDelayCalc1() -{ - delete search_pred_; - delete invalid_delays_; - delete search_non_latch_pred_; - delete clk_pred_; - delete iter_; - deleteMultiDrvrNets(); - delete observer_; -} - -void -GraphDelayCalc1::deleteMultiDrvrNets() -{ - MultiDrvrNetSet drvr_nets; - MultiDrvrNetMap::Iterator multi_iter(multi_drvr_net_map_); - while (multi_iter.hasNext()) { - MultiDrvrNet *multi_drvr = multi_iter.next(); - // Multiple drvr pins point to the same drvr PinSet, - // so collect them into a set. - drvr_nets.insert(multi_drvr); - } - multi_drvr_net_map_.clear(); - drvr_nets.deleteContents(); -} - -void -GraphDelayCalc1::copyState(const StaState *sta) -{ - GraphDelayCalc::copyState(sta); - // Notify sub-components. - iter_->copyState(sta); -} - -void -GraphDelayCalc1::clear() -{ - delaysInvalid(); - deleteMultiDrvrNets(); - multi_drvr_nets_found_ = false; - GraphDelayCalc::clear(); -} - -float -GraphDelayCalc1::incrementalDelayTolerance() -{ - return incremental_delay_tolerance_; -} - -void -GraphDelayCalc1::setIncrementalDelayTolerance(float tol) -{ - incremental_delay_tolerance_ = tol; -} - -void -GraphDelayCalc1::setObserver(DelayCalcObserver *observer) -{ - delete observer_; - observer_ = observer; -} - -void -GraphDelayCalc1::delaysInvalid() -{ - debugPrint(debug_, "delay_calc", 1, "delays invalid"); - delays_exist_ = false; - delays_seeded_ = false; - incremental_ = false; - iter_->clear(); - // No need to keep track of incremental updates any more. - invalid_delays_->clear(); - invalid_check_edges_.clear(); - invalid_latch_edges_.clear(); -} - -void -GraphDelayCalc1::delayInvalid(const Pin *pin) -{ - if (graph_ && incremental_) { - if (network_->isHierarchical(pin)) { - EdgesThruHierPinIterator edge_iter(pin, network_, graph_); - while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - delayInvalid(edge->from(graph_)); - } - } - else { - Vertex *vertex, *bidirect_drvr_vertex; - graph_->pinVertices(pin, vertex, bidirect_drvr_vertex); - if (vertex) - delayInvalid(vertex); - if (bidirect_drvr_vertex) - delayInvalid(bidirect_drvr_vertex); - } - } -} - -void -GraphDelayCalc1::delayInvalid(Vertex *vertex) -{ - debugPrint(debug_, "delay_calc", 2, "delay invalid %s", - vertex->name(sdc_network_)); - if (graph_ && incremental_) { - invalid_delays_->insert(vertex); - // Invalidate driver that triggers dcalc for multi-driver nets. - MultiDrvrNet *multi_drvr = multiDrvrNet(vertex); - if (multi_drvr) - invalid_delays_->insert(multi_drvr->dcalcDrvr()); - } -} - -void -GraphDelayCalc1::deleteVertexBefore(Vertex *vertex) -{ - iter_->deleteVertexBefore(vertex); - if (incremental_) - invalid_delays_->erase(vertex); - MultiDrvrNet *multi_drvr = multiDrvrNet(vertex); - if (multi_drvr) { - multi_drvr->drvrs()->erase(vertex); - multi_drvr_net_map_.erase(vertex); - } -} - -//////////////////////////////////////////////////////////////// - -class FindVertexDelays : public VertexVisitor -{ -public: - FindVertexDelays(GraphDelayCalc1 *graph_delay_calc1); - virtual ~FindVertexDelays(); - virtual void visit(Vertex *vertex); - virtual VertexVisitor *copy() const; - -protected: - GraphDelayCalc1 *graph_delay_calc1_; - ArcDelayCalc *arc_delay_calc_; -}; - -FindVertexDelays::FindVertexDelays(GraphDelayCalc1 *graph_delay_calc1) : - VertexVisitor(), - graph_delay_calc1_(graph_delay_calc1), - arc_delay_calc_(graph_delay_calc1_->arc_delay_calc_->copy()) -{ -} - -FindVertexDelays::~FindVertexDelays() -{ - delete arc_delay_calc_; -} - -VertexVisitor * -FindVertexDelays::copy() const -{ - // Copy StaState::arc_delay_calc_ because it needs separate state - // for each thread. - return new FindVertexDelays(graph_delay_calc1_); -} - -void -FindVertexDelays::visit(Vertex *vertex) -{ - graph_delay_calc1_->findVertexDelay(vertex, arc_delay_calc_, true); -} - -// The logical structure of incremental delay calculation closely -// resembles the incremental search arrival time algorithm -// (Search::findArrivals). -void -GraphDelayCalc1::findDelays(Level level) -{ - if (arc_delay_calc_) { - Stats stats(debug_, report_); - int dcalc_count = 0; - debugPrint(debug_, "delay_calc", 1, "find delays to level %d", level); - if (!delays_seeded_) { - iter_->clear(); - ensureMultiDrvrNetsFound(); - seedRootSlews(); - delays_seeded_ = true; - } - else - iter_->ensureSize(); - if (incremental_) - seedInvalidDelays(); - - FindVertexDelays visitor(this); - dcalc_count += iter_->visitParallel(level, &visitor); - - // Timing checks require slews at both ends of the arc, - // so find their delays after all slews are known. - 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; - debugPrint(debug_, "delay_calc", 1, "found %d delays", dcalc_count); - stats.report("Delay calc"); - } -} - -void -GraphDelayCalc1::seedInvalidDelays() -{ - for (Vertex *vertex : *invalid_delays_) { - if (vertex->isRoot()) - seedRootSlew(vertex, arc_delay_calc_); - else { - if (search_non_latch_pred_->searchFrom(vertex)) - iter_->enqueue(vertex); - } - } - invalid_delays_->clear(); -} - -class FindNetDrvrs : public PinVisitor -{ -public: - FindNetDrvrs(PinSet &drvr_pins, - const Network *network, - const Graph *graph); - virtual void operator()(const Pin *pin); - -protected: - PinSet &drvr_pins_; - const Network *network_; - const Graph *graph_; -}; - -FindNetDrvrs::FindNetDrvrs(PinSet &drvr_pins, - const Network *network, - const Graph *graph) : - drvr_pins_(drvr_pins), - network_(network), - graph_(graph) -{ -} - -void -FindNetDrvrs::operator()(const Pin *pin) -{ - Vertex *vertex = graph_->pinDrvrVertex(pin); - if (isLeafDriver(pin, network_) - && !(vertex && vertex->isRoot())) - drvr_pins_.insert(pin); -} - -void -GraphDelayCalc1::ensureMultiDrvrNetsFound() -{ - if (!multi_drvr_nets_found_) { - LeafInstanceIterator *inst_iter = network_->leafInstanceIterator(); - while (inst_iter->hasNext()) { - Instance *inst = inst_iter->next(); - InstancePinIterator *pin_iter = network_->pinIterator(inst); - while (pin_iter->hasNext()) { - Pin *pin = pin_iter->next(); - Vertex *drvr_vertex = graph_->pinDrvrVertex(pin); - if (network_->isDriver(pin) - && !multi_drvr_net_map_.hasKey(drvr_vertex)) { - PinSet drvr_pins(network_); - FindNetDrvrs visitor(drvr_pins, network_, graph_); - network_->visitConnectedPins(pin, visitor); - if (drvr_pins.size() > 1) - makeMultiDrvrNet(drvr_pins); - } - } - delete pin_iter; - } - delete inst_iter; - multi_drvr_nets_found_ = true; - } -} - -void -GraphDelayCalc1::makeMultiDrvrNet(PinSet &drvr_pins) -{ - debugPrint(debug_, "delay_calc", 3, "multi-driver net"); - VertexSet *drvr_vertices = new VertexSet(graph_); - MultiDrvrNet *multi_drvr = new MultiDrvrNet(drvr_vertices); - Level max_drvr_level = 0; - Vertex *max_drvr = nullptr; - PinSet::Iterator pin_iter(drvr_pins); - while (pin_iter.hasNext()) { - const Pin *pin = pin_iter.next(); - Vertex *drvr_vertex = graph_->pinDrvrVertex(pin); - debugPrint(debug_, "delay_calc", 3, " %s", - network_->pathName(pin)); - multi_drvr_net_map_[drvr_vertex] = multi_drvr; - drvr_vertices->insert(drvr_vertex); - Level drvr_level = drvr_vertex->level(); - if (max_drvr == nullptr - || drvr_level > max_drvr_level) { - max_drvr = drvr_vertex; - max_drvr_level = drvr_level; - } - } - multi_drvr->setDcalcDrvr(max_drvr); - multi_drvr->findCaps(this, sdc_); -} - -static bool -isLeafDriver(const Pin *pin, - const Network *network) -{ - PortDirection *dir = network->direction(pin); - const Instance *inst = network->instance(pin); - return network->isLeaf(inst) && dir->isAnyOutput(); -} - -MultiDrvrNet * -GraphDelayCalc1::multiDrvrNet(const Vertex *drvr_vertex) const -{ - return multi_drvr_net_map_.findKey(drvr_vertex); -} - -void -GraphDelayCalc1::seedRootSlews() -{ - for (Vertex *vertex : *levelize_->roots()) - seedRootSlew(vertex, arc_delay_calc_); -} - -void -GraphDelayCalc1::seedRootSlew(Vertex *vertex, - ArcDelayCalc *arc_delay_calc) -{ - if (vertex->isDriver(network_)) - seedDrvrSlew(vertex, arc_delay_calc); - else - seedLoadSlew(vertex); - iter_->enqueueAdjacentVertices(vertex); -} - -void -GraphDelayCalc1::seedDrvrSlew(Vertex *drvr_vertex, - ArcDelayCalc *arc_delay_calc) -{ - const Pin *drvr_pin = drvr_vertex->pin(); - debugPrint(debug_, "delay_calc", 2, "seed driver slew %s", - drvr_vertex->name(sdc_network_)); - InputDrive *drive = 0; - if (network_->isTopLevelPort(drvr_pin)) { - Port *port = network_->port(drvr_pin); - drive = sdc_->findInputDrive(port); - } - for (auto rf : RiseFall::range()) { - for (auto dcalc_ap : corners_->dcalcAnalysisPts()) { - if (drive) { - const MinMax *cnst_min_max = dcalc_ap->constraintMinMax(); - const LibertyCell *drvr_cell; - const LibertyPort *from_port, *to_port; - float *from_slews; - drive->driveCell(rf, cnst_min_max, drvr_cell, from_port, - from_slews, to_port); - if (drvr_cell) { - if (from_port == nullptr) - from_port = driveCellDefaultFromPort(drvr_cell, to_port); - findInputDriverDelay(drvr_cell, drvr_pin, drvr_vertex, rf, - from_port, from_slews, to_port, dcalc_ap); - } - else - seedNoDrvrCellSlew(drvr_vertex, drvr_pin, rf, drive, dcalc_ap, - arc_delay_calc); - } - else - seedNoDrvrSlew(drvr_vertex, drvr_pin, rf, dcalc_ap, arc_delay_calc); - } - } -} - -void -GraphDelayCalc1::seedNoDrvrCellSlew(Vertex *drvr_vertex, - const Pin *drvr_pin, - const RiseFall *rf, - InputDrive *drive, - DcalcAnalysisPt *dcalc_ap, - ArcDelayCalc *arc_delay_calc) -{ - DcalcAPIndex ap_index = dcalc_ap->index(); - const MinMax *cnst_min_max = dcalc_ap->constraintMinMax(); - Slew slew = default_slew; - float drive_slew; - bool exists; - drive->slew(rf, cnst_min_max, drive_slew, exists); - if (exists) - slew = drive_slew; - else { - // Top level bidirect driver uses load slew unless - // bidirect instance paths are disabled. - if (sdc_->bidirectDrvrSlewFromLoad(drvr_pin)) { - Vertex *load_vertex = graph_->pinLoadVertex(drvr_pin); - slew = graph_->slew(load_vertex, rf, ap_index); - } - } - Delay drive_delay = delay_zero; - float drive_res; - drive->driveResistance(rf, cnst_min_max, drive_res, exists); - Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin, rf, dcalc_ap); - if (exists) { - float cap = loadCap(drvr_pin, parasitic, rf, dcalc_ap); - drive_delay = cap * drive_res; - slew = cap * drive_res; - } - const MinMax *slew_min_max = dcalc_ap->slewMinMax(); - if (!drvr_vertex->slewAnnotated(rf, slew_min_max)) - graph_->setSlew(drvr_vertex, rf, ap_index, slew); - arc_delay_calc->inputPortDelay(drvr_pin, delayAsFloat(slew), rf, - parasitic, dcalc_ap); - annotateLoadDelays(drvr_vertex, rf, drive_delay, false, dcalc_ap, - arc_delay_calc); - arc_delay_calc->finishDrvrPin(); -} - -void -GraphDelayCalc1::seedNoDrvrSlew(Vertex *drvr_vertex, - const Pin *drvr_pin, - const RiseFall *rf, - DcalcAnalysisPt *dcalc_ap, - ArcDelayCalc *arc_delay_calc) -{ - const MinMax *slew_min_max = dcalc_ap->slewMinMax(); - DcalcAPIndex ap_index = dcalc_ap->index(); - Slew slew(default_slew); - // Top level bidirect driver uses load slew unless - // bidirect instance paths are disabled. - if (sdc_->bidirectDrvrSlewFromLoad(drvr_pin)) { - Vertex *load_vertex = graph_->pinLoadVertex(drvr_pin); - slew = graph_->slew(load_vertex, rf, ap_index); - } - if (!drvr_vertex->slewAnnotated(rf, slew_min_max)) - graph_->setSlew(drvr_vertex, rf, ap_index, slew); - Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin, rf, dcalc_ap); - arc_delay_calc->inputPortDelay(drvr_pin, delayAsFloat(slew), rf, - parasitic, dcalc_ap); - annotateLoadDelays(drvr_vertex, rf, delay_zero, false, dcalc_ap, - arc_delay_calc); - arc_delay_calc->finishDrvrPin(); -} - -void -GraphDelayCalc1::seedLoadSlew(Vertex *vertex) -{ - const Pin *pin = vertex->pin(); - debugPrint(debug_, "delay_calc", 2, "seed load slew %s", - vertex->name(sdc_network_)); - ClockSet *clks = sdc_->findLeafPinClocks(pin); - initSlew(vertex); - for (auto rf : RiseFall::range()) { - for (auto dcalc_ap : corners_->dcalcAnalysisPts()) { - const MinMax *slew_min_max = dcalc_ap->slewMinMax(); - if (!vertex->slewAnnotated(rf, slew_min_max)) { - float slew = 0.0; - if (clks) { - slew = slew_min_max->initValue(); - ClockSet::Iterator clk_iter(clks); - while (clk_iter.hasNext()) { - Clock *clk = clk_iter.next(); - float clk_slew = clk->slew(rf, slew_min_max); - if (slew_min_max->compare(clk_slew, slew)) - slew = clk_slew; - } - } - DcalcAPIndex ap_index = dcalc_ap->index(); - graph_->setSlew(vertex, rf, ap_index, slew); - } - } - } -} - -// If a driving cell does not specify a -from_pin, the first port -// defined in the cell that has a timing group to the output port -// is used. Not exactly reasonable, but it's compatible. -LibertyPort * -GraphDelayCalc1::driveCellDefaultFromPort(const LibertyCell *cell, - const LibertyPort *to_port) -{ - LibertyPort *from_port = 0; - int from_port_index = 0; - for (TimingArcSet *arc_set : cell->timingArcSets(nullptr, to_port)) { - LibertyPort *set_from_port = arc_set->from(); - int set_from_port_index = findPortIndex(cell, set_from_port); - if (from_port == nullptr - || set_from_port_index < from_port_index) { - from_port = set_from_port; - from_port_index = set_from_port_index; - } - } - return from_port; -} - -// Find the index that port is defined in cell. -int -GraphDelayCalc1::findPortIndex(const LibertyCell *cell, - const LibertyPort *port) -{ - int index = 0; - LibertyCellPortIterator port_iter(cell); - while (port_iter.hasNext()) { - LibertyPort *cell_port = port_iter.next(); - if (cell_port == port) - return index; - index++; - } - report_->critical(207, "port not found in cell"); - return 0; -} - -void -GraphDelayCalc1::findInputDriverDelay(const LibertyCell *drvr_cell, - const Pin *drvr_pin, - Vertex *drvr_vertex, - const RiseFall *rf, - const LibertyPort *from_port, - float *from_slews, - const LibertyPort *to_port, - const DcalcAnalysisPt *dcalc_ap) -{ - debugPrint(debug_, "delay_calc", 2, " driver cell %s %s", - drvr_cell->name(), - rf->asString()); - for (TimingArcSet *arc_set : drvr_cell->timingArcSets(from_port, to_port)) { - for (TimingArc *arc : arc_set->arcs()) { - if (arc->toEdge()->asRiseFall() == rf) { - float from_slew = from_slews[arc->fromEdge()->index()]; - findInputArcDelay(drvr_cell, drvr_pin, drvr_vertex, - arc, from_slew, dcalc_ap); - } - } - } -} - -// Driving cell delay is the load dependent delay, which is the gate -// delay minus the intrinsic delay. Driving cell delays are annotated -// to the wire arcs from the input port pin to the load pins. -void -GraphDelayCalc1::findInputArcDelay(const LibertyCell *drvr_cell, - const Pin *drvr_pin, - Vertex *drvr_vertex, - const TimingArc *arc, - float from_slew, - const DcalcAnalysisPt *dcalc_ap) -{ - debugPrint(debug_, "delay_calc", 3, " %s %s -> %s %s (%s)", - arc->from()->name(), - arc->fromEdge()->asString(), - arc->to()->name(), - arc->toEdge()->asString(), - arc->role()->asString()); - RiseFall *drvr_rf = arc->toEdge()->asRiseFall(); - if (drvr_rf) { - DcalcAPIndex ap_index = dcalc_ap->index(); - const Pvt *pvt = dcalc_ap->operatingConditions(); - Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, - dcalc_ap); - float load_cap = loadCap(drvr_pin, drvr_parasitic, drvr_rf, dcalc_ap); - - ArcDelay intrinsic_delay; - Slew intrinsic_slew; - arc_delay_calc_->gateDelay(drvr_cell, arc, Slew(from_slew), - 0.0, 0, 0.0, pvt, dcalc_ap, - intrinsic_delay, intrinsic_slew); - - // For input drivers there is no instance to find a related_output_pin. - ArcDelay gate_delay; - Slew gate_slew; - arc_delay_calc_->gateDelay(drvr_cell, arc, - Slew(from_slew), load_cap, - drvr_parasitic, 0.0, pvt, dcalc_ap, - gate_delay, gate_slew); - ArcDelay load_delay = gate_delay - intrinsic_delay; - debugPrint(debug_, "delay_calc", 3, - " gate delay = %s intrinsic = %s slew = %s", - delayAsString(gate_delay, this), - delayAsString(intrinsic_delay, this), - delayAsString(gate_slew, this)); - graph_->setSlew(drvr_vertex, drvr_rf, ap_index, gate_slew); - annotateLoadDelays(drvr_vertex, drvr_rf, load_delay, false, dcalc_ap, - arc_delay_calc_); - } -} - -void -GraphDelayCalc1::findDelays(Vertex *drvr_vertex) -{ - findVertexDelay(drvr_vertex, arc_delay_calc_, true); -} - -void -GraphDelayCalc1::findVertexDelay(Vertex *vertex, - ArcDelayCalc *arc_delay_calc, - bool propagate) -{ - const Pin *pin = vertex->pin(); - debugPrint(debug_, "delay_calc", 2, "find delays %s (%s)", - vertex->name(sdc_network_), - network_->cellName(network_->instance(pin))); - if (vertex->isRoot()) { - seedRootSlew(vertex, arc_delay_calc); - if (propagate) - iter_->enqueueAdjacentVertices(vertex); - } - else { - if (network_->isLeaf(pin)) { - if (vertex->isDriver(network_)) { - bool delay_changed = findDriverDelays(vertex, arc_delay_calc); - if (propagate) { - if (network_->direction(pin)->isInternal()) - enqueueTimingChecksEdges(vertex); - // Enqueue adjacent vertices even if the delays did not - // change when non-incremental to stride past annotations. - if (delay_changed || !incremental_) - iter_->enqueueAdjacentVertices(vertex); - } - } - else { - // Load vertex. - enqueueTimingChecksEdges(vertex); - // Enqueue driver vertices from this input load. - if (propagate) - iter_->enqueueAdjacentVertices(vertex); - } - } - // Bidirect port drivers are enqueued by their load vertex in - // annotateLoadDelays. - else if (vertex->isBidirectDriver() - && network_->isTopLevelPort(pin)) - seedRootSlew(vertex, arc_delay_calc); - } -} - -void -GraphDelayCalc1::enqueueTimingChecksEdges(Vertex *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); - } - } -} - -bool -GraphDelayCalc1::findDriverDelays(Vertex *drvr_vertex, - ArcDelayCalc *arc_delay_calc) -{ - bool delay_changed = false; - MultiDrvrNet *multi_drvr = multiDrvrNet(drvr_vertex); - if (multi_drvr) { - Vertex *dcalc_drvr = multi_drvr->dcalcDrvr(); - if (drvr_vertex == dcalc_drvr) { - bool init_load_slews = true; - for (Vertex *drvr_vertex : *multi_drvr->drvrs()) { - // Only init load slews once so previous driver dcalc results - // aren't clobbered. - delay_changed |= findDriverDelays1(drvr_vertex, init_load_slews, - multi_drvr, arc_delay_calc); - init_load_slews = false; - } - } - } - else - delay_changed = findDriverDelays1(drvr_vertex, true, nullptr, arc_delay_calc); - arc_delay_calc->finishDrvrPin(); - return delay_changed; -} - -bool -GraphDelayCalc1::findDriverDelays1(Vertex *drvr_vertex, - bool init_load_slews, - MultiDrvrNet *multi_drvr, - ArcDelayCalc *arc_delay_calc) -{ - const Pin *drvr_pin = drvr_vertex->pin(); - Instance *drvr_inst = network_->instance(drvr_pin); - LibertyCell *drvr_cell = network_->libertyCell(drvr_inst); - 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) - && !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; -} - -// Init slews to zero on root vertices that are not inputs, such as -// floating input pins. -void -GraphDelayCalc1::initRootSlews(Vertex *vertex) -{ - for (auto dcalc_ap : corners_->dcalcAnalysisPts()) { - const MinMax *slew_min_max = dcalc_ap->slewMinMax(); - DcalcAPIndex ap_index = dcalc_ap->index(); - for (auto rf : RiseFall::range()) { - if (!vertex->slewAnnotated(rf, slew_min_max)) - graph_->setSlew(vertex, rf, ap_index, default_slew); - } - } -} - -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, - const Pin *drvr_pin, - Vertex *drvr_vertex, - MultiDrvrNet *multi_drvr, - Edge *edge, - ArcDelayCalc *arc_delay_calc) -{ - Vertex *in_vertex = edge->from(graph_); - TimingArcSet *arc_set = edge->timingArcSet(); - const LibertyPort *related_out_port = arc_set->relatedOut(); - const Pin *related_out_pin = 0; - bool delay_changed = false; - if (related_out_port) - related_out_pin = network_->findPin(drvr_inst, related_out_port); - for (auto dcalc_ap : corners_->dcalcAnalysisPts()) { - const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax()); - if (pvt == nullptr) - pvt = dcalc_ap->operatingConditions(); - for (TimingArc *arc : arc_set->arcs()) { - const RiseFall *rf = arc->toEdge()->asRiseFall(); - Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin, rf, - dcalc_ap); - float related_out_cap = 0.0; - if (related_out_pin) { - Parasitic *related_out_parasitic = - arc_delay_calc->findParasitic(related_out_pin, rf, dcalc_ap); - related_out_cap = loadCap(related_out_pin, - related_out_parasitic, - rf, dcalc_ap); - } - delay_changed |= findArcDelay(drvr_cell, drvr_pin, drvr_vertex, - multi_drvr, arc, parasitic, - related_out_cap, - in_vertex, edge, pvt, dcalc_ap, - arc_delay_calc); - } - } - - if (delay_changed && observer_) { - observer_->delayChangedFrom(in_vertex); - observer_->delayChangedFrom(drvr_vertex); - } - return delay_changed; -} - -float -GraphDelayCalc1::loadCap(const Pin *drvr_pin, - const DcalcAnalysisPt *dcalc_ap) const -{ - const MinMax *min_max = dcalc_ap->constraintMinMax(); - float load_cap = 0.0; - for (auto drvr_rf : RiseFall::range()) { - Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, - dcalc_ap); - float cap = loadCap(drvr_pin, nullptr, drvr_parasitic, drvr_rf, dcalc_ap); - arc_delay_calc_->finishDrvrPin(); - if (min_max->compare(cap, load_cap)) - load_cap = cap; - } - return load_cap; -} - -float -GraphDelayCalc1::loadCap(const Pin *drvr_pin, - const RiseFall *drvr_rf, - const DcalcAnalysisPt *dcalc_ap) const -{ - Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, - dcalc_ap); - float cap = loadCap(drvr_pin, nullptr, drvr_parasitic, drvr_rf, dcalc_ap); - return cap; -} - -float -GraphDelayCalc1::loadCap(const Pin *drvr_pin, - const Parasitic *drvr_parasitic, - const RiseFall *rf, - const DcalcAnalysisPt *dcalc_ap) const -{ - return loadCap(drvr_pin, nullptr, drvr_parasitic, rf, dcalc_ap); -} - -float -GraphDelayCalc1::loadCap(const Pin *drvr_pin, - MultiDrvrNet *multi_drvr, - const Parasitic *drvr_parasitic, - const RiseFall *rf, - const DcalcAnalysisPt *dcalc_ap) const -{ - float pin_cap, wire_cap; - bool has_net_load; - float fanout; - if (multi_drvr) - multi_drvr->netCaps(rf, dcalc_ap, - pin_cap, wire_cap, fanout, has_net_load); - else - netCaps(drvr_pin, rf, dcalc_ap, - pin_cap, wire_cap, fanout, has_net_load); - loadCap(drvr_parasitic, has_net_load, pin_cap, wire_cap); - return wire_cap + pin_cap; -} - -void -GraphDelayCalc1::loadCap(const Pin *drvr_pin, - const Parasitic *drvr_parasitic, - const RiseFall *rf, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - float &pin_cap, - float &wire_cap) const -{ - bool has_net_load; - float fanout; - // Find pin and external pin/wire capacitance. - netCaps(drvr_pin, rf, dcalc_ap, - pin_cap, wire_cap, fanout, has_net_load); - loadCap(drvr_parasitic, has_net_load, pin_cap, wire_cap); -} - -void -GraphDelayCalc1::loadCap(const Parasitic *drvr_parasitic, - bool has_net_load, - // Return values. - float &pin_cap, - float &wire_cap) const -{ - // set_load net has precidence over parasitics. - if (!has_net_load && drvr_parasitic) { - if (parasitics_->isParasiticNetwork(drvr_parasitic)) - wire_cap += parasitics_->capacitance(drvr_parasitic); - else { - // PiModel includes both pin and external caps. - float cap = parasitics_->capacitance(drvr_parasitic); - if (pin_cap > cap) { - pin_cap = 0.0; - wire_cap = cap; - } - else - wire_cap = cap - pin_cap; - } - } -} - -void -GraphDelayCalc1::netCaps(const Pin *drvr_pin, - const RiseFall *rf, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - float &pin_cap, - float &wire_cap, - float &fanout, - bool &has_net_load) const -{ - MultiDrvrNet *multi_drvr = nullptr; - if (graph_) { - Vertex *drvr_vertex = graph_->pinDrvrVertex(drvr_pin); - multi_drvr = multiDrvrNet(drvr_vertex); - } - if (multi_drvr) - multi_drvr->netCaps(rf, dcalc_ap, - pin_cap, wire_cap, fanout, has_net_load); - else { - const OperatingConditions *op_cond = dcalc_ap->operatingConditions(); - const Corner *corner = dcalc_ap->corner(); - const MinMax *min_max = dcalc_ap->constraintMinMax(); - // Find pin and external pin/wire capacitance. - sdc_->connectedCap(drvr_pin, rf, op_cond, corner, min_max, - pin_cap, wire_cap, fanout, has_net_load); - } -} - -void -GraphDelayCalc1::initSlew(Vertex *vertex) -{ - for (auto rf : RiseFall::range()) { - for (auto dcalc_ap : corners_->dcalcAnalysisPts()) { - const MinMax *slew_min_max = dcalc_ap->slewMinMax(); - if (!vertex->slewAnnotated(rf, slew_min_max)) { - DcalcAPIndex ap_index = dcalc_ap->index(); - graph_->setSlew(vertex, rf, ap_index, slew_min_max->initValue()); - } - } - } -} - -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 rf : RiseFall::range()) { - // Init drvr slew. - if (!drvr_vertex->slewAnnotated(rf, slew_min_max)) { - DcalcAPIndex ap_index = dcalc_ap->index(); - graph_->setSlew(drvr_vertex, rf, 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, rf, ap_index)) - graph_->setWireArcDelay(wire_edge, rf, ap_index, 0.0); - // Init load vertex slew. - if (!load_vertex->slewAnnotated(rf, slew_min_max)) - graph_->setSlew(load_vertex, rf, ap_index, 0.0); - } - } - } - } -} - -// Init wire delays and load slews. -void -GraphDelayCalc1::initWireDelays(Vertex *drvr_vertex, - bool init_load_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_); - for (auto dcalc_ap : corners_->dcalcAnalysisPts()) { - const MinMax *delay_min_max = dcalc_ap->delayMinMax(); - const MinMax *slew_min_max = dcalc_ap->slewMinMax(); - Delay delay_init_value(delay_min_max->initValue()); - Slew slew_init_value(slew_min_max->initValue()); - DcalcAPIndex ap_index = dcalc_ap->index(); - 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(rf, slew_min_max)) - graph_->setSlew(load_vertex, rf, ap_index, slew_init_value); - } - } - } - } -} - -// Call the arc delay calculator to find the delay thru a single gate -// input to output timing arc, the wire delays from the gate output to -// each load pin, and the slew at each load pin. Annotate the graph -// with the results. -bool -GraphDelayCalc1::findArcDelay(LibertyCell *drvr_cell, - const Pin *drvr_pin, - Vertex *drvr_vertex, - MultiDrvrNet *multi_drvr, - TimingArc *arc, - Parasitic *drvr_parasitic, - float related_out_cap, - Vertex *from_vertex, - Edge *edge, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - ArcDelayCalc *arc_delay_calc) -{ - bool delay_changed = false; - RiseFall *from_rf = arc->fromEdge()->asRiseFall(); - RiseFall *drvr_rf = arc->toEdge()->asRiseFall(); - if (from_rf && drvr_rf) { - DcalcAPIndex ap_index = dcalc_ap->index(); - debugPrint(debug_, "delay_calc", 3, - " %s %s -> %s %s (%s) corner:%s/%s", - arc->from()->name(), - arc->fromEdge()->asString(), - arc->to()->name(), - arc->toEdge()->asString(), - arc->role()->asString(), - dcalc_ap->corner()->name(), - dcalc_ap->delayMinMax()->asString()); - // Delay calculation is done even when the gate delays/slews are - // annotated because the wire delays may not be annotated. - const Slew from_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap); - ArcDelay gate_delay; - Slew gate_slew; - if (multi_drvr - && arc->to()->direction()->isOutput()) - parallelGateDelay(multi_drvr, drvr_cell, drvr_pin, arc, - pvt, dcalc_ap, from_slew, drvr_parasitic, - related_out_cap, - arc_delay_calc, - gate_delay, gate_slew); - else { - float load_cap = loadCap(drvr_pin, multi_drvr, drvr_parasitic, - drvr_rf, dcalc_ap); - arc_delay_calc->gateDelay(drvr_cell, arc, - from_slew, load_cap, drvr_parasitic, - related_out_cap, pvt, dcalc_ap, - gate_delay, gate_slew); - } - debugPrint(debug_, "delay_calc", 3, - " gate delay = %s slew = %s", - delayAsString(gate_delay, this), - delayAsString(gate_slew, this)); - // Merge slews. - 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) - && !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); - float gate_delay1 = delayAsFloat(gate_delay); - float prev_gate_delay1 = delayAsFloat(prev_gate_delay); - if (prev_gate_delay1 == 0.0 - || (abs(gate_delay1 - prev_gate_delay1) / prev_gate_delay1 - > incremental_delay_tolerance_)) - delay_changed = true; - graph_->setArcDelay(edge, arc, ap_index, gate_delay); - } - if (!edge->role()->isLatchDtoQ()) - annotateLoadDelays(drvr_vertex, drvr_rf, delay_zero, true, dcalc_ap, - arc_delay_calc); - } - return delay_changed; -} - -void -GraphDelayCalc1::parallelGateDelay(MultiDrvrNet *multi_drvr, - LibertyCell *drvr_cell, - const Pin *drvr_pin, - TimingArc *arc, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - const Slew from_slew, - Parasitic *drvr_parasitic, - float related_out_cap, - ArcDelayCalc *arc_delay_calc, - // Return values. - ArcDelay &gate_delay, - Slew &gate_slew) -{ - ArcDelay intrinsic_delay; - Slew intrinsic_slew; - arc_delay_calc->gateDelay(drvr_cell, arc, from_slew, - 0.0, 0, 0.0, pvt, dcalc_ap, - intrinsic_delay, intrinsic_slew); - ArcDelay parallel_delay; - Slew parallel_slew; - const RiseFall *drvr_rf = arc->toEdge()->asRiseFall(); - multi_drvr->parallelDelaySlew(drvr_rf, dcalc_ap, arc_delay_calc, this, - parallel_delay, parallel_slew); - - gate_delay = parallel_delay + intrinsic_delay; - gate_slew = parallel_slew; - - float load_cap = loadCap(drvr_pin, multi_drvr, drvr_parasitic, - drvr_rf, dcalc_ap); - Delay gate_delay1; - Slew gate_slew1; - arc_delay_calc->gateDelay(drvr_cell, arc, - from_slew, load_cap, drvr_parasitic, - related_out_cap, pvt, dcalc_ap, - gate_delay1, gate_slew1); - float factor = delayRatio(gate_slew, gate_slew1); - arc_delay_calc->setMultiDrvrSlewFactor(factor); -} - -void -GraphDelayCalc1::findMultiDrvrGateDelay(MultiDrvrNet *multi_drvr, - const RiseFall *drvr_rf, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - ArcDelayCalc *arc_delay_calc, - // Return values. - ArcDelay ¶llel_delay, - Slew ¶llel_slew) -{ - ArcDelay delay_sum = 1.0; - Slew slew_sum = 1.0; - for (Vertex *drvr_vertex1 : *multi_drvr->drvrs()) { - Pin *drvr_pin1 = drvr_vertex1->pin(); - Instance *drvr_inst1 = network_->instance(drvr_pin1); - LibertyCell *drvr_cell1 = network_->libertyCell(drvr_inst1); - if (network_->isDriver(drvr_pin1)) { - VertexInEdgeIterator edge_iter(drvr_vertex1, graph_); - while (edge_iter.hasNext()) { - Edge *edge1 = edge_iter.next(); - TimingArcSet *arc_set1 = edge1->timingArcSet(); - const LibertyPort *related_out_port = arc_set1->relatedOut(); - for (TimingArc *arc1 : arc_set1->arcs()) { - RiseFall *drvr_rf1 = arc1->toEdge()->asRiseFall(); - if (drvr_rf1 == drvr_rf) { - Vertex *from_vertex1 = edge1->from(graph_); - RiseFall *from_rf1 = arc1->fromEdge()->asRiseFall(); - Slew from_slew1 = edgeFromSlew(from_vertex1, from_rf1, edge1, dcalc_ap); - ArcDelay intrinsic_delay1; - Slew intrinsic_slew1; - arc_delay_calc->gateDelay(drvr_cell1, arc1, from_slew1, - 0.0, 0, 0.0, pvt, dcalc_ap, - intrinsic_delay1, intrinsic_slew1); - Parasitic *parasitic1 = - arc_delay_calc->findParasitic(drvr_pin1, drvr_rf1, dcalc_ap); - const Pin *related_out_pin1 = 0; - float related_out_cap1 = 0.0; - if (related_out_port) { - Instance *inst1 = network_->instance(drvr_pin1); - related_out_pin1 = network_->findPin(inst1, related_out_port); - if (related_out_pin1) { - Parasitic *related_out_parasitic1 = - arc_delay_calc->findParasitic(related_out_pin1, drvr_rf, - dcalc_ap); - related_out_cap1 = loadCap(related_out_pin1, - related_out_parasitic1, - drvr_rf, dcalc_ap); - } - } - float load_cap1 = loadCap(drvr_pin1, parasitic1, - drvr_rf, dcalc_ap); - ArcDelay gate_delay1; - Slew gate_slew1; - arc_delay_calc->gateDelay(drvr_cell1, arc1, - from_slew1, load_cap1, parasitic1, - related_out_cap1, pvt, dcalc_ap, - gate_delay1, gate_slew1); - delay_sum += 1.0F / (gate_delay1 - intrinsic_delay1); - slew_sum += 1.0F / gate_slew1; - } - } - } - } - } - parallel_delay = 1.0F / delay_sum; - parallel_slew = 1.0F / slew_sum; -} - -// Use clock slew for register/latch clk->q edges. -Slew -GraphDelayCalc1::edgeFromSlew(const Vertex *from_vertex, - const RiseFall *from_rf, - const Edge *edge, - const DcalcAnalysisPt *dcalc_ap) -{ - const TimingRole *role = edge->role(); - if (role->genericRole() == TimingRole::regClkToQ() - && clk_network_->isIdealClock(from_vertex->pin())) - return clk_network_->idealClkSlew(from_vertex->pin(), from_rf, - dcalc_ap->slewMinMax()); - else - return graph_->slew(from_vertex, from_rf, dcalc_ap->index()); -} - -// Annotate wire arc delays and load pin slews. -// extra_delay is additional wire delay to add to delay returned -// by the delay calculator. -void -GraphDelayCalc1::annotateLoadDelays(Vertex *drvr_vertex, - const RiseFall *drvr_rf, - const ArcDelay &extra_delay, - bool merge, - const DcalcAnalysisPt *dcalc_ap, - ArcDelayCalc *arc_delay_calc) -{ - DcalcAPIndex ap_index = dcalc_ap->index(); - const MinMax *slew_min_max = dcalc_ap->slewMinMax(); - 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_); - Pin *load_pin = load_vertex->pin(); - ArcDelay wire_delay; - Slew load_slew; - arc_delay_calc->loadDelay(load_pin, wire_delay, load_slew); - debugPrint(debug_, "delay_calc", 3, - " %s load delay = %s slew = %s", - load_vertex->name(sdc_network_), - delayAsString(wire_delay, this), - delayAsString(load_slew, this)); - if (!load_vertex->slewAnnotated(drvr_rf, slew_min_max)) { - if (drvr_vertex->slewAnnotated(drvr_rf, slew_min_max)) { - // Copy the driver slew to the load if it is annotated. - const Slew &drvr_slew = graph_->slew(drvr_vertex,drvr_rf,ap_index); - graph_->setSlew(load_vertex, drvr_rf, ap_index, drvr_slew); - } - else { - const Slew &slew = graph_->slew(load_vertex, drvr_rf, ap_index); - if (!merge - || delayGreater(load_slew, slew, slew_min_max, this)) - graph_->setSlew(load_vertex, drvr_rf, ap_index, load_slew); - } - } - if (!graph_->wireDelayAnnotated(wire_edge, drvr_rf, ap_index)) { - // Multiple timing arcs with the same output transition - // annotate the same wire edges so they must be combined - // rather than set. - const ArcDelay &delay = graph_->wireArcDelay(wire_edge, drvr_rf, - ap_index); - Delay wire_delay_extra = extra_delay + wire_delay; - const MinMax *delay_min_max = dcalc_ap->delayMinMax(); - if (!merge - || delayGreater(wire_delay_extra, delay, delay_min_max, this)) { - graph_->setWireArcDelay(wire_edge, drvr_rf, ap_index, - wire_delay_extra); - if (observer_) - observer_->delayChangedTo(load_vertex); - } - } - // Enqueue bidirect driver from load vertex. - if (sdc_->bidirectDrvrSlewFromLoad(load_pin)) - iter_->enqueue(graph_->pinDrvrVertex(load_pin)); - } - } -} - -void -GraphDelayCalc1::findCheckEdgeDelays(Edge *edge, - ArcDelayCalc *arc_delay_calc) -{ - Vertex *from_vertex = edge->from(graph_); - Vertex *to_vertex = edge->to(graph_); - TimingArcSet *arc_set = edge->timingArcSet(); - 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; - for (TimingArc *arc : arc_set->arcs()) { - RiseFall *from_rf = arc->fromEdge()->asRiseFall(); - RiseFall *to_rf = arc->toEdge()->asRiseFall(); - if (from_rf && to_rf) { - const LibertyPort *related_out_port = arc_set->relatedOut(); - const Pin *related_out_pin = 0; - if (related_out_port) - related_out_pin = network_->findPin(inst, related_out_port); - for (auto dcalc_ap : corners_->dcalcAnalysisPts()) { - DcalcAPIndex ap_index = dcalc_ap->index(); - if (!graph_->arcDelayAnnotated(edge, arc, ap_index)) { - const Pvt *pvt = sdc_->pvt(inst,dcalc_ap->constraintMinMax()); - if (pvt == nullptr) - pvt = dcalc_ap->operatingConditions(); - const Slew &from_slew = checkEdgeClkSlew(from_vertex, from_rf, - dcalc_ap); - int slew_index = dcalc_ap->checkDataSlewIndex(); - const Slew &to_slew = graph_->slew(to_vertex, to_rf, slew_index); - debugPrint(debug_, "delay_calc", 3, - " %s %s -> %s %s (%s)", - arc_set->from()->name(), - arc->fromEdge()->asString(), - arc_set->to()->name(), - arc->toEdge()->asString(), - arc_set->role()->asString()); - debugPrint(debug_, "delay_calc", 3, - " from_slew = %s to_slew = %s", - delayAsString(from_slew, this), - delayAsString(to_slew, this)); - float related_out_cap = 0.0; - if (related_out_pin) { - Parasitic *related_out_parasitic = - arc_delay_calc->findParasitic(related_out_pin, to_rf, dcalc_ap); - related_out_cap = loadCap(related_out_pin, - related_out_parasitic, - to_rf, dcalc_ap); - } - ArcDelay check_delay; - arc_delay_calc->checkDelay(cell, arc, - from_slew, to_slew, - related_out_cap, - pvt, dcalc_ap, - check_delay); - debugPrint(debug_, "delay_calc", 3, - " check_delay = %s", - delayAsString(check_delay, this)); - graph_->setArcDelay(edge, arc, ap_index, check_delay); - delay_changed = true; - } - } - } - } - - if (delay_changed && observer_) - observer_->checkDelayChangedTo(to_vertex); -} - -// Use clock slew for timing check clock edges. -Slew -GraphDelayCalc1::checkEdgeClkSlew(const Vertex *from_vertex, - const RiseFall *from_rf, - const DcalcAnalysisPt *dcalc_ap) -{ - if (clk_network_->isIdealClock(from_vertex->pin())) - return clk_network_->idealClkSlew(from_vertex->pin(), from_rf, - dcalc_ap->checkClkSlewMinMax()); - else - return graph_->slew(from_vertex, from_rf, dcalc_ap->checkClkSlewIndex()); -} - -//////////////////////////////////////////////////////////////// - -float -GraphDelayCalc1::ceff(Edge *edge, - TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap) -{ - Vertex *from_vertex = edge->from(graph_); - Vertex *to_vertex = edge->to(graph_); - Pin *to_pin = to_vertex->pin(); - Instance *inst = network_->instance(to_pin); - LibertyCell *cell = network_->libertyCell(inst); - TimingArcSet *arc_set = edge->timingArcSet(); - float ceff = 0.0; - const Pvt *pvt = sdc_->pvt(inst, dcalc_ap->constraintMinMax()); - if (pvt == nullptr) - pvt = dcalc_ap->operatingConditions(); - RiseFall *from_rf = arc->fromEdge()->asRiseFall(); - RiseFall *to_rf = arc->toEdge()->asRiseFall(); - if (from_rf && to_rf) { - const LibertyPort *related_out_port = arc_set->relatedOut(); - const Pin *related_out_pin = 0; - if (related_out_port) - related_out_pin = network_->findPin(inst, related_out_port); - float related_out_cap = 0.0; - if (related_out_pin) { - Parasitic *related_out_parasitic = - arc_delay_calc_->findParasitic(related_out_pin, to_rf, dcalc_ap); - related_out_cap = loadCap(related_out_pin, related_out_parasitic, - to_rf, dcalc_ap); - } - Parasitic *to_parasitic = arc_delay_calc_->findParasitic(to_pin, to_rf, - dcalc_ap); - const Slew &from_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap); - float load_cap = loadCap(to_pin, to_parasitic, to_rf, dcalc_ap); - ceff = arc_delay_calc_->ceff(cell, arc, - from_slew, load_cap, to_parasitic, - related_out_cap, pvt, dcalc_ap); - arc_delay_calc_->finishDrvrPin(); - } - return ceff; -} - -//////////////////////////////////////////////////////////////// - -string -GraphDelayCalc1::reportDelayCalc(Edge *edge, - TimingArc *arc, - const Corner *corner, - const MinMax *min_max, - int digits) -{ - Vertex *from_vertex = edge->from(graph_); - Vertex *to_vertex = edge->to(graph_); - Pin *to_pin = to_vertex->pin(); - TimingRole *role = arc->role(); - Instance *inst = network_->instance(to_pin); - LibertyCell *cell = network_->libertyCell(inst); - TimingArcSet *arc_set = edge->timingArcSet(); - string result; - DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); - const Pvt *pvt = sdc_->pvt(inst, dcalc_ap->constraintMinMax()); - if (pvt == nullptr) - pvt = dcalc_ap->operatingConditions(); - RiseFall *from_rf = arc->fromEdge()->asRiseFall(); - RiseFall *to_rf = arc->toEdge()->asRiseFall(); - if (from_rf && to_rf) { - const LibertyPort *related_out_port = arc_set->relatedOut(); - const Pin *related_out_pin = 0; - if (related_out_port) - related_out_pin = network_->findPin(inst, related_out_port); - float related_out_cap = 0.0; - if (related_out_pin) { - Parasitic *related_out_parasitic = - arc_delay_calc_->findParasitic(related_out_pin, to_rf, dcalc_ap); - related_out_cap = loadCap(related_out_pin, related_out_parasitic, - to_rf, dcalc_ap); - } - if (role->isTimingCheck()) { - const Slew &from_slew = checkEdgeClkSlew(from_vertex, from_rf, dcalc_ap); - int slew_index = dcalc_ap->checkDataSlewIndex(); - const Slew &to_slew = graph_->slew(to_vertex, to_rf, slew_index); - bool from_ideal_clk = clk_network_->isIdealClock(from_vertex->pin()); - const char *from_slew_annotation = from_ideal_clk ? " (ideal clock)" : nullptr; - result = arc_delay_calc_->reportCheckDelay(cell, arc, from_slew, - from_slew_annotation, to_slew, - related_out_cap, pvt, dcalc_ap, - digits); - } - else { - Parasitic *to_parasitic = - arc_delay_calc_->findParasitic(to_pin, to_rf, dcalc_ap); - const Slew &from_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap); - float load_cap = loadCap(to_pin, to_parasitic, to_rf, dcalc_ap); - result = arc_delay_calc_->reportGateDelay(cell, arc, - from_slew, load_cap, to_parasitic, - related_out_cap, pvt, dcalc_ap, digits); - } - arc_delay_calc_->finishDrvrPin(); - } - return result; -} - -} // namespace diff --git a/dcalc/GraphDelayCalc1.hh b/dcalc/GraphDelayCalc1.hh deleted file mode 100644 index 84189dcb..00000000 --- a/dcalc/GraphDelayCalc1.hh +++ /dev/null @@ -1,236 +0,0 @@ -// OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#pragma once - -#include - -#include "Delay.hh" -#include "GraphDelayCalc.hh" - -namespace sta { - -class MultiDrvrNet; -class FindVertexDelays; -class Corner; - -typedef Map MultiDrvrNetMap; - -// This class traverses the graph calling the arc delay calculator and -// annotating delays on graph edges. -class GraphDelayCalc1 : public GraphDelayCalc -{ -public: - GraphDelayCalc1(StaState *sta); - virtual ~GraphDelayCalc1(); - virtual void copyState(const StaState *sta); - virtual void delaysInvalid(); - virtual void delayInvalid(Vertex *vertex); - virtual void delayInvalid(const Pin *pin); - virtual void deleteVertexBefore(Vertex *vertex); - virtual void clear(); - virtual void findDelays(Level level); - virtual void findDelays(Vertex *drvr_vertex); - virtual string reportDelayCalc(Edge *edge, - TimingArc *arc, - const Corner *corner, - const MinMax *min_max, - int digits); - virtual float incrementalDelayTolerance(); - virtual void setIncrementalDelayTolerance(float tol); - virtual void setObserver(DelayCalcObserver *observer); - // Load pin_cap + wire_cap. - virtual float loadCap(const Pin *drvr_pin, - const RiseFall *drvr_rf, - const DcalcAnalysisPt *dcalc_ap) const; - virtual float loadCap(const Pin *drvr_pin, - const DcalcAnalysisPt *dcalc_ap) const; - virtual void loadCap(const Pin *drvr_pin, - const Parasitic *drvr_parasitic, - const RiseFall *rf, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - float &pin_cap, - float &wire_cap) const; - virtual float loadCap(const Pin *drvr_pin, - const Parasitic *drvr_parasitic, - const RiseFall *rf, - const DcalcAnalysisPt *dcalc_ap) const; - virtual void netCaps(const Pin *drvr_pin, - const RiseFall *rf, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - float &pin_cap, - float &wire_cap, - float &fanout, - bool &has_set_load) const; - float ceff(Edge *edge, - TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap); - -protected: - void seedInvalidDelays(); - void ensureMultiDrvrNetsFound(); - void makeMultiDrvrNet(PinSet &drvr_pins); - void initSlew(Vertex *vertex); - void seedRootSlew(Vertex *vertex, - ArcDelayCalc *arc_delay_calc); - void seedRootSlews(); - void seedDrvrSlew(Vertex *vertex, - ArcDelayCalc *arc_delay_calc); - void seedNoDrvrSlew(Vertex *drvr_vertex, - const Pin *drvr_pin, - const RiseFall *rf, - DcalcAnalysisPt *dcalc_ap, - ArcDelayCalc *arc_delay_calc); - void seedNoDrvrCellSlew(Vertex *drvr_vertex, - const Pin *drvr_pin, - const RiseFall *rf, - InputDrive *drive, - DcalcAnalysisPt *dcalc_ap, - ArcDelayCalc *arc_delay_calc); - void seedLoadSlew(Vertex *vertex); - void setInputPortWireDelays(Vertex *vertex); - void findInputDriverDelay(const LibertyCell *drvr_cell, - const Pin *drvr_pin, - Vertex *drvr_vertex, - const RiseFall *rf, - const LibertyPort *from_port, - float *from_slews, - const LibertyPort *to_port, - const DcalcAnalysisPt *dcalc_ap); - LibertyPort *driveCellDefaultFromPort(const LibertyCell *cell, - const LibertyPort *to_port); - int findPortIndex(const LibertyCell *cell, - const LibertyPort *port); - void findInputArcDelay(const LibertyCell *drvr_cell, - const Pin *drvr_pin, - Vertex *drvr_vertex, - const TimingArc *arc, - float from_slew, - const DcalcAnalysisPt *dcalc_ap); - bool findDriverDelays(Vertex *drvr_vertex, - ArcDelayCalc *arc_delay_calc); - bool findDriverDelays1(Vertex *drvr_vertex, - bool init_load_slews, - MultiDrvrNet *multi_drvr, - ArcDelayCalc *arc_delay_calc); - bool findDriverEdgeDelays(LibertyCell *drvr_cell, - Instance *drvr_inst, - const Pin *drvr_pin, - Vertex *drvr_vertex, - MultiDrvrNet *multi_drvr, - Edge *edge, - ArcDelayCalc *arc_delay_calc); - 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); - void enqueueTimingChecksEdges(Vertex *vertex); - bool findArcDelay(LibertyCell *drvr_cell, - const Pin *drvr_pin, - Vertex *drvr_vertex, - MultiDrvrNet *multi_drvr, - TimingArc *arc, - Parasitic *drvr_parasitic, - float related_out_cap, - Vertex *from_vertex, - Edge *edge, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - ArcDelayCalc *arc_delay_calc); - void annotateLoadDelays(Vertex *drvr_vertex, - const RiseFall *drvr_rf, - const ArcDelay &extra_delay, - bool merge, - const DcalcAnalysisPt *dcalc_ap, - ArcDelayCalc *arc_delay_calc); - void findLatchEdgeDelays(Edge *edge); - void findCheckEdgeDelays(Edge *edge, - ArcDelayCalc *arc_delay_calc); - void findMultiDrvrGateDelay(MultiDrvrNet *multi_drvr, - const RiseFall *drvr_rf, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - ArcDelayCalc *arc_delay_calc, - // Return values. - ArcDelay ¶llel_delay, - Slew ¶llel_slew); - void parallelGateDelay(MultiDrvrNet *multi_drvr, - LibertyCell *drvr_cell, - const Pin *drvr_pin, - TimingArc *arc, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - const Slew from_slew, - Parasitic *drvr_parasitic, - float related_out_cap, - ArcDelayCalc *arc_delay_calc, - // Return values. - ArcDelay &gate_delay, - Slew &gate_slew); - void deleteMultiDrvrNets(); - Slew edgeFromSlew(const Vertex *from_vertex, - const RiseFall *from_rf, - const Edge *edge, - const DcalcAnalysisPt *dcalc_ap); - Slew checkEdgeClkSlew(const Vertex *from_vertex, - const RiseFall *from_rf, - const DcalcAnalysisPt *dcalc_ap); - bool bidirectDrvrSlewFromLoad(const Vertex *vertex) const; - MultiDrvrNet *multiDrvrNet(const Vertex *drvr_vertex) const; - void loadCap(const Parasitic *drvr_parasitic, - bool has_set_load, - // Return values. - float &pin_cap, - float &wire_cap) const; - float loadCap(const Pin *drvr_pin, - MultiDrvrNet *multi_drvr, - const Parasitic *drvr_parasitic, - const RiseFall *rf, - const DcalcAnalysisPt *dcalc_ap) const; - - // Observer for edge delay changes. - DelayCalcObserver *observer_; - bool delays_seeded_; - bool incremental_; - bool delays_exist_; - // Vertices with invalid -to delays. - VertexSet *invalid_delays_; - // 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_; - BfsFwdIterator *iter_; - MultiDrvrNetMap multi_drvr_net_map_; - bool multi_drvr_nets_found_; - // Percentage (0.0:1.0) change in delay that causes downstream - // delays to be recomputed during incremental delay calculation. - float incremental_delay_tolerance_; - - friend class FindVertexDelays; - friend class MultiDrvrNet; -}; - -} // namespace diff --git a/include/sta/GraphDelayCalc.hh b/include/sta/GraphDelayCalc.hh index 5d795979..d6aa9526 100644 --- a/include/sta/GraphDelayCalc.hh +++ b/include/sta/GraphDelayCalc.hh @@ -16,46 +16,44 @@ #pragma once -#include - +#include "Map.hh" +#include "NetworkClass.hh" #include "GraphClass.hh" +#include "SearchClass.hh" #include "DcalcAnalysisPt.hh" #include "StaState.hh" +#include "Delay.hh" namespace sta { -using std::string; - -class BfsFwdIterator; -class SearchPred; class DelayCalcObserver; -class Parasitic; -class Corner; +class MultiDrvrNet; +class FindVertexDelays; -// Base class for graph delay calculator. -// This class annotates the arc delays and slews on the graph by calling -// the timing arc delay calculation primitive through an implementation -// of the ArcDelayCalc abstract class. -// This class does not traverse the graph or call an arc delay -// calculator. Use it with applications that use an external delay -// calculator and annotate all edge delays. +typedef Map MultiDrvrNetMap; + +// This class traverses the graph calling the arc delay calculator and +// annotating delays on graph edges. class GraphDelayCalc : public StaState { public: - explicit GraphDelayCalc(StaState *sta); - virtual ~GraphDelayCalc() {} - // Find arc delays and vertex slews thru level. - virtual void findDelays(Level /* level */) {}; - // Find and annotate drvr_vertex gate and load delays/slews. - virtual void findDelays(Vertex * /* drvr_vertex */) {}; + GraphDelayCalc(StaState *sta); + virtual ~GraphDelayCalc(); + virtual void copyState(const StaState *sta); + // Set the observer for edge delay changes. + virtual void setObserver(DelayCalcObserver *observer); // Invalidate all delays/slews. - virtual void delaysInvalid() {}; + virtual void delaysInvalid(); // Invalidate vertex and downstream delays/slews. - virtual void delayInvalid(Vertex * /* vertex */) {}; - virtual void delayInvalid(const Pin * /* pin */) {}; - virtual void deleteVertexBefore(Vertex * /* vertex */) {}; + virtual void delayInvalid(Vertex *vertex); + virtual void delayInvalid(const Pin *pin); + virtual void deleteVertexBefore(Vertex *vertex); // Reset to virgin state. - virtual void clear() {} + virtual void clear(); + // Find arc delays and vertex slews thru level. + virtual void findDelays(Level level); + // Find and annotate drvr_vertex gate and load delays/slews. + virtual void findDelays(Vertex *drvr_vertex); // Returned string is owned by the caller. virtual string reportDelayCalc(Edge *edge, TimingArc *arc, @@ -65,9 +63,14 @@ public: // Percentage (0.0:1.0) change in delay that causes downstream // delays to be recomputed during incremental delay calculation. virtual float incrementalDelayTolerance(); - virtual void setIncrementalDelayTolerance(float /* tol */) {} - // Set the observer for edge delay changes. - virtual void setObserver(DelayCalcObserver *observer); + virtual void setIncrementalDelayTolerance(float tol); + // Load pin_cap + wire_cap. + virtual float loadCap(const Pin *drvr_pin, + const RiseFall *drvr_rf, + const DcalcAnalysisPt *dcalc_ap) const; + // Load pin_cap + wire_cap including parasitic min/max for rise/fall. + virtual float loadCap(const Pin *drvr_pin, + const DcalcAnalysisPt *dcalc_ap) const; // pin_cap = net pin capacitances + port external pin capacitance, // wire_cap = annotated net capacitance + port external wire capacitance. virtual void loadCap(const Pin *drvr_pin, @@ -78,13 +81,6 @@ public: float &pin_cap, float &wire_cap) const; // Load pin_cap + wire_cap including parasitic. - virtual float loadCap(const Pin *drvr_pin, - const RiseFall *to_rf, - const DcalcAnalysisPt *dcalc_ap) const; - // Load pin_cap + wire_cap including parasitic min/max for rise/fall. - virtual float loadCap(const Pin *drvr_pin, - const DcalcAnalysisPt *dcalc_ap) const; - // Load pin_cap + wire_cap. virtual float loadCap(const Pin *drvr_pin, const Parasitic *drvr_parasitic, const RiseFall *rf, @@ -97,9 +93,9 @@ public: float &wire_cap, float &fanout, bool &has_set_load) const; - virtual float ceff(Edge *edge, - TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap); + float ceff(Edge *edge, + TimingArc *arc, + const DcalcAnalysisPt *dcalc_ap); // Precedence: // SDF annotation // Liberty library @@ -118,6 +114,157 @@ public: // Return values. float &min_period, bool &exists); + +protected: + void seedInvalidDelays(); + void ensureMultiDrvrNetsFound(); + void makeMultiDrvrNet(PinSet &drvr_pins); + void initSlew(Vertex *vertex); + void seedRootSlew(Vertex *vertex, + ArcDelayCalc *arc_delay_calc); + void seedRootSlews(); + void seedDrvrSlew(Vertex *vertex, + ArcDelayCalc *arc_delay_calc); + void seedNoDrvrSlew(Vertex *drvr_vertex, + const Pin *drvr_pin, + const RiseFall *rf, + DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc); + void seedNoDrvrCellSlew(Vertex *drvr_vertex, + const Pin *drvr_pin, + const RiseFall *rf, + InputDrive *drive, + DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc); + void seedLoadSlew(Vertex *vertex); + void setInputPortWireDelays(Vertex *vertex); + void findInputDriverDelay(const LibertyCell *drvr_cell, + const Pin *drvr_pin, + Vertex *drvr_vertex, + const RiseFall *rf, + const LibertyPort *from_port, + float *from_slews, + const LibertyPort *to_port, + const DcalcAnalysisPt *dcalc_ap); + LibertyPort *driveCellDefaultFromPort(const LibertyCell *cell, + const LibertyPort *to_port); + int findPortIndex(const LibertyCell *cell, + const LibertyPort *port); + void findInputArcDelay(const LibertyCell *drvr_cell, + const Pin *drvr_pin, + Vertex *drvr_vertex, + const TimingArc *arc, + float from_slew, + const DcalcAnalysisPt *dcalc_ap); + bool findDriverDelays(Vertex *drvr_vertex, + ArcDelayCalc *arc_delay_calc); + bool findDriverDelays1(Vertex *drvr_vertex, + bool init_load_slews, + MultiDrvrNet *multi_drvr, + ArcDelayCalc *arc_delay_calc); + bool findDriverEdgeDelays(LibertyCell *drvr_cell, + Instance *drvr_inst, + const Pin *drvr_pin, + Vertex *drvr_vertex, + MultiDrvrNet *multi_drvr, + Edge *edge, + ArcDelayCalc *arc_delay_calc); + 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); + void enqueueTimingChecksEdges(Vertex *vertex); + bool findArcDelay(LibertyCell *drvr_cell, + const Pin *drvr_pin, + Vertex *drvr_vertex, + MultiDrvrNet *multi_drvr, + TimingArc *arc, + Parasitic *drvr_parasitic, + float related_out_cap, + Vertex *from_vertex, + Edge *edge, + const Pvt *pvt, + const DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc); + void annotateLoadDelays(Vertex *drvr_vertex, + const RiseFall *drvr_rf, + const ArcDelay &extra_delay, + bool merge, + const DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc); + void findLatchEdgeDelays(Edge *edge); + void findCheckEdgeDelays(Edge *edge, + ArcDelayCalc *arc_delay_calc); + void findMultiDrvrGateDelay(MultiDrvrNet *multi_drvr, + const RiseFall *drvr_rf, + const Pvt *pvt, + const DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc, + // Return values. + ArcDelay ¶llel_delay, + Slew ¶llel_slew); + void parallelGateDelay(MultiDrvrNet *multi_drvr, + LibertyCell *drvr_cell, + const Pin *drvr_pin, + TimingArc *arc, + const Pvt *pvt, + const DcalcAnalysisPt *dcalc_ap, + const Slew from_slew, + Parasitic *drvr_parasitic, + float related_out_cap, + ArcDelayCalc *arc_delay_calc, + // Return values. + ArcDelay &gate_delay, + Slew &gate_slew); + void deleteMultiDrvrNets(); + Slew edgeFromSlew(const Vertex *from_vertex, + const RiseFall *from_rf, + const Edge *edge, + const DcalcAnalysisPt *dcalc_ap); + Slew checkEdgeClkSlew(const Vertex *from_vertex, + const RiseFall *from_rf, + const DcalcAnalysisPt *dcalc_ap); + bool bidirectDrvrSlewFromLoad(const Vertex *vertex) const; + MultiDrvrNet *multiDrvrNet(const Vertex *drvr_vertex) const; + void loadCap(const Parasitic *drvr_parasitic, + bool has_set_load, + // Return values. + float &pin_cap, + float &wire_cap) const; + float loadCap(const Pin *drvr_pin, + MultiDrvrNet *multi_drvr, + const Parasitic *drvr_parasitic, + const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap) const; + + // Observer for edge delay changes. + DelayCalcObserver *observer_; + bool delays_seeded_; + bool incremental_; + bool delays_exist_; + // Vertices with invalid -to delays. + VertexSet *invalid_delays_; + // 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_; + BfsFwdIterator *iter_; + MultiDrvrNetMap multi_drvr_net_map_; + bool multi_drvr_nets_found_; + // Percentage (0.0:1.0) change in delay that causes downstream + // delays to be recomputed during incremental delay calculation. + float incremental_delay_tolerance_; + + friend class FindVertexDelays; + friend class MultiDrvrNet; }; // Abstract base class for edge delay change observer. diff --git a/include/sta/SearchClass.hh b/include/sta/SearchClass.hh index 6aea164f..52b27f77 100644 --- a/include/sta/SearchClass.hh +++ b/include/sta/SearchClass.hh @@ -59,6 +59,8 @@ class MinPulseWidthCheck; class MinPeriodCheck; class MaxSkewCheck; class CharPtrLess; +class SearchPred; +class BfsFwdIterator; // Tag compare using tag matching (tagMatch) critera. class TagMatchLess diff --git a/search/MakeTimingModel.cc b/search/MakeTimingModel.cc index b73c7b89..6c9d6895 100644 --- a/search/MakeTimingModel.cc +++ b/search/MakeTimingModel.cc @@ -31,7 +31,7 @@ #include "PortDirection.hh" #include "Corner.hh" #include "DcalcAnalysisPt.hh" -#include "dcalc/GraphDelayCalc1.hh" +#include "GraphDelayCalc.hh" #include "Sdc.hh" #include "StaState.hh" #include "Graph.hh" diff --git a/search/Sta.cc b/search/Sta.cc index b886db80..2e7500aa 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -44,7 +44,7 @@ #include "parasitics/ReportParasiticAnnotation.hh" #include "DelayCalc.hh" #include "ArcDelayCalc.hh" -#include "dcalc/GraphDelayCalc1.hh" +#include "GraphDelayCalc.hh" #include "sdf/SdfWriter.hh" #include "Levelize.hh" #include "Sim.hh" @@ -414,7 +414,7 @@ Sta::makeArcDelayCalc() void Sta::makeGraphDelayCalc() { - graph_delay_calc_ = new GraphDelayCalc1(this); + graph_delay_calc_ = new GraphDelayCalc(this); } void