DelayCalc reorg

commit 410ed56c2c2d0d7afb0e84d0c65d5ff75234e9e3
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Nov 19 08:44:13 2023 -0700

    ArcDelayCalcBase -> DelayCalcBase

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 1fdfebe2838c47f6c1866c8a10b14df6439506e0
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Nov 19 08:25:36 2023 -0700

    LumpedCapDelayCalc::inputPortDelay

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 3a5e1d01aaff240b2f71d006d620ccd6a70bce6d
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Nov 17 16:32:32 2023 -0700

    gateDelayInit cleanup

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit d0133319126ae4a488a7b31679fbf6507c7f6266
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Nov 17 15:36:12 2023 -0700

    mv RCDelayCalc to ArcDelayCalcBase

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit fd028e6ba5e092243a84685eb1756a8e4e4bad76
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Nov 17 14:32:53 2023 -0700

    ArcDelayCalcBase

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 0ce9cf4c766f7419b998b40aed5af14df97249f1
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Nov 17 10:57:41 2023 -0700

    ParallelArcDelayCalc -> ParallelDelayCalc

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 7fa7db6b252f1450fa5b546f5d33d8cb8a94d4bb
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Nov 17 08:45:01 2023 -0700

    parallelGateDelay args

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 6b85756774ce049c0f5f123f6d60ebbcd62cdd2b
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Nov 16 19:55:20 2023 -0700

    TimingModel cell_

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit e536d6b0ca0d01e2ad8bd609ad20f9a02497d8f5
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Nov 16 18:07:11 2023 -0700

    TimingModel cell_

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit d2d622da4206e06d176e4ae741334fde8df35007
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Nov 16 17:21:15 2023 -0700

    rm drvr_cell from arc dcalc funcs

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 522961e8f58bc1a0f0530a0a5218086280a2bcb0
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Nov 16 16:24:34 2023 -0700

    tr -> rf

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 29aa0ed40345611b9e3a898342ecc17f6355396f
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Nov 16 13:17:44 2023 -0700

    GraphDelayCalc

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 934d9f19c52c62925b23ae9b457f14d25e818f1a
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Nov 16 12:52:55 2023 -0700

    ParallelArcDelayCalc

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit d5687d9482ad0f572b017f0ef806ba8e6ff8b6fa
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Nov 16 12:16:05 2023 -0700

    ParallelArcDelayCalc pvt

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 0de501e5bf2329364b572d1360c18d5aedf3b841
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Nov 16 10:46:22 2023 -0700

    ParallelArcDelayCalc::findMultiDrvrGateDelay

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit d7457b9e335ed5fa583798e0512914aab6524fcc
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Nov 16 10:19:01 2023 -0700

    mv multi_drvr_slew_factor_ to ParallelArcDelayCalc

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit afec4daa2ab6dd61a2450f1ac8a8cad1ef015a29
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Nov 16 08:02:40 2023 -0700

    MultiDrvrNet::net_caps vector

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit b450b3a35616ffc8d85610158a91c5d9483b6958
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Nov 16 07:46:43 2023 -0700

    sic

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 65767403b3b2ab4e6f7552625accf9aa4766628a
Author: James Cherry <cherry@parallaxsw.com>
Date:   Tue Nov 14 17:49:22 2023 -0700

    Sta::connectedCap simplify

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 85bdb8f3362413e7b05f49447a0383140cbb924f
Author: James Cherry <cherry@parallaxsw.com>
Date:   Tue Nov 14 16:43:38 2023 -0700

    ParallelArcDelayCalc

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 4feea3ba2277d53697b644d79832e309ce98058a
Author: James Cherry <cherry@parallaxsw.com>
Date:   Tue Nov 14 15:10:18 2023 -0700

    mv parallel dcalc to arc delay calc

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 915ed28a2c05acce6569c7933366ef94da8bfaeb
Author: James Cherry <cherry@parallaxsw.com>
Date:   Mon Nov 13 17:47:14 2023 -0700

    rm MultiDrvrNet::delays_valid_

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 2384eb4e5bdca1410c4bf5e23f35bfb49f013e74
Author: James Cherry <cherry@parallaxsw.com>
Date:   Mon Nov 13 16:02:57 2023 -0700

    mkae MultiDrvrNets on the fly

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2023-11-19 10:04:45 -07:00
parent 19cf68c72a
commit 31369dd750
37 changed files with 1070 additions and 1170 deletions

View File

