From 31369dd750befe1305e49eebb26c0d0fac032e21 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Sun, 19 Nov 2023 10:04:45 -0700 Subject: [PATCH] DelayCalc reorg commit 410ed56c2c2d0d7afb0e84d0c65d5ff75234e9e3 Author: James Cherry Date: Sun Nov 19 08:44:13 2023 -0700 ArcDelayCalcBase -> DelayCalcBase Signed-off-by: James Cherry commit 1fdfebe2838c47f6c1866c8a10b14df6439506e0 Author: James Cherry Date: Sun Nov 19 08:25:36 2023 -0700 LumpedCapDelayCalc::inputPortDelay Signed-off-by: James Cherry commit 3a5e1d01aaff240b2f71d006d620ccd6a70bce6d Author: James Cherry Date: Fri Nov 17 16:32:32 2023 -0700 gateDelayInit cleanup Signed-off-by: James Cherry commit d0133319126ae4a488a7b31679fbf6507c7f6266 Author: James Cherry Date: Fri Nov 17 15:36:12 2023 -0700 mv RCDelayCalc to ArcDelayCalcBase Signed-off-by: James Cherry commit fd028e6ba5e092243a84685eb1756a8e4e4bad76 Author: James Cherry Date: Fri Nov 17 14:32:53 2023 -0700 ArcDelayCalcBase Signed-off-by: James Cherry commit 0ce9cf4c766f7419b998b40aed5af14df97249f1 Author: James Cherry Date: Fri Nov 17 10:57:41 2023 -0700 ParallelArcDelayCalc -> ParallelDelayCalc Signed-off-by: James Cherry commit 7fa7db6b252f1450fa5b546f5d33d8cb8a94d4bb Author: James Cherry Date: Fri Nov 17 08:45:01 2023 -0700 parallelGateDelay args Signed-off-by: James Cherry commit 6b85756774ce049c0f5f123f6d60ebbcd62cdd2b Author: James Cherry Date: Thu Nov 16 19:55:20 2023 -0700 TimingModel cell_ Signed-off-by: James Cherry commit e536d6b0ca0d01e2ad8bd609ad20f9a02497d8f5 Author: James Cherry Date: Thu Nov 16 18:07:11 2023 -0700 TimingModel cell_ Signed-off-by: James Cherry commit d2d622da4206e06d176e4ae741334fde8df35007 Author: James Cherry Date: Thu Nov 16 17:21:15 2023 -0700 rm drvr_cell from arc dcalc funcs Signed-off-by: James Cherry commit 522961e8f58bc1a0f0530a0a5218086280a2bcb0 Author: James Cherry Date: Thu Nov 16 16:24:34 2023 -0700 tr -> rf Signed-off-by: James Cherry commit 29aa0ed40345611b9e3a898342ecc17f6355396f Author: James Cherry Date: Thu Nov 16 13:17:44 2023 -0700 GraphDelayCalc Signed-off-by: James Cherry commit 934d9f19c52c62925b23ae9b457f14d25e818f1a Author: James Cherry Date: Thu Nov 16 12:52:55 2023 -0700 ParallelArcDelayCalc Signed-off-by: James Cherry commit d5687d9482ad0f572b017f0ef806ba8e6ff8b6fa Author: James Cherry Date: Thu Nov 16 12:16:05 2023 -0700 ParallelArcDelayCalc pvt Signed-off-by: James Cherry commit 0de501e5bf2329364b572d1360c18d5aedf3b841 Author: James Cherry Date: Thu Nov 16 10:46:22 2023 -0700 ParallelArcDelayCalc::findMultiDrvrGateDelay Signed-off-by: James Cherry commit d7457b9e335ed5fa583798e0512914aab6524fcc Author: James Cherry Date: Thu Nov 16 10:19:01 2023 -0700 mv multi_drvr_slew_factor_ to ParallelArcDelayCalc Signed-off-by: James Cherry commit afec4daa2ab6dd61a2450f1ac8a8cad1ef015a29 Author: James Cherry Date: Thu Nov 16 08:02:40 2023 -0700 MultiDrvrNet::net_caps vector Signed-off-by: James Cherry commit b450b3a35616ffc8d85610158a91c5d9483b6958 Author: James Cherry Date: Thu Nov 16 07:46:43 2023 -0700 sic Signed-off-by: James Cherry commit 65767403b3b2ab4e6f7552625accf9aa4766628a Author: James Cherry Date: Tue Nov 14 17:49:22 2023 -0700 Sta::connectedCap simplify Signed-off-by: James Cherry commit 85bdb8f3362413e7b05f49447a0383140cbb924f Author: James Cherry Date: Tue Nov 14 16:43:38 2023 -0700 ParallelArcDelayCalc Signed-off-by: James Cherry commit 4feea3ba2277d53697b644d79832e309ce98058a Author: James Cherry Date: Tue Nov 14 15:10:18 2023 -0700 mv parallel dcalc to arc delay calc Signed-off-by: James Cherry commit 915ed28a2c05acce6569c7933366ef94da8bfaeb Author: James Cherry Date: Mon Nov 13 17:47:14 2023 -0700 rm MultiDrvrNet::delays_valid_ Signed-off-by: James Cherry commit 2384eb4e5bdca1410c4bf5e23f35bfb49f013e74 Author: James Cherry Date: Mon Nov 13 16:02:57 2023 -0700 mkae MultiDrvrNets on the fly Signed-off-by: James Cherry Signed-off-by: James Cherry --- CMakeLists.txt | 4 +- dcalc/ArnoldiDelayCalc.cc | 51 +- dcalc/DelayCalcBase.cc | 132 +++++ dcalc/{RCDelayCalc.hh => DelayCalcBase.hh} | 26 +- dcalc/DmpCeff.cc | 40 +- dcalc/DmpCeff.hh | 13 +- dcalc/DmpDelayCalc.cc | 52 +- dcalc/GraphDelayCalc.cc | 641 ++++++--------------- dcalc/LumpedCapDelayCalc.cc | 112 +--- dcalc/LumpedCapDelayCalc.hh | 42 +- dcalc/ParallelDelayCalc.cc | 171 ++++++ dcalc/ParallelDelayCalc.hh | 68 +++ dcalc/RCDelayCalc.cc | 74 --- dcalc/SlewDegradeDelayCalc.cc | 65 +-- dcalc/SlewDegradeDelayCalc.hh | 5 +- dcalc/UnitDelayCalc.cc | 38 +- dcalc/UnitDelayCalc.hh | 30 +- graph/Graph.cc | 6 +- include/sta/ArcDelayCalc.hh | 52 +- include/sta/Graph.hh | 7 +- include/sta/GraphDelayCalc.hh | 99 ++-- include/sta/Liberty.hh | 12 +- include/sta/LinearModel.hh | 22 +- include/sta/Sdc.hh | 3 +- include/sta/TableModel.hh | 51 +- include/sta/TimingModel.hh | 23 +- liberty/InternalPower.cc | 8 +- liberty/Liberty.cc | 71 ++- liberty/LibertyReader.cc | 30 +- liberty/LibertyReaderPvt.hh | 7 +- liberty/LinearModel.cc | 27 +- liberty/TableModel.cc | 187 +++--- liberty/TimingArc.cc | 10 +- liberty/TimingModel.cc | 31 + sdc/Sdc.cc | 2 +- search/MakeTimingModel.cc | 15 +- search/Sta.cc | 13 +- 37 files changed, 1070 insertions(+), 1170 deletions(-) create mode 100644 dcalc/DelayCalcBase.cc rename dcalc/{RCDelayCalc.hh => DelayCalcBase.hh} (58%) create mode 100644 dcalc/ParallelDelayCalc.cc create mode 100644 dcalc/ParallelDelayCalc.hh delete mode 100644 dcalc/RCDelayCalc.cc create mode 100644 liberty/TimingModel.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c2f1615..25573174 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,12 +66,13 @@ set(STA_SOURCE dcalc/ArnoldiReduce.cc dcalc/DcalcAnalysisPt.cc dcalc/DelayCalc.cc + dcalc/DelayCalcBase.cc dcalc/DmpCeff.cc dcalc/DmpDelayCalc.cc dcalc/GraphDelayCalc.cc dcalc/LumpedCapDelayCalc.cc dcalc/NetCaps.cc - dcalc/RCDelayCalc.cc + dcalc/ParallelDelayCalc.cc dcalc/SlewDegradeDelayCalc.cc dcalc/UnitDelayCalc.cc @@ -96,6 +97,7 @@ set(STA_SOURCE liberty/Sequential.cc liberty/TableModel.cc liberty/TimingArc.cc + liberty/TimingModel.cc liberty/TimingRole.cc liberty/Units.cc liberty/Wireload.cc diff --git a/dcalc/ArnoldiDelayCalc.cc b/dcalc/ArnoldiDelayCalc.cc index b3205010..15610b41 100644 --- a/dcalc/ArnoldiDelayCalc.cc +++ b/dcalc/ArnoldiDelayCalc.cc @@ -37,7 +37,7 @@ #include "DcalcAnalysisPt.hh" #include "DelayCalc.hh" #include "ArcDelayCalc.hh" -#include "RCDelayCalc.hh" +#include "LumpedCapDelayCalc.hh" #include "GraphDelayCalc.hh" #include "Arnoldi.hh" #include "ArnoldiReduce.hh" @@ -108,7 +108,7 @@ struct delay_work //////////////////////////////////////////////////////////////// -class ArnoldiDelayCalc : public RCDelayCalc +class ArnoldiDelayCalc : public LumpedCapDelayCalc { public: ArnoldiDelayCalc(StaState *sta); @@ -123,8 +123,7 @@ public: const RiseFall *rf, const Parasitic *parasitic, const DcalcAnalysisPt *dcalc_ap) override; - void gateDelay(const LibertyCell *drvr_cell, - const TimingArc *arc, + void gateDelay(const TimingArc *arc, const Slew &in_slew, float load_cap, const Parasitic *drvr_parasitic, @@ -138,8 +137,7 @@ public: // Return values. ArcDelay &wire_delay, Slew &load_slew) override; - string reportGateDelay(const LibertyCell *drvr_cell, - const TimingArc *arc, + string reportGateDelay(const TimingArc *arc, const Slew &in_slew, float load_cap, const Parasitic *drvr_parasitic, @@ -238,7 +236,7 @@ makeArnoldiDelayCalc(StaState *sta) } ArnoldiDelayCalc::ArnoldiDelayCalc(StaState *sta) : - RCDelayCalc(sta), + LumpedCapDelayCalc(sta), reduce_(new ArnoldiReduce(sta)), delay_work_(delay_work_create()) { @@ -321,7 +319,7 @@ ArnoldiDelayCalc::inputPortDelay(const Pin *drvr_pin, const Parasitic *parasitic, const DcalcAnalysisPt *dcalc_ap) { - RCDelayCalc::inputPortDelay(drvr_pin, in_slew, rf, parasitic, dcalc_ap); + LumpedCapDelayCalc::inputPortDelay(drvr_pin, in_slew, rf, parasitic, dcalc_ap); rcmodel_ = nullptr; _delayV[0] = 0.0; _slewV[0] = in_slew; @@ -358,8 +356,7 @@ ArnoldiDelayCalc::inputPortDelay(const Pin *drvr_pin, } void -ArnoldiDelayCalc::gateDelay(const LibertyCell *drvr_cell, - const TimingArc *arc, +ArnoldiDelayCalc::gateDelay(const TimingArc *arc, const Slew &in_slew, float load_cap, const Parasitic *drvr_parasitic, @@ -372,6 +369,7 @@ ArnoldiDelayCalc::gateDelay(const LibertyCell *drvr_cell, { 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 = @@ -384,9 +382,9 @@ ArnoldiDelayCalc::gateDelay(const LibertyCell *drvr_cell, related_out_cap, pvt, gate_delay, drvr_slew); else - LumpedCapDelayCalc::gateDelay(drvr_cell, arc, in_slew, load_cap, - drvr_parasitic, related_out_cap, pvt, - dcalc_ap, gate_delay, drvr_slew); + 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; } @@ -455,8 +453,7 @@ ArnoldiDelayCalc::loadDelay(const Pin *load_pin, } string -ArnoldiDelayCalc::reportGateDelay(const LibertyCell *, - const TimingArc *, +ArnoldiDelayCalc::reportGateDelay(const TimingArc *, const Slew &, float, const Parasitic *, @@ -1313,9 +1310,7 @@ ArnoldiDelayCalc::ra_get_r(delay_work *D, c1 = ctot; ArcDelay d1; Slew s1; - tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, - c1, tab->relcap, pocv_enabled_, - d1, s1); + tab->table->gateDelay(tab->pvt, tab->in_slew, c1, tab->relcap, pocv_enabled_, d1, s1); tlohi = slew_derate*delayAsFloat(s1); r = tlohi/(c_log*c1); if (rdelay>0.0 && r > rdelay) @@ -1337,8 +1332,7 @@ ArnoldiDelayCalc::ra_get_s(delay_work *D, double tlohi,smin,s; ArcDelay d1; Slew s1; - tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, - c, tab->relcap, pocv_enabled_, d1, s1); + tab->table->gateDelay(tab->pvt, tab->in_slew, c, tab->relcap, 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) { @@ -1371,10 +1365,8 @@ ArnoldiDelayCalc::ra_rdelay_1(timing_table *tab, return 0.0; ArcDelay d1, d2; Slew s1, s2; - tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, - c1, tab->relcap, pocv_enabled_, d1, s1); - tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, - c2, tab->relcap, pocv_enabled_, d2, 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); double dt50 = delayAsFloat(d1)-delayAsFloat(d2); if (dt50 <= 0.0) return 0.0; @@ -1426,8 +1418,8 @@ 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->cell, tab->pvt,tab->in_slew, - ctot, tab->relcap, pocv_enabled_, df, sf); + tab->table->gateDelay(tab->pvt,tab->in_slew, ctot, tab->relcap, 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), @@ -1438,8 +1430,8 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D, units_->timeUnit()->asString(tlox-thix)); } ceff = ctot; - tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, - ceff, tab->relcap, pocv_enabled_, df, sf); + tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, tab->relcap, pocv_enabled_, + df, sf); t50_sy = delayAsFloat(df); t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5); @@ -1480,8 +1472,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D, units_->timeUnit()->asString(ceff_time), units_->capacitanceUnit()->asString(ceff)); - tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, ceff, - tab->relcap, pocv_enabled_, df, sf); + tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, tab->relcap, 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/DelayCalcBase.cc b/dcalc/DelayCalcBase.cc new file mode 100644 index 00000000..c2639664 --- /dev/null +++ b/dcalc/DelayCalcBase.cc @@ -0,0 +1,132 @@ +// 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 "DelayCalcBase.hh" + +#include "Liberty.hh" +#include "TimingArc.hh" +#include "Network.hh" +#include "Parasitics.hh" + +namespace sta { + +DelayCalcBase::DelayCalcBase(StaState *sta) : + ArcDelayCalc(sta) +{ +} + +void +DelayCalcBase::finishDrvrPin() +{ + for (auto parasitic : unsaved_parasitics_) + parasitics_->deleteUnsavedParasitic(parasitic); + unsaved_parasitics_.clear(); + for (auto drvr_pin : reduced_parasitic_drvrs_) + parasitics_->deleteDrvrReducedParasitics(drvr_pin); + 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 *, + 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(); + wire_delay = -elmore * log(1.0 - vth); + load_slew = drvr_slew_ + elmore * log((1.0 - vl) / (1.0 - vh)) / slew_derate; +} + +void +DelayCalcBase::thresholdAdjust(const Pin *load_pin, + 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_); + float load_delay_delta = + delayAsFloat(load_slew) * ((load_vth - drvr_vth) / drvr_slew_delta); + load_delay += (drvr_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_derate = load_library->slewDerateFromLibrary(); + load_slew = load_slew * ((load_slew_delta / load_slew_derate) + / (drvr_slew_delta / drvr_slew_derate)); + } +} + +LibertyLibrary * +DelayCalcBase::thresholdLibrary(const Pin *load_pin) +{ + if (network_->isTopLevelPort(load_pin)) + // Input/output slews use the default (first read) library + // for slew thresholds. + return network_->defaultLibertyLibrary(); + else { + LibertyPort *lib_port = network_->libertyPort(load_pin); + if (lib_port) + return lib_port->libertyCell()->libertyLibrary(); + else + return network_->defaultLibertyLibrary(); + } +} + +} // namespace diff --git a/dcalc/RCDelayCalc.hh b/dcalc/DelayCalcBase.hh similarity index 58% rename from dcalc/RCDelayCalc.hh rename to dcalc/DelayCalcBase.hh index 24530959..248e8e5a 100644 --- a/dcalc/RCDelayCalc.hh +++ b/dcalc/DelayCalcBase.hh @@ -16,32 +16,48 @@ #pragma once -#include "LumpedCapDelayCalc.hh" +#include "ArcDelayCalc.hh" namespace sta { -// Base class for delay calculators with RC wire delay. -class RCDelayCalc : public LumpedCapDelayCalc +class DelayCalcBase : public ArcDelayCalc { public: - RCDelayCalc(StaState *sta); - ArcDelayCalc *copy() override; + explicit DelayCalcBase(StaState *sta); void inputPortDelay(const Pin *port_pin, float in_slew, const RiseFall *rf, const Parasitic *parasitic, const DcalcAnalysisPt *dcalc_ap) override; + void finishDrvrPin() override; protected: + void gateDelayInit(const TimingArc *arc, + const Slew &in_slew, + const Parasitic *drvr_parasitic); + // 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, + ArcDelay &load_delay, + Slew &load_slew); // Helper function for input ports driving dspf parasitic. void dspfWireDelaySlew(const Pin *load_pin, float elmore, ArcDelay &wire_delay, Slew &load_slew); + 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. + Vector unsaved_parasitics_; + Vector reduced_parasitic_drvrs_; }; } // namespace diff --git a/dcalc/DmpCeff.cc b/dcalc/DmpCeff.cc index 7ebdf5a6..0d298a78 100644 --- a/dcalc/DmpCeff.cc +++ b/dcalc/DmpCeff.cc @@ -381,7 +381,7 @@ DmpAlg::gateCapDelaySlew(double ceff, { ArcDelay model_delay; Slew model_slew; - gate_model_->gateDelay(drvr_cell_, pvt_, in_slew_, ceff, related_out_cap_, + gate_model_->gateDelay(pvt_, in_slew_, ceff, related_out_cap_, pocv_enabled_, model_delay, model_slew); delay = delayAsFloat(model_delay); slew = delayAsFloat(model_slew); @@ -1528,7 +1528,7 @@ testLuDecomp2() bool DmpCeffDelayCalc::unsuppored_model_warned_ = false; DmpCeffDelayCalc::DmpCeffDelayCalc(StaState *sta) : - RCDelayCalc(sta), + LumpedCapDelayCalc(sta), dmp_cap_(new DmpCap(sta)), dmp_pi_(new DmpPi(sta)), dmp_zero_c2_(new DmpZeroC2(sta)), @@ -1551,12 +1551,11 @@ DmpCeffDelayCalc::inputPortDelay(const Pin *port_pin, const DcalcAnalysisPt *dcalc_ap) { dmp_alg_ = nullptr; - RCDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap); + LumpedCapDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap); } void -DmpCeffDelayCalc::gateDelay(const LibertyCell *drvr_cell, - const TimingArc *arc, +DmpCeffDelayCalc::gateDelay(const TimingArc *arc, const Slew &in_slew, float load_cap, const Parasitic *drvr_parasitic, @@ -1569,8 +1568,10 @@ DmpCeffDelayCalc::gateDelay(const LibertyCell *drvr_cell, { input_port_ = false; drvr_rf_ = arc->toEdge()->asRiseFall(); + const LibertyCell *drvr_cell = arc->from()->libertyCell(); drvr_library_ = drvr_cell->libertyLibrary(); drvr_parasitic_ = drvr_parasitic; + GateTimingModel *model = gateModel(arc, dcalc_ap); GateTableModel *table_model = dynamic_cast(model); if (table_model && drvr_parasitic) { @@ -1588,9 +1589,9 @@ DmpCeffDelayCalc::gateDelay(const LibertyCell *drvr_cell, drvr_slew = dmp_drvr_slew; } else { - LumpedCapDelayCalc::gateDelay(drvr_cell, arc, in_slew, load_cap, - drvr_parasitic, related_out_cap, pvt, - dcalc_ap, gate_delay, drvr_slew); + LumpedCapDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic, + related_out_cap, pvt, dcalc_ap, + gate_delay, drvr_slew); if (drvr_parasitic && !unsuppored_model_warned_) { unsuppored_model_warned_ = true; @@ -1646,8 +1647,7 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library, } float -DmpCeffDelayCalc::ceff(const LibertyCell *drvr_cell, - const TimingArc *arc, +DmpCeffDelayCalc::ceff(const TimingArc *arc, const Slew &in_slew, float load_cap, const Parasitic *drvr_parasitic, @@ -1657,8 +1657,7 @@ DmpCeffDelayCalc::ceff(const LibertyCell *drvr_cell, { ArcDelay gate_delay; Slew drvr_slew; - gateDelay(drvr_cell, arc, in_slew, load_cap, - drvr_parasitic, related_out_cap, pvt, dcalc_ap, + 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(); @@ -1667,8 +1666,7 @@ DmpCeffDelayCalc::ceff(const LibertyCell *drvr_cell, } string -DmpCeffDelayCalc::reportGateDelay(const LibertyCell *drvr_cell, - const TimingArc *arc, +DmpCeffDelayCalc::reportGateDelay(const TimingArc *arc, const Slew &in_slew, float load_cap, const Parasitic *drvr_parasitic, @@ -1679,14 +1677,14 @@ DmpCeffDelayCalc::reportGateDelay(const LibertyCell *drvr_cell, { ArcDelay gate_delay; Slew drvr_slew; - gateDelay(drvr_cell, arc, in_slew, load_cap, - drvr_parasitic, related_out_cap, pvt, dcalc_ap, + gateDelay(arc, in_slew, load_cap, drvr_parasitic, related_out_cap, pvt, dcalc_ap, gate_delay, drvr_slew); GateTimingModel *model = gateModel(arc, dcalc_ap); float c_eff = 0.0; string result; if (drvr_parasitic_ && dmp_alg_) { c_eff = dmp_alg_->ceff(); + const LibertyCell *drvr_cell = arc->from()->libertyCell(); const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary(); const Units *units = drvr_library->units(); const Unit *cap_unit = units->capacitanceUnit(); @@ -1707,8 +1705,8 @@ DmpCeffDelayCalc::reportGateDelay(const LibertyCell *drvr_cell, c_eff = load_cap; if (model) { float in_slew1 = delayAsFloat(in_slew); - result += model->reportGateDelay(drvr_cell, pvt, in_slew1, c_eff, - related_out_cap, pocv_enabled_, digits); + result += model->reportGateDelay(pvt, in_slew1, c_eff, related_out_cap, + pocv_enabled_, digits); } return result; } @@ -1728,10 +1726,8 @@ gateModelRd(const LibertyCell *cell, float cap2 = cap1 + 1e-15; ArcDelay d1, d2; Slew s1, s2; - gate_model->gateDelay(cell, pvt, in_slew, cap1, related_out_cap, pocv_enabled, - d1, s1); - gate_model->gateDelay(cell, pvt, in_slew, cap2, related_out_cap, pocv_enabled, - d2, 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); double vth = cell->libertyLibrary()->outputThreshold(rf); float rd = -log(vth) * abs(delayAsFloat(d1) - delayAsFloat(d2)) / (cap2 - cap1); return rd; diff --git a/dcalc/DmpCeff.hh b/dcalc/DmpCeff.hh index 5f8360d2..b79dbdc6 100644 --- a/dcalc/DmpCeff.hh +++ b/dcalc/DmpCeff.hh @@ -17,7 +17,7 @@ #pragma once #include "LibertyClass.hh" -#include "RCDelayCalc.hh" +#include "LumpedCapDelayCalc.hh" namespace sta { @@ -29,7 +29,7 @@ class GateTableModel; // Delay calculator using Dartu/Menezes/Pileggi effective capacitance // algorithm for RSPF loads. -class DmpCeffDelayCalc : public RCDelayCalc +class DmpCeffDelayCalc : public LumpedCapDelayCalc { public: DmpCeffDelayCalc(StaState *sta); @@ -39,8 +39,7 @@ public: const RiseFall *rf, const Parasitic *parasitic, const DcalcAnalysisPt *dcalc_ap); - virtual void gateDelay(const LibertyCell *drvr_cell, - const TimingArc *arc, + virtual void gateDelay(const TimingArc *arc, const Slew &in_slew, float load_cap, const Parasitic *drvr_parasitic, @@ -50,16 +49,14 @@ public: // return values ArcDelay &gate_delay, Slew &drvr_slew); - virtual float ceff(const LibertyCell *drvr_cell, - const TimingArc *arc, + 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 LibertyCell *drvr_cell, - const TimingArc *arc, + virtual string reportGateDelay(const TimingArc *arc, const Slew &in_slew, float load_cap, const Parasitic *drvr_parasitic, diff --git a/dcalc/DmpDelayCalc.cc b/dcalc/DmpDelayCalc.cc index 169b1051..ed97468a 100644 --- a/dcalc/DmpDelayCalc.cc +++ b/dcalc/DmpDelayCalc.cc @@ -35,17 +35,6 @@ class DmpCeffElmoreDelayCalc : public DmpCeffDelayCalc public: DmpCeffElmoreDelayCalc(StaState *sta); ArcDelayCalc *copy() override; - void gateDelay(const LibertyCell *drvr_cell, - 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_, - Slew &drvr_slew) override; void loadDelay(const Pin *load_pin, ArcDelay &wire_delay, Slew &load_slew) override; @@ -68,25 +57,6 @@ DmpCeffElmoreDelayCalc::copy() return new DmpCeffElmoreDelayCalc(this); } -void -DmpCeffElmoreDelayCalc::gateDelay(const LibertyCell *drvr_cell, - 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) -{ - DmpCeffDelayCalc::gateDelay(drvr_cell, arc, in_slew, - load_cap, drvr_parasitic, related_out_cap, - pvt, dcalc_ap, - gate_delay, drvr_slew); -} - void DmpCeffElmoreDelayCalc::loadDelay(const Pin *load_pin, ArcDelay &wire_delay, @@ -127,8 +97,7 @@ public: const RiseFall *rf, const Parasitic *parasitic, const DcalcAnalysisPt *dcalc_ap) override; - void gateDelay(const LibertyCell *drvr_cell, - const TimingArc *arc, + void gateDelay(const TimingArc *arc, const Slew &in_slew, float load_cap, const Parasitic *drvr_parasitic, @@ -233,7 +202,7 @@ DmpCeffTwoPoleDelayCalc::findParasitic(const Pin *drvr_pin, cnst_min_max, parasitic_ap); // Estimated parasitics are not recorded in the "database", so - // it for deletion after the drvr pin delay calc is finished. + // save it for deletion after the drvr pin delay calc is finished. if (parasitic) unsaved_parasitics_.push_back(parasitic); } @@ -260,8 +229,7 @@ DmpCeffTwoPoleDelayCalc::inputPortDelay(const Pin *port_pin, } void -DmpCeffTwoPoleDelayCalc::gateDelay(const LibertyCell *drvr_cell, - const TimingArc *arc, +DmpCeffTwoPoleDelayCalc::gateDelay(const TimingArc *arc, const Slew &in_slew, float load_cap, const Parasitic *drvr_parasitic, @@ -272,15 +240,13 @@ DmpCeffTwoPoleDelayCalc::gateDelay(const LibertyCell *drvr_cell, ArcDelay &gate_delay, Slew &drvr_slew) { + gateDelayInit(arc, in_slew, drvr_parasitic); parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(drvr_parasitic); - const LibertyLibrary *drvr_library = drvr_cell->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(); - DmpCeffDelayCalc::gateDelay(drvr_cell, arc, in_slew, - load_cap, 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); } diff --git a/dcalc/GraphDelayCalc.cc b/dcalc/GraphDelayCalc.cc index beee3dfb..ef8735db 100644 --- a/dcalc/GraphDelayCalc.cc +++ b/dcalc/GraphDelayCalc.cc @@ -44,170 +44,10 @@ using std::abs; static const Slew default_slew = 0.0; -typedef Set MultiDrvrNetSet; - static bool isLeafDriver(const Pin *pin, const Network *network); -// Cache parallel delay/slew values for nets with multiple drivers. -class MultiDrvrNet -{ -public: - MultiDrvrNet(VertexSet *drvrs); - ~MultiDrvrNet(); - const VertexSet *drvrs() const { return drvrs_; } - VertexSet *drvrs() { return drvrs_; } - Vertex *dcalcDrvr() const { return dcalc_drvr_; } - void setDcalcDrvr(Vertex *drvr); - void parallelDelaySlew(const RiseFall *drvr_rf, - const DcalcAnalysisPt *dcalc_ap, - ArcDelayCalc *arc_delay_calc, - GraphDelayCalc *dcalc, - // Return values. - ArcDelay ¶llel_delay, - Slew ¶llel_slew); - void netCaps(const RiseFall *rf, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - float &pin_cap, - float &wire_cap, - float &fanout, - bool &has_net_load); - void findCaps(const GraphDelayCalc *dcalc, - const Sdc *sdc); - -private: - void findDelaysSlews(ArcDelayCalc *arc_delay_calc, - GraphDelayCalc *dcalc); - - // Driver that triggers delay calculation for all the drivers on the net. - Vertex *dcalc_drvr_; - VertexSet *drvrs_; - // [drvr_rf->index][dcalc_ap->index] - ArcDelay *parallel_delays_; - // [drvr_rf->index][dcalc_ap->index] - Slew *parallel_slews_; - // [drvr_rf->index][dcalc_ap->index] - NetCaps *net_caps_; - bool delays_valid_:1; -}; - -MultiDrvrNet::MultiDrvrNet(VertexSet *drvrs) : - dcalc_drvr_(nullptr), - drvrs_(drvrs), - parallel_delays_(nullptr), - parallel_slews_(nullptr), - net_caps_(nullptr), - delays_valid_(false) -{ -} - -MultiDrvrNet::~MultiDrvrNet() -{ - delete drvrs_; - if (delays_valid_) { - delete [] parallel_delays_; - delete [] parallel_slews_; - } - delete [] net_caps_; -} - -void -MultiDrvrNet::parallelDelaySlew(const RiseFall *drvr_rf, - const DcalcAnalysisPt *dcalc_ap, - ArcDelayCalc *arc_delay_calc, - GraphDelayCalc *dcalc, - // Return values. - ArcDelay ¶llel_delay, - Slew ¶llel_slew) -{ - if (!delays_valid_) { - findDelaysSlews(arc_delay_calc, dcalc); - delays_valid_ = true; - } - - int index = dcalc_ap->index() * RiseFall::index_count - + drvr_rf->index(); - parallel_delay = parallel_delays_[index]; - parallel_slew = parallel_slews_[index]; -} - -void -MultiDrvrNet::findDelaysSlews(ArcDelayCalc *arc_delay_calc, - GraphDelayCalc *dcalc) -{ - Corners *corners = dcalc->corners(); - int count = RiseFall::index_count * corners->dcalcAnalysisPtCount(); - parallel_delays_ = new ArcDelay[count]; - parallel_slews_ = new Slew[count]; - for (auto dcalc_ap : corners->dcalcAnalysisPts()) { - DcalcAPIndex ap_index = dcalc_ap->index(); - const Pvt *pvt = dcalc_ap->operatingConditions(); - for (auto drvr_rf : RiseFall::range()) { - int drvr_rf_index = drvr_rf->index(); - int index = ap_index*RiseFall::index_count+drvr_rf_index; - dcalc->findMultiDrvrGateDelay(this, drvr_rf, pvt, dcalc_ap, - arc_delay_calc, - parallel_delays_[index], - parallel_slews_[index]); - } - } -} - -void -MultiDrvrNet::netCaps(const RiseFall *drvr_rf, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - float &pin_cap, - float &wire_cap, - float &fanout, - bool &has_net_load) -{ - int index = dcalc_ap->index() * RiseFall::index_count - + drvr_rf->index(); - NetCaps &net_caps = net_caps_[index]; - pin_cap = net_caps.pinCap(); - wire_cap = net_caps.wireCap(); - fanout = net_caps.fanout(); - has_net_load = net_caps.hasNetLoad(); -} - -void -MultiDrvrNet::findCaps(const GraphDelayCalc *dcalc, - const Sdc *sdc) -{ - Corners *corners = dcalc->corners(); - int count = RiseFall::index_count * corners->dcalcAnalysisPtCount(); - net_caps_ = new NetCaps[count]; - const Pin *drvr_pin = dcalc_drvr_->pin(); - for (auto dcalc_ap : corners->dcalcAnalysisPts()) { - DcalcAPIndex ap_index = dcalc_ap->index(); - const Corner *corner = dcalc_ap->corner(); - const OperatingConditions *op_cond = dcalc_ap->operatingConditions(); - const MinMax *min_max = dcalc_ap->constraintMinMax(); - for (auto drvr_rf : RiseFall::range()) { - int drvr_rf_index = drvr_rf->index(); - int index = ap_index * RiseFall::index_count + drvr_rf_index; - NetCaps &net_caps = net_caps_[index]; - float pin_cap, wire_cap, fanout; - bool has_net_load; - // Find pin and external pin/wire capacitance. - sdc->connectedCap(drvr_pin, drvr_rf, op_cond, corner, min_max, - pin_cap, wire_cap, fanout, has_net_load); - net_caps.init(pin_cap, wire_cap, fanout, has_net_load); - } - } -} - -void -MultiDrvrNet::setDcalcDrvr(Vertex *drvr) -{ - dcalc_drvr_ = drvr; -} - -//////////////////////////////////////////////////////////////// - GraphDelayCalc::GraphDelayCalc(StaState *sta) : StaState(sta), observer_(nullptr), @@ -238,7 +78,7 @@ GraphDelayCalc::~GraphDelayCalc() void GraphDelayCalc::deleteMultiDrvrNets() { - MultiDrvrNetSet drvr_nets; + Set drvr_nets; MultiDrvrNetMap::Iterator multi_iter(multi_drvr_net_map_); while (multi_iter.hasNext()) { MultiDrvrNet *multi_drvr = multi_iter.next(); @@ -401,7 +241,6 @@ GraphDelayCalc::findDelays(Level level) debugPrint(debug_, "delay_calc", 1, "find delays to level %d", level); if (!delays_seeded_) { iter_->clear(); - ensureMultiDrvrNetsFound(); seedRootSlews(); delays_seeded_ = true; } @@ -444,107 +283,6 @@ GraphDelayCalc::seedInvalidDelays() invalid_delays_->clear(); } -class FindNetDrvrs : public PinVisitor -{ -public: - FindNetDrvrs(PinSet &drvr_pins, - const Network *network, - const Graph *graph); - virtual void operator()(const Pin *pin); - -protected: - PinSet &drvr_pins_; - const Network *network_; - const Graph *graph_; -}; - -FindNetDrvrs::FindNetDrvrs(PinSet &drvr_pins, - const Network *network, - const Graph *graph) : - drvr_pins_(drvr_pins), - network_(network), - graph_(graph) -{ -} - -void -FindNetDrvrs::operator()(const Pin *pin) -{ - Vertex *vertex = graph_->pinDrvrVertex(pin); - if (isLeafDriver(pin, network_) - && !(vertex && vertex->isRoot())) - drvr_pins_.insert(pin); -} - -void -GraphDelayCalc::ensureMultiDrvrNetsFound() -{ - if (!multi_drvr_nets_found_) { - LeafInstanceIterator *inst_iter = network_->leafInstanceIterator(); - while (inst_iter->hasNext()) { - Instance *inst = inst_iter->next(); - InstancePinIterator *pin_iter = network_->pinIterator(inst); - while (pin_iter->hasNext()) { - Pin *pin = pin_iter->next(); - Vertex *drvr_vertex = graph_->pinDrvrVertex(pin); - if (network_->isDriver(pin) - && !multi_drvr_net_map_.hasKey(drvr_vertex)) { - PinSet drvr_pins(network_); - FindNetDrvrs visitor(drvr_pins, network_, graph_); - network_->visitConnectedPins(pin, visitor); - if (drvr_pins.size() > 1) - makeMultiDrvrNet(drvr_pins); - } - } - delete pin_iter; - } - delete inst_iter; - multi_drvr_nets_found_ = true; - } -} - -void -GraphDelayCalc::makeMultiDrvrNet(PinSet &drvr_pins) -{ - debugPrint(debug_, "delay_calc", 3, "multi-driver net"); - VertexSet *drvr_vertices = new VertexSet(graph_); - MultiDrvrNet *multi_drvr = new MultiDrvrNet(drvr_vertices); - Level max_drvr_level = 0; - Vertex *max_drvr = nullptr; - PinSet::Iterator pin_iter(drvr_pins); - while (pin_iter.hasNext()) { - const Pin *pin = pin_iter.next(); - Vertex *drvr_vertex = graph_->pinDrvrVertex(pin); - debugPrint(debug_, "delay_calc", 3, " %s", - network_->pathName(pin)); - multi_drvr_net_map_[drvr_vertex] = multi_drvr; - drvr_vertices->insert(drvr_vertex); - Level drvr_level = drvr_vertex->level(); - if (max_drvr == nullptr - || drvr_level > max_drvr_level) { - max_drvr = drvr_vertex; - max_drvr_level = drvr_level; - } - } - multi_drvr->setDcalcDrvr(max_drvr); - multi_drvr->findCaps(this, sdc_); -} - -static bool -isLeafDriver(const Pin *pin, - const Network *network) -{ - PortDirection *dir = network->direction(pin); - const Instance *inst = network->instance(pin); - return network->isLeaf(inst) && dir->isAnyOutput(); -} - -MultiDrvrNet * -GraphDelayCalc::multiDrvrNet(const Vertex *drvr_vertex) const -{ - return multi_drvr_net_map_.findKey(drvr_vertex); -} - void GraphDelayCalc::seedRootSlews() { @@ -754,8 +492,7 @@ GraphDelayCalc::findInputDriverDelay(const LibertyCell *drvr_cell, for (TimingArc *arc : arc_set->arcs()) { if (arc->toEdge()->asRiseFall() == rf) { float from_slew = from_slews[arc->fromEdge()->index()]; - findInputArcDelay(drvr_cell, drvr_pin, drvr_vertex, - arc, from_slew, dcalc_ap); + findInputArcDelay(drvr_pin, drvr_vertex, arc, from_slew, dcalc_ap); } } } @@ -765,8 +502,7 @@ GraphDelayCalc::findInputDriverDelay(const LibertyCell *drvr_cell, // delay minus the intrinsic delay. Driving cell delays are annotated // to the wire arcs from the input port pin to the load pins. void -GraphDelayCalc::findInputArcDelay(const LibertyCell *drvr_cell, - const Pin *drvr_pin, +GraphDelayCalc::findInputArcDelay(const Pin *drvr_pin, Vertex *drvr_vertex, const TimingArc *arc, float from_slew, @@ -788,15 +524,13 @@ GraphDelayCalc::findInputArcDelay(const LibertyCell *drvr_cell, ArcDelay intrinsic_delay; Slew intrinsic_slew; - arc_delay_calc_->gateDelay(drvr_cell, arc, Slew(from_slew), - 0.0, 0, 0.0, pvt, dcalc_ap, + arc_delay_calc_->gateDelay(arc, Slew(from_slew), 0.0, 0, 0.0, pvt, dcalc_ap, intrinsic_delay, intrinsic_slew); // For input drivers there is no instance to find a related_output_pin. ArcDelay gate_delay; Slew gate_slew; - arc_delay_calc_->gateDelay(drvr_cell, arc, - Slew(from_slew), load_cap, + 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; @@ -899,16 +633,15 @@ GraphDelayCalc::findDriverDelays(Vertex *drvr_vertex, ArcDelayCalc *arc_delay_calc) { bool delay_changed = false; - MultiDrvrNet *multi_drvr = multiDrvrNet(drvr_vertex); - if (multi_drvr) { + 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); - for (Vertex *drvr_vertex : *multi_drvr->drvrs()) { - // Only init load slews once so previous driver dcalc results - // aren't clobbered. + 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 { @@ -919,6 +652,74 @@ GraphDelayCalc::findDriverDelays(Vertex *drvr_vertex, return delay_changed; } +MultiDrvrNet * +GraphDelayCalc::findMultiDrvrNet(Vertex *drvr_vertex) +{ + MultiDrvrNet *multi_drvr = multiDrvrNet(drvr_vertex); + if (multi_drvr) + return multi_drvr; + else { + const PinSet *drvrs = network_->drivers(drvr_vertex->pin()); + if (drvrs && drvrs->size() > 1) { + PinSet drvrs1(network_); + // Filter input ports and non-leaf drivers. + for (const Pin *pin : *drvrs) { + if (isLeafDriver(pin, network_)) + drvrs1.insert(pin); + } + MultiDrvrNet *multi_drvr = nullptr; + if (drvrs1.size() > 1) + multi_drvr = makeMultiDrvrNet(drvrs1); + return multi_drvr; + } + else + return nullptr; + } +} + +static bool +isLeafDriver(const Pin *pin, + const Network *network) +{ + PortDirection *dir = network->direction(pin); + const Instance *inst = network->instance(pin); + return network->isLeaf(inst) && dir->isAnyOutput(); +} + +MultiDrvrNet * +GraphDelayCalc::multiDrvrNet(const Vertex *drvr_vertex) const +{ + return multi_drvr_net_map_.findKey(drvr_vertex); +} + +MultiDrvrNet * +GraphDelayCalc::makeMultiDrvrNet(PinSet &drvr_pins) +{ + debugPrint(debug_, "delay_calc", 3, "multi-driver net"); + VertexSet *drvr_vertices = new VertexSet(graph_); + MultiDrvrNet *multi_drvr = new MultiDrvrNet(drvr_vertices); + Level max_drvr_level = 0; + Vertex *max_drvr = nullptr; + PinSet::Iterator pin_iter(drvr_pins); + while (pin_iter.hasNext()) { + const Pin *pin = pin_iter.next(); + Vertex *drvr_vertex = graph_->pinDrvrVertex(pin); + debugPrint(debug_, "delay_calc", 3, " %s", + network_->pathName(pin)); + multi_drvr_net_map_[drvr_vertex] = multi_drvr; + drvr_vertices->insert(drvr_vertex); + Level drvr_level = drvr_vertex->level(); + if (max_drvr == nullptr + || drvr_level > max_drvr_level) { + max_drvr = drvr_vertex; + max_drvr_level = drvr_level; + } + } + multi_drvr->setDcalcDrvr(max_drvr); + multi_drvr->findCaps(sdc_); + return multi_drvr; +} + void GraphDelayCalc::initLoadSlews(Vertex *drvr_vertex) { @@ -947,7 +748,6 @@ GraphDelayCalc::findDriverDelays1(Vertex *drvr_vertex, { const Pin *drvr_pin = drvr_vertex->pin(); Instance *drvr_inst = network_->instance(drvr_pin); - LibertyCell *drvr_cell = network_->libertyCell(drvr_inst); initSlew(drvr_vertex); initWireDelays(drvr_vertex); bool delay_changed = false; @@ -960,9 +760,8 @@ GraphDelayCalc::findDriverDelays1(Vertex *drvr_vertex, if (search_pred_->searchFrom(from_vertex) && search_pred_->searchThru(edge) && !edge->role()->isLatchDtoQ()) { - delay_changed |= findDriverEdgeDelays(drvr_cell, drvr_inst, drvr_pin, - drvr_vertex, multi_drvr, edge, - arc_delay_calc); + delay_changed |= findDriverEdgeDelays(drvr_inst, drvr_pin, drvr_vertex, + multi_drvr, edge, arc_delay_calc); has_delays = true; } } @@ -994,26 +793,24 @@ GraphDelayCalc::findLatchEdgeDelays(Edge *edge) Vertex *drvr_vertex = edge->to(graph_); const Pin *drvr_pin = drvr_vertex->pin(); Instance *drvr_inst = network_->instance(drvr_pin); - LibertyCell *drvr_cell = network_->libertyCell(drvr_inst); debugPrint(debug_, "delay_calc", 2, "find latch D->Q %s", sdc_network_->pathName(drvr_inst)); - bool delay_changed = findDriverEdgeDelays(drvr_cell, drvr_inst, drvr_pin, - drvr_vertex, nullptr, edge, arc_delay_calc_); + bool delay_changed = findDriverEdgeDelays(drvr_inst, drvr_pin, drvr_vertex, + nullptr, edge, arc_delay_calc_); if (delay_changed && observer_) observer_->delayChangedTo(drvr_vertex); } bool -GraphDelayCalc::findDriverEdgeDelays(LibertyCell *drvr_cell, - Instance *drvr_inst, +GraphDelayCalc::findDriverEdgeDelays(const Instance *drvr_inst, const Pin *drvr_pin, Vertex *drvr_vertex, - MultiDrvrNet *multi_drvr, + const MultiDrvrNet *multi_drvr, Edge *edge, ArcDelayCalc *arc_delay_calc) { Vertex *in_vertex = edge->from(graph_); - TimingArcSet *arc_set = edge->timingArcSet(); + const TimingArcSet *arc_set = edge->timingArcSet(); const LibertyPort *related_out_port = arc_set->relatedOut(); const Pin *related_out_pin = 0; bool delay_changed = false; @@ -1025,21 +822,16 @@ GraphDelayCalc::findDriverEdgeDelays(LibertyCell *drvr_cell, 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); + 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); + related_out_cap = loadCap(related_out_pin, related_out_parasitic, rf, dcalc_ap); } - delay_changed |= findArcDelay(drvr_cell, drvr_pin, drvr_vertex, - multi_drvr, arc, parasitic, - related_out_cap, - in_vertex, edge, pvt, dcalc_ap, - arc_delay_calc); + delay_changed |= findArcDelay(drvr_pin, drvr_vertex, arc, parasitic, + related_out_cap, in_vertex, edge, pvt, dcalc_ap, + multi_drvr, arc_delay_calc); } } @@ -1059,7 +851,7 @@ GraphDelayCalc::loadCap(const Pin *drvr_pin, for (auto drvr_rf : RiseFall::range()) { Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, dcalc_ap); - float cap = loadCap(drvr_pin, nullptr, drvr_parasitic, drvr_rf, dcalc_ap); + float cap = loadCap(drvr_pin, drvr_parasitic, drvr_rf, dcalc_ap, nullptr); arc_delay_calc_->finishDrvrPin(); if (min_max->compare(cap, load_cap)) load_cap = cap; @@ -1074,7 +866,7 @@ GraphDelayCalc::loadCap(const Pin *drvr_pin, { Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, dcalc_ap); - float cap = loadCap(drvr_pin, nullptr, drvr_parasitic, drvr_rf, dcalc_ap); + float cap = loadCap(drvr_pin, drvr_parasitic, drvr_rf, dcalc_ap, nullptr); return cap; } @@ -1084,15 +876,15 @@ GraphDelayCalc::loadCap(const Pin *drvr_pin, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) const { - return loadCap(drvr_pin, nullptr, drvr_parasitic, rf, dcalc_ap); + return loadCap(drvr_pin, drvr_parasitic, rf, dcalc_ap, nullptr); } float GraphDelayCalc::loadCap(const Pin *drvr_pin, - MultiDrvrNet *multi_drvr, const Parasitic *drvr_parasitic, const RiseFall *rf, - const DcalcAnalysisPt *dcalc_ap) const + const DcalcAnalysisPt *dcalc_ap, + const MultiDrvrNet *multi_drvr) const { float pin_cap, wire_cap; bool has_net_load; @@ -1241,21 +1033,20 @@ 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 +// input to output timing arc, The wire delays from the gate output to +// each load pin, and the slew at each load pin. Annotate the graph // with the results. bool -GraphDelayCalc::findArcDelay(LibertyCell *drvr_cell, - const Pin *drvr_pin, +GraphDelayCalc::findArcDelay(const Pin *drvr_pin, Vertex *drvr_vertex, - MultiDrvrNet *multi_drvr, - TimingArc *arc, - Parasitic *drvr_parasitic, + 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; @@ -1277,21 +1068,16 @@ GraphDelayCalc::findArcDelay(LibertyCell *drvr_cell, 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 - && arc->to()->direction()->isOutput()) - parallelGateDelay(multi_drvr, drvr_cell, drvr_pin, arc, - pvt, dcalc_ap, from_slew, drvr_parasitic, - related_out_cap, - arc_delay_calc, - gate_delay, gate_slew); - else { - float load_cap = loadCap(drvr_pin, multi_drvr, drvr_parasitic, - drvr_rf, dcalc_ap); - arc_delay_calc->gateDelay(drvr_cell, arc, - from_slew, load_cap, drvr_parasitic, + && 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), @@ -1320,115 +1106,6 @@ GraphDelayCalc::findArcDelay(LibertyCell *drvr_cell, return delay_changed; } -void -GraphDelayCalc::parallelGateDelay(MultiDrvrNet *multi_drvr, - LibertyCell *drvr_cell, - const Pin *drvr_pin, - TimingArc *arc, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - const Slew from_slew, - Parasitic *drvr_parasitic, - float related_out_cap, - ArcDelayCalc *arc_delay_calc, - // Return values. - ArcDelay &gate_delay, - Slew &gate_slew) -{ - ArcDelay intrinsic_delay; - Slew intrinsic_slew; - arc_delay_calc->gateDelay(drvr_cell, arc, from_slew, - 0.0, 0, 0.0, pvt, dcalc_ap, - intrinsic_delay, intrinsic_slew); - ArcDelay parallel_delay; - Slew parallel_slew; - const RiseFall *drvr_rf = arc->toEdge()->asRiseFall(); - multi_drvr->parallelDelaySlew(drvr_rf, dcalc_ap, arc_delay_calc, this, - parallel_delay, parallel_slew); - - gate_delay = parallel_delay + intrinsic_delay; - gate_slew = parallel_slew; - - float load_cap = loadCap(drvr_pin, multi_drvr, drvr_parasitic, - drvr_rf, dcalc_ap); - Delay gate_delay1; - Slew gate_slew1; - arc_delay_calc->gateDelay(drvr_cell, arc, - from_slew, load_cap, drvr_parasitic, - related_out_cap, pvt, dcalc_ap, - gate_delay1, gate_slew1); - float factor = delayRatio(gate_slew, gate_slew1); - arc_delay_calc->setMultiDrvrSlewFactor(factor); -} - -void -GraphDelayCalc::findMultiDrvrGateDelay(MultiDrvrNet *multi_drvr, - const RiseFall *drvr_rf, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - ArcDelayCalc *arc_delay_calc, - // Return values. - ArcDelay ¶llel_delay, - Slew ¶llel_slew) -{ - ArcDelay delay_sum = 1.0; - Slew slew_sum = 1.0; - for (Vertex *drvr_vertex1 : *multi_drvr->drvrs()) { - Pin *drvr_pin1 = drvr_vertex1->pin(); - Instance *drvr_inst1 = network_->instance(drvr_pin1); - LibertyCell *drvr_cell1 = network_->libertyCell(drvr_inst1); - if (network_->isDriver(drvr_pin1)) { - VertexInEdgeIterator edge_iter(drvr_vertex1, graph_); - while (edge_iter.hasNext()) { - Edge *edge1 = edge_iter.next(); - TimingArcSet *arc_set1 = edge1->timingArcSet(); - const LibertyPort *related_out_port = arc_set1->relatedOut(); - for (TimingArc *arc1 : arc_set1->arcs()) { - RiseFall *drvr_rf1 = arc1->toEdge()->asRiseFall(); - if (drvr_rf1 == drvr_rf) { - Vertex *from_vertex1 = edge1->from(graph_); - RiseFall *from_rf1 = arc1->fromEdge()->asRiseFall(); - Slew from_slew1 = edgeFromSlew(from_vertex1, from_rf1, edge1, dcalc_ap); - ArcDelay intrinsic_delay1; - Slew intrinsic_slew1; - arc_delay_calc->gateDelay(drvr_cell1, arc1, from_slew1, - 0.0, 0, 0.0, pvt, dcalc_ap, - intrinsic_delay1, intrinsic_slew1); - Parasitic *parasitic1 = - arc_delay_calc->findParasitic(drvr_pin1, drvr_rf1, dcalc_ap); - const Pin *related_out_pin1 = 0; - float related_out_cap1 = 0.0; - if (related_out_port) { - Instance *inst1 = network_->instance(drvr_pin1); - related_out_pin1 = network_->findPin(inst1, related_out_port); - if (related_out_pin1) { - Parasitic *related_out_parasitic1 = - arc_delay_calc->findParasitic(related_out_pin1, drvr_rf, - dcalc_ap); - related_out_cap1 = loadCap(related_out_pin1, - related_out_parasitic1, - drvr_rf, dcalc_ap); - } - } - float load_cap1 = loadCap(drvr_pin1, parasitic1, - drvr_rf, dcalc_ap); - ArcDelay gate_delay1; - Slew gate_slew1; - arc_delay_calc->gateDelay(drvr_cell1, arc1, - from_slew1, load_cap1, parasitic1, - related_out_cap1, pvt, dcalc_ap, - gate_delay1, gate_slew1); - delay_sum += 1.0F / (gate_delay1 - intrinsic_delay1); - slew_sum += 1.0F / gate_slew1; - } - } - } - } - } - parallel_delay = 1.0F / delay_sum; - parallel_slew = 1.0F / slew_sum; -} - // Use clock slew for register/latch clk->q edges. Slew GraphDelayCalc::edgeFromSlew(const Vertex *from_vertex, @@ -1517,7 +1194,6 @@ GraphDelayCalc::findCheckEdgeDelays(Edge *edge, TimingArcSet *arc_set = edge->timingArcSet(); const Pin *to_pin = to_vertex->pin(); Instance *inst = network_->instance(to_pin); - const LibertyCell *cell = network_->libertyCell(inst); debugPrint(debug_, "delay_calc", 2, "find check %s %s -> %s", sdc_network_->pathName(inst), network_->portName(from_vertex->pin()), @@ -1561,11 +1237,8 @@ GraphDelayCalc::findCheckEdgeDelays(Edge *edge, to_rf, dcalc_ap); } ArcDelay check_delay; - arc_delay_calc->checkDelay(cell, arc, - from_slew, to_slew, - related_out_cap, - pvt, dcalc_ap, - check_delay); + arc_delay_calc->checkDelay(arc, from_slew, to_slew, related_out_cap, + pvt, dcalc_ap, check_delay); debugPrint(debug_, "delay_calc", 3, " check_delay = %s", delayAsString(check_delay, this)); @@ -1604,8 +1277,7 @@ GraphDelayCalc::ceff(Edge *edge, Vertex *to_vertex = edge->to(graph_); Pin *to_pin = to_vertex->pin(); Instance *inst = network_->instance(to_pin); - LibertyCell *cell = network_->libertyCell(inst); - TimingArcSet *arc_set = edge->timingArcSet(); + const TimingArcSet *arc_set = edge->timingArcSet(); float ceff = 0.0; const Pvt *pvt = sdc_->pvt(inst, dcalc_ap->constraintMinMax()); if (pvt == nullptr) @@ -1628,8 +1300,7 @@ GraphDelayCalc::ceff(Edge *edge, dcalc_ap); const Slew &from_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap); float load_cap = loadCap(to_pin, to_parasitic, to_rf, dcalc_ap); - ceff = arc_delay_calc_->ceff(cell, arc, - from_slew, load_cap, to_parasitic, + ceff = arc_delay_calc_->ceff(arc, from_slew, load_cap, to_parasitic, related_out_cap, pvt, dcalc_ap); arc_delay_calc_->finishDrvrPin(); } @@ -1639,8 +1310,8 @@ GraphDelayCalc::ceff(Edge *edge, //////////////////////////////////////////////////////////////// string -GraphDelayCalc::reportDelayCalc(Edge *edge, - TimingArc *arc, +GraphDelayCalc::reportDelayCalc(const Edge *edge, + const TimingArc *arc, const Corner *corner, const MinMax *min_max, int digits) @@ -1649,9 +1320,8 @@ GraphDelayCalc::reportDelayCalc(Edge *edge, Vertex *to_vertex = edge->to(graph_); Pin *to_pin = to_vertex->pin(); TimingRole *role = arc->role(); - Instance *inst = network_->instance(to_pin); - LibertyCell *cell = network_->libertyCell(inst); - TimingArcSet *arc_set = edge->timingArcSet(); + const Instance *inst = network_->instance(to_pin); + const TimingArcSet *arc_set = edge->timingArcSet(); string result; DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); const Pvt *pvt = sdc_->pvt(inst, dcalc_ap->constraintMinMax()); @@ -1677,18 +1347,16 @@ GraphDelayCalc::reportDelayCalc(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(cell, arc, from_slew, - from_slew_annotation, to_slew, - related_out_cap, pvt, dcalc_ap, - digits); + result = arc_delay_calc_->reportCheckDelay(arc, from_slew, from_slew_annotation, + to_slew, related_out_cap, pvt, + dcalc_ap, digits); } else { Parasitic *to_parasitic = arc_delay_calc_->findParasitic(to_pin, to_rf, dcalc_ap); const Slew &from_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap); float load_cap = loadCap(to_pin, to_parasitic, to_rf, dcalc_ap); - result = arc_delay_calc_->reportGateDelay(cell, arc, - from_slew, load_cap, to_parasitic, + result = arc_delay_calc_->reportGateDelay(arc, from_slew, load_cap, to_parasitic, related_out_cap, pvt, dcalc_ap, digits); } arc_delay_calc_->finishDrvrPin(); @@ -1754,4 +1422,73 @@ GraphDelayCalc::minPeriod(const Pin *pin, } } +//////////////////////////////////////////////////////////////// + +MultiDrvrNet::MultiDrvrNet(VertexSet *drvrs) : + dcalc_drvr_(nullptr), + drvrs_(drvrs) +{ +} + +MultiDrvrNet::~MultiDrvrNet() +{ + delete drvrs_; +} + +void +MultiDrvrNet::netCaps(const RiseFall *drvr_rf, + const DcalcAnalysisPt *dcalc_ap, + // Return values. + float &pin_cap, + float &wire_cap, + float &fanout, + bool &has_net_load) const +{ + int index = dcalc_ap->index() * RiseFall::index_count + + drvr_rf->index(); + const NetCaps &net_caps = net_caps_[index]; + pin_cap = net_caps.pinCap(); + wire_cap = net_caps.wireCap(); + fanout = net_caps.fanout(); + has_net_load = net_caps.hasNetLoad(); +} + +void +MultiDrvrNet::findCaps(const Sdc *sdc) +{ + Corners *corners = sdc->corners(); + int count = RiseFall::index_count * corners->dcalcAnalysisPtCount(); + net_caps_.resize(count); + const Pin *drvr_pin = dcalc_drvr_->pin(); + for (auto dcalc_ap : corners->dcalcAnalysisPts()) { + DcalcAPIndex ap_index = dcalc_ap->index(); + const Corner *corner = dcalc_ap->corner(); + const OperatingConditions *op_cond = dcalc_ap->operatingConditions(); + const MinMax *min_max = dcalc_ap->constraintMinMax(); + for (auto drvr_rf : RiseFall::range()) { + int drvr_rf_index = drvr_rf->index(); + int index = ap_index * RiseFall::index_count + drvr_rf_index; + NetCaps &net_caps = net_caps_[index]; + float pin_cap, wire_cap, fanout; + bool has_net_load; + // Find pin and external pin/wire capacitance. + sdc->connectedCap(drvr_pin, drvr_rf, op_cond, corner, min_max, + pin_cap, wire_cap, fanout, has_net_load); + net_caps.init(pin_cap, wire_cap, fanout, has_net_load); + } + } +} + +void +MultiDrvrNet::setDcalcDrvr(Vertex *drvr) +{ + dcalc_drvr_ = drvr; +} + +bool +MultiDrvrNet::parallelGates(const Network *network) const +{ + return network->direction(dcalc_drvr_->pin())->isOutput(); +} + } // namespace diff --git a/dcalc/LumpedCapDelayCalc.cc b/dcalc/LumpedCapDelayCalc.cc index 0309c2c5..5e99dd7a 100644 --- a/dcalc/LumpedCapDelayCalc.cc +++ b/dcalc/LumpedCapDelayCalc.cc @@ -40,7 +40,7 @@ makeLumpedCapDelayCalc(StaState *sta) } LumpedCapDelayCalc::LumpedCapDelayCalc(StaState *sta) : - ArcDelayCalc(sta) + ParallelDelayCalc(sta) { } @@ -82,9 +82,9 @@ LumpedCapDelayCalc::findParasitic(const Pin *drvr_pin, Wireload *wireload = sdc_->wireload(cnst_min_max); if (wireload) { float pin_cap, wire_cap, fanout; - bool has_wire_cap; + bool has_net_load; graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap, - pin_cap, wire_cap, fanout, has_wire_cap); + pin_cap, wire_cap, fanout, has_net_load); parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload, fanout, pin_cap, dcalc_ap->operatingConditions(), @@ -107,32 +107,8 @@ LumpedCapDelayCalc::reducedParasiticType() const return ReducedParasiticType::pi_elmore; } -void -LumpedCapDelayCalc::finishDrvrPin() -{ - for (auto parasitic : unsaved_parasitics_) - parasitics_->deleteUnsavedParasitic(parasitic); - unsaved_parasitics_.clear(); - for (auto drvr_pin : reduced_parasitic_drvrs_) - parasitics_->deleteDrvrReducedParasitics(drvr_pin); - reduced_parasitic_drvrs_.clear(); -} - -void -LumpedCapDelayCalc::inputPortDelay(const Pin *, float in_slew, - const RiseFall *rf, - const Parasitic *, - const DcalcAnalysisPt *) -{ - drvr_slew_ = in_slew; - drvr_rf_ = rf; - drvr_library_ = network_->defaultLibertyLibrary(); - multi_drvr_slew_factor_ = 1.0F; -} - float -LumpedCapDelayCalc::ceff(const LibertyCell *, - const TimingArc *, +LumpedCapDelayCalc::ceff(const TimingArc *, const Slew &, float load_cap, const Parasitic *, @@ -144,11 +120,10 @@ LumpedCapDelayCalc::ceff(const LibertyCell *, } void -LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell, - const TimingArc *arc, +LumpedCapDelayCalc::gateDelay(const TimingArc *arc, const Slew &in_slew, float load_cap, - const Parasitic *, + const Parasitic *drvr_parasitic, float related_out_cap, const Pvt *pvt, const DcalcAnalysisPt *dcalc_ap, @@ -156,6 +131,7 @@ LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell, ArcDelay &gate_delay, Slew &drvr_slew) { + 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", @@ -169,7 +145,7 @@ LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell, // NaNs cause seg faults during table lookup. if (isnan(load_cap) || isnan(related_out_cap) || isnan(delayAsFloat(in_slew))) report_->error(710, "gate delay input variable is NaN"); - model->gateDelay(drvr_cell, pvt, in_slew1, load_cap, related_out_cap, + model->gateDelay(pvt, in_slew1, load_cap, related_out_cap, pocv_enabled_, gate_delay1, drvr_slew1); gate_delay = gate_delay1; drvr_slew = drvr_slew1; @@ -180,9 +156,6 @@ LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell, drvr_slew = delay_zero; drvr_slew_ = 0.0; } - drvr_rf_ = arc->toEdge()->asRiseFall(); - drvr_library_ = drvr_cell->libertyLibrary(); - multi_drvr_slew_factor_ = 1.0F; } void @@ -197,52 +170,8 @@ LumpedCapDelayCalc::loadDelay(const Pin *load_pin, load_slew = load_slew1; } -void -LumpedCapDelayCalc::thresholdAdjust(const Pin *load_pin, - 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_); - float load_delay_delta = - delayAsFloat(load_slew) * ((load_vth - drvr_vth) / drvr_slew_delta); - load_delay += (drvr_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_derate = load_library->slewDerateFromLibrary(); - load_slew = load_slew * ((load_slew_delta / load_slew_derate) - / (drvr_slew_delta / drvr_slew_derate)); - } -} - -LibertyLibrary * -LumpedCapDelayCalc::thresholdLibrary(const Pin *load_pin) -{ - if (network_->isTopLevelPort(load_pin)) - // Input/output slews use the default (first read) library - // for slew thresholds. - return network_->defaultLibertyLibrary(); - else { - LibertyPort *lib_port = network_->libertyPort(load_pin); - if (lib_port) - return lib_port->libertyCell()->libertyLibrary(); - else - return network_->defaultLibertyLibrary(); - } -} - string -LumpedCapDelayCalc::reportGateDelay(const LibertyCell *drvr_cell, - const TimingArc *arc, +LumpedCapDelayCalc::reportGateDelay(const TimingArc *arc, const Slew &in_slew, float load_cap, const Parasitic *, @@ -254,15 +183,14 @@ LumpedCapDelayCalc::reportGateDelay(const LibertyCell *drvr_cell, GateTimingModel *model = gateModel(arc, dcalc_ap); if (model) { float in_slew1 = delayAsFloat(in_slew); - return model->reportGateDelay(drvr_cell, pvt, in_slew1, load_cap, - related_out_cap, false, digits); + return model->reportGateDelay(pvt, in_slew1, load_cap, related_out_cap, + false, digits); } return ""; } void -LumpedCapDelayCalc::checkDelay(const LibertyCell *cell, - const TimingArc *arc, +LumpedCapDelayCalc::checkDelay(const TimingArc *arc, const Slew &from_slew, const Slew &to_slew, float related_out_cap, @@ -275,16 +203,14 @@ LumpedCapDelayCalc::checkDelay(const LibertyCell *cell, if (model) { float from_slew1 = delayAsFloat(from_slew); float to_slew1 = delayAsFloat(to_slew); - model->checkDelay(cell, pvt, from_slew1, to_slew1, related_out_cap, - pocv_enabled_, margin); + model->checkDelay(pvt, from_slew1, to_slew1, related_out_cap, pocv_enabled_, margin); } else margin = delay_zero; } string -LumpedCapDelayCalc::reportCheckDelay(const LibertyCell *cell, - const TimingArc *arc, +LumpedCapDelayCalc::reportCheckDelay(const TimingArc *arc, const Slew &from_slew, const char *from_slew_annotation, const Slew &to_slew, @@ -297,16 +223,10 @@ LumpedCapDelayCalc::reportCheckDelay(const LibertyCell *cell, if (model) { float from_slew1 = delayAsFloat(from_slew); float to_slew1 = delayAsFloat(to_slew); - return model->reportCheckDelay(cell, pvt, from_slew1, from_slew_annotation, to_slew1, - related_out_cap, false, digits); + return model->reportCheckDelay(pvt, from_slew1, from_slew_annotation, + to_slew1, related_out_cap, false, digits); } return ""; } -void -LumpedCapDelayCalc::setMultiDrvrSlewFactor(float factor) -{ - multi_drvr_slew_factor_ = factor; -} - } // namespace diff --git a/dcalc/LumpedCapDelayCalc.hh b/dcalc/LumpedCapDelayCalc.hh index ff92dea4..db7473c0 100644 --- a/dcalc/LumpedCapDelayCalc.hh +++ b/dcalc/LumpedCapDelayCalc.hh @@ -16,13 +16,13 @@ #pragma once -#include "ArcDelayCalc.hh" +#include "ParallelDelayCalc.hh" namespace sta { // Liberty table model lumped capacitance arc delay calculator. // Wire delays are zero. -class LumpedCapDelayCalc : public ArcDelayCalc +class LumpedCapDelayCalc : public ParallelDelayCalc { public: LumpedCapDelayCalc(StaState *sta); @@ -31,13 +31,7 @@ public: 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 LibertyCell *drvr_cell, - const TimingArc *arc, + void gateDelay(const TimingArc *arc, const Slew &in_slew, float load_cap, const Parasitic *drvr_parasitic, @@ -47,9 +41,7 @@ public: // Return values. ArcDelay &gate_delay, Slew &drvr_slew) override; - void setMultiDrvrSlewFactor(float factor) override; - float ceff(const LibertyCell *drvr_cell, - const TimingArc *arc, + float ceff(const TimingArc *arc, const Slew &in_slew, float load_cap, const Parasitic *drvr_parasitic, @@ -60,8 +52,7 @@ public: // Return values. ArcDelay &wire_delay, Slew &load_slew) override; - void checkDelay(const LibertyCell *cell, - const TimingArc *arc, + void checkDelay(const TimingArc *arc, const Slew &from_slew, const Slew &to_slew, float related_out_cap, @@ -69,8 +60,7 @@ public: const DcalcAnalysisPt *dcalc_ap, // Return values. ArcDelay &margin) override; - string reportGateDelay(const LibertyCell *drvr_cell, - const TimingArc *arc, + string reportGateDelay(const TimingArc *arc, const Slew &in_slew, float load_cap, const Parasitic *drvr_parasitic, @@ -78,8 +68,7 @@ public: const Pvt *pvt, const DcalcAnalysisPt *dcalc_ap, int digits) override; - string reportCheckDelay(const LibertyCell *cell, - const TimingArc *arc, + string reportCheckDelay(const TimingArc *arc, const Slew &from_slew, const char *from_slew_annotation, const Slew &to_slew, @@ -87,25 +76,8 @@ public: const Pvt *pvt, const DcalcAnalysisPt *dcalc_ap, int digits) override; - void finishDrvrPin() override; protected: - // 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, - ArcDelay &load_delay, - Slew &load_slew); - - Slew drvr_slew_; - float multi_drvr_slew_factor_; - const LibertyLibrary *drvr_library_; - 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. - Vector unsaved_parasitics_; - Vector reduced_parasitic_drvrs_; }; ArcDelayCalc * diff --git a/dcalc/ParallelDelayCalc.cc b/dcalc/ParallelDelayCalc.cc new file mode 100644 index 00000000..62fd90a6 --- /dev/null +++ b/dcalc/ParallelDelayCalc.cc @@ -0,0 +1,171 @@ +// 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 "ParallelDelayCalc.hh" + +#include "TimingArc.hh" +#include "Corner.hh" +#include "Network.hh" +#include "Graph.hh" +#include "Sdc.hh" +#include "Liberty.hh" +#include "GraphDelayCalc.hh" + +namespace sta { + +ParallelDelayCalc::ParallelDelayCalc(StaState *sta): + DelayCalcBase(sta) +{ +} + +void +ParallelDelayCalc::inputPortDelay(const Pin *drvr_pin, + float in_slew, + const RiseFall *rf, + const Parasitic *parasitic, + 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; + 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; + } + } + } + } + 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; + + 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; +} + +} // namespace diff --git a/dcalc/ParallelDelayCalc.hh b/dcalc/ParallelDelayCalc.hh new file mode 100644 index 00000000..68510e99 --- /dev/null +++ b/dcalc/ParallelDelayCalc.hh @@ -0,0 +1,68 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2023, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include + +#include "DelayCalcBase.hh" + +namespace sta { + +// Delay calculation for parallel gates based on 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_; +}; + +} // namespace diff --git a/dcalc/RCDelayCalc.cc b/dcalc/RCDelayCalc.cc deleted file mode 100644 index 900df3f0..00000000 --- a/dcalc/RCDelayCalc.cc +++ /dev/null @@ -1,74 +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 "RCDelayCalc.hh" - -#include "Liberty.hh" -#include "Network.hh" -#include "Sdc.hh" -#include "Parasitics.hh" -#include "GraphDelayCalc.hh" - -namespace sta { - -RCDelayCalc::RCDelayCalc(StaState *sta) : - LumpedCapDelayCalc(sta) -{ -} - -ArcDelayCalc * -RCDelayCalc::copy() -{ - return new RCDelayCalc(this); -} - -void -RCDelayCalc::inputPortDelay(const Pin *, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *) -{ - drvr_parasitic_ = parasitic; - drvr_slew_ = in_slew; - drvr_rf_ = rf; - drvr_cell_ = nullptr; - drvr_library_ = network_->defaultLibertyLibrary(); - multi_drvr_slew_factor_ = 1.0F; - input_port_ = true; -} - -// 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 -RCDelayCalc::dspfWireDelaySlew(const Pin *, - 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(); - wire_delay = -elmore * log(1.0 - vth); - load_slew = (drvr_slew_ + elmore * log((1.0 - vl) / (1.0 - vh)) - / slew_derate) * multi_drvr_slew_factor_; -} - -} // namespace diff --git a/dcalc/SlewDegradeDelayCalc.cc b/dcalc/SlewDegradeDelayCalc.cc index 5e9a9f20..3e00e164 100644 --- a/dcalc/SlewDegradeDelayCalc.cc +++ b/dcalc/SlewDegradeDelayCalc.cc @@ -22,6 +22,7 @@ #include "Sdc.hh" #include "Parasitics.hh" #include "DcalcAnalysisPt.hh" +#include "LumpedCapDelayCalc.hh" namespace sta { @@ -30,33 +31,32 @@ namespace sta { // Wire delays are elmore delays. // Driver slews are degraded to loads by rise/fall transition_degradation // tables. -class SlewDegradeDelayCalc : public RCDelayCalc +class SlewDegradeDelayCalc : public LumpedCapDelayCalc { public: SlewDegradeDelayCalc(StaState *sta); - virtual ArcDelayCalc *copy(); - virtual void inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap); - virtual void gateDelay(const LibertyCell *drvr_cell, - 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 void loadDelay(const Pin *load_pin, - ArcDelay &wire_delay, - Slew &load_slew); + 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 RCDelayCalc::gateDelay; - using RCDelayCalc::reportGateDelay; + using LumpedCapDelayCalc::gateDelay; + using LumpedCapDelayCalc::reportGateDelay; private: const Pvt *pvt_; @@ -69,7 +69,7 @@ makeSlewDegradeDelayCalc(StaState *sta) } SlewDegradeDelayCalc::SlewDegradeDelayCalc(StaState *sta) : - RCDelayCalc(sta) + LumpedCapDelayCalc(sta) { } @@ -87,12 +87,11 @@ SlewDegradeDelayCalc::inputPortDelay(const Pin *port_pin, const DcalcAnalysisPt *dcalc_ap) { pvt_ = dcalc_ap->operatingConditions(); - RCDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap); + LumpedCapDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap); } void -SlewDegradeDelayCalc::gateDelay(const LibertyCell *drvr_cell, - const TimingArc *arc, +SlewDegradeDelayCalc::gateDelay(const TimingArc *arc, const Slew &in_slew, float load_cap, const Parasitic *drvr_parasitic, @@ -106,12 +105,11 @@ SlewDegradeDelayCalc::gateDelay(const LibertyCell *drvr_cell, input_port_ = false; drvr_parasitic_ = drvr_parasitic; drvr_rf_ = arc->toEdge()->asRiseFall(); - drvr_cell_ = drvr_cell; - drvr_library_ = drvr_cell->libertyLibrary(); + drvr_cell_ = arc->from()->libertyCell(); + drvr_library_ = drvr_cell_->libertyLibrary(); pvt_ = pvt; - LumpedCapDelayCalc::gateDelay(drvr_cell, arc, in_slew, - load_cap, drvr_parasitic, related_out_cap, - pvt, dcalc_ap, + LumpedCapDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic, + related_out_cap, pvt, dcalc_ap, gate_delay, drvr_slew); } @@ -129,8 +127,7 @@ SlewDegradeDelayCalc::loadDelay(const Pin *load_pin, if (elmore_exists) { if (drvr_library_ && drvr_library_->wireSlewDegradationTable(drvr_rf_)) { wire_delay1 = elmore; - load_slew1 = drvr_library_->degradeWireSlew(drvr_cell_, drvr_rf_, - pvt_, + load_slew1 = drvr_library_->degradeWireSlew(drvr_rf_, delayAsFloat(drvr_slew_), delayAsFloat(wire_delay1)); } diff --git a/dcalc/SlewDegradeDelayCalc.hh b/dcalc/SlewDegradeDelayCalc.hh index 97b39c5f..7195985d 100644 --- a/dcalc/SlewDegradeDelayCalc.hh +++ b/dcalc/SlewDegradeDelayCalc.hh @@ -16,10 +16,11 @@ #pragma once -#include "RCDelayCalc.hh" - namespace sta { +class ArcDelayCalc; +class StaState; + ArcDelayCalc * makeSlewDegradeDelayCalc(StaState *sta); diff --git a/dcalc/UnitDelayCalc.cc b/dcalc/UnitDelayCalc.cc index 20ddaf14..cc629ba5 100644 --- a/dcalc/UnitDelayCalc.cc +++ b/dcalc/UnitDelayCalc.cc @@ -61,8 +61,7 @@ UnitDelayCalc::inputPortDelay(const Pin *, } void -UnitDelayCalc::gateDelay(const LibertyCell *, - const TimingArc *, +UnitDelayCalc::gateDelay(const TimingArc *, const Slew &, float, const Parasitic *, @@ -75,6 +74,29 @@ UnitDelayCalc::gateDelay(const LibertyCell *, drvr_slew = 0.0; } +void +UnitDelayCalc::findParallelGateDelays(const MultiDrvrNet *, + GraphDelayCalc *) +{ +} + +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) +{ + gate_delay = units_->timeUnit()->scale(); + gate_slew = 0.0; +} + void UnitDelayCalc::loadDelay(const Pin *, ArcDelay &wire_delay, @@ -85,8 +107,7 @@ UnitDelayCalc::loadDelay(const Pin *, } float -UnitDelayCalc::ceff(const LibertyCell *, - const TimingArc *, +UnitDelayCalc::ceff(const TimingArc *, const Slew &, float, const Parasitic *, @@ -98,8 +119,7 @@ UnitDelayCalc::ceff(const LibertyCell *, } string -UnitDelayCalc::reportGateDelay(const LibertyCell *, - const TimingArc *, +UnitDelayCalc::reportGateDelay(const TimingArc *, const Slew &, float, const Parasitic *, @@ -114,8 +134,7 @@ UnitDelayCalc::reportGateDelay(const LibertyCell *, } void -UnitDelayCalc::checkDelay(const LibertyCell *, - const TimingArc *, +UnitDelayCalc::checkDelay(const TimingArc *, const Slew &, const Slew &, float, @@ -128,8 +147,7 @@ UnitDelayCalc::checkDelay(const LibertyCell *, } string -UnitDelayCalc::reportCheckDelay(const LibertyCell *, - const TimingArc *, +UnitDelayCalc::reportCheckDelay(const TimingArc *, const Slew &, const char *, const Slew &, diff --git a/dcalc/UnitDelayCalc.hh b/dcalc/UnitDelayCalc.hh index 1b7b22b9..6ecae7cf 100644 --- a/dcalc/UnitDelayCalc.hh +++ b/dcalc/UnitDelayCalc.hh @@ -35,8 +35,7 @@ public: const RiseFall *rf, const Parasitic *parasitic, const DcalcAnalysisPt *dcalc_ap) override; - void gateDelay(const LibertyCell *drvr_cell, - const TimingArc *arc, + void gateDelay(const TimingArc *arc, const Slew &in_slew, float load_cap, const Parasitic *drvr_parasitic, @@ -46,21 +45,32 @@ public: // 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, + 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; - void setMultiDrvrSlewFactor(float) override {} - float ceff(const LibertyCell *drvr_cell, - const TimingArc *arc, + 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 LibertyCell *cell, - const TimingArc *arc, + void checkDelay(const TimingArc *arc, const Slew &from_slew, const Slew &to_slew, float related_out_cap, @@ -68,8 +78,7 @@ public: const DcalcAnalysisPt *dcalc_ap, // Return values. ArcDelay &margin) override; - string reportGateDelay(const LibertyCell *drvr_cell, - const TimingArc *arc, + string reportGateDelay(const TimingArc *arc, const Slew &in_slew, float load_cap, const Parasitic *drvr_parasitic, @@ -77,8 +86,7 @@ public: const Pvt *pvt, const DcalcAnalysisPt *dcalc_ap, int digits) override; - string reportCheckDelay(const LibertyCell *cell, - const TimingArc *arc, + string reportCheckDelay(const TimingArc *arc, const Slew &from_slew, const char *from_slew_annotation, const Slew &to_slew, diff --git a/graph/Graph.cc b/graph/Graph.cc index 8d5bc4ee..29af550a 100644 --- a/graph/Graph.cc +++ b/graph/Graph.cc @@ -783,8 +783,8 @@ Graph::setWireArcDelay(Edge *edge, } bool -Graph::arcDelayAnnotated(Edge *edge, - TimingArc *arc, +Graph::arcDelayAnnotated(const Edge *edge, + const TimingArc *arc, DcalcAPIndex ap_index) const { if (arc_delay_annotated_.size()) { @@ -799,7 +799,7 @@ Graph::arcDelayAnnotated(Edge *edge, void Graph::setArcDelayAnnotated(Edge *edge, - TimingArc *arc, + const TimingArc *arc, DcalcAPIndex ap_index, bool annotated) { diff --git a/include/sta/ArcDelayCalc.hh b/include/sta/ArcDelayCalc.hh index 37ed4baf..c1c6617b 100644 --- a/include/sta/ArcDelayCalc.hh +++ b/include/sta/ArcDelayCalc.hh @@ -17,6 +17,7 @@ #pragma once #include +#include #include "MinMax.hh" #include "LibertyClass.hh" @@ -28,22 +29,26 @@ namespace sta { using std::string; +using std::vector; class Parasitic; class DcalcAnalysisPt; +class MultiDrvrNet; // Delay calculator class hierarchy. // ArcDelayCalc // UnitDelayCalc -// LumpedCapDelayCalc -// RCDelayCalc -// SlewDegradeDelayCalc -// DmpCeffDelayCalc -// DmpCeffElmoreDelayCalc -// DmpCeffTwoPoleDelayCalc -// ArnoldiDelayCalc +// DelayCalcBase +// ParallelDelayCalc +// LumpedCapDelayCalc +// SlewDegradeDelayCalc +// DmpCeffDelayCalc +// DmpCeffElmoreDelayCalc +// DmpCeffTwoPoleDelayCalc +// ArnoldiDelayCalc -// Abstract class to interface to a delay calculator primitive. +// Abstract class for the graph delay calculator traversal to interface +// to a delay calculator primitive. class ArcDelayCalc : public StaState { public: @@ -66,8 +71,7 @@ public: const DcalcAnalysisPt *dcalc_ap) = 0; // Find the delay and slew for arc driving drvr_pin. - virtual void gateDelay(const LibertyCell *drvr_cell, - const TimingArc *arc, + virtual void gateDelay(const TimingArc *arc, const Slew &in_slew, // Pass in load_cap or drvr_parasitic. float load_cap, @@ -78,16 +82,29 @@ public: // Return values. ArcDelay &gate_delay, Slew &drvr_slew) = 0; + // 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; - virtual void setMultiDrvrSlewFactor(float factor) = 0; // Ceff for parasitics with pi models. - virtual float ceff(const LibertyCell *drvr_cell, - const TimingArc *arc, + virtual float ceff(const TimingArc *arc, const Slew &in_slew, float load_cap, const Parasitic *drvr_parasitic, @@ -97,8 +114,7 @@ public: // 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 LibertyCell *drvr_cell, - const TimingArc *arc, + virtual void checkDelay(const TimingArc *arc, const Slew &from_slew, const Slew &to_slew, float related_out_cap, @@ -107,8 +123,7 @@ public: // Return values. ArcDelay &margin) = 0; // Report delay and slew calculation. - virtual string reportGateDelay(const LibertyCell *drvr_cell, - const TimingArc *arc, + virtual string reportGateDelay(const TimingArc *arc, const Slew &in_slew, // Pass in load_cap or drvr_parasitic. float load_cap, @@ -118,8 +133,7 @@ public: const DcalcAnalysisPt *dcalc_ap, int digits) = 0; // Report timing check delay calculation. - virtual string reportCheckDelay(const LibertyCell *cell, - const TimingArc *arc, + virtual string reportCheckDelay(const TimingArc *arc, const Slew &from_slew, const char *from_slew_annotation, const Slew &to_slew, diff --git a/include/sta/Graph.hh b/include/sta/Graph.hh index 247b5bcf..d2dea625 100644 --- a/include/sta/Graph.hh +++ b/include/sta/Graph.hh @@ -157,11 +157,11 @@ public: DcalcAPIndex ap_index, const ArcDelay &delay); // Is timing arc delay annotated. - bool arcDelayAnnotated(Edge *edge, - TimingArc *arc, + bool arcDelayAnnotated(const Edge *edge, + const TimingArc *arc, DcalcAPIndex ap_index) const; void setArcDelayAnnotated(Edge *edge, - TimingArc *arc, + const TimingArc *arc, DcalcAPIndex ap_index, bool annotated); bool wireDelayAnnotated(Edge *edge, @@ -539,7 +539,6 @@ class VertexSet : public Set { public: VertexSet(Graph *&graph); - VertexSet(const VertexSet &set); }; } // namespace diff --git a/include/sta/GraphDelayCalc.hh b/include/sta/GraphDelayCalc.hh index 67dfc15e..da47b31e 100644 --- a/include/sta/GraphDelayCalc.hh +++ b/include/sta/GraphDelayCalc.hh @@ -16,6 +16,8 @@ #pragma once +#include + #include "Map.hh" #include "NetworkClass.hh" #include "GraphClass.hh" @@ -26,9 +28,12 @@ namespace sta { +using std::vector; + class DelayCalcObserver; class MultiDrvrNet; class FindVertexDelays; +class NetCaps; typedef Map MultiDrvrNetMap; @@ -55,8 +60,8 @@ public: // Find and annotate drvr_vertex gate and load delays/slews. virtual void findDelays(Vertex *drvr_vertex); // Returned string is owned by the caller. - virtual string reportDelayCalc(Edge *edge, - TimingArc *arc, + virtual string reportDelayCalc(const Edge *edge, + const TimingArc *arc, const Corner *corner, const MinMax *min_max, int digits); @@ -85,6 +90,11 @@ public: const Parasitic *drvr_parasitic, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) const; + float loadCap(const Pin *drvr_pin, + const Parasitic *drvr_parasitic, + const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap, + const MultiDrvrNet *multi_drvr) const; virtual void netCaps(const Pin *drvr_pin, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap, @@ -115,10 +125,13 @@ public: float &min_period, bool &exists); + Slew edgeFromSlew(const Vertex *from_vertex, + const RiseFall *from_rf, + const Edge *edge, + const DcalcAnalysisPt *dcalc_ap); + protected: void seedInvalidDelays(); - void ensureMultiDrvrNetsFound(); - void makeMultiDrvrNet(PinSet &drvr_pins); void initSlew(Vertex *vertex); void seedRootSlew(Vertex *vertex, ArcDelayCalc *arc_delay_calc); @@ -150,23 +163,23 @@ protected: const LibertyPort *to_port); int findPortIndex(const LibertyCell *cell, const LibertyPort *port); - void findInputArcDelay(const LibertyCell *drvr_cell, - const Pin *drvr_pin, + void findInputArcDelay(const Pin *drvr_pin, Vertex *drvr_vertex, const TimingArc *arc, float from_slew, const DcalcAnalysisPt *dcalc_ap); bool findDriverDelays(Vertex *drvr_vertex, ArcDelayCalc *arc_delay_calc); + MultiDrvrNet *findMultiDrvrNet(Vertex *drvr_pin); + MultiDrvrNet *makeMultiDrvrNet(PinSet &drvr_pins); bool findDriverDelays1(Vertex *drvr_vertex, MultiDrvrNet *multi_drvr, ArcDelayCalc *arc_delay_calc); void initLoadSlews(Vertex *drvr_vertex); - bool findDriverEdgeDelays(LibertyCell *drvr_cell, - Instance *drvr_inst, + bool findDriverEdgeDelays(const Instance *drvr_inst, const Pin *drvr_pin, Vertex *drvr_vertex, - MultiDrvrNet *multi_drvr, + const MultiDrvrNet *multi_drvr, Edge *edge, ArcDelayCalc *arc_delay_calc); void initWireDelays(Vertex *drvr_vertex); @@ -176,17 +189,16 @@ protected: ArcDelayCalc *arc_delay_calc, bool propagate); void enqueueTimingChecksEdges(Vertex *vertex); - bool findArcDelay(LibertyCell *drvr_cell, - const Pin *drvr_pin, + bool findArcDelay(const Pin *drvr_pin, Vertex *drvr_vertex, - MultiDrvrNet *multi_drvr, - TimingArc *arc, - Parasitic *drvr_parasitic, + 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); void annotateLoadDelays(Vertex *drvr_vertex, const RiseFall *drvr_rf, @@ -197,32 +209,7 @@ protected: void findLatchEdgeDelays(Edge *edge); void findCheckEdgeDelays(Edge *edge, ArcDelayCalc *arc_delay_calc); - void findMultiDrvrGateDelay(MultiDrvrNet *multi_drvr, - const RiseFall *drvr_rf, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - ArcDelayCalc *arc_delay_calc, - // Return values. - ArcDelay ¶llel_delay, - Slew ¶llel_slew); - void parallelGateDelay(MultiDrvrNet *multi_drvr, - LibertyCell *drvr_cell, - const Pin *drvr_pin, - TimingArc *arc, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - const Slew from_slew, - Parasitic *drvr_parasitic, - float related_out_cap, - ArcDelayCalc *arc_delay_calc, - // Return values. - ArcDelay &gate_delay, - Slew &gate_slew); void deleteMultiDrvrNets(); - Slew edgeFromSlew(const Vertex *from_vertex, - const RiseFall *from_rf, - const Edge *edge, - const DcalcAnalysisPt *dcalc_ap); Slew checkEdgeClkSlew(const Vertex *from_vertex, const RiseFall *from_rf, const DcalcAnalysisPt *dcalc_ap); @@ -233,11 +220,6 @@ protected: // Return values. float &pin_cap, float &wire_cap) const; - float loadCap(const Pin *drvr_pin, - MultiDrvrNet *multi_drvr, - const Parasitic *drvr_parasitic, - const RiseFall *rf, - const DcalcAnalysisPt *dcalc_ap) const; // Observer for edge delay changes. DelayCalcObserver *observer_; @@ -277,4 +259,33 @@ public: virtual void checkDelayChangedTo(Vertex *vertex) = 0; }; +// Nets with multiple drivers (tristate, bidirect or output). +// Cache net caps to prevent N^2 net pin walk. +class MultiDrvrNet +{ +public: + MultiDrvrNet(VertexSet *drvrs); + ~MultiDrvrNet(); + const VertexSet *drvrs() const { return drvrs_; } + VertexSet *drvrs() { return drvrs_; } + bool parallelGates(const Network *network) const; + Vertex *dcalcDrvr() const { return dcalc_drvr_; } + void setDcalcDrvr(Vertex *drvr); + void netCaps(const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap, + // Return values. + float &pin_cap, + float &wire_cap, + float &fanout, + bool &has_net_load) const; + void findCaps(const Sdc *sdc); + +private: + // Driver that triggers delay calculation for all the drivers on the net. + Vertex *dcalc_drvr_; + VertexSet *drvrs_; + // [drvr_rf->index][dcalc_ap->index] + vector net_caps_; +}; + } // namespace diff --git a/include/sta/Liberty.hh b/include/sta/Liberty.hh index 0924ebd9..14dab380 100644 --- a/include/sta/Liberty.hh +++ b/include/sta/Liberty.hh @@ -167,16 +167,14 @@ public: const LibertyCell *cell, const Pvt *pvt) const; float scaleFactor(ScaleFactorType type, - int tr_index, + int rf_index, const LibertyCell *cell, const Pvt *pvt) const; void setWireSlewDegradationTable(TableModel *model, RiseFall *rf); TableModel *wireSlewDegradationTable(const RiseFall *rf) const; - float degradeWireSlew(const LibertyCell *cell, - const RiseFall *rf, - const Pvt *pvt, + float degradeWireSlew(const RiseFall *rf, float in_slew, float wire_delay) const; // Check for supported axis variables. @@ -323,9 +321,7 @@ public: void addDriverWaveform(DriverWaveform *driver_waveform); protected: - float degradeWireSlew(const LibertyCell *cell, - const Pvt *pvt, - const TableModel *model, + float degradeWireSlew(const TableModel *model, float in_slew, float wire_delay) const; @@ -925,7 +921,7 @@ public: RiseFall *rf); float scale(ScaleFactorType type, ScaleFactorPvt pvt, - int tr_index); + int rf_index); float scale(ScaleFactorType type, ScaleFactorPvt pvt); void setScale(ScaleFactorType type, diff --git a/include/sta/LinearModel.hh b/include/sta/LinearModel.hh index f06558e0..25f1988c 100644 --- a/include/sta/LinearModel.hh +++ b/include/sta/LinearModel.hh @@ -23,9 +23,10 @@ namespace sta { class GateLinearModel : public GateTimingModel { public: - GateLinearModel(float intrinsic, float resistance); - void gateDelay(const LibertyCell *cell, - const Pvt *pvt, + GateLinearModel(LibertyCell *cell, + float intrinsic, + float resistance); + void gateDelay(const Pvt *pvt, float in_slew, float load_cap, float related_out_cap, @@ -33,15 +34,13 @@ public: // Return values. ArcDelay &gate_delay, Slew &drvr_slew) const override; - string reportGateDelay(const LibertyCell *cell, - const Pvt *pvt, + 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 LibertyCell *cell, - const Pvt *pvt) const override; + float driveResistance(const Pvt *pvt) const override; protected: void setIsScaled(bool is_scaled) override; @@ -53,17 +52,16 @@ protected: class CheckLinearModel : public CheckTimingModel { public: - explicit CheckLinearModel(float intrinsic); - void checkDelay(const LibertyCell *cell, - const Pvt *pvt, + 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; - string reportCheckDelay(const LibertyCell *cell, - const Pvt *pvt, + string reportCheckDelay(const Pvt *pvt, float from_slew, const char *from_slew_annotation, float to_slew, diff --git a/include/sta/Sdc.hh b/include/sta/Sdc.hh index c6ddeaef..eb471f20 100644 --- a/include/sta/Sdc.hh +++ b/include/sta/Sdc.hh @@ -827,7 +827,8 @@ public: // Returns nullptr if set_operating_conditions has not been called. OperatingConditions *operatingConditions(const MinMax *min_max); // Instance specific process/voltage/temperature. - const Pvt *pvt(Instance *inst, const MinMax *min_max) const; + const Pvt *pvt(const Instance *inst, + const MinMax *min_max) const; // Pvt may be shared among multiple instances. void setPvt(const Instance *inst, const MinMaxAll *min_max, diff --git a/include/sta/TableModel.hh b/include/sta/TableModel.hh index 0ec14588..81b03895 100644 --- a/include/sta/TableModel.hh +++ b/include/sta/TableModel.hh @@ -51,15 +51,15 @@ tableVariableUnit(TableAxisVariable variable, class GateTableModel : public GateTimingModel { public: - GateTableModel(TableModel *delay_model, + GateTableModel(LibertyCell *cell, + TableModel *delay_model, TableModel *delay_sigma_models[EarlyLate::index_count], TableModel *slew_model, TableModel *slew_sigma_models[EarlyLate::index_count], ReceiverModelPtr receiver_model, OutputWaveforms *output_waveforms); virtual ~GateTableModel(); - void gateDelay(const LibertyCell *cell, - const Pvt *pvt, + void gateDelay(const Pvt *pvt, float in_slew, float load_cap, float related_out_cap, @@ -67,15 +67,13 @@ public: // Return values. ArcDelay &gate_delay, Slew &drvr_slew) const override; - string reportGateDelay(const LibertyCell *cell, - const Pvt *pvt, + 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 LibertyCell *cell, - const Pvt *pvt) const override; + float driveResistance(const Pvt *pvt) const override; const TableModel *delayModel() const { return delay_model_; } const TableModel *slewModel() const { return slew_model_; } @@ -86,8 +84,7 @@ public: static bool checkAxes(const TablePtr table); protected: - void maxCapSlew(const LibertyCell *cell, - float in_slew, + void maxCapSlew(float in_slew, const Pvt *pvt, float &slew, float &cap) const; @@ -96,16 +93,12 @@ protected: float load_cap, float in_slew, float related_out_cap) const; - float findValue(const LibertyLibrary *library, - const LibertyCell *cell, - const Pvt *pvt, + float findValue(const Pvt *pvt, const TableModel *model, float in_slew, float load_cap, float related_out_cap) const; string reportTableLookup(const char *result_name, - const LibertyLibrary *library, - const LibertyCell *cell, const Pvt *pvt, const TableModel *model, float in_slew, @@ -133,19 +126,18 @@ protected: class CheckTableModel : public CheckTimingModel { public: - explicit CheckTableModel(TableModel *model, + explicit CheckTableModel(LibertyCell *cell, + TableModel *model, TableModel *sigma_models[EarlyLate::index_count]); virtual ~CheckTableModel(); - void checkDelay(const LibertyCell *cell, - const Pvt *pvt, + void checkDelay(const Pvt *pvt, float from_slew, float to_slew, float related_out_cap, bool pocv_enabled, // Return values. ArcDelay &margin) const override; - string reportCheckDelay(const LibertyCell *cell, - const Pvt *pvt, + string reportCheckDelay(const Pvt *pvt, float from_slew, const char *from_slew_annotation, float to_slew, @@ -160,9 +152,7 @@ public: protected: void setIsScaled(bool is_scaled) override; - float findValue(const LibertyLibrary *library, - const LibertyCell *cell, - const Pvt *pvt, + float findValue(const Pvt *pvt, const TableModel *model, float from_slew, float to_slew, @@ -179,8 +169,6 @@ protected: float in_slew, float related_out_cap) const; string reportTableDelay(const char *result_name, - const LibertyLibrary *library, - const LibertyCell *cell, const Pvt *pvt, const TableModel *model, float from_slew, @@ -217,14 +205,12 @@ public: float value2, float value3) const; // Table interpolated lookup with scale factor. - float findValue(const LibertyLibrary *library, - const LibertyCell *cell, + float findValue(const LibertyCell *cell, const Pvt *pvt, float value1, float value2, float value3) const; string reportValue(const char *result_name, - const LibertyLibrary *library, const LibertyCell *cell, const Pvt *pvt, float value1, @@ -237,11 +223,9 @@ public: Report *report) const; protected: - float scaleFactor(const LibertyLibrary *library, - const LibertyCell *cell, + float scaleFactor(const LibertyCell *cell, const Pvt *pvt) const; - string reportPvtScaleFactor(const LibertyLibrary *library, - const LibertyCell *cell, + string reportPvtScaleFactor(const LibertyCell *cell, const Pvt *pvt, int digits) const; @@ -280,7 +264,6 @@ public: float axis_value2, float axis_value3) const; virtual string reportValue(const char *result_name, - const LibertyLibrary *library, const LibertyCell *cell, const Pvt *pvt, float value1, @@ -306,7 +289,6 @@ public: float axis_value2, float axis_value3) const override; string reportValue(const char *result_name, - const LibertyLibrary *library, const LibertyCell *cell, const Pvt *pvt, float value1, @@ -342,7 +324,6 @@ public: float value2, float value3) const override; string reportValue(const char *result_name, - const LibertyLibrary *library, const LibertyCell *cell, const Pvt *pvt, float value1, @@ -389,7 +370,6 @@ public: float value2, float value3) const override; string reportValue(const char *result_name, - const LibertyLibrary *library, const LibertyCell *cell, const Pvt *pvt, float value1, @@ -436,7 +416,6 @@ public: float value2, float value3) const override; string reportValue(const char *result_name, - const LibertyLibrary *library, const LibertyCell *cell, const Pvt *pvt, float value1, diff --git a/include/sta/TimingModel.hh b/include/sta/TimingModel.hh index 94604d78..e6b2fd04 100644 --- a/include/sta/TimingModel.hh +++ b/include/sta/TimingModel.hh @@ -29,21 +29,21 @@ using std::string; class TimingModel { public: + TimingModel(LibertyCell *cell); virtual ~TimingModel() {} - -protected: virtual void setIsScaled(bool is_scaled) = 0; - friend class LibertyCell; +protected: + LibertyCell *cell_; }; // Abstract base class for LinearModel and TableModel. class GateTimingModel : public TimingModel { public: + GateTimingModel(LibertyCell *cell); // Gate delay calculation. - virtual void gateDelay(const LibertyCell *cell, - const Pvt *pvt, + virtual void gateDelay(const Pvt *pvt, float in_slew, float load_cap, float related_out_cap, @@ -51,32 +51,29 @@ public: // Return values. ArcDelay &gate_delay, Slew &drvr_slew) const = 0; - virtual string reportGateDelay(const LibertyCell *cell, - const Pvt *pvt, + 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 LibertyCell *cell, - const Pvt *pvt) const = 0; + virtual float driveResistance(const Pvt *pvt) const = 0; }; // Abstract base class for timing check timing models. class CheckTimingModel : public TimingModel { public: + CheckTimingModel(LibertyCell *cell); // Timing check margin delay calculation. - virtual void checkDelay(const LibertyCell *cell, - const Pvt *pvt, + 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 string reportCheckDelay(const LibertyCell *cell, - const Pvt *pvt, + virtual string reportCheckDelay(const Pvt *pvt, float from_slew, const char *from_slew_annotation, float to_slew, diff --git a/liberty/InternalPower.cc b/liberty/InternalPower.cc index efa6afce..4c251eb4 100644 --- a/liberty/InternalPower.cc +++ b/liberty/InternalPower.cc @@ -131,9 +131,7 @@ InternalPowerModel::power(const LibertyCell *cell, float axis_value1, axis_value2, axis_value3; findAxisValues(in_slew, load_cap, axis_value1, axis_value2, axis_value3); - const LibertyLibrary *library = cell->libertyLibrary(); - return model_->findValue(library, cell, pvt, - axis_value1, axis_value2, axis_value3); + return model_->findValue(cell, pvt, axis_value1, axis_value2, axis_value3); } else return 0.0; @@ -151,8 +149,8 @@ InternalPowerModel::reportPower(const LibertyCell *cell, findAxisValues(in_slew, load_cap, axis_value1, axis_value2, axis_value3); const LibertyLibrary *library = cell->libertyLibrary(); - return model_->reportValue("Power", library, cell, pvt, - axis_value1, nullptr, axis_value2, axis_value3, + return model_->reportValue("Power", cell, pvt, axis_value1, nullptr, + axis_value2, axis_value3, library->units()->powerUnit(), digits); } return ""; diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index 5d5e3535..6e8a91c0 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -94,12 +94,12 @@ LibertyLibrary::LibertyLibrary(const char *name, addTableTemplate(scalar_template, type); } - for (auto tr_index : RiseFall::rangeIndex()) { - wire_slew_degradation_tbls_[tr_index] = nullptr; - input_threshold_[tr_index] = input_threshold_default_; - output_threshold_[tr_index] = output_threshold_default_; - slew_lower_threshold_[tr_index] = slew_lower_threshold_default_; - slew_upper_threshold_[tr_index] = slew_upper_threshold_default_; + for (auto rf_index : RiseFall::rangeIndex()) { + wire_slew_degradation_tbls_[rf_index] = nullptr; + input_threshold_[rf_index] = input_threshold_default_; + output_threshold_[rf_index] = output_threshold_default_; + slew_lower_threshold_[rf_index] = slew_lower_threshold_default_; + slew_upper_threshold_[rf_index] = slew_upper_threshold_default_; } } @@ -111,8 +111,8 @@ LibertyLibrary::~LibertyLibrary() scale_factors_map_.deleteContents(); delete scale_factors_; - for (auto tr_index : RiseFall::rangeIndex()) { - TableModel *model = wire_slew_degradation_tbls_[tr_index]; + for (auto rf_index : RiseFall::rangeIndex()) { + TableModel *model = wire_slew_degradation_tbls_[rf_index]; delete model; } operating_conditions_.deleteContents(); @@ -289,7 +289,7 @@ LibertyLibrary::scaleFactor(ScaleFactorType type, float LibertyLibrary::scaleFactor(ScaleFactorType type, - int tr_index, + int rf_index, const LibertyCell *cell, const Pvt *pvt) const { @@ -299,18 +299,18 @@ LibertyLibrary::scaleFactor(ScaleFactorType type, // All scale factors are unity for nominal pvt. if (pvt) { ScaleFactors *scale_factors = nullptr; - // Cell level scale factors have precidence over library scale factors. + // Cell level scale factors have precedence over library scale factors. if (cell) scale_factors = cell->scaleFactors(); if (scale_factors == nullptr) scale_factors = scale_factors_; if (scale_factors) { float process_scale = 1.0F + (pvt->process() - nominal_process_) - * scale_factors->scale(type, ScaleFactorPvt::process, tr_index); + * scale_factors->scale(type, ScaleFactorPvt::process, rf_index); float temp_scale = 1.0F + (pvt->temperature() - nominal_temperature_) - * scale_factors->scale(type, ScaleFactorPvt::temp, tr_index); + * scale_factors->scale(type, ScaleFactorPvt::temp, rf_index); float volt_scale = 1.0F + (pvt->voltage() - nominal_voltage_) - * scale_factors->scale(type, ScaleFactorPvt::volt, tr_index); + * scale_factors->scale(type, ScaleFactorPvt::volt, rf_index); float scale = process_scale * temp_scale * volt_scale; return scale; } @@ -322,10 +322,10 @@ void LibertyLibrary::setWireSlewDegradationTable(TableModel *model, RiseFall *rf) { - int tr_index = rf->index(); - if (wire_slew_degradation_tbls_[tr_index]) - delete wire_slew_degradation_tbls_[tr_index]; - wire_slew_degradation_tbls_[tr_index] = model; + int rf_index = rf->index(); + if (wire_slew_degradation_tbls_[rf_index]) + delete wire_slew_degradation_tbls_[rf_index]; + wire_slew_degradation_tbls_[rf_index] = model; } TableModel * @@ -335,36 +335,32 @@ LibertyLibrary::wireSlewDegradationTable(const RiseFall *rf) const } float -LibertyLibrary::degradeWireSlew(const LibertyCell *cell, - const RiseFall *rf, - const Pvt *pvt, +LibertyLibrary::degradeWireSlew(const RiseFall *rf, float in_slew, float wire_delay) const { const TableModel *model = wireSlewDegradationTable(rf); if (model) - return degradeWireSlew(cell, pvt, model, in_slew, wire_delay); + return degradeWireSlew(model, in_slew, wire_delay); else return in_slew; } float -LibertyLibrary::degradeWireSlew(const LibertyCell *cell, - const Pvt *pvt, - const TableModel *model, +LibertyLibrary::degradeWireSlew(const TableModel *model, float in_slew, float wire_delay) const { switch (model->order()) { case 0: - return model->findValue(this, cell, pvt, 0.0, 0.0, 0.0); + return model->findValue(0.0, 0.0, 0.0); case 1: { TableAxisPtr axis1 = model->axis1(); TableAxisVariable var1 = axis1->variable(); if (var1 == TableAxisVariable::output_pin_transition) - return model->findValue(this, cell, pvt, in_slew, 0.0, 0.0); + return model->findValue(in_slew, 0.0, 0.0); else if (var1 == TableAxisVariable::connect_delay) - return model->findValue(this, cell, pvt, wire_delay, 0.0, 0.0); + return model->findValue(wire_delay, 0.0, 0.0); else { criticalError(231, "unsupported slew degradation table axes"); return 0.0; @@ -377,10 +373,10 @@ LibertyLibrary::degradeWireSlew(const LibertyCell *cell, TableAxisVariable var2 = axis2->variable(); if (var1 == TableAxisVariable::output_pin_transition && var2 == TableAxisVariable::connect_delay) - return model->findValue(this, cell, pvt, in_slew, wire_delay, 0.0); + return model->findValue(in_slew, wire_delay, 0.0); else if (var1 == TableAxisVariable::connect_delay && var2 == TableAxisVariable::output_pin_transition) - return model->findValue(this, cell, pvt, wire_delay, in_slew, 0.0); + return model->findValue(wire_delay, in_slew, 0.0); else { criticalError(232, "unsupported slew degradation table axes"); return 0.0; @@ -2580,8 +2576,7 @@ LibertyPort::clockTreePathDelays() GateTimingModel *gate_model = dynamic_cast(model); ArcDelay delay; Slew slew; - gate_model->gateDelay(liberty_cell_, nullptr, 0.0, 0.0, 0.0, false, - delay, slew); + gate_model->gateDelay(nullptr, 0.0, 0.0, 0.0, false, delay, slew); const RiseFall *rf = arc->toEdge()->asRiseFall(); const MinMax *min_max = (role == TimingRole::clockTreePathMin()) ? MinMax::min() @@ -2911,8 +2906,8 @@ ScaleFactors::ScaleFactors(const char *name) : { for (int type = 0; type < scale_factor_type_count; type++) { for (int pvt = 0; pvt < scale_factor_pvt_count; pvt++) { - for (auto tr_index : RiseFall::rangeIndex()) { - scales_[type][pvt][tr_index] = 0.0; + for (auto rf_index : RiseFall::rangeIndex()) { + scales_[type][pvt][rf_index] = 0.0; } } } @@ -2951,9 +2946,9 @@ ScaleFactors::scale(ScaleFactorType type, float ScaleFactors::scale(ScaleFactorType type, ScaleFactorPvt pvt, - int tr_index) + int rf_index) { - return scales_[int(type)][int(pvt)][tr_index]; + return scales_[int(type)][int(pvt)][rf_index]; } float @@ -3050,9 +3045,9 @@ OcvDerate::OcvDerate(const char *name) : name_(name) { for (auto el_index : EarlyLate::rangeIndex()) { - for (auto tr_index : RiseFall::rangeIndex()) { - derate_[tr_index][el_index][int(PathType::clk)] = nullptr; - derate_[tr_index][el_index][int(PathType::data)] = nullptr; + for (auto rf_index : RiseFall::rangeIndex()) { + derate_[rf_index][el_index][int(PathType::clk)] = nullptr; + derate_[rf_index][el_index][int(PathType::data)] = nullptr; } } } diff --git a/liberty/LibertyReader.cc b/liberty/LibertyReader.cc index 0bef2ef2..049d345c 100644 --- a/liberty/LibertyReader.cc +++ b/liberty/LibertyReader.cc @@ -1939,7 +1939,7 @@ void LibertyReader::makeTimingArcs(PortGroup *port_group) { for (TimingGroup *timing : port_group->timingGroups()) { - timing->makeTimingModels(library_, this); + timing->makeTimingModels(cell_, this); for (LibertyPort *port : *port_group->ports()) makeTimingArcs(port, timing); @@ -2204,15 +2204,15 @@ LibertyReader::makeTimingArcs(LibertyPort *to_port, } void -TimingGroup::makeTimingModels(LibertyLibrary *library, +TimingGroup::makeTimingModels(LibertyCell *cell, LibertyReader *visitor) { - switch (library->delayModelType()) { + switch (cell->libertyLibrary()->delayModelType()) { case DelayModelType::cmos_linear: - makeLinearModels(library); + makeLinearModels(cell); break; case DelayModelType::table: - makeTableModels(visitor); + makeTableModels(cell, visitor); break; case DelayModelType::cmos_pwl: case DelayModelType::cmos2: @@ -2223,8 +2223,9 @@ TimingGroup::makeTimingModels(LibertyLibrary *library, } void -TimingGroup::makeLinearModels(LibertyLibrary *library) +TimingGroup::makeLinearModels(LibertyCell *cell) { + LibertyLibrary *library = cell->libertyLibrary(); for (auto rf : RiseFall::range()) { int rf_index = rf->index(); float intr = intrinsic_[rf_index]; @@ -2234,7 +2235,7 @@ TimingGroup::makeLinearModels(LibertyLibrary *library) TimingModel *model = nullptr; if (timingTypeIsCheck(attrs_->timingType())) { if (intr_exists) - model = new CheckLinearModel(intr); + model = new CheckLinearModel(cell, intr); } else { float res = resistance_[rf_index]; @@ -2245,22 +2246,23 @@ TimingGroup::makeLinearModels(LibertyLibrary *library) if (!res_exists) res = 0.0F; if (intr_exists) - model = new GateLinearModel(intr, res); + model = new GateLinearModel(cell, intr, res); } attrs_->setModel(rf, model); } } void -TimingGroup::makeTableModels(LibertyReader *reader) +TimingGroup::makeTableModels(LibertyCell *cell, + LibertyReader *reader) { for (auto rf : RiseFall::range()) { int rf_index = rf->index(); - TableModel *cell = cell_[rf_index]; + TableModel *delay = cell_[rf_index]; TableModel *transition = transition_[rf_index]; TableModel *constraint = constraint_[rf_index]; - if (cell || transition) { - attrs_->setModel(rf, new GateTableModel(cell, delay_sigma_[rf_index], + if (delay || transition) { + attrs_->setModel(rf, new GateTableModel(cell, delay, delay_sigma_[rf_index], transition, slew_sigma_[rf_index], receiver_model_, @@ -2281,11 +2283,11 @@ TimingGroup::makeTableModels(LibertyReader *reader) || timing_type == TimingType::three_state_enable_rise) { if (transition == nullptr) reader->libWarn(95, line_, "missing %s_transition.", rf->name()); - if (cell == nullptr) + if (delay == nullptr) reader->libWarn(96, line_, "missing cell_%s.", rf->name()); } } else if (constraint) - attrs_->setModel(rf, new CheckTableModel(constraint, + attrs_->setModel(rf, new CheckTableModel(cell, constraint, constraint_sigma_[rf_index])); } } diff --git a/liberty/LibertyReaderPvt.hh b/liberty/LibertyReaderPvt.hh index 4a32067d..f99fa1f1 100644 --- a/liberty/LibertyReaderPvt.hh +++ b/liberty/LibertyReaderPvt.hh @@ -784,7 +784,7 @@ public: TableModel *transition(RiseFall *rf); void setTransition(RiseFall *rf, TableModel *model); - void makeTimingModels(LibertyLibrary *library, + void makeTimingModels(LibertyCell *cell, LibertyReader *visitor); void setDelaySigma(RiseFall *rf, EarlyLate *early_late, @@ -801,8 +801,9 @@ public: OutputWaveforms *output_current); protected: - void makeLinearModels(LibertyLibrary *library); - void makeTableModels(LibertyReader *reader); + void makeLinearModels(LibertyCell *cell); + void makeTableModels(LibertyCell *cell, + LibertyReader *reader); TimingArcAttrsPtr attrs_; const char *related_output_port_name_; diff --git a/liberty/LinearModel.cc b/liberty/LinearModel.cc index 6baa5671..1ba8ff8b 100644 --- a/liberty/LinearModel.cc +++ b/liberty/LinearModel.cc @@ -21,16 +21,17 @@ namespace sta { -GateLinearModel::GateLinearModel(float intrinsic, +GateLinearModel::GateLinearModel(LibertyCell *cell, + float intrinsic, float resistance) : + GateTimingModel(cell), intrinsic_(intrinsic), resistance_(resistance) { } void -GateLinearModel::gateDelay(const LibertyCell *, - const Pvt *, +GateLinearModel::gateDelay(const Pvt *, float, float load_cap, float, @@ -44,15 +45,14 @@ GateLinearModel::gateDelay(const LibertyCell *, } string -GateLinearModel::reportGateDelay(const LibertyCell *cell, - const Pvt *, +GateLinearModel::reportGateDelay(const Pvt *, float, float load_cap, float, bool, int digits) const { - const LibertyLibrary *library = cell->libertyLibrary(); + const LibertyLibrary *library = cell_->libertyLibrary(); const Units *units = library->units(); const Unit *time_unit = units->timeUnit(); const Unit *res_unit = units->resistanceUnit(); @@ -70,8 +70,7 @@ GateLinearModel::reportGateDelay(const LibertyCell *cell, } float -GateLinearModel::driveResistance(const LibertyCell *, - const Pvt *) const +GateLinearModel::driveResistance(const Pvt *) const { return resistance_; } @@ -81,14 +80,15 @@ GateLinearModel::setIsScaled(bool) { } -CheckLinearModel::CheckLinearModel(float intrinsic) : +CheckLinearModel::CheckLinearModel(LibertyCell *cell, + float intrinsic) : + CheckTimingModel(cell), intrinsic_(intrinsic) { } void -CheckLinearModel::checkDelay(const LibertyCell *, - const Pvt *, +CheckLinearModel::checkDelay(const Pvt *, float, float, float, @@ -99,8 +99,7 @@ CheckLinearModel::checkDelay(const LibertyCell *, } string -CheckLinearModel::reportCheckDelay(const LibertyCell *cell, - const Pvt *, +CheckLinearModel::reportCheckDelay(const Pvt *, float, const char *, float, @@ -108,7 +107,7 @@ CheckLinearModel::reportCheckDelay(const LibertyCell *cell, bool, int digits) const { - const LibertyLibrary *library = cell->libertyLibrary(); + const LibertyLibrary *library = cell_->libertyLibrary(); const Units *units = library->units(); const Unit *time_unit = units->timeUnit(); string result = "Check = "; diff --git a/liberty/TableModel.cc b/liberty/TableModel.cc index 57e9865a..7ec97126 100644 --- a/liberty/TableModel.cc +++ b/liberty/TableModel.cc @@ -34,19 +34,26 @@ using std::make_shared; static void deleteSigmaModels(TableModel *models[EarlyLate::index_count]); static string -reportPvt(const LibertyLibrary *library, - const Pvt *pvt, +reportPvt(const LibertyCell *cell, + const Pvt *pvt, int digits); static void appendSpaces(string &result, int count); -GateTableModel::GateTableModel(TableModel *delay_model, +TimingModel::TimingModel(LibertyCell *cell) : + cell_(cell) +{ +} + +GateTableModel::GateTableModel(LibertyCell *cell, + TableModel *delay_model, TableModel *delay_sigma_models[EarlyLate::index_count], TableModel *slew_model, TableModel *slew_sigma_models[EarlyLate::index_count], ReceiverModelPtr receiver_model, OutputWaveforms *output_waveforms) : + GateTimingModel(cell), delay_model_(delay_model), slew_model_(slew_model), receiver_model_(receiver_model), @@ -94,8 +101,7 @@ GateTableModel::setIsScaled(bool is_scaled) } void -GateTableModel::gateDelay(const LibertyCell *cell, - const Pvt *pvt, +GateTableModel::gateDelay(const Pvt *pvt, float in_slew, float load_cap, float related_out_cap, @@ -104,30 +110,23 @@ GateTableModel::gateDelay(const LibertyCell *cell, ArcDelay &gate_delay, Slew &drvr_slew) const { - const LibertyLibrary *library = cell->libertyLibrary(); - float delay = findValue(library, cell, pvt, delay_model_, in_slew, - load_cap, related_out_cap); + float delay = findValue(pvt, delay_model_, in_slew, load_cap, related_out_cap); float sigma_early = 0.0; float sigma_late = 0.0; if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()]) - sigma_early = findValue(library, cell, pvt, - delay_sigma_models_[EarlyLate::earlyIndex()], + sigma_early = findValue(pvt, delay_sigma_models_[EarlyLate::earlyIndex()], in_slew, load_cap, related_out_cap); if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()]) - sigma_late = findValue(library, cell, pvt, - delay_sigma_models_[EarlyLate::lateIndex()], + sigma_late = findValue(pvt, delay_sigma_models_[EarlyLate::lateIndex()], in_slew, load_cap, related_out_cap); gate_delay = makeDelay(delay, sigma_early, sigma_late); - float slew = findValue(library, cell, pvt, slew_model_, in_slew, - load_cap, related_out_cap); + float slew = findValue(pvt, slew_model_, in_slew, load_cap, related_out_cap); if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()]) - sigma_early = findValue(library, cell, pvt, - slew_sigma_models_[EarlyLate::earlyIndex()], + sigma_early = findValue(pvt, slew_sigma_models_[EarlyLate::earlyIndex()], in_slew, load_cap, related_out_cap); if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()]) - sigma_late = findValue(library, cell, pvt, - slew_sigma_models_[EarlyLate::lateIndex()], + sigma_late = findValue(pvt, slew_sigma_models_[EarlyLate::lateIndex()], in_slew, load_cap, related_out_cap); // Clip negative slews to zero. if (slew < 0.0) @@ -136,39 +135,36 @@ GateTableModel::gateDelay(const LibertyCell *cell, } string -GateTableModel::reportGateDelay(const LibertyCell *cell, - const Pvt *pvt, +GateTableModel::reportGateDelay(const Pvt *pvt, float in_slew, float load_cap, float related_out_cap, bool pocv_enabled, int digits) const { - const LibertyLibrary *library = cell->libertyLibrary(); - string result = reportPvt(library, pvt, digits); - result += reportTableLookup("Delay", library, cell, pvt, delay_model_, in_slew, + string result = reportPvt(cell_, pvt, digits); + result += reportTableLookup("Delay", pvt, delay_model_, in_slew, load_cap, related_out_cap, digits); if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()]) - result += reportTableLookup("Delay sigma(early)", library, cell, pvt, + result += reportTableLookup("Delay sigma(early)", pvt, delay_sigma_models_[EarlyLate::earlyIndex()], in_slew, load_cap, related_out_cap, digits); if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()]) - result += reportTableLookup("Delay sigma(late)", library, cell, pvt, + result += reportTableLookup("Delay sigma(late)", pvt, delay_sigma_models_[EarlyLate::lateIndex()], in_slew, load_cap, related_out_cap, digits); result += '\n'; - result += reportTableLookup("Slew", library, cell, pvt, slew_model_, in_slew, + result += reportTableLookup("Slew", pvt, slew_model_, in_slew, load_cap, related_out_cap, digits); if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()]) - result += reportTableLookup("Slew sigma(early)", library, cell, pvt, + result += reportTableLookup("Slew sigma(early)", pvt, slew_sigma_models_[EarlyLate::earlyIndex()], in_slew, load_cap, related_out_cap, digits); if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()]) - result += reportTableLookup("Slew sigma(late)", library, cell, pvt, + result += reportTableLookup("Slew sigma(late)", pvt, slew_sigma_models_[EarlyLate::lateIndex()], in_slew, load_cap, related_out_cap, digits); - float drvr_slew = findValue(library, cell, pvt, slew_model_, in_slew, - load_cap, related_out_cap); + float drvr_slew = findValue(pvt, slew_model_, in_slew, load_cap, related_out_cap); if (drvr_slew < 0.0) result += "Negative slew clipped to 0.0\n"; return result; @@ -176,8 +172,6 @@ GateTableModel::reportGateDelay(const LibertyCell *cell, string GateTableModel::reportTableLookup(const char *result_name, - const LibertyLibrary *library, - const LibertyCell *cell, const Pvt *pvt, const TableModel *model, float in_slew, @@ -189,17 +183,16 @@ GateTableModel::reportTableLookup(const char *result_name, float axis_value1, axis_value2, axis_value3; findAxisValues(model, in_slew, load_cap, related_out_cap, axis_value1, axis_value2, axis_value3); - return model->reportValue(result_name, library, cell, pvt, - axis_value1, nullptr, axis_value2, axis_value3, + const LibertyLibrary *library = cell_->libertyLibrary(); + return model->reportValue(result_name, cell_, pvt, axis_value1, nullptr, + axis_value2, axis_value3, library->units()->timeUnit(), digits); } return ""; } float -GateTableModel::findValue(const LibertyLibrary *library, - const LibertyCell *cell, - const Pvt *pvt, +GateTableModel::findValue(const Pvt *pvt, const TableModel *model, float in_slew, float load_cap, @@ -209,8 +202,7 @@ GateTableModel::findValue(const LibertyLibrary *library, float axis_value1, axis_value2, axis_value3; findAxisValues(model, in_slew, load_cap, related_out_cap, axis_value1, axis_value2, axis_value3); - return model->findValue(library, cell, pvt, - axis_value1, axis_value2, axis_value3); + return model->findValue(cell_, pvt, axis_value1, axis_value2, axis_value3); } else return 0.0; @@ -264,42 +256,36 @@ GateTableModel::findAxisValues(const TableModel *model, // Use slew/Cload for the highest Cload, which approximates output // admittance as the "drive". float -GateTableModel::driveResistance(const LibertyCell *cell, - const Pvt *pvt) const +GateTableModel::driveResistance(const Pvt *pvt) const { float slew, cap; - maxCapSlew(cell, 0.0, pvt, slew, cap); + maxCapSlew(0.0, pvt, slew, cap); return slew / cap; } void -GateTableModel::maxCapSlew(const LibertyCell *cell, - float in_slew, +GateTableModel::maxCapSlew(float in_slew, const Pvt *pvt, float &slew, float &cap) const { - const LibertyLibrary *library = cell->libertyLibrary(); TableAxisPtr axis1 = slew_model_->axis1(); TableAxisPtr axis2 = slew_model_->axis2(); TableAxisPtr axis3 = slew_model_->axis3(); if (axis1 && axis1->variable() == TableAxisVariable::total_output_net_capacitance) { cap = axis1->axisValue(axis1->size() - 1); - slew = findValue(library, cell, pvt, slew_model_, - in_slew, cap, 0.0); + slew = findValue(pvt, slew_model_, in_slew, cap, 0.0); } else if (axis2 && axis2->variable()==TableAxisVariable::total_output_net_capacitance) { cap = axis2->axisValue(axis2->size() - 1); - slew = findValue(library, cell, pvt, slew_model_, - in_slew, cap, 0.0); + slew = findValue(pvt, slew_model_, in_slew, cap, 0.0); } else if (axis3 && axis3->variable()==TableAxisVariable::total_output_net_capacitance) { cap = axis3->axisValue(axis3->size() - 1); - slew = findValue(library, cell, pvt, slew_model_, - in_slew, cap, 0.0); + slew = findValue(pvt, slew_model_, in_slew, cap, 0.0); } else { // Table not dependent on capacitance. @@ -399,8 +385,10 @@ ReceiverModel::checkAxes(TablePtr table) //////////////////////////////////////////////////////////////// -CheckTableModel::CheckTableModel(TableModel *model, +CheckTableModel::CheckTableModel(LibertyCell *cell, + TableModel *model, TableModel *sigma_models[EarlyLate::index_count]) : + CheckTimingModel(cell), model_(model) { for (auto el_index : EarlyLate::rangeIndex()) @@ -420,8 +408,7 @@ CheckTableModel::setIsScaled(bool is_scaled) } void -CheckTableModel::checkDelay(const LibertyCell *cell, - const Pvt *pvt, +CheckTableModel::checkDelay(const Pvt *pvt, float from_slew, float to_slew, float related_out_cap, @@ -430,18 +417,14 @@ CheckTableModel::checkDelay(const LibertyCell *cell, ArcDelay &margin) const { if (model_) { - const LibertyLibrary *library = cell->libertyLibrary(); - float mean = findValue(library, cell, pvt, model_, - from_slew, to_slew, related_out_cap); + float mean = findValue(pvt, model_, from_slew, to_slew, related_out_cap); float sigma_early = 0.0; float sigma_late = 0.0; if (pocv_enabled && sigma_models_[EarlyLate::earlyIndex()]) - sigma_early = findValue(library, cell, pvt, - sigma_models_[EarlyLate::earlyIndex()], + sigma_early = findValue(pvt, sigma_models_[EarlyLate::earlyIndex()], from_slew, to_slew, related_out_cap); if (pocv_enabled && sigma_models_[EarlyLate::lateIndex()]) - sigma_late = findValue(library, cell, pvt, - 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); } @@ -450,9 +433,7 @@ CheckTableModel::checkDelay(const LibertyCell *cell, } float -CheckTableModel::findValue(const LibertyLibrary *library, - const LibertyCell *cell, - const Pvt *pvt, +CheckTableModel::findValue(const Pvt *pvt, const TableModel *model, float from_slew, float to_slew, @@ -462,16 +443,14 @@ CheckTableModel::findValue(const LibertyLibrary *library, float axis_value1, axis_value2, axis_value3; findAxisValues(from_slew, to_slew, related_out_cap, axis_value1, axis_value2, axis_value3); - return model->findValue(library, cell, pvt, - axis_value1, axis_value2, axis_value3); + return model->findValue(cell_, pvt, axis_value1, axis_value2, axis_value3); } else return 0.0; } string -CheckTableModel::reportCheckDelay(const LibertyCell *cell, - const Pvt *pvt, +CheckTableModel::reportCheckDelay(const Pvt *pvt, float from_slew, const char *from_slew_annotation, float to_slew, @@ -479,17 +458,16 @@ CheckTableModel::reportCheckDelay(const LibertyCell *cell, bool pocv_enabled, int digits) const { - const LibertyLibrary *library = cell->libertyLibrary(); - string result = reportTableDelay("Check", library, cell, pvt, model_, + string result = reportTableDelay("Check", pvt, model_, from_slew, from_slew_annotation, to_slew, related_out_cap, digits); if (pocv_enabled && sigma_models_[EarlyLate::earlyIndex()]) - result += reportTableDelay("Check sigma early", library, cell, pvt, + result += reportTableDelay("Check sigma early", pvt, sigma_models_[EarlyLate::earlyIndex()], from_slew, from_slew_annotation, to_slew, related_out_cap, digits); if (pocv_enabled && sigma_models_[EarlyLate::lateIndex()]) - result += reportTableDelay("Check sigma late", library, cell, pvt, + result += reportTableDelay("Check sigma late", pvt, sigma_models_[EarlyLate::lateIndex()], from_slew, from_slew_annotation, to_slew, related_out_cap, digits); @@ -498,8 +476,6 @@ CheckTableModel::reportCheckDelay(const LibertyCell *cell, string CheckTableModel::reportTableDelay(const char *result_name, - const LibertyLibrary *library, - const LibertyCell *cell, const Pvt *pvt, const TableModel *model, float from_slew, @@ -512,10 +488,11 @@ CheckTableModel::reportTableDelay(const char *result_name, float axis_value1, axis_value2, axis_value3; findAxisValues(from_slew, to_slew, related_out_cap, axis_value1, axis_value2, axis_value3); - string result = reportPvt(library, pvt, digits); - result += model_->reportValue(result_name, library, cell, pvt, + string result = reportPvt(cell_, pvt, digits); + result += model_->reportValue(result_name, cell_, pvt, axis_value1, from_slew_annotation, axis_value2, - axis_value3, library->units()->timeUnit(), digits); + axis_value3, + cell_->libertyLibrary()->units()->timeUnit(), digits); return result; } return ""; @@ -665,20 +642,26 @@ TableModel::value(size_t axis_index1, } float -TableModel::findValue(const LibertyLibrary *library, - const LibertyCell *cell, +TableModel::findValue(float axis_value1, + float axis_value2, + float axis_value3) const +{ + return table_->findValue(axis_value1, axis_value2, axis_value3); +} + +float +TableModel::findValue(const LibertyCell *cell, const Pvt *pvt, float axis_value1, float axis_value2, float axis_value3) const { return table_->findValue(axis_value1, axis_value2, axis_value3) - * scaleFactor(library, cell, pvt); + * scaleFactor(cell, pvt); } float -TableModel::scaleFactor(const LibertyLibrary *library, - const LibertyCell *cell, +TableModel::scaleFactor(const LibertyCell *cell, const Pvt *pvt) const { if (is_scaled_) @@ -686,13 +669,12 @@ TableModel::scaleFactor(const LibertyLibrary *library, // nominal pvt. return 1.0F; else - return library->scaleFactor(static_cast(scale_factor_type_), - rf_index_, cell, pvt); + return cell->libertyLibrary()->scaleFactor(static_cast(scale_factor_type_), + rf_index_, cell, pvt); } string TableModel::reportValue(const char *result_name, - const LibertyLibrary *library, const LibertyCell *cell, const Pvt *pvt, float value1, @@ -702,24 +684,24 @@ TableModel::reportValue(const char *result_name, const Unit *table_unit, int digits) const { - string result = table_->reportValue("Table value", library, cell, pvt, value1, + string result = table_->reportValue("Table value", cell, pvt, value1, comment1, value2, value3, table_unit, digits); - result += reportPvtScaleFactor(library, cell, pvt, digits); + result += reportPvtScaleFactor(cell, pvt, digits); result += result_name; result += " = "; - result += table_unit->asString(findValue(library, cell, pvt, - value1, value2, value3), digits); + result += table_unit->asString(findValue(cell, pvt, value1, value2, value3), digits); result += '\n'; return result; } static string -reportPvt(const LibertyLibrary *library, +reportPvt(const LibertyCell *cell, const Pvt *pvt, int digits) { + const LibertyLibrary *library = cell->libertyLibrary(); if (pvt == nullptr) pvt = library->defaultOperatingConditions(); if (pvt) { @@ -734,18 +716,17 @@ reportPvt(const LibertyLibrary *library, } string -TableModel::reportPvtScaleFactor(const LibertyLibrary *library, - const LibertyCell *cell, +TableModel::reportPvtScaleFactor(const LibertyCell *cell, const Pvt *pvt, int digits) const { if (pvt == nullptr) - pvt = library->defaultOperatingConditions(); + pvt = cell->libertyLibrary()->defaultOperatingConditions(); if (pvt) { string result; stringPrint(result, "PVT scale factor = %.*f\n", digits, - scaleFactor(library, cell, pvt)); + scaleFactor(cell, pvt)); return result; } return ""; @@ -777,7 +758,6 @@ Table0::findValue(float, string Table0::reportValue(const char *result_name, - const LibertyLibrary *, const LibertyCell *, const Pvt *, float value1, @@ -930,9 +910,8 @@ Table1::findValueClipZero(float axis_value1) const } string -Table1::reportValue(const char *result_name, const - LibertyLibrary *library, - const LibertyCell *, +Table1::reportValue(const char *result_name, + const LibertyCell *cell, const Pvt *, float value1, const char *comment1, @@ -941,7 +920,7 @@ Table1::reportValue(const char *result_name, const const Unit *table_unit, int digits) const { - const Units *units = library->units(); + const Units *units = cell->libertyLibrary()->units(); const Unit *unit1 = axis1_->unit(units); string result = "Table is indexed by\n "; result += axis1_->variableString(); @@ -1098,8 +1077,7 @@ Table2::findValue(float axis_value1, string Table2::reportValue(const char *result_name, - const LibertyLibrary *library, - const LibertyCell *, + const LibertyCell *cell, const Pvt *, float value1, const char *comment1, @@ -1108,7 +1086,7 @@ Table2::reportValue(const char *result_name, const Unit *table_unit, int digits) const { - const Units *units = library->units(); + const Units *units = cell->libertyLibrary()->units(); const Unit *unit1 = axis1_->unit(units); const Unit *unit2 = axis2_->unit(units); string result = "------- "; @@ -1289,8 +1267,7 @@ Table3::findValue(float axis_value1, // 0.40 | 0.20 0.30 string Table3::reportValue(const char *result_name, - const LibertyLibrary *library, - const LibertyCell *, + const LibertyCell *cell, const Pvt *, float value1, const char *comment1, @@ -1299,7 +1276,7 @@ Table3::reportValue(const char *result_name, const Unit *table_unit, int digits) const { - const Units *units = library->units(); + const Units *units = cell->libertyLibrary()->units(); const Unit *unit1 = axis1_->unit(units); const Unit *unit2 = axis2_->unit(units); const Unit *unit3 = axis3_->unit(units); diff --git a/liberty/TimingArc.cc b/liberty/TimingArc.cc index ba7301c7..0f1532e3 100644 --- a/liberty/TimingArc.cc +++ b/liberty/TimingArc.cc @@ -149,10 +149,8 @@ float TimingArc::driveResistance() const { GateTimingModel *model = dynamic_cast(model_); - if (model) { - LibertyCell *cell = set_->libertyCell(); - return model->driveResistance(cell, nullptr); - } + if (model) + return model->driveResistance(nullptr); else return 0.0; } @@ -162,11 +160,9 @@ TimingArc::intrinsicDelay() const { GateTimingModel *model = dynamic_cast(model_); if (model) { - LibertyCell *cell = set_->libertyCell(); ArcDelay arc_delay; Slew slew; - model->gateDelay(cell, nullptr, 0.0, 0.0, 0.0, false, - arc_delay, slew); + model->gateDelay(nullptr, 0.0, 0.0, 0.0, false, arc_delay, slew); return arc_delay; } else diff --git a/liberty/TimingModel.cc b/liberty/TimingModel.cc new file mode 100644 index 00000000..efb73cf6 --- /dev/null +++ b/liberty/TimingModel.cc @@ -0,0 +1,31 @@ +// 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 "TimingModel.hh" + +namespace sta { + +GateTimingModel::GateTimingModel(LibertyCell *cell) : + TimingModel(cell) +{ +} + +CheckTimingModel::CheckTimingModel(LibertyCell *cell) : + TimingModel(cell) +{ +} + +} // namespace diff --git a/sdc/Sdc.cc b/sdc/Sdc.cc index 51e2e20e..c4c071d8 100644 --- a/sdc/Sdc.cc +++ b/sdc/Sdc.cc @@ -472,7 +472,7 @@ Sdc::operatingConditions(const MinMax *min_max) } const Pvt * -Sdc::pvt(Instance *inst, +Sdc::pvt(const Instance *inst, const MinMax *min_max) const { const InstancePvtMap &pvt_map = instance_pvt_maps_[min_max->index()]; diff --git a/search/MakeTimingModel.cc b/search/MakeTimingModel.cc index 3788d507..58932034 100644 --- a/search/MakeTimingModel.cc +++ b/search/MakeTimingModel.cc @@ -581,7 +581,7 @@ MakeTimingModel::makeScalarCheckModel(float value, library_->findTableTemplate("scalar", TableTemplateType::delay); TableModel *table_model = new TableModel(table, tbl_template, scale_factor_type, rf); - CheckTableModel *check_model = new CheckTableModel(table_model, nullptr); + CheckTableModel *check_model = new CheckTableModel(cell_, table_model, nullptr); return check_model; } @@ -598,7 +598,7 @@ MakeTimingModel::makeGateModelScalar(Delay delay, ScaleFactorType::cell, rf); TableModel *slew_model = new TableModel(slew_table, tbl_template, ScaleFactorType::cell, rf); - GateTableModel *gate_model = new GateTableModel(delay_model, nullptr, + GateTableModel *gate_model = new GateTableModel(cell_, delay_model, nullptr, slew_model, nullptr, nullptr, nullptr); return gate_model; @@ -613,7 +613,7 @@ MakeTimingModel::makeGateModelScalar(Delay delay, library_->findTableTemplate("scalar", TableTemplateType::delay); TableModel *delay_model = new TableModel(delay_table, tbl_template, ScaleFactorType::cell, rf); - GateTableModel *gate_model = new GateTableModel(delay_model, nullptr, + GateTableModel *gate_model = new GateTableModel(cell_, delay_model, nullptr, nullptr, nullptr, nullptr, nullptr); return gate_model; @@ -655,8 +655,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(drvr_cell, pvt, in_slew1, - output_load_cap, 0.0, false, + drvr_gate_model->gateDelay(pvt, in_slew1, output_load_cap, 0.0, false, drvr_self_delay, drvr_self_slew); const TableModel *drvr_table = drvr_gate_model->delayModel(); @@ -671,8 +670,7 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin, // get slew from driver input pin ArcDelay gate_delay; Slew gate_slew; - drvr_gate_model->gateDelay(drvr_cell, pvt, in_slew1, - load_cap, 0.0, false, + drvr_gate_model->gateDelay(pvt, in_slew1, load_cap, 0.0, false, gate_delay, gate_slew); // Remove the self delay driving the output pin net load cap. load_values->push_back(delayAsFloat(delay + gate_delay @@ -694,7 +692,8 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin, ScaleFactorType::cell, rf); TableModel *slew_model = new TableModel(slew_table, model_template, ScaleFactorType::cell, rf); - GateTableModel *gate_model = new GateTableModel(delay_model, nullptr, + GateTableModel *gate_model = new GateTableModel(cell_, + delay_model, nullptr, slew_model, nullptr, nullptr, nullptr); return gate_model; diff --git a/search/Sta.cc b/search/Sta.cc index 2e7500aa..bb437451 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -3789,22 +3789,11 @@ Sta::connectedCap(const Pin *drvr_pin, float &pin_cap, float &wire_cap) const { - pin_cap = 0.0; - wire_cap = 0.0; - bool cap_exists = false; const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); Parasitic *parasitic = arc_delay_calc_->findParasitic(drvr_pin, rf, dcalc_ap); - float ap_pin_cap = 0.0; - float ap_wire_cap = 0.0; graph_delay_calc_->loadCap(drvr_pin, parasitic, rf, dcalc_ap, - ap_pin_cap, ap_wire_cap); + pin_cap, wire_cap); arc_delay_calc_->finishDrvrPin(); - if (!cap_exists - || min_max->compare(ap_pin_cap, pin_cap)) { - pin_cap = ap_pin_cap; - wire_cap = ap_wire_cap; - cap_exists = true; - } } void