DelayCalc reorg

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

    ArcDelayCalcBase -> DelayCalcBase

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

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

    LumpedCapDelayCalc::inputPortDelay

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

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

    gateDelayInit cleanup

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

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

    mv RCDelayCalc to ArcDelayCalcBase

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

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

    ArcDelayCalcBase

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

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

    ParallelArcDelayCalc -> ParallelDelayCalc

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

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

    parallelGateDelay args

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

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

    TimingModel cell_

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

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

    TimingModel cell_

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

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

    rm drvr_cell from arc dcalc funcs

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

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

    tr -> rf

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

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

    GraphDelayCalc

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

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

    ParallelArcDelayCalc

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

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

    ParallelArcDelayCalc pvt

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

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

    ParallelArcDelayCalc::findMultiDrvrGateDelay

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

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

    mv multi_drvr_slew_factor_ to ParallelArcDelayCalc

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

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

    MultiDrvrNet::net_caps vector

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

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

    sic

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

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

    Sta::connectedCap simplify

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

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

    ParallelArcDelayCalc

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

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

    mv parallel dcalc to arc delay calc

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

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

    rm MultiDrvrNet::delays_valid_

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

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

    mkae MultiDrvrNets on the fly

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

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

View File

@ -66,12 +66,13 @@ set(STA_SOURCE
dcalc/ArnoldiReduce.cc
dcalc/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

View File

@ -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++) {

132
dcalc/DelayCalcBase.cc Normal file
View File

@ -0,0 +1,132 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "DelayCalcBase.hh"
#include "Liberty.hh"
#include "TimingArc.hh"
#include "Network.hh"
#include "Parasitics.hh"
namespace sta {
DelayCalcBase::DelayCalcBase(StaState *sta) :
ArcDelayCalc(sta)
{
}
void
DelayCalcBase::finishDrvrPin()
{
for (auto parasitic : unsaved_parasitics_)
parasitics_->deleteUnsavedParasitic(parasitic);
unsaved_parasitics_.clear();
for (auto drvr_pin : reduced_parasitic_drvrs_)
parasitics_->deleteDrvrReducedParasitics(drvr_pin);
reduced_parasitic_drvrs_.clear();
}
void
DelayCalcBase::inputPortDelay(const Pin *,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *)
{
drvr_cell_ = nullptr;
drvr_library_ = network_->defaultLibertyLibrary();
drvr_slew_ = in_slew;
drvr_rf_ = rf;
drvr_parasitic_ = parasitic;
input_port_ = true;
}
void
DelayCalcBase::gateDelayInit(const TimingArc *arc,
const Slew &in_slew,
const Parasitic *drvr_parasitic)
{
drvr_cell_ = arc->from()->libertyCell();
drvr_library_ = drvr_cell_->libertyLibrary();
drvr_rf_ = arc->toEdge()->asRiseFall();
drvr_slew_ = in_slew;
drvr_parasitic_ = drvr_parasitic;
input_port_ = false;
}
// For DSPF on an input port the elmore delay is used as the time
// constant of an exponential waveform. The delay to the logic
// threshold and slew are computed for the exponential waveform.
// Note that this uses the driver thresholds and relies on
// thresholdAdjust to convert the delay and slew to the load's thresholds.
void
DelayCalcBase::dspfWireDelaySlew(const Pin *,
float elmore,
ArcDelay &wire_delay,
Slew &load_slew)
{
float vth = drvr_library_->inputThreshold(drvr_rf_);
float vl = drvr_library_->slewLowerThreshold(drvr_rf_);
float vh = drvr_library_->slewUpperThreshold(drvr_rf_);
float slew_derate = drvr_library_->slewDerateFromLibrary();
wire_delay = -elmore * log(1.0 - vth);
load_slew = drvr_slew_ + elmore * log((1.0 - vl) / (1.0 - vh)) / slew_derate;
}
void
DelayCalcBase::thresholdAdjust(const Pin *load_pin,
ArcDelay &load_delay,
Slew &load_slew)
{
LibertyLibrary *load_library = thresholdLibrary(load_pin);
if (load_library
&& drvr_library_
&& load_library != drvr_library_) {
float drvr_vth = drvr_library_->outputThreshold(drvr_rf_);
float load_vth = load_library->inputThreshold(drvr_rf_);
float drvr_slew_delta = drvr_library_->slewUpperThreshold(drvr_rf_)
- drvr_library_->slewLowerThreshold(drvr_rf_);
float load_delay_delta =
delayAsFloat(load_slew) * ((load_vth - drvr_vth) / drvr_slew_delta);
load_delay += (drvr_rf_ == RiseFall::rise())
? load_delay_delta
: -load_delay_delta;
float load_slew_delta = load_library->slewUpperThreshold(drvr_rf_)
- load_library->slewLowerThreshold(drvr_rf_);
float drvr_slew_derate = drvr_library_->slewDerateFromLibrary();
float load_slew_derate = load_library->slewDerateFromLibrary();
load_slew = load_slew * ((load_slew_delta / load_slew_derate)
/ (drvr_slew_delta / drvr_slew_derate));
}
}
LibertyLibrary *
DelayCalcBase::thresholdLibrary(const Pin *load_pin)
{
if (network_->isTopLevelPort(load_pin))
// Input/output slews use the default (first read) library
// for slew thresholds.
return network_->defaultLibertyLibrary();
else {
LibertyPort *lib_port = network_->libertyPort(load_pin);
if (lib_port)
return lib_port->libertyCell()->libertyLibrary();
else
return network_->defaultLibertyLibrary();
}
}
} // namespace

View File

@ -16,32 +16,48 @@
#pragma once
#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

View File

@ -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;

View File

@ -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,

View File

@ -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);
}

View File

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

View File

@ -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

View File

@ -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 *

171
dcalc/ParallelDelayCalc.cc Normal file
View File

@ -0,0 +1,171 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "ParallelDelayCalc.hh"
#include "TimingArc.hh"
#include "Corner.hh"
#include "Network.hh"
#include "Graph.hh"
#include "Sdc.hh"
#include "Liberty.hh"
#include "GraphDelayCalc.hh"
namespace sta {
ParallelDelayCalc::ParallelDelayCalc(StaState *sta):
DelayCalcBase(sta)
{
}
void
ParallelDelayCalc::inputPortDelay(const Pin *drvr_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap)
{
DelayCalcBase::inputPortDelay(drvr_pin, in_slew, rf, parasitic, dcalc_ap);
multi_drvr_slew_factor_ = 1.0;
}
void
ParallelDelayCalc::gateDelayInit(const TimingArc *arc,
const Slew &in_slew,
const Parasitic *drvr_parasitic)
{
DelayCalcBase::gateDelayInit(arc, in_slew, drvr_parasitic);
multi_drvr_slew_factor_ = 1.0F;
}
void
ParallelDelayCalc::findParallelGateDelays(const MultiDrvrNet *multi_drvr,
GraphDelayCalc *dcalc)
{
int count = RiseFall::index_count * corners_->dcalcAnalysisPtCount();
parallel_delays_.resize(count);
parallel_slews_.resize(count);
for (auto dcalc_ap : corners_->dcalcAnalysisPts()) {
for (auto drvr_rf : RiseFall::range()) {
DcalcAPIndex ap_index = dcalc_ap->index();
int drvr_rf_index = drvr_rf->index();
int index = ap_index * RiseFall::index_count + drvr_rf_index;
findMultiDrvrGateDelay(multi_drvr, drvr_rf, dcalc_ap, dcalc,
parallel_delays_[index],
parallel_slews_[index]);
}
}
}
void
ParallelDelayCalc::findMultiDrvrGateDelay(const MultiDrvrNet *multi_drvr,
const RiseFall *drvr_rf,
const DcalcAnalysisPt *dcalc_ap,
GraphDelayCalc *dcalc,
// Return values.
ArcDelay &parallel_delay,
Slew &parallel_slew)
{
ArcDelay delay_sum = 0.0;
Slew slew_sum = 0.0;
for (Vertex *drvr_vertex : *multi_drvr->drvrs()) {
Pin *drvr_pin = drvr_vertex->pin();
Instance *drvr_inst = network_->instance(drvr_pin);
const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax());
if (pvt == nullptr)
pvt = dcalc_ap->operatingConditions();
VertexInEdgeIterator edge_iter(drvr_vertex, graph_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
TimingArcSet *arc_set = edge->timingArcSet();
const LibertyPort *related_out_port = arc_set->relatedOut();
for (TimingArc *arc : arc_set->arcs()) {
RiseFall *arc_rf = arc->toEdge()->asRiseFall();
if (arc_rf == drvr_rf) {
Vertex *from_vertex = edge->from(graph_);
RiseFall *from_rf = arc->fromEdge()->asRiseFall();
Slew from_slew = dcalc->edgeFromSlew(from_vertex, from_rf,
edge, dcalc_ap);
ArcDelay intrinsic_delay;
Slew intrinsic_slew;
gateDelay(arc, from_slew, 0.0, 0, 0.0, pvt, dcalc_ap,
intrinsic_delay, intrinsic_slew);
Parasitic *parasitic = findParasitic(drvr_pin, drvr_rf, dcalc_ap);
const Pin *related_out_pin = 0;
float related_out_cap = 0.0;
if (related_out_port) {
Instance *inst = network_->instance(drvr_pin);
related_out_pin = network_->findPin(inst, related_out_port);
if (related_out_pin) {
Parasitic *related_out_parasitic = findParasitic(related_out_pin,
drvr_rf,
dcalc_ap);
related_out_cap = dcalc->loadCap(related_out_pin,
related_out_parasitic,
drvr_rf, dcalc_ap);
}
}
float load_cap = dcalc->loadCap(drvr_pin, parasitic,
drvr_rf, dcalc_ap);
ArcDelay gate_delay;
Slew gate_slew;
gateDelay(arc, from_slew, load_cap, parasitic,
related_out_cap, pvt, dcalc_ap,
gate_delay, gate_slew);
delay_sum += 1.0F / (gate_delay - intrinsic_delay);
slew_sum += 1.0F / gate_slew;
}
}
}
}
parallel_delay = 1.0F / delay_sum;
parallel_slew = 1.0F / slew_sum;
}
void
ParallelDelayCalc::parallelGateDelay(const Pin *,
const TimingArc *arc,
const Slew &from_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &gate_slew)
{
ArcDelay intrinsic_delay;
Slew intrinsic_slew;
gateDelay(arc, from_slew, 0.0, 0, 0.0, pvt, dcalc_ap,
intrinsic_delay, intrinsic_slew);
const RiseFall *drvr_rf = arc->toEdge()->asRiseFall();
int index = dcalc_ap->index() * RiseFall::index_count + drvr_rf->index();
ArcDelay parallel_delay = parallel_delays_[index];
Slew parallel_slew = parallel_slews_[index];
gate_delay = parallel_delay + intrinsic_delay;
gate_slew = parallel_slew;
Delay gate_delay1;
Slew gate_slew1;
gateDelay(arc, from_slew, load_cap, drvr_parasitic,
related_out_cap, pvt, dcalc_ap,
gate_delay1, gate_slew1);
float factor = delayRatio(gate_slew, gate_slew1);
multi_drvr_slew_factor_ = factor;
}
} // namespace