@ -66,12 +66,13 @@ set(STA_SOURCE
dcalc/ArnoldiReduce.cc dcalc/ArnoldiReduce.cc
dcalc/DcalcAnalysisPt.cc dcalc/DcalcAnalysisPt.cc
dcalc/DelayCalc.cc dcalc/DelayCalc.cc
dcalc/DelayCalcBase.cc
dcalc/DmpCeff.cc dcalc/DmpCeff.cc
dcalc/DmpDelayCalc.cc dcalc/DmpDelayCalc.cc
dcalc/GraphDelayCalc.cc dcalc/GraphDelayCalc.cc
dcalc/LumpedCapDelayCalc.cc dcalc/LumpedCapDelayCalc.cc
dcalc/NetCaps.cc dcalc/NetCaps.cc
dcalc/RCDelayCalc.cc dcalc/ParallelDelayCalc.cc
dcalc/SlewDegradeDelayCalc.cc dcalc/SlewDegradeDelayCalc.cc
dcalc/UnitDelayCalc.cc dcalc/UnitDelayCalc.cc
@ -96,6 +97,7 @@ set(STA_SOURCE
liberty/Sequential.cc liberty/Sequential.cc
liberty/TableModel.cc liberty/TableModel.cc
liberty/TimingArc.cc liberty/TimingArc.cc
liberty/TimingModel.cc
liberty/TimingRole.cc liberty/TimingRole.cc
liberty/Units.cc liberty/Units.cc
liberty/Wireload.cc liberty/Wireload.cc

View File

@ -37,7 +37,7 @@
#include "DcalcAnalysisPt.hh" #include "DcalcAnalysisPt.hh"
#include "DelayCalc.hh" #include "DelayCalc.hh"
#include "ArcDelayCalc.hh" #include "ArcDelayCalc.hh"
#include "RCDelayCalc.hh" #include "LumpedCapDelayCalc.hh"
#include "GraphDelayCalc.hh" #include "GraphDelayCalc.hh"
#include "Arnoldi.hh" #include "Arnoldi.hh"
#include "ArnoldiReduce.hh" #include "ArnoldiReduce.hh"
@ -108,7 +108,7 @@ struct delay_work
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
class ArnoldiDelayCalc : public RCDelayCalc class ArnoldiDelayCalc : public LumpedCapDelayCalc
{ {
public: public:
ArnoldiDelayCalc(StaState *sta); ArnoldiDelayCalc(StaState *sta);
@ -123,8 +123,7 @@ public:
const RiseFall *rf, const RiseFall *rf,
const Parasitic *parasitic, const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap) override; const DcalcAnalysisPt *dcalc_ap) override;
void gateDelay(const LibertyCell *drvr_cell, void gateDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
float load_cap, float load_cap,
const Parasitic *drvr_parasitic, const Parasitic *drvr_parasitic,
@ -138,8 +137,7 @@ public:
// Return values. // Return values.
ArcDelay &wire_delay, ArcDelay &wire_delay,
Slew &load_slew) override; Slew &load_slew) override;
string reportGateDelay(const LibertyCell *drvr_cell, string reportGateDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
float load_cap, float load_cap,
const Parasitic *drvr_parasitic, const Parasitic *drvr_parasitic,
@ -238,7 +236,7 @@ makeArnoldiDelayCalc(StaState *sta)
} }
ArnoldiDelayCalc::ArnoldiDelayCalc(StaState *sta) : ArnoldiDelayCalc::ArnoldiDelayCalc(StaState *sta) :
RCDelayCalc(sta), LumpedCapDelayCalc(sta),
reduce_(new ArnoldiReduce(sta)), reduce_(new ArnoldiReduce(sta)),
delay_work_(delay_work_create()) delay_work_(delay_work_create())
{ {
@ -321,7 +319,7 @@ ArnoldiDelayCalc::inputPortDelay(const Pin *drvr_pin,
const Parasitic *parasitic, const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap) 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; rcmodel_ = nullptr;
_delayV[0] = 0.0; _delayV[0] = 0.0;
_slewV[0] = in_slew; _slewV[0] = in_slew;
@ -358,8 +356,7 @@ ArnoldiDelayCalc::inputPortDelay(const Pin *drvr_pin,
} }
void void
ArnoldiDelayCalc::gateDelay(const LibertyCell *drvr_cell, ArnoldiDelayCalc::gateDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
float load_cap, float load_cap,
const Parasitic *drvr_parasitic, const Parasitic *drvr_parasitic,
@ -372,6 +369,7 @@ ArnoldiDelayCalc::gateDelay(const LibertyCell *drvr_cell,
{ {
input_port_ = false; input_port_ = false;
drvr_rf_ = arc->toEdge()->asRiseFall(); drvr_rf_ = arc->toEdge()->asRiseFall();
const LibertyCell *drvr_cell = arc->from()->libertyCell();
drvr_library_ = drvr_cell->libertyLibrary(); drvr_library_ = drvr_cell->libertyLibrary();
drvr_parasitic_ = drvr_parasitic; drvr_parasitic_ = drvr_parasitic;
ConcreteParasitic *drvr_cparasitic = ConcreteParasitic *drvr_cparasitic =
@ -384,9 +382,9 @@ ArnoldiDelayCalc::gateDelay(const LibertyCell *drvr_cell,
related_out_cap, pvt, related_out_cap, pvt,
gate_delay, drvr_slew); gate_delay, drvr_slew);
else else
LumpedCapDelayCalc::gateDelay(drvr_cell, arc, in_slew, load_cap, LumpedCapDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic,
drvr_parasitic, related_out_cap, pvt, related_out_cap, pvt, dcalc_ap,
dcalc_ap, gate_delay, drvr_slew); gate_delay, drvr_slew);
drvr_slew_ = drvr_slew; drvr_slew_ = drvr_slew;
multi_drvr_slew_factor_ = 1.0F; multi_drvr_slew_factor_ = 1.0F;
} }
@ -455,8 +453,7 @@ ArnoldiDelayCalc::loadDelay(const Pin *load_pin,
} }
string string
ArnoldiDelayCalc::reportGateDelay(const LibertyCell *, ArnoldiDelayCalc::reportGateDelay(const TimingArc *,
const TimingArc *,
const Slew &, const Slew &,
float, float,
const Parasitic *, const Parasitic *,
@ -1313,9 +1310,7 @@ ArnoldiDelayCalc::ra_get_r(delay_work *D,
c1 = ctot; c1 = ctot;
ArcDelay d1; ArcDelay d1;
Slew s1; Slew s1;
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, tab->table->gateDelay(tab->pvt, tab->in_slew, c1, tab->relcap, pocv_enabled_, d1, s1);
c1, tab->relcap, pocv_enabled_,
d1, s1);
tlohi = slew_derate*delayAsFloat(s1); tlohi = slew_derate*delayAsFloat(s1);
r = tlohi/(c_log*c1); r = tlohi/(c_log*c1);
if (rdelay>0.0 && r > rdelay) if (rdelay>0.0 && r > rdelay)
@ -1337,8 +1332,7 @@ ArnoldiDelayCalc::ra_get_s(delay_work *D,
double tlohi,smin,s; double tlohi,smin,s;
ArcDelay d1; ArcDelay d1;
Slew s1; Slew s1;
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, tab->table->gateDelay(tab->pvt, tab->in_slew, c, tab->relcap, pocv_enabled_, d1, s1);
c, tab->relcap, pocv_enabled_, d1, s1);
tlohi = slew_derate*delayAsFloat(s1); tlohi = slew_derate*delayAsFloat(s1);
smin = r*c*c_smin; // c_smin = ra_hinv((1-vhi)/vhi-log(vhi)) + log(vhi); smin = r*c*c_smin; // c_smin = ra_hinv((1-vhi)/vhi-log(vhi)) + log(vhi);
if (c_log*r*c >= tlohi) { if (c_log*r*c >= tlohi) {
@ -1371,10 +1365,8 @@ ArnoldiDelayCalc::ra_rdelay_1(timing_table *tab,
return 0.0; return 0.0;
ArcDelay d1, d2; ArcDelay d1, d2;
Slew s1, s2; Slew s1, s2;
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, tab->table->gateDelay(tab->pvt, tab->in_slew, c1, tab->relcap, pocv_enabled_, d1, s1);
c1, tab->relcap, pocv_enabled_, d1, s1); tab->table->gateDelay(tab->pvt, tab->in_slew, c2, tab->relcap, pocv_enabled_, d2, s2);
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew,
c2, tab->relcap, pocv_enabled_, d2, s2);
double dt50 = delayAsFloat(d1)-delayAsFloat(d2); double dt50 = delayAsFloat(d1)-delayAsFloat(d2);
if (dt50 <= 0.0) if (dt50 <= 0.0)
return 0.0; return 0.0;
@ -1426,8 +1418,8 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
units_->timeUnit()->asString(s)); units_->timeUnit()->asString(s));
thix = ra_solve_for_t(p,s,vhi); thix = ra_solve_for_t(p,s,vhi);
tlox = ra_solve_for_t(p,s,vlo); tlox = ra_solve_for_t(p,s,vlo);
tab->table->gateDelay(tab->cell, tab->pvt,tab->in_slew, tab->table->gateDelay(tab->pvt,tab->in_slew, ctot, tab->relcap, pocv_enabled_,
ctot, tab->relcap, pocv_enabled_, df, sf); df, sf);
debugPrint(debug_, "arnoldi", 1, "table slew (in_slew %s ctot %s) = %s", debugPrint(debug_, "arnoldi", 1, "table slew (in_slew %s ctot %s) = %s",
units_->timeUnit()->asString(tab->in_slew), units_->timeUnit()->asString(tab->in_slew),
units_->capacitanceUnit()->asString(ctot), units_->capacitanceUnit()->asString(ctot),
@ -1438,8 +1430,8 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
units_->timeUnit()->asString(tlox-thix)); units_->timeUnit()->asString(tlox-thix));
} }
ceff = ctot; ceff = ctot;
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, tab->relcap, pocv_enabled_,
ceff, tab->relcap, pocv_enabled_, df, sf); df, sf);
t50_sy = delayAsFloat(df); t50_sy = delayAsFloat(df);
t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5); 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_->timeUnit()->asString(ceff_time),
units_->capacitanceUnit()->asString(ceff)); units_->capacitanceUnit()->asString(ceff));
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, ceff, tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, tab->relcap, pocv_enabled_, df, sf);
tab->relcap, pocv_enabled_, df, sf);
t50_sy = delayAsFloat(df); t50_sy = delayAsFloat(df);
t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5); t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5);
for (j=0;j<mod->n;j++) { for (j=0;j<mod->n;j++) {

132
dcalc/DelayCalcBase.cc Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
#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

View File

@ -16,32 +16,48 @@
#pragma once #pragma once
#include "LumpedCapDelayCalc.hh" #include "ArcDelayCalc.hh"
namespace sta { namespace sta {
// Base class for delay calculators with RC wire delay. class DelayCalcBase : public ArcDelayCalc
class RCDelayCalc : public LumpedCapDelayCalc
{ {
public: public:
RCDelayCalc(StaState *sta); explicit DelayCalcBase(StaState *sta);
ArcDelayCalc *copy() override;
void inputPortDelay(const Pin *port_pin, void inputPortDelay(const Pin *port_pin,
float in_slew, float in_slew,
const RiseFall *rf, const RiseFall *rf,
const Parasitic *parasitic, const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap) override; const DcalcAnalysisPt *dcalc_ap) override;
void finishDrvrPin() override;
protected: 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. // Helper function for input ports driving dspf parasitic.
void dspfWireDelaySlew(const Pin *load_pin, void dspfWireDelaySlew(const Pin *load_pin,
float elmore, float elmore,
ArcDelay &wire_delay, ArcDelay &wire_delay,
Slew &load_slew); Slew &load_slew);
Slew drvr_slew_;
const LibertyCell *drvr_cell_; const LibertyCell *drvr_cell_;
const LibertyLibrary *drvr_library_;
const Parasitic *drvr_parasitic_; const Parasitic *drvr_parasitic_;
bool input_port_; 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<Parasitic*> unsaved_parasitics_;
Vector<const Pin *> reduced_parasitic_drvrs_;
}; };
} // namespace } // namespace

View File

@ -381,7 +381,7 @@ DmpAlg::gateCapDelaySlew(double ceff,
{ {
ArcDelay model_delay; ArcDelay model_delay;
Slew model_slew; 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); pocv_enabled_, model_delay, model_slew);
delay = delayAsFloat(model_delay); delay = delayAsFloat(model_delay);
slew = delayAsFloat(model_slew); slew = delayAsFloat(model_slew);
@ -1528,7 +1528,7 @@ testLuDecomp2()
bool DmpCeffDelayCalc::unsuppored_model_warned_ = false; bool DmpCeffDelayCalc::unsuppored_model_warned_ = false;
DmpCeffDelayCalc::DmpCeffDelayCalc(StaState *sta) : DmpCeffDelayCalc::DmpCeffDelayCalc(StaState *sta) :
RCDelayCalc(sta), LumpedCapDelayCalc(sta),
dmp_cap_(new DmpCap(sta)), dmp_cap_(new DmpCap(sta)),
dmp_pi_(new DmpPi(sta)), dmp_pi_(new DmpPi(sta)),
dmp_zero_c2_(new DmpZeroC2(sta)), dmp_zero_c2_(new DmpZeroC2(sta)),
@ -1551,12 +1551,11 @@ DmpCeffDelayCalc::inputPortDelay(const Pin *port_pin,
const DcalcAnalysisPt *dcalc_ap) const DcalcAnalysisPt *dcalc_ap)
{ {
dmp_alg_ = nullptr; dmp_alg_ = nullptr;
RCDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap); LumpedCapDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap);
} }
void void
DmpCeffDelayCalc::gateDelay(const LibertyCell *drvr_cell, DmpCeffDelayCalc::gateDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
float load_cap, float load_cap,
const Parasitic *drvr_parasitic, const Parasitic *drvr_parasitic,
@ -1569,8 +1568,10 @@ DmpCeffDelayCalc::gateDelay(const LibertyCell *drvr_cell,
{ {
input_port_ = false; input_port_ = false;
drvr_rf_ = arc->toEdge()->asRiseFall(); drvr_rf_ = arc->toEdge()->asRiseFall();
const LibertyCell *drvr_cell = arc->from()->libertyCell();
drvr_library_ = drvr_cell->libertyLibrary(); drvr_library_ = drvr_cell->libertyLibrary();
drvr_parasitic_ = drvr_parasitic; drvr_parasitic_ = drvr_parasitic;
GateTimingModel *model = gateModel(arc, dcalc_ap); GateTimingModel *model = gateModel(arc, dcalc_ap);
GateTableModel *table_model = dynamic_cast<GateTableModel*>(model); GateTableModel *table_model = dynamic_cast<GateTableModel*>(model);
if (table_model && drvr_parasitic) { if (table_model && drvr_parasitic) {
@ -1588,9 +1589,9 @@ DmpCeffDelayCalc::gateDelay(const LibertyCell *drvr_cell,
drvr_slew = dmp_drvr_slew; drvr_slew = dmp_drvr_slew;
} }
else { else {
LumpedCapDelayCalc::gateDelay(drvr_cell, arc, in_slew, load_cap, LumpedCapDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic,
drvr_parasitic, related_out_cap, pvt, related_out_cap, pvt, dcalc_ap,
dcalc_ap, gate_delay, drvr_slew); gate_delay, drvr_slew);
if (drvr_parasitic if (drvr_parasitic
&& !unsuppored_model_warned_) { && !unsuppored_model_warned_) {
unsuppored_model_warned_ = true; unsuppored_model_warned_ = true;
@ -1646,8 +1647,7 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library,
} }
float float
DmpCeffDelayCalc::ceff(const LibertyCell *drvr_cell, DmpCeffDelayCalc::ceff(const TimingArc *arc,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
float load_cap, float load_cap,
const Parasitic *drvr_parasitic, const Parasitic *drvr_parasitic,
@ -1657,8 +1657,7 @@ DmpCeffDelayCalc::ceff(const LibertyCell *drvr_cell,
{ {
ArcDelay gate_delay; ArcDelay gate_delay;
Slew drvr_slew; Slew drvr_slew;
gateDelay(drvr_cell, arc, in_slew, load_cap, gateDelay(arc, in_slew, load_cap, drvr_parasitic, related_out_cap, pvt, dcalc_ap,
drvr_parasitic, related_out_cap, pvt, dcalc_ap,
gate_delay, drvr_slew); gate_delay, drvr_slew);
if (dmp_alg_) if (dmp_alg_)
return dmp_alg_->ceff(); return dmp_alg_->ceff();
@ -1667,8 +1666,7 @@ DmpCeffDelayCalc::ceff(const LibertyCell *drvr_cell,
} }
string string
DmpCeffDelayCalc::reportGateDelay(const LibertyCell *drvr_cell, DmpCeffDelayCalc::reportGateDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
float load_cap, float load_cap,
const Parasitic *drvr_parasitic, const Parasitic *drvr_parasitic,
@ -1679,14 +1677,14 @@ DmpCeffDelayCalc::reportGateDelay(const LibertyCell *drvr_cell,
{ {
ArcDelay gate_delay; ArcDelay gate_delay;
Slew drvr_slew; Slew drvr_slew;
gateDelay(drvr_cell, arc, in_slew, load_cap, gateDelay(arc, in_slew, load_cap, drvr_parasitic, related_out_cap, pvt, dcalc_ap,
drvr_parasitic, related_out_cap, pvt, dcalc_ap,
gate_delay, drvr_slew); gate_delay, drvr_slew);
GateTimingModel *model = gateModel(arc, dcalc_ap); GateTimingModel *model = gateModel(arc, dcalc_ap);
float c_eff = 0.0; float c_eff = 0.0;
string result; string result;
if (drvr_parasitic_ && dmp_alg_) { if (drvr_parasitic_ && dmp_alg_) {
c_eff = dmp_alg_->ceff(); c_eff = dmp_alg_->ceff();
const LibertyCell *drvr_cell = arc->from()->libertyCell();
const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary(); const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary();
const Units *units = drvr_library->units(); const Units *units = drvr_library->units();
const Unit *cap_unit = units->capacitanceUnit(); const Unit *cap_unit = units->capacitanceUnit();
@ -1707,8 +1705,8 @@ DmpCeffDelayCalc::reportGateDelay(const LibertyCell *drvr_cell,
c_eff = load_cap; c_eff = load_cap;
if (model) { if (model) {
float in_slew1 = delayAsFloat(in_slew); float in_slew1 = delayAsFloat(in_slew);
result += model->reportGateDelay(drvr_cell, pvt, in_slew1, c_eff, result += model->reportGateDelay(pvt, in_slew1, c_eff, related_out_cap,
related_out_cap, pocv_enabled_, digits); pocv_enabled_, digits);
} }
return result; return result;
} }
@ -1728,10 +1726,8 @@ gateModelRd(const LibertyCell *cell,
float cap2 = cap1 + 1e-15; float cap2 = cap1 + 1e-15;
ArcDelay d1, d2; ArcDelay d1, d2;
Slew s1, s2; Slew s1, s2;
gate_model->gateDelay(cell, pvt, in_slew, cap1, related_out_cap, pocv_enabled, gate_model->gateDelay(pvt, in_slew, cap1, related_out_cap, pocv_enabled, d1, s1);
d1, s1); gate_model->gateDelay(pvt, in_slew, cap2, related_out_cap, pocv_enabled, d2, s2);
gate_model->gateDelay(cell, pvt, in_slew, cap2, related_out_cap, pocv_enabled,
d2, s2);
double vth = cell->libertyLibrary()->outputThreshold(rf); double vth = cell->libertyLibrary()->outputThreshold(rf);
float rd = -log(vth) * abs(delayAsFloat(d1) - delayAsFloat(d2)) / (cap2 - cap1); float rd = -log(vth) * abs(delayAsFloat(d1) - delayAsFloat(d2)) / (cap2 - cap1);
return rd; return rd;

View File

@ -17,7 +17,7 @@
#pragma once #pragma once
#include "LibertyClass.hh" #include "LibertyClass.hh"
#include "RCDelayCalc.hh" #include "LumpedCapDelayCalc.hh"
namespace sta { namespace sta {
@ -29,7 +29,7 @@ class GateTableModel;
// Delay calculator using Dartu/Menezes/Pileggi effective capacitance // Delay calculator using Dartu/Menezes/Pileggi effective capacitance
// algorithm for RSPF loads. // algorithm for RSPF loads.
class DmpCeffDelayCalc : public RCDelayCalc class DmpCeffDelayCalc : public LumpedCapDelayCalc
{ {
public: public:
DmpCeffDelayCalc(StaState *sta); DmpCeffDelayCalc(StaState *sta);
@ -39,8 +39,7 @@ public:
const RiseFall *rf, const RiseFall *rf,
const Parasitic *parasitic, const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap); const DcalcAnalysisPt *dcalc_ap);
virtual void gateDelay(const LibertyCell *drvr_cell, virtual void gateDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
float load_cap, float load_cap,
const Parasitic *drvr_parasitic, const Parasitic *drvr_parasitic,
@ -50,16 +49,14 @@ public:
// return values // return values
ArcDelay &gate_delay, ArcDelay &gate_delay,
Slew &drvr_slew); Slew &drvr_slew);
virtual float ceff(const LibertyCell *drvr_cell, virtual float ceff(const TimingArc *arc,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
float load_cap, float load_cap,
const Parasitic *drvr_parasitic, const Parasitic *drvr_parasitic,
float related_out_cap, float related_out_cap,
const Pvt *pvt, const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap); const DcalcAnalysisPt *dcalc_ap);
virtual string reportGateDelay(const LibertyCell *drvr_cell, virtual string reportGateDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
float load_cap, float load_cap,
const Parasitic *drvr_parasitic, const Parasitic *drvr_parasitic,

View File

@ -35,17 +35,6 @@ class DmpCeffElmoreDelayCalc : public DmpCeffDelayCalc
public: public:
DmpCeffElmoreDelayCalc(StaState *sta); DmpCeffElmoreDelayCalc(StaState *sta);
ArcDelayCalc *copy() override; 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, void loadDelay(const Pin *load_pin,
ArcDelay &wire_delay, ArcDelay &wire_delay,
Slew &load_slew) override; Slew &load_slew) override;
@ -68,25 +57,6 @@ DmpCeffElmoreDelayCalc::copy()
return new DmpCeffElmoreDelayCalc(this); 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 void
DmpCeffElmoreDelayCalc::loadDelay(const Pin *load_pin, DmpCeffElmoreDelayCalc::loadDelay(const Pin *load_pin,
ArcDelay &wire_delay, ArcDelay &wire_delay,
@ -127,8 +97,7 @@ public:
const RiseFall *rf, const RiseFall *rf,
const Parasitic *parasitic, const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap) override; const DcalcAnalysisPt *dcalc_ap) override;
void gateDelay(const LibertyCell *drvr_cell, void gateDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
float load_cap, float load_cap,
const Parasitic *drvr_parasitic, const Parasitic *drvr_parasitic,
@ -233,7 +202,7 @@ DmpCeffTwoPoleDelayCalc::findParasitic(const Pin *drvr_pin,
cnst_min_max, cnst_min_max,
parasitic_ap); parasitic_ap);
// Estimated parasitics are not recorded in the "database", so // 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) if (parasitic)
unsaved_parasitics_.push_back(parasitic); unsaved_parasitics_.push_back(parasitic);
} }
@ -260,8 +229,7 @@ DmpCeffTwoPoleDelayCalc::inputPortDelay(const Pin *port_pin,
} }
void void
DmpCeffTwoPoleDelayCalc::gateDelay(const LibertyCell *drvr_cell, DmpCeffTwoPoleDelayCalc::gateDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
float load_cap, float load_cap,
const Parasitic *drvr_parasitic, const Parasitic *drvr_parasitic,
@ -272,15 +240,13 @@ DmpCeffTwoPoleDelayCalc::gateDelay(const LibertyCell *drvr_cell,
ArcDelay &gate_delay, ArcDelay &gate_delay,
Slew &drvr_slew) Slew &drvr_slew)
{ {
gateDelayInit(arc, in_slew, drvr_parasitic);
parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(drvr_parasitic); parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(drvr_parasitic);
const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary(); vth_ = drvr_library_->outputThreshold(drvr_rf_);
const RiseFall *rf = arc->toEdge()->asRiseFall(); vl_ = drvr_library_->slewLowerThreshold(drvr_rf_);
vth_ = drvr_library->outputThreshold(rf); vh_ = drvr_library_->slewUpperThreshold(drvr_rf_);
vl_ = drvr_library->slewLowerThreshold(rf); slew_derate_ = drvr_library_->slewDerateFromLibrary();
vh_ = drvr_library->slewUpperThreshold(rf); DmpCeffDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic,
slew_derate_ = drvr_library->slewDerateFromLibrary();
DmpCeffDelayCalc::gateDelay(drvr_cell, arc, in_slew,
load_cap, drvr_parasitic,
related_out_cap, pvt, dcalc_ap, related_out_cap, pvt, dcalc_ap,
gate_delay, drvr_slew); gate_delay, drvr_slew);
} }

View File

@ -44,170 +44,10 @@ using std::abs;
static const Slew default_slew = 0.0; static const Slew default_slew = 0.0;
typedef Set<MultiDrvrNet*> MultiDrvrNetSet;
static bool static bool
isLeafDriver(const Pin *pin, isLeafDriver(const Pin *pin,
const Network *network); 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 &parallel_delay,
Slew &parallel_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 &parallel_delay,
Slew &parallel_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) : GraphDelayCalc::GraphDelayCalc(StaState *sta) :
StaState(sta), StaState(sta),
observer_(nullptr), observer_(nullptr),
@ -238,7 +78,7 @@ GraphDelayCalc::~GraphDelayCalc()
void void
GraphDelayCalc::deleteMultiDrvrNets() GraphDelayCalc::deleteMultiDrvrNets()
{ {
MultiDrvrNetSet drvr_nets; Set<MultiDrvrNet*> drvr_nets;
MultiDrvrNetMap::Iterator multi_iter(multi_drvr_net_map_); MultiDrvrNetMap::Iterator multi_iter(multi_drvr_net_map_);
while (multi_iter.hasNext()) { while (multi_iter.hasNext()) {
MultiDrvrNet *multi_drvr = multi_iter.next(); 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); debugPrint(debug_, "delay_calc", 1, "find delays to level %d", level);
if (!delays_seeded_) { if (!delays_seeded_) {
iter_->clear(); iter_->clear();
ensureMultiDrvrNetsFound();
seedRootSlews(); seedRootSlews();
delays_seeded_ = true; delays_seeded_ = true;
} }
@ -444,107 +283,6 @@ GraphDelayCalc::seedInvalidDelays()
invalid_delays_->clear(); 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 void
GraphDelayCalc::seedRootSlews() GraphDelayCalc::seedRootSlews()
{ {
@ -754,8 +492,7 @@ GraphDelayCalc::findInputDriverDelay(const LibertyCell *drvr_cell,
for (TimingArc *arc : arc_set->arcs()) { for (TimingArc *arc : arc_set->arcs()) {
if (arc->toEdge()->asRiseFall() == rf) { if (arc->toEdge()->asRiseFall() == rf) {
float from_slew = from_slews[arc->fromEdge()->index()]; float from_slew = from_slews[arc->fromEdge()->index()];
findInputArcDelay(drvr_cell, drvr_pin, drvr_vertex, findInputArcDelay(drvr_pin, drvr_vertex, arc, from_slew, dcalc_ap);
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 // delay minus the intrinsic delay. Driving cell delays are annotated
// to the wire arcs from the input port pin to the load pins. // to the wire arcs from the input port pin to the load pins.
void void
GraphDelayCalc::findInputArcDelay(const LibertyCell *drvr_cell, GraphDelayCalc::findInputArcDelay(const Pin *drvr_pin,
const Pin *drvr_pin,
Vertex *drvr_vertex, Vertex *drvr_vertex,
const TimingArc *arc, const TimingArc *arc,
float from_slew, float from_slew,
@ -788,15 +524,13 @@ GraphDelayCalc::findInputArcDelay(const LibertyCell *drvr_cell,
ArcDelay intrinsic_delay; ArcDelay intrinsic_delay;
Slew intrinsic_slew; Slew intrinsic_slew;
arc_delay_calc_->gateDelay(drvr_cell, arc, Slew(from_slew), arc_delay_calc_->gateDelay(arc, Slew(from_slew), 0.0, 0, 0.0, pvt, dcalc_ap,
0.0, 0, 0.0, pvt, dcalc_ap,
intrinsic_delay, intrinsic_slew); intrinsic_delay, intrinsic_slew);
// For input drivers there is no instance to find a related_output_pin. // For input drivers there is no instance to find a related_output_pin.
ArcDelay gate_delay; ArcDelay gate_delay;
Slew gate_slew; Slew gate_slew;
arc_delay_calc_->gateDelay(drvr_cell, arc, arc_delay_calc_->gateDelay(arc, Slew(from_slew), load_cap,
Slew(from_slew), load_cap,
drvr_parasitic, 0.0, pvt, dcalc_ap, drvr_parasitic, 0.0, pvt, dcalc_ap,
gate_delay, gate_slew); gate_delay, gate_slew);
ArcDelay load_delay = gate_delay - intrinsic_delay; ArcDelay load_delay = gate_delay - intrinsic_delay;
@ -899,16 +633,15 @@ GraphDelayCalc::findDriverDelays(Vertex *drvr_vertex,
ArcDelayCalc *arc_delay_calc) ArcDelayCalc *arc_delay_calc)
{ {
bool delay_changed = false; bool delay_changed = false;
MultiDrvrNet *multi_drvr = multiDrvrNet(drvr_vertex); MultiDrvrNet *multi_drvr = findMultiDrvrNet(drvr_vertex);
if (multi_drvr) { if (multi_drvr
&& multi_drvr->parallelGates(network_)) {
Vertex *dcalc_drvr = multi_drvr->dcalcDrvr(); Vertex *dcalc_drvr = multi_drvr->dcalcDrvr();
if (drvr_vertex == dcalc_drvr) { if (drvr_vertex == dcalc_drvr) {
initLoadSlews(drvr_vertex); initLoadSlews(drvr_vertex);
for (Vertex *drvr_vertex : *multi_drvr->drvrs()) { arc_delay_calc->findParallelGateDelays(multi_drvr, this);
// Only init load slews once so previous driver dcalc results for (Vertex *drvr_vertex : *multi_drvr->drvrs())
// aren't clobbered.
delay_changed |= findDriverDelays1(drvr_vertex, multi_drvr, arc_delay_calc); delay_changed |= findDriverDelays1(drvr_vertex, multi_drvr, arc_delay_calc);
}
} }
} }
else { else {
@ -919,6 +652,74 @@ GraphDelayCalc::findDriverDelays(Vertex *drvr_vertex,
return delay_changed; 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 void
GraphDelayCalc::initLoadSlews(Vertex *drvr_vertex) GraphDelayCalc::initLoadSlews(Vertex *drvr_vertex)
{ {
@ -947,7 +748,6 @@ GraphDelayCalc::findDriverDelays1(Vertex *drvr_vertex,
{ {
const Pin *drvr_pin = drvr_vertex->pin(); const Pin *drvr_pin = drvr_vertex->pin();
Instance *drvr_inst = network_->instance(drvr_pin); Instance *drvr_inst = network_->instance(drvr_pin);
LibertyCell *drvr_cell = network_->libertyCell(drvr_inst);
initSlew(drvr_vertex); initSlew(drvr_vertex);
initWireDelays(drvr_vertex); initWireDelays(drvr_vertex);
bool delay_changed = false; bool delay_changed = false;
@ -960,9 +760,8 @@ GraphDelayCalc::findDriverDelays1(Vertex *drvr_vertex,
if (search_pred_->searchFrom(from_vertex) if (search_pred_->searchFrom(from_vertex)
&& search_pred_->searchThru(edge) && search_pred_->searchThru(edge)
&& !edge->role()->isLatchDtoQ()) { && !edge->role()->isLatchDtoQ()) {
delay_changed |= findDriverEdgeDelays(drvr_cell, drvr_inst, drvr_pin, delay_changed |= findDriverEdgeDelays(drvr_inst, drvr_pin, drvr_vertex,
drvr_vertex, multi_drvr, edge, multi_drvr, edge, arc_delay_calc);
arc_delay_calc);
has_delays = true; has_delays = true;
} }
} }
@ -994,26 +793,24 @@ GraphDelayCalc::findLatchEdgeDelays(Edge *edge)
Vertex *drvr_vertex = edge->to(graph_); Vertex *drvr_vertex = edge->to(graph_);
const Pin *drvr_pin = drvr_vertex->pin(); const Pin *drvr_pin = drvr_vertex->pin();
Instance *drvr_inst = network_->instance(drvr_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", debugPrint(debug_, "delay_calc", 2, "find latch D->Q %s",
sdc_network_->pathName(drvr_inst)); sdc_network_->pathName(drvr_inst));
bool delay_changed = findDriverEdgeDelays(drvr_cell, drvr_inst, drvr_pin, bool delay_changed = findDriverEdgeDelays(drvr_inst, drvr_pin, drvr_vertex,
drvr_vertex, nullptr, edge, arc_delay_calc_); nullptr, edge, arc_delay_calc_);
if (delay_changed && observer_) if (delay_changed && observer_)
observer_->delayChangedTo(drvr_vertex); observer_->delayChangedTo(drvr_vertex);
} }
bool bool
GraphDelayCalc::findDriverEdgeDelays(LibertyCell *drvr_cell, GraphDelayCalc::findDriverEdgeDelays(const Instance *drvr_inst,
Instance *drvr_inst,
const Pin *drvr_pin, const Pin *drvr_pin,
Vertex *drvr_vertex, Vertex *drvr_vertex,
MultiDrvrNet *multi_drvr, const MultiDrvrNet *multi_drvr,
Edge *edge, Edge *edge,
ArcDelayCalc *arc_delay_calc) ArcDelayCalc *arc_delay_calc)
{ {
Vertex *in_vertex = edge->from(graph_); 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 LibertyPort *related_out_port = arc_set->relatedOut();
const Pin *related_out_pin = 0; const Pin *related_out_pin = 0;
bool delay_changed = false; bool delay_changed = false;
@ -1025,21 +822,16 @@ GraphDelayCalc::findDriverEdgeDelays(LibertyCell *drvr_cell,
pvt = dcalc_ap->operatingConditions(); pvt = dcalc_ap->operatingConditions();
for (TimingArc *arc : arc_set->arcs()) { for (TimingArc *arc : arc_set->arcs()) {
const RiseFall *rf = arc->toEdge()->asRiseFall(); const RiseFall *rf = arc->toEdge()->asRiseFall();
Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin, rf, Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin, rf, dcalc_ap);
dcalc_ap);
float related_out_cap = 0.0; float related_out_cap = 0.0;
if (related_out_pin) { if (related_out_pin) {
Parasitic *related_out_parasitic = Parasitic *related_out_parasitic =
arc_delay_calc->findParasitic(related_out_pin, rf, dcalc_ap); arc_delay_calc->findParasitic(related_out_pin, rf, dcalc_ap);
related_out_cap = loadCap(related_out_pin, related_out_cap = loadCap(related_out_pin, related_out_parasitic, rf, dcalc_ap);
related_out_parasitic,
rf, dcalc_ap);
} }
delay_changed |= findArcDelay(drvr_cell, drvr_pin, drvr_vertex, delay_changed |= findArcDelay(drvr_pin, drvr_vertex, arc, parasitic,
multi_drvr, arc, parasitic, related_out_cap, in_vertex, edge, pvt, dcalc_ap,
related_out_cap, multi_drvr, arc_delay_calc);
in_vertex, edge, pvt, dcalc_ap,
arc_delay_calc);
} }
} }
@ -1059,7 +851,7 @@ GraphDelayCalc::loadCap(const Pin *drvr_pin,
for (auto drvr_rf : RiseFall::range()) { for (auto drvr_rf : RiseFall::range()) {
Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf,
dcalc_ap); 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(); arc_delay_calc_->finishDrvrPin();
if (min_max->compare(cap, load_cap)) if (min_max->compare(cap, load_cap))
load_cap = 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, Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf,
dcalc_ap); 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; return cap;
} }
@ -1084,15 +876,15 @@ GraphDelayCalc::loadCap(const Pin *drvr_pin,
const RiseFall *rf, const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) const 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 float
GraphDelayCalc::loadCap(const Pin *drvr_pin, GraphDelayCalc::loadCap(const Pin *drvr_pin,
MultiDrvrNet *multi_drvr,
const Parasitic *drvr_parasitic, const Parasitic *drvr_parasitic,
const RiseFall *rf, const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) const const DcalcAnalysisPt *dcalc_ap,
const MultiDrvrNet *multi_drvr) const
{ {
float pin_cap, wire_cap; float pin_cap, wire_cap;
bool has_net_load; 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 // 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 // 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 // each load pin, and the slew at each load pin. Annotate the graph
// with the results. // with the results.
bool bool
GraphDelayCalc::findArcDelay(LibertyCell *drvr_cell, GraphDelayCalc::findArcDelay(const Pin *drvr_pin,
const Pin *drvr_pin,
Vertex *drvr_vertex, Vertex *drvr_vertex,
MultiDrvrNet *multi_drvr, const TimingArc *arc,
TimingArc *arc, const Parasitic *drvr_parasitic,
Parasitic *drvr_parasitic,
float related_out_cap, float related_out_cap,
Vertex *from_vertex, Vertex *from_vertex,
Edge *edge, Edge *edge,
const Pvt *pvt, const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap, const DcalcAnalysisPt *dcalc_ap,
const MultiDrvrNet *multi_drvr,
ArcDelayCalc *arc_delay_calc) ArcDelayCalc *arc_delay_calc)
{ {
bool delay_changed = false; 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); const Slew from_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap);
ArcDelay gate_delay; ArcDelay gate_delay;
Slew gate_slew; Slew gate_slew;
float load_cap = loadCap(drvr_pin, drvr_parasitic, drvr_rf, dcalc_ap, multi_drvr);
if (multi_drvr if (multi_drvr
&& arc->to()->direction()->isOutput()) && multi_drvr->parallelGates(network_))
parallelGateDelay(multi_drvr, drvr_cell, drvr_pin, arc, arc_delay_calc->parallelGateDelay(drvr_pin, arc, from_slew, load_cap,
pvt, dcalc_ap, from_slew, drvr_parasitic, drvr_parasitic, related_out_cap, pvt, dcalc_ap,
related_out_cap, gate_delay, gate_slew);
arc_delay_calc, else
gate_delay, gate_slew); arc_delay_calc->gateDelay(arc, from_slew, load_cap, drvr_parasitic,
else {
float load_cap = loadCap(drvr_pin, multi_drvr, drvr_parasitic,
drvr_rf, dcalc_ap);
arc_delay_calc->gateDelay(drvr_cell, arc,
from_slew, load_cap, drvr_parasitic,
related_out_cap, pvt, dcalc_ap, related_out_cap, pvt, dcalc_ap,
gate_delay, gate_slew); gate_delay, gate_slew);
}
debugPrint(debug_, "delay_calc", 3, debugPrint(debug_, "delay_calc", 3,
" gate delay = %s slew = %s", " gate delay = %s slew = %s",
delayAsString(gate_delay, this), delayAsString(gate_delay, this),
@ -1320,115 +1106,6 @@ GraphDelayCalc::findArcDelay(LibertyCell *drvr_cell,
return delay_changed; 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 &parallel_delay,
Slew &parallel_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. // Use clock slew for register/latch clk->q edges.
Slew Slew
GraphDelayCalc::edgeFromSlew(const Vertex *from_vertex, GraphDelayCalc::edgeFromSlew(const Vertex *from_vertex,
@ -1517,7 +1194,6 @@ GraphDelayCalc::findCheckEdgeDelays(Edge *edge,
TimingArcSet *arc_set = edge->timingArcSet(); TimingArcSet *arc_set = edge->timingArcSet();
const Pin *to_pin = to_vertex->pin(); const Pin *to_pin = to_vertex->pin();
Instance *inst = network_->instance(to_pin); Instance *inst = network_->instance(to_pin);
const LibertyCell *cell = network_->libertyCell(inst);
debugPrint(debug_, "delay_calc", 2, "find check %s %s -> %s", debugPrint(debug_, "delay_calc", 2, "find check %s %s -> %s",
sdc_network_->pathName(inst), sdc_network_->pathName(inst),
network_->portName(from_vertex->pin()), network_->portName(from_vertex->pin()),
@ -1561,11 +1237,8 @@ GraphDelayCalc::findCheckEdgeDelays(Edge *edge,
to_rf, dcalc_ap); to_rf, dcalc_ap);
} }
ArcDelay check_delay; ArcDelay check_delay;
arc_delay_calc->checkDelay(cell, arc, arc_delay_calc->checkDelay(arc, from_slew, to_slew, related_out_cap,
from_slew, to_slew, pvt, dcalc_ap, check_delay);
related_out_cap,
pvt, dcalc_ap,
check_delay);
debugPrint(debug_, "delay_calc", 3, debugPrint(debug_, "delay_calc", 3,
" check_delay = %s", " check_delay = %s",
delayAsString(check_delay, this)); delayAsString(check_delay, this));
@ -1604,8 +1277,7 @@ GraphDelayCalc::ceff(Edge *edge,
Vertex *to_vertex = edge->to(graph_); Vertex *to_vertex = edge->to(graph_);
Pin *to_pin = to_vertex->pin(); Pin *to_pin = to_vertex->pin();
Instance *inst = network_->instance(to_pin); Instance *inst = network_->instance(to_pin);
LibertyCell *cell = network_->libertyCell(inst); const TimingArcSet *arc_set = edge->timingArcSet();
TimingArcSet *arc_set = edge->timingArcSet();
float ceff = 0.0; float ceff = 0.0;
const Pvt *pvt = sdc_->pvt(inst, dcalc_ap->constraintMinMax()); const Pvt *pvt = sdc_->pvt(inst, dcalc_ap->constraintMinMax());
if (pvt == nullptr) if (pvt == nullptr)
@ -1628,8 +1300,7 @@ GraphDelayCalc::ceff(Edge *edge,
dcalc_ap); dcalc_ap);
const Slew &from_slew = edgeFromSlew(from_vertex, from_rf, 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); float load_cap = loadCap(to_pin, to_parasitic, to_rf, dcalc_ap);
ceff = arc_delay_calc_->ceff(cell, arc, ceff = arc_delay_calc_->ceff(arc, from_slew, load_cap, to_parasitic,
from_slew, load_cap, to_parasitic,
related_out_cap, pvt, dcalc_ap); related_out_cap, pvt, dcalc_ap);
arc_delay_calc_->finishDrvrPin(); arc_delay_calc_->finishDrvrPin();
} }
@ -1639,8 +1310,8 @@ GraphDelayCalc::ceff(Edge *edge,
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
string string
GraphDelayCalc::reportDelayCalc(Edge *edge, GraphDelayCalc::reportDelayCalc(const Edge *edge,
TimingArc *arc, const TimingArc *arc,
const Corner *corner, const Corner *corner,
const MinMax *min_max, const MinMax *min_max,
int digits) int digits)
@ -1649,9 +1320,8 @@ GraphDelayCalc::reportDelayCalc(Edge *edge,
Vertex *to_vertex = edge->to(graph_); Vertex *to_vertex = edge->to(graph_);
Pin *to_pin = to_vertex->pin(); Pin *to_pin = to_vertex->pin();
TimingRole *role = arc->role(); TimingRole *role = arc->role();
Instance *inst = network_->instance(to_pin); const Instance *inst = network_->instance(to_pin);
LibertyCell *cell = network_->libertyCell(inst); const TimingArcSet *arc_set = edge->timingArcSet();
TimingArcSet *arc_set = edge->timingArcSet();
string result; string result;
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
const Pvt *pvt = sdc_->pvt(inst, dcalc_ap->constraintMinMax()); 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); const Slew &to_slew = graph_->slew(to_vertex, to_rf, slew_index);
bool from_ideal_clk = clk_network_->isIdealClock(from_vertex->pin()); bool from_ideal_clk = clk_network_->isIdealClock(from_vertex->pin());
const char *from_slew_annotation = from_ideal_clk ? " (ideal clock)" : nullptr; const char *from_slew_annotation = from_ideal_clk ? " (ideal clock)" : nullptr;
result = arc_delay_calc_->reportCheckDelay(cell, arc, from_slew, result = arc_delay_calc_->reportCheckDelay(arc, from_slew, from_slew_annotation,
from_slew_annotation, to_slew, to_slew, related_out_cap, pvt,
related_out_cap, pvt, dcalc_ap, dcalc_ap, digits);
digits);
} }
else { else {
Parasitic *to_parasitic = Parasitic *to_parasitic =
arc_delay_calc_->findParasitic(to_pin, to_rf, dcalc_ap); arc_delay_calc_->findParasitic(to_pin, to_rf, dcalc_ap);
const Slew &from_slew = edgeFromSlew(from_vertex, from_rf, 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); float load_cap = loadCap(to_pin, to_parasitic, to_rf, dcalc_ap);
result = arc_delay_calc_->reportGateDelay(cell, arc, result = arc_delay_calc_->reportGateDelay(arc, from_slew, load_cap, to_parasitic,
from_slew, load_cap, to_parasitic,
related_out_cap, pvt, dcalc_ap, digits); related_out_cap, pvt, dcalc_ap, digits);
} }
arc_delay_calc_->finishDrvrPin(); 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 } // namespace

View File

@ -40,7 +40,7 @@ makeLumpedCapDelayCalc(StaState *sta)
} }
LumpedCapDelayCalc::LumpedCapDelayCalc(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); Wireload *wireload = sdc_->wireload(cnst_min_max);
if (wireload) { if (wireload) {
float pin_cap, wire_cap, fanout; float pin_cap, wire_cap, fanout;
bool has_wire_cap; bool has_net_load;
graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap, 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, parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload,
fanout, pin_cap, fanout, pin_cap,
dcalc_ap->operatingConditions(), dcalc_ap->operatingConditions(),
@ -107,32 +107,8 @@ LumpedCapDelayCalc::reducedParasiticType() const
return ReducedParasiticType::pi_elmore; 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 float
LumpedCapDelayCalc::ceff(const LibertyCell *, LumpedCapDelayCalc::ceff(const TimingArc *,
const TimingArc *,
const Slew &, const Slew &,
float load_cap, float load_cap,
const Parasitic *, const Parasitic *,
@ -144,11 +120,10 @@ LumpedCapDelayCalc::ceff(const LibertyCell *,
} }
void void
LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell, LumpedCapDelayCalc::gateDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
float load_cap, float load_cap,
const Parasitic *, const Parasitic *drvr_parasitic,
float related_out_cap, float related_out_cap,
const Pvt *pvt, const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap, const DcalcAnalysisPt *dcalc_ap,
@ -156,6 +131,7 @@ LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell,
ArcDelay &gate_delay, ArcDelay &gate_delay,
Slew &drvr_slew) Slew &drvr_slew)
{ {
gateDelayInit(arc, in_slew, drvr_parasitic);
GateTimingModel *model = gateModel(arc, dcalc_ap); GateTimingModel *model = gateModel(arc, dcalc_ap);
debugPrint(debug_, "delay_calc", 3, debugPrint(debug_, "delay_calc", 3,
" in_slew = %s load_cap = %s related_load_cap = %s lumped", " 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. // NaNs cause seg faults during table lookup.
if (isnan(load_cap) || isnan(related_out_cap) || isnan(delayAsFloat(in_slew))) if (isnan(load_cap) || isnan(related_out_cap) || isnan(delayAsFloat(in_slew)))
report_->error(710, "gate delay input variable is NaN"); 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); pocv_enabled_, gate_delay1, drvr_slew1);
gate_delay = gate_delay1; gate_delay = gate_delay1;
drvr_slew = drvr_slew1; drvr_slew = drvr_slew1;
@ -180,9 +156,6 @@ LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell,
drvr_slew = delay_zero; drvr_slew = delay_zero;
drvr_slew_ = 0.0; drvr_slew_ = 0.0;
} }
drvr_rf_ = arc->toEdge()->asRiseFall();
drvr_library_ = drvr_cell->libertyLibrary();
multi_drvr_slew_factor_ = 1.0F;
} }
void void
@ -197,52 +170,8 @@ LumpedCapDelayCalc::loadDelay(const Pin *load_pin,
load_slew = load_slew1; 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 string
LumpedCapDelayCalc::reportGateDelay(const LibertyCell *drvr_cell, LumpedCapDelayCalc::reportGateDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
float load_cap, float load_cap,
const Parasitic *, const Parasitic *,
@ -254,15 +183,14 @@ LumpedCapDelayCalc::reportGateDelay(const LibertyCell *drvr_cell,
GateTimingModel *model = gateModel(arc, dcalc_ap); GateTimingModel *model = gateModel(arc, dcalc_ap);
if (model) { if (model) {
float in_slew1 = delayAsFloat(in_slew); float in_slew1 = delayAsFloat(in_slew);
return model->reportGateDelay(drvr_cell, pvt, in_slew1, load_cap, return model->reportGateDelay(pvt, in_slew1, load_cap, related_out_cap,
related_out_cap, false, digits); false, digits);
} }
return ""; return "";
} }
void void
LumpedCapDelayCalc::checkDelay(const LibertyCell *cell, LumpedCapDelayCalc::checkDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &from_slew, const Slew &from_slew,
const Slew &to_slew, const Slew &to_slew,
float related_out_cap, float related_out_cap,
@ -275,16 +203,14 @@ LumpedCapDelayCalc::checkDelay(const LibertyCell *cell,
if (model) { if (model) {
float from_slew1 = delayAsFloat(from_slew); float from_slew1 = delayAsFloat(from_slew);
float to_slew1 = delayAsFloat(to_slew); float to_slew1 = delayAsFloat(to_slew);
model->checkDelay(cell, pvt, from_slew1, to_slew1, related_out_cap, model->checkDelay(pvt, from_slew1, to_slew1, related_out_cap, pocv_enabled_, margin);
pocv_enabled_, margin);
} }
else else
margin = delay_zero; margin = delay_zero;
} }
string string
LumpedCapDelayCalc::reportCheckDelay(const LibertyCell *cell, LumpedCapDelayCalc::reportCheckDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &from_slew, const Slew &from_slew,
const char *from_slew_annotation, const char *from_slew_annotation,
const Slew &to_slew, const Slew &to_slew,
@ -297,16 +223,10 @@ LumpedCapDelayCalc::reportCheckDelay(const LibertyCell *cell,
if (model) { if (model) {
float from_slew1 = delayAsFloat(from_slew); float from_slew1 = delayAsFloat(from_slew);
float to_slew1 = delayAsFloat(to_slew); float to_slew1 = delayAsFloat(to_slew);
return model->reportCheckDelay(cell, pvt, from_slew1, from_slew_annotation, to_slew1, return model->reportCheckDelay(pvt, from_slew1, from_slew_annotation,
related_out_cap, false, digits); to_slew1, related_out_cap, false, digits);
} }
return ""; return "";
} }
void
LumpedCapDelayCalc::setMultiDrvrSlewFactor(float factor)
{
multi_drvr_slew_factor_ = factor;
}
} // namespace } // namespace

View File

@ -16,13 +16,13 @@
#pragma once #pragma once
#include "ArcDelayCalc.hh" #include "ParallelDelayCalc.hh"
namespace sta { namespace sta {
// Liberty table model lumped capacitance arc delay calculator. // Liberty table model lumped capacitance arc delay calculator.
// Wire delays are zero. // Wire delays are zero.
class LumpedCapDelayCalc : public ArcDelayCalc class LumpedCapDelayCalc : public ParallelDelayCalc
{ {
public: public:
LumpedCapDelayCalc(StaState *sta); LumpedCapDelayCalc(StaState *sta);
@ -31,13 +31,7 @@ public:
const RiseFall *rf, const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override; const DcalcAnalysisPt *dcalc_ap) override;
ReducedParasiticType reducedParasiticType() const override; ReducedParasiticType reducedParasiticType() const override;
void inputPortDelay(const Pin *port_pin, void gateDelay(const TimingArc *arc,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap) override;
void gateDelay(const LibertyCell *drvr_cell,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
float load_cap, float load_cap,
const Parasitic *drvr_parasitic, const Parasitic *drvr_parasitic,
@ -47,9 +41,7 @@ public:
// Return values. // Return values.
ArcDelay &gate_delay, ArcDelay &gate_delay,
Slew &drvr_slew) override; Slew &drvr_slew) override;
void setMultiDrvrSlewFactor(float factor) override; float ceff(const TimingArc *arc,
float ceff(const LibertyCell *drvr_cell,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
float load_cap, float load_cap,
const Parasitic *drvr_parasitic, const Parasitic *drvr_parasitic,
@ -60,8 +52,7 @@ public:
// Return values. // Return values.
ArcDelay &wire_delay, ArcDelay &wire_delay,
Slew &load_slew) override; Slew &load_slew) override;
void checkDelay(const LibertyCell *cell, void checkDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &from_slew, const Slew &from_slew,
const Slew &to_slew, const Slew &to_slew,
float related_out_cap, float related_out_cap,
@ -69,8 +60,7 @@ public:
const DcalcAnalysisPt *dcalc_ap, const DcalcAnalysisPt *dcalc_ap,
// Return values. // Return values.
ArcDelay &margin) override; ArcDelay &margin) override;
string reportGateDelay(const LibertyCell *drvr_cell, string reportGateDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
float load_cap, float load_cap,
const Parasitic *drvr_parasitic, const Parasitic *drvr_parasitic,
@ -78,8 +68,7 @@ public:
const Pvt *pvt, const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap, const DcalcAnalysisPt *dcalc_ap,
int digits) override; int digits) override;
string reportCheckDelay(const LibertyCell *cell, string reportCheckDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &from_slew, const Slew &from_slew,
const char *from_slew_annotation, const char *from_slew_annotation,
const Slew &to_slew, const Slew &to_slew,
@ -87,25 +76,8 @@ public:
const Pvt *pvt, const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap, const DcalcAnalysisPt *dcalc_ap,
int digits) override; int digits) override;
void finishDrvrPin() override;
protected: 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<Parasitic*> unsaved_parasitics_;
Vector<const Pin *> reduced_parasitic_drvrs_;
}; };
ArcDelayCalc * ArcDelayCalc *

171
dcalc/ParallelDelayCalc.cc Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
#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 &parallel_delay,
Slew &parallel_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

View File

@ -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 <https://www.gnu.org/licenses/>.
#pragma once
#include <vector>
#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 &parallel_delay,
Slew &parallel_slew);
// [drvr_rf->index][dcalc_ap->index]
vector<ArcDelay> parallel_delays_;
// [drvr_rf->index][dcalc_ap->index]
vector<Slew> parallel_slews_;
float multi_drvr_slew_factor_;
};
} // namespace

View File

@ -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 <https://www.gnu.org/licenses/>.
#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

View File

@ -22,6 +22,7 @@
#include "Sdc.hh" #include "Sdc.hh"
#include "Parasitics.hh" #include "Parasitics.hh"
#include "DcalcAnalysisPt.hh" #include "DcalcAnalysisPt.hh"
#include "LumpedCapDelayCalc.hh"
namespace sta { namespace sta {
@ -30,33 +31,32 @@ namespace sta {
// Wire delays are elmore delays. // Wire delays are elmore delays.
// Driver slews are degraded to loads by rise/fall transition_degradation // Driver slews are degraded to loads by rise/fall transition_degradation
// tables. // tables.
class SlewDegradeDelayCalc : public RCDelayCalc class SlewDegradeDelayCalc : public LumpedCapDelayCalc
{ {
public: public:
SlewDegradeDelayCalc(StaState *sta); SlewDegradeDelayCalc(StaState *sta);
virtual ArcDelayCalc *copy(); ArcDelayCalc *copy() override;
virtual void inputPortDelay(const Pin *port_pin, void inputPortDelay(const Pin *port_pin,
float in_slew, float in_slew,
const RiseFall *rf, const RiseFall *rf,
const Parasitic *parasitic, const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap); const DcalcAnalysisPt *dcalc_ap) override;
virtual void gateDelay(const LibertyCell *drvr_cell, void gateDelay(const TimingArc *arc,
const TimingArc *arc, const Slew &in_slew,
const Slew &in_slew, float load_cap,
float load_cap, const Parasitic *drvr_parasitic,
const Parasitic *drvr_parasitic, float related_out_cap,
float related_out_cap, const Pvt *pvt,
const Pvt *pvt, const DcalcAnalysisPt *dcalc_ap,
const DcalcAnalysisPt *dcalc_ap, // Return values.
// Return values. ArcDelay &gate_delay,
ArcDelay &gate_delay, Slew &drvr_slew) override;
Slew &drvr_slew); void loadDelay(const Pin *load_pin,
virtual void loadDelay(const Pin *load_pin, ArcDelay &wire_delay,
ArcDelay &wire_delay, Slew &load_slew) override;
Slew &load_slew);
using RCDelayCalc::gateDelay; using LumpedCapDelayCalc::gateDelay;
using RCDelayCalc::reportGateDelay; using LumpedCapDelayCalc::reportGateDelay;
private: private:
const Pvt *pvt_; const Pvt *pvt_;
@ -69,7 +69,7 @@ makeSlewDegradeDelayCalc(StaState *sta)
} }
SlewDegradeDelayCalc::SlewDegradeDelayCalc(StaState *sta) : SlewDegradeDelayCalc::SlewDegradeDelayCalc(StaState *sta) :
RCDelayCalc(sta) LumpedCapDelayCalc(sta)
{ {
} }
@ -87,12 +87,11 @@ SlewDegradeDelayCalc::inputPortDelay(const Pin *port_pin,
const DcalcAnalysisPt *dcalc_ap) const DcalcAnalysisPt *dcalc_ap)
{ {
pvt_ = dcalc_ap->operatingConditions(); 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 void
SlewDegradeDelayCalc::gateDelay(const LibertyCell *drvr_cell, SlewDegradeDelayCalc::gateDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
float load_cap, float load_cap,
const Parasitic *drvr_parasitic, const Parasitic *drvr_parasitic,
@ -106,12 +105,11 @@ SlewDegradeDelayCalc::gateDelay(const LibertyCell *drvr_cell,
input_port_ = false; input_port_ = false;
drvr_parasitic_ = drvr_parasitic; drvr_parasitic_ = drvr_parasitic;
drvr_rf_ = arc->toEdge()->asRiseFall(); drvr_rf_ = arc->toEdge()->asRiseFall();
drvr_cell_ = drvr_cell; drvr_cell_ = arc->from()->libertyCell();
drvr_library_ = drvr_cell->libertyLibrary(); drvr_library_ = drvr_cell_->libertyLibrary();
pvt_ = pvt; pvt_ = pvt;
LumpedCapDelayCalc::gateDelay(drvr_cell, arc, in_slew, LumpedCapDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic,
load_cap, drvr_parasitic, related_out_cap, related_out_cap, pvt, dcalc_ap,
pvt, dcalc_ap,
gate_delay, drvr_slew); gate_delay, drvr_slew);
} }
@ -129,8 +127,7 @@ SlewDegradeDelayCalc::loadDelay(const Pin *load_pin,
if (elmore_exists) { if (elmore_exists) {
if (drvr_library_ && drvr_library_->wireSlewDegradationTable(drvr_rf_)) { if (drvr_library_ && drvr_library_->wireSlewDegradationTable(drvr_rf_)) {
wire_delay1 = elmore; wire_delay1 = elmore;
load_slew1 = drvr_library_->degradeWireSlew(drvr_cell_, drvr_rf_, load_slew1 = drvr_library_->degradeWireSlew(drvr_rf_,
pvt_,
delayAsFloat(drvr_slew_), delayAsFloat(drvr_slew_),
delayAsFloat(wire_delay1)); delayAsFloat(wire_delay1));
} }

View File

@ -16,10 +16,11 @@
#pragma once #pragma once
#include "RCDelayCalc.hh"
namespace sta { namespace sta {
class ArcDelayCalc;
class StaState;
ArcDelayCalc * ArcDelayCalc *
makeSlewDegradeDelayCalc(StaState *sta); makeSlewDegradeDelayCalc(StaState *sta);

View File

@ -61,8 +61,7 @@ UnitDelayCalc::inputPortDelay(const Pin *,
} }
void void
UnitDelayCalc::gateDelay(const LibertyCell *, UnitDelayCalc::gateDelay(const TimingArc *,
const TimingArc *,
const Slew &, const Slew &,
float, float,
const Parasitic *, const Parasitic *,
@ -75,6 +74,29 @@ UnitDelayCalc::gateDelay(const LibertyCell *,
drvr_slew = 0.0; 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 void
UnitDelayCalc::loadDelay(const Pin *, UnitDelayCalc::loadDelay(const Pin *,
ArcDelay &wire_delay, ArcDelay &wire_delay,
@ -85,8 +107,7 @@ UnitDelayCalc::loadDelay(const Pin *,
} }
float float
UnitDelayCalc::ceff(const LibertyCell *, UnitDelayCalc::ceff(const TimingArc *,
const TimingArc *,
const Slew &, const Slew &,
float, float,
const Parasitic *, const Parasitic *,
@ -98,8 +119,7 @@ UnitDelayCalc::ceff(const LibertyCell *,
} }
string string
UnitDelayCalc::reportGateDelay(const LibertyCell *, UnitDelayCalc::reportGateDelay(const TimingArc *,
const TimingArc *,
const Slew &, const Slew &,
float, float,
const Parasitic *, const Parasitic *,
@ -114,8 +134,7 @@ UnitDelayCalc::reportGateDelay(const LibertyCell *,
} }
void void
UnitDelayCalc::checkDelay(const LibertyCell *, UnitDelayCalc::checkDelay(const TimingArc *,
const TimingArc *,
const Slew &, const Slew &,
const Slew &, const Slew &,
float, float,
@ -128,8 +147,7 @@ UnitDelayCalc::checkDelay(const LibertyCell *,
} }
string string
UnitDelayCalc::reportCheckDelay(const LibertyCell *, UnitDelayCalc::reportCheckDelay(const TimingArc *,
const TimingArc *,
const Slew &, const Slew &,
const char *, const char *,
const Slew &, const Slew &,

View File

@ -35,8 +35,7 @@ public:
const RiseFall *rf, const RiseFall *rf,
const Parasitic *parasitic, const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap) override; const DcalcAnalysisPt *dcalc_ap) override;
void gateDelay(const LibertyCell *drvr_cell, void gateDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
float load_cap, float load_cap,
const Parasitic *drvr_parasitic, const Parasitic *drvr_parasitic,
@ -46,21 +45,32 @@ public:
// Return values. // Return values.
ArcDelay &gate_delay, ArcDelay &gate_delay,
Slew &drvr_slew) override; 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, void loadDelay(const Pin *load_pin,
// Return values. // Return values.
ArcDelay &wire_delay, ArcDelay &wire_delay,
Slew &load_slew) override; Slew &load_slew) override;
void setMultiDrvrSlewFactor(float) override {} float ceff(const TimingArc *arc,
float ceff(const LibertyCell *drvr_cell,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
float load_cap, float load_cap,
const Parasitic *drvr_parasitic, const Parasitic *drvr_parasitic,
float related_out_cap, float related_out_cap,
const Pvt *pvt, const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap) override; const DcalcAnalysisPt *dcalc_ap) override;
void checkDelay(const LibertyCell *cell, void checkDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &from_slew, const Slew &from_slew,
const Slew &to_slew, const Slew &to_slew,
float related_out_cap, float related_out_cap,
@ -68,8 +78,7 @@ public:
const DcalcAnalysisPt *dcalc_ap, const DcalcAnalysisPt *dcalc_ap,
// Return values. // Return values.
ArcDelay &margin) override; ArcDelay &margin) override;
string reportGateDelay(const LibertyCell *drvr_cell, string reportGateDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
float load_cap, float load_cap,
const Parasitic *drvr_parasitic, const Parasitic *drvr_parasitic,
@ -77,8 +86,7 @@ public:
const Pvt *pvt, const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap, const DcalcAnalysisPt *dcalc_ap,
int digits) override; int digits) override;
string reportCheckDelay(const LibertyCell *cell, string reportCheckDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &from_slew, const Slew &from_slew,
const char *from_slew_annotation, const char *from_slew_annotation,
const Slew &to_slew, const Slew &to_slew,

View File

@ -783,8 +783,8 @@ Graph::setWireArcDelay(Edge *edge,
} }
bool bool
Graph::arcDelayAnnotated(Edge *edge, Graph::arcDelayAnnotated(const Edge *edge,
TimingArc *arc, const TimingArc *arc,
DcalcAPIndex ap_index) const DcalcAPIndex ap_index) const
{ {
if (arc_delay_annotated_.size()) { if (arc_delay_annotated_.size()) {
@ -799,7 +799,7 @@ Graph::arcDelayAnnotated(Edge *edge,
void void
Graph::setArcDelayAnnotated(Edge *edge, Graph::setArcDelayAnnotated(Edge *edge,
TimingArc *arc, const TimingArc *arc,
DcalcAPIndex ap_index, DcalcAPIndex ap_index,
bool annotated) bool annotated)
{ {

View File

@ -17,6 +17,7 @@
#pragma once #pragma once
#include <string> #include <string>
#include <vector>
#include "MinMax.hh" #include "MinMax.hh"
#include "LibertyClass.hh" #include "LibertyClass.hh"
@ -28,22 +29,26 @@
namespace sta { namespace sta {
using std::string; using std::string;
using std::vector;
class Parasitic; class Parasitic;
class DcalcAnalysisPt; class DcalcAnalysisPt;
class MultiDrvrNet;
// Delay calculator class hierarchy. // Delay calculator class hierarchy.
// ArcDelayCalc // ArcDelayCalc
// UnitDelayCalc // UnitDelayCalc
// LumpedCapDelayCalc // DelayCalcBase
// RCDelayCalc // ParallelDelayCalc
// SlewDegradeDelayCalc // LumpedCapDelayCalc
// DmpCeffDelayCalc // SlewDegradeDelayCalc
// DmpCeffElmoreDelayCalc // DmpCeffDelayCalc
// DmpCeffTwoPoleDelayCalc // DmpCeffElmoreDelayCalc
// ArnoldiDelayCalc // 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 class ArcDelayCalc : public StaState
{ {
public: public:
@ -66,8 +71,7 @@ public:
const DcalcAnalysisPt *dcalc_ap) = 0; const DcalcAnalysisPt *dcalc_ap) = 0;
// Find the delay and slew for arc driving drvr_pin. // Find the delay and slew for arc driving drvr_pin.
virtual void gateDelay(const LibertyCell *drvr_cell, virtual void gateDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
// Pass in load_cap or drvr_parasitic. // Pass in load_cap or drvr_parasitic.
float load_cap, float load_cap,
@ -78,16 +82,29 @@ public:
// Return values. // Return values.
ArcDelay &gate_delay, ArcDelay &gate_delay,
Slew &drvr_slew) = 0; 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. // Find the wire delay and load slew of a load pin.
// Called after inputPortDelay or gateDelay. // Called after inputPortDelay or gateDelay.
virtual void loadDelay(const Pin *load_pin, virtual void loadDelay(const Pin *load_pin,
// Return values. // Return values.
ArcDelay &wire_delay, ArcDelay &wire_delay,
Slew &load_slew) = 0; Slew &load_slew) = 0;
virtual void setMultiDrvrSlewFactor(float factor) = 0;
// Ceff for parasitics with pi models. // Ceff for parasitics with pi models.
virtual float ceff(const LibertyCell *drvr_cell, virtual float ceff(const TimingArc *arc,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
float load_cap, float load_cap,
const Parasitic *drvr_parasitic, const Parasitic *drvr_parasitic,
@ -97,8 +114,7 @@ public:
// Find the delay for a timing check arc given the arc's // Find the delay for a timing check arc given the arc's
// from/clock, to/data slews and related output pin parasitic. // from/clock, to/data slews and related output pin parasitic.
virtual void checkDelay(const LibertyCell *drvr_cell, virtual void checkDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &from_slew, const Slew &from_slew,
const Slew &to_slew, const Slew &to_slew,
float related_out_cap, float related_out_cap,
@ -107,8 +123,7 @@ public:
// Return values. // Return values.
ArcDelay &margin) = 0; ArcDelay &margin) = 0;
// Report delay and slew calculation. // Report delay and slew calculation.
virtual string reportGateDelay(const LibertyCell *drvr_cell, virtual string reportGateDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,
// Pass in load_cap or drvr_parasitic. // Pass in load_cap or drvr_parasitic.
float load_cap, float load_cap,
@ -118,8 +133,7 @@ public:
const DcalcAnalysisPt *dcalc_ap, const DcalcAnalysisPt *dcalc_ap,
int digits) = 0; int digits) = 0;
// Report timing check delay calculation. // Report timing check delay calculation.
virtual string reportCheckDelay(const LibertyCell *cell, virtual string reportCheckDelay(const TimingArc *arc,
const TimingArc *arc,
const Slew &from_slew, const Slew &from_slew,
const char *from_slew_annotation, const char *from_slew_annotation,
const Slew &to_slew, const Slew &to_slew,

View File

@ -157,11 +157,11 @@ public:
DcalcAPIndex ap_index, DcalcAPIndex ap_index,
const ArcDelay &delay); const ArcDelay &delay);
// Is timing arc delay annotated. // Is timing arc delay annotated.
bool arcDelayAnnotated(Edge *edge, bool arcDelayAnnotated(const Edge *edge,
TimingArc *arc, const TimingArc *arc,
DcalcAPIndex ap_index) const; DcalcAPIndex ap_index) const;
void setArcDelayAnnotated(Edge *edge, void setArcDelayAnnotated(Edge *edge,
TimingArc *arc, const TimingArc *arc,
DcalcAPIndex ap_index, DcalcAPIndex ap_index,
bool annotated); bool annotated);
bool wireDelayAnnotated(Edge *edge, bool wireDelayAnnotated(Edge *edge,
@ -539,7 +539,6 @@ class VertexSet : public Set<Vertex*, VertexIdLess>
{ {
public: public:
VertexSet(Graph *&graph); VertexSet(Graph *&graph);
VertexSet(const VertexSet &set);
}; };
} // namespace } // namespace

View File

@ -16,6 +16,8 @@
#pragma once #pragma once
#include <vector>
#include "Map.hh" #include "Map.hh"
#include "NetworkClass.hh" #include "NetworkClass.hh"
#include "GraphClass.hh" #include "GraphClass.hh"
@ -26,9 +28,12 @@
namespace sta { namespace sta {
using std::vector;
class DelayCalcObserver; class DelayCalcObserver;
class MultiDrvrNet; class MultiDrvrNet;
class FindVertexDelays; class FindVertexDelays;
class NetCaps;
typedef Map<const Vertex*, MultiDrvrNet*> MultiDrvrNetMap; typedef Map<const Vertex*, MultiDrvrNet*> MultiDrvrNetMap;
@ -55,8 +60,8 @@ public:
// Find and annotate drvr_vertex gate and load delays/slews. // Find and annotate drvr_vertex gate and load delays/slews.
virtual void findDelays(Vertex *drvr_vertex); virtual void findDelays(Vertex *drvr_vertex);
// Returned string is owned by the caller. // Returned string is owned by the caller.
virtual string reportDelayCalc(Edge *edge, virtual string reportDelayCalc(const Edge *edge,
TimingArc *arc, const TimingArc *arc,
const Corner *corner, const Corner *corner,
const MinMax *min_max, const MinMax *min_max,
int digits); int digits);
@ -85,6 +90,11 @@ public:
const Parasitic *drvr_parasitic, const Parasitic *drvr_parasitic,
const RiseFall *rf, const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) const; 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, virtual void netCaps(const Pin *drvr_pin,
const RiseFall *rf, const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap, const DcalcAnalysisPt *dcalc_ap,
@ -115,10 +125,13 @@ public:
float &min_period, float &min_period,
bool &exists); bool &exists);
Slew edgeFromSlew(const Vertex *from_vertex,
const RiseFall *from_rf,
const Edge *edge,
const DcalcAnalysisPt *dcalc_ap);
protected: protected:
void seedInvalidDelays(); void seedInvalidDelays();
void ensureMultiDrvrNetsFound();
void makeMultiDrvrNet(PinSet &drvr_pins);
void initSlew(Vertex *vertex); void initSlew(Vertex *vertex);
void seedRootSlew(Vertex *vertex, void seedRootSlew(Vertex *vertex,
ArcDelayCalc *arc_delay_calc); ArcDelayCalc *arc_delay_calc);
@ -150,23 +163,23 @@ protected:
const LibertyPort *to_port); const LibertyPort *to_port);
int findPortIndex(const LibertyCell *cell, int findPortIndex(const LibertyCell *cell,
const LibertyPort *port); const LibertyPort *port);
void findInputArcDelay(const LibertyCell *drvr_cell, void findInputArcDelay(const Pin *drvr_pin,
const Pin *drvr_pin,
Vertex *drvr_vertex, Vertex *drvr_vertex,
const TimingArc *arc, const TimingArc *arc,
float from_slew, float from_slew,
const DcalcAnalysisPt *dcalc_ap); const DcalcAnalysisPt *dcalc_ap);
bool findDriverDelays(Vertex *drvr_vertex, bool findDriverDelays(Vertex *drvr_vertex,
ArcDelayCalc *arc_delay_calc); ArcDelayCalc *arc_delay_calc);
MultiDrvrNet *findMultiDrvrNet(Vertex *drvr_pin);
MultiDrvrNet *makeMultiDrvrNet(PinSet &drvr_pins);
bool findDriverDelays1(Vertex *drvr_vertex, bool findDriverDelays1(Vertex *drvr_vertex,
MultiDrvrNet *multi_drvr, MultiDrvrNet *multi_drvr,
ArcDelayCalc *arc_delay_calc); ArcDelayCalc *arc_delay_calc);
void initLoadSlews(Vertex *drvr_vertex); void initLoadSlews(Vertex *drvr_vertex);
bool findDriverEdgeDelays(LibertyCell *drvr_cell, bool findDriverEdgeDelays(const Instance *drvr_inst,
Instance *drvr_inst,
const Pin *drvr_pin, const Pin *drvr_pin,
Vertex *drvr_vertex, Vertex *drvr_vertex,
MultiDrvrNet *multi_drvr, const MultiDrvrNet *multi_drvr,
Edge *edge, Edge *edge,
ArcDelayCalc *arc_delay_calc); ArcDelayCalc *arc_delay_calc);
void initWireDelays(Vertex *drvr_vertex); void initWireDelays(Vertex *drvr_vertex);
@ -176,17 +189,16 @@ protected:
ArcDelayCalc *arc_delay_calc, ArcDelayCalc *arc_delay_calc,
bool propagate); bool propagate);
void enqueueTimingChecksEdges(Vertex *vertex); void enqueueTimingChecksEdges(Vertex *vertex);
bool findArcDelay(LibertyCell *drvr_cell, bool findArcDelay(const Pin *drvr_pin,
const Pin *drvr_pin,
Vertex *drvr_vertex, Vertex *drvr_vertex,
MultiDrvrNet *multi_drvr, const TimingArc *arc,
TimingArc *arc, const Parasitic *drvr_parasitic,
Parasitic *drvr_parasitic,
float related_out_cap, float related_out_cap,
Vertex *from_vertex, Vertex *from_vertex,
Edge *edge, Edge *edge,
const Pvt *pvt, const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap, const DcalcAnalysisPt *dcalc_ap,
const MultiDrvrNet *multi_drvr,
ArcDelayCalc *arc_delay_calc); ArcDelayCalc *arc_delay_calc);
void annotateLoadDelays(Vertex *drvr_vertex, void annotateLoadDelays(Vertex *drvr_vertex,
const RiseFall *drvr_rf, const RiseFall *drvr_rf,
@ -197,32 +209,7 @@ protected:
void findLatchEdgeDelays(Edge *edge); void findLatchEdgeDelays(Edge *edge);
void findCheckEdgeDelays(Edge *edge, void findCheckEdgeDelays(Edge *edge,
ArcDelayCalc *arc_delay_calc); 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 &parallel_delay,
Slew &parallel_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(); 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, Slew checkEdgeClkSlew(const Vertex *from_vertex,
const RiseFall *from_rf, const RiseFall *from_rf,
const DcalcAnalysisPt *dcalc_ap); const DcalcAnalysisPt *dcalc_ap);
@ -233,11 +220,6 @@ protected:
// Return values. // Return values.
float &pin_cap, float &pin_cap,
float &wire_cap) const; 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. // Observer for edge delay changes.
DelayCalcObserver *observer_; DelayCalcObserver *observer_;
@ -277,4 +259,33 @@ public:
virtual void checkDelayChangedTo(Vertex *vertex) = 0; 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<NetCaps> net_caps_;
};
} // namespace } // namespace

View File

@ -167,16 +167,14 @@ public:
const LibertyCell *cell, const LibertyCell *cell,
const Pvt *pvt) const; const Pvt *pvt) const;
float scaleFactor(ScaleFactorType type, float scaleFactor(ScaleFactorType type,
int tr_index, int rf_index,
const LibertyCell *cell, const LibertyCell *cell,
const Pvt *pvt) const; const Pvt *pvt) const;
void setWireSlewDegradationTable(TableModel *model, void setWireSlewDegradationTable(TableModel *model,
RiseFall *rf); RiseFall *rf);
TableModel *wireSlewDegradationTable(const RiseFall *rf) const; TableModel *wireSlewDegradationTable(const RiseFall *rf) const;
float degradeWireSlew(const LibertyCell *cell, float degradeWireSlew(const RiseFall *rf,
const RiseFall *rf,
const Pvt *pvt,
float in_slew, float in_slew,
float wire_delay) const; float wire_delay) const;
// Check for supported axis variables. // Check for supported axis variables.
@ -323,9 +321,7 @@ public:
void addDriverWaveform(DriverWaveform *driver_waveform); void addDriverWaveform(DriverWaveform *driver_waveform);
protected: protected:
float degradeWireSlew(const LibertyCell *cell, float degradeWireSlew(const TableModel *model,
const Pvt *pvt,
const TableModel *model,
float in_slew, float in_slew,
float wire_delay) const; float wire_delay) const;
@ -925,7 +921,7 @@ public:
RiseFall *rf); RiseFall *rf);
float scale(ScaleFactorType type, float scale(ScaleFactorType type,
ScaleFactorPvt pvt, ScaleFactorPvt pvt,
int tr_index); int rf_index);
float scale(ScaleFactorType type, float scale(ScaleFactorType type,
ScaleFactorPvt pvt); ScaleFactorPvt pvt);
void setScale(ScaleFactorType type, void setScale(ScaleFactorType type,

View File

@ -23,9 +23,10 @@ namespace sta {
class GateLinearModel : public GateTimingModel class GateLinearModel : public GateTimingModel
{ {
public: public:
GateLinearModel(float intrinsic, float resistance); GateLinearModel(LibertyCell *cell,
void gateDelay(const LibertyCell *cell, float intrinsic,
const Pvt *pvt, float resistance);
void gateDelay(const Pvt *pvt,
float in_slew, float in_slew,
float load_cap, float load_cap,
float related_out_cap, float related_out_cap,
@ -33,15 +34,13 @@ public:
// Return values. // Return values.
ArcDelay &gate_delay, ArcDelay &gate_delay,
Slew &drvr_slew) const override; Slew &drvr_slew) const override;
string reportGateDelay(const LibertyCell *cell, string reportGateDelay(const Pvt *pvt,
const Pvt *pvt,
float in_slew, float in_slew,
float load_cap, float load_cap,
float related_out_cap, float related_out_cap,
bool pocv_enabled, bool pocv_enabled,
int digits) const override; int digits) const override;
float driveResistance(const LibertyCell *cell, float driveResistance(const Pvt *pvt) const override;
const Pvt *pvt) const override;
protected: protected:
void setIsScaled(bool is_scaled) override; void setIsScaled(bool is_scaled) override;
@ -53,17 +52,16 @@ protected:
class CheckLinearModel : public CheckTimingModel class CheckLinearModel : public CheckTimingModel
{ {
public: public:
explicit CheckLinearModel(float intrinsic); explicit CheckLinearModel(LibertyCell *cell,
void checkDelay(const LibertyCell *cell, float intrinsic);
const Pvt *pvt, void checkDelay(const Pvt *pvt,
float from_slew, float from_slew,
float to_slew, float to_slew,
float related_out_cap, float related_out_cap,
bool pocv_enabled, bool pocv_enabled,
// Return values. // Return values.
ArcDelay &margin) const override; ArcDelay &margin) const override;
string reportCheckDelay(const LibertyCell *cell, string reportCheckDelay(const Pvt *pvt,
const Pvt *pvt,
float from_slew, float from_slew,
const char *from_slew_annotation, const char *from_slew_annotation,
float to_slew, float to_slew,

View File

@ -827,7 +827,8 @@ public:
// Returns nullptr if set_operating_conditions has not been called. // Returns nullptr if set_operating_conditions has not been called.
OperatingConditions *operatingConditions(const MinMax *min_max); OperatingConditions *operatingConditions(const MinMax *min_max);
// Instance specific process/voltage/temperature. // 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. // Pvt may be shared among multiple instances.
void setPvt(const Instance *inst, void setPvt(const Instance *inst,
const MinMaxAll *min_max, const MinMaxAll *min_max,

View File

@ -51,15 +51,15 @@ tableVariableUnit(TableAxisVariable variable,
class GateTableModel : public GateTimingModel class GateTableModel : public GateTimingModel
{ {
public: public:
GateTableModel(TableModel *delay_model, GateTableModel(LibertyCell *cell,
TableModel *delay_model,
TableModel *delay_sigma_models[EarlyLate::index_count], TableModel *delay_sigma_models[EarlyLate::index_count],
TableModel *slew_model, TableModel *slew_model,
TableModel *slew_sigma_models[EarlyLate::index_count], TableModel *slew_sigma_models[EarlyLate::index_count],
ReceiverModelPtr receiver_model, ReceiverModelPtr receiver_model,
OutputWaveforms *output_waveforms); OutputWaveforms *output_waveforms);
virtual ~GateTableModel(); virtual ~GateTableModel();
void gateDelay(const LibertyCell *cell, void gateDelay(const Pvt *pvt,
const Pvt *pvt,
float in_slew, float in_slew,
float load_cap, float load_cap,
float related_out_cap, float related_out_cap,
@ -67,15 +67,13 @@ public:
// Return values. // Return values.
ArcDelay &gate_delay, ArcDelay &gate_delay,
Slew &drvr_slew) const override; Slew &drvr_slew) const override;
string reportGateDelay(const LibertyCell *cell, string reportGateDelay(const Pvt *pvt,
const Pvt *pvt,
float in_slew, float in_slew,
float load_cap, float load_cap,
float related_out_cap, float related_out_cap,
bool pocv_enabled, bool pocv_enabled,
int digits) const override; int digits) const override;
float driveResistance(const LibertyCell *cell, float driveResistance(const Pvt *pvt) const override;
const Pvt *pvt) const override;
const TableModel *delayModel() const { return delay_model_; } const TableModel *delayModel() const { return delay_model_; }
const TableModel *slewModel() const { return slew_model_; } const TableModel *slewModel() const { return slew_model_; }
@ -86,8 +84,7 @@ public:
static bool checkAxes(const TablePtr table); static bool checkAxes(const TablePtr table);
protected: protected:
void maxCapSlew(const LibertyCell *cell, void maxCapSlew(float in_slew,
float in_slew,
const Pvt *pvt, const Pvt *pvt,
float &slew, float &slew,
float &cap) const; float &cap) const;
@ -96,16 +93,12 @@ protected:
float load_cap, float load_cap,
float in_slew, float in_slew,
float related_out_cap) const; float related_out_cap) const;
float findValue(const LibertyLibrary *library, float findValue(const Pvt *pvt,
const LibertyCell *cell,
const Pvt *pvt,
const TableModel *model, const TableModel *model,
float in_slew, float in_slew,
float load_cap, float load_cap,
float related_out_cap) const; float related_out_cap) const;
string reportTableLookup(const char *result_name, string reportTableLookup(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
const TableModel *model, const TableModel *model,
float in_slew, float in_slew,
@ -133,19 +126,18 @@ protected:
class CheckTableModel : public CheckTimingModel class CheckTableModel : public CheckTimingModel
{ {
public: public:
explicit CheckTableModel(TableModel *model, explicit CheckTableModel(LibertyCell *cell,
TableModel *model,
TableModel *sigma_models[EarlyLate::index_count]); TableModel *sigma_models[EarlyLate::index_count]);
virtual ~CheckTableModel(); virtual ~CheckTableModel();
void checkDelay(const LibertyCell *cell, void checkDelay(const Pvt *pvt,
const Pvt *pvt,
float from_slew, float from_slew,
float to_slew, float to_slew,
float related_out_cap, float related_out_cap,
bool pocv_enabled, bool pocv_enabled,
// Return values. // Return values.
ArcDelay &margin) const override; ArcDelay &margin) const override;
string reportCheckDelay(const LibertyCell *cell, string reportCheckDelay(const Pvt *pvt,
const Pvt *pvt,
float from_slew, float from_slew,
const char *from_slew_annotation, const char *from_slew_annotation,
float to_slew, float to_slew,
@ -160,9 +152,7 @@ public:
protected: protected:
void setIsScaled(bool is_scaled) override; void setIsScaled(bool is_scaled) override;
float findValue(const LibertyLibrary *library, float findValue(const Pvt *pvt,
const LibertyCell *cell,
const Pvt *pvt,
const TableModel *model, const TableModel *model,
float from_slew, float from_slew,
float to_slew, float to_slew,
@ -179,8 +169,6 @@ protected:
float in_slew, float in_slew,
float related_out_cap) const; float related_out_cap) const;
string reportTableDelay(const char *result_name, string reportTableDelay(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
const TableModel *model, const TableModel *model,
float from_slew, float from_slew,
@ -217,14 +205,12 @@ public:
float value2, float value2,
float value3) const; float value3) const;
// Table interpolated lookup with scale factor. // Table interpolated lookup with scale factor.
float findValue(const LibertyLibrary *library, float findValue(const LibertyCell *cell,
const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
float value1, float value1,
float value2, float value2,
float value3) const; float value3) const;
string reportValue(const char *result_name, string reportValue(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell, const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
float value1, float value1,
@ -237,11 +223,9 @@ public:
Report *report) const; Report *report) const;
protected: protected:
float scaleFactor(const LibertyLibrary *library, float scaleFactor(const LibertyCell *cell,
const LibertyCell *cell,
const Pvt *pvt) const; const Pvt *pvt) const;
string reportPvtScaleFactor(const LibertyLibrary *library, string reportPvtScaleFactor(const LibertyCell *cell,
const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
int digits) const; int digits) const;
@ -280,7 +264,6 @@ public:
float axis_value2, float axis_value2,
float axis_value3) const; float axis_value3) const;
virtual string reportValue(const char *result_name, virtual string reportValue(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell, const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
float value1, float value1,
@ -306,7 +289,6 @@ public:
float axis_value2, float axis_value2,
float axis_value3) const override; float axis_value3) const override;
string reportValue(const char *result_name, string reportValue(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell, const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
float value1, float value1,
@ -342,7 +324,6 @@ public:
float value2, float value2,
float value3) const override; float value3) const override;
string reportValue(const char *result_name, string reportValue(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell, const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
float value1, float value1,
@ -389,7 +370,6 @@ public:
float value2, float value2,
float value3) const override; float value3) const override;
string reportValue(const char *result_name, string reportValue(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell, const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
float value1, float value1,
@ -436,7 +416,6 @@ public:
float value2, float value2,
float value3) const override; float value3) const override;
string reportValue(const char *result_name, string reportValue(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell, const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
float value1, float value1,

View File

@ -29,21 +29,21 @@ using std::string;
class TimingModel class TimingModel
{ {
public: public:
TimingModel(LibertyCell *cell);
virtual ~TimingModel() {} virtual ~TimingModel() {}
protected:
virtual void setIsScaled(bool is_scaled) = 0; virtual void setIsScaled(bool is_scaled) = 0;
friend class LibertyCell; protected:
LibertyCell *cell_;
}; };
// Abstract base class for LinearModel and TableModel. // Abstract base class for LinearModel and TableModel.
class GateTimingModel : public TimingModel class GateTimingModel : public TimingModel
{ {
public: public:
GateTimingModel(LibertyCell *cell);
// Gate delay calculation. // Gate delay calculation.
virtual void gateDelay(const LibertyCell *cell, virtual void gateDelay(const Pvt *pvt,
const Pvt *pvt,
float in_slew, float in_slew,
float load_cap, float load_cap,
float related_out_cap, float related_out_cap,
@ -51,32 +51,29 @@ public:
// Return values. // Return values.
ArcDelay &gate_delay, ArcDelay &gate_delay,
Slew &drvr_slew) const = 0; Slew &drvr_slew) const = 0;
virtual string reportGateDelay(const LibertyCell *cell, virtual string reportGateDelay(const Pvt *pvt,
const Pvt *pvt,
float in_slew, float in_slew,
float load_cap, float load_cap,
float related_out_cap, float related_out_cap,
bool pocv_enabled, bool pocv_enabled,
int digits) const = 0; int digits) const = 0;
virtual float driveResistance(const LibertyCell *cell, virtual float driveResistance(const Pvt *pvt) const = 0;
const Pvt *pvt) const = 0;
}; };
// Abstract base class for timing check timing models. // Abstract base class for timing check timing models.
class CheckTimingModel : public TimingModel class CheckTimingModel : public TimingModel
{ {
public: public:
CheckTimingModel(LibertyCell *cell);
// Timing check margin delay calculation. // Timing check margin delay calculation.
virtual void checkDelay(const LibertyCell *cell, virtual void checkDelay(const Pvt *pvt,
const Pvt *pvt,
float from_slew, float from_slew,
float to_slew, float to_slew,
float related_out_cap, float related_out_cap,
bool pocv_enabled, bool pocv_enabled,
// Return values. // Return values.
ArcDelay &margin) const = 0; ArcDelay &margin) const = 0;
virtual string reportCheckDelay(const LibertyCell *cell, virtual string reportCheckDelay(const Pvt *pvt,
const Pvt *pvt,
float from_slew, float from_slew,
const char *from_slew_annotation, const char *from_slew_annotation,
float to_slew, float to_slew,

View File

@ -131,9 +131,7 @@ InternalPowerModel::power(const LibertyCell *cell,
float axis_value1, axis_value2, axis_value3; float axis_value1, axis_value2, axis_value3;
findAxisValues(in_slew, load_cap, findAxisValues(in_slew, load_cap,
axis_value1, axis_value2, axis_value3); axis_value1, axis_value2, axis_value3);
const LibertyLibrary *library = cell->libertyLibrary(); return model_->findValue(cell, pvt, axis_value1, axis_value2, axis_value3);
return model_->findValue(library, cell, pvt,
axis_value1, axis_value2, axis_value3);
} }
else else
return 0.0; return 0.0;
@ -151,8 +149,8 @@ InternalPowerModel::reportPower(const LibertyCell *cell,
findAxisValues(in_slew, load_cap, findAxisValues(in_slew, load_cap,
axis_value1, axis_value2, axis_value3); axis_value1, axis_value2, axis_value3);
const LibertyLibrary *library = cell->libertyLibrary(); const LibertyLibrary *library = cell->libertyLibrary();
return model_->reportValue("Power", library, cell, pvt, return model_->reportValue("Power", cell, pvt, axis_value1, nullptr,
axis_value1, nullptr, axis_value2, axis_value3, axis_value2, axis_value3,
library->units()->powerUnit(), digits); library->units()->powerUnit(), digits);
} }
return ""; return "";

View File

@ -94,12 +94,12 @@ LibertyLibrary::LibertyLibrary(const char *name,
addTableTemplate(scalar_template, type); addTableTemplate(scalar_template, type);
} }
for (auto tr_index : RiseFall::rangeIndex()) { for (auto rf_index : RiseFall::rangeIndex()) {
wire_slew_degradation_tbls_[tr_index] = nullptr; wire_slew_degradation_tbls_[rf_index] = nullptr;
input_threshold_[tr_index] = input_threshold_default_; input_threshold_[rf_index] = input_threshold_default_;
output_threshold_[tr_index] = output_threshold_default_; output_threshold_[rf_index] = output_threshold_default_;
slew_lower_threshold_[tr_index] = slew_lower_threshold_default_; slew_lower_threshold_[rf_index] = slew_lower_threshold_default_;
slew_upper_threshold_[tr_index] = slew_upper_threshold_default_; slew_upper_threshold_[rf_index] = slew_upper_threshold_default_;
} }
} }
@ -111,8 +111,8 @@ LibertyLibrary::~LibertyLibrary()
scale_factors_map_.deleteContents(); scale_factors_map_.deleteContents();
delete scale_factors_; delete scale_factors_;
for (auto tr_index : RiseFall::rangeIndex()) { for (auto rf_index : RiseFall::rangeIndex()) {
TableModel *model = wire_slew_degradation_tbls_[tr_index]; TableModel *model = wire_slew_degradation_tbls_[rf_index];
delete model; delete model;
} }
operating_conditions_.deleteContents(); operating_conditions_.deleteContents();
@ -289,7 +289,7 @@ LibertyLibrary::scaleFactor(ScaleFactorType type,
float float
LibertyLibrary::scaleFactor(ScaleFactorType type, LibertyLibrary::scaleFactor(ScaleFactorType type,
int tr_index, int rf_index,
const LibertyCell *cell, const LibertyCell *cell,
const Pvt *pvt) const const Pvt *pvt) const
{ {
@ -299,18 +299,18 @@ LibertyLibrary::scaleFactor(ScaleFactorType type,
// All scale factors are unity for nominal pvt. // All scale factors are unity for nominal pvt.
if (pvt) { if (pvt) {
ScaleFactors *scale_factors = nullptr; 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) if (cell)
scale_factors = cell->scaleFactors(); scale_factors = cell->scaleFactors();
if (scale_factors == nullptr) if (scale_factors == nullptr)
scale_factors = scale_factors_; scale_factors = scale_factors_;
if (scale_factors) { if (scale_factors) {
float process_scale = 1.0F + (pvt->process() - nominal_process_) 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_) 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_) 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; float scale = process_scale * temp_scale * volt_scale;
return scale; return scale;
} }
@ -322,10 +322,10 @@ void
LibertyLibrary::setWireSlewDegradationTable(TableModel *model, LibertyLibrary::setWireSlewDegradationTable(TableModel *model,
RiseFall *rf) RiseFall *rf)
{ {
int tr_index = rf->index(); int rf_index = rf->index();
if (wire_slew_degradation_tbls_[tr_index]) if (wire_slew_degradation_tbls_[rf_index])
delete wire_slew_degradation_tbls_[tr_index]; delete wire_slew_degradation_tbls_[rf_index];
wire_slew_degradation_tbls_[tr_index] = model; wire_slew_degradation_tbls_[rf_index] = model;
} }
TableModel * TableModel *
@ -335,36 +335,32 @@ LibertyLibrary::wireSlewDegradationTable(const RiseFall *rf) const
} }
float float
LibertyLibrary::degradeWireSlew(const LibertyCell *cell, LibertyLibrary::degradeWireSlew(const RiseFall *rf,
const RiseFall *rf,
const Pvt *pvt,
float in_slew, float in_slew,
float wire_delay) const float wire_delay) const
{ {
const TableModel *model = wireSlewDegradationTable(rf); const TableModel *model = wireSlewDegradationTable(rf);
if (model) if (model)
return degradeWireSlew(cell, pvt, model, in_slew, wire_delay); return degradeWireSlew(model, in_slew, wire_delay);
else else
return in_slew; return in_slew;
} }
float float
LibertyLibrary::degradeWireSlew(const LibertyCell *cell, LibertyLibrary::degradeWireSlew(const TableModel *model,
const Pvt *pvt,
const TableModel *model,
float in_slew, float in_slew,
float wire_delay) const float wire_delay) const
{ {
switch (model->order()) { switch (model->order()) {
case 0: 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: { case 1: {
TableAxisPtr axis1 = model->axis1(); TableAxisPtr axis1 = model->axis1();
TableAxisVariable var1 = axis1->variable(); TableAxisVariable var1 = axis1->variable();
if (var1 == TableAxisVariable::output_pin_transition) 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) 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 { else {
criticalError(231, "unsupported slew degradation table axes"); criticalError(231, "unsupported slew degradation table axes");
return 0.0; return 0.0;
@ -377,10 +373,10 @@ LibertyLibrary::degradeWireSlew(const LibertyCell *cell,
TableAxisVariable var2 = axis2->variable(); TableAxisVariable var2 = axis2->variable();
if (var1 == TableAxisVariable::output_pin_transition if (var1 == TableAxisVariable::output_pin_transition
&& var2 == TableAxisVariable::connect_delay) && 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 else if (var1 == TableAxisVariable::connect_delay
&& var2 == TableAxisVariable::output_pin_transition) && 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 { else {
criticalError(232, "unsupported slew degradation table axes"); criticalError(232, "unsupported slew degradation table axes");
return 0.0; return 0.0;
@ -2580,8 +2576,7 @@ LibertyPort::clockTreePathDelays()
GateTimingModel *gate_model = dynamic_cast<GateTimingModel*>(model); GateTimingModel *gate_model = dynamic_cast<GateTimingModel*>(model);
ArcDelay delay; ArcDelay delay;
Slew slew; Slew slew;
gate_model->gateDelay(liberty_cell_, nullptr, 0.0, 0.0, 0.0, false, gate_model->gateDelay(nullptr, 0.0, 0.0, 0.0, false, delay, slew);
delay, slew);
const RiseFall *rf = arc->toEdge()->asRiseFall(); const RiseFall *rf = arc->toEdge()->asRiseFall();
const MinMax *min_max = (role == TimingRole::clockTreePathMin()) const MinMax *min_max = (role == TimingRole::clockTreePathMin())
? MinMax::min() ? MinMax::min()
@ -2911,8 +2906,8 @@ ScaleFactors::ScaleFactors(const char *name) :
{ {
for (int type = 0; type < scale_factor_type_count; type++) { for (int type = 0; type < scale_factor_type_count; type++) {
for (int pvt = 0; pvt < scale_factor_pvt_count; pvt++) { for (int pvt = 0; pvt < scale_factor_pvt_count; pvt++) {
for (auto tr_index : RiseFall::rangeIndex()) { for (auto rf_index : RiseFall::rangeIndex()) {
scales_[type][pvt][tr_index] = 0.0; scales_[type][pvt][rf_index] = 0.0;
} }
} }
} }
@ -2951,9 +2946,9 @@ ScaleFactors::scale(ScaleFactorType type,
float float
ScaleFactors::scale(ScaleFactorType type, ScaleFactors::scale(ScaleFactorType type,
ScaleFactorPvt pvt, 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 float
@ -3050,9 +3045,9 @@ OcvDerate::OcvDerate(const char *name) :
name_(name) name_(name)
{ {
for (auto el_index : EarlyLate::rangeIndex()) { for (auto el_index : EarlyLate::rangeIndex()) {
for (auto tr_index : RiseFall::rangeIndex()) { for (auto rf_index : RiseFall::rangeIndex()) {
derate_[tr_index][el_index][int(PathType::clk)] = nullptr; derate_[rf_index][el_index][int(PathType::clk)] = nullptr;
derate_[tr_index][el_index][int(PathType::data)] = nullptr; derate_[rf_index][el_index][int(PathType::data)] = nullptr;
} }
} }
} }

View File

@ -1939,7 +1939,7 @@ void
LibertyReader::makeTimingArcs(PortGroup *port_group) LibertyReader::makeTimingArcs(PortGroup *port_group)
{ {
for (TimingGroup *timing : port_group->timingGroups()) { for (TimingGroup *timing : port_group->timingGroups()) {
timing->makeTimingModels(library_, this); timing->makeTimingModels(cell_, this);
for (LibertyPort *port : *port_group->ports()) for (LibertyPort *port : *port_group->ports())
makeTimingArcs(port, timing); makeTimingArcs(port, timing);
@ -2204,15 +2204,15 @@ LibertyReader::makeTimingArcs(LibertyPort *to_port,
} }
void void
TimingGroup::makeTimingModels(LibertyLibrary *library, TimingGroup::makeTimingModels(LibertyCell *cell,
LibertyReader *visitor) LibertyReader *visitor)
{ {
switch (library->delayModelType()) { switch (cell->libertyLibrary()->delayModelType()) {
case DelayModelType::cmos_linear: case DelayModelType::cmos_linear:
makeLinearModels(library); makeLinearModels(cell);
break; break;
case DelayModelType::table: case DelayModelType::table:
makeTableModels(visitor); makeTableModels(cell, visitor);
break; break;
case DelayModelType::cmos_pwl: case DelayModelType::cmos_pwl:
case DelayModelType::cmos2: case DelayModelType::cmos2:
@ -2223,8 +2223,9 @@ TimingGroup::makeTimingModels(LibertyLibrary *library,
} }
void void
TimingGroup::makeLinearModels(LibertyLibrary *library) TimingGroup::makeLinearModels(LibertyCell *cell)
{ {
LibertyLibrary *library = cell->libertyLibrary();
for (auto rf : RiseFall::range()) { for (auto rf : RiseFall::range()) {
int rf_index = rf->index(); int rf_index = rf->index();
float intr = intrinsic_[rf_index]; float intr = intrinsic_[rf_index];
@ -2234,7 +2235,7 @@ TimingGroup::makeLinearModels(LibertyLibrary *library)
TimingModel *model = nullptr; TimingModel *model = nullptr;
if (timingTypeIsCheck(attrs_->timingType())) { if (timingTypeIsCheck(attrs_->timingType())) {
if (intr_exists) if (intr_exists)
model = new CheckLinearModel(intr); model = new CheckLinearModel(cell, intr);
} }
else { else {
float res = resistance_[rf_index]; float res = resistance_[rf_index];
@ -2245,22 +2246,23 @@ TimingGroup::makeLinearModels(LibertyLibrary *library)
if (!res_exists) if (!res_exists)
res = 0.0F; res = 0.0F;
if (intr_exists) if (intr_exists)
model = new GateLinearModel(intr, res); model = new GateLinearModel(cell, intr, res);
} }
attrs_->setModel(rf, model); attrs_->setModel(rf, model);
} }
} }
void void
TimingGroup::makeTableModels(LibertyReader *reader) TimingGroup::makeTableModels(LibertyCell *cell,
LibertyReader *reader)
{ {
for (auto rf : RiseFall::range()) { for (auto rf : RiseFall::range()) {
int rf_index = rf->index(); int rf_index = rf->index();
TableModel *cell = cell_[rf_index]; TableModel *delay = cell_[rf_index];
TableModel *transition = transition_[rf_index]; TableModel *transition = transition_[rf_index];
TableModel *constraint = constraint_[rf_index]; TableModel *constraint = constraint_[rf_index];
if (cell || transition) { if (delay || transition) {
attrs_->setModel(rf, new GateTableModel(cell, delay_sigma_[rf_index], attrs_->setModel(rf, new GateTableModel(cell, delay, delay_sigma_[rf_index],
transition, transition,
slew_sigma_[rf_index], slew_sigma_[rf_index],
receiver_model_, receiver_model_,
@ -2281,11 +2283,11 @@ TimingGroup::makeTableModels(LibertyReader *reader)
|| timing_type == TimingType::three_state_enable_rise) { || timing_type == TimingType::three_state_enable_rise) {
if (transition == nullptr) if (transition == nullptr)
reader->libWarn(95, line_, "missing %s_transition.", rf->name()); reader->libWarn(95, line_, "missing %s_transition.", rf->name());
if (cell == nullptr) if (delay == nullptr)
reader->libWarn(96, line_, "missing cell_%s.", rf->name()); reader->libWarn(96, line_, "missing cell_%s.", rf->name());
} }
} else if (constraint) } else if (constraint)
attrs_->setModel(rf, new CheckTableModel(constraint, attrs_->setModel(rf, new CheckTableModel(cell, constraint,
constraint_sigma_[rf_index])); constraint_sigma_[rf_index]));
} }
} }

View File

@ -784,7 +784,7 @@ public:
TableModel *transition(RiseFall *rf); TableModel *transition(RiseFall *rf);
void setTransition(RiseFall *rf, void setTransition(RiseFall *rf,
TableModel *model); TableModel *model);
void makeTimingModels(LibertyLibrary *library, void makeTimingModels(LibertyCell *cell,
LibertyReader *visitor); LibertyReader *visitor);
void setDelaySigma(RiseFall *rf, void setDelaySigma(RiseFall *rf,
EarlyLate *early_late, EarlyLate *early_late,
@ -801,8 +801,9 @@ public:
OutputWaveforms *output_current); OutputWaveforms *output_current);
protected: protected:
void makeLinearModels(LibertyLibrary *library); void makeLinearModels(LibertyCell *cell);
void makeTableModels(LibertyReader *reader); void makeTableModels(LibertyCell *cell,
LibertyReader *reader);
TimingArcAttrsPtr attrs_; TimingArcAttrsPtr attrs_;
const char *related_output_port_name_; const char *related_output_port_name_;

View File

@ -21,16 +21,17 @@
namespace sta { namespace sta {
GateLinearModel::GateLinearModel(float intrinsic, GateLinearModel::GateLinearModel(LibertyCell *cell,
float intrinsic,
float resistance) : float resistance) :
GateTimingModel(cell),
intrinsic_(intrinsic), intrinsic_(intrinsic),
resistance_(resistance) resistance_(resistance)
{ {
} }
void void
GateLinearModel::gateDelay(const LibertyCell *, GateLinearModel::gateDelay(const Pvt *,
const Pvt *,
float, float,
float load_cap, float load_cap,
float, float,
@ -44,15 +45,14 @@ GateLinearModel::gateDelay(const LibertyCell *,
} }
string string
GateLinearModel::reportGateDelay(const LibertyCell *cell, GateLinearModel::reportGateDelay(const Pvt *,
const Pvt *,
float, float,
float load_cap, float load_cap,
float, float,
bool, bool,
int digits) const int digits) const
{ {
const LibertyLibrary *library = cell->libertyLibrary(); const LibertyLibrary *library = cell_->libertyLibrary();
const Units *units = library->units(); const Units *units = library->units();
const Unit *time_unit = units->timeUnit(); const Unit *time_unit = units->timeUnit();
const Unit *res_unit = units->resistanceUnit(); const Unit *res_unit = units->resistanceUnit();
@ -70,8 +70,7 @@ GateLinearModel::reportGateDelay(const LibertyCell *cell,
} }
float float
GateLinearModel::driveResistance(const LibertyCell *, GateLinearModel::driveResistance(const Pvt *) const
const Pvt *) const
{ {
return resistance_; return resistance_;
} }
@ -81,14 +80,15 @@ GateLinearModel::setIsScaled(bool)
{ {
} }
CheckLinearModel::CheckLinearModel(float intrinsic) : CheckLinearModel::CheckLinearModel(LibertyCell *cell,
float intrinsic) :
CheckTimingModel(cell),
intrinsic_(intrinsic) intrinsic_(intrinsic)
{ {
} }
void void
CheckLinearModel::checkDelay(const LibertyCell *, CheckLinearModel::checkDelay(const Pvt *,
const Pvt *,
float, float,
float, float,
float, float,
@ -99,8 +99,7 @@ CheckLinearModel::checkDelay(const LibertyCell *,
} }
string string
CheckLinearModel::reportCheckDelay(const LibertyCell *cell, CheckLinearModel::reportCheckDelay(const Pvt *,
const Pvt *,
float, float,
const char *, const char *,
float, float,
@ -108,7 +107,7 @@ CheckLinearModel::reportCheckDelay(const LibertyCell *cell,
bool, bool,
int digits) const int digits) const
{ {
const LibertyLibrary *library = cell->libertyLibrary(); const LibertyLibrary *library = cell_->libertyLibrary();
const Units *units = library->units(); const Units *units = library->units();
const Unit *time_unit = units->timeUnit(); const Unit *time_unit = units->timeUnit();
string result = "Check = "; string result = "Check = ";

View File

@ -34,19 +34,26 @@ using std::make_shared;
static void static void
deleteSigmaModels(TableModel *models[EarlyLate::index_count]); deleteSigmaModels(TableModel *models[EarlyLate::index_count]);
static string static string
reportPvt(const LibertyLibrary *library, reportPvt(const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
int digits); int digits);
static void static void
appendSpaces(string &result, appendSpaces(string &result,
int count); 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 *delay_sigma_models[EarlyLate::index_count],
TableModel *slew_model, TableModel *slew_model,
TableModel *slew_sigma_models[EarlyLate::index_count], TableModel *slew_sigma_models[EarlyLate::index_count],
ReceiverModelPtr receiver_model, ReceiverModelPtr receiver_model,
OutputWaveforms *output_waveforms) : OutputWaveforms *output_waveforms) :
GateTimingModel(cell),
delay_model_(delay_model), delay_model_(delay_model),
slew_model_(slew_model), slew_model_(slew_model),
receiver_model_(receiver_model), receiver_model_(receiver_model),
@ -94,8 +101,7 @@ GateTableModel::setIsScaled(bool is_scaled)
} }
void void
GateTableModel::gateDelay(const LibertyCell *cell, GateTableModel::gateDelay(const Pvt *pvt,
const Pvt *pvt,
float in_slew, float in_slew,
float load_cap, float load_cap,
float related_out_cap, float related_out_cap,
@ -104,30 +110,23 @@ GateTableModel::gateDelay(const LibertyCell *cell,
ArcDelay &gate_delay, ArcDelay &gate_delay,
Slew &drvr_slew) const Slew &drvr_slew) const
{ {
const LibertyLibrary *library = cell->libertyLibrary(); float delay = findValue(pvt, delay_model_, in_slew, load_cap, related_out_cap);
float delay = findValue(library, cell, pvt, delay_model_, in_slew,
load_cap, related_out_cap);
float sigma_early = 0.0; float sigma_early = 0.0;
float sigma_late = 0.0; float sigma_late = 0.0;
if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()]) if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()])
sigma_early = findValue(library, cell, pvt, sigma_early = findValue(pvt, delay_sigma_models_[EarlyLate::earlyIndex()],
delay_sigma_models_[EarlyLate::earlyIndex()],
in_slew, load_cap, related_out_cap); in_slew, load_cap, related_out_cap);
if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()]) if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()])
sigma_late = findValue(library, cell, pvt, sigma_late = findValue(pvt, delay_sigma_models_[EarlyLate::lateIndex()],
delay_sigma_models_[EarlyLate::lateIndex()],
in_slew, load_cap, related_out_cap); in_slew, load_cap, related_out_cap);
gate_delay = makeDelay(delay, sigma_early, sigma_late); gate_delay = makeDelay(delay, sigma_early, sigma_late);
float slew = findValue(library, cell, pvt, slew_model_, in_slew, float slew = findValue(pvt, slew_model_, in_slew, load_cap, related_out_cap);
load_cap, related_out_cap);
if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()]) if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()])
sigma_early = findValue(library, cell, pvt, sigma_early = findValue(pvt, slew_sigma_models_[EarlyLate::earlyIndex()],
slew_sigma_models_[EarlyLate::earlyIndex()],
in_slew, load_cap, related_out_cap); in_slew, load_cap, related_out_cap);
if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()]) if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()])
sigma_late = findValue(library, cell, pvt, sigma_late = findValue(pvt, slew_sigma_models_[EarlyLate::lateIndex()],
slew_sigma_models_[EarlyLate::lateIndex()],
in_slew, load_cap, related_out_cap); in_slew, load_cap, related_out_cap);
// Clip negative slews to zero. // Clip negative slews to zero.
if (slew < 0.0) if (slew < 0.0)
@ -136,39 +135,36 @@ GateTableModel::gateDelay(const LibertyCell *cell,
} }
string string
GateTableModel::reportGateDelay(const LibertyCell *cell, GateTableModel::reportGateDelay(const Pvt *pvt,
const Pvt *pvt,
float in_slew, float in_slew,
float load_cap, float load_cap,
float related_out_cap, float related_out_cap,
bool pocv_enabled, bool pocv_enabled,
int digits) const int digits) const
{ {
const LibertyLibrary *library = cell->libertyLibrary(); string result = reportPvt(cell_, pvt, digits);
string result = reportPvt(library, pvt, digits); result += reportTableLookup("Delay", pvt, delay_model_, in_slew,
result += reportTableLookup("Delay", library, cell, pvt, delay_model_, in_slew,
load_cap, related_out_cap, digits); load_cap, related_out_cap, digits);
if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()]) 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()], delay_sigma_models_[EarlyLate::earlyIndex()],
in_slew, load_cap, related_out_cap, digits); in_slew, load_cap, related_out_cap, digits);
if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()]) 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()], delay_sigma_models_[EarlyLate::lateIndex()],
in_slew, load_cap, related_out_cap, digits); in_slew, load_cap, related_out_cap, digits);
result += '\n'; 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); load_cap, related_out_cap, digits);
if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()]) 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()], slew_sigma_models_[EarlyLate::earlyIndex()],
in_slew, load_cap, related_out_cap, digits); in_slew, load_cap, related_out_cap, digits);
if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()]) 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()], slew_sigma_models_[EarlyLate::lateIndex()],
in_slew, load_cap, related_out_cap, digits); in_slew, load_cap, related_out_cap, digits);
float drvr_slew = findValue(library, cell, pvt, slew_model_, in_slew, float drvr_slew = findValue(pvt, slew_model_, in_slew, load_cap, related_out_cap);
load_cap, related_out_cap);
if (drvr_slew < 0.0) if (drvr_slew < 0.0)
result += "Negative slew clipped to 0.0\n"; result += "Negative slew clipped to 0.0\n";
return result; return result;
@ -176,8 +172,6 @@ GateTableModel::reportGateDelay(const LibertyCell *cell,
string string
GateTableModel::reportTableLookup(const char *result_name, GateTableModel::reportTableLookup(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
const TableModel *model, const TableModel *model,
float in_slew, float in_slew,
@ -189,17 +183,16 @@ GateTableModel::reportTableLookup(const char *result_name,
float axis_value1, axis_value2, axis_value3; float axis_value1, axis_value2, axis_value3;
findAxisValues(model, in_slew, load_cap, related_out_cap, findAxisValues(model, in_slew, load_cap, related_out_cap,
axis_value1, axis_value2, axis_value3); axis_value1, axis_value2, axis_value3);
return model->reportValue(result_name, library, cell, pvt, const LibertyLibrary *library = cell_->libertyLibrary();
axis_value1, nullptr, axis_value2, axis_value3, return model->reportValue(result_name, cell_, pvt, axis_value1, nullptr,
axis_value2, axis_value3,
library->units()->timeUnit(), digits); library->units()->timeUnit(), digits);
} }
return ""; return "";
} }
float float
GateTableModel::findValue(const LibertyLibrary *library, GateTableModel::findValue(const Pvt *pvt,
const LibertyCell *cell,
const Pvt *pvt,
const TableModel *model, const TableModel *model,
float in_slew, float in_slew,
float load_cap, float load_cap,
@ -209,8 +202,7 @@ GateTableModel::findValue(const LibertyLibrary *library,
float axis_value1, axis_value2, axis_value3; float axis_value1, axis_value2, axis_value3;
findAxisValues(model, in_slew, load_cap, related_out_cap, findAxisValues(model, in_slew, load_cap, related_out_cap,
axis_value1, axis_value2, axis_value3); axis_value1, axis_value2, axis_value3);
return model->findValue(library, cell, pvt, return model->findValue(cell_, pvt, axis_value1, axis_value2, axis_value3);
axis_value1, axis_value2, axis_value3);
} }
else else
return 0.0; return 0.0;
@ -264,42 +256,36 @@ GateTableModel::findAxisValues(const TableModel *model,
// Use slew/Cload for the highest Cload, which approximates output // Use slew/Cload for the highest Cload, which approximates output
// admittance as the "drive". // admittance as the "drive".
float float
GateTableModel::driveResistance(const LibertyCell *cell, GateTableModel::driveResistance(const Pvt *pvt) const
const Pvt *pvt) const
{ {
float slew, cap; float slew, cap;
maxCapSlew(cell, 0.0, pvt, slew, cap); maxCapSlew(0.0, pvt, slew, cap);
return slew / cap; return slew / cap;
} }
void void
GateTableModel::maxCapSlew(const LibertyCell *cell, GateTableModel::maxCapSlew(float in_slew,
float in_slew,
const Pvt *pvt, const Pvt *pvt,
float &slew, float &slew,
float &cap) const float &cap) const
{ {
const LibertyLibrary *library = cell->libertyLibrary();
TableAxisPtr axis1 = slew_model_->axis1(); TableAxisPtr axis1 = slew_model_->axis1();
TableAxisPtr axis2 = slew_model_->axis2(); TableAxisPtr axis2 = slew_model_->axis2();
TableAxisPtr axis3 = slew_model_->axis3(); TableAxisPtr axis3 = slew_model_->axis3();
if (axis1 if (axis1
&& axis1->variable() == TableAxisVariable::total_output_net_capacitance) { && axis1->variable() == TableAxisVariable::total_output_net_capacitance) {
cap = axis1->axisValue(axis1->size() - 1); cap = axis1->axisValue(axis1->size() - 1);
slew = findValue(library, cell, pvt, slew_model_, slew = findValue(pvt, slew_model_, in_slew, cap, 0.0);
in_slew, cap, 0.0);
} }
else if (axis2 else if (axis2
&& axis2->variable()==TableAxisVariable::total_output_net_capacitance) { && axis2->variable()==TableAxisVariable::total_output_net_capacitance) {
cap = axis2->axisValue(axis2->size() - 1); cap = axis2->axisValue(axis2->size() - 1);
slew = findValue(library, cell, pvt, slew_model_, slew = findValue(pvt, slew_model_, in_slew, cap, 0.0);
in_slew, cap, 0.0);
} }
else if (axis3 else if (axis3
&& axis3->variable()==TableAxisVariable::total_output_net_capacitance) { && axis3->variable()==TableAxisVariable::total_output_net_capacitance) {
cap = axis3->axisValue(axis3->size() - 1); cap = axis3->axisValue(axis3->size() - 1);
slew = findValue(library, cell, pvt, slew_model_, slew = findValue(pvt, slew_model_, in_slew, cap, 0.0);
in_slew, cap, 0.0);
} }
else { else {
// Table not dependent on capacitance. // 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]) : TableModel *sigma_models[EarlyLate::index_count]) :
CheckTimingModel(cell),
model_(model) model_(model)
{ {
for (auto el_index : EarlyLate::rangeIndex()) for (auto el_index : EarlyLate::rangeIndex())
@ -420,8 +408,7 @@ CheckTableModel::setIsScaled(bool is_scaled)
} }
void void
CheckTableModel::checkDelay(const LibertyCell *cell, CheckTableModel::checkDelay(const Pvt *pvt,
const Pvt *pvt,
float from_slew, float from_slew,
float to_slew, float to_slew,
float related_out_cap, float related_out_cap,
@ -430,18 +417,14 @@ CheckTableModel::checkDelay(const LibertyCell *cell,
ArcDelay &margin) const ArcDelay &margin) const
{ {
if (model_) { if (model_) {
const LibertyLibrary *library = cell->libertyLibrary(); float mean = findValue(pvt, model_, from_slew, to_slew, related_out_cap);
float mean = findValue(library, cell, pvt, model_,
from_slew, to_slew, related_out_cap);
float sigma_early = 0.0; float sigma_early = 0.0;
float sigma_late = 0.0; float sigma_late = 0.0;
if (pocv_enabled && sigma_models_[EarlyLate::earlyIndex()]) if (pocv_enabled && sigma_models_[EarlyLate::earlyIndex()])
sigma_early = findValue(library, cell, pvt, sigma_early = findValue(pvt, sigma_models_[EarlyLate::earlyIndex()],
sigma_models_[EarlyLate::earlyIndex()],
from_slew, to_slew, related_out_cap); from_slew, to_slew, related_out_cap);
if (pocv_enabled && sigma_models_[EarlyLate::lateIndex()]) if (pocv_enabled && sigma_models_[EarlyLate::lateIndex()])
sigma_late = findValue(library, cell, pvt, sigma_late = findValue(pvt, sigma_models_[EarlyLate::lateIndex()],
sigma_models_[EarlyLate::lateIndex()],
from_slew, to_slew, related_out_cap); from_slew, to_slew, related_out_cap);
margin = makeDelay(mean, sigma_early, sigma_late); margin = makeDelay(mean, sigma_early, sigma_late);
} }
@ -450,9 +433,7 @@ CheckTableModel::checkDelay(const LibertyCell *cell,
} }
float float
CheckTableModel::findValue(const LibertyLibrary *library, CheckTableModel::findValue(const Pvt *pvt,
const LibertyCell *cell,
const Pvt *pvt,
const TableModel *model, const TableModel *model,
float from_slew, float from_slew,
float to_slew, float to_slew,
@ -462,16 +443,14 @@ CheckTableModel::findValue(const LibertyLibrary *library,
float axis_value1, axis_value2, axis_value3; float axis_value1, axis_value2, axis_value3;
findAxisValues(from_slew, to_slew, related_out_cap, findAxisValues(from_slew, to_slew, related_out_cap,
axis_value1, axis_value2, axis_value3); axis_value1, axis_value2, axis_value3);
return model->findValue(library, cell, pvt, return model->findValue(cell_, pvt, axis_value1, axis_value2, axis_value3);
axis_value1, axis_value2, axis_value3);
} }
else else
return 0.0; return 0.0;
} }
string string
CheckTableModel::reportCheckDelay(const LibertyCell *cell, CheckTableModel::reportCheckDelay(const Pvt *pvt,
const Pvt *pvt,
float from_slew, float from_slew,
const char *from_slew_annotation, const char *from_slew_annotation,
float to_slew, float to_slew,
@ -479,17 +458,16 @@ CheckTableModel::reportCheckDelay(const LibertyCell *cell,
bool pocv_enabled, bool pocv_enabled,
int digits) const int digits) const
{ {
const LibertyLibrary *library = cell->libertyLibrary(); string result = reportTableDelay("Check", pvt, model_,
string result = reportTableDelay("Check", library, cell, pvt, model_,
from_slew, from_slew_annotation, to_slew, from_slew, from_slew_annotation, to_slew,
related_out_cap, digits); related_out_cap, digits);
if (pocv_enabled && sigma_models_[EarlyLate::earlyIndex()]) 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()], sigma_models_[EarlyLate::earlyIndex()],
from_slew, from_slew_annotation, to_slew, from_slew, from_slew_annotation, to_slew,
related_out_cap, digits); related_out_cap, digits);
if (pocv_enabled && sigma_models_[EarlyLate::lateIndex()]) 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()], sigma_models_[EarlyLate::lateIndex()],
from_slew, from_slew_annotation, to_slew, from_slew, from_slew_annotation, to_slew,
related_out_cap, digits); related_out_cap, digits);
@ -498,8 +476,6 @@ CheckTableModel::reportCheckDelay(const LibertyCell *cell,
string string
CheckTableModel::reportTableDelay(const char *result_name, CheckTableModel::reportTableDelay(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
const TableModel *model, const TableModel *model,
float from_slew, float from_slew,
@ -512,10 +488,11 @@ CheckTableModel::reportTableDelay(const char *result_name,
float axis_value1, axis_value2, axis_value3; float axis_value1, axis_value2, axis_value3;
findAxisValues(from_slew, to_slew, related_out_cap, findAxisValues(from_slew, to_slew, related_out_cap,
axis_value1, axis_value2, axis_value3); axis_value1, axis_value2, axis_value3);
string result = reportPvt(library, pvt, digits); string result = reportPvt(cell_, pvt, digits);
result += model_->reportValue(result_name, library, cell, pvt, result += model_->reportValue(result_name, cell_, pvt,
axis_value1, from_slew_annotation, axis_value2, axis_value1, from_slew_annotation, axis_value2,
axis_value3, library->units()->timeUnit(), digits); axis_value3,
cell_->libertyLibrary()->units()->timeUnit(), digits);
return result; return result;
} }
return ""; return "";
@ -665,20 +642,26 @@ TableModel::value(size_t axis_index1,
} }
float float
TableModel::findValue(const LibertyLibrary *library, TableModel::findValue(float axis_value1,
const LibertyCell *cell, 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, const Pvt *pvt,
float axis_value1, float axis_value1,
float axis_value2, float axis_value2,
float axis_value3) const float axis_value3) const
{ {
return table_->findValue(axis_value1, axis_value2, axis_value3) return table_->findValue(axis_value1, axis_value2, axis_value3)
* scaleFactor(library, cell, pvt); * scaleFactor(cell, pvt);
} }
float float
TableModel::scaleFactor(const LibertyLibrary *library, TableModel::scaleFactor(const LibertyCell *cell,
const LibertyCell *cell,
const Pvt *pvt) const const Pvt *pvt) const
{ {
if (is_scaled_) if (is_scaled_)
@ -686,13 +669,12 @@ TableModel::scaleFactor(const LibertyLibrary *library,
// nominal pvt. // nominal pvt.
return 1.0F; return 1.0F;
else else
return library->scaleFactor(static_cast<ScaleFactorType>(scale_factor_type_), return cell->libertyLibrary()->scaleFactor(static_cast<ScaleFactorType>(scale_factor_type_),
rf_index_, cell, pvt); rf_index_, cell, pvt);
} }
string string
TableModel::reportValue(const char *result_name, TableModel::reportValue(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell, const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
float value1, float value1,
@ -702,24 +684,24 @@ TableModel::reportValue(const char *result_name,
const Unit *table_unit, const Unit *table_unit,
int digits) const 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); comment1, value2, value3, table_unit, digits);
result += reportPvtScaleFactor(library, cell, pvt, digits); result += reportPvtScaleFactor(cell, pvt, digits);
result += result_name; result += result_name;
result += " = "; result += " = ";
result += table_unit->asString(findValue(library, cell, pvt, result += table_unit->asString(findValue(cell, pvt, value1, value2, value3), digits);
value1, value2, value3), digits);
result += '\n'; result += '\n';
return result; return result;
} }
static string static string
reportPvt(const LibertyLibrary *library, reportPvt(const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
int digits) int digits)
{ {
const LibertyLibrary *library = cell->libertyLibrary();
if (pvt == nullptr) if (pvt == nullptr)
pvt = library->defaultOperatingConditions(); pvt = library->defaultOperatingConditions();
if (pvt) { if (pvt) {
@ -734,18 +716,17 @@ reportPvt(const LibertyLibrary *library,
} }
string string
TableModel::reportPvtScaleFactor(const LibertyLibrary *library, TableModel::reportPvtScaleFactor(const LibertyCell *cell,
const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
int digits) const int digits) const
{ {
if (pvt == nullptr) if (pvt == nullptr)
pvt = library->defaultOperatingConditions(); pvt = cell->libertyLibrary()->defaultOperatingConditions();
if (pvt) { if (pvt) {
string result; string result;
stringPrint(result, "PVT scale factor = %.*f\n", stringPrint(result, "PVT scale factor = %.*f\n",
digits, digits,
scaleFactor(library, cell, pvt)); scaleFactor(cell, pvt));
return result; return result;
} }
return ""; return "";
@ -777,7 +758,6 @@ Table0::findValue(float,
string string
Table0::reportValue(const char *result_name, Table0::reportValue(const char *result_name,
const LibertyLibrary *,
const LibertyCell *, const LibertyCell *,
const Pvt *, const Pvt *,
float value1, float value1,
@ -930,9 +910,8 @@ Table1::findValueClipZero(float axis_value1) const
} }
string string
Table1::reportValue(const char *result_name, const Table1::reportValue(const char *result_name,
LibertyLibrary *library, const LibertyCell *cell,
const LibertyCell *,
const Pvt *, const Pvt *,
float value1, float value1,
const char *comment1, const char *comment1,
@ -941,7 +920,7 @@ Table1::reportValue(const char *result_name, const
const Unit *table_unit, const Unit *table_unit,
int digits) const int digits) const
{ {
const Units *units = library->units(); const Units *units = cell->libertyLibrary()->units();
const Unit *unit1 = axis1_->unit(units); const Unit *unit1 = axis1_->unit(units);
string result = "Table is indexed by\n "; string result = "Table is indexed by\n ";
result += axis1_->variableString(); result += axis1_->variableString();
@ -1098,8 +1077,7 @@ Table2::findValue(float axis_value1,
string string
Table2::reportValue(const char *result_name, Table2::reportValue(const char *result_name,
const LibertyLibrary *library, const LibertyCell *cell,
const LibertyCell *,
const Pvt *, const Pvt *,
float value1, float value1,
const char *comment1, const char *comment1,
@ -1108,7 +1086,7 @@ Table2::reportValue(const char *result_name,
const Unit *table_unit, const Unit *table_unit,
int digits) const int digits) const
{ {
const Units *units = library->units(); const Units *units = cell->libertyLibrary()->units();
const Unit *unit1 = axis1_->unit(units); const Unit *unit1 = axis1_->unit(units);
const Unit *unit2 = axis2_->unit(units); const Unit *unit2 = axis2_->unit(units);
string result = "------- "; string result = "------- ";
@ -1289,8 +1267,7 @@ Table3::findValue(float axis_value1,
// 0.40 | 0.20 0.30 // 0.40 | 0.20 0.30
string string
Table3::reportValue(const char *result_name, Table3::reportValue(const char *result_name,
const LibertyLibrary *library, const LibertyCell *cell,
const LibertyCell *,
const Pvt *, const Pvt *,
float value1, float value1,
const char *comment1, const char *comment1,
@ -1299,7 +1276,7 @@ Table3::reportValue(const char *result_name,
const Unit *table_unit, const Unit *table_unit,
int digits) const int digits) const
{ {
const Units *units = library->units(); const Units *units = cell->libertyLibrary()->units();
const Unit *unit1 = axis1_->unit(units); const Unit *unit1 = axis1_->unit(units);
const Unit *unit2 = axis2_->unit(units); const Unit *unit2 = axis2_->unit(units);
const Unit *unit3 = axis3_->unit(units); const Unit *unit3 = axis3_->unit(units);

View File

@ -149,10 +149,8 @@ float
TimingArc::driveResistance() const TimingArc::driveResistance() const
{ {
GateTimingModel *model = dynamic_cast<GateTimingModel*>(model_); GateTimingModel *model = dynamic_cast<GateTimingModel*>(model_);
if (model) { if (model)
LibertyCell *cell = set_->libertyCell(); return model->driveResistance(nullptr);
return model->driveResistance(cell, nullptr);
}
else else
return 0.0; return 0.0;
} }
@ -162,11 +160,9 @@ TimingArc::intrinsicDelay() const
{ {
GateTimingModel *model = dynamic_cast<GateTimingModel*>(model_); GateTimingModel *model = dynamic_cast<GateTimingModel*>(model_);
if (model) { if (model) {
LibertyCell *cell = set_->libertyCell();
ArcDelay arc_delay; ArcDelay arc_delay;
Slew slew; Slew slew;
model->gateDelay(cell, nullptr, 0.0, 0.0, 0.0, false, model->gateDelay(nullptr, 0.0, 0.0, 0.0, false, arc_delay, slew);
arc_delay, slew);
return arc_delay; return arc_delay;
} }
else else

31
liberty/TimingModel.cc Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
#include "TimingModel.hh"
namespace sta {
GateTimingModel::GateTimingModel(LibertyCell *cell) :
TimingModel(cell)
{
}
CheckTimingModel::CheckTimingModel(LibertyCell *cell) :
TimingModel(cell)
{
}
} // namespace

View File

@ -472,7 +472,7 @@ Sdc::operatingConditions(const MinMax *min_max)
} }
const Pvt * const Pvt *
Sdc::pvt(Instance *inst, Sdc::pvt(const Instance *inst,
const MinMax *min_max) const const MinMax *min_max) const
{ {
const InstancePvtMap &pvt_map = instance_pvt_maps_[min_max->index()]; const InstancePvtMap &pvt_map = instance_pvt_maps_[min_max->index()];

View File

@ -581,7 +581,7 @@ MakeTimingModel::makeScalarCheckModel(float value,
library_->findTableTemplate("scalar", TableTemplateType::delay); library_->findTableTemplate("scalar", TableTemplateType::delay);
TableModel *table_model = new TableModel(table, tbl_template, TableModel *table_model = new TableModel(table, tbl_template,
scale_factor_type, rf); scale_factor_type, rf);
CheckTableModel *check_model = new CheckTableModel(table_model, nullptr); CheckTableModel *check_model = new CheckTableModel(cell_, table_model, nullptr);
return check_model; return check_model;
} }
@ -598,7 +598,7 @@ MakeTimingModel::makeGateModelScalar(Delay delay,
ScaleFactorType::cell, rf); ScaleFactorType::cell, rf);
TableModel *slew_model = new TableModel(slew_table, tbl_template, TableModel *slew_model = new TableModel(slew_table, tbl_template,
ScaleFactorType::cell, rf); ScaleFactorType::cell, rf);
GateTableModel *gate_model = new GateTableModel(delay_model, nullptr, GateTableModel *gate_model = new GateTableModel(cell_, delay_model, nullptr,
slew_model, nullptr, slew_model, nullptr,
nullptr, nullptr); nullptr, nullptr);
return gate_model; return gate_model;
@ -613,7 +613,7 @@ MakeTimingModel::makeGateModelScalar(Delay delay,
library_->findTableTemplate("scalar", TableTemplateType::delay); library_->findTableTemplate("scalar", TableTemplateType::delay);
TableModel *delay_model = new TableModel(delay_table, tbl_template, TableModel *delay_model = new TableModel(delay_table, tbl_template,
ScaleFactorType::cell, rf); ScaleFactorType::cell, rf);
GateTableModel *gate_model = new GateTableModel(delay_model, nullptr, GateTableModel *gate_model = new GateTableModel(cell_, delay_model, nullptr,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr); nullptr, nullptr);
return gate_model; 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); float output_load_cap = graph_delay_calc_->loadCap(output_pin, dcalc_ap);
ArcDelay drvr_self_delay; ArcDelay drvr_self_delay;
Slew drvr_self_slew; Slew drvr_self_slew;
drvr_gate_model->gateDelay(drvr_cell, pvt, in_slew1, drvr_gate_model->gateDelay(pvt, in_slew1, output_load_cap, 0.0, false,
output_load_cap, 0.0, false,
drvr_self_delay, drvr_self_slew); drvr_self_delay, drvr_self_slew);
const TableModel *drvr_table = drvr_gate_model->delayModel(); const TableModel *drvr_table = drvr_gate_model->delayModel();
@ -671,8 +670,7 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin,
// get slew from driver input pin // get slew from driver input pin
ArcDelay gate_delay; ArcDelay gate_delay;
Slew gate_slew; Slew gate_slew;
drvr_gate_model->gateDelay(drvr_cell, pvt, in_slew1, drvr_gate_model->gateDelay(pvt, in_slew1, load_cap, 0.0, false,
load_cap, 0.0, false,
gate_delay, gate_slew); gate_delay, gate_slew);
// Remove the self delay driving the output pin net load cap. // Remove the self delay driving the output pin net load cap.
load_values->push_back(delayAsFloat(delay + gate_delay load_values->push_back(delayAsFloat(delay + gate_delay
@ -694,7 +692,8 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin,
ScaleFactorType::cell, rf); ScaleFactorType::cell, rf);
TableModel *slew_model = new TableModel(slew_table, model_template, TableModel *slew_model = new TableModel(slew_table, model_template,
ScaleFactorType::cell, rf); ScaleFactorType::cell, rf);
GateTableModel *gate_model = new GateTableModel(delay_model, nullptr, GateTableModel *gate_model = new GateTableModel(cell_,
delay_model, nullptr,
slew_model, nullptr, slew_model, nullptr,
nullptr, nullptr); nullptr, nullptr);
return gate_model; return gate_model;

View File

@ -3789,22 +3789,11 @@ Sta::connectedCap(const Pin *drvr_pin,
float &pin_cap, float &pin_cap,
float &wire_cap) const float &wire_cap) const
{ {
pin_cap = 0.0;
wire_cap = 0.0;
bool cap_exists = false;
const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
Parasitic *parasitic = arc_delay_calc_->findParasitic(drvr_pin, rf, dcalc_ap); 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, graph_delay_calc_->loadCap(drvr_pin, parasitic, rf, dcalc_ap,
ap_pin_cap, ap_wire_cap); pin_cap, wire_cap);
arc_delay_calc_->finishDrvrPin(); 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 void