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