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:
parent
19cf68c72a
commit
31369dd750
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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++) {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 ¶llel_delay,
|
|
||||||
Slew ¶llel_slew);
|
|
||||||
void netCaps(const RiseFall *rf,
|
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
|
||||||
// Return values.
|
|
||||||
float &pin_cap,
|
|
||||||
float &wire_cap,
|
|
||||||
float &fanout,
|
|
||||||
bool &has_net_load);
|
|
||||||
void findCaps(const GraphDelayCalc *dcalc,
|
|
||||||
const Sdc *sdc);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void findDelaysSlews(ArcDelayCalc *arc_delay_calc,
|
|
||||||
GraphDelayCalc *dcalc);
|
|
||||||
|
|
||||||
// Driver that triggers delay calculation for all the drivers on the net.
|
|
||||||
Vertex *dcalc_drvr_;
|
|
||||||
VertexSet *drvrs_;
|
|
||||||
// [drvr_rf->index][dcalc_ap->index]
|
|
||||||
ArcDelay *parallel_delays_;
|
|
||||||
// [drvr_rf->index][dcalc_ap->index]
|
|
||||||
Slew *parallel_slews_;
|
|
||||||
// [drvr_rf->index][dcalc_ap->index]
|
|
||||||
NetCaps *net_caps_;
|
|
||||||
bool delays_valid_:1;
|
|
||||||
};
|
|
||||||
|
|
||||||
MultiDrvrNet::MultiDrvrNet(VertexSet *drvrs) :
|
|
||||||
dcalc_drvr_(nullptr),
|
|
||||||
drvrs_(drvrs),
|
|
||||||
parallel_delays_(nullptr),
|
|
||||||
parallel_slews_(nullptr),
|
|
||||||
net_caps_(nullptr),
|
|
||||||
delays_valid_(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
MultiDrvrNet::~MultiDrvrNet()
|
|
||||||
{
|
|
||||||
delete drvrs_;
|
|
||||||
if (delays_valid_) {
|
|
||||||
delete [] parallel_delays_;
|
|
||||||
delete [] parallel_slews_;
|
|
||||||
}
|
|
||||||
delete [] net_caps_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MultiDrvrNet::parallelDelaySlew(const RiseFall *drvr_rf,
|
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
|
||||||
ArcDelayCalc *arc_delay_calc,
|
|
||||||
GraphDelayCalc *dcalc,
|
|
||||||
// Return values.
|
|
||||||
ArcDelay ¶llel_delay,
|
|
||||||
Slew ¶llel_slew)
|
|
||||||
{
|
|
||||||
if (!delays_valid_) {
|
|
||||||
findDelaysSlews(arc_delay_calc, dcalc);
|
|
||||||
delays_valid_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int index = dcalc_ap->index() * RiseFall::index_count
|
|
||||||
+ drvr_rf->index();
|
|
||||||
parallel_delay = parallel_delays_[index];
|
|
||||||
parallel_slew = parallel_slews_[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MultiDrvrNet::findDelaysSlews(ArcDelayCalc *arc_delay_calc,
|
|
||||||
GraphDelayCalc *dcalc)
|
|
||||||
{
|
|
||||||
Corners *corners = dcalc->corners();
|
|
||||||
int count = RiseFall::index_count * corners->dcalcAnalysisPtCount();
|
|
||||||
parallel_delays_ = new ArcDelay[count];
|
|
||||||
parallel_slews_ = new Slew[count];
|
|
||||||
for (auto dcalc_ap : corners->dcalcAnalysisPts()) {
|
|
||||||
DcalcAPIndex ap_index = dcalc_ap->index();
|
|
||||||
const Pvt *pvt = dcalc_ap->operatingConditions();
|
|
||||||
for (auto drvr_rf : RiseFall::range()) {
|
|
||||||
int drvr_rf_index = drvr_rf->index();
|
|
||||||
int index = ap_index*RiseFall::index_count+drvr_rf_index;
|
|
||||||
dcalc->findMultiDrvrGateDelay(this, drvr_rf, pvt, dcalc_ap,
|
|
||||||
arc_delay_calc,
|
|
||||||
parallel_delays_[index],
|
|
||||||
parallel_slews_[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MultiDrvrNet::netCaps(const RiseFall *drvr_rf,
|
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
|
||||||
// Return values.
|
|
||||||
float &pin_cap,
|
|
||||||
float &wire_cap,
|
|
||||||
float &fanout,
|
|
||||||
bool &has_net_load)
|
|
||||||
{
|
|
||||||
int index = dcalc_ap->index() * RiseFall::index_count
|
|
||||||
+ drvr_rf->index();
|
|
||||||
NetCaps &net_caps = net_caps_[index];
|
|
||||||
pin_cap = net_caps.pinCap();
|
|
||||||
wire_cap = net_caps.wireCap();
|
|
||||||
fanout = net_caps.fanout();
|
|
||||||
has_net_load = net_caps.hasNetLoad();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MultiDrvrNet::findCaps(const GraphDelayCalc *dcalc,
|
|
||||||
const Sdc *sdc)
|
|
||||||
{
|
|
||||||
Corners *corners = dcalc->corners();
|
|
||||||
int count = RiseFall::index_count * corners->dcalcAnalysisPtCount();
|
|
||||||
net_caps_ = new NetCaps[count];
|
|
||||||
const Pin *drvr_pin = dcalc_drvr_->pin();
|
|
||||||
for (auto dcalc_ap : corners->dcalcAnalysisPts()) {
|
|
||||||
DcalcAPIndex ap_index = dcalc_ap->index();
|
|
||||||
const Corner *corner = dcalc_ap->corner();
|
|
||||||
const OperatingConditions *op_cond = dcalc_ap->operatingConditions();
|
|
||||||
const MinMax *min_max = dcalc_ap->constraintMinMax();
|
|
||||||
for (auto drvr_rf : RiseFall::range()) {
|
|
||||||
int drvr_rf_index = drvr_rf->index();
|
|
||||||
int index = ap_index * RiseFall::index_count + drvr_rf_index;
|
|
||||||
NetCaps &net_caps = net_caps_[index];
|
|
||||||
float pin_cap, wire_cap, fanout;
|
|
||||||
bool has_net_load;
|
|
||||||
// Find pin and external pin/wire capacitance.
|
|
||||||
sdc->connectedCap(drvr_pin, drvr_rf, op_cond, corner, min_max,
|
|
||||||
pin_cap, wire_cap, fanout, has_net_load);
|
|
||||||
net_caps.init(pin_cap, wire_cap, fanout, has_net_load);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MultiDrvrNet::setDcalcDrvr(Vertex *drvr)
|
|
||||||
{
|
|
||||||
dcalc_drvr_ = drvr;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
GraphDelayCalc::GraphDelayCalc(StaState *sta) :
|
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 ¶llel_delay,
|
|
||||||
Slew ¶llel_slew)
|
|
||||||
{
|
|
||||||
ArcDelay delay_sum = 1.0;
|
|
||||||
Slew slew_sum = 1.0;
|
|
||||||
for (Vertex *drvr_vertex1 : *multi_drvr->drvrs()) {
|
|
||||||
Pin *drvr_pin1 = drvr_vertex1->pin();
|
|
||||||
Instance *drvr_inst1 = network_->instance(drvr_pin1);
|
|
||||||
LibertyCell *drvr_cell1 = network_->libertyCell(drvr_inst1);
|
|
||||||
if (network_->isDriver(drvr_pin1)) {
|
|
||||||
VertexInEdgeIterator edge_iter(drvr_vertex1, graph_);
|
|
||||||
while (edge_iter.hasNext()) {
|
|
||||||
Edge *edge1 = edge_iter.next();
|
|
||||||
TimingArcSet *arc_set1 = edge1->timingArcSet();
|
|
||||||
const LibertyPort *related_out_port = arc_set1->relatedOut();
|
|
||||||
for (TimingArc *arc1 : arc_set1->arcs()) {
|
|
||||||
RiseFall *drvr_rf1 = arc1->toEdge()->asRiseFall();
|
|
||||||
if (drvr_rf1 == drvr_rf) {
|
|
||||||
Vertex *from_vertex1 = edge1->from(graph_);
|
|
||||||
RiseFall *from_rf1 = arc1->fromEdge()->asRiseFall();
|
|
||||||
Slew from_slew1 = edgeFromSlew(from_vertex1, from_rf1, edge1, dcalc_ap);
|
|
||||||
ArcDelay intrinsic_delay1;
|
|
||||||
Slew intrinsic_slew1;
|
|
||||||
arc_delay_calc->gateDelay(drvr_cell1, arc1, from_slew1,
|
|
||||||
0.0, 0, 0.0, pvt, dcalc_ap,
|
|
||||||
intrinsic_delay1, intrinsic_slew1);
|
|
||||||
Parasitic *parasitic1 =
|
|
||||||
arc_delay_calc->findParasitic(drvr_pin1, drvr_rf1, dcalc_ap);
|
|
||||||
const Pin *related_out_pin1 = 0;
|
|
||||||
float related_out_cap1 = 0.0;
|
|
||||||
if (related_out_port) {
|
|
||||||
Instance *inst1 = network_->instance(drvr_pin1);
|
|
||||||
related_out_pin1 = network_->findPin(inst1, related_out_port);
|
|
||||||
if (related_out_pin1) {
|
|
||||||
Parasitic *related_out_parasitic1 =
|
|
||||||
arc_delay_calc->findParasitic(related_out_pin1, drvr_rf,
|
|
||||||
dcalc_ap);
|
|
||||||
related_out_cap1 = loadCap(related_out_pin1,
|
|
||||||
related_out_parasitic1,
|
|
||||||
drvr_rf, dcalc_ap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
float load_cap1 = loadCap(drvr_pin1, parasitic1,
|
|
||||||
drvr_rf, dcalc_ap);
|
|
||||||
ArcDelay gate_delay1;
|
|
||||||
Slew gate_slew1;
|
|
||||||
arc_delay_calc->gateDelay(drvr_cell1, arc1,
|
|
||||||
from_slew1, load_cap1, parasitic1,
|
|
||||||
related_out_cap1, pvt, dcalc_ap,
|
|
||||||
gate_delay1, gate_slew1);
|
|
||||||
delay_sum += 1.0F / (gate_delay1 - intrinsic_delay1);
|
|
||||||
slew_sum += 1.0F / gate_slew1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parallel_delay = 1.0F / delay_sum;
|
|
||||||
parallel_slew = 1.0F / slew_sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use clock slew for register/latch clk->q edges.
|
// 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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 *
|
||||||
|
|
|
||||||
|
|
@ -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 ¶llel_delay,
|
||||||
|
Slew ¶llel_slew)
|
||||||
|
{
|
||||||
|
ArcDelay delay_sum = 0.0;
|
||||||
|
Slew slew_sum = 0.0;
|
||||||
|
for (Vertex *drvr_vertex : *multi_drvr->drvrs()) {
|
||||||
|
Pin *drvr_pin = drvr_vertex->pin();
|
||||||
|
Instance *drvr_inst = network_->instance(drvr_pin);
|
||||||
|
const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax());
|
||||||
|
if (pvt == nullptr)
|
||||||
|
pvt = dcalc_ap->operatingConditions();
|
||||||
|
VertexInEdgeIterator edge_iter(drvr_vertex, graph_);
|
||||||
|
while (edge_iter.hasNext()) {
|
||||||
|
Edge *edge = edge_iter.next();
|
||||||
|
TimingArcSet *arc_set = edge->timingArcSet();
|
||||||
|
const LibertyPort *related_out_port = arc_set->relatedOut();
|
||||||
|
for (TimingArc *arc : arc_set->arcs()) {
|
||||||
|
RiseFall *arc_rf = arc->toEdge()->asRiseFall();
|
||||||
|
if (arc_rf == drvr_rf) {
|
||||||
|
Vertex *from_vertex = edge->from(graph_);
|
||||||
|
RiseFall *from_rf = arc->fromEdge()->asRiseFall();
|
||||||
|
Slew from_slew = dcalc->edgeFromSlew(from_vertex, from_rf,
|
||||||
|
edge, dcalc_ap);
|
||||||
|
ArcDelay intrinsic_delay;
|
||||||
|
Slew intrinsic_slew;
|
||||||
|
gateDelay(arc, from_slew, 0.0, 0, 0.0, pvt, dcalc_ap,
|
||||||
|
intrinsic_delay, intrinsic_slew);
|
||||||
|
Parasitic *parasitic = findParasitic(drvr_pin, drvr_rf, dcalc_ap);
|
||||||
|
const Pin *related_out_pin = 0;
|
||||||
|
float related_out_cap = 0.0;
|
||||||
|
if (related_out_port) {
|
||||||
|
Instance *inst = network_->instance(drvr_pin);
|
||||||
|
related_out_pin = network_->findPin(inst, related_out_port);
|
||||||
|
if (related_out_pin) {
|
||||||
|
Parasitic *related_out_parasitic = findParasitic(related_out_pin,
|
||||||
|
drvr_rf,
|
||||||
|
dcalc_ap);
|
||||||
|
related_out_cap = dcalc->loadCap(related_out_pin,
|
||||||
|
related_out_parasitic,
|
||||||
|
drvr_rf, dcalc_ap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float load_cap = dcalc->loadCap(drvr_pin, parasitic,
|
||||||
|
drvr_rf, dcalc_ap);
|
||||||
|
ArcDelay gate_delay;
|
||||||
|
Slew gate_slew;
|
||||||
|
gateDelay(arc, from_slew, load_cap, parasitic,
|
||||||
|
related_out_cap, pvt, dcalc_ap,
|
||||||
|
gate_delay, gate_slew);
|
||||||
|
delay_sum += 1.0F / (gate_delay - intrinsic_delay);
|
||||||
|
slew_sum += 1.0F / gate_slew;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parallel_delay = 1.0F / delay_sum;
|
||||||
|
parallel_slew = 1.0F / slew_sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ParallelDelayCalc::parallelGateDelay(const Pin *,
|
||||||
|
const TimingArc *arc,
|
||||||
|
const Slew &from_slew,
|
||||||
|
float load_cap,
|
||||||
|
const Parasitic *drvr_parasitic,
|
||||||
|
float related_out_cap,
|
||||||
|
const Pvt *pvt,
|
||||||
|
const DcalcAnalysisPt *dcalc_ap,
|
||||||
|
// Return values.
|
||||||
|
ArcDelay &gate_delay,
|
||||||
|
Slew &gate_slew)
|
||||||
|
{
|
||||||
|
ArcDelay intrinsic_delay;
|
||||||
|
Slew intrinsic_slew;
|
||||||
|
gateDelay(arc, from_slew, 0.0, 0, 0.0, pvt, dcalc_ap,
|
||||||
|
intrinsic_delay, intrinsic_slew);
|
||||||
|
const RiseFall *drvr_rf = arc->toEdge()->asRiseFall();
|
||||||
|
int index = dcalc_ap->index() * RiseFall::index_count + drvr_rf->index();
|
||||||
|
ArcDelay parallel_delay = parallel_delays_[index];
|
||||||
|
Slew parallel_slew = parallel_slews_[index];
|
||||||
|
gate_delay = parallel_delay + intrinsic_delay;
|
||||||
|
gate_slew = parallel_slew;
|
||||||
|
|
||||||
|
Delay gate_delay1;
|
||||||
|
Slew gate_slew1;
|
||||||
|
gateDelay(arc, from_slew, load_cap, drvr_parasitic,
|
||||||
|
related_out_cap, pvt, dcalc_ap,
|
||||||
|
gate_delay1, gate_slew1);
|
||||||
|
float factor = delayRatio(gate_slew, gate_slew1);
|
||||||
|
multi_drvr_slew_factor_ = factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
@ -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 ¶llel_delay,
|
||||||
|
Slew ¶llel_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
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 &,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 ¶llel_delay,
|
|
||||||
Slew ¶llel_slew);
|
|
||||||
void parallelGateDelay(MultiDrvrNet *multi_drvr,
|
|
||||||
LibertyCell *drvr_cell,
|
|
||||||
const Pin *drvr_pin,
|
|
||||||
TimingArc *arc,
|
|
||||||
const Pvt *pvt,
|
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
|
||||||
const Slew from_slew,
|
|
||||||
Parasitic *drvr_parasitic,
|
|
||||||
float related_out_cap,
|
|
||||||
ArcDelayCalc *arc_delay_calc,
|
|
||||||
// Return values.
|
|
||||||
ArcDelay &gate_delay,
|
|
||||||
Slew &gate_slew);
|
|
||||||
void deleteMultiDrvrNets();
|
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
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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 "";
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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_;
|
||||||
|
|
|
||||||
|
|
@ -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 = ";
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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()];
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue