diff --git a/dcalc/ArnoldiDelayCalc.cc b/dcalc/ArnoldiDelayCalc.cc index 53bda7f1..b3205010 100644 --- a/dcalc/ArnoldiDelayCalc.cc +++ b/dcalc/ArnoldiDelayCalc.cc @@ -266,8 +266,9 @@ ArnoldiDelayCalc::findParasitic(const Pin *drvr_pin, const RiseFall *drvr_rf, const DcalcAnalysisPt *dcalc_ap) { + Parasitic *parasitic = nullptr; const Corner *corner = dcalc_ap->corner(); - // set_load has precidence over parasitics. + // set_load net has precidence over parasitics. if (!sdc_->drvrPinHasWireCap(drvr_pin, corner)) { const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt(); Parasitic *parasitic_network = @@ -291,22 +292,20 @@ ArnoldiDelayCalc::findParasitic(const Pin *drvr_pin, } if (parasitic_network) { - Parasitic *parasitic = - reduce_->reduceToArnoldi(parasitic_network, - drvr_pin, - parasitic_ap->couplingCapFactor(), - drvr_rf, op_cond, corner, - cnst_min_max, parasitic_ap); + parasitic = reduce_->reduceToArnoldi(parasitic_network, + drvr_pin, + parasitic_ap->couplingCapFactor(), + drvr_rf, op_cond, corner, + cnst_min_max, parasitic_ap); if (delete_parasitic_network) { Net *net = network_->net(drvr_pin); parasitics_->deleteParasiticNetwork(net, parasitic_ap); } - // Arnoldi parasitics their own class that are not saved in the parasitic db. + // Arnoldi parasitics are their own class that are not saved in the parasitic db. unsaved_parasitics_.push_back(parasitic); - return parasitic; } } - return nullptr; + return parasitic; } ReducedParasiticType diff --git a/dcalc/DmpDelayCalc.cc b/dcalc/DmpDelayCalc.cc index 25fcd3f9..169b1051 100644 --- a/dcalc/DmpDelayCalc.cc +++ b/dcalc/DmpDelayCalc.cc @@ -99,17 +99,8 @@ DmpCeffElmoreDelayCalc::loadDelay(const Pin *load_pin, if (drvr_parasitic_) parasitics_->findElmore(drvr_parasitic_, load_pin, elmore, elmore_exists); if (elmore_exists) { - if (input_port_) { - // Input port with no external driver. - if (parasitics_->isReducedParasiticNetwork(drvr_parasitic_)) - dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1); - else { - // The elmore delay on an input port is used for the wire - // delay and the load slew is the same as the driver slew. - wire_delay1 = elmore; - load_slew1 = drvr_slew_; - } - } + if (input_port_) + dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1); else loadDelaySlew(load_pin, elmore, wire_delay1, load_slew1); } @@ -202,57 +193,53 @@ DmpCeffTwoPoleDelayCalc::findParasitic(const Pin *drvr_pin, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) { + Parasitic *parasitic = nullptr; const Corner *corner = dcalc_ap->corner(); - // set_load has precidence over parasitics. + // set_load net has precidence over parasitics. if (!sdc_->drvrPinHasWireCap(drvr_pin, corner)) { - Parasitic *parasitic = nullptr; const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt(); if (parasitics_->haveParasitics()) { // Prefer PiPoleResidue. - parasitic = parasitics_->findPiPoleResidue(drvr_pin, rf, - parasitic_ap); - if (parasitic) - return parasitic; - - parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap); - if (parasitic) - return parasitic; - - Parasitic *parasitic_network = - parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap); - if (parasitic_network) { - parasitics_->reduceToPiPoleResidue2(parasitic_network, drvr_pin, - dcalc_ap->operatingConditions(), - corner, - dcalc_ap->constraintMinMax(), - parasitic_ap); - parasitic = parasitics_->findPiPoleResidue(drvr_pin, rf, parasitic_ap); - reduced_parasitic_drvrs_.push_back(drvr_pin); - return parasitic; + parasitic = parasitics_->findPiPoleResidue(drvr_pin, rf, parasitic_ap); + if (parasitic == nullptr) { + parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap); + if (parasitic == nullptr) { + Parasitic *parasitic_network = + parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap); + if (parasitic_network) { + parasitics_->reduceToPiPoleResidue2(parasitic_network, drvr_pin, + dcalc_ap->operatingConditions(), + corner, + dcalc_ap->constraintMinMax(), + parasitic_ap); + parasitic = parasitics_->findPiPoleResidue(drvr_pin, rf, parasitic_ap); + reduced_parasitic_drvrs_.push_back(drvr_pin); + } + } } } - - const MinMax *cnst_min_max = dcalc_ap->constraintMinMax(); - Wireload *wireload = sdc_->wireload(cnst_min_max); - if (wireload) { - float pin_cap, wire_cap, fanout; - bool has_wire_cap; - graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap, - pin_cap, wire_cap, fanout, has_wire_cap); - parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload, - fanout, pin_cap, - dcalc_ap->operatingConditions(), - corner, - cnst_min_max, - parasitic_ap); - // Estimated parasitics are not recorded in the "database", so - // it for deletion after the drvr pin delay calc is finished. - if (parasitic) - unsaved_parasitics_.push_back(parasitic); - return parasitic; + else { + const MinMax *cnst_min_max = dcalc_ap->constraintMinMax(); + Wireload *wireload = sdc_->wireload(cnst_min_max); + if (wireload) { + float pin_cap, wire_cap, fanout; + bool has_wire_cap; + graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap, + pin_cap, wire_cap, fanout, has_wire_cap); + parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload, + fanout, pin_cap, + dcalc_ap->operatingConditions(), + corner, + cnst_min_max, + parasitic_ap); + // Estimated parasitics are not recorded in the "database", so + // it for deletion after the drvr pin delay calc is finished. + if (parasitic) + unsaved_parasitics_.push_back(parasitic); + } } } - return nullptr; + return parasitic; } ReducedParasiticType @@ -322,14 +309,7 @@ DmpCeffTwoPoleDelayCalc::loadDelay(const Pin *load_pin, if (input_port_) { float elmore = 1.0F / p1; // Input port with no external driver. - if (parasitics_->isReducedParasiticNetwork(drvr_parasitic_)) - dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1); - else { - // For RSPF on an input port the elmore delay is used for the - // wire delay and the load slew is the same as the driver slew. - wire_delay1 = elmore; - load_slew1 = drvr_slew_; - } + dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1); } else { if (pole_count >= 2) diff --git a/dcalc/GraphDelayCalc.cc b/dcalc/GraphDelayCalc.cc index 748d6cbd..d559e29d 100644 --- a/dcalc/GraphDelayCalc.cc +++ b/dcalc/GraphDelayCalc.cc @@ -54,7 +54,7 @@ GraphDelayCalc::incrementalDelayTolerance() void GraphDelayCalc::loadCap(const Pin *, - Parasitic *, + const Parasitic *, const RiseFall *, const DcalcAnalysisPt *, // Return values. @@ -74,7 +74,7 @@ GraphDelayCalc::loadCap(const Pin *, float GraphDelayCalc::loadCap(const Pin *, - Parasitic *, + const Parasitic *, const RiseFall *, const DcalcAnalysisPt *) const { diff --git a/dcalc/GraphDelayCalc1.cc b/dcalc/GraphDelayCalc1.cc index 300a4450..4ddbe053 100644 --- a/dcalc/GraphDelayCalc1.cc +++ b/dcalc/GraphDelayCalc1.cc @@ -1062,7 +1062,7 @@ GraphDelayCalc1::loadCap(const Pin *drvr_pin, float GraphDelayCalc1::loadCap(const Pin *drvr_pin, - Parasitic *drvr_parasitic, + const Parasitic *drvr_parasitic, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) const { @@ -1072,7 +1072,7 @@ GraphDelayCalc1::loadCap(const Pin *drvr_pin, float GraphDelayCalc1::loadCap(const Pin *drvr_pin, MultiDrvrNet *multi_drvr, - Parasitic *drvr_parasitic, + const Parasitic *drvr_parasitic, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) const { @@ -1091,7 +1091,7 @@ GraphDelayCalc1::loadCap(const Pin *drvr_pin, void GraphDelayCalc1::loadCap(const Pin *drvr_pin, - Parasitic *drvr_parasitic, + const Parasitic *drvr_parasitic, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap, // Return values. @@ -1107,7 +1107,7 @@ GraphDelayCalc1::loadCap(const Pin *drvr_pin, } void -GraphDelayCalc1::loadCap(Parasitic *drvr_parasitic, +GraphDelayCalc1::loadCap(const Parasitic *drvr_parasitic, bool has_net_load, // Return values. float &pin_cap, diff --git a/dcalc/GraphDelayCalc1.hh b/dcalc/GraphDelayCalc1.hh index 268da284..84189dcb 100644 --- a/dcalc/GraphDelayCalc1.hh +++ b/dcalc/GraphDelayCalc1.hh @@ -59,14 +59,14 @@ public: virtual float loadCap(const Pin *drvr_pin, const DcalcAnalysisPt *dcalc_ap) const; virtual void loadCap(const Pin *drvr_pin, - Parasitic *drvr_parasitic, + 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, - Parasitic *drvr_parasitic, + const Parasitic *drvr_parasitic, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) const; virtual void netCaps(const Pin *drvr_pin, @@ -195,14 +195,14 @@ protected: const DcalcAnalysisPt *dcalc_ap); bool bidirectDrvrSlewFromLoad(const Vertex *vertex) const; MultiDrvrNet *multiDrvrNet(const Vertex *drvr_vertex) const; - void loadCap(Parasitic *drvr_parasitic, + 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, - Parasitic *drvr_parasitic, + const Parasitic *drvr_parasitic, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) const; diff --git a/dcalc/LumpedCapDelayCalc.cc b/dcalc/LumpedCapDelayCalc.cc index 91c38bab..0309c2c5 100644 --- a/dcalc/LumpedCapDelayCalc.cc +++ b/dcalc/LumpedCapDelayCalc.cc @@ -55,52 +55,50 @@ LumpedCapDelayCalc::findParasitic(const Pin *drvr_pin, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) { + Parasitic *parasitic = nullptr; const Corner *corner = dcalc_ap->corner(); - // set_load has precidence over parasitics. + // set_load net has precidence over parasitics. if (!sdc_->drvrPinHasWireCap(drvr_pin, corner)) { - Parasitic *parasitic = nullptr; const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt(); if (parasitics_->haveParasitics()) { // Prefer PiElmore. parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap); - if (parasitic) - return parasitic; - - Parasitic *parasitic_network = - parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap); - if (parasitic_network) { - parasitics_->reduceToPiElmore(parasitic_network, drvr_pin, - dcalc_ap->operatingConditions(), - corner, - dcalc_ap->constraintMinMax(), - parasitic_ap); - parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap); - reduced_parasitic_drvrs_.push_back(drvr_pin); - return parasitic; + if (parasitic == nullptr) { + Parasitic *parasitic_network = + parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap); + if (parasitic_network) { + parasitics_->reduceToPiElmore(parasitic_network, drvr_pin, + dcalc_ap->operatingConditions(), + corner, + dcalc_ap->constraintMinMax(), + parasitic_ap); + parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap); + reduced_parasitic_drvrs_.push_back(drvr_pin); + } } } - - const MinMax *cnst_min_max = dcalc_ap->constraintMinMax(); - Wireload *wireload = sdc_->wireload(cnst_min_max); - if (wireload) { - float pin_cap, wire_cap, fanout; - bool has_wire_cap; - graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap, - pin_cap, wire_cap, fanout, has_wire_cap); - parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload, - fanout, pin_cap, - dcalc_ap->operatingConditions(), - corner, - cnst_min_max, - parasitic_ap); - // Estimated parasitics are not recorded in the "database", so - // it for deletion after the drvr pin delay calc is finished. - if (parasitic) - unsaved_parasitics_.push_back(parasitic); - return parasitic; + else { + const MinMax *cnst_min_max = dcalc_ap->constraintMinMax(); + Wireload *wireload = sdc_->wireload(cnst_min_max); + if (wireload) { + float pin_cap, wire_cap, fanout; + bool has_wire_cap; + graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap, + pin_cap, wire_cap, fanout, has_wire_cap); + parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload, + fanout, pin_cap, + dcalc_ap->operatingConditions(), + corner, + cnst_min_max, + parasitic_ap); + // Estimated parasitics are not recorded in the "database", so save + // it for deletion after the drvr pin delay calc is finished. + if (parasitic) + unsaved_parasitics_.push_back(parasitic); + } } } - return nullptr; + return parasitic; } ReducedParasiticType diff --git a/dcalc/RCDelayCalc.cc b/dcalc/RCDelayCalc.cc index 5f852e14..900df3f0 100644 --- a/dcalc/RCDelayCalc.cc +++ b/dcalc/RCDelayCalc.cc @@ -66,7 +66,7 @@ RCDelayCalc::dspfWireDelaySlew(const Pin *, float vl = drvr_library_->slewLowerThreshold(drvr_rf_); float vh = drvr_library_->slewUpperThreshold(drvr_rf_); float slew_derate = drvr_library_->slewDerateFromLibrary(); - wire_delay = static_cast(-elmore * log(1.0 - vth)); + wire_delay = -elmore * log(1.0 - vth); load_slew = (drvr_slew_ + elmore * log((1.0 - vl) / (1.0 - vh)) / slew_derate) * multi_drvr_slew_factor_; } diff --git a/dcalc/SlewDegradeDelayCalc.cc b/dcalc/SlewDegradeDelayCalc.cc index 1e61ebe0..5e9a9f20 100644 --- a/dcalc/SlewDegradeDelayCalc.cc +++ b/dcalc/SlewDegradeDelayCalc.cc @@ -134,14 +134,7 @@ SlewDegradeDelayCalc::loadDelay(const Pin *load_pin, delayAsFloat(drvr_slew_), delayAsFloat(wire_delay1)); } - else if (parasitics_->isReducedParasiticNetwork(drvr_parasitic_)) - dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1); - else { - // For RSPF on an input port the elmore delay is used for the - // wire delay and the slew is copied from the driver. - wire_delay1 = elmore; - load_slew1 = drvr_slew_; - } + dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1); } thresholdAdjust(load_pin, wire_delay1, load_slew1); wire_delay = wire_delay1; diff --git a/graph/Graph.cc b/graph/Graph.cc index 6875636a..8d5bc4ee 100644 --- a/graph/Graph.cc +++ b/graph/Graph.cc @@ -191,7 +191,7 @@ Graph::makePortInstanceEdges(const Instance *inst, if ((from_to_port == nullptr || from_port == from_to_port || to_port == from_to_port) - && filterEdge(arc_set)) { + && from_port) { Pin *from_pin = network_->findPin(inst, from_port); Pin *to_pin = network_->findPin(inst, to_port); if (from_pin && to_pin) { diff --git a/include/sta/Graph.hh b/include/sta/Graph.hh index 8fc8813f..247b5bcf 100644 --- a/include/sta/Graph.hh +++ b/include/sta/Graph.hh @@ -232,8 +232,6 @@ protected: Edge *edge); void removeDelays(); void removeDelayAnnotated(Edge *edge); - // User defined predicate to filter graph edges for liberty timing arcs. - virtual bool filterEdge(TimingArcSet *) const { return true; } VertexTable *vertices_; EdgeTable *edges_; diff --git a/include/sta/GraphDelayCalc.hh b/include/sta/GraphDelayCalc.hh index 77f5eae0..5d795979 100644 --- a/include/sta/GraphDelayCalc.hh +++ b/include/sta/GraphDelayCalc.hh @@ -71,7 +71,7 @@ public: // 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, - Parasitic *drvr_parasitic, + const Parasitic *drvr_parasitic, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap, // Return values. @@ -86,7 +86,7 @@ public: const DcalcAnalysisPt *dcalc_ap) const; // Load pin_cap + wire_cap. virtual float loadCap(const Pin *drvr_pin, - Parasitic *drvr_parasitic, + const Parasitic *drvr_parasitic, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) const; virtual void netCaps(const Pin *drvr_pin, diff --git a/include/sta/Liberty.hh b/include/sta/Liberty.hh index d1ede379..0924ebd9 100644 --- a/include/sta/Liberty.hh +++ b/include/sta/Liberty.hh @@ -794,6 +794,7 @@ public: DriverWaveform *driverWaveform(const RiseFall *rf) const; void setDriverWaveform(DriverWaveform *driver_waveform, const RiseFall *rf); + RiseFallMinMax clockTreePathDelays(); static bool equiv(const LibertyPort *port1, const LibertyPort *port2); diff --git a/include/sta/MinMaxValues.hh b/include/sta/MinMaxValues.hh index 790f386d..50d0b9eb 100644 --- a/include/sta/MinMaxValues.hh +++ b/include/sta/MinMaxValues.hh @@ -110,8 +110,10 @@ public: bool exists = exists_[mm_index]; if (exists) return values_[mm_index]; - else + else { criticalError(226, "uninitialized value reference"); + return 0.0; + } } void diff --git a/include/sta/NullParasitics.hh b/include/sta/NullParasitics.hh index c3aebb8b..21331cb1 100644 --- a/include/sta/NullParasitics.hh +++ b/include/sta/NullParasitics.hh @@ -38,7 +38,7 @@ public: const ParasiticAnalysisPt *ap); virtual void deleteDrvrReducedParasitics(const Pin *drvr_pin); - virtual float capacitance(Parasitic *parasitic) const; + virtual float capacitance(const Parasitic *parasitic) const; virtual Parasitic * findPiElmore(const Pin *drvr_pin, @@ -91,7 +91,7 @@ public: virtual void poleResidue(const Parasitic *parasitic, int pole_index, ComplexFloat &pole, ComplexFloat &residue) const; - virtual bool isParasiticNetwork(Parasitic *parasitic) const; + virtual bool isParasiticNetwork(const Parasitic *parasitic) const; virtual Parasitic *findParasiticNetwork(const Net *net, const ParasiticAnalysisPt *ap) const; virtual Parasitic * @@ -101,9 +101,9 @@ public: makeParasiticNetwork(const Net *net, bool pin_cap_included, const ParasiticAnalysisPt *ap); - virtual ParasiticDeviceIterator *deviceIterator(Parasitic *) { return nullptr; } - virtual ParasiticNodeIterator *nodeIterator(Parasitic *) { return nullptr; } - virtual bool includesPinCaps(Parasitic *parasitic) const; + virtual ParasiticDeviceIterator *deviceIterator(const Parasitic *) { return nullptr; } + virtual ParasiticNodeIterator *nodeIterator(const Parasitic *) { return nullptr; } + virtual bool includesPinCaps(const Parasitic *parasitic) const; virtual void deleteParasiticNetwork(const Net *net, const ParasiticAnalysisPt *ap); virtual void deleteParasiticNetworks(const Net *net); @@ -132,7 +132,7 @@ public: virtual const char *name(const ParasiticNode *node); virtual const Pin *connectionPin(const ParasiticNode *node) const; - virtual ParasiticNode *findNode(Parasitic *parasitic, + virtual ParasiticNode *findNode(const Parasitic *parasitic, const Pin *pin) const; virtual float nodeGndCap(const ParasiticNode *node, const ParasiticAnalysisPt *ap) const; @@ -148,33 +148,33 @@ public: virtual ParasiticNode *otherNode(const ParasiticDevice *device, ParasiticNode *node) const; // Reduce parasitic network to reduce_to model. - virtual void reduceTo(Parasitic *parasitic, + virtual void reduceTo(const Parasitic *parasitic, const Net *net, ReducedParasiticType reduce_to, const OperatingConditions *op_cond, const Corner *corner, const MinMax *cnst_min_max, const ParasiticAnalysisPt *ap); - virtual void reduceToPiElmore(Parasitic *parasitic, + virtual void reduceToPiElmore(const Parasitic *parasitic, const Net *net, const OperatingConditions *op_cond, const Corner *corner, const MinMax *cnst_min_max, const ParasiticAnalysisPt *ap); // Reduce parasitic network to pi elmore model for drvr_pin. - virtual void reduceToPiElmore(Parasitic *parasitic, + virtual void reduceToPiElmore(const Parasitic *parasitic, const Pin *drvr_pin, const OperatingConditions *op_cond, const Corner *corner, const MinMax *cnst_min_max, const ParasiticAnalysisPt *ap); - virtual void reduceToPiPoleResidue2(Parasitic *parasitic, + virtual void reduceToPiPoleResidue2(const Parasitic *parasitic, const Net *net, const OperatingConditions *op_cond, const Corner *corner, const MinMax *cnst_min_max, const ParasiticAnalysisPt *ap); - virtual void reduceToPiPoleResidue2(Parasitic *parasitic, + virtual void reduceToPiPoleResidue2(const Parasitic *parasitic, const Pin *drvr_pin, const OperatingConditions *op_cond, const Corner *corner, diff --git a/include/sta/Parasitics.hh b/include/sta/Parasitics.hh index 4b772f11..f7dca806 100644 --- a/include/sta/Parasitics.hh +++ b/include/sta/Parasitics.hh @@ -71,7 +71,7 @@ public: bool is_reduced) = 0; // Capacitance value of parasitic object. - virtual float capacitance(Parasitic *parasitic) const = 0; + virtual float capacitance(const Parasitic *parasitic) const = 0; //////////////////////////////////////////////////////////////// // Pi model driver load with elmore delays to load pins (RSPF). @@ -145,7 +145,7 @@ public: // Parasitic Network (detailed parasitics). // This api assumes that parasitic networks are not rise/fall // dependent because they do not include pin capacitances. - virtual bool isParasiticNetwork(Parasitic *parasitic) const = 0; + virtual bool isParasiticNetwork(const Parasitic *parasitic) const = 0; virtual Parasitic *findParasiticNetwork(const Net *net, const ParasiticAnalysisPt *ap) const = 0; virtual Parasitic *findParasiticNetwork(const Pin *pin, @@ -153,14 +153,14 @@ public: virtual Parasitic *makeParasiticNetwork(const Net *net, bool includes_pin_caps, const ParasiticAnalysisPt *ap) = 0; - virtual ParasiticDeviceIterator *deviceIterator(Parasitic *parasitic) = 0; - virtual ParasiticNodeIterator *nodeIterator(Parasitic *parasitic) = 0; + virtual ParasiticDeviceIterator *deviceIterator(const Parasitic *parasitic) = 0; + virtual ParasiticNodeIterator *nodeIterator(const Parasitic *parasitic) = 0; // Delete parasitic network if it exists. virtual void deleteParasiticNetwork(const Net *net, const ParasiticAnalysisPt *ap) = 0; virtual void deleteParasiticNetworks(const Net *net) = 0; // True if the parasitic network caps include pin capacitances. - virtual bool includesPinCaps(Parasitic *parasitic) const = 0; + virtual bool includesPinCaps(const Parasitic *parasitic) const = 0; // Parasitic network component builders. // Make a subnode of the parasitic network net. virtual ParasiticNode *ensureParasiticNode(Parasitic *parasitic, @@ -207,7 +207,7 @@ public: virtual const char *name(const ParasiticNode *node) = 0; virtual const Pin *connectionPin(const ParasiticNode *node) const = 0; // Find the parasitic node connected to pin. - virtual ParasiticNode *findNode(Parasitic *parasitic, + virtual ParasiticNode *findNode(const Parasitic *parasitic, const Pin *pin) const = 0; // Node capacitance to ground. virtual float nodeGndCap(const ParasiticNode *node, @@ -235,7 +235,7 @@ public: const Pin *drvr_pin) = 0; // Reduce parasitic network to reduce_to model. - virtual void reduceTo(Parasitic *parasitic, + virtual void reduceTo(const Parasitic *parasitic, const Net *net, ReducedParasiticType reduce_to, const OperatingConditions *op_cond, @@ -243,21 +243,21 @@ public: const MinMax *cnst_min_max, const ParasiticAnalysisPt *ap) = 0; // Reduce parasitic network to pi elmore models. - virtual void reduceToPiElmore(Parasitic *parasitic, + virtual void reduceToPiElmore(const Parasitic *parasitic, const Net *net, const OperatingConditions *op_cond, const Corner *corner, const MinMax *cnst_min_max, const ParasiticAnalysisPt *ap) = 0; // Reduce parasitic network to pi elmore model for drvr_pin. - virtual void reduceToPiElmore(Parasitic *parasitic, + virtual void reduceToPiElmore(const Parasitic *parasitic, const Pin *drvr_pin, const OperatingConditions *op_cond, const Corner *corner, const MinMax *cnst_min_max, const ParasiticAnalysisPt *ap) = 0; // Reduce parasitic network to pi and 2nd order pole/residue models. - virtual void reduceToPiPoleResidue2(Parasitic *parasitic, + virtual void reduceToPiPoleResidue2(const Parasitic *parasitic, const Net *net, const OperatingConditions *op_cond, const Corner *corner, @@ -265,7 +265,7 @@ public: const ParasiticAnalysisPt *ap) = 0; // Reduce parasitic network to pi and 2nd order pole/residue models // for drvr_pin. - virtual void reduceToPiPoleResidue2(Parasitic *parasitic, + virtual void reduceToPiPoleResidue2(const Parasitic *parasitic, const Pin *drvr_pin, const OperatingConditions *op_cond, const Corner *corner, diff --git a/include/sta/SearchClass.hh b/include/sta/SearchClass.hh index b582341d..6aea164f 100644 --- a/include/sta/SearchClass.hh +++ b/include/sta/SearchClass.hh @@ -23,6 +23,7 @@ #include "Map.hh" #include "UnorderedMap.hh" #include "StringSet.hh" +#include "MinMaxValues.hh" #include "Delay.hh" #include "NetworkClass.hh" #include "GraphClass.hh" @@ -113,6 +114,7 @@ typedef Vector PathVertexSeq; typedef Vector SlackSeq; typedef Delay Crpr; typedef Vector PathRefSeq; +typedef MinMaxValues ClkDelays[RiseFall::index_count][RiseFall::index_count]; enum class ReportPathFormat { full, full_clock, diff --git a/include/sta/Sta.hh b/include/sta/Sta.hh index f14d0f60..718aa880 100644 --- a/include/sta/Sta.hh +++ b/include/sta/Sta.hh @@ -900,12 +900,6 @@ public: void setReportPathDigits(int digits); void setReportPathNoSplit(bool no_split); void setReportPathSigmas(bool report_sigmas); - // Report clk skews for clks. - void reportClkSkew(ClockSet *clks, - const Corner *corner, - const SetupHold *setup_hold, - int digits); - float findWorstClkSkew(const SetupHold *setup_hold); // Header above reportPathEnd results. void reportPathEndHeader(); // Footer below reportPathEnd results. @@ -919,6 +913,18 @@ public: void reportPathEnds(PathEndSeq *ends); ReportPath *reportPath() { return report_path_; } void reportPath(Path *path); + + // Report clk skews for clks. + void reportClkSkew(ClockSet *clks, + const Corner *corner, + const SetupHold *setup_hold, + int digits); + float findWorstClkSkew(const SetupHold *setup_hold); + // Find min/max/rise/fall delays for clk. + void findClkDelays(const Clock *clk, + // Return values. + ClkDelays &delays); + // Update arrival times for all pins. // If necessary updateTiming propagates arrivals around latch // loops until the arrivals converge. diff --git a/include/sta/TableModel.hh b/include/sta/TableModel.hh index 1184a3b8..0ec14588 100644 --- a/include/sta/TableModel.hh +++ b/include/sta/TableModel.hh @@ -201,7 +201,7 @@ public: TableModel(TablePtr table, TableTemplate *tbl_template, ScaleFactorType scale_factor_type, - RiseFall *rf); + const RiseFall *rf); void setScaleFactorType(ScaleFactorType type); int order() const; TableTemplate *tblTemplate() const { return tbl_template_; } diff --git a/include/sta/TimingArc.hh b/include/sta/TimingArc.hh index 3d46a815..1c30b77c 100644 --- a/include/sta/TimingArc.hh +++ b/include/sta/TimingArc.hh @@ -105,8 +105,8 @@ public: void setModeName(const char *name); const char *modeValue() const { return mode_value_; } void setModeValue(const char *value); - TimingModel *model(RiseFall *rf) const; - void setModel(RiseFall *rf, + TimingModel *model(const RiseFall *rf) const; + void setModel(const RiseFall *rf, TimingModel *model); float ocvArcDepth() const { return ocv_arc_depth_; } void setOcvArcDepth(float depth); diff --git a/include/sta/TimingRole.hh b/include/sta/TimingRole.hh index 3aadc4fc..be20a04a 100644 --- a/include/sta/TimingRole.hh +++ b/include/sta/TimingRole.hh @@ -59,6 +59,8 @@ public: static TimingRole *dataCheckHold() { return data_check_hold_; } static TimingRole *nonSeqSetup() { return non_seq_setup_; } static TimingRole *nonSeqHold() { return non_seq_hold_; } + static TimingRole *clockTreePathMin() { return clock_tree_path_min_; } + static TimingRole *clockTreePathMax() { return clock_tree_path_max_; } const char *asString() const { return name_; } int index() const { return index_; } bool isWire() const; @@ -125,6 +127,8 @@ private: static TimingRole *data_check_hold_; static TimingRole *non_seq_setup_; static TimingRole *non_seq_hold_; + static TimingRole *clock_tree_path_min_; + static TimingRole *clock_tree_path_max_; static TimingRoleMap timing_roles_; friend class TimingRoleLess; diff --git a/include/sta/Transition.hh b/include/sta/Transition.hh index ceb474d5..f4035d20 100644 --- a/include/sta/Transition.hh +++ b/include/sta/Transition.hh @@ -55,9 +55,9 @@ public: RiseFall *opposite() const; // for range support. - // for (auto tr : RiseFall::range()) {} + // for (auto rf : RiseFall::range()) {} static const std::array &range() { return range_; } - // for (auto tr_index : RiseFall::rangeIndex()) {} + // for (auto rf_index : RiseFall::rangeIndex()) {} static const std::array &rangeIndex() { return range_index_; } static const int index_count = 2; static const int index_max = (index_count - 1); diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index dea3e49b..aedcb5b6 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -2352,15 +2352,16 @@ bool LibertyPort::less(const LibertyPort *port1, const LibertyPort *port2) { + if (port1 == nullptr && port2 != nullptr) + return true; + if (port1 != nullptr && port2 == nullptr) + return false; const char *name1 = port1->name(); const char *name2 = port2->name(); if (stringEq(name1, name2)) { PortDirection *dir1 = port1->direction(); PortDirection *dir2 = port2->direction(); - if (dir1 == dir2) { - } - else - return dir1->index() < dir2->index(); + return dir1->index() < dir2->index(); } return stringLess(name1, name2); } @@ -2565,6 +2566,33 @@ LibertyPort::setDriverWaveform(DriverWaveform *driver_waveform, driver_waveform_[rf->index()] = driver_waveform; } +RiseFallMinMax +LibertyPort::clockTreePathDelays() +{ + RiseFallMinMax delays; + const TimingArcSetSeq &arc_sets = liberty_cell_->timingArcSets(nullptr, this); + for (TimingArcSet *arc_set : arc_sets) { + TimingRole *role = arc_set->role(); + if (role == TimingRole::clockTreePathMin() + || role == TimingRole::clockTreePathMax()) { + for (TimingArc *arc : arc_set->arcs()) { + TimingModel *model = arc->model(); + GateTimingModel *gate_model = dynamic_cast(model); + ArcDelay delay; + Slew slew; + gate_model->gateDelay(liberty_cell_, nullptr, 0.0, 0.0, 0.0, false, + delay, slew); + const RiseFall *rf = arc->toEdge()->asRiseFall(); + const MinMax *min_max = (role == TimingRole::clockTreePathMin()) + ? MinMax::min() + : MinMax::max(); + delays.setValue(rf, min_max, delay); + } + } + } + return delays; +} + //////////////////////////////////////////////////////////////// LibertyPortSeq @@ -2588,8 +2616,8 @@ bool LibertyPortPairLess::operator()(const LibertyPortPair &pair1, const LibertyPortPair &pair2) const { - ObjectId id1 = pair1.first->id(); - ObjectId id2 = pair2.first->id(); + ObjectId id1 = pair1.first ? pair1.first->id() : 0; + ObjectId id2 = pair2.first ? pair2.first->id() : 0; return id1 < id2 || (id1 == id2 && pair1.second->id() < pair2.second->id()); diff --git a/liberty/LibertyBuilder.cc b/liberty/LibertyBuilder.cc index 779d5d68..c80a1de7 100644 --- a/liberty/LibertyBuilder.cc +++ b/liberty/LibertyBuilder.cc @@ -281,6 +281,14 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell, RiseFall::fall(), TimingRole::nonSeqHold(), attrs); + case TimingType::min_clock_tree_path: + return makeClockTreePathArcs(cell, to_port, related_out, + TimingRole::clockTreePathMin(), + attrs); + case TimingType::max_clock_tree_path: + return makeClockTreePathArcs(cell, to_port, related_out, + TimingRole::clockTreePathMax(), + attrs); case TimingType::min_pulse_width: case TimingType::minimum_period: case TimingType::nochange_high_high: @@ -289,8 +297,6 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell, case TimingType::nochange_low_low: case TimingType::retaining_time: case TimingType::unknown: - case TimingType::min_clock_tree_path: - case TimingType::max_clock_tree_path: return nullptr; } // Prevent warnings from lame compilers. @@ -647,6 +653,23 @@ LibertyBuilder::makeTristateDisableArcs(LibertyCell *cell, return arc_set; } +TimingArcSet * +LibertyBuilder::makeClockTreePathArcs(LibertyCell *cell, + LibertyPort *to_port, + LibertyPort *related_out, + TimingRole *role, + TimingArcAttrsPtr attrs) +{ + TimingArcSet *arc_set = makeTimingArcSet(cell, nullptr, to_port, + related_out, role, attrs); + for (auto to_rf : RiseFall::range()) { + TimingModel *model = attrs->model(to_rf); + if (model) + makeTimingArc(arc_set, nullptr, to_rf, model); + } + return arc_set; +} + TimingArcSet * LibertyBuilder::makeTimingArcSet(LibertyCell *cell, LibertyPort *from, diff --git a/liberty/LibertyBuilder.hh b/liberty/LibertyBuilder.hh index 62286512..f6b64b86 100644 --- a/liberty/LibertyBuilder.hh +++ b/liberty/LibertyBuilder.hh @@ -79,6 +79,11 @@ public: bool to_rise, bool to_fall, TimingArcAttrsPtr attrs); + TimingArcSet *makeClockTreePathArcs(LibertyCell *cell, + LibertyPort *to_port, + LibertyPort *related_out, + TimingRole *role, + TimingArcAttrsPtr attrs); protected: ConcretePort *makeBusPort(const char *name, diff --git a/liberty/LibertyReader.cc b/liberty/LibertyReader.cc index 9946e201..8ec9ff1d 100644 --- a/liberty/LibertyReader.cc +++ b/liberty/LibertyReader.cc @@ -2195,6 +2195,8 @@ LibertyReader::makeTimingArcs(LibertyPort *to_port, } } } + else + makeTimingArcs(to_port, related_out_port, timing); } void @@ -2363,6 +2365,26 @@ LibertyReader::makeTimingArcs(const char *from_port_name, } } +void +LibertyReader::makeTimingArcs(LibertyPort *to_port, + LibertyPort *related_out_port, + TimingGroup *timing) +{ + if (to_port->hasMembers()) { + LibertyPortMemberIterator bit_iter(to_port); + while (bit_iter.hasNext()) { + LibertyPort *to_port_bit = bit_iter.next(); + builder_.makeTimingArcs(cell_, nullptr, to_port_bit, + related_out_port, timing->attrs(), + timing->line()); + } + } + else + builder_.makeTimingArcs(cell_, nullptr, to_port, + related_out_port, timing->attrs(), + timing->line()); +} + //////////////////////////////////////////////////////////////// void diff --git a/liberty/LibertyReaderPvt.hh b/liberty/LibertyReaderPvt.hh index 5b799a50..4a32067d 100644 --- a/liberty/LibertyReaderPvt.hh +++ b/liberty/LibertyReaderPvt.hh @@ -178,6 +178,9 @@ public: LibertyPort *to_port, LibertyPort *related_out_port, TimingGroup *timing); + virtual void makeTimingArcs(LibertyPort *to_port, + LibertyPort *related_out_port, + TimingGroup *timing); virtual void visitClockGatingIntegratedCell(LibertyAttr *attr); virtual void visitArea(LibertyAttr *attr); diff --git a/liberty/LibertyWriter.cc b/liberty/LibertyWriter.cc index 6d6a7b80..48bdce86 100644 --- a/liberty/LibertyWriter.cc +++ b/liberty/LibertyWriter.cc @@ -364,7 +364,8 @@ void LibertyWriter::writeTimingArcSet(const TimingArcSet *arc_set) { fprintf(stream_, " timing() {\n"); - fprintf(stream_, " related_pin : \"%s\";\n", arc_set->from()->name()); + if (arc_set->from()) + fprintf(stream_, " related_pin : \"%s\";\n", arc_set->from()->name()); TimingSense sense = arc_set->sense(); if (sense != TimingSense::unknown && sense != TimingSense::non_unate) @@ -398,11 +399,14 @@ LibertyWriter::writeTimingModels(const TimingArc *arc, fprintf(stream_, " }\n"); const TableModel *slew_model = gate_model->slewModel(); - template_name = slew_model->tblTemplate()->name(); - fprintf(stream_, " %s_transition(%s) {\n", rf->name(), template_name); - writeTableModel(slew_model); - fprintf(stream_, " }\n"); - } else if (check_model) { + if (slew_model) { + template_name = slew_model->tblTemplate()->name(); + fprintf(stream_, " %s_transition(%s) {\n", rf->name(), template_name); + writeTableModel(slew_model); + fprintf(stream_, " }\n"); + } + } + else if (check_model) { const TableModel *model = check_model->model(); const char *template_name = model->tblTemplate()->name(); fprintf(stream_, " %s_constraint(%s) {\n", rf->name(), template_name); @@ -569,11 +573,15 @@ LibertyWriter::timingTypeString(const TimingArcSet *arc_set) else return "non_seq_hold_falling"; } + else if (role == TimingRole::clockTreePathMin()) + return "min_clock_tree_path"; + else if (role == TimingRole::clockTreePathMax()) + return "max_clock_tree_path"; else { report_->error(703, "%s/%s/%s timing arc type %s not supported.", library_->name(), - arc_set->from()->libertyCell()->name(), - arc_set->from()->name(), + arc_set->to()->libertyCell()->name(), + arc_set->to()->name(), role->asString()); return nullptr; } diff --git a/liberty/TableModel.cc b/liberty/TableModel.cc index 45e7cfe4..57e9865a 100644 --- a/liberty/TableModel.cc +++ b/liberty/TableModel.cc @@ -611,7 +611,7 @@ CheckTableModel::checkAxis(TableAxisPtr axis) TableModel::TableModel(TablePtr table, TableTemplate *tbl_template, ScaleFactorType scale_factor_type, - RiseFall *rf) : + const RiseFall *rf) : table_(table), tbl_template_(tbl_template), scale_factor_type_(int(scale_factor_type)), diff --git a/liberty/TimingArc.cc b/liberty/TimingArc.cc index 4176985e..ba7301c7 100644 --- a/liberty/TimingArc.cc +++ b/liberty/TimingArc.cc @@ -127,13 +127,13 @@ TimingArcAttrs::setModeValue(const char *value) } TimingModel * -TimingArcAttrs::model(RiseFall *rf) const +TimingArcAttrs::model(const RiseFall *rf) const { return models_[rf->index()]; } void -TimingArcAttrs::setModel(RiseFall *rf, +TimingArcAttrs::setModel(const RiseFall *rf, TimingModel *model) { models_[rf->index()] = model; diff --git a/liberty/TimingRole.cc b/liberty/TimingRole.cc index 1676a14a..4747a2e6 100644 --- a/liberty/TimingRole.cc +++ b/liberty/TimingRole.cc @@ -45,6 +45,8 @@ TimingRole *TimingRole::data_check_setup_; TimingRole *TimingRole::data_check_hold_; TimingRole *TimingRole::non_seq_setup_; TimingRole *TimingRole::non_seq_hold_; +TimingRole *TimingRole::clock_tree_path_min_; +TimingRole *TimingRole::clock_tree_path_max_; TimingRoleMap TimingRole::timing_roles_; @@ -111,6 +113,10 @@ TimingRole::init() MinMax::max(), TimingRole::setup(), 25); non_seq_hold_ = new TimingRole("non-sequential hold", false, true, true, MinMax::min(), TimingRole::hold(), 26); + clock_tree_path_min_ = new TimingRole("min clock tree path", false, false, false, + MinMax::min(), nullptr, 27); + clock_tree_path_max_ = new TimingRole("max clock tree path", false, false, false, + MinMax::max(), nullptr, 28); } void diff --git a/parasitics/ConcreteParasitics.cc b/parasitics/ConcreteParasitics.cc index 20851c23..2ab1086a 100644 --- a/parasitics/ConcreteParasitics.cc +++ b/parasitics/ConcreteParasitics.cc @@ -131,13 +131,13 @@ ConcreteParasitic::setPoleResidue(const Pin *, } ParasiticDeviceIterator * -ConcreteParasitic::deviceIterator() +ConcreteParasitic::deviceIterator() const { return nullptr; } ParasiticNodeIterator * -ConcreteParasitic::nodeIterator() +ConcreteParasitic::nodeIterator() const { return nullptr; } @@ -688,15 +688,15 @@ ConcreteParasiticNetwork::deleteDevices() } ParasiticNodeIterator * -ConcreteParasiticNetwork::nodeIterator() +ConcreteParasiticNetwork::nodeIterator() const { ConcreteParasiticNodeSeq *nodes = new ConcreteParasiticNodeSeq(); - ConcreteParasiticPinNodeMap::Iterator node_iter2(pin_nodes_); + ConcreteParasiticPinNodeMap::ConstIterator node_iter2(pin_nodes_); while (node_iter2.hasNext()) { ConcreteParasiticPinNode *node = node_iter2.next(); nodes->push_back(node); } - ConcreteParasiticSubNodeMap::Iterator node_iter1(sub_nodes_); + ConcreteParasiticSubNodeMap::ConstIterator node_iter1(sub_nodes_); while (node_iter1.hasNext()) { ConcreteParasiticSubNode *node = node_iter1.next(); nodes->push_back(node); @@ -705,7 +705,7 @@ ConcreteParasiticNetwork::nodeIterator() } ParasiticDeviceIterator * -ConcreteParasiticNetwork::deviceIterator() +ConcreteParasiticNetwork::deviceIterator() const { ConcreteParasiticDeviceSet *devices1 = new ConcreteParasiticDeviceSet(); devices(devices1); @@ -713,11 +713,11 @@ ConcreteParasiticNetwork::deviceIterator() } void -ConcreteParasiticNetwork::devices(ConcreteParasiticDeviceSet *devices) +ConcreteParasiticNetwork::devices(ConcreteParasiticDeviceSet *devices) const { // Collect devices into a set so they are only deleted once // because multiple sub-nodes or pin nodes can refer to them. - ConcreteParasiticSubNodeMap::Iterator node_iter1(sub_nodes_); + ConcreteParasiticSubNodeMap::ConstIterator node_iter1(sub_nodes_); while (node_iter1.hasNext()) { ConcreteParasiticSubNode *node = node_iter1.next(); ConcreteParasiticDeviceSeq::Iterator device_iter(node->devices()); @@ -727,10 +727,10 @@ ConcreteParasiticNetwork::devices(ConcreteParasiticDeviceSet *devices) } } - ConcreteParasiticPinNodeMap::Iterator node_iter2(pin_nodes_); + ConcreteParasiticPinNodeMap::ConstIterator node_iter2(pin_nodes_); while (node_iter2.hasNext()) { ConcreteParasiticPinNode *node = node_iter2.next(); - ConcreteParasiticDeviceSeq::Iterator device_iter(node->devices()); + ConcreteParasiticDeviceSeq::ConstIterator device_iter(node->devices()); while (device_iter.hasNext()) { ConcreteParasiticDevice *device = device_iter.next(); devices->insert(device); @@ -771,7 +771,7 @@ ConcreteParasiticNetwork::ensureParasiticNode(const Net *net, } ConcreteParasiticNode * -ConcreteParasiticNetwork::findNode(const Pin *pin) +ConcreteParasiticNetwork::findNode(const Pin *pin) const { return pin_nodes_.findKey(pin); } @@ -928,9 +928,9 @@ ConcreteParasitics::save() } float -ConcreteParasitics::capacitance(Parasitic *parasitic) const +ConcreteParasitics::capacitance(const Parasitic *parasitic) const { - ConcreteParasitic *cparasitic = static_cast(parasitic); + const ConcreteParasitic *cparasitic = static_cast(parasitic); return cparasitic->capacitance(); } @@ -1273,9 +1273,9 @@ ConcreteParasitics::poleResidue(const Parasitic *parasitic, //////////////////////////////////////////////////////////////// bool -ConcreteParasitics::isParasiticNetwork(Parasitic *parasitic) const +ConcreteParasitics::isParasiticNetwork(const Parasitic *parasitic) const { - ConcreteParasitic *cparasitic = static_cast(parasitic); + const ConcreteParasitic *cparasitic = static_cast(parasitic); return cparasitic && cparasitic->isParasiticNetwork(); } @@ -1373,10 +1373,10 @@ ConcreteParasitics::deleteParasiticNetworks(const Net *net) } bool -ConcreteParasitics::includesPinCaps(Parasitic *parasitic) const +ConcreteParasitics::includesPinCaps(const Parasitic *parasitic) const { - ConcreteParasiticNetwork *cparasitic = - static_cast(parasitic); + const ConcreteParasiticNetwork *cparasitic = + static_cast(parasitic); return cparasitic->includesPinCaps(); } @@ -1468,16 +1468,16 @@ ConcreteParasitics::makeResistor(const char *name, } ParasiticDeviceIterator * -ConcreteParasitics::deviceIterator(Parasitic *parasitic) +ConcreteParasitics::deviceIterator(const Parasitic *parasitic) { - ConcreteParasitic *cparasitic = static_cast(parasitic); + const ConcreteParasitic *cparasitic = static_cast(parasitic); return cparasitic->deviceIterator(); } ParasiticNodeIterator * -ConcreteParasitics::nodeIterator(Parasitic *parasitic) +ConcreteParasitics::nodeIterator(const Parasitic *parasitic) { - ConcreteParasitic *cparasitic = static_cast(parasitic); + const ConcreteParasitic *cparasitic = static_cast(parasitic); return cparasitic->nodeIterator(); } @@ -1513,11 +1513,11 @@ ConcreteParasitics::connectionPin(const ParasiticNode *node) const } ParasiticNode * -ConcreteParasitics::findNode(Parasitic *parasitic, +ConcreteParasitics::findNode(const Parasitic *parasitic, const Pin *pin) const { - ConcreteParasiticNetwork *cparasitic = - static_cast(parasitic); + const ConcreteParasiticNetwork *cparasitic = + static_cast(parasitic); return cparasitic->findNode(pin); } @@ -1674,7 +1674,7 @@ ConcreteParasitics::checkAnnotation2(const Pin *drvr_pin, //////////////////////////////////////////////////////////////// void -ConcreteParasitics::reduceTo(Parasitic *parasitic, +ConcreteParasitics::reduceTo(const Parasitic *parasitic, const Net *net, ReducedParasiticType reduce_to, const OperatingConditions *op_cond, @@ -1697,7 +1697,7 @@ ConcreteParasitics::reduceTo(Parasitic *parasitic, } void -ConcreteParasitics::reduceToPiElmore(Parasitic *parasitic, +ConcreteParasitics::reduceToPiElmore(const Parasitic *parasitic, const Net *net, const OperatingConditions *op_cond, const Corner *corner, @@ -1718,7 +1718,7 @@ ConcreteParasitics::reduceToPiElmore(Parasitic *parasitic, } void -ConcreteParasitics::reduceToPiElmore(Parasitic *parasitic, +ConcreteParasitics::reduceToPiElmore(const Parasitic *parasitic, const Pin *drvr_pin, const OperatingConditions *op_cond, const Corner *corner, @@ -1730,7 +1730,7 @@ ConcreteParasitics::reduceToPiElmore(Parasitic *parasitic, } void -ConcreteParasitics::reduceToPiPoleResidue2(Parasitic *parasitic, +ConcreteParasitics::reduceToPiPoleResidue2(const Parasitic *parasitic, const Net *net, const OperatingConditions *op_cond, const Corner *corner, @@ -1750,7 +1750,7 @@ ConcreteParasitics::reduceToPiPoleResidue2(Parasitic *parasitic, } void -ConcreteParasitics::reduceToPiPoleResidue2(Parasitic *parasitic, +ConcreteParasitics::reduceToPiPoleResidue2(const Parasitic *parasitic, const Pin *drvr_pin, const OperatingConditions *op_cond, const Corner *corner, diff --git a/parasitics/ConcreteParasitics.hh b/parasitics/ConcreteParasitics.hh index b4535bcf..c4323c34 100644 --- a/parasitics/ConcreteParasitics.hh +++ b/parasitics/ConcreteParasitics.hh @@ -59,7 +59,7 @@ public: virtual void setIsReducedParasiticNetwork(Parasitic *parasitic, bool is_reduced); - virtual float capacitance(Parasitic *parasitic) const; + virtual float capacitance(const Parasitic *parasitic) const; virtual bool isPiElmore(const Parasitic *parasitic) const; virtual Parasitic *findPiElmore(const Pin *drvr_pin, @@ -108,7 +108,7 @@ public: virtual void poleResidue(const Parasitic *parasitic, int pole_index, ComplexFloat &pole, ComplexFloat &residue) const; - virtual bool isParasiticNetwork(Parasitic *parasitic) const; + virtual bool isParasiticNetwork(const Parasitic *parasitic) const; virtual Parasitic *findParasiticNetwork(const Net *net, const ParasiticAnalysisPt *ap) const; virtual Parasitic *findParasiticNetwork(const Pin *pin, @@ -119,7 +119,7 @@ public: virtual void deleteParasiticNetwork(const Net *net, const ParasiticAnalysisPt *ap); virtual void deleteParasiticNetworks(const Net *net); - virtual bool includesPinCaps(Parasitic *parasitic) const; + virtual bool includesPinCaps(const Parasitic *parasitic) const; virtual ParasiticNode *ensureParasiticNode(Parasitic *parasitic, const Net *net, int id); @@ -142,12 +142,13 @@ public: virtual void makeResistor(const char *name, ParasiticNode *node1, ParasiticNode *node2, float res, const ParasiticAnalysisPt *ap); - virtual ParasiticDeviceIterator *deviceIterator(Parasitic *parasitic); - virtual ParasiticNodeIterator *nodeIterator(Parasitic *parasitic); + virtual ParasiticDeviceIterator *deviceIterator(const Parasitic *parasitic); + virtual ParasiticNodeIterator *nodeIterator(const Parasitic *parasitic); virtual const char *name(const ParasiticNode *node); virtual const Pin *connectionPin(const ParasiticNode *node) const; - virtual ParasiticNode *findNode(Parasitic *parasitic, const Pin *pin) const; + virtual ParasiticNode *findNode(const Parasitic *parasitic, + const Pin *pin) const; virtual float nodeGndCap(const ParasiticNode *node, const ParasiticAnalysisPt *ap) const; virtual ParasiticDeviceIterator * @@ -183,32 +184,32 @@ public: virtual void disconnectPinBefore(const Pin *pin); virtual void loadPinCapacitanceChanged(const Pin *pin); - virtual void reduceTo(Parasitic *parasitic, + virtual void reduceTo(const Parasitic *parasitic, const Net *net, ReducedParasiticType reduce_to, const OperatingConditions *op_cond, const Corner *corner, const MinMax *cnst_min_max, const ParasiticAnalysisPt *ap); - virtual void reduceToPiElmore(Parasitic *parasitic, + virtual void reduceToPiElmore(const Parasitic *parasitic, const Net *net, const OperatingConditions *op_cond, const Corner *corner, const MinMax *cnst_min_max, const ParasiticAnalysisPt *ap); - virtual void reduceToPiElmore(Parasitic *parasitic, + virtual void reduceToPiElmore(const Parasitic *parasitic, const Pin *drvr_pin, const OperatingConditions *op_cond, const Corner *corner, const MinMax *cnst_min_max, const ParasiticAnalysisPt *ap); - virtual void reduceToPiPoleResidue2(Parasitic *parasitic, + virtual void reduceToPiPoleResidue2(const Parasitic *parasitic, const Net *net, const OperatingConditions *op_cond, const Corner *corner, const MinMax *cnst_min_max, const ParasiticAnalysisPt *ap); - virtual void reduceToPiPoleResidue2(Parasitic *parasitic, + virtual void reduceToPiPoleResidue2(const Parasitic *parasitic, const Pin *drvr_pin, const OperatingConditions *op_cond, const Corner *corner, diff --git a/parasitics/ConcreteParasiticsPvt.hh b/parasitics/ConcreteParasiticsPvt.hh index 122b757b..0444b0f6 100644 --- a/parasitics/ConcreteParasiticsPvt.hh +++ b/parasitics/ConcreteParasiticsPvt.hh @@ -78,8 +78,8 @@ public: virtual void setPoleResidue(const Pin *load_pin, ComplexFloatSeq *poles, ComplexFloatSeq *residues); - virtual ParasiticDeviceIterator *deviceIterator(); - virtual ParasiticNodeIterator *nodeIterator(); + virtual ParasiticDeviceIterator *deviceIterator() const; + virtual ParasiticNodeIterator *nodeIterator() const; }; // Pi model for a driver pin. @@ -407,17 +407,17 @@ public: bool includesPinCaps() const { return includes_pin_caps_; } ConcreteParasiticNode *ensureParasiticNode(const Net *net, int id); - ConcreteParasiticNode *findNode(const Pin *pin); + ConcreteParasiticNode *findNode(const Pin *pin) const; ConcreteParasiticNode *ensureParasiticNode(const Pin *pin); virtual float capacitance() const; ConcreteParasiticPinNodeMap *pinNodes() { return &pin_nodes_; } ConcreteParasiticSubNodeMap *subNodes() { return &sub_nodes_; } void disconnectPin(const Pin *pin, const Net *net); - virtual ParasiticDeviceIterator *deviceIterator(); - virtual ParasiticNodeIterator *nodeIterator(); + virtual ParasiticDeviceIterator *deviceIterator() const; + virtual ParasiticNodeIterator *nodeIterator() const; virtual void devices(// Return value. - ConcreteParasiticDeviceSet *devices); + ConcreteParasiticDeviceSet *devices) const; private: void deleteNodes(); diff --git a/parasitics/NullParasitics.cc b/parasitics/NullParasitics.cc index 9ec90c39..351bea3b 100644 --- a/parasitics/NullParasitics.cc +++ b/parasitics/NullParasitics.cc @@ -72,7 +72,7 @@ NullParasitics::deleteDrvrReducedParasitics(const Pin *) } float -NullParasitics::capacitance(Parasitic *) const +NullParasitics::capacitance(const Parasitic *) const { return 0.0; } @@ -212,7 +212,7 @@ NullParasitics::poleResidue(const Parasitic *, } bool -NullParasitics::isParasiticNetwork(Parasitic *) const +NullParasitics::isParasiticNetwork(const Parasitic *) const { return false; } @@ -240,7 +240,7 @@ NullParasitics::makeParasiticNetwork(const Net *, } bool -NullParasitics::includesPinCaps(Parasitic *) const +NullParasitics::includesPinCaps(const Parasitic *) const { return false; } @@ -327,7 +327,7 @@ NullParasitics::connectionPin(const ParasiticNode *) const } ParasiticNode * -NullParasitics::findNode(Parasitic *, +NullParasitics::findNode(const Parasitic *, const Pin *) const { return nullptr; @@ -391,7 +391,7 @@ NullParasitics::otherNode(const ParasiticDevice *, } void -NullParasitics::reduceTo(Parasitic *, +NullParasitics::reduceTo(const Parasitic *, const Net *, ReducedParasiticType , const OperatingConditions *, @@ -402,7 +402,7 @@ NullParasitics::reduceTo(Parasitic *, } void -NullParasitics::reduceToPiElmore(Parasitic *, +NullParasitics::reduceToPiElmore(const Parasitic *, const Net *, const OperatingConditions *, const Corner *, @@ -412,7 +412,7 @@ NullParasitics::reduceToPiElmore(Parasitic *, } void -NullParasitics::reduceToPiElmore(Parasitic *, +NullParasitics::reduceToPiElmore(const Parasitic *, const Pin *, const OperatingConditions *, const Corner *, @@ -422,7 +422,7 @@ NullParasitics::reduceToPiElmore(Parasitic *, } void -NullParasitics::reduceToPiPoleResidue2(Parasitic *, const Net *, +NullParasitics::reduceToPiPoleResidue2(const Parasitic *, const Net *, const OperatingConditions *, const Corner *, const MinMax *, @@ -431,7 +431,7 @@ NullParasitics::reduceToPiPoleResidue2(Parasitic *, const Net *, } void -NullParasitics::reduceToPiPoleResidue2(Parasitic *, +NullParasitics::reduceToPiPoleResidue2(const Parasitic *, const Pin *, const OperatingConditions *, const Corner *, diff --git a/parasitics/ReduceParasitics.cc b/parasitics/ReduceParasitics.cc index 2f224312..be1b3093 100644 --- a/parasitics/ReduceParasitics.cc +++ b/parasitics/ReduceParasitics.cc @@ -280,7 +280,7 @@ class ReduceToPiElmore : public ReduceToPi { public: ReduceToPiElmore(StaState *sta); - void makePiElmore(Parasitic *parasitic_network, + void makePiElmore(const Parasitic *parasitic_network, const Pin *drvr_pin, ParasiticNode *drvr_node, float coupling_cap_factor, @@ -298,7 +298,7 @@ public: }; void -reduceToPiElmore(Parasitic *parasitic_network, +reduceToPiElmore(const Parasitic *parasitic_network, const Pin *drvr_pin, float coupling_cap_factor, const OperatingConditions *op_cond, @@ -332,7 +332,7 @@ ReduceToPiElmore::ReduceToPiElmore(StaState *sta) : } void -ReduceToPiElmore::makePiElmore(Parasitic *parasitic_network, +ReduceToPiElmore::makePiElmore(const Parasitic *parasitic_network, const Pin *drvr_pin, ParasiticNode *drvr_node, float coupling_cap_factor, @@ -400,12 +400,12 @@ class ReduceToPiPoleResidue2 : public ReduceToPi public: ReduceToPiPoleResidue2(StaState *sta); ~ReduceToPiPoleResidue2(); - void findPolesResidues(Parasitic *parasitic_network, + void findPolesResidues(const Parasitic *parasitic_network, Parasitic *pi_pole_residue, const Pin *drvr_pin, ParasiticNode *drvr_node, const ParasiticAnalysisPt *ap); - void makePiPoleResidue2(Parasitic *parasitic_network, + void makePiPoleResidue2(const Parasitic *parasitic_network, const Pin *drvr_pin, ParasiticNode *drvr_node, float coupling_cap_factor, @@ -466,7 +466,7 @@ ReduceToPiPoleResidue2::ReduceToPiPoleResidue2(StaState *sta) : // Three Moments of the Impulse Response", Proceedings of the 33rd // Design Automation Conference, 1996, pg 611-616. void -reduceToPiPoleResidue2(Parasitic *parasitic_network, +reduceToPiPoleResidue2(const Parasitic *parasitic_network, const Pin *drvr_pin, float coupling_cap_factor, const OperatingConditions *op_cond, @@ -494,7 +494,7 @@ reduceToPiPoleResidue2(Parasitic *parasitic_network, } void -ReduceToPiPoleResidue2::makePiPoleResidue2(Parasitic *parasitic_network, +ReduceToPiPoleResidue2::makePiPoleResidue2(const Parasitic *parasitic_network, const Pin *drvr_pin, ParasiticNode *drvr_node, float coupling_cap_factor, @@ -524,7 +524,7 @@ ReduceToPiPoleResidue2::~ReduceToPiPoleResidue2() } void -ReduceToPiPoleResidue2::findPolesResidues(Parasitic *parasitic_network, +ReduceToPiPoleResidue2::findPolesResidues(const Parasitic *parasitic_network, Parasitic *pi_pole_residue, const Pin *drvr_pin, ParasiticNode *drvr_node, diff --git a/parasitics/ReduceParasitics.hh b/parasitics/ReduceParasitics.hh index 65cc17c7..105e34b7 100644 --- a/parasitics/ReduceParasitics.hh +++ b/parasitics/ReduceParasitics.hh @@ -28,7 +28,7 @@ class StaState; // Reduce parasitic network to pi elmore model for drvr_pin. void -reduceToPiElmore(Parasitic *parasitic_network, +reduceToPiElmore(const Parasitic *parasitic_network, const Pin *drvr_pin, float coupling_cap_factor, const OperatingConditions *op_cond, @@ -40,7 +40,7 @@ reduceToPiElmore(Parasitic *parasitic_network, // Reduce parasitic network to pi and 2nd order pole/residue models // for drvr_pin. void -reduceToPiPoleResidue2(Parasitic *parasitic_network, +reduceToPiPoleResidue2(const Parasitic *parasitic_network, const Pin *drvr_pin, float coupling_cap_factor, const OperatingConditions *op_cond, diff --git a/search/ClkSkew.cc b/search/ClkSkew.cc index 8d001d9d..03c1019f 100644 --- a/search/ClkSkew.cc +++ b/search/ClkSkew.cc @@ -358,4 +358,29 @@ ClkSkews::findFanout(Vertex *from) return endpoints; } +//////////////////////////////////////////////////////////////// + +void +ClkSkews::findClkDelays(const Clock *clk, + // Return values. + ClkDelays &delays) +{ + for (Vertex *clk_vertex : *graph_->regClkVertices()) { + VertexPathIterator path_iter(clk_vertex, this); + while (path_iter.hasNext()) { + PathVertex *path = path_iter.next(); + const ClockEdge *path_clk_edge = path->clkEdge(this); + const RiseFall *clk_rf = path_clk_edge->transition(); + const Clock *path_clk = path_clk_edge->clock(); + if (path_clk == clk) { + Arrival arrival = path->arrival(this); + Delay clk_delay = delayAsFloat(arrival) - path_clk_edge->time(); + const MinMax *min_max = path->minMax(this); + const RiseFall *rf = path->transition(this); + delays[clk_rf->index()][rf->index()].setValue(min_max, clk_delay); + } + } + } +} + } // namespace diff --git a/search/ClkSkew.hh b/search/ClkSkew.hh index 6e9c332f..b7c7a290 100644 --- a/search/ClkSkew.hh +++ b/search/ClkSkew.hh @@ -19,6 +19,7 @@ #include "Map.hh" #include "SdcClass.hh" #include "StaState.hh" +#include "Transition.hh" #include "SearchClass.hh" namespace sta { @@ -27,7 +28,7 @@ class ClkSkew; typedef Map ClkSkewMap; -// Find and report min clock skews. +// Find and report clock skews between source/target registers. class ClkSkews : public StaState { public: @@ -37,10 +38,13 @@ public: const Corner *corner, const SetupHold *setup_hold, int digits); - // Find worst clock skew. + // Find worst clock skew between src/target registers. float findWorstClkSkew(const Corner *corner, const SetupHold *setup_hold); - + void findClkDelays(const Clock *clk, + // Return values. + ClkDelays &delays); + protected: void findClkSkew(ClockSet *clks, const Corner *corner, diff --git a/search/MakeTimingModel.cc b/search/MakeTimingModel.cc index 6cbae47e..734c80f7 100644 --- a/search/MakeTimingModel.cc +++ b/search/MakeTimingModel.cc @@ -40,9 +40,11 @@ #include "Sta.hh" #include "VisitPathEnds.hh" #include "ArcDelayCalc.hh" +#include "ClkSkew.hh" namespace sta { +using std::min; using std::max; using std::make_shared; @@ -96,6 +98,7 @@ MakeTimingModel::makeTimingModel() findTimingFromInputs(); findClkedOutputPaths(); + findClkInsertionDelays(); cell_->finish(false, report_, debug_); restoreSdc(); @@ -505,6 +508,63 @@ MakeTimingModel::findClkedOutputPaths() delete output_iter; } +//////////////////////////////////////////////////////////////// + +void +MakeTimingModel::findClkInsertionDelays() +{ + Instance *top_inst = network_->topInstance(); + Cell *top_cell = network_->cell(top_inst); + CellPortIterator *port_iter = network_->portIterator(top_cell); + while (port_iter->hasNext()) { + Port *port = port_iter->next(); + if (network_->direction(port)->isInput()) { + const char *port_name = network_->name(port); + LibertyPort *lib_port = cell_->findLibertyPort(port_name); + Pin *pin = network_->findPin(top_inst, port); + if (sdc_->isClock(pin)) { + lib_port->setIsClock(true); + ClockSet *clks = sdc_->findClocks(pin); + size_t clk_count = clks->size(); + if (clk_count == 1) { + for (const Clock *clk : *clks) { + TimingArcAttrsPtr attrs = nullptr; + ClkDelays delays; + sta_->findClkDelays(clk, delays); + for (const MinMax *min_max : MinMax::range()) { + for (const RiseFall *clk_rf : RiseFall::range()) { + int clk_rf_index = clk_rf->index(); + float delay = min_max->initValue(); + for (const int end_rf_index : RiseFall::rangeIndex()) { + float delay1; + bool exists; + delays[clk_rf_index][end_rf_index].value(min_max, delay1, exists); + if (exists) + delay = min_max->minMax(delay, delay1); + } + TimingModel *model = makeGateModelScalar(delay, clk_rf); + if (attrs == nullptr) + attrs = std::make_shared(); + attrs->setModel(clk_rf, model); + } + if (attrs) + attrs->setTimingSense(TimingSense::positive_unate); + TimingRole *role = (min_max == MinMax::min()) + ? TimingRole::clockTreePathMin() + : TimingRole::clockTreePathMax(); + lib_builder_->makeClockTreePathArcs(cell_, lib_port, nullptr, + role, attrs); + } + } + } + } + } + } + delete port_iter; +} + +//////////////////////////////////////////////////////////////// + LibertyPort * MakeTimingModel::modelPort(const Pin *pin) { @@ -514,7 +574,7 @@ MakeTimingModel::modelPort(const Pin *pin) TimingModel * MakeTimingModel::makeScalarCheckModel(float value, ScaleFactorType scale_factor_type, - RiseFall *rf) + const RiseFall *rf) { TablePtr table = make_shared(value); TableTemplate *tbl_template = @@ -528,7 +588,7 @@ MakeTimingModel::makeScalarCheckModel(float value, TimingModel * MakeTimingModel::makeGateModelScalar(Delay delay, Slew slew, - RiseFall *rf) + const RiseFall *rf) { TablePtr delay_table = make_shared(delayAsFloat(delay)); TablePtr slew_table = make_shared(delayAsFloat(slew)); @@ -544,12 +604,27 @@ MakeTimingModel::makeGateModelScalar(Delay delay, return gate_model; } +TimingModel * +MakeTimingModel::makeGateModelScalar(Delay delay, + const RiseFall *rf) +{ + TablePtr delay_table = make_shared(delayAsFloat(delay)); + TableTemplate *tbl_template = + library_->findTableTemplate("scalar", TableTemplateType::delay); + TableModel *delay_model = new TableModel(delay_table, tbl_template, + ScaleFactorType::cell, rf); + GateTableModel *gate_model = new GateTableModel(delay_model, nullptr, + nullptr, nullptr, + nullptr, nullptr); + return gate_model; +} + // Eval the driver pin model along its load capacitance // axis and add the input to output 'delay' to the table values. TimingModel * MakeTimingModel::makeGateModelTable(const Pin *output_pin, Delay delay, - RiseFall *rf) + const RiseFall *rf) { const DcalcAnalysisPt *dcalc_ap = corner_->findDcalcAnalysisPt(min_max_); const Pvt *pvt = dcalc_ap->operatingConditions(); diff --git a/search/MakeTimingModelPvt.hh b/search/MakeTimingModelPvt.hh index 2895acee..d2ae18f2 100644 --- a/search/MakeTimingModelPvt.hh +++ b/search/MakeTimingModelPvt.hh @@ -62,6 +62,7 @@ private: void findTimingFromInputs(); void findTimingFromInput(Port *input_port); void findClkedOutputPaths(); + void findClkInsertionDelays(); void findOutputDelays(const RiseFall *input_rf, OutputPinDelays &output_pin_delays); void makeSetupHoldTimingArcs(const Pin *input_pin, @@ -70,13 +71,15 @@ private: OutputPinDelays &output_pin_delays); TimingModel *makeScalarCheckModel(float value, ScaleFactorType scale_factor_type, - RiseFall *rf); + const RiseFall *rf); TimingModel *makeGateModelScalar(Delay delay, Slew slew, - RiseFall *rf); + const RiseFall *rf); + TimingModel *makeGateModelScalar(Delay delay, + const RiseFall *rf); TimingModel *makeGateModelTable(const Pin *output_pin, Delay delay, - RiseFall *rf); + const RiseFall *rf); TableTemplate *ensureTableTemplate(const TableTemplate *drvr_template, TableAxisPtr load_axis); TableAxisPtr loadCapacitanceAxis(const TableModel *table); diff --git a/search/Sta.cc b/search/Sta.cc index a67dfae7..58dae681 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -2617,6 +2617,15 @@ Sta::findWorstClkSkew(const SetupHold *setup_hold) return clk_skews_->findWorstClkSkew(cmd_corner_, setup_hold); } +void +Sta::findClkDelays(const Clock *clk, + // Return values. + ClkDelays &delays) +{ + clkSkewPreamble(); + clk_skews_->findClkDelays(clk, delays); +} + void Sta::clkSkewPreamble() { diff --git a/tcl/Sdc.tcl b/tcl/Sdc.tcl index 4f5b97d5..c8b67729 100644 --- a/tcl/Sdc.tcl +++ b/tcl/Sdc.tcl @@ -454,7 +454,6 @@ proc get_cells { args } { parse_key_args "get_cells" args keys {-hsc -filter -of_objects} \ flags {-hierarchical -regexp -nocase -quiet} - check_argc_eq0or1 "get_cells" $args check_nocase_flag flags set regexp [info exists flags(-regexp)] @@ -493,23 +492,20 @@ proc get_cells { args } { $pin_iter finish } } else { - if { $args == {} } { - set insts [network_leaf_instances] - } else { - foreach pattern $patterns { - if { $divider != $hierarchy_separator } { - regsub $divider $pattern $hierarchy_separator pattern - } - if { $hierarchical } { - set matches [find_instances_hier_matching $pattern $regexp $nocase] - } else { - set matches [find_instances_matching $pattern $regexp $nocase] - } - if { $matches == {} && !$quiet} { - sta_warn 322 "instance '$pattern' not found." - } - set insts [concat $insts $matches] + check_argc_eq1 "get_cells" $args + foreach pattern $patterns { + if { $divider != $hierarchy_separator } { + regsub $divider $pattern $hierarchy_separator pattern } + if { $hierarchical } { + set matches [find_instances_hier_matching $pattern $regexp $nocase] + } else { + set matches [find_instances_matching $pattern $regexp $nocase] + } + if { $matches == {} && !$quiet} { + sta_warn 322 "instance '$pattern' not found." + } + set insts [concat $insts $matches] } } if [info exists keys(-filter)] { @@ -586,7 +582,6 @@ proc get_lib_cells { args } { global hierarchy_separator parse_key_args "get_lib_cells" args keys {-hsc -of_objects} \ flags {-regexp -nocase -quiet} - check_argc_eq0or1 "get_lib_cells" $args check_nocase_flag flags set regexp [info exists flags(-regexp)] @@ -601,6 +596,7 @@ proc get_lib_cells { args } { lappend cells [$inst liberty_cell] } } else { + check_argc_eq1 "get_lib_cells" $args # Copy backslashes that will be removed by foreach. set patterns [string map {\\ \\\\} [lindex $args 0]] # Parse library_name/pattern. @@ -838,7 +834,7 @@ proc get_nets { args } { define_cmd_args "get_pins" \ {[-hierarchical] [-hsc separator] [-quiet] [-filter expr]\ - [-regexp] [-nocase] [-of_objects objects] patterns} + [-regexp] [-nocase] [-of_objects objects] [patterns]} define_cmd_alias "get_pin" "get_pins"