View File

@ -0,0 +1,68 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
#include <vector>
#include "DelayCalcBase.hh"
namespace sta {
// Delay calculation for parallel gates based on using parallel drive resistance.
class ParallelDelayCalc : public DelayCalcBase
{
public:
explicit ParallelDelayCalc(StaState *sta);
void inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap) override;
void gateDelayInit(const TimingArc *arc,
const Slew &in_slew,
const Parasitic *drvr_parasitic);
void findParallelGateDelays(const MultiDrvrNet *multi_drvr,
GraphDelayCalc *dcalc) override;
void parallelGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &from_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &gate_slew) override;
protected:
void findMultiDrvrGateDelay(const MultiDrvrNet *multi_drvr,
const RiseFall *drvr_rf,
const DcalcAnalysisPt *dcalc_ap,
GraphDelayCalc *dcalc,
// Return values.
ArcDelay &parallel_delay,
Slew &parallel_slew);
// [drvr_rf->index][dcalc_ap->index]
vector<ArcDelay> parallel_delays_;
// [drvr_rf->index][dcalc_ap->index]
vector<Slew> parallel_slews_;
float multi_drvr_slew_factor_;
};
} // namespace

View File

@ -1,74 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "RCDelayCalc.hh"
#include "Liberty.hh"
#include "Network.hh"
#include "Sdc.hh"
#include "Parasitics.hh"
#include "GraphDelayCalc.hh"
namespace sta {
RCDelayCalc::RCDelayCalc(StaState *sta) :
LumpedCapDelayCalc(sta)
{
}
ArcDelayCalc *
RCDelayCalc::copy()
{
return new RCDelayCalc(this);
}
void
RCDelayCalc::inputPortDelay(const Pin *,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *)
{
drvr_parasitic_ = parasitic;
drvr_slew_ = in_slew;
drvr_rf_ = rf;
drvr_cell_ = nullptr;
drvr_library_ = network_->defaultLibertyLibrary();
multi_drvr_slew_factor_ = 1.0F;
input_port_ = true;
}
// For DSPF on an input port the elmore delay is used as the time
// constant of an exponential waveform. The delay to the logic
// threshold and slew are computed for the exponential waveform.
// Note that this uses the driver thresholds and relies on
// thresholdAdjust to convert the delay and slew to the load's thresholds.
void
RCDelayCalc::dspfWireDelaySlew(const Pin *,
float elmore,
ArcDelay &wire_delay,
Slew &load_slew)
{
float vth = drvr_library_->inputThreshold(drvr_rf_);
float vl = drvr_library_->slewLowerThreshold(drvr_rf_);
float vh = drvr_library_->slewUpperThreshold(drvr_rf_);
float slew_derate = drvr_library_->slewDerateFromLibrary();
wire_delay = -elmore * log(1.0 - vth);
load_slew = (drvr_slew_ + elmore * log((1.0 - vl) / (1.0 - vh))
/ slew_derate) * multi_drvr_slew_factor_;
}
} // namespace

