diff --git a/CMakeLists.txt b/CMakeLists.txt index f706de89..83457ea8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,7 @@ set(STA_SOURCE app/StaMain.cc dcalc/ArcDelayCalc.cc + dcalc/ArcDcalcWaveforms.cc dcalc/ArnoldiDelayCalc.cc dcalc/ArnoldiReduce.cc dcalc/DcalcAnalysisPt.cc @@ -73,7 +74,6 @@ set(STA_SOURCE dcalc/LumpedCapDelayCalc.cc dcalc/NetCaps.cc dcalc/ParallelDelayCalc.cc - dcalc/SlewDegradeDelayCalc.cc dcalc/UnitDelayCalc.cc graph/DelayFloat.cc diff --git a/dcalc/SlewDegradeDelayCalc.hh b/dcalc/ArcDcalcWaveforms.cc similarity index 54% rename from dcalc/SlewDegradeDelayCalc.hh rename to dcalc/ArcDcalcWaveforms.cc index 7195985d..6b282596 100644 --- a/dcalc/SlewDegradeDelayCalc.hh +++ b/dcalc/ArcDcalcWaveforms.cc @@ -14,14 +14,30 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#pragma once +#include "ArcDcalcWaveforms.hh" + namespace sta { -class ArcDelayCalc; -class StaState; +Table1 +ArcDcalcWaveforms::inputWaveform(const Pin *, + const RiseFall *, + const Corner *, + const MinMax *) +{ + return Table1(); +} -ArcDelayCalc * -makeSlewDegradeDelayCalc(StaState *sta); +Table1 +ArcDcalcWaveforms::drvrRampWaveform(const Pin *, + const RiseFall *, + const Pin *, + const RiseFall *, + const Pin *, + const Corner *, + const MinMax *) +{ + return Table1(); +} } // namespace diff --git a/dcalc/ArcDcalcWaveforms.hh b/dcalc/ArcDcalcWaveforms.hh new file mode 100644 index 00000000..a47eff0b --- /dev/null +++ b/dcalc/ArcDcalcWaveforms.hh @@ -0,0 +1,59 @@ +// 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 "MinMax.hh" +#include "TableModel.hh" +#include "NetworkClass.hh" + +namespace sta { + +class Corner; +class DcalcAnalysisPt; + +// Abstract class for the graph delay calculator traversal to interface +class ArcDcalcWaveforms +{ +public: + virtual Table1 inputWaveform(const Pin *in_pin, + const RiseFall *in_rf, + const Corner *corner, + const MinMax *min_max); + virtual Table1 drvrWaveform(const Pin *in_pin, + const RiseFall *in_rf, + const Pin *drvr_pin, + const RiseFall *drvr_rf, + const Corner *corner, + const MinMax *min_max) = 0; + virtual Table1 loadWaveform(const Pin *in_pin, + const RiseFall *in_rf, + const Pin *drvr_pin, + const RiseFall *drvr_rf, + const Pin *load_pin, + const Corner *corner, + const MinMax *min_max) = 0; + virtual Table1 drvrRampWaveform(const Pin *in_pin, + const RiseFall *in_rf, + const Pin *drvr_pin, + const RiseFall *drvr_rf, + const Pin *load_pin, + const Corner *corner, + const MinMax *min_max); +}; + +} // namespace + diff --git a/dcalc/ArcDelayCalc.cc b/dcalc/ArcDelayCalc.cc index 56825b3b..8999a3af 100644 --- a/dcalc/ArcDelayCalc.cc +++ b/dcalc/ArcDelayCalc.cc @@ -16,10 +16,6 @@ #include "ArcDelayCalc.hh" -#include "TimingModel.hh" -#include "TimingArc.hh" -#include "GraphDelayCalc.hh" - namespace sta { ArcDelayCalc::ArcDelayCalc(StaState *sta): @@ -27,27 +23,114 @@ ArcDelayCalc::ArcDelayCalc(StaState *sta): { } -TimingModel * -ArcDelayCalc::model(const TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap) const +void +ArcDelayCalc::gateDelay(const TimingArc *arc, + const Slew &in_slew, + float load_cap, + const Parasitic *parasitic, + float, + const Pvt *, + const DcalcAnalysisPt *dcalc_ap, + // Return values. + ArcDelay &gate_delay, + Slew &drvr_slew) { - const OperatingConditions *op_cond = dcalc_ap->operatingConditions(); - const TimingArc *corner_arc = arc->cornerArc(dcalc_ap->libertyIndex()); - return corner_arc->model(op_cond); + LoadPinIndexMap load_pin_index_map(network_); + ArcDcalcResult dcalc_result = gateDelay(nullptr, arc, in_slew, load_cap, parasitic, + load_pin_index_map, dcalc_ap); + gate_delay = dcalc_result.gateDelay(); + drvr_slew = dcalc_result.drvrSlew(); } -GateTimingModel * -ArcDelayCalc::gateModel(const TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap) const +//////////////////////////////////////////////////////////////// + +ArcDcalcArg::ArcDcalcArg() : + drvr_pin_(nullptr), + edge_(nullptr), + arc_(nullptr), + in_slew_(0.0), + parasitic_(nullptr) { - return dynamic_cast(model(arc, dcalc_ap)); } -CheckTimingModel * -ArcDelayCalc::checkModel(const TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap) const +ArcDcalcArg::ArcDcalcArg(const Pin *drvr_pin, + Edge *edge, + const TimingArc *arc, + const Slew in_slew, + const Parasitic *parasitic) : + drvr_pin_(drvr_pin), + edge_(edge), + arc_(arc), + in_slew_(in_slew), + parasitic_(parasitic) { - return dynamic_cast(model(arc, dcalc_ap)); +} + +void +ArcDcalcArg::setParasitic(const Parasitic *parasitic) +{ + parasitic_ = parasitic; +} + +//////////////////////////////////////////////////////////////// + +ArcDcalcResult::ArcDcalcResult() : + gate_delay_(0.0), + drvr_slew_(0.0) +{ +} + +ArcDcalcResult::ArcDcalcResult(size_t load_count) : + gate_delay_(0.0), + drvr_slew_(0.0) +{ + wire_delays_.resize(load_count); + load_slews_.resize(load_count); +} + +void +ArcDcalcResult::setGateDelay(ArcDelay gate_delay) +{ + gate_delay_ = gate_delay; +} + +void +ArcDcalcResult::setDrvrSlew(Slew drvr_slew) +{ + drvr_slew_ = drvr_slew; +} + +ArcDelay +ArcDcalcResult::wireDelay(size_t load_idx) const +{ + return wire_delays_[load_idx]; +} + +void +ArcDcalcResult::setWireDelay(size_t load_idx, + ArcDelay wire_delay) +{ + wire_delays_[load_idx] = wire_delay; +} + +void +ArcDcalcResult::setLoadCount(size_t load_count) +{ + wire_delays_.resize(load_count); + load_slews_.resize(load_count); +} + +Slew +ArcDcalcResult::loadSlew(size_t load_idx) const +{ + return load_slews_[load_idx]; +} + +void +ArcDcalcResult::setLoadSlew(size_t load_idx, + Slew load_slew) +{ + load_slews_[load_idx] = load_slew; } } // namespace diff --git a/dcalc/Arnoldi.hh b/dcalc/Arnoldi.hh index 0437e914..79f3a77a 100644 --- a/dcalc/Arnoldi.hh +++ b/dcalc/Arnoldi.hh @@ -74,7 +74,6 @@ struct timing_table const LibertyCell *cell; const Pvt *pvt; float in_slew; - float relcap; }; } // namespace diff --git a/dcalc/ArnoldiDelayCalc.cc b/dcalc/ArnoldiDelayCalc.cc index 15610b41..11f8d775 100644 --- a/dcalc/ArnoldiDelayCalc.cc +++ b/dcalc/ArnoldiDelayCalc.cc @@ -117,32 +117,26 @@ public: Parasitic *findParasitic(const Pin *drvr_pin, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) override; - ReducedParasiticType reducedParasiticType() const override; - void inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap) override; - void gateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) override; - void loadDelay(const Pin *load_pin, - // Return values. - ArcDelay &wire_delay, - Slew &load_slew) override; - string reportGateDelay(const TimingArc *arc, + ArcDcalcResult inputPortDelay(const Pin *port_pin, + float in_slew, + const RiseFall *rf, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) override; + ArcDcalcResult gateDelay(const Pin *drvr_pin, + const TimingArc *arc, + const Slew &in_slew, + // Pass in load_cap or parasitic. + float load_cap, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) override; + string reportGateDelay(const Pin *drvr_pin, + const TimingArc *arc, const Slew &in_slew, float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap, int digits) override; void delay_work_set_thresholds(delay_work *D, @@ -152,14 +146,12 @@ public: double derate); private: - void gateDelaySlew(const LibertyCell *drvr_cell, - const GateTableModel *table_model, - const Slew &in_slew, - float related_out_cap, - const Pvt *pvt, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew); + ArcDcalcResult gateDelaySlew(const LibertyCell *drvr_cell, + const TimingArc *arc, + const GateTableModel *table_model, + const Slew &in_slew, + const LoadPinIndexMap &load_pin_index_map, + const Pvt *pvt); void ar1_ceff_delay(delay_work *D, timing_table *tab, arnoldi1 *mod, @@ -224,7 +216,6 @@ private: double *_delayV; double *_slewV; int pin_n_; - bool input_port_; ArnoldiReduce *reduce_; delay_work *delay_work_; }; @@ -306,25 +297,20 @@ ArnoldiDelayCalc::findParasitic(const Pin *drvr_pin, return parasitic; } -ReducedParasiticType -ArnoldiDelayCalc::reducedParasiticType() const +ArcDcalcResult +ArnoldiDelayCalc::inputPortDelay(const Pin *, + float in_slew, + const RiseFall *rf, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *) { - return ReducedParasiticType::arnoldi; -} - -void -ArnoldiDelayCalc::inputPortDelay(const Pin *drvr_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap) -{ - LumpedCapDelayCalc::inputPortDelay(drvr_pin, in_slew, rf, parasitic, dcalc_ap); rcmodel_ = nullptr; _delayV[0] = 0.0; _slewV[0] = in_slew; - int j; + LibertyLibrary *drvr_library = network_->defaultLibertyLibrary(); + ArcDcalcResult dcalc_result(load_pin_index_map.size()); if (parasitic) { rcmodel_ = reinterpret_cast(const_cast(parasitic)); pin_n_ = rcmodel_->n; @@ -335,69 +321,67 @@ ArnoldiDelayCalc::inputPortDelay(const Pin *drvr_pin, _delayV = (double*)realloc(_delayV,_pinNmax * sizeof(double)); _slewV = (double*)realloc(_slewV,_pinNmax * sizeof(double)); } - pin_n_ = 1; pin_n_ = rcmodel_->n; - double slew_derate = drvr_library_->slewDerateFromLibrary(); - double lo_thresh = drvr_library_->slewLowerThreshold(drvr_rf_); - double hi_thresh = drvr_library_->slewUpperThreshold(drvr_rf_); - bool rising = (drvr_rf_ == RiseFall::rise()); - delay_work_set_thresholds(delay_work_, lo_thresh, hi_thresh, rising, - slew_derate); + double slew_derate = drvr_library->slewDerateFromLibrary(); + double lo_thresh = drvr_library->slewLowerThreshold(rf); + double hi_thresh = drvr_library->slewUpperThreshold(rf); + bool rising = (rf == RiseFall::rise()); + delay_work_set_thresholds(delay_work_, lo_thresh, hi_thresh, rising, slew_derate); delay_c *c = delay_work_->c; double c_log = c->vlg; - for (j=1;jelmore(j); - _delayV[j] = 0.6931472*elmore; - _slewV[j] = in_slew + c_log*elmore/slew_derate; + double wire_delay = 0.6931472*elmore; + double load_slew = in_slew + c_log*elmore/slew_derate; + _delayV[j] = wire_delay; + _slewV[j] = load_slew; + + const Pin *load_pin = rcmodel_->pinV[j]; + auto load_idx_itr = load_pin_index_map.find(load_pin); + if (load_idx_itr != load_pin_index_map.end()) { + size_t load_idx = load_idx_itr->second; + dcalc_result.setWireDelay(load_idx, wire_delay); + dcalc_result.setLoadSlew(load_idx, load_slew); + } } } -} - -void -ArnoldiDelayCalc::gateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) -{ - input_port_ = false; - drvr_rf_ = arc->toEdge()->asRiseFall(); - const LibertyCell *drvr_cell = arc->from()->libertyCell(); - drvr_library_ = drvr_cell->libertyLibrary(); - drvr_parasitic_ = drvr_parasitic; - ConcreteParasitic *drvr_cparasitic = - reinterpret_cast(const_cast(drvr_parasitic)); - rcmodel_ = dynamic_cast(drvr_cparasitic); - GateTimingModel *model = gateModel(arc, dcalc_ap); - GateTableModel *table_model = dynamic_cast(model); - if (table_model && rcmodel_) - gateDelaySlew(drvr_cell, table_model, in_slew, - related_out_cap, pvt, - gate_delay, drvr_slew); else - LumpedCapDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic, - related_out_cap, pvt, dcalc_ap, - gate_delay, drvr_slew); - drvr_slew_ = drvr_slew; - multi_drvr_slew_factor_ = 1.0F; + dcalc_result = makeResult(drvr_library, rf, 0.0, in_slew, load_pin_index_map); + return dcalc_result; } -void +ArcDcalcResult +ArnoldiDelayCalc::gateDelay(const Pin *drvr_pin, + const TimingArc *arc, + const Slew &in_slew, + float load_cap, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) +{ + const LibertyCell *drvr_cell = arc->from()->libertyCell(); + ConcreteParasitic *cparasitic = + reinterpret_cast(const_cast(parasitic)); + rcmodel_ = dynamic_cast(cparasitic); + GateTableModel *table_model = gateTableModel(arc, dcalc_ap); + if (table_model && rcmodel_) { + const Pvt *pvt = pinPvt(drvr_pin, dcalc_ap); + return gateDelaySlew(drvr_cell, arc, table_model, in_slew, load_pin_index_map, pvt); + } + else + return LumpedCapDelayCalc::gateDelay(drvr_pin, arc, in_slew, load_cap, + parasitic, load_pin_index_map, dcalc_ap); +} + +ArcDcalcResult ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell, + const TimingArc *arc, const GateTableModel *table_model, const Slew &in_slew, - float related_out_cap, - const Pvt *pvt, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) + const LoadPinIndexMap &load_pin_index_map, + const Pvt *pvt) { pin_n_ = rcmodel_->n; if (pin_n_ >= _pinNmax) { @@ -407,12 +391,15 @@ ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell, _slewV = (double*)realloc(_slewV,_pinNmax * sizeof(double)); } + ArcDcalcResult dcalc_result(load_pin_index_map.size()); pin_n_ = rcmodel_->n; - if (table_model) { - double slew_derate = drvr_library_->slewDerateFromLibrary(); - double lo_thresh = drvr_library_->slewLowerThreshold(drvr_rf_); - double hi_thresh = drvr_library_->slewUpperThreshold(drvr_rf_); - bool rising = (drvr_rf_ == RiseFall::rise()); + const RiseFall *rf = arc->toEdge()->asRiseFall(); + if (table_model && rf) { + const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary(); + double slew_derate = drvr_library->slewDerateFromLibrary(); + double lo_thresh = drvr_library->slewLowerThreshold(rf); + double hi_thresh = drvr_library->slewUpperThreshold(rf); + bool rising = (rf == RiseFall::rise()); delay_work_set_thresholds(delay_work_, lo_thresh, hi_thresh, rising, slew_derate); if (rcmodel_->order > 0) { @@ -421,48 +408,43 @@ ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell, tab.cell = drvr_cell; tab.pvt = pvt; tab.in_slew = delayAsFloat(in_slew); - tab.relcap = related_out_cap; ar1_ceff_delay(delay_work_, &tab, rcmodel_, _delayV, _slewV); } - gate_delay = _delayV[0]; - drvr_slew = _slewV[0]; - } -} + dcalc_result.setGateDelay(_delayV[0]); + dcalc_result.setDrvrSlew(_slewV[0]); -void -ArnoldiDelayCalc::loadDelay(const Pin *load_pin, - // Return values. - ArcDelay &wire_delay, - Slew &load_slew) -{ - // This does not appear to handle input port parasitics correctly. - wire_delay = 0.0; - load_slew = drvr_slew_ * multi_drvr_slew_factor_; - if (rcmodel_) { - // HACK - for (int i = 0; i < rcmodel_->n; i++) { - if (rcmodel_->pinV[i] == load_pin) { - wire_delay = _delayV[i] - _delayV[0]; - load_slew = _slewV[i] * multi_drvr_slew_factor_; - break; + if (rcmodel_) { + for (int i = 0; i < rcmodel_->n; i++) { + const Pin *load_pin = rcmodel_->pinV[i]; + auto load_idx_itr = load_pin_index_map.find(load_pin); + if (load_idx_itr != load_pin_index_map.end()) { + size_t load_idx = load_idx_itr->second; + ArcDelay wire_delay = _delayV[i] - _delayV[0]; + Slew load_slew = _slewV[i]; + thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew); + dcalc_result.setWireDelay(load_idx, wire_delay); + dcalc_result.setLoadSlew(load_idx, load_slew); + } } } } - thresholdAdjust(load_pin, wire_delay, load_slew); + return dcalc_result; } string -ArnoldiDelayCalc::reportGateDelay(const TimingArc *, - const Slew &, - float, - const Parasitic *, - float, - const Pvt *, - const DcalcAnalysisPt *, - int) +ArnoldiDelayCalc::reportGateDelay(const Pin *drvr_pin, + const TimingArc *arc, + const Slew &in_slew, + float load_cap, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap, + int digits) { - return ""; + return LumpedCapDelayCalc::reportGateDelay(drvr_pin, arc, in_slew, load_cap, + parasitic, load_pin_index_map, + dcalc_ap, digits); } //////////////////////////////////////////////////////////////// @@ -1310,7 +1292,7 @@ ArnoldiDelayCalc::ra_get_r(delay_work *D, c1 = ctot; ArcDelay d1; Slew s1; - tab->table->gateDelay(tab->pvt, tab->in_slew, c1, tab->relcap, pocv_enabled_, d1, s1); + tab->table->gateDelay(tab->pvt, tab->in_slew, c1, pocv_enabled_, d1, s1); tlohi = slew_derate*delayAsFloat(s1); r = tlohi/(c_log*c1); if (rdelay>0.0 && r > rdelay) @@ -1332,7 +1314,7 @@ ArnoldiDelayCalc::ra_get_s(delay_work *D, double tlohi,smin,s; ArcDelay d1; Slew s1; - tab->table->gateDelay(tab->pvt, tab->in_slew, c, tab->relcap, pocv_enabled_, d1, s1); + tab->table->gateDelay(tab->pvt, tab->in_slew, c, pocv_enabled_, d1, s1); tlohi = slew_derate*delayAsFloat(s1); smin = r*c*c_smin; // c_smin = ra_hinv((1-vhi)/vhi-log(vhi)) + log(vhi); if (c_log*r*c >= tlohi) { @@ -1365,8 +1347,8 @@ ArnoldiDelayCalc::ra_rdelay_1(timing_table *tab, return 0.0; ArcDelay d1, d2; Slew s1, s2; - tab->table->gateDelay(tab->pvt, tab->in_slew, c1, tab->relcap, pocv_enabled_, d1, s1); - tab->table->gateDelay(tab->pvt, tab->in_slew, c2, tab->relcap, pocv_enabled_, d2, s2); + tab->table->gateDelay(tab->pvt, tab->in_slew, c1, pocv_enabled_, d1, s1); + tab->table->gateDelay(tab->pvt, tab->in_slew, c2, pocv_enabled_, d2, s2); double dt50 = delayAsFloat(d1)-delayAsFloat(d2); if (dt50 <= 0.0) return 0.0; @@ -1418,8 +1400,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D, units_->timeUnit()->asString(s)); thix = ra_solve_for_t(p,s,vhi); tlox = ra_solve_for_t(p,s,vlo); - tab->table->gateDelay(tab->pvt,tab->in_slew, ctot, tab->relcap, pocv_enabled_, - df, sf); + tab->table->gateDelay(tab->pvt,tab->in_slew, ctot, pocv_enabled_, df, sf); debugPrint(debug_, "arnoldi", 1, "table slew (in_slew %s ctot %s) = %s", units_->timeUnit()->asString(tab->in_slew), units_->capacitanceUnit()->asString(ctot), @@ -1430,7 +1411,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D, units_->timeUnit()->asString(tlox-thix)); } ceff = ctot; - tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, tab->relcap, pocv_enabled_, + tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, pocv_enabled_, df, sf); t50_sy = delayAsFloat(df); t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5); @@ -1472,7 +1453,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D, units_->timeUnit()->asString(ceff_time), units_->capacitanceUnit()->asString(ceff)); - tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, tab->relcap, pocv_enabled_, df, sf); + tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, pocv_enabled_, df, sf); t50_sy = delayAsFloat(df); t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5); for (j=0;jn;j++) { diff --git a/dcalc/DelayCalc.cc b/dcalc/DelayCalc.cc index 2c5c1ba0..cfb940de 100644 --- a/dcalc/DelayCalc.cc +++ b/dcalc/DelayCalc.cc @@ -20,7 +20,6 @@ #include "StringUtil.hh" #include "UnitDelayCalc.hh" #include "LumpedCapDelayCalc.hh" -#include "SlewDegradeDelayCalc.hh" #include "DmpDelayCalc.hh" #include "ArnoldiDelayCalc.hh" @@ -35,7 +34,6 @@ registerDelayCalcs() { registerDelayCalc("unit", makeUnitDelayCalc); registerDelayCalc("lumped_cap", makeLumpedCapDelayCalc); - registerDelayCalc("slew_degrade", makeSlewDegradeDelayCalc); registerDelayCalc("dmp_ceff_elmore", makeDmpCeffElmoreDelayCalc); registerDelayCalc("dmp_ceff_two_pole", makeDmpCeffTwoPoleDelayCalc); registerDelayCalc("arnoldi", makeArnoldiDelayCalc); diff --git a/dcalc/DelayCalc.i b/dcalc/DelayCalc.i index 52711847..b96b0470 100644 --- a/dcalc/DelayCalc.i +++ b/dcalc/DelayCalc.i @@ -19,6 +19,8 @@ // along with this program. If not, see . #include "Sta.hh" +#include "ArcDelayCalc.hh" +#include "dcalc/ArcDcalcWaveforms.hh" %} @@ -59,4 +61,76 @@ report_delay_calc_cmd(Edge *edge, return Sta::sta()->reportDelayCalc(edge, arc, corner, min_max, digits); } +//////////////////////////////////////////////////////////////// + +Table1 +ccs_input_waveform(const Pin *in_pin, + const RiseFall *in_rf, + const Corner *corner, + const MinMax *min_max) +{ + cmdLinkedNetwork(); + Sta *sta = Sta::sta(); + ArcDcalcWaveforms *arc_dcalc = dynamic_cast(sta->arcDelayCalc()); + if (arc_dcalc) + return arc_dcalc->inputWaveform(in_pin, in_rf, corner, min_max); + else + return Table1(); +} + +Table1 +ccs_driver_waveform(const Pin *in_pin, + const RiseFall *in_rf, + const Pin *drvr_pin, + const RiseFall *drvr_rf, + const Corner *corner, + const MinMax *min_max) +{ + cmdLinkedNetwork(); + Sta *sta = Sta::sta(); + ArcDcalcWaveforms *arc_dcalc = dynamic_cast(sta->arcDelayCalc()); + if (arc_dcalc) + return arc_dcalc->drvrWaveform(in_pin, in_rf, drvr_pin, drvr_rf, corner, min_max); + else + return Table1(); +} + +Table1 +ccs_driver_ramp_waveform(const Pin *in_pin, + const RiseFall *in_rf, + const Pin *drvr_pin, + const RiseFall *drvr_rf, + const Pin *load_pin, + const Corner *corner, + const MinMax *min_max) +{ + cmdLinkedNetwork(); + Sta *sta = Sta::sta(); + ArcDcalcWaveforms *arc_dcalc = dynamic_cast(sta->arcDelayCalc()); + if (arc_dcalc) + return arc_dcalc->drvrRampWaveform(in_pin, in_rf, drvr_pin, drvr_rf, + load_pin, corner, min_max); + else + return Table1(); +} + +Table1 +ccs_load_waveform(const Pin *in_pin, + const RiseFall *in_rf, + const Pin *drvr_pin, + const RiseFall *drvr_rf, + const Pin *load_pin, + const Corner *corner, + const MinMax *min_max) +{ + cmdLinkedNetwork(); + Sta *sta = Sta::sta(); + ArcDcalcWaveforms *arc_dcalc = dynamic_cast(sta->arcDelayCalc()); + if (arc_dcalc) + return arc_dcalc->loadWaveform(in_pin, in_rf, drvr_pin, drvr_rf, + load_pin, corner, min_max); + else + return Table1(); +} + %} // inline diff --git a/dcalc/DelayCalcBase.cc b/dcalc/DelayCalcBase.cc index c2639664..d4adc760 100644 --- a/dcalc/DelayCalcBase.cc +++ b/dcalc/DelayCalcBase.cc @@ -18,16 +18,52 @@ #include "Liberty.hh" #include "TimingArc.hh" +#include "TimingModel.hh" +#include "TableModel.hh" #include "Network.hh" #include "Parasitics.hh" +#include "Sdc.hh" +#include "DcalcAnalysisPt.hh" namespace sta { +using std::log; + DelayCalcBase::DelayCalcBase(StaState *sta) : ArcDelayCalc(sta) { } +TimingModel * +DelayCalcBase::model(const TimingArc *arc, + const DcalcAnalysisPt *dcalc_ap) const +{ + const OperatingConditions *op_cond = dcalc_ap->operatingConditions(); + const TimingArc *corner_arc = arc->cornerArc(dcalc_ap->libertyIndex()); + return corner_arc->model(op_cond); +} + +GateTimingModel * +DelayCalcBase::gateModel(const TimingArc *arc, + const DcalcAnalysisPt *dcalc_ap) const +{ + return dynamic_cast(model(arc, dcalc_ap)); +} + +GateTableModel * +DelayCalcBase::gateTableModel(const TimingArc *arc, + const DcalcAnalysisPt *dcalc_ap) const +{ + return dynamic_cast(model(arc, dcalc_ap)); +} + +CheckTimingModel * +DelayCalcBase::checkModel(const TimingArc *arc, + const DcalcAnalysisPt *dcalc_ap) const +{ + return dynamic_cast(model(arc, dcalc_ap)); +} + void DelayCalcBase::finishDrvrPin() { @@ -39,74 +75,53 @@ DelayCalcBase::finishDrvrPin() reduced_parasitic_drvrs_.clear(); } -void -DelayCalcBase::inputPortDelay(const Pin *, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *) -{ - drvr_cell_ = nullptr; - drvr_library_ = network_->defaultLibertyLibrary(); - drvr_slew_ = in_slew; - drvr_rf_ = rf; - drvr_parasitic_ = parasitic; - input_port_ = true; -} - -void -DelayCalcBase::gateDelayInit(const TimingArc *arc, - const Slew &in_slew, - const Parasitic *drvr_parasitic) -{ - drvr_cell_ = arc->from()->libertyCell(); - drvr_library_ = drvr_cell_->libertyLibrary(); - drvr_rf_ = arc->toEdge()->asRiseFall(); - drvr_slew_ = in_slew; - drvr_parasitic_ = drvr_parasitic; - input_port_ = false; -} - // For DSPF on an input port the elmore delay is used as the time // constant of an exponential waveform. The delay to the logic // threshold and slew are computed for the exponential waveform. // Note that this uses the driver thresholds and relies on // thresholdAdjust to convert the delay and slew to the load's thresholds. void -DelayCalcBase::dspfWireDelaySlew(const Pin *, +DelayCalcBase::dspfWireDelaySlew(const Pin *load_pin, + const RiseFall *rf, + Slew drvr_slew, float elmore, ArcDelay &wire_delay, Slew &load_slew) { - float vth = drvr_library_->inputThreshold(drvr_rf_); - float vl = drvr_library_->slewLowerThreshold(drvr_rf_); - float vh = drvr_library_->slewUpperThreshold(drvr_rf_); - float slew_derate = drvr_library_->slewDerateFromLibrary(); + + LibertyLibrary *load_library = thresholdLibrary(load_pin); + float vth = load_library->inputThreshold(rf); + float vl = load_library->slewLowerThreshold(rf); + float vh = load_library->slewUpperThreshold(rf); + float slew_derate = load_library->slewDerateFromLibrary(); wire_delay = -elmore * log(1.0 - vth); - load_slew = drvr_slew_ + elmore * log((1.0 - vl) / (1.0 - vh)) / slew_derate; + load_slew = drvr_slew + elmore * log((1.0 - vl) / (1.0 - vh)) / slew_derate; + load_slew = drvr_slew + elmore * log((1.0 - vl) / (1.0 - vh)) / slew_derate; } void DelayCalcBase::thresholdAdjust(const Pin *load_pin, + const LibertyLibrary *drvr_library, + const RiseFall *rf, ArcDelay &load_delay, Slew &load_slew) { LibertyLibrary *load_library = thresholdLibrary(load_pin); if (load_library - && drvr_library_ - && load_library != drvr_library_) { - float drvr_vth = drvr_library_->outputThreshold(drvr_rf_); - float load_vth = load_library->inputThreshold(drvr_rf_); - float drvr_slew_delta = drvr_library_->slewUpperThreshold(drvr_rf_) - - drvr_library_->slewLowerThreshold(drvr_rf_); + && drvr_library + && load_library != drvr_library) { + float drvr_vth = drvr_library->outputThreshold(rf); + float load_vth = load_library->inputThreshold(rf); + float drvr_slew_delta = drvr_library->slewUpperThreshold(rf) + - drvr_library->slewLowerThreshold(rf); float load_delay_delta = delayAsFloat(load_slew) * ((load_vth - drvr_vth) / drvr_slew_delta); - load_delay += (drvr_rf_ == RiseFall::rise()) + load_delay += (rf == RiseFall::rise()) ? load_delay_delta : -load_delay_delta; - float load_slew_delta = load_library->slewUpperThreshold(drvr_rf_) - - load_library->slewLowerThreshold(drvr_rf_); - float drvr_slew_derate = drvr_library_->slewDerateFromLibrary(); + float load_slew_delta = load_library->slewUpperThreshold(rf) + - load_library->slewLowerThreshold(rf); + float drvr_slew_derate = drvr_library->slewDerateFromLibrary(); float load_slew_derate = load_library->slewDerateFromLibrary(); load_slew = load_slew * ((load_slew_delta / load_slew_derate) / (drvr_slew_delta / drvr_slew_derate)); @@ -129,4 +144,55 @@ DelayCalcBase::thresholdLibrary(const Pin *load_pin) } } +ArcDelay +DelayCalcBase::checkDelay(const Pin *check_pin, + const TimingArc *arc, + const Slew &from_slew, + const Slew &to_slew, + float related_out_cap, + const DcalcAnalysisPt *dcalc_ap) +{ + CheckTimingModel *model = checkModel(arc, dcalc_ap); + if (model) { + float from_slew1 = delayAsFloat(from_slew); + float to_slew1 = delayAsFloat(to_slew); + return model->checkDelay(pinPvt(check_pin, dcalc_ap), from_slew1, to_slew1, + related_out_cap, pocv_enabled_); + } + else + return delay_zero; +} + +string +DelayCalcBase::reportCheckDelay(const Pin *check_pin, + const TimingArc *arc, + const Slew &from_slew, + const char *from_slew_annotation, + const Slew &to_slew, + float related_out_cap, + const DcalcAnalysisPt *dcalc_ap, + int digits) +{ + CheckTimingModel *model = checkModel(arc, dcalc_ap); + if (model) { + float from_slew1 = delayAsFloat(from_slew); + float to_slew1 = delayAsFloat(to_slew); + return model->reportCheckDelay(pinPvt(check_pin, dcalc_ap), from_slew1, + from_slew_annotation, to_slew1, + related_out_cap, false, digits); + } + return ""; +} + +const Pvt * +DelayCalcBase::pinPvt(const Pin *pin, + const DcalcAnalysisPt *dcalc_ap) +{ + const Instance *drvr_inst = network_->instance(pin); + const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax()); + if (pvt == nullptr) + pvt = dcalc_ap->operatingConditions(); + return pvt; +} + } // namespace diff --git a/dcalc/DelayCalcBase.hh b/dcalc/DelayCalcBase.hh index 248e8e5a..973f758c 100644 --- a/dcalc/DelayCalcBase.hh +++ b/dcalc/DelayCalcBase.hh @@ -20,39 +20,58 @@ namespace sta { +class GateTableModel; + class DelayCalcBase : public ArcDelayCalc { public: explicit DelayCalcBase(StaState *sta); - void inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, + void finishDrvrPin() override; + + ArcDelay checkDelay(const Pin *check_pin, + const TimingArc *arc, + const Slew &from_slew, + const Slew &to_slew, + float related_out_cap, const DcalcAnalysisPt *dcalc_ap) override; - void finishDrvrPin() override; + + string reportCheckDelay(const Pin *check_pin, + const TimingArc *arc, + const Slew &from_slew, + const char *from_slew_annotation, + const Slew &to_slew, + float related_out_cap, + const DcalcAnalysisPt *dcalc_ap, + int digits) override; protected: - void gateDelayInit(const TimingArc *arc, - const Slew &in_slew, - const Parasitic *drvr_parasitic); + GateTimingModel *gateModel(const TimingArc *arc, + const DcalcAnalysisPt *dcalc_ap) const; + GateTableModel *gateTableModel(const TimingArc *arc, + const DcalcAnalysisPt *dcalc_ap) const; + CheckTimingModel *checkModel(const TimingArc *arc, + const DcalcAnalysisPt *dcalc_ap) const; + TimingModel *model(const TimingArc *arc, + const DcalcAnalysisPt *dcalc_ap) const; // Find the liberty library to use for logic/slew thresholds. LibertyLibrary *thresholdLibrary(const Pin *load_pin); // Adjust load_delay and load_slew from driver thresholds to load thresholds. void thresholdAdjust(const Pin *load_pin, + const LibertyLibrary *drvr_library, + const RiseFall *rf, ArcDelay &load_delay, Slew &load_slew); // Helper function for input ports driving dspf parasitic. void dspfWireDelaySlew(const Pin *load_pin, - float elmore, + const RiseFall *rf, + Slew drvr_slew, + float elmore, + // Return values. ArcDelay &wire_delay, Slew &load_slew); + const Pvt *pinPvt(const Pin *pin, + const DcalcAnalysisPt *dcalc_ap); - Slew drvr_slew_; - const LibertyCell *drvr_cell_; - const LibertyLibrary *drvr_library_; - const Parasitic *drvr_parasitic_; - bool input_port_; - const RiseFall *drvr_rf_; // Parasitics returned by findParasitic that are reduced or estimated // that can be deleted after delay calculation for the driver pin // is finished. diff --git a/dcalc/DmpCeff.cc b/dcalc/DmpCeff.cc index 0d298a78..da9351a6 100644 --- a/dcalc/DmpCeff.cc +++ b/dcalc/DmpCeff.cc @@ -88,7 +88,6 @@ gateModelRd(const LibertyCell *cell, double in_slew, double c2, double c1, - float related_out_cap, const Pvt *pvt, bool pocv_enabled); static void @@ -155,7 +154,6 @@ public: const RiseFall *rf, double rd, double in_slew, - float related_out_cap, double c2, double rpi, double c1); @@ -235,7 +233,6 @@ protected: const Pvt *pvt_; const GateTableModel *gate_model_; double in_slew_; - float related_out_cap_; double c2_; double rpi_; double c1_; @@ -319,7 +316,6 @@ DmpAlg::init(const LibertyLibrary *drvr_library, const RiseFall *rf, double rd, double in_slew, - float related_out_cap, // Pi model. double c2, double rpi, @@ -331,7 +327,6 @@ DmpAlg::init(const LibertyLibrary *drvr_library, gate_model_ = gate_model; rd_ = rd; in_slew_ = in_slew; - related_out_cap_ = related_out_cap; c2_ = c2; rpi_ = rpi; c1_ = c1; @@ -381,8 +376,8 @@ DmpAlg::gateCapDelaySlew(double ceff, { ArcDelay model_delay; Slew model_slew; - gate_model_->gateDelay(pvt_, in_slew_, ceff, related_out_cap_, - pocv_enabled_, model_delay, model_slew); + gate_model_->gateDelay(pvt_, in_slew_, ceff, pocv_enabled_, + model_delay, model_slew); delay = delayAsFloat(model_delay); slew = delayAsFloat(model_slew); } @@ -696,7 +691,6 @@ public: const RiseFall *rf, double rd, double in_slew, - float related_out_cap, double c2, double rpi, double c1); @@ -729,14 +723,13 @@ DmpCap::init(const LibertyLibrary *drvr_library, const RiseFall *rf, double rd, double in_slew, - float related_out_cap, double c2, double rpi, double c1) { debugPrint(debug_, "dmp_ceff", 3, "Using DMP cap"); DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf, - rd, in_slew, related_out_cap, c2, rpi, c1); + rd, in_slew, c2, rpi, c1); ceff_ = c1 + c2; } @@ -810,7 +803,6 @@ public: const RiseFall *rf, double rd, double in_slew, - float related_out_cap, double c2, double rpi, double c1); @@ -870,14 +862,13 @@ DmpPi::init(const LibertyLibrary *drvr_library, const RiseFall *rf, double rd, double in_slew, - float related_out_cap, double c2, double rpi, double c1) { debugPrint(debug_, "dmp_ceff", 3, "Using DMP Pi"); DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf, rd, - in_slew, related_out_cap, c2, rpi, c1); + in_slew, c2, rpi, c1); // Find poles/zeros. z1_ = 1.0 / (rpi_ * c1_); @@ -1144,7 +1135,6 @@ public: const RiseFall *rf, double rd, double in_slew, - float related_out_cap, double c2, double rpi, double c1); @@ -1187,14 +1177,13 @@ DmpZeroC2::init(const LibertyLibrary *drvr_library, const RiseFall *rf, double rd, double in_slew, - float related_out_cap, double c2, double rpi, double c1) { debugPrint(debug_, "dmp_ceff", 3, "Using DMP C2=0"); DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf, rd, - in_slew, related_out_cap, c2, rpi, c1); + in_slew, c2, rpi, c1); ceff_ = c1; z1_ = 1.0 / (rpi_ * c1_); @@ -1543,64 +1532,58 @@ DmpCeffDelayCalc::~DmpCeffDelayCalc() delete dmp_zero_c2_; } -void -DmpCeffDelayCalc::inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap) +ArcDcalcResult +DmpCeffDelayCalc::gateDelay(const Pin *drvr_pin, + const TimingArc *arc, + const Slew &in_slew, + float load_cap, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) { - dmp_alg_ = nullptr; - LumpedCapDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap); -} - -void -DmpCeffDelayCalc::gateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) -{ - input_port_ = false; - drvr_rf_ = arc->toEdge()->asRiseFall(); + const RiseFall *rf = arc->toEdge()->asRiseFall(); const LibertyCell *drvr_cell = arc->from()->libertyCell(); - drvr_library_ = drvr_cell->libertyLibrary(); - drvr_parasitic_ = drvr_parasitic; + const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary(); - GateTimingModel *model = gateModel(arc, dcalc_ap); - GateTableModel *table_model = dynamic_cast(model); - if (table_model && drvr_parasitic) { + GateTableModel *table_model = gateTableModel(arc, dcalc_ap); + if (table_model && parasitic) { float in_slew1 = delayAsFloat(in_slew); float c2, rpi, c1; - parasitics_->piModel(drvr_parasitic, c2, rpi, c1); + parasitics_->piModel(parasitic, c2, rpi, c1); if (isnan(c2) || isnan(c1) || isnan(rpi)) report_->error(618, "parasitic Pi model has NaNs."); - setCeffAlgorithm(drvr_library_, drvr_cell, pvt, table_model, - drvr_rf_, in_slew1, related_out_cap, - c2, rpi, c1); - double dmp_gate_delay, dmp_drvr_slew; - gateDelaySlew(dmp_gate_delay, dmp_drvr_slew); - gate_delay = dmp_gate_delay; - drvr_slew = dmp_drvr_slew; + setCeffAlgorithm(drvr_library, drvr_cell, pinPvt(drvr_pin, dcalc_ap), + table_model, rf, in_slew1, c2, rpi, c1); + double gate_delay, drvr_slew; + gateDelaySlew(gate_delay, drvr_slew); + ArcDcalcResult dcalc_result(load_pin_index_map.size()); + dcalc_result.setGateDelay(gate_delay); + dcalc_result.setDrvrSlew(drvr_slew); + + for (auto load_pin_index : load_pin_index_map) { + const Pin *load_pin = load_pin_index.first; + size_t load_idx = load_pin_index.second; + ArcDelay wire_delay; + Slew load_slew; + loadDelaySlew(load_pin, drvr_slew, rf, drvr_library, parasitic, + wire_delay, load_slew); + dcalc_result.setWireDelay(load_idx, wire_delay); + dcalc_result.setLoadSlew(load_idx, load_slew); + } + return dcalc_result; } else { - LumpedCapDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic, - related_out_cap, pvt, dcalc_ap, - gate_delay, drvr_slew); - if (drvr_parasitic + ArcDcalcResult dcalc_result = + LumpedCapDelayCalc::gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic, + load_pin_index_map, dcalc_ap); + if (parasitic && !unsuppored_model_warned_) { unsuppored_model_warned_ = true; report_->warn(1, "cell %s delay model not supported on SPF parasitics by DMP delay calculator", drvr_cell->name()); } + return dcalc_result; } - drvr_slew_ = drvr_slew; - multi_drvr_slew_factor_ = 1.0F; } void @@ -1610,7 +1593,6 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library, const GateTableModel *gate_model, const RiseFall *rf, double in_slew, - float related_out_cap, double c2, double rpi, double c1) @@ -1618,7 +1600,7 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library, double rd = 0.0; if (gate_model) { rd = gateModelRd(drvr_cell, gate_model, rf, in_slew, c2, c1, - related_out_cap, pvt, pocv_enabled_); + pvt, pocv_enabled_); // Zero Rd means the table is constant and thus independent of load cap. if (rd < 1e-2 // Rpi is small compared to Rd, which makes the load capacitive. @@ -1635,7 +1617,7 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library, else dmp_alg_ = dmp_cap_; dmp_alg_->init(drvr_library, drvr_cell, pvt, gate_model, - drvr_rf_, rd, in_slew, related_out_cap, c2, rpi, c1); + rf, rd, in_slew, c2, rpi, c1); debugPrint(debug_, "dmp_ceff", 3, " DMP in_slew = %s c2 = %s rpi = %s c1 = %s Rd = %s (%s alg)", units_->timeUnit()->asString(in_slew), @@ -1646,51 +1628,29 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library, dmp_alg_->name()); } -float -DmpCeffDelayCalc::ceff(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap) -{ - ArcDelay gate_delay; - Slew drvr_slew; - gateDelay(arc, in_slew, load_cap, drvr_parasitic, related_out_cap, pvt, dcalc_ap, - gate_delay, drvr_slew); - if (dmp_alg_) - return dmp_alg_->ceff(); - else - return load_cap; -} - string -DmpCeffDelayCalc::reportGateDelay(const TimingArc *arc, +DmpCeffDelayCalc::reportGateDelay(const Pin *drvr_pin, + const TimingArc *arc, const Slew &in_slew, float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap, int digits) { - ArcDelay gate_delay; - Slew drvr_slew; - gateDelay(arc, in_slew, load_cap, drvr_parasitic, related_out_cap, pvt, dcalc_ap, - gate_delay, drvr_slew); + gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic, load_pin_index_map, dcalc_ap); GateTimingModel *model = gateModel(arc, dcalc_ap); float c_eff = 0.0; string result; - if (drvr_parasitic_ && dmp_alg_) { + if (parasitic && dmp_alg_) { c_eff = dmp_alg_->ceff(); - const LibertyCell *drvr_cell = arc->from()->libertyCell(); + const LibertyCell *drvr_cell = arc->to()->libertyCell(); const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary(); const Units *units = drvr_library->units(); const Unit *cap_unit = units->capacitanceUnit(); const Unit *res_unit = units->resistanceUnit(); float c2, rpi, c1; - parasitics_->piModel(drvr_parasitic_, c2, rpi, c1); + parasitics_->piModel(parasitic, c2, rpi, c1); result += "Pi model C2="; result += cap_unit->asString(c2, digits); result += " Rpi="; @@ -1705,7 +1665,7 @@ DmpCeffDelayCalc::reportGateDelay(const TimingArc *arc, c_eff = load_cap; if (model) { float in_slew1 = delayAsFloat(in_slew); - result += model->reportGateDelay(pvt, in_slew1, c_eff, related_out_cap, + result += model->reportGateDelay(pinPvt(drvr_pin, dcalc_ap), in_slew1, c_eff, pocv_enabled_, digits); } return result; @@ -1718,7 +1678,6 @@ gateModelRd(const LibertyCell *cell, double in_slew, double c2, double c1, - float related_out_cap, const Pvt *pvt, bool pocv_enabled) { @@ -1726,8 +1685,8 @@ gateModelRd(const LibertyCell *cell, float cap2 = cap1 + 1e-15; ArcDelay d1, d2; Slew s1, s2; - gate_model->gateDelay(pvt, in_slew, cap1, related_out_cap, pocv_enabled, d1, s1); - gate_model->gateDelay(pvt, in_slew, cap2, related_out_cap, pocv_enabled, d2, s2); + gate_model->gateDelay(pvt, in_slew, cap1, pocv_enabled, d1, s1); + gate_model->gateDelay(pvt, in_slew, cap2, pocv_enabled, d2, s2); double vth = cell->libertyLibrary()->outputThreshold(rf); float rd = -log(vth) * abs(delayAsFloat(d1) - delayAsFloat(d2)) / (cap2 - cap1); return rd; @@ -1741,10 +1700,10 @@ DmpCeffDelayCalc::gateDelaySlew(double &delay, } void -DmpCeffDelayCalc::loadDelaySlew(const Pin *load_pin, - double elmore, - ArcDelay &delay, - Slew &slew) +DmpCeffDelayCalc::loadDelaySlewElmore(const Pin *load_pin, + double elmore, + ArcDelay &delay, + Slew &slew) { if (dmp_alg_) dmp_alg_->loadDelaySlew(load_pin, elmore, delay, slew); diff --git a/dcalc/DmpCeff.hh b/dcalc/DmpCeff.hh index b79dbdc6..960b8336 100644 --- a/dcalc/DmpCeff.hh +++ b/dcalc/DmpCeff.hh @@ -34,45 +34,39 @@ class DmpCeffDelayCalc : public LumpedCapDelayCalc public: DmpCeffDelayCalc(StaState *sta); virtual ~DmpCeffDelayCalc(); - virtual void inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap); - virtual void gateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // return values - ArcDelay &gate_delay, - Slew &drvr_slew); - virtual float ceff(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap); - virtual string reportGateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - int digits); - virtual void copyState(const StaState *sta); + ArcDcalcResult gateDelay(const Pin *drvr_pin, + const TimingArc *arc, + const Slew &in_slew, + float load_cap, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) override; + string reportGateDelay(const Pin *drvr_pin, + const TimingArc *arc, + const Slew &in_slew, + float load_cap, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap, + int digits) override; + void copyState(const StaState *sta) override; protected: - void gateDelaySlew(double &delay, + virtual void loadDelaySlew(const Pin *load_pin, + double drvr_slew, + const RiseFall *rf, + const LibertyLibrary *drvr_library, + const Parasitic *parasitic, + // Return values. + ArcDelay &wire_delay, + Slew &load_slew) = 0; + void gateDelaySlew(// Return values. + double &delay, double &slew); - void loadDelaySlew(const Pin *load_pin, - double elmore, - ArcDelay &delay, - Slew &slew); + void loadDelaySlewElmore(const Pin *load_pin, + double elmore, + ArcDelay &delay, + Slew &slew); // Select the appropriate special case Dartu/Menezes/Pileggi algorithm. void setCeffAlgorithm(const LibertyLibrary *library, const LibertyCell *cell, @@ -80,7 +74,6 @@ protected: const GateTableModel *gate_model, const RiseFall *rf, double in_slew, - float related_out_cap, double c2, double rpi, double c1); diff --git a/dcalc/DmpDelayCalc.cc b/dcalc/DmpDelayCalc.cc index ed97468a..bf0c7802 100644 --- a/dcalc/DmpDelayCalc.cc +++ b/dcalc/DmpDelayCalc.cc @@ -35,9 +35,22 @@ class DmpCeffElmoreDelayCalc : public DmpCeffDelayCalc public: DmpCeffElmoreDelayCalc(StaState *sta); ArcDelayCalc *copy() override; - void loadDelay(const Pin *load_pin, - ArcDelay &wire_delay, - Slew &load_slew) override; + ArcDcalcResult inputPortDelay(const Pin *port_pin, + float in_slew, + const RiseFall *rf, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) override; + +protected: + void loadDelaySlew(const Pin *load_pin, + double drvr_slew, + const RiseFall *rf, + const LibertyLibrary *drvr_library, + const Parasitic *parasitic, + // Return values. + ArcDelay &wire_delay, + Slew &load_slew) override; }; ArcDelayCalc * @@ -57,26 +70,54 @@ DmpCeffElmoreDelayCalc::copy() return new DmpCeffElmoreDelayCalc(this); } -void -DmpCeffElmoreDelayCalc::loadDelay(const Pin *load_pin, - ArcDelay &wire_delay, - Slew &load_slew) +ArcDcalcResult +DmpCeffElmoreDelayCalc::inputPortDelay(const Pin *, + float in_slew, + const RiseFall *rf, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *) { - ArcDelay wire_delay1 = 0.0; - Slew load_slew1 = drvr_slew_; + ArcDcalcResult dcalc_result(load_pin_index_map.size()); + LibertyLibrary *drvr_library = network_->defaultLibertyLibrary(); + for (auto load_pin_index : load_pin_index_map) { + const Pin *load_pin = load_pin_index.first; + size_t load_idx = load_pin_index.second; + ArcDelay wire_delay = 0.0; + Slew load_slew = in_slew; + bool elmore_exists = false; + float elmore = 0.0; + if (parasitic) + parasitics_->findElmore(parasitic, load_pin, elmore, elmore_exists); + if (elmore_exists) + // Input port with no external driver. + dspfWireDelaySlew(load_pin, rf, in_slew, elmore, wire_delay, load_slew); + thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew); + dcalc_result.setWireDelay(load_idx, wire_delay); + dcalc_result.setLoadSlew(load_idx, load_slew); + } + return dcalc_result; +} + +void +DmpCeffElmoreDelayCalc::loadDelaySlew(const Pin *load_pin, + double drvr_slew, + const RiseFall *rf, + const LibertyLibrary *drvr_library, + const Parasitic *parasitic, + // Return values. + ArcDelay &wire_delay, + Slew &load_slew) +{ + wire_delay = 0.0; + load_slew = drvr_slew; bool elmore_exists = false; float elmore = 0.0; - if (drvr_parasitic_) - parasitics_->findElmore(drvr_parasitic_, load_pin, elmore, elmore_exists); - if (elmore_exists) { - if (input_port_) - dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1); - else - loadDelaySlew(load_pin, elmore, wire_delay1, load_slew1); - } - thresholdAdjust(load_pin, wire_delay1, load_slew1); - wire_delay = wire_delay1; - load_slew = load_slew1 * multi_drvr_slew_factor_; + if (parasitic) + parasitics_->findElmore(parasitic, load_pin, elmore, elmore_exists); + if (elmore_exists) + loadDelaySlewElmore(load_pin, elmore, wire_delay, load_slew); + thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew); } //////////////////////////////////////////////////////////////// @@ -91,28 +132,31 @@ public: Parasitic *findParasitic(const Pin *drvr_pin, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) override; - ReducedParasiticType reducedParasiticType() const override; - void inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap) override; - void gateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) override; - void loadDelay(const Pin *load_pin, - ArcDelay &wire_delay, - Slew &load_slew) override; + ArcDcalcResult inputPortDelay(const Pin *port_pin, + float in_slew, + const RiseFall *rf, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) override; + ArcDcalcResult gateDelay(const Pin *drvr_pin, + const TimingArc *arc, + const Slew &in_slew, + float load_cap, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) override; private: - void loadDelay(Parasitic *pole_residue, + void loadDelaySlew(const Pin *load_pin, + double drvr_slew, + const RiseFall *rf, + const LibertyLibrary *drvr_library, + const Parasitic *parasitic, + // Return values. + ArcDelay &wire_delay, + Slew &load_slew) override; + void loadDelay(double drvr_slew, + Parasitic *pole_residue, double p1, double k1, ArcDelay &wire_delay, @@ -211,57 +255,81 @@ DmpCeffTwoPoleDelayCalc::findParasitic(const Pin *drvr_pin, return parasitic; } -ReducedParasiticType -DmpCeffTwoPoleDelayCalc::reducedParasiticType() const +ArcDcalcResult +DmpCeffTwoPoleDelayCalc::inputPortDelay(const Pin *, + float in_slew, + const RiseFall *rf, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *) { - return ReducedParasiticType::pi_pole_residue2; + ArcDcalcResult dcalc_result(load_pin_index_map.size()); + ArcDelay wire_delay = 0.0; + Slew load_slew = in_slew; + LibertyLibrary *drvr_library = network_->defaultLibertyLibrary(); + for (auto load_pin_index : load_pin_index_map) { + const Pin *load_pin = load_pin_index.first; + size_t load_idx = load_pin_index.second; + if (parasitics_->isPiPoleResidue(parasitic)) { + const Parasitic *pole_residue = parasitics_->findPoleResidue(parasitic, load_pin); + if (pole_residue) { + size_t pole_count = parasitics_->poleResidueCount(pole_residue); + if (pole_count >= 1) { + ComplexFloat pole1, residue1; + // Find the 1st (elmore) pole. + parasitics_->poleResidue(pole_residue, 0, pole1, residue1); + if (pole1.imag() == 0.0 + && residue1.imag() == 0.0) { + float p1 = pole1.real(); + float elmore = 1.0F / p1; + dspfWireDelaySlew(load_pin, rf, in_slew, elmore, wire_delay, load_slew); + thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew); + } + } + } + } + dcalc_result.setWireDelay(load_idx, wire_delay); + dcalc_result.setLoadSlew(load_idx, load_slew); + } + return dcalc_result; +} + +ArcDcalcResult +DmpCeffTwoPoleDelayCalc::gateDelay(const Pin *drvr_pin, + const TimingArc *arc, + const Slew &in_slew, + float load_cap, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) +{ + const LibertyLibrary *drvr_library = arc->to()->libertyLibrary(); + const RiseFall *rf = arc->toEdge()->asRiseFall(); + vth_ = drvr_library->outputThreshold(rf); + vl_ = drvr_library->slewLowerThreshold(rf); + vh_ = drvr_library->slewUpperThreshold(rf); + slew_derate_ = drvr_library->slewDerateFromLibrary(); + return DmpCeffDelayCalc::gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic, + load_pin_index_map, dcalc_ap) ; } void -DmpCeffTwoPoleDelayCalc::inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap) +DmpCeffTwoPoleDelayCalc::loadDelaySlew(const Pin *load_pin, + double drvr_slew, + const RiseFall *rf, + const LibertyLibrary *drvr_library, + const Parasitic *parasitic, + // Return values. + ArcDelay &wire_delay, + Slew &load_slew) { parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(parasitic); - DmpCeffDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap); -} - -void -DmpCeffTwoPoleDelayCalc::gateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) -{ - gateDelayInit(arc, in_slew, drvr_parasitic); - parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(drvr_parasitic); - vth_ = drvr_library_->outputThreshold(drvr_rf_); - vl_ = drvr_library_->slewLowerThreshold(drvr_rf_); - vh_ = drvr_library_->slewUpperThreshold(drvr_rf_); - slew_derate_ = drvr_library_->slewDerateFromLibrary(); - DmpCeffDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic, - related_out_cap, pvt, dcalc_ap, - gate_delay, drvr_slew); -} - -void -DmpCeffTwoPoleDelayCalc::loadDelay(const Pin *load_pin, - ArcDelay &wire_delay, - Slew &load_slew) -{ // Should handle PiElmore parasitic. - ArcDelay wire_delay1 = 0.0; - Slew load_slew1 = drvr_slew_; + wire_delay = 0.0; + load_slew = drvr_slew; Parasitic *pole_residue = 0; if (parasitic_is_pole_residue_) - pole_residue = parasitics_->findPoleResidue(drvr_parasitic_, load_pin); + pole_residue = parasitics_->findPoleResidue(parasitic, load_pin); if (pole_residue) { size_t pole_count = parasitics_->poleResidueCount(pole_residue); if (pole_count >= 1) { @@ -272,37 +340,31 @@ DmpCeffTwoPoleDelayCalc::loadDelay(const Pin *load_pin, && residue1.imag() == 0.0) { float p1 = pole1.real(); float k1 = residue1.real(); - if (input_port_) { - float elmore = 1.0F / p1; - // Input port with no external driver. - dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1); - } - else { - if (pole_count >= 2) - loadDelay(pole_residue, p1, k1, wire_delay1, load_slew1); - else { - float elmore = 1.0F / p1; - wire_delay1 = elmore; - load_slew1 = drvr_slew_; - } - } + if (pole_count >= 2) + loadDelay(drvr_slew, pole_residue, p1, k1, wire_delay, load_slew); + else { + float elmore = 1.0F / p1; + wire_delay = elmore; + load_slew = drvr_slew; + } } } } - thresholdAdjust(load_pin, wire_delay1, load_slew1); - wire_delay = wire_delay1; - load_slew = load_slew1 * multi_drvr_slew_factor_; + thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew); } void -DmpCeffTwoPoleDelayCalc::loadDelay(Parasitic *pole_residue, - double p1, double k1, - ArcDelay &wire_delay, +DmpCeffTwoPoleDelayCalc::loadDelay(double drvr_slew, + Parasitic *pole_residue, + double p1, + double k1, + // Return values. + ArcDelay &wire_delay, Slew &load_slew) { ComplexFloat pole2, residue2; parasitics_->poleResidue(pole_residue, 1, pole2, residue2); - if (!delayZero(drvr_slew_) + if (!delayZero(drvr_slew) && pole2.imag() == 0.0 && residue2.imag() == 0.0) { double p2 = pole2.real(); @@ -311,7 +373,7 @@ DmpCeffTwoPoleDelayCalc::loadDelay(Parasitic *pole_residue, double k2_p2_2 = k2 / (p2 * p2); double B = k1_p1_2 + k2_p2_2; // Convert tt to 0:1 range. - float tt = delayAsFloat(drvr_slew_) * slew_derate_ / (vh_ - vl_); + float tt = delayAsFloat(drvr_slew) * slew_derate_ / (vh_ - vl_); double y_tt = (tt - B + k1_p1_2 * exp(-p1 * tt) + k2_p2_2 * exp(-p2 * tt)) / tt; wire_delay = loadDelay(vth_, p1, p2, k1, k2, B, k1_p1_2, k2_p2_2, tt, y_tt) diff --git a/dcalc/GraphDelayCalc.cc b/dcalc/GraphDelayCalc.cc index 3f18bd2f..f0414b98 100644 --- a/dcalc/GraphDelayCalc.cc +++ b/dcalc/GraphDelayCalc.cc @@ -183,25 +183,10 @@ GraphDelayCalc::deleteVertexBefore(Vertex *vertex) invalid_delays_->erase(vertex); MultiDrvrNet *multi_drvr = multiDrvrNet(vertex); if (multi_drvr) { - VertexSet *drvrs = multi_drvr->drvrs(); - drvrs->erase(vertex); - multi_drvr_net_map_.erase(vertex); - if (drvrs->empty()) - delete multi_drvr; - else { - Level max_drvr_level = 0; - Vertex *max_drvr = nullptr; - for (Vertex *drvr_vertex : *drvrs) { - 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(sdc_); - } + // Don't bother incrementally updating MultiDrvrNet. + for (Vertex *drvr_vertex : *multi_drvr->drvrs()) + multi_drvr_net_map_.erase(drvr_vertex); + delete multi_drvr; } } @@ -391,10 +376,12 @@ GraphDelayCalc::seedNoDrvrCellSlew(Vertex *drvr_vertex, 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); + LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex); + ArcDcalcResult dcalc_result = + arc_delay_calc->inputPortDelay(drvr_pin, delayAsFloat(slew), rf, parasitic, + load_pin_index_map, dcalc_ap); + annotateLoadDelays(drvr_vertex, rf, dcalc_result, load_pin_index_map, + drive_delay, false, dcalc_ap); arc_delay_calc->finishDrvrPin(); } @@ -417,10 +404,12 @@ GraphDelayCalc::seedNoDrvrSlew(Vertex *drvr_vertex, 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); + LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex); + ArcDcalcResult dcalc_result = + arc_delay_calc->inputPortDelay(drvr_pin, delayAsFloat(slew), rf, parasitic, + load_pin_index_map, dcalc_ap); + annotateLoadDelays(drvr_vertex, rf, dcalc_result, load_pin_index_map, delay_zero, + false, dcalc_ap); arc_delay_calc->finishDrvrPin(); } @@ -531,25 +520,26 @@ GraphDelayCalc::findInputArcDelay(const Pin *drvr_pin, arc->to()->name(), arc->toEdge()->asString(), arc->role()->asString()); - RiseFall *drvr_rf = arc->toEdge()->asRiseFall(); + const 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); + Parasitic *parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, dcalc_ap); + float load_cap = loadCap(drvr_pin, parasitic, drvr_rf, dcalc_ap); - ArcDelay intrinsic_delay; - Slew intrinsic_slew; - arc_delay_calc_->gateDelay(arc, Slew(from_slew), 0.0, 0, 0.0, pvt, dcalc_ap, - intrinsic_delay, intrinsic_slew); + LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex); + ArcDcalcResult intrinsic_result = + arc_delay_calc_->gateDelay(drvr_pin, arc, Slew(from_slew), 0.0, nullptr, + load_pin_index_map, dcalc_ap); + ArcDelay intrinsic_delay = intrinsic_result.gateDelay(); + + ArcDcalcResult gate_result = arc_delay_calc_->gateDelay(drvr_pin, arc, + Slew(from_slew), load_cap, + parasitic, + load_pin_index_map, + dcalc_ap); + ArcDelay gate_delay = gate_result.gateDelay(); + Slew gate_slew = gate_result.drvrSlew(); - // For input drivers there is no instance to find a related_output_pin. - ArcDelay gate_delay; - Slew gate_slew; - arc_delay_calc_->gateDelay(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", @@ -557,8 +547,8 @@ GraphDelayCalc::findInputArcDelay(const Pin *drvr_pin, 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_); + annotateLoadDelays(drvr_vertex, drvr_rf, gate_result, load_pin_index_map, + load_delay, false, dcalc_ap); } } @@ -651,19 +641,12 @@ GraphDelayCalc::findDriverDelays(Vertex *drvr_vertex, { bool delay_changed = false; MultiDrvrNet *multi_drvr = findMultiDrvrNet(drvr_vertex); - if (multi_drvr - && multi_drvr->parallelGates(network_)) { - Vertex *dcalc_drvr = multi_drvr->dcalcDrvr(); - if (drvr_vertex == dcalc_drvr) { - initLoadSlews(drvr_vertex); - arc_delay_calc->findParallelGateDelays(multi_drvr, this); - for (Vertex *drvr_vertex : *multi_drvr->drvrs()) - delay_changed |= findDriverDelays1(drvr_vertex, multi_drvr, arc_delay_calc); - } - } - else { + if (multi_drvr == nullptr + || (multi_drvr + && (!multi_drvr->parallelGates(network_) + || drvr_vertex == multi_drvr->dcalcDrvr()))) { initLoadSlews(drvr_vertex); - delay_changed = findDriverDelays1(drvr_vertex, nullptr, arc_delay_calc); + delay_changed |= findDriverDelays1(drvr_vertex, multi_drvr, arc_delay_calc); } arc_delay_calc->finishDrvrPin(); return delay_changed; @@ -763,10 +746,17 @@ GraphDelayCalc::findDriverDelays1(Vertex *drvr_vertex, MultiDrvrNet *multi_drvr, ArcDelayCalc *arc_delay_calc) { - const Pin *drvr_pin = drvr_vertex->pin(); - Instance *drvr_inst = network_->instance(drvr_pin); initSlew(drvr_vertex); - initWireDelays(drvr_vertex); + if (multi_drvr + && multi_drvr->parallelGates(network_)) { + // Only init on the trigger driver. + if (drvr_vertex == multi_drvr->dcalcDrvr()) { + for (auto vertex : *multi_drvr->drvrs()) + initWireDelays(vertex); + } + } + else + initWireDelays(drvr_vertex); bool delay_changed = false; bool has_delays = false; VertexInEdgeIterator edge_iter(drvr_vertex, graph_); @@ -777,8 +767,8 @@ GraphDelayCalc::findDriverDelays1(Vertex *drvr_vertex, if (search_pred_->searchFrom(from_vertex) && search_pred_->searchThru(edge) && !edge->role()->isLatchDtoQ()) { - delay_changed |= findDriverEdgeDelays(drvr_inst, drvr_pin, drvr_vertex, - multi_drvr, edge, arc_delay_calc); + delay_changed |= findDriverEdgeDelays(drvr_vertex, multi_drvr, edge, + arc_delay_calc); has_delays = true; } } @@ -812,53 +802,329 @@ GraphDelayCalc::findLatchEdgeDelays(Edge *edge) Instance *drvr_inst = network_->instance(drvr_pin); debugPrint(debug_, "delay_calc", 2, "find latch D->Q %s", sdc_network_->pathName(drvr_inst)); - bool delay_changed = findDriverEdgeDelays(drvr_inst, drvr_pin, drvr_vertex, - nullptr, edge, arc_delay_calc_); + bool delay_changed = findDriverEdgeDelays(drvr_vertex, nullptr, edge, + arc_delay_calc_); if (delay_changed && observer_) observer_->delayChangedTo(drvr_vertex); } bool -GraphDelayCalc::findDriverEdgeDelays(const Instance *drvr_inst, - const Pin *drvr_pin, - Vertex *drvr_vertex, +GraphDelayCalc::findDriverEdgeDelays(Vertex *drvr_vertex, const MultiDrvrNet *multi_drvr, Edge *edge, ArcDelayCalc *arc_delay_calc) { - Vertex *in_vertex = edge->from(graph_); + Vertex *from_vertex = edge->from(graph_); const 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); + PinSeq load_pins = loadPins(drvr_vertex); + LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex); 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_pin, drvr_vertex, arc, parasitic, - related_out_cap, in_vertex, edge, pvt, dcalc_ap, - multi_drvr, arc_delay_calc); - } + for (const TimingArc *arc : arc_set->arcs()) + delay_changed |= findDriverArcDelays(drvr_vertex, multi_drvr, edge, arc, + load_pin_index_map, dcalc_ap, + arc_delay_calc); } - if (delay_changed && observer_) { - observer_->delayChangedFrom(in_vertex); + observer_->delayChangedFrom(from_vertex); observer_->delayChangedFrom(drvr_vertex); } return delay_changed; } +void +GraphDelayCalc::findDriverArcDelays(Vertex *drvr_vertex, + Edge *edge, + const TimingArc *arc, + const DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc) +{ + MultiDrvrNet *multi_drvr = multiDrvrNet(drvr_vertex); + LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex); + findDriverArcDelays(drvr_vertex, multi_drvr, edge, arc, + load_pin_index_map, dcalc_ap, + arc_delay_calc); +} + +bool +GraphDelayCalc::findDriverArcDelays(Vertex *drvr_vertex, + const MultiDrvrNet *multi_drvr, + Edge *edge, + const TimingArc *arc, + LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc) +{ + bool delay_changed = false; + const RiseFall *from_rf = arc->fromEdge()->asRiseFall(); + const RiseFall *drvr_rf = arc->toEdge()->asRiseFall(); + if (from_rf && drvr_rf) { + const Pin *drvr_pin = drvr_vertex->pin(); + Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin, drvr_rf, + dcalc_ap); + float load_cap = loadCap(drvr_pin, parasitic, drvr_rf, dcalc_ap, multi_drvr); + if (multi_drvr + && multi_drvr->parallelGates(network_)) { + ArcDcalcArgSeq dcalc_args = makeArcDcalcArgs(drvr_vertex, multi_drvr, + edge, arc, dcalc_ap, + arc_delay_calc); + ArcDcalcResultSeq dcalc_results = + arc_delay_calc->gateDelays(dcalc_args, load_cap, load_pin_index_map, + dcalc_ap); + size_t drvr_count = multi_drvr->drvrs()->size(); + for (size_t drvr_idx = 0; drvr_idx < drvr_count; drvr_idx++) { + ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx]; + ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx]; + delay_changed |= annotateDelaysSlews(dcalc_arg.edge(), dcalc_arg.arc(), + dcalc_result, load_pin_index_map, + dcalc_ap); + } + } + else { + Vertex *from_vertex = edge->from(graph_); + const Slew in_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap); + ArcDcalcResult dcalc_result = arc_delay_calc->gateDelay(drvr_pin, arc, in_slew, + load_cap, parasitic, + load_pin_index_map, + dcalc_ap); + delay_changed |= annotateDelaysSlews(edge, arc, dcalc_result, + load_pin_index_map, dcalc_ap); + } + } + return delay_changed; +} + +ArcDcalcArgSeq +GraphDelayCalc::makeArcDcalcArgs(Vertex *drvr_vertex, + const MultiDrvrNet *multi_drvr, + Edge *edge, + const TimingArc *arc, + const DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc) +{ + ArcDcalcArgSeq dcalc_args; + for (auto drvr_vertex1 : *multi_drvr->drvrs()) { + Edge *edge1; + const TimingArc *arc1; + if (drvr_vertex1 == drvr_vertex) { + edge1 = edge; + arc1 = arc; + } + else + findParallelEdge(drvr_vertex1, edge, arc, edge1, arc1); + Vertex *from_vertex = edge1->from(graph_); + const RiseFall *from_rf = arc1->fromEdge()->asRiseFall(); + const RiseFall *drvr_rf = arc1->toEdge()->asRiseFall(); + const Slew in_slew = edgeFromSlew(from_vertex, from_rf, edge1, dcalc_ap); + const Pin *drvr_pin1 = drvr_vertex1->pin(); + Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin1, drvr_rf, + dcalc_ap); + dcalc_args.push_back(ArcDcalcArg(drvr_pin1, edge1, arc1, in_slew, + parasitic)); + } + return dcalc_args; +} + +// Find an edge/arc for parallel driver vertex to go along with the +// primary driver drvr_edge/drvr_arc. +void +GraphDelayCalc::findParallelEdge(Vertex *vertex, + Edge *drvr_edge, + const TimingArc *drvr_arc, + // Return values. + Edge *&edge, + const TimingArc *&arc) +{ + LibertyCell *drvr_cell = network_->libertyCell(network_->instance(drvr_edge->to(graph_)->pin())); + LibertyCell *vertex_cell = network_->libertyCell(network_->instance(vertex->pin())); + if (vertex_cell == drvr_cell) { + // Homogeneous drivers. + arc = drvr_arc; + LibertyPort *from_port = network_->libertyPort(edge->from(graph_)->pin()); + VertexInEdgeIterator edge_iter(vertex, graph_); + while (edge_iter.hasNext()) { + edge = edge_iter.next(); + if (network_->libertyPort(edge->from(graph_)->pin()) == from_port) + return; + } + } + else { + VertexInEdgeIterator edge_iter(vertex, graph_); + while (edge_iter.hasNext()) { + edge = edge_iter.next(); + for (TimingArc *arc1 : edge->timingArcSet()->arcs()) { + if (arc1->fromEdge() == drvr_arc->fromEdge() + && arc1->toEdge() == drvr_arc->toEdge()) { + arc = arc1; + return; + } + } + } + } + edge = nullptr; + arc = nullptr; +} + +bool +GraphDelayCalc::annotateDelaysSlews(Edge *edge, + const TimingArc *arc, + ArcDcalcResult &dcalc_result, + LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) +{ + bool delay_changed = annotateDelaySlew(edge, arc, + dcalc_result.gateDelay(), + dcalc_result.drvrSlew(), dcalc_ap); + if (!edge->role()->isLatchDtoQ()) { + Vertex *drvr_vertex = edge->to(graph_); + annotateLoadDelays(drvr_vertex, arc->toEdge()->asRiseFall(), dcalc_result, + load_pin_index_map, delay_zero, true, dcalc_ap); + } + return delay_changed; +} + +// Annotate the gate delay and merge the slew at the driver pin. +// Annotate the wire delays from the gate output to +// each load pin, and the merge the slews at each load pin. +bool +GraphDelayCalc::annotateDelaySlew(Edge *edge, + const TimingArc *arc, + ArcDelay &gate_delay, + Slew &gate_slew, + const DcalcAnalysisPt *dcalc_ap) +{ + bool delay_changed = false; + 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()); + debugPrint(debug_, "delay_calc", 3, + " gate delay = %s slew = %s", + delayAsString(gate_delay, this), + delayAsString(gate_slew, this)); + Vertex *drvr_vertex = edge->to(graph_); + const RiseFall *drvr_rf = arc->toEdge()->asRiseFall(); + // 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); + } + return delay_changed; +} + +// 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, + ArcDcalcResult &dcalc_result, + LoadPinIndexMap &load_pin_index_map, + const ArcDelay &extra_delay, + bool merge, + const DcalcAnalysisPt *dcalc_ap) +{ + 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(); + size_t load_idx = load_pin_index_map[load_pin]; + ArcDelay wire_delay = dcalc_result.wireDelay(load_idx); + Slew load_slew = dcalc_result.loadSlew(load_idx); + 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)); + } + } +} + +PinSeq +GraphDelayCalc::loadPins(Vertex *drvr_vertex) +{ + PinSeq load_pins; + 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_); + load_pins.push_back(load_vertex->pin()); + } + } + return load_pins; +} + +LoadPinIndexMap +GraphDelayCalc::makeLoadPinIndexMap(Vertex *drvr_vertex) +{ + LoadPinIndexMap load_pin_index_map(network_); + size_t load_idx = 0; + 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_); + const Pin *load_pin = load_vertex->pin(); + load_pin_index_map[load_pin] = load_idx; + load_idx++; + } + } + return load_pin_index_map; +} + float GraphDelayCalc::loadCap(const Pin *drvr_pin, const DcalcAnalysisPt *dcalc_ap) const @@ -866,9 +1132,8 @@ GraphDelayCalc::loadCap(const Pin *drvr_pin, 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, drvr_parasitic, drvr_rf, dcalc_ap, nullptr); + Parasitic *parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, dcalc_ap); + float cap = loadCap(drvr_pin, parasitic, drvr_rf, dcalc_ap, nullptr); arc_delay_calc_->finishDrvrPin(); if (min_max->compare(cap, load_cap)) load_cap = cap; @@ -881,24 +1146,24 @@ 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, + Parasitic *parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, dcalc_ap); - float cap = loadCap(drvr_pin, drvr_parasitic, drvr_rf, dcalc_ap, nullptr); + float cap = loadCap(drvr_pin, parasitic, drvr_rf, dcalc_ap, nullptr); return cap; } float GraphDelayCalc::loadCap(const Pin *drvr_pin, - const Parasitic *drvr_parasitic, + const Parasitic *parasitic, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) const { - return loadCap(drvr_pin, drvr_parasitic, rf, dcalc_ap, nullptr); + return loadCap(drvr_pin, parasitic, rf, dcalc_ap, nullptr); } float GraphDelayCalc::loadCap(const Pin *drvr_pin, - const Parasitic *drvr_parasitic, + const Parasitic *parasitic, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap, const MultiDrvrNet *multi_drvr) const @@ -912,13 +1177,13 @@ GraphDelayCalc::loadCap(const Pin *drvr_pin, 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); + loadCap(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 Parasitic *parasitic, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap, // Return values. @@ -930,23 +1195,23 @@ GraphDelayCalc::loadCap(const Pin *drvr_pin, // 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); + loadCap(parasitic, has_net_load, pin_cap, wire_cap); } void -GraphDelayCalc::loadCap(const Parasitic *drvr_parasitic, +GraphDelayCalc::loadCap(const Parasitic *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); + if (!has_net_load && parasitic) { + if (parasitics_->isParasiticNetwork(parasitic)) + wire_cap += parasitics_->capacitance(parasitic); else { // PiModel includes both pin and external caps. - float cap = parasitics_->capacitance(drvr_parasitic); + float cap = parasitics_->capacitance(parasitic); if (pin_cap > cap) { pin_cap = 0.0; wire_cap = cap; @@ -1049,80 +1314,6 @@ GraphDelayCalc::initWireDelays(Vertex *drvr_vertex) } } -// 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(const Pin *drvr_pin, - Vertex *drvr_vertex, - const TimingArc *arc, - const Parasitic *drvr_parasitic, - float related_out_cap, - Vertex *from_vertex, - Edge *edge, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - const MultiDrvrNet *multi_drvr, - 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; - float load_cap = loadCap(drvr_pin, drvr_parasitic, drvr_rf, dcalc_ap, multi_drvr); - if (multi_drvr - && multi_drvr->parallelGates(network_)) - arc_delay_calc->parallelGateDelay(drvr_pin, arc, from_slew, load_cap, - drvr_parasitic, related_out_cap, pvt, dcalc_ap, - gate_delay, gate_slew); - else - arc_delay_calc->gateDelay(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; -} - // Use clock slew for register/latch clk->q edges. Slew GraphDelayCalc::edgeFromSlew(const Vertex *from_vertex, @@ -1139,69 +1330,6 @@ GraphDelayCalc::edgeFromSlew(const Vertex *from_vertex, 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) @@ -1227,9 +1355,6 @@ GraphDelayCalc::findCheckEdgeDelays(Edge *edge, 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(); @@ -1253,9 +1378,9 @@ GraphDelayCalc::findCheckEdgeDelays(Edge *edge, related_out_parasitic, to_rf, dcalc_ap); } - ArcDelay check_delay; - arc_delay_calc->checkDelay(arc, from_slew, to_slew, related_out_cap, - pvt, dcalc_ap, check_delay); + ArcDelay check_delay = arc_delay_calc->checkDelay(to_pin, arc, from_slew, + to_slew, related_out_cap, + dcalc_ap); debugPrint(debug_, "delay_calc", 3, " check_delay = %s", delayAsString(check_delay, this)); @@ -1285,47 +1410,6 @@ GraphDelayCalc::checkEdgeClkSlew(const Vertex *from_vertex, //////////////////////////////////////////////////////////////// -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); - const 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(arc, from_slew, load_cap, to_parasitic, - related_out_cap, pvt, dcalc_ap); - arc_delay_calc_->finishDrvrPin(); - } - return ceff; -} - -//////////////////////////////////////////////////////////////// - string GraphDelayCalc::reportDelayCalc(const Edge *edge, const TimingArc *arc, @@ -1341,9 +1425,6 @@ GraphDelayCalc::reportDelayCalc(const Edge *edge, const 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) { @@ -1364,17 +1445,19 @@ GraphDelayCalc::reportDelayCalc(const Edge *edge, 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(arc, from_slew, from_slew_annotation, - to_slew, related_out_cap, pvt, - dcalc_ap, digits); + result = arc_delay_calc_->reportCheckDelay(to_pin, arc, from_slew, + from_slew_annotation, to_slew, + related_out_cap, 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(arc, from_slew, load_cap, to_parasitic, - related_out_cap, pvt, dcalc_ap, digits); + LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(to_vertex); + result = arc_delay_calc_->reportGateDelay(to_pin, arc, from_slew, load_cap, + to_parasitic, load_pin_index_map, + dcalc_ap, digits); } arc_delay_calc_->finishDrvrPin(); } diff --git a/dcalc/LumpedCapDelayCalc.cc b/dcalc/LumpedCapDelayCalc.cc index 5e99dd7a..3f91a37f 100644 --- a/dcalc/LumpedCapDelayCalc.cc +++ b/dcalc/LumpedCapDelayCalc.cc @@ -101,132 +101,88 @@ LumpedCapDelayCalc::findParasitic(const Pin *drvr_pin, return parasitic; } -ReducedParasiticType -LumpedCapDelayCalc::reducedParasiticType() const +ArcDcalcResult +LumpedCapDelayCalc::inputPortDelay(const Pin *, + float in_slew, + const RiseFall *rf, + const Parasitic *, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *) { - return ReducedParasiticType::pi_elmore; + const LibertyLibrary *drvr_library = network_->defaultLibertyLibrary(); + return makeResult(drvr_library,rf, 0.0, in_slew, load_pin_index_map); } -float -LumpedCapDelayCalc::ceff(const TimingArc *, - const Slew &, - float load_cap, - const Parasitic *, - float, - const Pvt *, - const DcalcAnalysisPt *) -{ - return load_cap; -} - -void -LumpedCapDelayCalc::gateDelay(const TimingArc *arc, +ArcDcalcResult +LumpedCapDelayCalc::gateDelay(const Pin *drvr_pin, + const TimingArc *arc, const Slew &in_slew, float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) + const Parasitic *, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) { - gateDelayInit(arc, in_slew, drvr_parasitic); GateTimingModel *model = gateModel(arc, dcalc_ap); debugPrint(debug_, "delay_calc", 3, - " in_slew = %s load_cap = %s related_load_cap = %s lumped", + " in_slew = %s load_cap = %s lumped", delayAsString(in_slew, this), - units()->capacitanceUnit()->asString(load_cap), - units()->capacitanceUnit()->asString(related_out_cap)); + units()->capacitanceUnit()->asString(load_cap)); + const RiseFall *rf = arc->toEdge()->asRiseFall(); + const LibertyLibrary *drvr_library = arc->to()->libertyLibrary(); if (model) { - ArcDelay gate_delay1; - Slew drvr_slew1; + ArcDelay gate_delay; + Slew drvr_slew; float in_slew1 = delayAsFloat(in_slew); // NaNs cause seg faults during table lookup. - if (isnan(load_cap) || isnan(related_out_cap) || isnan(delayAsFloat(in_slew))) + if (isnan(load_cap) || isnan(delayAsFloat(in_slew))) report_->error(710, "gate delay input variable is NaN"); - model->gateDelay(pvt, in_slew1, load_cap, related_out_cap, - pocv_enabled_, gate_delay1, drvr_slew1); - gate_delay = gate_delay1; - drvr_slew = drvr_slew1; - drvr_slew_ = drvr_slew1; - } - else { - gate_delay = delay_zero; - drvr_slew = delay_zero; - drvr_slew_ = 0.0; + model->gateDelay(pinPvt(drvr_pin, dcalc_ap), in_slew1, load_cap, pocv_enabled_, + gate_delay, drvr_slew); + return makeResult(drvr_library, rf, gate_delay, drvr_slew, load_pin_index_map); } + else + return makeResult(drvr_library, rf, delay_zero, delay_zero, load_pin_index_map); } -void -LumpedCapDelayCalc::loadDelay(const Pin *load_pin, - ArcDelay &wire_delay, - Slew &load_slew) +ArcDcalcResult +LumpedCapDelayCalc::makeResult(const LibertyLibrary *drvr_library, + const RiseFall *rf, + ArcDelay gate_delay, + Slew drvr_slew, + const LoadPinIndexMap &load_pin_index_map) { - Delay wire_delay1 = 0.0; - Slew load_slew1 = drvr_slew_ * multi_drvr_slew_factor_; - thresholdAdjust(load_pin, wire_delay1, load_slew1); - wire_delay = wire_delay1; - load_slew = load_slew1; + ArcDcalcResult dcalc_result(load_pin_index_map.size()); + dcalc_result.setGateDelay(gate_delay); + dcalc_result.setDrvrSlew(drvr_slew); + + for (auto load_pin_index : load_pin_index_map) { + const Pin *load_pin = load_pin_index.first; + size_t load_idx = load_pin_index.second; + ArcDelay wire_delay = 0.0; + thresholdAdjust(load_pin, drvr_library, rf, wire_delay, drvr_slew); + dcalc_result.setWireDelay(load_idx, wire_delay); + dcalc_result.setLoadSlew(load_idx, drvr_slew); + } + return dcalc_result; } string -LumpedCapDelayCalc::reportGateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - int digits) +LumpedCapDelayCalc::reportGateDelay(const Pin *check_pin, + const TimingArc *arc, + const Slew &in_slew, + float load_cap, + const Parasitic *, + const LoadPinIndexMap &, + const DcalcAnalysisPt *dcalc_ap, + int digits) { GateTimingModel *model = gateModel(arc, dcalc_ap); if (model) { float in_slew1 = delayAsFloat(in_slew); - return model->reportGateDelay(pvt, in_slew1, load_cap, related_out_cap, + return model->reportGateDelay(pinPvt(check_pin, dcalc_ap), in_slew1, load_cap, false, digits); } return ""; } -void -LumpedCapDelayCalc::checkDelay(const TimingArc *arc, - const Slew &from_slew, - const Slew &to_slew, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &margin) -{ - CheckTimingModel *model = checkModel(arc, dcalc_ap); - if (model) { - float from_slew1 = delayAsFloat(from_slew); - float to_slew1 = delayAsFloat(to_slew); - model->checkDelay(pvt, from_slew1, to_slew1, related_out_cap, pocv_enabled_, margin); - } - else - margin = delay_zero; -} - -string -LumpedCapDelayCalc::reportCheckDelay(const TimingArc *arc, - const Slew &from_slew, - const char *from_slew_annotation, - const Slew &to_slew, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - int digits) -{ - CheckTimingModel *model = checkModel(arc, dcalc_ap); - if (model) { - float from_slew1 = delayAsFloat(from_slew); - float to_slew1 = delayAsFloat(to_slew); - return model->reportCheckDelay(pvt, from_slew1, from_slew_annotation, - to_slew1, related_out_cap, false, digits); - } - return ""; -} - } // namespace diff --git a/dcalc/LumpedCapDelayCalc.hh b/dcalc/LumpedCapDelayCalc.hh index db7473c0..3ac111c3 100644 --- a/dcalc/LumpedCapDelayCalc.hh +++ b/dcalc/LumpedCapDelayCalc.hh @@ -30,54 +30,34 @@ public: Parasitic *findParasitic(const Pin *drvr_pin, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) override; - ReducedParasiticType reducedParasiticType() const override; - void gateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) override; - float ceff(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap) override; - void loadDelay(const Pin *load_pin, - // Return values. - ArcDelay &wire_delay, - Slew &load_slew) override; - void checkDelay(const TimingArc *arc, - const Slew &from_slew, - const Slew &to_slew, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &margin) override; - string reportGateDelay(const TimingArc *arc, + ArcDcalcResult inputPortDelay(const Pin *port_pin, + float in_slew, + const RiseFall *rf, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) override; + ArcDcalcResult gateDelay(const Pin *drvr_pin, + const TimingArc *arc, + const Slew &in_slew, + float load_cap, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) override; + string reportGateDelay(const Pin *drvr_pin, + const TimingArc *arc, const Slew &in_slew, float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap, int digits) override; - string reportCheckDelay(const TimingArc *arc, - const Slew &from_slew, - const char *from_slew_annotation, - const Slew &to_slew, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - int digits) override; protected: + ArcDcalcResult makeResult(const LibertyLibrary *drvr_library, + const RiseFall *rf, + ArcDelay gate_delay, + Slew drvr_slew, + const LoadPinIndexMap &load_pin_index_map); }; ArcDelayCalc * diff --git a/dcalc/ParallelDelayCalc.cc b/dcalc/ParallelDelayCalc.cc index 62fd90a6..db352812 100644 --- a/dcalc/ParallelDelayCalc.cc +++ b/dcalc/ParallelDelayCalc.cc @@ -31,141 +31,65 @@ ParallelDelayCalc::ParallelDelayCalc(StaState *sta): { } -void -ParallelDelayCalc::inputPortDelay(const Pin *drvr_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap) +ArcDcalcResultSeq +ParallelDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args, + float load_cap, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) { - DelayCalcBase::inputPortDelay(drvr_pin, in_slew, rf, parasitic, dcalc_ap); - multi_drvr_slew_factor_ = 1.0; -} - -void -ParallelDelayCalc::gateDelayInit(const TimingArc *arc, - const Slew &in_slew, - const Parasitic *drvr_parasitic) -{ - DelayCalcBase::gateDelayInit(arc, in_slew, drvr_parasitic); - multi_drvr_slew_factor_ = 1.0F; -} - -void -ParallelDelayCalc::findParallelGateDelays(const MultiDrvrNet *multi_drvr, - GraphDelayCalc *dcalc) -{ - int count = RiseFall::index_count * corners_->dcalcAnalysisPtCount(); - parallel_delays_.resize(count); - parallel_slews_.resize(count); - for (auto dcalc_ap : corners_->dcalcAnalysisPts()) { - for (auto drvr_rf : RiseFall::range()) { - DcalcAPIndex ap_index = dcalc_ap->index(); - int drvr_rf_index = drvr_rf->index(); - int index = ap_index * RiseFall::index_count + drvr_rf_index; - findMultiDrvrGateDelay(multi_drvr, drvr_rf, dcalc_ap, dcalc, - parallel_delays_[index], - parallel_slews_[index]); - } - } -} - -void -ParallelDelayCalc::findMultiDrvrGateDelay(const MultiDrvrNet *multi_drvr, - const RiseFall *drvr_rf, - const DcalcAnalysisPt *dcalc_ap, - GraphDelayCalc *dcalc, - // Return values. - ArcDelay ¶llel_delay, - Slew ¶llel_slew) -{ - ArcDelay delay_sum = 0.0; + size_t drvr_count = dcalc_args.size(); + ArcDcalcResultSeq dcalc_results(drvr_count); Slew slew_sum = 0.0; - for (Vertex *drvr_vertex : *multi_drvr->drvrs()) { - Pin *drvr_pin = drvr_vertex->pin(); - Instance *drvr_inst = network_->instance(drvr_pin); - const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax()); - if (pvt == nullptr) - pvt = dcalc_ap->operatingConditions(); - VertexInEdgeIterator edge_iter(drvr_vertex, graph_); - while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - TimingArcSet *arc_set = edge->timingArcSet(); - const LibertyPort *related_out_port = arc_set->relatedOut(); - for (TimingArc *arc : arc_set->arcs()) { - RiseFall *arc_rf = arc->toEdge()->asRiseFall(); - if (arc_rf == drvr_rf) { - Vertex *from_vertex = edge->from(graph_); - RiseFall *from_rf = arc->fromEdge()->asRiseFall(); - Slew from_slew = dcalc->edgeFromSlew(from_vertex, from_rf, - edge, dcalc_ap); - ArcDelay intrinsic_delay; - Slew intrinsic_slew; - gateDelay(arc, from_slew, 0.0, 0, 0.0, pvt, dcalc_ap, - intrinsic_delay, intrinsic_slew); - Parasitic *parasitic = findParasitic(drvr_pin, drvr_rf, dcalc_ap); - const Pin *related_out_pin = 0; - float related_out_cap = 0.0; - if (related_out_port) { - Instance *inst = network_->instance(drvr_pin); - related_out_pin = network_->findPin(inst, related_out_port); - if (related_out_pin) { - Parasitic *related_out_parasitic = findParasitic(related_out_pin, - drvr_rf, - dcalc_ap); - related_out_cap = dcalc->loadCap(related_out_pin, - related_out_parasitic, - drvr_rf, dcalc_ap); - } - } - float load_cap = dcalc->loadCap(drvr_pin, parasitic, - drvr_rf, dcalc_ap); - ArcDelay gate_delay; - Slew gate_slew; - gateDelay(arc, from_slew, load_cap, parasitic, - related_out_cap, pvt, dcalc_ap, - gate_delay, gate_slew); - delay_sum += 1.0F / (gate_delay - intrinsic_delay); - slew_sum += 1.0F / gate_slew; - } - } + ArcDelay load_delay_sum = 0.0; + vector intrinsic_delays(dcalc_args.size()); + vector load_delays(dcalc_args.size()); + for (size_t drvr_idx = 0; drvr_idx < drvr_count; drvr_idx++) { + ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx]; + ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx]; + const Pin *drvr_pin = dcalc_arg.drvrPin(); + const TimingArc *arc = dcalc_arg.arc(); + Slew in_slew = dcalc_arg.inSlew(); + + ArcDcalcResult intrinsic_result = + arc_delay_calc_->gateDelay(drvr_pin, arc, in_slew, 0.0, nullptr, + load_pin_index_map, dcalc_ap); + ArcDelay intrinsic_delay = intrinsic_result.gateDelay(); + intrinsic_delays[drvr_idx] = intrinsic_result.gateDelay(); + + ArcDcalcResult gate_result = arc_delay_calc_->gateDelay(drvr_pin, arc, + in_slew, load_cap, + dcalc_arg.parasitic(), + load_pin_index_map, + dcalc_ap); + ArcDelay gate_delay = gate_result.gateDelay(); + Slew drvr_slew = gate_result.drvrSlew(); + ArcDelay load_delay = gate_delay - intrinsic_delay; + load_delays[drvr_idx] = load_delay; + + if (!delayZero(load_delay)) + load_delay_sum += 1.0 / load_delay; + if (!delayZero(drvr_slew)) + slew_sum += 1.0 / drvr_slew; + + dcalc_result.setLoadCount(load_pin_index_map.size()); + for (auto load_pin_index : load_pin_index_map) { + size_t load_idx = load_pin_index.second; + dcalc_result.setWireDelay(load_idx, gate_result.wireDelay(load_idx)); + dcalc_result.setLoadSlew(load_idx, gate_result.loadSlew(load_idx)); } } - parallel_delay = 1.0F / delay_sum; - parallel_slew = 1.0F / slew_sum; -} -void -ParallelDelayCalc::parallelGateDelay(const Pin *, - const TimingArc *arc, - const Slew &from_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &gate_slew) -{ - ArcDelay intrinsic_delay; - Slew intrinsic_slew; - gateDelay(arc, from_slew, 0.0, 0, 0.0, pvt, dcalc_ap, - intrinsic_delay, intrinsic_slew); - const RiseFall *drvr_rf = arc->toEdge()->asRiseFall(); - int index = dcalc_ap->index() * RiseFall::index_count + drvr_rf->index(); - ArcDelay parallel_delay = parallel_delays_[index]; - Slew parallel_slew = parallel_slews_[index]; - gate_delay = parallel_delay + intrinsic_delay; - gate_slew = parallel_slew; + ArcDelay gate_load_delay = delayZero(load_delay_sum) + ? delay_zero + : 1.0 / load_delay_sum; + ArcDelay drvr_slew = delayZero(slew_sum) ? delay_zero : 1.0 / slew_sum; - Delay gate_delay1; - Slew gate_slew1; - gateDelay(arc, from_slew, load_cap, drvr_parasitic, - related_out_cap, pvt, dcalc_ap, - gate_delay1, gate_slew1); - float factor = delayRatio(gate_slew, gate_slew1); - multi_drvr_slew_factor_ = factor; + for (size_t drvr_idx = 0; drvr_idx < drvr_count; drvr_idx++) { + ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx]; + dcalc_result.setGateDelay(intrinsic_delays[drvr_idx] + gate_load_delay); + dcalc_result.setDrvrSlew(drvr_slew); + } + return dcalc_results; } } // namespace diff --git a/dcalc/ParallelDelayCalc.hh b/dcalc/ParallelDelayCalc.hh index 68510e99..8079c31d 100644 --- a/dcalc/ParallelDelayCalc.hh +++ b/dcalc/ParallelDelayCalc.hh @@ -17,52 +17,21 @@ #pragma once #include +#include #include "DelayCalcBase.hh" namespace sta { -// Delay calculation for parallel gates based on using parallel drive resistance. +// Delay calculation for parallel gates using parallel drive resistance. class ParallelDelayCalc : public DelayCalcBase { public: - explicit ParallelDelayCalc(StaState *sta); - void inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap) override; - void gateDelayInit(const TimingArc *arc, - const Slew &in_slew, - const Parasitic *drvr_parasitic); - void findParallelGateDelays(const MultiDrvrNet *multi_drvr, - GraphDelayCalc *dcalc) override; - void parallelGateDelay(const Pin *drvr_pin, - const TimingArc *arc, - const Slew &from_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &gate_slew) override; - -protected: - void findMultiDrvrGateDelay(const MultiDrvrNet *multi_drvr, - const RiseFall *drvr_rf, - const DcalcAnalysisPt *dcalc_ap, - GraphDelayCalc *dcalc, - // Return values. - ArcDelay ¶llel_delay, - Slew ¶llel_slew); - - // [drvr_rf->index][dcalc_ap->index] - vector parallel_delays_; - // [drvr_rf->index][dcalc_ap->index] - vector parallel_slews_; - float multi_drvr_slew_factor_; + ParallelDelayCalc(StaState *sta); + ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &dcalc_args, + float load_cap, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) override; }; } // namespace diff --git a/dcalc/SlewDegradeDelayCalc.cc b/dcalc/SlewDegradeDelayCalc.cc deleted file mode 100644 index 3e00e164..00000000 --- a/dcalc/SlewDegradeDelayCalc.cc +++ /dev/null @@ -1,141 +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 "SlewDegradeDelayCalc.hh" - -#include "TimingArc.hh" -#include "Liberty.hh" -#include "Network.hh" -#include "Sdc.hh" -#include "Parasitics.hh" -#include "DcalcAnalysisPt.hh" -#include "LumpedCapDelayCalc.hh" - -namespace sta { - -// Liberty table model lumped capacitance arc delay calculator. -// Effective capacitance is the pi model total capacitance (C1+C2). -// Wire delays are elmore delays. -// Driver slews are degraded to loads by rise/fall transition_degradation -// tables. -class SlewDegradeDelayCalc : public LumpedCapDelayCalc -{ -public: - SlewDegradeDelayCalc(StaState *sta); - ArcDelayCalc *copy() override; - void inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap) override; - void gateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) override; - void loadDelay(const Pin *load_pin, - ArcDelay &wire_delay, - Slew &load_slew) override; - - using LumpedCapDelayCalc::gateDelay; - using LumpedCapDelayCalc::reportGateDelay; - -private: - const Pvt *pvt_; -}; - -ArcDelayCalc * -makeSlewDegradeDelayCalc(StaState *sta) -{ - return new SlewDegradeDelayCalc(sta); -} - -SlewDegradeDelayCalc::SlewDegradeDelayCalc(StaState *sta) : - LumpedCapDelayCalc(sta) -{ -} - -ArcDelayCalc * -SlewDegradeDelayCalc::copy() -{ - return new SlewDegradeDelayCalc(this); -} - -void -SlewDegradeDelayCalc::inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap) -{ - pvt_ = dcalc_ap->operatingConditions(); - LumpedCapDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap); -} - -void -SlewDegradeDelayCalc::gateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) -{ - input_port_ = false; - drvr_parasitic_ = drvr_parasitic; - drvr_rf_ = arc->toEdge()->asRiseFall(); - drvr_cell_ = arc->from()->libertyCell(); - drvr_library_ = drvr_cell_->libertyLibrary(); - pvt_ = pvt; - LumpedCapDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic, - related_out_cap, pvt, dcalc_ap, - gate_delay, drvr_slew); -} - -void -SlewDegradeDelayCalc::loadDelay(const Pin *load_pin, - ArcDelay &wire_delay, - Slew &load_slew) -{ - ArcDelay wire_delay1 = 0.0; - Slew load_slew1 = drvr_slew_; - bool elmore_exists = false; - float elmore = 0.0; - if (drvr_parasitic_) - parasitics_->findElmore(drvr_parasitic_, load_pin, elmore, elmore_exists); - if (elmore_exists) { - if (drvr_library_ && drvr_library_->wireSlewDegradationTable(drvr_rf_)) { - wire_delay1 = elmore; - load_slew1 = drvr_library_->degradeWireSlew(drvr_rf_, - delayAsFloat(drvr_slew_), - delayAsFloat(wire_delay1)); - } - dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1); - } - thresholdAdjust(load_pin, wire_delay1, load_slew1); - wire_delay = wire_delay1; - load_slew = load_slew1 * multi_drvr_slew_factor_; -} - -} // namespace diff --git a/dcalc/UnitDelayCalc.cc b/dcalc/UnitDelayCalc.cc index cc629ba5..232c8ecd 100644 --- a/dcalc/UnitDelayCalc.cc +++ b/dcalc/UnitDelayCalc.cc @@ -45,86 +45,65 @@ UnitDelayCalc::findParasitic(const Pin *, return nullptr; } -ReducedParasiticType -UnitDelayCalc::reducedParasiticType() const -{ - return ReducedParasiticType::none; -} - -void +ArcDcalcResult UnitDelayCalc::inputPortDelay(const Pin *, float, const RiseFall *, const Parasitic *, - const DcalcAnalysisPt *) + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *) { + return unitDelayResult(load_pin_index_map); } -void -UnitDelayCalc::gateDelay(const TimingArc *, +ArcDcalcResult +UnitDelayCalc::gateDelay(const Pin *, + const TimingArc *, const Slew &, float, const Parasitic *, - float, - const Pvt *, const DcalcAnalysisPt *, - // Return values. - ArcDelay &gate_delay, Slew &drvr_slew) + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *) { - gate_delay = units_->timeUnit()->scale(); - drvr_slew = 0.0; + return unitDelayResult(load_pin_index_map); } -void -UnitDelayCalc::findParallelGateDelays(const MultiDrvrNet *, - GraphDelayCalc *) +ArcDcalcResultSeq +UnitDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args, + float, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *) { + size_t drvr_count = dcalc_args.size(); + ArcDcalcResultSeq dcalc_results(drvr_count); + for (size_t drvr_idx = 0; drvr_idx < drvr_count; drvr_idx++) { + ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx]; + dcalc_result = unitDelayResult(load_pin_index_map); + } + return dcalc_results; } -void -UnitDelayCalc::parallelGateDelay(const Pin *, - const TimingArc *, - const Slew &, - float, - const Parasitic *, - float, - const Pvt *, - const DcalcAnalysisPt *, - // Return values. - ArcDelay &gate_delay, - Slew &gate_slew) +ArcDcalcResult +UnitDelayCalc::unitDelayResult(const LoadPinIndexMap &load_pin_index_map) { - gate_delay = units_->timeUnit()->scale(); - gate_slew = 0.0; -} - -void -UnitDelayCalc::loadDelay(const Pin *, - ArcDelay &wire_delay, - Slew &load_slew) -{ - wire_delay = 0.0; - load_slew = 0.0; -} - -float -UnitDelayCalc::ceff(const TimingArc *, - const Slew &, - float, - const Parasitic *, - float, - const Pvt *, - const DcalcAnalysisPt *) -{ - return 0.0; + size_t load_count = load_pin_index_map.size(); + ArcDcalcResult dcalc_result(load_count); + dcalc_result.setGateDelay(units_->timeUnit()->scale()); + dcalc_result.setDrvrSlew(0.0); + for (size_t load_idx = 0; load_idx < load_count; load_idx++) { + dcalc_result.setWireDelay(load_idx, 0.0); + dcalc_result.setLoadSlew(load_idx, 0.0); + } + return dcalc_result; } string -UnitDelayCalc::reportGateDelay(const TimingArc *, +UnitDelayCalc::reportGateDelay(const Pin *, + const TimingArc *, const Slew &, float, const Parasitic *, - float, - const Pvt *, + const LoadPinIndexMap &, const DcalcAnalysisPt *, int) { @@ -133,26 +112,24 @@ UnitDelayCalc::reportGateDelay(const TimingArc *, return result; } -void -UnitDelayCalc::checkDelay(const TimingArc *, +ArcDelay +UnitDelayCalc::checkDelay(const Pin *, + const TimingArc *, const Slew &, const Slew &, float, - const Pvt *, - const DcalcAnalysisPt *, - // Return values. - ArcDelay &margin) + const DcalcAnalysisPt *) { - margin = units_->timeUnit()->scale(); + return units_->timeUnit()->scale(); } string -UnitDelayCalc::reportCheckDelay(const TimingArc *, +UnitDelayCalc::reportCheckDelay(const Pin *, + const TimingArc *, const Slew &, const char *, const Slew &, float, - const Pvt *, const DcalcAnalysisPt *, int) { diff --git a/dcalc/UnitDelayCalc.hh b/dcalc/UnitDelayCalc.hh index 6ecae7cf..ec520a53 100644 --- a/dcalc/UnitDelayCalc.hh +++ b/dcalc/UnitDelayCalc.hh @@ -29,72 +29,50 @@ public: Parasitic *findParasitic(const Pin *drvr_pin, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) override; - ReducedParasiticType reducedParasiticType() const override; - void inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, + ArcDcalcResult inputPortDelay(const Pin *port_pin, + float in_slew, + const RiseFall *rf, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) override; + ArcDcalcResult gateDelay(const Pin *drvr_pin, + const TimingArc *arc, + const Slew &in_slew, + // Pass in load_cap or parasitic. + float load_cap, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) override; + ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &args, + float load_cap, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) override; + ArcDelay checkDelay(const Pin *check_pin, + const TimingArc *arc, + const Slew &from_slew, + const Slew &to_slew, + float related_out_cap, const DcalcAnalysisPt *dcalc_ap) override; - void gateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) override; - void findParallelGateDelays(const MultiDrvrNet *multi_drvr, - GraphDelayCalc *dcalc) override; - // Retrieve the delay and slew for one parallel gate. - void parallelGateDelay(const Pin *drvr_pin, + string reportGateDelay(const Pin *drvr_pin, const TimingArc *arc, - const Slew &from_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &gate_slew) override; - void loadDelay(const Pin *load_pin, - // Return values. - ArcDelay &wire_delay, - Slew &load_slew) override; - float ceff(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap) override; - void checkDelay(const TimingArc *arc, - const Slew &from_slew, - const Slew &to_slew, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &margin) override; - string reportGateDelay(const TimingArc *arc, const Slew &in_slew, float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap, int digits) override; - string reportCheckDelay(const TimingArc *arc, + string reportCheckDelay(const Pin *check_pin, + const TimingArc *arc, const Slew &from_slew, const char *from_slew_annotation, const Slew &to_slew, float related_out_cap, - const Pvt *pvt, const DcalcAnalysisPt *dcalc_ap, int digits) override; - void finishDrvrPin() override; + void finishDrvrPin() override; + +protected: + ArcDcalcResult unitDelayResult(const LoadPinIndexMap &load_pin_index_map); }; ArcDelayCalc * diff --git a/include/sta/ArcDelayCalc.hh b/include/sta/ArcDelayCalc.hh index c1c6617b..cbdb1fd9 100644 --- a/include/sta/ArcDelayCalc.hh +++ b/include/sta/ArcDelayCalc.hh @@ -18,10 +18,14 @@ #include #include +#include #include "MinMax.hh" #include "LibertyClass.hh" +#include "TimingArc.hh" +#include "TableModel.hh" #include "NetworkClass.hh" +#include "GraphClass.hh" #include "Delay.hh" #include "ParasiticsClass.hh" #include "StaState.hh" @@ -30,18 +34,77 @@ namespace sta { using std::string; using std::vector; +using std::map; +class Corner; class Parasitic; class DcalcAnalysisPt; class MultiDrvrNet; +// Driver load pin -> index in driver loads. +typedef map LoadPinIndexMap; + +// Arguments for gate delay calculation delay/slew at one driver pin +// through one timing arc at one delay calc analysis point. +class ArcDcalcArg +{ +public: + ArcDcalcArg(); + ArcDcalcArg(const Pin *drvr_pin, + Edge *edge, + const TimingArc *arc, + const Slew in_slew, + const Parasitic *parasitic); + const Pin *drvrPin() const { return drvr_pin_; } + Edge *edge() const { return edge_; } + const TimingArc *arc() const { return arc_; } + Slew inSlew() const { return in_slew_; } + const Parasitic *parasitic() { return parasitic_; } + void setParasitic(const Parasitic *parasitic); + +protected: + const Pin *drvr_pin_; + Edge *edge_; + const TimingArc *arc_; + Slew in_slew_; + const Parasitic *parasitic_; +}; + +// Arc delay calc result. +class ArcDcalcResult +{ +public: + ArcDcalcResult(); + ArcDcalcResult(size_t load_count); + void setLoadCount(size_t load_count); + ArcDelay &gateDelay() { return gate_delay_; } + void setGateDelay(ArcDelay gate_delay); + Slew &drvrSlew() { return drvr_slew_; } + void setDrvrSlew(Slew drvr_slew); + ArcDelay wireDelay(size_t load_idx) const; + void setWireDelay(size_t load_idx, + ArcDelay wire_delay); + Slew loadSlew(size_t load_idx) const; + void setLoadSlew(size_t load_idx, + Slew load_slew); + +protected: + ArcDelay gate_delay_; + Slew drvr_slew_; + // Load wire delay and slews indexed by load pin index. + vector wire_delays_; + vector load_slews_; +}; + +typedef vector ArcDcalcArgSeq; +typedef vector ArcDcalcResultSeq; + // Delay calculator class hierarchy. // ArcDelayCalc // UnitDelayCalc // DelayCalcBase // ParallelDelayCalc // LumpedCapDelayCalc -// SlewDegradeDelayCalc // DmpCeffDelayCalc // DmpCeffElmoreDelayCalc // DmpCeffTwoPoleDelayCalc @@ -61,95 +124,68 @@ public: virtual Parasitic *findParasitic(const Pin *drvr_pin, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) = 0; - virtual ReducedParasiticType reducedParasiticType() const = 0; // Find the wire delays and slews for an input port without a driving cell. // This call primarily initializes the load delay/slew iterator. - virtual void inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap) = 0; + virtual ArcDcalcResult inputPortDelay(const Pin *port_pin, + float in_slew, + const RiseFall *rf, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) = 0; // Find the delay and slew for arc driving drvr_pin. + virtual ArcDcalcResult gateDelay(const Pin *drvr_pin, + const TimingArc *arc, + const Slew &in_slew, + // Pass in load_cap or parasitic. + float load_cap, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) = 0; virtual void gateDelay(const TimingArc *arc, const Slew &in_slew, - // Pass in load_cap or drvr_parasitic. float load_cap, - const Parasitic *drvr_parasitic, + const Parasitic *parasitic, float related_out_cap, const Pvt *pvt, const DcalcAnalysisPt *dcalc_ap, // Return values. ArcDelay &gate_delay, - Slew &drvr_slew) = 0; + Slew &drvr_slew) __attribute__ ((deprecated)); + // Find gate delays and slews for parallel gates. - virtual void findParallelGateDelays(const MultiDrvrNet *multi_drvr, - GraphDelayCalc *dcalc) = 0; - // Retrieve the delay and slew for one parallel gate. - virtual void parallelGateDelay(const Pin *drvr_pin, - const TimingArc *arc, - const Slew &from_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &gate_slew) = 0; - // Find the wire delay and load slew of a load pin. - // Called after inputPortDelay or gateDelay. - virtual void loadDelay(const Pin *load_pin, - // Return values. - ArcDelay &wire_delay, - Slew &load_slew) = 0; - // Ceff for parasitics with pi models. - virtual float ceff(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap) = 0; + virtual ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &args, + float load_cap, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) = 0; // Find the delay for a timing check arc given the arc's // from/clock, to/data slews and related output pin parasitic. - virtual void checkDelay(const TimingArc *arc, - const Slew &from_slew, - const Slew &to_slew, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &margin) = 0; + virtual ArcDelay checkDelay(const Pin *check_pin, + const TimingArc *arc, + const Slew &from_slew, + const Slew &to_slew, + float related_out_cap, + const DcalcAnalysisPt *dcalc_ap) = 0; // Report delay and slew calculation. - virtual string reportGateDelay(const TimingArc *arc, + virtual string reportGateDelay(const Pin *drvr_pin, + const TimingArc *arc, const Slew &in_slew, - // Pass in load_cap or drvr_parasitic. float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap, int digits) = 0; // Report timing check delay calculation. - virtual string reportCheckDelay(const TimingArc *arc, + virtual string reportCheckDelay(const Pin *check_pin, + const TimingArc *arc, const Slew &from_slew, const char *from_slew_annotation, const Slew &to_slew, float related_out_cap, - const Pvt *pvt, const DcalcAnalysisPt *dcalc_ap, int digits) = 0; virtual void finishDrvrPin() = 0; - -protected: - GateTimingModel *gateModel(const TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap) const; - CheckTimingModel *checkModel(const TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap) const; - TimingModel *model(const TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap) const; }; } // namespace diff --git a/include/sta/GraphDelayCalc.hh b/include/sta/GraphDelayCalc.hh index da47b31e..aac2282c 100644 --- a/include/sta/GraphDelayCalc.hh +++ b/include/sta/GraphDelayCalc.hh @@ -25,10 +25,12 @@ #include "DcalcAnalysisPt.hh" #include "StaState.hh" #include "Delay.hh" +#include "ArcDelayCalc.hh" namespace sta { using std::vector; +using std::map; class DelayCalcObserver; class MultiDrvrNet; @@ -79,7 +81,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, - const Parasitic *drvr_parasitic, + const Parasitic *parasitic, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap, // Return values. @@ -87,11 +89,11 @@ public: float &wire_cap) const; // Load pin_cap + wire_cap including parasitic. virtual float loadCap(const Pin *drvr_pin, - const Parasitic *drvr_parasitic, + const Parasitic *parasitic, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) const; float loadCap(const Pin *drvr_pin, - const Parasitic *drvr_parasitic, + const Parasitic *parasitic, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap, const MultiDrvrNet *multi_drvr) const; @@ -103,9 +105,13 @@ public: float &wire_cap, float &fanout, bool &has_set_load) const; - float ceff(Edge *edge, - TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap); + PinSeq loadPins(Vertex *drvr_vertex); + LoadPinIndexMap makeLoadPinIndexMap(Vertex *drvr_vertex); + void findDriverArcDelays(Vertex *drvr_vertex, + Edge *edge, + const TimingArc *arc, + const DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc); // Precedence: // SDF annotation // Liberty library @@ -176,12 +182,29 @@ protected: MultiDrvrNet *multi_drvr, ArcDelayCalc *arc_delay_calc); void initLoadSlews(Vertex *drvr_vertex); - bool findDriverEdgeDelays(const Instance *drvr_inst, - const Pin *drvr_pin, - Vertex *drvr_vertex, + bool findDriverEdgeDelays(Vertex *drvr_vertex, const MultiDrvrNet *multi_drvr, Edge *edge, ArcDelayCalc *arc_delay_calc); + bool findDriverArcDelays(Vertex *drvr_vertex, + const MultiDrvrNet *multi_drvr, + Edge *edge, + const TimingArc *arc, + LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc); + ArcDcalcArgSeq makeArcDcalcArgs(Vertex *drvr_vertex, + const MultiDrvrNet *multi_drvr, + Edge *edge, + const TimingArc *arc, + const DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc); + void findParallelEdge(Vertex *vertex, + Edge *drvr_edge, + const TimingArc *drvr_arc, + // Return values. + Edge *&edge, + const TimingArc *&arc); void initWireDelays(Vertex *drvr_vertex); void initRootSlews(Vertex *vertex); void zeroSlewAndWireDelays(Vertex *drvr_vertex); @@ -189,23 +212,24 @@ protected: ArcDelayCalc *arc_delay_calc, bool propagate); void enqueueTimingChecksEdges(Vertex *vertex); - bool findArcDelay(const Pin *drvr_pin, - Vertex *drvr_vertex, - const TimingArc *arc, - const Parasitic *drvr_parasitic, - float related_out_cap, - Vertex *from_vertex, - Edge *edge, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - const MultiDrvrNet *multi_drvr, - ArcDelayCalc *arc_delay_calc); + bool annotateDelaysSlews(Edge *edge, + const TimingArc *arc, + ArcDcalcResult &dcalc_result, + LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap); + + bool annotateDelaySlew(Edge *edge, + const TimingArc *arc, + ArcDelay &gate_delay, + Slew &gate_slew, + const DcalcAnalysisPt *dcalc_ap); void annotateLoadDelays(Vertex *drvr_vertex, - const RiseFall *drvr_rf, - const ArcDelay &extra_delay, - bool merge, - const DcalcAnalysisPt *dcalc_ap, - ArcDelayCalc *arc_delay_calc); + const RiseFall *drvr_rf, + ArcDcalcResult &dcalc_result, + LoadPinIndexMap &load_pin_index_map, + const ArcDelay &extra_delay, + bool merge, + const DcalcAnalysisPt *dcalc_ap); void findLatchEdgeDelays(Edge *edge); void findCheckEdgeDelays(Edge *edge, ArcDelayCalc *arc_delay_calc); @@ -215,7 +239,7 @@ protected: const DcalcAnalysisPt *dcalc_ap); bool bidirectDrvrSlewFromLoad(const Vertex *vertex) const; MultiDrvrNet *multiDrvrNet(const Vertex *drvr_vertex) const; - void loadCap(const Parasitic *drvr_parasitic, + void loadCap(const Parasitic *parasitic, bool has_set_load, // Return values. float &pin_cap, diff --git a/include/sta/LinearModel.hh b/include/sta/LinearModel.hh index 25f1988c..5976995c 100644 --- a/include/sta/LinearModel.hh +++ b/include/sta/LinearModel.hh @@ -29,7 +29,6 @@ public: void gateDelay(const Pvt *pvt, float in_slew, float load_cap, - float related_out_cap, bool pocv_enabled, // Return values. ArcDelay &gate_delay, @@ -37,7 +36,6 @@ public: string reportGateDelay(const Pvt *pvt, float in_slew, float load_cap, - float related_out_cap, bool pocv_enabled, int digits) const override; float driveResistance(const Pvt *pvt) const override; @@ -54,13 +52,11 @@ class CheckLinearModel : public CheckTimingModel public: explicit CheckLinearModel(LibertyCell *cell, float intrinsic); - void checkDelay(const Pvt *pvt, - float from_slew, - float to_slew, - float related_out_cap, - bool pocv_enabled, - // Return values. - ArcDelay &margin) const override; + ArcDelay checkDelay(const Pvt *pvt, + float from_slew, + float to_slew, + float related_out_cap, + bool pocv_enabled) const override; string reportCheckDelay(const Pvt *pvt, float from_slew, const char *from_slew_annotation, diff --git a/include/sta/TableModel.hh b/include/sta/TableModel.hh index 039b21e2..8015b147 100644 --- a/include/sta/TableModel.hh +++ b/include/sta/TableModel.hh @@ -62,15 +62,21 @@ public: void gateDelay(const Pvt *pvt, float in_slew, float load_cap, - float related_out_cap, bool pocv_enabled, // Return values. ArcDelay &gate_delay, Slew &drvr_slew) const override; + // related_out_cap arg removed. + void gateDelay(const Pvt *pvt, + float in_slew, + float load_cap, + float related_out_cap, + bool pocv_enabled, + ArcDelay &gate_delay, + Slew &drvr_slew) const __attribute__ ((deprecated)); string reportGateDelay(const Pvt *pvt, float in_slew, float load_cap, - float related_out_cap, bool pocv_enabled, int digits) const override; float driveResistance(const Pvt *pvt) const override; @@ -130,13 +136,11 @@ public: TableModel *model, TableModel *sigma_models[EarlyLate::index_count]); virtual ~CheckTableModel(); - void checkDelay(const Pvt *pvt, - float from_slew, - float to_slew, - float related_out_cap, - bool pocv_enabled, - // Return values. - ArcDelay &margin) const override; + ArcDelay checkDelay(const Pvt *pvt, + float from_slew, + float to_slew, + float related_out_cap, + bool pocv_enabled) const override; string reportCheckDelay(const Pvt *pvt, float from_slew, const char *from_slew_annotation, @@ -504,9 +508,6 @@ public: float voltageCurrent(float slew, float cap, float volt); - float currentVoltage(float slew, - float cap, - float current); float referenceTime(float slew); void setVdd(float vdd); static bool checkAxes(const TableTemplate *tbl_template); @@ -536,7 +537,6 @@ private: Table1Seq current_waveforms_; Table1Seq voltage_waveforms_; Table1Seq voltage_currents_; - Table1Seq current_voltages_; FloatTable voltage_times_; Table1 *ref_times_; float vdd_; diff --git a/include/sta/TimingModel.hh b/include/sta/TimingModel.hh index e6b2fd04..6750aa21 100644 --- a/include/sta/TimingModel.hh +++ b/include/sta/TimingModel.hh @@ -46,7 +46,6 @@ public: virtual void gateDelay(const Pvt *pvt, float in_slew, float load_cap, - float related_out_cap, bool pocv_enabled, // Return values. ArcDelay &gate_delay, @@ -54,7 +53,6 @@ public: virtual string reportGateDelay(const Pvt *pvt, float in_slew, float load_cap, - float related_out_cap, bool pocv_enabled, int digits) const = 0; virtual float driveResistance(const Pvt *pvt) const = 0; @@ -66,13 +64,11 @@ class CheckTimingModel : public TimingModel public: CheckTimingModel(LibertyCell *cell); // Timing check margin delay calculation. - virtual void checkDelay(const Pvt *pvt, - float from_slew, - float to_slew, - float related_out_cap, - bool pocv_enabled, - // Return values. - ArcDelay &margin) const = 0; + virtual ArcDelay checkDelay(const Pvt *pvt, + float from_slew, + float to_slew, + float related_out_cap, + bool pocv_enabled) const = 0; virtual string reportCheckDelay(const Pvt *pvt, float from_slew, const char *from_slew_annotation, diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index b9125ab5..6b8be6c0 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -2583,7 +2583,7 @@ LibertyPort::clockTreePathDelays() GateTimingModel *gate_model = dynamic_cast(model); ArcDelay delay; Slew slew; - gate_model->gateDelay(nullptr, 0.0, 0.0, 0.0, false, delay, slew); + gate_model->gateDelay(nullptr, 0.0, 0.0, false, delay, slew); const RiseFall *rf = arc->toEdge()->asRiseFall(); const MinMax *min_max = (role == TimingRole::clockTreePathMin()) ? MinMax::min() diff --git a/liberty/LibertyBuilder.cc b/liberty/LibertyBuilder.cc index 76de519a..c59c013c 100644 --- a/liberty/LibertyBuilder.cc +++ b/liberty/LibertyBuilder.cc @@ -182,17 +182,13 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell, && seq->data()->hasPort(from_port)) // Latch D->Q timing arcs. return makeLatchDtoQArcs(cell, from_port, to_port, - seq->data()->portTimingSense(from_port), - related_out, attrs); + seq->data()->portTimingSense(from_port), attrs); else - return makeCombinationalArcs(cell, from_port, to_port, related_out, - true, true, attrs); + return makeCombinationalArcs(cell, from_port, to_port, true, true, attrs); case TimingType::combinational_fall: - return makeCombinationalArcs(cell, from_port, to_port, related_out, - false, true, attrs); + return makeCombinationalArcs(cell, from_port, to_port, false, true, attrs); case TimingType::combinational_rise: - return makeCombinationalArcs(cell, from_port, to_port, related_out, - true, false, attrs); + return makeCombinationalArcs(cell, from_port, to_port, true, false, attrs); case TimingType::setup_rising: return makeFromTransitionArcs(cell, from_port, to_port, related_out, RiseFall::rise(), TimingRole::setup(), @@ -210,17 +206,13 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell, RiseFall::fall(), TimingRole::hold(), attrs); case TimingType::rising_edge: - return makeRegLatchArcs(cell, from_port, to_port, related_out, - RiseFall::rise(), attrs); + return makeRegLatchArcs(cell, from_port, to_port, RiseFall::rise(), attrs); case TimingType::falling_edge: - return makeRegLatchArcs(cell, from_port, to_port, related_out, - RiseFall::fall(), attrs); + return makeRegLatchArcs(cell, from_port, to_port, RiseFall::fall(), attrs); case TimingType::preset: - return makePresetClrArcs(cell, from_port, to_port, related_out, - RiseFall::rise(), attrs); + return makePresetClrArcs(cell, from_port, to_port, RiseFall::rise(), attrs); case TimingType::clear: - return makePresetClrArcs(cell, from_port, to_port, related_out, - RiseFall::fall(), attrs); + return makePresetClrArcs(cell, from_port, to_port, RiseFall::fall(), attrs); case TimingType::recovery_rising: return makeFromTransitionArcs(cell, from_port, to_port, related_out, RiseFall::rise(),TimingRole::recovery(), @@ -238,23 +230,17 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell, RiseFall::fall(), TimingRole::removal(), attrs); case TimingType::three_state_disable: - return makeTristateDisableArcs(cell, from_port, to_port, related_out, - true, true, attrs); + return makeTristateDisableArcs(cell, from_port, to_port, true, true, attrs); case TimingType::three_state_disable_fall: - return makeTristateDisableArcs(cell, from_port, to_port, related_out, - false, true, attrs); + return makeTristateDisableArcs(cell, from_port, to_port, false, true, attrs); case TimingType::three_state_disable_rise: - return makeTristateDisableArcs(cell, from_port, to_port, related_out, - true, false, attrs); + return makeTristateDisableArcs(cell, from_port, to_port, true, false, attrs); case TimingType::three_state_enable: - return makeTristateEnableArcs(cell, from_port, to_port, related_out, - true, true, attrs); + return makeTristateEnableArcs(cell, from_port, to_port, true, true, attrs); case TimingType::three_state_enable_fall: - return makeTristateEnableArcs(cell, from_port, to_port, related_out, - false, true, attrs); + return makeTristateEnableArcs(cell, from_port, to_port, false, true, attrs); case TimingType::three_state_enable_rise: - return makeTristateEnableArcs(cell, from_port, to_port, related_out, - true, false, attrs); + return makeTristateEnableArcs(cell, from_port, to_port, true, false, attrs); case TimingType::skew_falling: return makeFromTransitionArcs(cell, from_port, to_port, related_out, RiseFall::fall(), TimingRole::skew(), @@ -282,12 +268,10 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell, TimingRole::nonSeqHold(), attrs); case TimingType::min_clock_tree_path: - return makeClockTreePathArcs(cell, to_port, related_out, - TimingRole::clockTreePathMin(), + return makeClockTreePathArcs(cell, to_port, TimingRole::clockTreePathMin(), attrs); case TimingType::max_clock_tree_path: - return makeClockTreePathArcs(cell, to_port, related_out, - TimingRole::clockTreePathMax(), + return makeClockTreePathArcs(cell, to_port, TimingRole::clockTreePathMax(), attrs); case TimingType::min_pulse_width: case TimingType::minimum_period: @@ -307,14 +291,13 @@ TimingArcSet * LibertyBuilder::makeCombinationalArcs(LibertyCell *cell, LibertyPort *from_port, LibertyPort *to_port, - LibertyPort *related_out, bool to_rise, bool to_fall, TimingArcAttrsPtr attrs) { FuncExpr *func = to_port->function(); FuncExpr *enable = to_port->tristateEnable(); - TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port, related_out, + TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port, TimingRole::combinational(), attrs); TimingSense sense = attrs->timingSense(); if (sense == TimingSense::unknown) { @@ -393,11 +376,9 @@ LibertyBuilder::makeLatchDtoQArcs(LibertyCell *cell, LibertyPort *from_port, LibertyPort *to_port, TimingSense sense, - LibertyPort *related_out, TimingArcAttrsPtr attrs) { TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port, - related_out, TimingRole::latchDtoQ(), attrs); TimingModel *model; RiseFall *to_rf = RiseFall::rise(); @@ -421,7 +402,6 @@ TimingArcSet * LibertyBuilder::makeRegLatchArcs(LibertyCell *cell, LibertyPort *from_port, LibertyPort *to_port, - LibertyPort *related_out, RiseFall *from_rf, TimingArcAttrsPtr attrs) { @@ -434,24 +414,24 @@ LibertyBuilder::makeRegLatchArcs(LibertyCell *cell, if (seq->clock() && seq->clock()->hasPort(from_port)) { TimingRole *role = seq->isRegister() ? TimingRole::regClkToQ() : TimingRole::latchEnToQ(); - return makeFromTransitionArcs(cell, from_port, to_port, related_out, - from_rf, role, attrs); + return makeFromTransitionArcs(cell, from_port, to_port, nullptr, + from_rf, role, attrs); } else if (seq->isLatch() && seq->data() && seq->data()->hasPort(from_port)) - return makeFromTransitionArcs(cell, from_port, to_port, related_out, - from_rf, TimingRole::latchDtoQ(), attrs); + return makeFromTransitionArcs(cell, from_port, to_port, nullptr, + from_rf, TimingRole::latchDtoQ(), attrs); else if ((seq->clear() && seq->clear()->hasPort(from_port)) || (seq->preset() && seq->preset()->hasPort(from_port))) - return makeFromTransitionArcs(cell, from_port, to_port, related_out, - from_rf, TimingRole::regSetClr(), attrs); + return makeFromTransitionArcs(cell, from_port, to_port, nullptr, + from_rf, TimingRole::regSetClr(), attrs); } } // No associated ff/latch - assume register clk->q. cell->setHasInferedRegTimingArcs(true); - return makeFromTransitionArcs(cell, from_port, to_port, related_out, - from_rf, TimingRole::regClkToQ(), attrs); + return makeFromTransitionArcs(cell, from_port, to_port, nullptr, + from_rf, TimingRole::regClkToQ(), attrs); } TimingArcSet * @@ -477,14 +457,13 @@ TimingArcSet * LibertyBuilder::makePresetClrArcs(LibertyCell *cell, LibertyPort *from_port, LibertyPort *to_port, - LibertyPort *related_out, RiseFall *to_rf, TimingArcAttrsPtr attrs) { TimingArcSet *arc_set = nullptr; TimingModel *model = attrs->model(to_rf); if (model) { - arc_set = makeTimingArcSet(cell, from_port, to_port, related_out, + arc_set = makeTimingArcSet(cell, from_port, to_port, TimingRole::regSetClr(), attrs); RiseFall *opp_rf = to_rf->opposite(); switch (attrs->timingSense()) { @@ -513,12 +492,11 @@ TimingArcSet * LibertyBuilder::makeTristateEnableArcs(LibertyCell *cell, LibertyPort *from_port, LibertyPort *to_port, - LibertyPort *related_out, bool to_rise, bool to_fall, TimingArcAttrsPtr attrs) { - TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port, related_out, + TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port, TimingRole::tristateEnable(), attrs); FuncExpr *tristate_enable = to_port->tristateEnable(); TimingSense sense = attrs->timingSense(); @@ -584,13 +562,11 @@ TimingArcSet * LibertyBuilder::makeTristateDisableArcs(LibertyCell *cell, LibertyPort *from_port, LibertyPort *to_port, - LibertyPort *related_out, bool to_rise, bool to_fall, TimingArcAttrsPtr attrs) { TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port, - related_out, TimingRole::tristateDisable(), attrs); TimingSense sense = attrs->timingSense(); @@ -656,12 +632,10 @@ LibertyBuilder::makeTristateDisableArcs(LibertyCell *cell, 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); + TimingArcSet *arc_set = makeTimingArcSet(cell, nullptr, to_port, role, attrs); for (auto to_rf : RiseFall::range()) { TimingModel *model = attrs->model(to_rf); if (model) @@ -670,6 +644,16 @@ LibertyBuilder::makeClockTreePathArcs(LibertyCell *cell, return arc_set; } +TimingArcSet * +LibertyBuilder::makeTimingArcSet(LibertyCell *cell, + LibertyPort *from, + LibertyPort *to, + TimingRole *role, + TimingArcAttrsPtr attrs) +{ + return new TimingArcSet(cell, from, to, nullptr, role, attrs); +} + TimingArcSet * LibertyBuilder::makeTimingArcSet(LibertyCell *cell, LibertyPort *from, diff --git a/liberty/LibertyBuilder.hh b/liberty/LibertyBuilder.hh index f6b64b86..87e291b8 100644 --- a/liberty/LibertyBuilder.hh +++ b/liberty/LibertyBuilder.hh @@ -75,13 +75,11 @@ public: TimingArcSet *makeCombinationalArcs(LibertyCell *cell, LibertyPort *from_port, LibertyPort *to_port, - LibertyPort *related_out, bool to_rise, bool to_fall, TimingArcAttrsPtr attrs); TimingArcSet *makeClockTreePathArcs(LibertyCell *cell, LibertyPort *to_port, - LibertyPort *related_out, TimingRole *role, TimingArcAttrsPtr attrs); @@ -105,6 +103,11 @@ protected: ConcretePort *bus_port, const char *bus_name, int index); + virtual TimingArcSet *makeTimingArcSet(LibertyCell *cell, + LibertyPort *from, + LibertyPort *to, + TimingRole *role, + TimingArcAttrsPtr attrs); virtual TimingArcSet *makeTimingArcSet(LibertyCell *cell, LibertyPort *from, LibertyPort *to, @@ -123,31 +126,26 @@ protected: LibertyPort *from_port, LibertyPort *to_port, TimingSense sense, - LibertyPort *related_out, TimingArcAttrsPtr attrs); TimingArcSet *makeRegLatchArcs(LibertyCell *cell, LibertyPort *from_port, LibertyPort *to_port, - LibertyPort *related_out, RiseFall *from_rf, TimingArcAttrsPtr attrs); TimingArcSet *makePresetClrArcs(LibertyCell *cell, LibertyPort *from_port, LibertyPort *to_port, - LibertyPort *related_out, RiseFall *to_rf, TimingArcAttrsPtr attrs); TimingArcSet *makeTristateEnableArcs(LibertyCell *cell, LibertyPort *from_port, LibertyPort *to_port, - LibertyPort *related_out, bool to_rise, bool to_fall, TimingArcAttrsPtr attrs); TimingArcSet *makeTristateDisableArcs(LibertyCell *cell, LibertyPort *from_port, LibertyPort *to_port, - LibertyPort *related_out, bool to_rise, bool to_fall, TimingArcAttrsPtr attrs); diff --git a/liberty/LinearModel.cc b/liberty/LinearModel.cc index 1ba8ff8b..cba74116 100644 --- a/liberty/LinearModel.cc +++ b/liberty/LinearModel.cc @@ -34,7 +34,6 @@ void GateLinearModel::gateDelay(const Pvt *, float, float load_cap, - float, bool, // return values ArcDelay &gate_delay, @@ -48,7 +47,6 @@ string GateLinearModel::reportGateDelay(const Pvt *, float, float load_cap, - float, bool, int digits) const { @@ -87,15 +85,14 @@ CheckLinearModel::CheckLinearModel(LibertyCell *cell, { } -void +ArcDelay CheckLinearModel::checkDelay(const Pvt *, float, float, float, - bool, - ArcDelay &margin) const + bool) const { - margin = intrinsic_; + return intrinsic_; } string diff --git a/liberty/TableModel.cc b/liberty/TableModel.cc index ff9753dd..51df5ac1 100644 --- a/liberty/TableModel.cc +++ b/liberty/TableModel.cc @@ -104,67 +104,77 @@ void GateTableModel::gateDelay(const Pvt *pvt, float in_slew, float load_cap, - float related_out_cap, bool pocv_enabled, // return values ArcDelay &gate_delay, Slew &drvr_slew) const { - float delay = findValue(pvt, delay_model_, in_slew, load_cap, related_out_cap); + float delay = findValue(pvt, delay_model_, in_slew, load_cap, 0.0); float sigma_early = 0.0; float sigma_late = 0.0; if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()]) sigma_early = findValue(pvt, delay_sigma_models_[EarlyLate::earlyIndex()], - in_slew, load_cap, related_out_cap); + in_slew, load_cap, 0.0); if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()]) sigma_late = findValue(pvt, delay_sigma_models_[EarlyLate::lateIndex()], - in_slew, load_cap, related_out_cap); + in_slew, load_cap, 0.0); gate_delay = makeDelay(delay, sigma_early, sigma_late); - float slew = findValue(pvt, slew_model_, in_slew, load_cap, related_out_cap); + float slew = findValue(pvt, slew_model_, in_slew, load_cap, 0.0); if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()]) sigma_early = findValue(pvt, slew_sigma_models_[EarlyLate::earlyIndex()], - in_slew, load_cap, related_out_cap); + in_slew, load_cap, 0.0); if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()]) sigma_late = findValue(pvt, slew_sigma_models_[EarlyLate::lateIndex()], - in_slew, load_cap, related_out_cap); + in_slew, load_cap, 0.0); // Clip negative slews to zero. if (slew < 0.0) slew = 0.0; drvr_slew = makeDelay(slew, sigma_early, sigma_late); } +void +GateTableModel::gateDelay(const Pvt *pvt, + float in_slew, + float load_cap, + float, + bool pocv_enabled, + ArcDelay &gate_delay, + Slew &drvr_slew) const +{ + gateDelay(pvt, in_slew, load_cap, pocv_enabled, gate_delay, drvr_slew); +} + string GateTableModel::reportGateDelay(const Pvt *pvt, float in_slew, float load_cap, - float related_out_cap, bool pocv_enabled, int digits) const { string result = reportPvt(cell_, pvt, digits); result += reportTableLookup("Delay", pvt, delay_model_, in_slew, - load_cap, related_out_cap, digits); + load_cap, 0.0, digits); if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()]) result += reportTableLookup("Delay sigma(early)", pvt, delay_sigma_models_[EarlyLate::earlyIndex()], - in_slew, load_cap, related_out_cap, digits); + in_slew, load_cap, 0.0, digits); if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()]) result += reportTableLookup("Delay sigma(late)", pvt, delay_sigma_models_[EarlyLate::lateIndex()], - in_slew, load_cap, related_out_cap, digits); + in_slew, load_cap, 0.0, digits); result += '\n'; result += reportTableLookup("Slew", pvt, slew_model_, in_slew, - load_cap, related_out_cap, digits); + load_cap, 9.0, digits); if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()]) result += reportTableLookup("Slew sigma(early)", pvt, slew_sigma_models_[EarlyLate::earlyIndex()], - in_slew, load_cap, related_out_cap, digits); + in_slew, load_cap, 0.0, digits); if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()]) result += reportTableLookup("Slew sigma(late)", pvt, slew_sigma_models_[EarlyLate::lateIndex()], - in_slew, load_cap, related_out_cap, digits); - float drvr_slew = findValue(pvt, slew_model_, in_slew, load_cap, related_out_cap); + in_slew, load_cap, 0.0, digits); + float drvr_slew = findValue(pvt, slew_model_, in_slew, load_cap, 0.0); if (drvr_slew < 0.0) result += "Negative slew clipped to 0.0\n"; return result; @@ -407,14 +417,12 @@ CheckTableModel::setIsScaled(bool is_scaled) model_->setIsScaled(is_scaled); } -void +ArcDelay CheckTableModel::checkDelay(const Pvt *pvt, float from_slew, float to_slew, float related_out_cap, - bool pocv_enabled, - // Return values. - ArcDelay &margin) const + bool pocv_enabled) const { if (model_) { float mean = findValue(pvt, model_, from_slew, to_slew, related_out_cap); @@ -426,10 +434,10 @@ CheckTableModel::checkDelay(const Pvt *pvt, if (pocv_enabled && sigma_models_[EarlyLate::lateIndex()]) sigma_late = findValue(pvt, sigma_models_[EarlyLate::lateIndex()], from_slew, to_slew, related_out_cap); - margin = makeDelay(mean, sigma_early, sigma_late); + return makeDelay(mean, sigma_early, sigma_late); } else - margin = 0.0; + return 0.0; } float @@ -1577,7 +1585,6 @@ OutputWaveforms::~OutputWaveforms() current_waveforms_.deleteContents(); voltage_waveforms_.deleteContents(); voltage_currents_.deleteContents(); - current_voltages_.deleteContents(); voltage_times_.deleteContents(); delete ref_times_; } @@ -1635,15 +1642,6 @@ OutputWaveforms::voltageCurrent(float slew, return waveformValue(slew, cap, volt, voltage_currents_); } -float -OutputWaveforms::currentVoltage(float slew, - float cap, - float current) -{ - ensureVoltages(); - return waveformValue(slew, cap, current, current_voltages_); -} - float OutputWaveforms::waveformValue(float slew, float cap, @@ -1809,7 +1807,6 @@ OutputWaveforms::ensureVoltages() size_t size = current_waveforms_.size(); voltage_waveforms_.resize(size); voltage_currents_.resize(size); - current_voltages_.resize(size); voltage_times_.resize(size); size_t cap_count = cap_axis_->size(); for (size_t slew_index = 0; slew_index < slew_axis_->size(); slew_index++) { @@ -1858,14 +1855,6 @@ OutputWaveforms::findVoltages(size_t wave_index, Table1 *volt_currents = new Table1(currents1, volt_axis); voltage_currents_[wave_index] = volt_currents; - // Make current -> voltage table. - FloatSeq *axis_currents = new FloatSeq(*currents->values()); - TableAxisPtr current_axis = - make_shared(TableAxisVariable::input_voltage, axis_currents); - FloatSeq *volts1 = new FloatSeq(*volts); - Table1 *current_volts = new Table1(volts1, current_axis); - current_voltages_[wave_index] = current_volts; - // Sample the voltage waveform at uniform intervals to speed up // voltage time lookup. FloatSeq *voltage_times = new FloatSeq; diff --git a/liberty/TimingArc.cc b/liberty/TimingArc.cc index 0f1532e3..cf9a7b74 100644 --- a/liberty/TimingArc.cc +++ b/liberty/TimingArc.cc @@ -162,7 +162,7 @@ TimingArc::intrinsicDelay() const if (model) { ArcDelay arc_delay; Slew slew; - model->gateDelay(nullptr, 0.0, 0.0, 0.0, false, arc_delay, slew); + model->gateDelay(nullptr, 0.0, 0.0, false, arc_delay, slew); return arc_delay; } else diff --git a/search/MakeTimingModel.cc b/search/MakeTimingModel.cc index b45d116b..ddda57a2 100644 --- a/search/MakeTimingModel.cc +++ b/search/MakeTimingModel.cc @@ -446,8 +446,7 @@ MakeTimingModel::makeInputOutputTimingArcs(const Pin *input_pin, LibertyPort *output_port = modelPort(output_pin); LibertyPort *input_port = modelPort(input_pin); attrs->setTimingSense(output_delays.timingSense()); - lib_builder_->makeCombinationalArcs(cell_, input_port, - output_port, nullptr, + lib_builder_->makeCombinationalArcs(cell_, input_port, output_port, true, true, attrs); } } @@ -552,8 +551,7 @@ MakeTimingModel::findClkInsertionDelays() TimingRole *role = (min_max == MinMax::min()) ? TimingRole::clockTreePathMin() : TimingRole::clockTreePathMax(); - lib_builder_->makeClockTreePathArcs(cell_, lib_port, nullptr, - role, attrs); + lib_builder_->makeClockTreePathArcs(cell_, lib_port, role, attrs); } } } @@ -655,7 +653,7 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin, float output_load_cap = graph_delay_calc_->loadCap(output_pin, dcalc_ap); ArcDelay drvr_self_delay; Slew drvr_self_slew; - drvr_gate_model->gateDelay(pvt, in_slew1, output_load_cap, 0.0, false, + drvr_gate_model->gateDelay(pvt, in_slew1, output_load_cap, false, drvr_self_delay, drvr_self_slew); const TableModel *drvr_table = drvr_gate_model->delayModel(); @@ -670,7 +668,7 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin, // get slew from driver input pin ArcDelay gate_delay; Slew gate_slew; - drvr_gate_model->gateDelay(pvt, in_slew1, load_cap, 0.0, false, + drvr_gate_model->gateDelay(pvt, in_slew1, load_cap, false, gate_delay, gate_slew); // Remove the self delay driving the output pin net load cap. load_values->push_back(delayAsFloat(delay + gate_delay