View File

@ -22,6 +22,7 @@
#include "Sdc.hh"
#include "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));
}

View File

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

View File

@ -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 &,

View File

@ -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,

View File

@ -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)
{

View File

@ -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,

View File

@ -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

View File

@ -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 &parallel_delay,
Slew &parallel_slew);
void parallelGateDelay(MultiDrvrNet *multi_drvr,
LibertyCell *drvr_cell,
const Pin *drvr_pin,
TimingArc *arc,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
const Slew from_slew,
Parasitic *drvr_parasitic,
float related_out_cap,
ArcDelayCalc *arc_delay_calc,
// Return values.
ArcDelay &gate_delay,
Slew &gate_slew);
void deleteMultiDrvrNets();
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

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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 "";

View File

@ -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;
}
}
}

View File

@ -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]));
}
}

View File

@ -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_;

View File

@ -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 = ";

View File

@ -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);

View File

@ -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

31
liberty/TimingModel.cc Normal file
View File

@ -0,0 +1,31 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2023, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "TimingModel.hh"
namespace sta {
GateTimingModel::GateTimingModel(LibertyCell *cell) :
TimingModel(cell)
{
}
CheckTimingModel::CheckTimingModel(LibertyCell *cell) :
TimingModel(cell)
{
}
} // namespace

View File

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

View File

@ -581,7 +581,7 @@ MakeTimingModel::makeScalarCheckModel(float value,
library_->findTableTemplate("scalar", TableTemplateType::delay);
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;

View File

@ -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