Merge remote-tracking branch 'parallax/master'
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
This commit is contained in:
commit
94e86553c1
|
|
@ -66,13 +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/GraphDelayCalc1.cc
|
||||
dcalc/LumpedCapDelayCalc.cc
|
||||
dcalc/NetCaps.cc
|
||||
dcalc/RCDelayCalc.cc
|
||||
dcalc/ParallelDelayCalc.cc
|
||||
dcalc/SlewDegradeDelayCalc.cc
|
||||
dcalc/UnitDelayCalc.cc
|
||||
|
||||
|
|
@ -97,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
|
||||
|
|
@ -435,14 +436,14 @@ if (USE_CUDD)
|
|||
find_library(CUDD_LIB
|
||||
NAME cudd
|
||||
PATHS ${CUDD_DIR}
|
||||
PATH_SUFFIXES lib lib/cudd
|
||||
PATH_SUFFIXES lib lib/cudd cudd/.libs
|
||||
)
|
||||
if (CUDD_LIB)
|
||||
message(STATUS "CUDD library: ${CUDD_LIB}")
|
||||
get_filename_component(CUDD_LIB_DIR "${CUDD_LIB}" PATH)
|
||||
get_filename_component(CUDD_LIB_PARENT1 "${CUDD_LIB_DIR}" PATH)
|
||||
find_file(CUDD_HEADER cudd.h
|
||||
PATHS ${CUDD_LIB_PARENT1}/include ${CUDD_LIB_PARENT1}/include/cudd)
|
||||
PATHS ${CUDD_LIB_PARENT1} ${CUDD_LIB_PARENT1}/include ${CUDD_LIB_PARENT1}/include/cudd)
|
||||
if (CUDD_HEADER)
|
||||
get_filename_component(CUDD_INCLUDE "${CUDD_HEADER}" PATH)
|
||||
message(STATUS "CUDD header: ${CUDD_HEADER}")
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
#include "DcalcAnalysisPt.hh"
|
||||
#include "DelayCalc.hh"
|
||||
#include "ArcDelayCalc.hh"
|
||||
#include "RCDelayCalc.hh"
|
||||
#include "LumpedCapDelayCalc.hh"
|
||||
#include "GraphDelayCalc.hh"
|
||||
#include "Arnoldi.hh"
|
||||
#include "ArnoldiReduce.hh"
|
||||
|
|
@ -108,7 +108,7 @@ struct delay_work
|
|||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
class ArnoldiDelayCalc : public RCDelayCalc
|
||||
class ArnoldiDelayCalc : public LumpedCapDelayCalc
|
||||
{
|
||||
public:
|
||||
ArnoldiDelayCalc(StaState *sta);
|
||||
|
|
@ -123,8 +123,7 @@ public:
|
|||
const RiseFall *rf,
|
||||
const Parasitic *parasitic,
|
||||
const DcalcAnalysisPt *dcalc_ap) override;
|
||||
void gateDelay(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
void gateDelay(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
|
|
@ -138,8 +137,7 @@ public:
|
|||
// Return values.
|
||||
ArcDelay &wire_delay,
|
||||
Slew &load_slew) override;
|
||||
string reportGateDelay(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
string reportGateDelay(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
|
|
@ -238,7 +236,7 @@ makeArnoldiDelayCalc(StaState *sta)
|
|||
}
|
||||
|
||||
ArnoldiDelayCalc::ArnoldiDelayCalc(StaState *sta) :
|
||||
RCDelayCalc(sta),
|
||||
LumpedCapDelayCalc(sta),
|
||||
reduce_(new ArnoldiReduce(sta)),
|
||||
delay_work_(delay_work_create())
|
||||
{
|
||||
|
|
@ -321,7 +319,7 @@ ArnoldiDelayCalc::inputPortDelay(const Pin *drvr_pin,
|
|||
const Parasitic *parasitic,
|
||||
const DcalcAnalysisPt *dcalc_ap)
|
||||
{
|
||||
RCDelayCalc::inputPortDelay(drvr_pin, in_slew, rf, parasitic, dcalc_ap);
|
||||
LumpedCapDelayCalc::inputPortDelay(drvr_pin, in_slew, rf, parasitic, dcalc_ap);
|
||||
rcmodel_ = nullptr;
|
||||
_delayV[0] = 0.0;
|
||||
_slewV[0] = in_slew;
|
||||
|
|
@ -358,8 +356,7 @@ ArnoldiDelayCalc::inputPortDelay(const Pin *drvr_pin,
|
|||
}
|
||||
|
||||
void
|
||||
ArnoldiDelayCalc::gateDelay(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
ArnoldiDelayCalc::gateDelay(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
|
|
@ -372,6 +369,7 @@ ArnoldiDelayCalc::gateDelay(const LibertyCell *drvr_cell,
|
|||
{
|
||||
input_port_ = false;
|
||||
drvr_rf_ = arc->toEdge()->asRiseFall();
|
||||
const LibertyCell *drvr_cell = arc->from()->libertyCell();
|
||||
drvr_library_ = drvr_cell->libertyLibrary();
|
||||
drvr_parasitic_ = drvr_parasitic;
|
||||
ConcreteParasitic *drvr_cparasitic =
|
||||
|
|
@ -384,9 +382,9 @@ ArnoldiDelayCalc::gateDelay(const LibertyCell *drvr_cell,
|
|||
related_out_cap, pvt,
|
||||
gate_delay, drvr_slew);
|
||||
else
|
||||
LumpedCapDelayCalc::gateDelay(drvr_cell, arc, in_slew, load_cap,
|
||||
drvr_parasitic, related_out_cap, pvt,
|
||||
dcalc_ap, gate_delay, drvr_slew);
|
||||
LumpedCapDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic,
|
||||
related_out_cap, pvt, dcalc_ap,
|
||||
gate_delay, drvr_slew);
|
||||
drvr_slew_ = drvr_slew;
|
||||
multi_drvr_slew_factor_ = 1.0F;
|
||||
}
|
||||
|
|
@ -455,8 +453,7 @@ ArnoldiDelayCalc::loadDelay(const Pin *load_pin,
|
|||
}
|
||||
|
||||
string
|
||||
ArnoldiDelayCalc::reportGateDelay(const LibertyCell *,
|
||||
const TimingArc *,
|
||||
ArnoldiDelayCalc::reportGateDelay(const TimingArc *,
|
||||
const Slew &,
|
||||
float,
|
||||
const Parasitic *,
|
||||
|
|
@ -1313,9 +1310,7 @@ ArnoldiDelayCalc::ra_get_r(delay_work *D,
|
|||
c1 = ctot;
|
||||
ArcDelay d1;
|
||||
Slew s1;
|
||||
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew,
|
||||
c1, tab->relcap, pocv_enabled_,
|
||||
d1, s1);
|
||||
tab->table->gateDelay(tab->pvt, tab->in_slew, c1, tab->relcap, pocv_enabled_, d1, s1);
|
||||
tlohi = slew_derate*delayAsFloat(s1);
|
||||
r = tlohi/(c_log*c1);
|
||||
if (rdelay>0.0 && r > rdelay)
|
||||
|
|
@ -1337,8 +1332,7 @@ ArnoldiDelayCalc::ra_get_s(delay_work *D,
|
|||
double tlohi,smin,s;
|
||||
ArcDelay d1;
|
||||
Slew s1;
|
||||
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew,
|
||||
c, tab->relcap, pocv_enabled_, d1, s1);
|
||||
tab->table->gateDelay(tab->pvt, tab->in_slew, c, tab->relcap, pocv_enabled_, d1, s1);
|
||||
tlohi = slew_derate*delayAsFloat(s1);
|
||||
smin = r*c*c_smin; // c_smin = ra_hinv((1-vhi)/vhi-log(vhi)) + log(vhi);
|
||||
if (c_log*r*c >= tlohi) {
|
||||
|
|
@ -1371,10 +1365,8 @@ ArnoldiDelayCalc::ra_rdelay_1(timing_table *tab,
|
|||
return 0.0;
|
||||
ArcDelay d1, d2;
|
||||
Slew s1, s2;
|
||||
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew,
|
||||
c1, tab->relcap, pocv_enabled_, d1, s1);
|
||||
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew,
|
||||
c2, tab->relcap, pocv_enabled_, d2, s2);
|
||||
tab->table->gateDelay(tab->pvt, tab->in_slew, c1, tab->relcap, pocv_enabled_, d1, s1);
|
||||
tab->table->gateDelay(tab->pvt, tab->in_slew, c2, tab->relcap, pocv_enabled_, d2, s2);
|
||||
double dt50 = delayAsFloat(d1)-delayAsFloat(d2);
|
||||
if (dt50 <= 0.0)
|
||||
return 0.0;
|
||||
|
|
@ -1426,8 +1418,8 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
|
|||
units_->timeUnit()->asString(s));
|
||||
thix = ra_solve_for_t(p,s,vhi);
|
||||
tlox = ra_solve_for_t(p,s,vlo);
|
||||
tab->table->gateDelay(tab->cell, tab->pvt,tab->in_slew,
|
||||
ctot, tab->relcap, pocv_enabled_, df, sf);
|
||||
tab->table->gateDelay(tab->pvt,tab->in_slew, ctot, tab->relcap, pocv_enabled_,
|
||||
df, sf);
|
||||
debugPrint(debug_, "arnoldi", 1, "table slew (in_slew %s ctot %s) = %s",
|
||||
units_->timeUnit()->asString(tab->in_slew),
|
||||
units_->capacitanceUnit()->asString(ctot),
|
||||
|
|
@ -1438,8 +1430,8 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
|
|||
units_->timeUnit()->asString(tlox-thix));
|
||||
}
|
||||
ceff = ctot;
|
||||
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew,
|
||||
ceff, tab->relcap, pocv_enabled_, df, sf);
|
||||
tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, tab->relcap, pocv_enabled_,
|
||||
df, sf);
|
||||
t50_sy = delayAsFloat(df);
|
||||
t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5);
|
||||
|
||||
|
|
@ -1480,8 +1472,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
|
|||
units_->timeUnit()->asString(ceff_time),
|
||||
units_->capacitanceUnit()->asString(ceff));
|
||||
|
||||
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, ceff,
|
||||
tab->relcap, pocv_enabled_, df, sf);
|
||||
tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, tab->relcap, pocv_enabled_, df, sf);
|
||||
t50_sy = delayAsFloat(df);
|
||||
t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5);
|
||||
for (j=0;j<mod->n;j++) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,132 @@
|
|||
// OpenSTA, Static Timing Analyzer
|
||||
// Copyright (c) 2023, Parallax Software, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "DelayCalcBase.hh"
|
||||
|
||||
#include "Liberty.hh"
|
||||
#include "TimingArc.hh"
|
||||
#include "Network.hh"
|
||||
#include "Parasitics.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
DelayCalcBase::DelayCalcBase(StaState *sta) :
|
||||
ArcDelayCalc(sta)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
DelayCalcBase::finishDrvrPin()
|
||||
{
|
||||
for (auto parasitic : unsaved_parasitics_)
|
||||
parasitics_->deleteUnsavedParasitic(parasitic);
|
||||
unsaved_parasitics_.clear();
|
||||
for (auto drvr_pin : reduced_parasitic_drvrs_)
|
||||
parasitics_->deleteDrvrReducedParasitics(drvr_pin);
|
||||
reduced_parasitic_drvrs_.clear();
|
||||
}
|
||||
|
||||
void
|
||||
DelayCalcBase::inputPortDelay(const Pin *,
|
||||
float in_slew,
|
||||
const RiseFall *rf,
|
||||
const Parasitic *parasitic,
|
||||
const DcalcAnalysisPt *)
|
||||
{
|
||||
drvr_cell_ = nullptr;
|
||||
drvr_library_ = network_->defaultLibertyLibrary();
|
||||
drvr_slew_ = in_slew;
|
||||
drvr_rf_ = rf;
|
||||
drvr_parasitic_ = parasitic;
|
||||
input_port_ = true;
|
||||
}
|
||||
|
||||
void
|
||||
DelayCalcBase::gateDelayInit(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
const Parasitic *drvr_parasitic)
|
||||
{
|
||||
drvr_cell_ = arc->from()->libertyCell();
|
||||
drvr_library_ = drvr_cell_->libertyLibrary();
|
||||
drvr_rf_ = arc->toEdge()->asRiseFall();
|
||||
drvr_slew_ = in_slew;
|
||||
drvr_parasitic_ = drvr_parasitic;
|
||||
input_port_ = false;
|
||||
}
|
||||
|
||||
// For DSPF on an input port the elmore delay is used as the time
|
||||
// constant of an exponential waveform. The delay to the logic
|
||||
// threshold and slew are computed for the exponential waveform.
|
||||
// Note that this uses the driver thresholds and relies on
|
||||
// thresholdAdjust to convert the delay and slew to the load's thresholds.
|
||||
void
|
||||
DelayCalcBase::dspfWireDelaySlew(const Pin *,
|
||||
float elmore,
|
||||
ArcDelay &wire_delay,
|
||||
Slew &load_slew)
|
||||
{
|
||||
float vth = drvr_library_->inputThreshold(drvr_rf_);
|
||||
float vl = drvr_library_->slewLowerThreshold(drvr_rf_);
|
||||
float vh = drvr_library_->slewUpperThreshold(drvr_rf_);
|
||||
float slew_derate = drvr_library_->slewDerateFromLibrary();
|
||||
wire_delay = -elmore * log(1.0 - vth);
|
||||
load_slew = drvr_slew_ + elmore * log((1.0 - vl) / (1.0 - vh)) / slew_derate;
|
||||
}
|
||||
|
||||
void
|
||||
DelayCalcBase::thresholdAdjust(const Pin *load_pin,
|
||||
ArcDelay &load_delay,
|
||||
Slew &load_slew)
|
||||
{
|
||||
LibertyLibrary *load_library = thresholdLibrary(load_pin);
|
||||
if (load_library
|
||||
&& drvr_library_
|
||||
&& load_library != drvr_library_) {
|
||||
float drvr_vth = drvr_library_->outputThreshold(drvr_rf_);
|
||||
float load_vth = load_library->inputThreshold(drvr_rf_);
|
||||
float drvr_slew_delta = drvr_library_->slewUpperThreshold(drvr_rf_)
|
||||
- drvr_library_->slewLowerThreshold(drvr_rf_);
|
||||
float load_delay_delta =
|
||||
delayAsFloat(load_slew) * ((load_vth - drvr_vth) / drvr_slew_delta);
|
||||
load_delay += (drvr_rf_ == RiseFall::rise())
|
||||
? load_delay_delta
|
||||
: -load_delay_delta;
|
||||
float load_slew_delta = load_library->slewUpperThreshold(drvr_rf_)
|
||||
- load_library->slewLowerThreshold(drvr_rf_);
|
||||
float drvr_slew_derate = drvr_library_->slewDerateFromLibrary();
|
||||
float load_slew_derate = load_library->slewDerateFromLibrary();
|
||||
load_slew = load_slew * ((load_slew_delta / load_slew_derate)
|
||||
/ (drvr_slew_delta / drvr_slew_derate));
|
||||
}
|
||||
}
|
||||
|
||||
LibertyLibrary *
|
||||
DelayCalcBase::thresholdLibrary(const Pin *load_pin)
|
||||
{
|
||||
if (network_->isTopLevelPort(load_pin))
|
||||
// Input/output slews use the default (first read) library
|
||||
// for slew thresholds.
|
||||
return network_->defaultLibertyLibrary();
|
||||
else {
|
||||
LibertyPort *lib_port = network_->libertyPort(load_pin);
|
||||
if (lib_port)
|
||||
return lib_port->libertyCell()->libertyLibrary();
|
||||
else
|
||||
return network_->defaultLibertyLibrary();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
@ -16,32 +16,48 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "LumpedCapDelayCalc.hh"
|
||||
#include "ArcDelayCalc.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
// Base class for delay calculators with RC wire delay.
|
||||
class RCDelayCalc : public LumpedCapDelayCalc
|
||||
class DelayCalcBase : public ArcDelayCalc
|
||||
{
|
||||
public:
|
||||
RCDelayCalc(StaState *sta);
|
||||
ArcDelayCalc *copy() override;
|
||||
explicit DelayCalcBase(StaState *sta);
|
||||
void inputPortDelay(const Pin *port_pin,
|
||||
float in_slew,
|
||||
const RiseFall *rf,
|
||||
const Parasitic *parasitic,
|
||||
const DcalcAnalysisPt *dcalc_ap) override;
|
||||
void finishDrvrPin() override;
|
||||
|
||||
protected:
|
||||
void gateDelayInit(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
const Parasitic *drvr_parasitic);
|
||||
// Find the liberty library to use for logic/slew thresholds.
|
||||
LibertyLibrary *thresholdLibrary(const Pin *load_pin);
|
||||
// Adjust load_delay and load_slew from driver thresholds to load thresholds.
|
||||
void thresholdAdjust(const Pin *load_pin,
|
||||
ArcDelay &load_delay,
|
||||
Slew &load_slew);
|
||||
// Helper function for input ports driving dspf parasitic.
|
||||
void dspfWireDelaySlew(const Pin *load_pin,
|
||||
float elmore,
|
||||
ArcDelay &wire_delay,
|
||||
Slew &load_slew);
|
||||
|
||||
Slew drvr_slew_;
|
||||
const LibertyCell *drvr_cell_;
|
||||
const LibertyLibrary *drvr_library_;
|
||||
const Parasitic *drvr_parasitic_;
|
||||
bool input_port_;
|
||||
const RiseFall *drvr_rf_;
|
||||
// Parasitics returned by findParasitic that are reduced or estimated
|
||||
// that can be deleted after delay calculation for the driver pin
|
||||
// is finished.
|
||||
Vector<Parasitic*> unsaved_parasitics_;
|
||||
Vector<const Pin *> reduced_parasitic_drvrs_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
@ -381,7 +381,7 @@ DmpAlg::gateCapDelaySlew(double ceff,
|
|||
{
|
||||
ArcDelay model_delay;
|
||||
Slew model_slew;
|
||||
gate_model_->gateDelay(drvr_cell_, pvt_, in_slew_, ceff, related_out_cap_,
|
||||
gate_model_->gateDelay(pvt_, in_slew_, ceff, related_out_cap_,
|
||||
pocv_enabled_, model_delay, model_slew);
|
||||
delay = delayAsFloat(model_delay);
|
||||
slew = delayAsFloat(model_slew);
|
||||
|
|
@ -1528,7 +1528,7 @@ testLuDecomp2()
|
|||
bool DmpCeffDelayCalc::unsuppored_model_warned_ = false;
|
||||
|
||||
DmpCeffDelayCalc::DmpCeffDelayCalc(StaState *sta) :
|
||||
RCDelayCalc(sta),
|
||||
LumpedCapDelayCalc(sta),
|
||||
dmp_cap_(new DmpCap(sta)),
|
||||
dmp_pi_(new DmpPi(sta)),
|
||||
dmp_zero_c2_(new DmpZeroC2(sta)),
|
||||
|
|
@ -1551,12 +1551,11 @@ DmpCeffDelayCalc::inputPortDelay(const Pin *port_pin,
|
|||
const DcalcAnalysisPt *dcalc_ap)
|
||||
{
|
||||
dmp_alg_ = nullptr;
|
||||
RCDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap);
|
||||
LumpedCapDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap);
|
||||
}
|
||||
|
||||
void
|
||||
DmpCeffDelayCalc::gateDelay(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
DmpCeffDelayCalc::gateDelay(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
|
|
@ -1569,8 +1568,10 @@ DmpCeffDelayCalc::gateDelay(const LibertyCell *drvr_cell,
|
|||
{
|
||||
input_port_ = false;
|
||||
drvr_rf_ = arc->toEdge()->asRiseFall();
|
||||
const LibertyCell *drvr_cell = arc->from()->libertyCell();
|
||||
drvr_library_ = drvr_cell->libertyLibrary();
|
||||
drvr_parasitic_ = drvr_parasitic;
|
||||
|
||||
GateTimingModel *model = gateModel(arc, dcalc_ap);
|
||||
GateTableModel *table_model = dynamic_cast<GateTableModel*>(model);
|
||||
if (table_model && drvr_parasitic) {
|
||||
|
|
@ -1588,9 +1589,9 @@ DmpCeffDelayCalc::gateDelay(const LibertyCell *drvr_cell,
|
|||
drvr_slew = dmp_drvr_slew;
|
||||
}
|
||||
else {
|
||||
LumpedCapDelayCalc::gateDelay(drvr_cell, arc, in_slew, load_cap,
|
||||
drvr_parasitic, related_out_cap, pvt,
|
||||
dcalc_ap, gate_delay, drvr_slew);
|
||||
LumpedCapDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic,
|
||||
related_out_cap, pvt, dcalc_ap,
|
||||
gate_delay, drvr_slew);
|
||||
if (drvr_parasitic
|
||||
&& !unsuppored_model_warned_) {
|
||||
unsuppored_model_warned_ = true;
|
||||
|
|
@ -1646,8 +1647,7 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library,
|
|||
}
|
||||
|
||||
float
|
||||
DmpCeffDelayCalc::ceff(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
DmpCeffDelayCalc::ceff(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
|
|
@ -1657,8 +1657,7 @@ DmpCeffDelayCalc::ceff(const LibertyCell *drvr_cell,
|
|||
{
|
||||
ArcDelay gate_delay;
|
||||
Slew drvr_slew;
|
||||
gateDelay(drvr_cell, arc, in_slew, load_cap,
|
||||
drvr_parasitic, related_out_cap, pvt, dcalc_ap,
|
||||
gateDelay(arc, in_slew, load_cap, drvr_parasitic, related_out_cap, pvt, dcalc_ap,
|
||||
gate_delay, drvr_slew);
|
||||
if (dmp_alg_)
|
||||
return dmp_alg_->ceff();
|
||||
|
|
@ -1667,8 +1666,7 @@ DmpCeffDelayCalc::ceff(const LibertyCell *drvr_cell,
|
|||
}
|
||||
|
||||
string
|
||||
DmpCeffDelayCalc::reportGateDelay(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
DmpCeffDelayCalc::reportGateDelay(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
|
|
@ -1679,14 +1677,14 @@ DmpCeffDelayCalc::reportGateDelay(const LibertyCell *drvr_cell,
|
|||
{
|
||||
ArcDelay gate_delay;
|
||||
Slew drvr_slew;
|
||||
gateDelay(drvr_cell, arc, in_slew, load_cap,
|
||||
drvr_parasitic, related_out_cap, pvt, dcalc_ap,
|
||||
gateDelay(arc, in_slew, load_cap, drvr_parasitic, related_out_cap, pvt, dcalc_ap,
|
||||
gate_delay, drvr_slew);
|
||||
GateTimingModel *model = gateModel(arc, dcalc_ap);
|
||||
float c_eff = 0.0;
|
||||
string result;
|
||||
if (drvr_parasitic_ && dmp_alg_) {
|
||||
c_eff = dmp_alg_->ceff();
|
||||
const LibertyCell *drvr_cell = arc->from()->libertyCell();
|
||||
const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary();
|
||||
const Units *units = drvr_library->units();
|
||||
const Unit *cap_unit = units->capacitanceUnit();
|
||||
|
|
@ -1707,8 +1705,8 @@ DmpCeffDelayCalc::reportGateDelay(const LibertyCell *drvr_cell,
|
|||
c_eff = load_cap;
|
||||
if (model) {
|
||||
float in_slew1 = delayAsFloat(in_slew);
|
||||
result += model->reportGateDelay(drvr_cell, pvt, in_slew1, c_eff,
|
||||
related_out_cap, pocv_enabled_, digits);
|
||||
result += model->reportGateDelay(pvt, in_slew1, c_eff, related_out_cap,
|
||||
pocv_enabled_, digits);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1728,10 +1726,8 @@ gateModelRd(const LibertyCell *cell,
|
|||
float cap2 = cap1 + 1e-15;
|
||||
ArcDelay d1, d2;
|
||||
Slew s1, s2;
|
||||
gate_model->gateDelay(cell, pvt, in_slew, cap1, related_out_cap, pocv_enabled,
|
||||
d1, s1);
|
||||
gate_model->gateDelay(cell, pvt, in_slew, cap2, related_out_cap, pocv_enabled,
|
||||
d2, s2);
|
||||
gate_model->gateDelay(pvt, in_slew, cap1, related_out_cap, pocv_enabled, d1, s1);
|
||||
gate_model->gateDelay(pvt, in_slew, cap2, related_out_cap, pocv_enabled, d2, s2);
|
||||
double vth = cell->libertyLibrary()->outputThreshold(rf);
|
||||
float rd = -log(vth) * abs(delayAsFloat(d1) - delayAsFloat(d2)) / (cap2 - cap1);
|
||||
return rd;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "LibertyClass.hh"
|
||||
#include "RCDelayCalc.hh"
|
||||
#include "LumpedCapDelayCalc.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ class GateTableModel;
|
|||
|
||||
// Delay calculator using Dartu/Menezes/Pileggi effective capacitance
|
||||
// algorithm for RSPF loads.
|
||||
class DmpCeffDelayCalc : public RCDelayCalc
|
||||
class DmpCeffDelayCalc : public LumpedCapDelayCalc
|
||||
{
|
||||
public:
|
||||
DmpCeffDelayCalc(StaState *sta);
|
||||
|
|
@ -39,8 +39,7 @@ public:
|
|||
const RiseFall *rf,
|
||||
const Parasitic *parasitic,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
virtual void gateDelay(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
virtual void gateDelay(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
|
|
@ -50,16 +49,14 @@ public:
|
|||
// return values
|
||||
ArcDelay &gate_delay,
|
||||
Slew &drvr_slew);
|
||||
virtual float ceff(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
virtual float ceff(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
virtual string reportGateDelay(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
virtual string reportGateDelay(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
|
|
|
|||
|
|
@ -35,17 +35,6 @@ class DmpCeffElmoreDelayCalc : public DmpCeffDelayCalc
|
|||
public:
|
||||
DmpCeffElmoreDelayCalc(StaState *sta);
|
||||
ArcDelayCalc *copy() override;
|
||||
void gateDelay(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
ArcDelay &gate_,
|
||||
Slew &drvr_slew) override;
|
||||
void loadDelay(const Pin *load_pin,
|
||||
ArcDelay &wire_delay,
|
||||
Slew &load_slew) override;
|
||||
|
|
@ -68,25 +57,6 @@ DmpCeffElmoreDelayCalc::copy()
|
|||
return new DmpCeffElmoreDelayCalc(this);
|
||||
}
|
||||
|
||||
void
|
||||
DmpCeffElmoreDelayCalc::gateDelay(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
ArcDelay &gate_delay,
|
||||
Slew &drvr_slew)
|
||||
{
|
||||
DmpCeffDelayCalc::gateDelay(drvr_cell, arc, in_slew,
|
||||
load_cap, drvr_parasitic, related_out_cap,
|
||||
pvt, dcalc_ap,
|
||||
gate_delay, drvr_slew);
|
||||
}
|
||||
|
||||
void
|
||||
DmpCeffElmoreDelayCalc::loadDelay(const Pin *load_pin,
|
||||
ArcDelay &wire_delay,
|
||||
|
|
@ -127,8 +97,7 @@ public:
|
|||
const RiseFall *rf,
|
||||
const Parasitic *parasitic,
|
||||
const DcalcAnalysisPt *dcalc_ap) override;
|
||||
void gateDelay(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
void gateDelay(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
|
|
@ -233,7 +202,7 @@ DmpCeffTwoPoleDelayCalc::findParasitic(const Pin *drvr_pin,
|
|||
cnst_min_max,
|
||||
parasitic_ap);
|
||||
// Estimated parasitics are not recorded in the "database", so
|
||||
// it for deletion after the drvr pin delay calc is finished.
|
||||
// save it for deletion after the drvr pin delay calc is finished.
|
||||
if (parasitic)
|
||||
unsaved_parasitics_.push_back(parasitic);
|
||||
}
|
||||
|
|
@ -260,8 +229,7 @@ DmpCeffTwoPoleDelayCalc::inputPortDelay(const Pin *port_pin,
|
|||
}
|
||||
|
||||
void
|
||||
DmpCeffTwoPoleDelayCalc::gateDelay(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
DmpCeffTwoPoleDelayCalc::gateDelay(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
|
|
@ -272,15 +240,13 @@ DmpCeffTwoPoleDelayCalc::gateDelay(const LibertyCell *drvr_cell,
|
|||
ArcDelay &gate_delay,
|
||||
Slew &drvr_slew)
|
||||
{
|
||||
gateDelayInit(arc, in_slew, drvr_parasitic);
|
||||
parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(drvr_parasitic);
|
||||
const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary();
|
||||
const RiseFall *rf = arc->toEdge()->asRiseFall();
|
||||
vth_ = drvr_library->outputThreshold(rf);
|
||||
vl_ = drvr_library->slewLowerThreshold(rf);
|
||||
vh_ = drvr_library->slewUpperThreshold(rf);
|
||||
slew_derate_ = drvr_library->slewDerateFromLibrary();
|
||||
DmpCeffDelayCalc::gateDelay(drvr_cell, arc, in_slew,
|
||||
load_cap, drvr_parasitic,
|
||||
vth_ = drvr_library_->outputThreshold(drvr_rf_);
|
||||
vl_ = drvr_library_->slewLowerThreshold(drvr_rf_);
|
||||
vh_ = drvr_library_->slewUpperThreshold(drvr_rf_);
|
||||
slew_derate_ = drvr_library_->slewDerateFromLibrary();
|
||||
DmpCeffDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic,
|
||||
related_out_cap, pvt, dcalc_ap,
|
||||
gate_delay, drvr_slew);
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -1,236 +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/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "Delay.hh"
|
||||
#include "GraphDelayCalc.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
class MultiDrvrNet;
|
||||
class FindVertexDelays;
|
||||
class Corner;
|
||||
|
||||
typedef Map<const Vertex*, MultiDrvrNet*> MultiDrvrNetMap;
|
||||
|
||||
// This class traverses the graph calling the arc delay calculator and
|
||||
// annotating delays on graph edges.
|
||||
class GraphDelayCalc1 : public GraphDelayCalc
|
||||
{
|
||||
public:
|
||||
GraphDelayCalc1(StaState *sta);
|
||||
virtual ~GraphDelayCalc1();
|
||||
virtual void copyState(const StaState *sta);
|
||||
virtual void delaysInvalid();
|
||||
virtual void delayInvalid(Vertex *vertex);
|
||||
virtual void delayInvalid(const Pin *pin);
|
||||
virtual void deleteVertexBefore(Vertex *vertex);
|
||||
virtual void clear();
|
||||
virtual void findDelays(Level level);
|
||||
virtual void findDelays(Vertex *drvr_vertex);
|
||||
virtual string reportDelayCalc(Edge *edge,
|
||||
TimingArc *arc,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
int digits);
|
||||
virtual float incrementalDelayTolerance();
|
||||
virtual void setIncrementalDelayTolerance(float tol);
|
||||
virtual void setObserver(DelayCalcObserver *observer);
|
||||
// Load pin_cap + wire_cap.
|
||||
virtual float loadCap(const Pin *drvr_pin,
|
||||
const RiseFall *drvr_rf,
|
||||
const DcalcAnalysisPt *dcalc_ap) const;
|
||||
virtual float loadCap(const Pin *drvr_pin,
|
||||
const DcalcAnalysisPt *dcalc_ap) const;
|
||||
virtual void loadCap(const Pin *drvr_pin,
|
||||
const Parasitic *drvr_parasitic,
|
||||
const RiseFall *rf,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
float &pin_cap,
|
||||
float &wire_cap) const;
|
||||
virtual float loadCap(const Pin *drvr_pin,
|
||||
const Parasitic *drvr_parasitic,
|
||||
const RiseFall *rf,
|
||||
const DcalcAnalysisPt *dcalc_ap) const;
|
||||
virtual void netCaps(const Pin *drvr_pin,
|
||||
const RiseFall *rf,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
float &pin_cap,
|
||||
float &wire_cap,
|
||||
float &fanout,
|
||||
bool &has_set_load) const;
|
||||
float ceff(Edge *edge,
|
||||
TimingArc *arc,
|
||||
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);
|
||||
void seedRootSlews();
|
||||
void seedDrvrSlew(Vertex *vertex,
|
||||
ArcDelayCalc *arc_delay_calc);
|
||||
void seedNoDrvrSlew(Vertex *drvr_vertex,
|
||||
const Pin *drvr_pin,
|
||||
const RiseFall *rf,
|
||||
DcalcAnalysisPt *dcalc_ap,
|
||||
ArcDelayCalc *arc_delay_calc);
|
||||
void seedNoDrvrCellSlew(Vertex *drvr_vertex,
|
||||
const Pin *drvr_pin,
|
||||
const RiseFall *rf,
|
||||
InputDrive *drive,
|
||||
DcalcAnalysisPt *dcalc_ap,
|
||||
ArcDelayCalc *arc_delay_calc);
|
||||
void seedLoadSlew(Vertex *vertex);
|
||||
void setInputPortWireDelays(Vertex *vertex);
|
||||
void findInputDriverDelay(const LibertyCell *drvr_cell,
|
||||
const Pin *drvr_pin,
|
||||
Vertex *drvr_vertex,
|
||||
const RiseFall *rf,
|
||||
const LibertyPort *from_port,
|
||||
float *from_slews,
|
||||
const LibertyPort *to_port,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
LibertyPort *driveCellDefaultFromPort(const LibertyCell *cell,
|
||||
const LibertyPort *to_port);
|
||||
int findPortIndex(const LibertyCell *cell,
|
||||
const LibertyPort *port);
|
||||
void findInputArcDelay(const LibertyCell *drvr_cell,
|
||||
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);
|
||||
bool findDriverDelays1(Vertex *drvr_vertex,
|
||||
bool init_load_slews,
|
||||
MultiDrvrNet *multi_drvr,
|
||||
ArcDelayCalc *arc_delay_calc);
|
||||
bool findDriverEdgeDelays(LibertyCell *drvr_cell,
|
||||
Instance *drvr_inst,
|
||||
const Pin *drvr_pin,
|
||||
Vertex *drvr_vertex,
|
||||
MultiDrvrNet *multi_drvr,
|
||||
Edge *edge,
|
||||
ArcDelayCalc *arc_delay_calc);
|
||||
void initWireDelays(Vertex *drvr_vertex,
|
||||
bool init_load_slews);
|
||||
void initRootSlews(Vertex *vertex);
|
||||
void zeroSlewAndWireDelays(Vertex *drvr_vertex);
|
||||
void findVertexDelay(Vertex *vertex,
|
||||
ArcDelayCalc *arc_delay_calc,
|
||||
bool propagate);
|
||||
void enqueueTimingChecksEdges(Vertex *vertex);
|
||||
bool findArcDelay(LibertyCell *drvr_cell,
|
||||
const Pin *drvr_pin,
|
||||
Vertex *drvr_vertex,
|
||||
MultiDrvrNet *multi_drvr,
|
||||
TimingArc *arc,
|
||||
Parasitic *drvr_parasitic,
|
||||
float related_out_cap,
|
||||
Vertex *from_vertex,
|
||||
Edge *edge,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
ArcDelayCalc *arc_delay_calc);
|
||||
void annotateLoadDelays(Vertex *drvr_vertex,
|
||||
const RiseFall *drvr_rf,
|
||||
const ArcDelay &extra_delay,
|
||||
bool merge,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
ArcDelayCalc *arc_delay_calc);
|
||||
void findLatchEdgeDelays(Edge *edge);
|
||||
void findCheckEdgeDelays(Edge *edge,
|
||||
ArcDelayCalc *arc_delay_calc);
|
||||
void findMultiDrvrGateDelay(MultiDrvrNet *multi_drvr,
|
||||
const RiseFall *drvr_rf,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
ArcDelayCalc *arc_delay_calc,
|
||||
// Return values.
|
||||
ArcDelay ¶llel_delay,
|
||||
Slew ¶llel_slew);
|
||||
void parallelGateDelay(MultiDrvrNet *multi_drvr,
|
||||
LibertyCell *drvr_cell,
|
||||
const Pin *drvr_pin,
|
||||
TimingArc *arc,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
const Slew from_slew,
|
||||
Parasitic *drvr_parasitic,
|
||||
float related_out_cap,
|
||||
ArcDelayCalc *arc_delay_calc,
|
||||
// Return values.
|
||||
ArcDelay &gate_delay,
|
||||
Slew &gate_slew);
|
||||
void deleteMultiDrvrNets();
|
||||
Slew edgeFromSlew(const Vertex *from_vertex,
|
||||
const RiseFall *from_rf,
|
||||
const Edge *edge,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
Slew checkEdgeClkSlew(const Vertex *from_vertex,
|
||||
const RiseFall *from_rf,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
bool bidirectDrvrSlewFromLoad(const Vertex *vertex) const;
|
||||
MultiDrvrNet *multiDrvrNet(const Vertex *drvr_vertex) const;
|
||||
void loadCap(const Parasitic *drvr_parasitic,
|
||||
bool has_set_load,
|
||||
// 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_;
|
||||
bool delays_seeded_;
|
||||
bool incremental_;
|
||||
bool delays_exist_;
|
||||
// Vertices with invalid -to delays.
|
||||
VertexSet *invalid_delays_;
|
||||
// Timing check edges with invalid delays.
|
||||
EdgeSet invalid_check_edges_;
|
||||
// Latch D->Q edges with invalid delays.
|
||||
EdgeSet invalid_latch_edges_;
|
||||
// shared by invalid_check_edges_ and invalid_latch_edges_
|
||||
std::mutex invalid_edge_lock_;
|
||||
SearchPred *search_pred_;
|
||||
SearchPred *search_non_latch_pred_;
|
||||
SearchPred *clk_pred_;
|
||||
BfsFwdIterator *iter_;
|
||||
MultiDrvrNetMap multi_drvr_net_map_;
|
||||
bool multi_drvr_nets_found_;
|
||||
// Percentage (0.0:1.0) change in delay that causes downstream
|
||||
// delays to be recomputed during incremental delay calculation.
|
||||
float incremental_delay_tolerance_;
|
||||
|
||||
friend class FindVertexDelays;
|
||||
friend class MultiDrvrNet;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
@ -40,7 +40,7 @@ makeLumpedCapDelayCalc(StaState *sta)
|
|||
}
|
||||
|
||||
LumpedCapDelayCalc::LumpedCapDelayCalc(StaState *sta) :
|
||||
ArcDelayCalc(sta)
|
||||
ParallelDelayCalc(sta)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -82,9 +82,9 @@ LumpedCapDelayCalc::findParasitic(const Pin *drvr_pin,
|
|||
Wireload *wireload = sdc_->wireload(cnst_min_max);
|
||||
if (wireload) {
|
||||
float pin_cap, wire_cap, fanout;
|
||||
bool has_wire_cap;
|
||||
bool has_net_load;
|
||||
graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap,
|
||||
pin_cap, wire_cap, fanout, has_wire_cap);
|
||||
pin_cap, wire_cap, fanout, has_net_load);
|
||||
parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload,
|
||||
fanout, pin_cap,
|
||||
dcalc_ap->operatingConditions(),
|
||||
|
|
@ -107,32 +107,8 @@ LumpedCapDelayCalc::reducedParasiticType() const
|
|||
return ReducedParasiticType::pi_elmore;
|
||||
}
|
||||
|
||||
void
|
||||
LumpedCapDelayCalc::finishDrvrPin()
|
||||
{
|
||||
for (auto parasitic : unsaved_parasitics_)
|
||||
parasitics_->deleteUnsavedParasitic(parasitic);
|
||||
unsaved_parasitics_.clear();
|
||||
for (auto drvr_pin : reduced_parasitic_drvrs_)
|
||||
parasitics_->deleteDrvrReducedParasitics(drvr_pin);
|
||||
reduced_parasitic_drvrs_.clear();
|
||||
}
|
||||
|
||||
void
|
||||
LumpedCapDelayCalc::inputPortDelay(const Pin *, float in_slew,
|
||||
const RiseFall *rf,
|
||||
const Parasitic *,
|
||||
const DcalcAnalysisPt *)
|
||||
{
|
||||
drvr_slew_ = in_slew;
|
||||
drvr_rf_ = rf;
|
||||
drvr_library_ = network_->defaultLibertyLibrary();
|
||||
multi_drvr_slew_factor_ = 1.0F;
|
||||
}
|
||||
|
||||
float
|
||||
LumpedCapDelayCalc::ceff(const LibertyCell *,
|
||||
const TimingArc *,
|
||||
LumpedCapDelayCalc::ceff(const TimingArc *,
|
||||
const Slew &,
|
||||
float load_cap,
|
||||
const Parasitic *,
|
||||
|
|
@ -144,11 +120,10 @@ LumpedCapDelayCalc::ceff(const LibertyCell *,
|
|||
}
|
||||
|
||||
void
|
||||
LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
LumpedCapDelayCalc::gateDelay(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *,
|
||||
const Parasitic *drvr_parasitic,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
|
|
@ -156,6 +131,7 @@ LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell,
|
|||
ArcDelay &gate_delay,
|
||||
Slew &drvr_slew)
|
||||
{
|
||||
gateDelayInit(arc, in_slew, drvr_parasitic);
|
||||
GateTimingModel *model = gateModel(arc, dcalc_ap);
|
||||
debugPrint(debug_, "delay_calc", 3,
|
||||
" in_slew = %s load_cap = %s related_load_cap = %s lumped",
|
||||
|
|
@ -169,7 +145,7 @@ LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell,
|
|||
// NaNs cause seg faults during table lookup.
|
||||
if (isnan(load_cap) || isnan(related_out_cap) || isnan(delayAsFloat(in_slew)))
|
||||
report_->error(710, "gate delay input variable is NaN");
|
||||
model->gateDelay(drvr_cell, pvt, in_slew1, load_cap, related_out_cap,
|
||||
model->gateDelay(pvt, in_slew1, load_cap, related_out_cap,
|
||||
pocv_enabled_, gate_delay1, drvr_slew1);
|
||||
gate_delay = gate_delay1;
|
||||
drvr_slew = drvr_slew1;
|
||||
|
|
@ -180,9 +156,6 @@ LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell,
|
|||
drvr_slew = delay_zero;
|
||||
drvr_slew_ = 0.0;
|
||||
}
|
||||
drvr_rf_ = arc->toEdge()->asRiseFall();
|
||||
drvr_library_ = drvr_cell->libertyLibrary();
|
||||
multi_drvr_slew_factor_ = 1.0F;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -197,52 +170,8 @@ LumpedCapDelayCalc::loadDelay(const Pin *load_pin,
|
|||
load_slew = load_slew1;
|
||||
}
|
||||
|
||||
void
|
||||
LumpedCapDelayCalc::thresholdAdjust(const Pin *load_pin,
|
||||
ArcDelay &load_delay,
|
||||
Slew &load_slew)
|
||||
{
|
||||
LibertyLibrary *load_library = thresholdLibrary(load_pin);
|
||||
if (load_library
|
||||
&& drvr_library_
|
||||
&& load_library != drvr_library_) {
|
||||
float drvr_vth = drvr_library_->outputThreshold(drvr_rf_);
|
||||
float load_vth = load_library->inputThreshold(drvr_rf_);
|
||||
float drvr_slew_delta = drvr_library_->slewUpperThreshold(drvr_rf_)
|
||||
- drvr_library_->slewLowerThreshold(drvr_rf_);
|
||||
float load_delay_delta =
|
||||
delayAsFloat(load_slew) * ((load_vth - drvr_vth) / drvr_slew_delta);
|
||||
load_delay += (drvr_rf_ == RiseFall::rise())
|
||||
? load_delay_delta
|
||||
: -load_delay_delta;
|
||||
float load_slew_delta = load_library->slewUpperThreshold(drvr_rf_)
|
||||
- load_library->slewLowerThreshold(drvr_rf_);
|
||||
float drvr_slew_derate = drvr_library_->slewDerateFromLibrary();
|
||||
float load_slew_derate = load_library->slewDerateFromLibrary();
|
||||
load_slew = load_slew * ((load_slew_delta / load_slew_derate)
|
||||
/ (drvr_slew_delta / drvr_slew_derate));
|
||||
}
|
||||
}
|
||||
|
||||
LibertyLibrary *
|
||||
LumpedCapDelayCalc::thresholdLibrary(const Pin *load_pin)
|
||||
{
|
||||
if (network_->isTopLevelPort(load_pin))
|
||||
// Input/output slews use the default (first read) library
|
||||
// for slew thresholds.
|
||||
return network_->defaultLibertyLibrary();
|
||||
else {
|
||||
LibertyPort *lib_port = network_->libertyPort(load_pin);
|
||||
if (lib_port)
|
||||
return lib_port->libertyCell()->libertyLibrary();
|
||||
else
|
||||
return network_->defaultLibertyLibrary();
|
||||
}
|
||||
}
|
||||
|
||||
string
|
||||
LumpedCapDelayCalc::reportGateDelay(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
LumpedCapDelayCalc::reportGateDelay(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *,
|
||||
|
|
@ -254,15 +183,14 @@ LumpedCapDelayCalc::reportGateDelay(const LibertyCell *drvr_cell,
|
|||
GateTimingModel *model = gateModel(arc, dcalc_ap);
|
||||
if (model) {
|
||||
float in_slew1 = delayAsFloat(in_slew);
|
||||
return model->reportGateDelay(drvr_cell, pvt, in_slew1, load_cap,
|
||||
related_out_cap, false, digits);
|
||||
return model->reportGateDelay(pvt, in_slew1, load_cap, related_out_cap,
|
||||
false, digits);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void
|
||||
LumpedCapDelayCalc::checkDelay(const LibertyCell *cell,
|
||||
const TimingArc *arc,
|
||||
LumpedCapDelayCalc::checkDelay(const TimingArc *arc,
|
||||
const Slew &from_slew,
|
||||
const Slew &to_slew,
|
||||
float related_out_cap,
|
||||
|
|
@ -275,16 +203,14 @@ LumpedCapDelayCalc::checkDelay(const LibertyCell *cell,
|
|||
if (model) {
|
||||
float from_slew1 = delayAsFloat(from_slew);
|
||||
float to_slew1 = delayAsFloat(to_slew);
|
||||
model->checkDelay(cell, pvt, from_slew1, to_slew1, related_out_cap,
|
||||
pocv_enabled_, margin);
|
||||
model->checkDelay(pvt, from_slew1, to_slew1, related_out_cap, pocv_enabled_, margin);
|
||||
}
|
||||
else
|
||||
margin = delay_zero;
|
||||
}
|
||||
|
||||
string
|
||||
LumpedCapDelayCalc::reportCheckDelay(const LibertyCell *cell,
|
||||
const TimingArc *arc,
|
||||
LumpedCapDelayCalc::reportCheckDelay(const TimingArc *arc,
|
||||
const Slew &from_slew,
|
||||
const char *from_slew_annotation,
|
||||
const Slew &to_slew,
|
||||
|
|
@ -297,16 +223,10 @@ LumpedCapDelayCalc::reportCheckDelay(const LibertyCell *cell,
|
|||
if (model) {
|
||||
float from_slew1 = delayAsFloat(from_slew);
|
||||
float to_slew1 = delayAsFloat(to_slew);
|
||||
return model->reportCheckDelay(cell, pvt, from_slew1, from_slew_annotation, to_slew1,
|
||||
related_out_cap, false, digits);
|
||||
return model->reportCheckDelay(pvt, from_slew1, from_slew_annotation,
|
||||
to_slew1, related_out_cap, false, digits);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void
|
||||
LumpedCapDelayCalc::setMultiDrvrSlewFactor(float factor)
|
||||
{
|
||||
multi_drvr_slew_factor_ = factor;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -16,13 +16,13 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "ArcDelayCalc.hh"
|
||||
#include "ParallelDelayCalc.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
// Liberty table model lumped capacitance arc delay calculator.
|
||||
// Wire delays are zero.
|
||||
class LumpedCapDelayCalc : public ArcDelayCalc
|
||||
class LumpedCapDelayCalc : public ParallelDelayCalc
|
||||
{
|
||||
public:
|
||||
LumpedCapDelayCalc(StaState *sta);
|
||||
|
|
@ -31,13 +31,7 @@ public:
|
|||
const RiseFall *rf,
|
||||
const DcalcAnalysisPt *dcalc_ap) override;
|
||||
ReducedParasiticType reducedParasiticType() const override;
|
||||
void inputPortDelay(const Pin *port_pin,
|
||||
float in_slew,
|
||||
const RiseFall *rf,
|
||||
const Parasitic *parasitic,
|
||||
const DcalcAnalysisPt *dcalc_ap) override;
|
||||
void gateDelay(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
void gateDelay(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
|
|
@ -47,9 +41,7 @@ public:
|
|||
// Return values.
|
||||
ArcDelay &gate_delay,
|
||||
Slew &drvr_slew) override;
|
||||
void setMultiDrvrSlewFactor(float factor) override;
|
||||
float ceff(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
float ceff(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
|
|
@ -60,8 +52,7 @@ public:
|
|||
// Return values.
|
||||
ArcDelay &wire_delay,
|
||||
Slew &load_slew) override;
|
||||
void checkDelay(const LibertyCell *cell,
|
||||
const TimingArc *arc,
|
||||
void checkDelay(const TimingArc *arc,
|
||||
const Slew &from_slew,
|
||||
const Slew &to_slew,
|
||||
float related_out_cap,
|
||||
|
|
@ -69,8 +60,7 @@ public:
|
|||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
ArcDelay &margin) override;
|
||||
string reportGateDelay(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
string reportGateDelay(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
|
|
@ -78,8 +68,7 @@ public:
|
|||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
int digits) override;
|
||||
string reportCheckDelay(const LibertyCell *cell,
|
||||
const TimingArc *arc,
|
||||
string reportCheckDelay(const TimingArc *arc,
|
||||
const Slew &from_slew,
|
||||
const char *from_slew_annotation,
|
||||
const Slew &to_slew,
|
||||
|
|
@ -87,25 +76,8 @@ public:
|
|||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
int digits) override;
|
||||
void finishDrvrPin() override;
|
||||
|
||||
protected:
|
||||
// Find the liberty library to use for logic/slew thresholds.
|
||||
LibertyLibrary *thresholdLibrary(const Pin *load_pin);
|
||||
// Adjust load_delay and load_slew from driver thresholds to load thresholds.
|
||||
void thresholdAdjust(const Pin *load_pin,
|
||||
ArcDelay &load_delay,
|
||||
Slew &load_slew);
|
||||
|
||||
Slew drvr_slew_;
|
||||
float multi_drvr_slew_factor_;
|
||||
const LibertyLibrary *drvr_library_;
|
||||
const RiseFall *drvr_rf_;
|
||||
// Parasitics returned by findParasitic that are reduced or estimated
|
||||
// that can be deleted after delay calculation for the driver pin
|
||||
// is finished.
|
||||
Vector<Parasitic*> unsaved_parasitics_;
|
||||
Vector<const Pin *> reduced_parasitic_drvrs_;
|
||||
};
|
||||
|
||||
ArcDelayCalc *
|
||||
|
|
|
|||
|
|
@ -0,0 +1,171 @@
|
|||
// OpenSTA, Static Timing Analyzer
|
||||
// Copyright (c) 2023, Parallax Software, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "ParallelDelayCalc.hh"
|
||||
|
||||
#include "TimingArc.hh"
|
||||
#include "Corner.hh"
|
||||
#include "Network.hh"
|
||||
#include "Graph.hh"
|
||||
#include "Sdc.hh"
|
||||
#include "Liberty.hh"
|
||||
#include "GraphDelayCalc.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
ParallelDelayCalc::ParallelDelayCalc(StaState *sta):
|
||||
DelayCalcBase(sta)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ParallelDelayCalc::inputPortDelay(const Pin *drvr_pin,
|
||||
float in_slew,
|
||||
const RiseFall *rf,
|
||||
const Parasitic *parasitic,
|
||||
const DcalcAnalysisPt *dcalc_ap)
|
||||
{
|
||||
DelayCalcBase::inputPortDelay(drvr_pin, in_slew, rf, parasitic, dcalc_ap);
|
||||
multi_drvr_slew_factor_ = 1.0;
|
||||
}
|
||||
|
||||
void
|
||||
ParallelDelayCalc::gateDelayInit(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
const Parasitic *drvr_parasitic)
|
||||
{
|
||||
DelayCalcBase::gateDelayInit(arc, in_slew, drvr_parasitic);
|
||||
multi_drvr_slew_factor_ = 1.0F;
|
||||
}
|
||||
|
||||
void
|
||||
ParallelDelayCalc::findParallelGateDelays(const MultiDrvrNet *multi_drvr,
|
||||
GraphDelayCalc *dcalc)
|
||||
{
|
||||
int count = RiseFall::index_count * corners_->dcalcAnalysisPtCount();
|
||||
parallel_delays_.resize(count);
|
||||
parallel_slews_.resize(count);
|
||||
for (auto dcalc_ap : corners_->dcalcAnalysisPts()) {
|
||||
for (auto drvr_rf : RiseFall::range()) {
|
||||
DcalcAPIndex ap_index = dcalc_ap->index();
|
||||
int drvr_rf_index = drvr_rf->index();
|
||||
int index = ap_index * RiseFall::index_count + drvr_rf_index;
|
||||
findMultiDrvrGateDelay(multi_drvr, drvr_rf, dcalc_ap, dcalc,
|
||||
parallel_delays_[index],
|
||||
parallel_slews_[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ParallelDelayCalc::findMultiDrvrGateDelay(const MultiDrvrNet *multi_drvr,
|
||||
const RiseFall *drvr_rf,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
GraphDelayCalc *dcalc,
|
||||
// Return values.
|
||||
ArcDelay ¶llel_delay,
|
||||
Slew ¶llel_slew)
|
||||
{
|
||||
ArcDelay delay_sum = 0.0;
|
||||
Slew slew_sum = 0.0;
|
||||
for (Vertex *drvr_vertex : *multi_drvr->drvrs()) {
|
||||
Pin *drvr_pin = drvr_vertex->pin();
|
||||
Instance *drvr_inst = network_->instance(drvr_pin);
|
||||
const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax());
|
||||
if (pvt == nullptr)
|
||||
pvt = dcalc_ap->operatingConditions();
|
||||
VertexInEdgeIterator edge_iter(drvr_vertex, graph_);
|
||||
while (edge_iter.hasNext()) {
|
||||
Edge *edge = edge_iter.next();
|
||||
TimingArcSet *arc_set = edge->timingArcSet();
|
||||
const LibertyPort *related_out_port = arc_set->relatedOut();
|
||||
for (TimingArc *arc : arc_set->arcs()) {
|
||||
RiseFall *arc_rf = arc->toEdge()->asRiseFall();
|
||||
if (arc_rf == drvr_rf) {
|
||||
Vertex *from_vertex = edge->from(graph_);
|
||||
RiseFall *from_rf = arc->fromEdge()->asRiseFall();
|
||||
Slew from_slew = dcalc->edgeFromSlew(from_vertex, from_rf,
|
||||
edge, dcalc_ap);
|
||||
ArcDelay intrinsic_delay;
|
||||
Slew intrinsic_slew;
|
||||
gateDelay(arc, from_slew, 0.0, 0, 0.0, pvt, dcalc_ap,
|
||||
intrinsic_delay, intrinsic_slew);
|
||||
Parasitic *parasitic = findParasitic(drvr_pin, drvr_rf, dcalc_ap);
|
||||
const Pin *related_out_pin = 0;
|
||||
float related_out_cap = 0.0;
|
||||
if (related_out_port) {
|
||||
Instance *inst = network_->instance(drvr_pin);
|
||||
related_out_pin = network_->findPin(inst, related_out_port);
|
||||
if (related_out_pin) {
|
||||
Parasitic *related_out_parasitic = findParasitic(related_out_pin,
|
||||
drvr_rf,
|
||||
dcalc_ap);
|
||||
related_out_cap = dcalc->loadCap(related_out_pin,
|
||||
related_out_parasitic,
|
||||
drvr_rf, dcalc_ap);
|
||||
}
|
||||
}
|
||||
float load_cap = dcalc->loadCap(drvr_pin, parasitic,
|
||||
drvr_rf, dcalc_ap);
|
||||
ArcDelay gate_delay;
|
||||
Slew gate_slew;
|
||||
gateDelay(arc, from_slew, load_cap, parasitic,
|
||||
related_out_cap, pvt, dcalc_ap,
|
||||
gate_delay, gate_slew);
|
||||
delay_sum += 1.0F / (gate_delay - intrinsic_delay);
|
||||
slew_sum += 1.0F / gate_slew;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
parallel_delay = 1.0F / delay_sum;
|
||||
parallel_slew = 1.0F / slew_sum;
|
||||
}
|
||||
|
||||
void
|
||||
ParallelDelayCalc::parallelGateDelay(const Pin *,
|
||||
const TimingArc *arc,
|
||||
const Slew &from_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
ArcDelay &gate_delay,
|
||||
Slew &gate_slew)
|
||||
{
|
||||
ArcDelay intrinsic_delay;
|
||||
Slew intrinsic_slew;
|
||||
gateDelay(arc, from_slew, 0.0, 0, 0.0, pvt, dcalc_ap,
|
||||
intrinsic_delay, intrinsic_slew);
|
||||
const RiseFall *drvr_rf = arc->toEdge()->asRiseFall();
|
||||
int index = dcalc_ap->index() * RiseFall::index_count + drvr_rf->index();
|
||||
ArcDelay parallel_delay = parallel_delays_[index];
|
||||
Slew parallel_slew = parallel_slews_[index];
|
||||
gate_delay = parallel_delay + intrinsic_delay;
|
||||
gate_slew = parallel_slew;
|
||||
|
||||
Delay gate_delay1;
|
||||
Slew gate_slew1;
|
||||
gateDelay(arc, from_slew, load_cap, drvr_parasitic,
|
||||
related_out_cap, pvt, dcalc_ap,
|
||||
gate_delay1, gate_slew1);
|
||||
float factor = delayRatio(gate_slew, gate_slew1);
|
||||
multi_drvr_slew_factor_ = factor;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
// OpenSTA, Static Timing Analyzer
|
||||
// Copyright (c) 2023, Parallax Software, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "DelayCalcBase.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
// Delay calculation for parallel gates based on using parallel drive resistance.
|
||||
class ParallelDelayCalc : public DelayCalcBase
|
||||
{
|
||||
public:
|
||||
explicit ParallelDelayCalc(StaState *sta);
|
||||
void inputPortDelay(const Pin *port_pin,
|
||||
float in_slew,
|
||||
const RiseFall *rf,
|
||||
const Parasitic *parasitic,
|
||||
const DcalcAnalysisPt *dcalc_ap) override;
|
||||
void gateDelayInit(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
const Parasitic *drvr_parasitic);
|
||||
void findParallelGateDelays(const MultiDrvrNet *multi_drvr,
|
||||
GraphDelayCalc *dcalc) override;
|
||||
void parallelGateDelay(const Pin *drvr_pin,
|
||||
const TimingArc *arc,
|
||||
const Slew &from_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
ArcDelay &gate_delay,
|
||||
Slew &gate_slew) override;
|
||||
|
||||
protected:
|
||||
void findMultiDrvrGateDelay(const MultiDrvrNet *multi_drvr,
|
||||
const RiseFall *drvr_rf,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
GraphDelayCalc *dcalc,
|
||||
// Return values.
|
||||
ArcDelay ¶llel_delay,
|
||||
Slew ¶llel_slew);
|
||||
|
||||
// [drvr_rf->index][dcalc_ap->index]
|
||||
vector<ArcDelay> parallel_delays_;
|
||||
// [drvr_rf->index][dcalc_ap->index]
|
||||
vector<Slew> parallel_slews_;
|
||||
float multi_drvr_slew_factor_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
// OpenSTA, Static Timing Analyzer
|
||||
// Copyright (c) 2023, Parallax Software, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "RCDelayCalc.hh"
|
||||
|
||||
#include "Liberty.hh"
|
||||
#include "Network.hh"
|
||||
#include "Sdc.hh"
|
||||
#include "Parasitics.hh"
|
||||
#include "GraphDelayCalc.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
RCDelayCalc::RCDelayCalc(StaState *sta) :
|
||||
LumpedCapDelayCalc(sta)
|
||||
{
|
||||
}
|
||||
|
||||
ArcDelayCalc *
|
||||
RCDelayCalc::copy()
|
||||
{
|
||||
return new RCDelayCalc(this);
|
||||
}
|
||||
|
||||
void
|
||||
RCDelayCalc::inputPortDelay(const Pin *,
|
||||
float in_slew,
|
||||
const RiseFall *rf,
|
||||
const Parasitic *parasitic,
|
||||
const DcalcAnalysisPt *)
|
||||
{
|
||||
drvr_parasitic_ = parasitic;
|
||||
drvr_slew_ = in_slew;
|
||||
drvr_rf_ = rf;
|
||||
drvr_cell_ = nullptr;
|
||||
drvr_library_ = network_->defaultLibertyLibrary();
|
||||
multi_drvr_slew_factor_ = 1.0F;
|
||||
input_port_ = true;
|
||||
}
|
||||
|
||||
// For DSPF on an input port the elmore delay is used as the time
|
||||
// constant of an exponential waveform. The delay to the logic
|
||||
// threshold and slew are computed for the exponential waveform.
|
||||
// Note that this uses the driver thresholds and relies on
|
||||
// thresholdAdjust to convert the delay and slew to the load's thresholds.
|
||||
void
|
||||
RCDelayCalc::dspfWireDelaySlew(const Pin *,
|
||||
float elmore,
|
||||
ArcDelay &wire_delay,
|
||||
Slew &load_slew)
|
||||
{
|
||||
float vth = drvr_library_->inputThreshold(drvr_rf_);
|
||||
float vl = drvr_library_->slewLowerThreshold(drvr_rf_);
|
||||
float vh = drvr_library_->slewUpperThreshold(drvr_rf_);
|
||||
float slew_derate = drvr_library_->slewDerateFromLibrary();
|
||||
wire_delay = -elmore * log(1.0 - vth);
|
||||
load_slew = (drvr_slew_ + elmore * log((1.0 - vl) / (1.0 - vh))
|
||||
/ slew_derate) * multi_drvr_slew_factor_;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
#include "Sdc.hh"
|
||||
#include "Parasitics.hh"
|
||||
#include "DcalcAnalysisPt.hh"
|
||||
#include "LumpedCapDelayCalc.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
|
|
@ -30,33 +31,32 @@ namespace sta {
|
|||
// Wire delays are elmore delays.
|
||||
// Driver slews are degraded to loads by rise/fall transition_degradation
|
||||
// tables.
|
||||
class SlewDegradeDelayCalc : public RCDelayCalc
|
||||
class SlewDegradeDelayCalc : public LumpedCapDelayCalc
|
||||
{
|
||||
public:
|
||||
SlewDegradeDelayCalc(StaState *sta);
|
||||
virtual ArcDelayCalc *copy();
|
||||
virtual void inputPortDelay(const Pin *port_pin,
|
||||
float in_slew,
|
||||
const RiseFall *rf,
|
||||
const Parasitic *parasitic,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
virtual void gateDelay(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
ArcDelay &gate_delay,
|
||||
Slew &drvr_slew);
|
||||
virtual void loadDelay(const Pin *load_pin,
|
||||
ArcDelay &wire_delay,
|
||||
Slew &load_slew);
|
||||
ArcDelayCalc *copy() override;
|
||||
void inputPortDelay(const Pin *port_pin,
|
||||
float in_slew,
|
||||
const RiseFall *rf,
|
||||
const Parasitic *parasitic,
|
||||
const DcalcAnalysisPt *dcalc_ap) override;
|
||||
void gateDelay(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
ArcDelay &gate_delay,
|
||||
Slew &drvr_slew) override;
|
||||
void loadDelay(const Pin *load_pin,
|
||||
ArcDelay &wire_delay,
|
||||
Slew &load_slew) override;
|
||||
|
||||
using RCDelayCalc::gateDelay;
|
||||
using RCDelayCalc::reportGateDelay;
|
||||
using LumpedCapDelayCalc::gateDelay;
|
||||
using LumpedCapDelayCalc::reportGateDelay;
|
||||
|
||||
private:
|
||||
const Pvt *pvt_;
|
||||
|
|
@ -69,7 +69,7 @@ makeSlewDegradeDelayCalc(StaState *sta)
|
|||
}
|
||||
|
||||
SlewDegradeDelayCalc::SlewDegradeDelayCalc(StaState *sta) :
|
||||
RCDelayCalc(sta)
|
||||
LumpedCapDelayCalc(sta)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -87,12 +87,11 @@ SlewDegradeDelayCalc::inputPortDelay(const Pin *port_pin,
|
|||
const DcalcAnalysisPt *dcalc_ap)
|
||||
{
|
||||
pvt_ = dcalc_ap->operatingConditions();
|
||||
RCDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap);
|
||||
LumpedCapDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap);
|
||||
}
|
||||
|
||||
void
|
||||
SlewDegradeDelayCalc::gateDelay(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
SlewDegradeDelayCalc::gateDelay(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
|
|
@ -106,12 +105,11 @@ SlewDegradeDelayCalc::gateDelay(const LibertyCell *drvr_cell,
|
|||
input_port_ = false;
|
||||
drvr_parasitic_ = drvr_parasitic;
|
||||
drvr_rf_ = arc->toEdge()->asRiseFall();
|
||||
drvr_cell_ = drvr_cell;
|
||||
drvr_library_ = drvr_cell->libertyLibrary();
|
||||
drvr_cell_ = arc->from()->libertyCell();
|
||||
drvr_library_ = drvr_cell_->libertyLibrary();
|
||||
pvt_ = pvt;
|
||||
LumpedCapDelayCalc::gateDelay(drvr_cell, arc, in_slew,
|
||||
load_cap, drvr_parasitic, related_out_cap,
|
||||
pvt, dcalc_ap,
|
||||
LumpedCapDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic,
|
||||
related_out_cap, pvt, dcalc_ap,
|
||||
gate_delay, drvr_slew);
|
||||
}
|
||||
|
||||
|
|
@ -129,8 +127,7 @@ SlewDegradeDelayCalc::loadDelay(const Pin *load_pin,
|
|||
if (elmore_exists) {
|
||||
if (drvr_library_ && drvr_library_->wireSlewDegradationTable(drvr_rf_)) {
|
||||
wire_delay1 = elmore;
|
||||
load_slew1 = drvr_library_->degradeWireSlew(drvr_cell_, drvr_rf_,
|
||||
pvt_,
|
||||
load_slew1 = drvr_library_->degradeWireSlew(drvr_rf_,
|
||||
delayAsFloat(drvr_slew_),
|
||||
delayAsFloat(wire_delay1));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,10 +16,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "RCDelayCalc.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
class ArcDelayCalc;
|
||||
class StaState;
|
||||
|
||||
ArcDelayCalc *
|
||||
makeSlewDegradeDelayCalc(StaState *sta);
|
||||
|
||||
|
|
|
|||
|
|
@ -61,8 +61,7 @@ UnitDelayCalc::inputPortDelay(const Pin *,
|
|||
}
|
||||
|
||||
void
|
||||
UnitDelayCalc::gateDelay(const LibertyCell *,
|
||||
const TimingArc *,
|
||||
UnitDelayCalc::gateDelay(const TimingArc *,
|
||||
const Slew &,
|
||||
float,
|
||||
const Parasitic *,
|
||||
|
|
@ -75,6 +74,29 @@ UnitDelayCalc::gateDelay(const LibertyCell *,
|
|||
drvr_slew = 0.0;
|
||||
}
|
||||
|
||||
void
|
||||
UnitDelayCalc::findParallelGateDelays(const MultiDrvrNet *,
|
||||
GraphDelayCalc *)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
UnitDelayCalc::parallelGateDelay(const Pin *,
|
||||
const TimingArc *,
|
||||
const Slew &,
|
||||
float,
|
||||
const Parasitic *,
|
||||
float,
|
||||
const Pvt *,
|
||||
const DcalcAnalysisPt *,
|
||||
// Return values.
|
||||
ArcDelay &gate_delay,
|
||||
Slew &gate_slew)
|
||||
{
|
||||
gate_delay = units_->timeUnit()->scale();
|
||||
gate_slew = 0.0;
|
||||
}
|
||||
|
||||
void
|
||||
UnitDelayCalc::loadDelay(const Pin *,
|
||||
ArcDelay &wire_delay,
|
||||
|
|
@ -85,8 +107,7 @@ UnitDelayCalc::loadDelay(const Pin *,
|
|||
}
|
||||
|
||||
float
|
||||
UnitDelayCalc::ceff(const LibertyCell *,
|
||||
const TimingArc *,
|
||||
UnitDelayCalc::ceff(const TimingArc *,
|
||||
const Slew &,
|
||||
float,
|
||||
const Parasitic *,
|
||||
|
|
@ -98,8 +119,7 @@ UnitDelayCalc::ceff(const LibertyCell *,
|
|||
}
|
||||
|
||||
string
|
||||
UnitDelayCalc::reportGateDelay(const LibertyCell *,
|
||||
const TimingArc *,
|
||||
UnitDelayCalc::reportGateDelay(const TimingArc *,
|
||||
const Slew &,
|
||||
float,
|
||||
const Parasitic *,
|
||||
|
|
@ -114,8 +134,7 @@ UnitDelayCalc::reportGateDelay(const LibertyCell *,
|
|||
}
|
||||
|
||||
void
|
||||
UnitDelayCalc::checkDelay(const LibertyCell *,
|
||||
const TimingArc *,
|
||||
UnitDelayCalc::checkDelay(const TimingArc *,
|
||||
const Slew &,
|
||||
const Slew &,
|
||||
float,
|
||||
|
|
@ -128,8 +147,7 @@ UnitDelayCalc::checkDelay(const LibertyCell *,
|
|||
}
|
||||
|
||||
string
|
||||
UnitDelayCalc::reportCheckDelay(const LibertyCell *,
|
||||
const TimingArc *,
|
||||
UnitDelayCalc::reportCheckDelay(const TimingArc *,
|
||||
const Slew &,
|
||||
const char *,
|
||||
const Slew &,
|
||||
|
|
|
|||
|
|
@ -35,8 +35,7 @@ public:
|
|||
const RiseFall *rf,
|
||||
const Parasitic *parasitic,
|
||||
const DcalcAnalysisPt *dcalc_ap) override;
|
||||
void gateDelay(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
void gateDelay(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
|
|
@ -46,21 +45,32 @@ public:
|
|||
// Return values.
|
||||
ArcDelay &gate_delay,
|
||||
Slew &drvr_slew) override;
|
||||
void findParallelGateDelays(const MultiDrvrNet *multi_drvr,
|
||||
GraphDelayCalc *dcalc) override;
|
||||
// Retrieve the delay and slew for one parallel gate.
|
||||
void parallelGateDelay(const Pin *drvr_pin,
|
||||
const TimingArc *arc,
|
||||
const Slew &from_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
ArcDelay &gate_delay,
|
||||
Slew &gate_slew) override;
|
||||
void loadDelay(const Pin *load_pin,
|
||||
// Return values.
|
||||
ArcDelay &wire_delay,
|
||||
Slew &load_slew) override;
|
||||
void setMultiDrvrSlewFactor(float) override {}
|
||||
float ceff(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
float ceff(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap) override;
|
||||
void checkDelay(const LibertyCell *cell,
|
||||
const TimingArc *arc,
|
||||
void checkDelay(const TimingArc *arc,
|
||||
const Slew &from_slew,
|
||||
const Slew &to_slew,
|
||||
float related_out_cap,
|
||||
|
|
@ -68,8 +78,7 @@ public:
|
|||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
ArcDelay &margin) override;
|
||||
string reportGateDelay(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
string reportGateDelay(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
|
|
@ -77,8 +86,7 @@ public:
|
|||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
int digits) override;
|
||||
string reportCheckDelay(const LibertyCell *cell,
|
||||
const TimingArc *arc,
|
||||
string reportCheckDelay(const TimingArc *arc,
|
||||
const Slew &from_slew,
|
||||
const char *from_slew_annotation,
|
||||
const Slew &to_slew,
|
||||
|
|
|
|||
BIN
doc/OpenSTA.odt
BIN
doc/OpenSTA.odt
Binary file not shown.
|
|
@ -783,8 +783,8 @@ Graph::setWireArcDelay(Edge *edge,
|
|||
}
|
||||
|
||||
bool
|
||||
Graph::arcDelayAnnotated(Edge *edge,
|
||||
TimingArc *arc,
|
||||
Graph::arcDelayAnnotated(const Edge *edge,
|
||||
const TimingArc *arc,
|
||||
DcalcAPIndex ap_index) const
|
||||
{
|
||||
if (arc_delay_annotated_.size()) {
|
||||
|
|
@ -799,7 +799,7 @@ Graph::arcDelayAnnotated(Edge *edge,
|
|||
|
||||
void
|
||||
Graph::setArcDelayAnnotated(Edge *edge,
|
||||
TimingArc *arc,
|
||||
const TimingArc *arc,
|
||||
DcalcAPIndex ap_index,
|
||||
bool annotated)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "MinMax.hh"
|
||||
#include "LibertyClass.hh"
|
||||
|
|
@ -28,22 +29,26 @@
|
|||
namespace sta {
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
class Parasitic;
|
||||
class DcalcAnalysisPt;
|
||||
class MultiDrvrNet;
|
||||
|
||||
// Delay calculator class hierarchy.
|
||||
// ArcDelayCalc
|
||||
// UnitDelayCalc
|
||||
// LumpedCapDelayCalc
|
||||
// RCDelayCalc
|
||||
// SlewDegradeDelayCalc
|
||||
// DmpCeffDelayCalc
|
||||
// DmpCeffElmoreDelayCalc
|
||||
// DmpCeffTwoPoleDelayCalc
|
||||
// ArnoldiDelayCalc
|
||||
// DelayCalcBase
|
||||
// ParallelDelayCalc
|
||||
// LumpedCapDelayCalc
|
||||
// SlewDegradeDelayCalc
|
||||
// DmpCeffDelayCalc
|
||||
// DmpCeffElmoreDelayCalc
|
||||
// DmpCeffTwoPoleDelayCalc
|
||||
// ArnoldiDelayCalc
|
||||
|
||||
// Abstract class to interface to a delay calculator primitive.
|
||||
// Abstract class for the graph delay calculator traversal to interface
|
||||
// to a delay calculator primitive.
|
||||
class ArcDelayCalc : public StaState
|
||||
{
|
||||
public:
|
||||
|
|
@ -66,8 +71,7 @@ public:
|
|||
const DcalcAnalysisPt *dcalc_ap) = 0;
|
||||
|
||||
// Find the delay and slew for arc driving drvr_pin.
|
||||
virtual void gateDelay(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
virtual void gateDelay(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
// Pass in load_cap or drvr_parasitic.
|
||||
float load_cap,
|
||||
|
|
@ -78,16 +82,29 @@ public:
|
|||
// Return values.
|
||||
ArcDelay &gate_delay,
|
||||
Slew &drvr_slew) = 0;
|
||||
// Find gate delays and slews for parallel gates.
|
||||
virtual void findParallelGateDelays(const MultiDrvrNet *multi_drvr,
|
||||
GraphDelayCalc *dcalc) = 0;
|
||||
// Retrieve the delay and slew for one parallel gate.
|
||||
virtual void parallelGateDelay(const Pin *drvr_pin,
|
||||
const TimingArc *arc,
|
||||
const Slew &from_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
ArcDelay &gate_delay,
|
||||
Slew &gate_slew) = 0;
|
||||
// Find the wire delay and load slew of a load pin.
|
||||
// Called after inputPortDelay or gateDelay.
|
||||
virtual void loadDelay(const Pin *load_pin,
|
||||
// Return values.
|
||||
ArcDelay &wire_delay,
|
||||
Slew &load_slew) = 0;
|
||||
virtual void setMultiDrvrSlewFactor(float factor) = 0;
|
||||
// Ceff for parasitics with pi models.
|
||||
virtual float ceff(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
virtual float ceff(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
const Parasitic *drvr_parasitic,
|
||||
|
|
@ -97,8 +114,7 @@ public:
|
|||
|
||||
// Find the delay for a timing check arc given the arc's
|
||||
// from/clock, to/data slews and related output pin parasitic.
|
||||
virtual void checkDelay(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
virtual void checkDelay(const TimingArc *arc,
|
||||
const Slew &from_slew,
|
||||
const Slew &to_slew,
|
||||
float related_out_cap,
|
||||
|
|
@ -107,8 +123,7 @@ public:
|
|||
// Return values.
|
||||
ArcDelay &margin) = 0;
|
||||
// Report delay and slew calculation.
|
||||
virtual string reportGateDelay(const LibertyCell *drvr_cell,
|
||||
const TimingArc *arc,
|
||||
virtual string reportGateDelay(const TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
// Pass in load_cap or drvr_parasitic.
|
||||
float load_cap,
|
||||
|
|
@ -118,8 +133,7 @@ public:
|
|||
const DcalcAnalysisPt *dcalc_ap,
|
||||
int digits) = 0;
|
||||
// Report timing check delay calculation.
|
||||
virtual string reportCheckDelay(const LibertyCell *cell,
|
||||
const TimingArc *arc,
|
||||
virtual string reportCheckDelay(const TimingArc *arc,
|
||||
const Slew &from_slew,
|
||||
const char *from_slew_annotation,
|
||||
const Slew &to_slew,
|
||||
|
|
|
|||
|
|
@ -157,11 +157,11 @@ public:
|
|||
DcalcAPIndex ap_index,
|
||||
const ArcDelay &delay);
|
||||
// Is timing arc delay annotated.
|
||||
bool arcDelayAnnotated(Edge *edge,
|
||||
TimingArc *arc,
|
||||
bool arcDelayAnnotated(const Edge *edge,
|
||||
const TimingArc *arc,
|
||||
DcalcAPIndex ap_index) const;
|
||||
void setArcDelayAnnotated(Edge *edge,
|
||||
TimingArc *arc,
|
||||
const TimingArc *arc,
|
||||
DcalcAPIndex ap_index,
|
||||
bool annotated);
|
||||
bool wireDelayAnnotated(Edge *edge,
|
||||
|
|
@ -539,7 +539,6 @@ class VertexSet : public Set<Vertex*, VertexIdLess>
|
|||
{
|
||||
public:
|
||||
VertexSet(Graph *&graph);
|
||||
VertexSet(const VertexSet &set);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -16,58 +16,66 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Map.hh"
|
||||
#include "NetworkClass.hh"
|
||||
#include "GraphClass.hh"
|
||||
#include "SearchClass.hh"
|
||||
#include "DcalcAnalysisPt.hh"
|
||||
#include "StaState.hh"
|
||||
#include "Delay.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
class BfsFwdIterator;
|
||||
class SearchPred;
|
||||
class DelayCalcObserver;
|
||||
class Parasitic;
|
||||
class Corner;
|
||||
class MultiDrvrNet;
|
||||
class FindVertexDelays;
|
||||
class NetCaps;
|
||||
|
||||
// Base class for graph delay calculator.
|
||||
// This class annotates the arc delays and slews on the graph by calling
|
||||
// the timing arc delay calculation primitive through an implementation
|
||||
// of the ArcDelayCalc abstract class.
|
||||
// This class does not traverse the graph or call an arc delay
|
||||
// calculator. Use it with applications that use an external delay
|
||||
// calculator and annotate all edge delays.
|
||||
typedef Map<const Vertex*, MultiDrvrNet*> MultiDrvrNetMap;
|
||||
|
||||
// This class traverses the graph calling the arc delay calculator and
|
||||
// annotating delays on graph edges.
|
||||
class GraphDelayCalc : public StaState
|
||||
{
|
||||
public:
|
||||
explicit GraphDelayCalc(StaState *sta);
|
||||
virtual ~GraphDelayCalc() {}
|
||||
// Find arc delays and vertex slews thru level.
|
||||
virtual void findDelays(Level /* level */) {};
|
||||
// Find and annotate drvr_vertex gate and load delays/slews.
|
||||
virtual void findDelays(Vertex * /* drvr_vertex */) {};
|
||||
GraphDelayCalc(StaState *sta);
|
||||
virtual ~GraphDelayCalc();
|
||||
virtual void copyState(const StaState *sta);
|
||||
// Set the observer for edge delay changes.
|
||||
virtual void setObserver(DelayCalcObserver *observer);
|
||||
// Invalidate all delays/slews.
|
||||
virtual void delaysInvalid() {};
|
||||
virtual void delaysInvalid();
|
||||
// Invalidate vertex and downstream delays/slews.
|
||||
virtual void delayInvalid(Vertex * /* vertex */) {};
|
||||
virtual void delayInvalid(const Pin * /* pin */) {};
|
||||
virtual void deleteVertexBefore(Vertex * /* vertex */) {};
|
||||
virtual void delayInvalid(Vertex *vertex);
|
||||
virtual void delayInvalid(const Pin *pin);
|
||||
virtual void deleteVertexBefore(Vertex *vertex);
|
||||
// Reset to virgin state.
|
||||
virtual void clear() {}
|
||||
virtual void clear();
|
||||
// Find arc delays and vertex slews thru level.
|
||||
virtual void findDelays(Level level);
|
||||
// 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);
|
||||
// Percentage (0.0:1.0) change in delay that causes downstream
|
||||
// delays to be recomputed during incremental delay calculation.
|
||||
virtual float incrementalDelayTolerance();
|
||||
virtual void setIncrementalDelayTolerance(float /* tol */) {}
|
||||
// Set the observer for edge delay changes.
|
||||
virtual void setObserver(DelayCalcObserver *observer);
|
||||
virtual void setIncrementalDelayTolerance(float tol);
|
||||
// Load pin_cap + wire_cap.
|
||||
virtual float loadCap(const Pin *drvr_pin,
|
||||
const RiseFall *drvr_rf,
|
||||
const DcalcAnalysisPt *dcalc_ap) const;
|
||||
// Load pin_cap + wire_cap including parasitic min/max for rise/fall.
|
||||
virtual float loadCap(const Pin *drvr_pin,
|
||||
const DcalcAnalysisPt *dcalc_ap) const;
|
||||
// pin_cap = net pin capacitances + port external pin capacitance,
|
||||
// wire_cap = annotated net capacitance + port external wire capacitance.
|
||||
virtual void loadCap(const Pin *drvr_pin,
|
||||
|
|
@ -78,17 +86,15 @@ public:
|
|||
float &pin_cap,
|
||||
float &wire_cap) const;
|
||||
// Load pin_cap + wire_cap including parasitic.
|
||||
virtual float loadCap(const Pin *drvr_pin,
|
||||
const RiseFall *to_rf,
|
||||
const DcalcAnalysisPt *dcalc_ap) const;
|
||||
// Load pin_cap + wire_cap including parasitic min/max for rise/fall.
|
||||
virtual float loadCap(const Pin *drvr_pin,
|
||||
const DcalcAnalysisPt *dcalc_ap) const;
|
||||
// Load pin_cap + wire_cap.
|
||||
virtual float loadCap(const Pin *drvr_pin,
|
||||
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,
|
||||
|
|
@ -97,9 +103,9 @@ public:
|
|||
float &wire_cap,
|
||||
float &fanout,
|
||||
bool &has_set_load) const;
|
||||
virtual float ceff(Edge *edge,
|
||||
TimingArc *arc,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
float ceff(Edge *edge,
|
||||
TimingArc *arc,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
// Precedence:
|
||||
// SDF annotation
|
||||
// Liberty library
|
||||
|
|
@ -118,6 +124,128 @@ public:
|
|||
// Return values.
|
||||
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 initSlew(Vertex *vertex);
|
||||
void seedRootSlew(Vertex *vertex,
|
||||
ArcDelayCalc *arc_delay_calc);
|
||||
void seedRootSlews();
|
||||
void seedDrvrSlew(Vertex *vertex,
|
||||
ArcDelayCalc *arc_delay_calc);
|
||||
void seedNoDrvrSlew(Vertex *drvr_vertex,
|
||||
const Pin *drvr_pin,
|
||||
const RiseFall *rf,
|
||||
DcalcAnalysisPt *dcalc_ap,
|
||||
ArcDelayCalc *arc_delay_calc);
|
||||
void seedNoDrvrCellSlew(Vertex *drvr_vertex,
|
||||
const Pin *drvr_pin,
|
||||
const RiseFall *rf,
|
||||
InputDrive *drive,
|
||||
DcalcAnalysisPt *dcalc_ap,
|
||||
ArcDelayCalc *arc_delay_calc);
|
||||
void seedLoadSlew(Vertex *vertex);
|
||||
void setInputPortWireDelays(Vertex *vertex);
|
||||
void findInputDriverDelay(const LibertyCell *drvr_cell,
|
||||
const Pin *drvr_pin,
|
||||
Vertex *drvr_vertex,
|
||||
const RiseFall *rf,
|
||||
const LibertyPort *from_port,
|
||||
float *from_slews,
|
||||
const LibertyPort *to_port,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
LibertyPort *driveCellDefaultFromPort(const LibertyCell *cell,
|
||||
const LibertyPort *to_port);
|
||||
int findPortIndex(const LibertyCell *cell,
|
||||
const LibertyPort *port);
|
||||
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(const Instance *drvr_inst,
|
||||
const Pin *drvr_pin,
|
||||
Vertex *drvr_vertex,
|
||||
const MultiDrvrNet *multi_drvr,
|
||||
Edge *edge,
|
||||
ArcDelayCalc *arc_delay_calc);
|
||||
void initWireDelays(Vertex *drvr_vertex);
|
||||
void initRootSlews(Vertex *vertex);
|
||||
void zeroSlewAndWireDelays(Vertex *drvr_vertex);
|
||||
void findVertexDelay(Vertex *vertex,
|
||||
ArcDelayCalc *arc_delay_calc,
|
||||
bool propagate);
|
||||
void enqueueTimingChecksEdges(Vertex *vertex);
|
||||
bool findArcDelay(const Pin *drvr_pin,
|
||||
Vertex *drvr_vertex,
|
||||
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,
|
||||
const ArcDelay &extra_delay,
|
||||
bool merge,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
ArcDelayCalc *arc_delay_calc);
|
||||
void findLatchEdgeDelays(Edge *edge);
|
||||
void findCheckEdgeDelays(Edge *edge,
|
||||
ArcDelayCalc *arc_delay_calc);
|
||||
void deleteMultiDrvrNets();
|
||||
Slew checkEdgeClkSlew(const Vertex *from_vertex,
|
||||
const RiseFall *from_rf,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
bool bidirectDrvrSlewFromLoad(const Vertex *vertex) const;
|
||||
MultiDrvrNet *multiDrvrNet(const Vertex *drvr_vertex) const;
|
||||
void loadCap(const Parasitic *drvr_parasitic,
|
||||
bool has_set_load,
|
||||
// Return values.
|
||||
float &pin_cap,
|
||||
float &wire_cap) const;
|
||||
|
||||
// Observer for edge delay changes.
|
||||
DelayCalcObserver *observer_;
|
||||
bool delays_seeded_;
|
||||
bool incremental_;
|
||||
bool delays_exist_;
|
||||
// Vertices with invalid -to delays.
|
||||
VertexSet *invalid_delays_;
|
||||
// Timing check edges with invalid delays.
|
||||
EdgeSet invalid_check_edges_;
|
||||
// Latch D->Q edges with invalid delays.
|
||||
EdgeSet invalid_latch_edges_;
|
||||
// shared by invalid_check_edges_ and invalid_latch_edges_
|
||||
std::mutex invalid_edge_lock_;
|
||||
SearchPred *search_pred_;
|
||||
SearchPred *search_non_latch_pred_;
|
||||
SearchPred *clk_pred_;
|
||||
BfsFwdIterator *iter_;
|
||||
MultiDrvrNetMap multi_drvr_net_map_;
|
||||
bool multi_drvr_nets_found_;
|
||||
// Percentage (0.0:1.0) change in delay that causes downstream
|
||||
// delays to be recomputed during incremental delay calculation.
|
||||
float incremental_delay_tolerance_;
|
||||
|
||||
friend class FindVertexDelays;
|
||||
friend class MultiDrvrNet;
|
||||
};
|
||||
|
||||
// Abstract base class for edge delay change observer.
|
||||
|
|
@ -131,4 +259,33 @@ public:
|
|||
virtual void checkDelayChangedTo(Vertex *vertex) = 0;
|
||||
};
|
||||
|
||||
// Nets with multiple drivers (tristate, bidirect or output).
|
||||
// Cache net caps to prevent N^2 net pin walk.
|
||||
class MultiDrvrNet
|
||||
{
|
||||
public:
|
||||
MultiDrvrNet(VertexSet *drvrs);
|
||||
~MultiDrvrNet();
|
||||
const VertexSet *drvrs() const { return drvrs_; }
|
||||
VertexSet *drvrs() { return drvrs_; }
|
||||
bool parallelGates(const Network *network) const;
|
||||
Vertex *dcalcDrvr() const { return dcalc_drvr_; }
|
||||
void setDcalcDrvr(Vertex *drvr);
|
||||
void netCaps(const RiseFall *rf,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
float &pin_cap,
|
||||
float &wire_cap,
|
||||
float &fanout,
|
||||
bool &has_net_load) const;
|
||||
void findCaps(const Sdc *sdc);
|
||||
|
||||
private:
|
||||
// Driver that triggers delay calculation for all the drivers on the net.
|
||||
Vertex *dcalc_drvr_;
|
||||
VertexSet *drvrs_;
|
||||
// [drvr_rf->index][dcalc_ap->index]
|
||||
vector<NetCaps> net_caps_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -167,16 +167,14 @@ public:
|
|||
const LibertyCell *cell,
|
||||
const Pvt *pvt) const;
|
||||
float scaleFactor(ScaleFactorType type,
|
||||
int tr_index,
|
||||
int rf_index,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *pvt) const;
|
||||
|
||||
void setWireSlewDegradationTable(TableModel *model,
|
||||
RiseFall *rf);
|
||||
TableModel *wireSlewDegradationTable(const RiseFall *rf) const;
|
||||
float degradeWireSlew(const LibertyCell *cell,
|
||||
const RiseFall *rf,
|
||||
const Pvt *pvt,
|
||||
float degradeWireSlew(const RiseFall *rf,
|
||||
float in_slew,
|
||||
float wire_delay) const;
|
||||
// Check for supported axis variables.
|
||||
|
|
@ -323,9 +321,7 @@ public:
|
|||
void addDriverWaveform(DriverWaveform *driver_waveform);
|
||||
|
||||
protected:
|
||||
float degradeWireSlew(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
const TableModel *model,
|
||||
float degradeWireSlew(const TableModel *model,
|
||||
float in_slew,
|
||||
float wire_delay) const;
|
||||
|
||||
|
|
@ -925,7 +921,7 @@ public:
|
|||
RiseFall *rf);
|
||||
float scale(ScaleFactorType type,
|
||||
ScaleFactorPvt pvt,
|
||||
int tr_index);
|
||||
int rf_index);
|
||||
float scale(ScaleFactorType type,
|
||||
ScaleFactorPvt pvt);
|
||||
void setScale(ScaleFactorType type,
|
||||
|
|
|
|||
|
|
@ -23,9 +23,10 @@ namespace sta {
|
|||
class GateLinearModel : public GateTimingModel
|
||||
{
|
||||
public:
|
||||
GateLinearModel(float intrinsic, float resistance);
|
||||
void gateDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
GateLinearModel(LibertyCell *cell,
|
||||
float intrinsic,
|
||||
float resistance);
|
||||
void gateDelay(const Pvt *pvt,
|
||||
float in_slew,
|
||||
float load_cap,
|
||||
float related_out_cap,
|
||||
|
|
@ -33,15 +34,13 @@ public:
|
|||
// Return values.
|
||||
ArcDelay &gate_delay,
|
||||
Slew &drvr_slew) const override;
|
||||
string reportGateDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
string reportGateDelay(const Pvt *pvt,
|
||||
float in_slew,
|
||||
float load_cap,
|
||||
float related_out_cap,
|
||||
bool pocv_enabled,
|
||||
int digits) const override;
|
||||
float driveResistance(const LibertyCell *cell,
|
||||
const Pvt *pvt) const override;
|
||||
float driveResistance(const Pvt *pvt) const override;
|
||||
|
||||
protected:
|
||||
void setIsScaled(bool is_scaled) override;
|
||||
|
|
@ -53,17 +52,16 @@ protected:
|
|||
class CheckLinearModel : public CheckTimingModel
|
||||
{
|
||||
public:
|
||||
explicit CheckLinearModel(float intrinsic);
|
||||
void checkDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
explicit CheckLinearModel(LibertyCell *cell,
|
||||
float intrinsic);
|
||||
void checkDelay(const Pvt *pvt,
|
||||
float from_slew,
|
||||
float to_slew,
|
||||
float related_out_cap,
|
||||
bool pocv_enabled,
|
||||
// Return values.
|
||||
ArcDelay &margin) const override;
|
||||
string reportCheckDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
string reportCheckDelay(const Pvt *pvt,
|
||||
float from_slew,
|
||||
const char *from_slew_annotation,
|
||||
float to_slew,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ enum class PwrActivityOrigin
|
|||
global,
|
||||
input,
|
||||
user,
|
||||
vcd,
|
||||
propagated,
|
||||
clock,
|
||||
constant,
|
||||
|
|
@ -42,6 +43,7 @@ public:
|
|||
float duty() const { return duty_; }
|
||||
void setDuty(float duty);
|
||||
PwrActivityOrigin origin() { return origin_; }
|
||||
void setOrigin(PwrActivityOrigin origin);
|
||||
const char *originName() const;
|
||||
void set(float activity,
|
||||
float duty,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ class MinPulseWidthCheck;
|
|||
class MinPeriodCheck;
|
||||
class MaxSkewCheck;
|
||||
class CharPtrLess;
|
||||
class SearchPred;
|
||||
class BfsFwdIterator;
|
||||
|
||||
// Tag compare using tag matching (tagMatch) critera.
|
||||
class TagMatchLess
|
||||
|
|
@ -114,7 +116,7 @@ typedef Vector<PathVertex> PathVertexSeq;
|
|||
typedef Vector<Slack> SlackSeq;
|
||||
typedef Delay Crpr;
|
||||
typedef Vector<PathRef> PathRefSeq;
|
||||
typedef MinMaxValues<float> ClkDelays[RiseFall::index_count][RiseFall::index_count];
|
||||
typedef MinMaxValues<Delay> ClkDelays[RiseFall::index_count][RiseFall::index_count];
|
||||
|
||||
enum class ReportPathFormat { full,
|
||||
full_clock,
|
||||
|
|
|
|||
|
|
@ -429,8 +429,6 @@ public:
|
|||
bool isDisabledConstant(Edge *edge);
|
||||
// Edge is default cond disabled by timing_disable_cond_default_arcs var.
|
||||
bool isDisabledCondDefault(Edge *edge);
|
||||
// Edge is disabled to prpath a clock from propagating.
|
||||
bool isDisabledClock(Edge *edge);
|
||||
// Return a set of constant pins that disabled edge.
|
||||
// Caller owns the returned set.
|
||||
PinSet disabledConstantPins(Edge *edge);
|
||||
|
|
|
|||
|
|
@ -51,15 +51,15 @@ tableVariableUnit(TableAxisVariable variable,
|
|||
class GateTableModel : public GateTimingModel
|
||||
{
|
||||
public:
|
||||
GateTableModel(TableModel *delay_model,
|
||||
GateTableModel(LibertyCell *cell,
|
||||
TableModel *delay_model,
|
||||
TableModel *delay_sigma_models[EarlyLate::index_count],
|
||||
TableModel *slew_model,
|
||||
TableModel *slew_sigma_models[EarlyLate::index_count],
|
||||
ReceiverModelPtr receiver_model,
|
||||
OutputWaveforms *output_waveforms);
|
||||
virtual ~GateTableModel();
|
||||
void gateDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
void gateDelay(const Pvt *pvt,
|
||||
float in_slew,
|
||||
float load_cap,
|
||||
float related_out_cap,
|
||||
|
|
@ -67,15 +67,13 @@ public:
|
|||
// Return values.
|
||||
ArcDelay &gate_delay,
|
||||
Slew &drvr_slew) const override;
|
||||
string reportGateDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
string reportGateDelay(const Pvt *pvt,
|
||||
float in_slew,
|
||||
float load_cap,
|
||||
float related_out_cap,
|
||||
bool pocv_enabled,
|
||||
int digits) const override;
|
||||
float driveResistance(const LibertyCell *cell,
|
||||
const Pvt *pvt) const override;
|
||||
float driveResistance(const Pvt *pvt) const override;
|
||||
|
||||
const TableModel *delayModel() const { return delay_model_; }
|
||||
const TableModel *slewModel() const { return slew_model_; }
|
||||
|
|
@ -86,8 +84,7 @@ public:
|
|||
static bool checkAxes(const TablePtr table);
|
||||
|
||||
protected:
|
||||
void maxCapSlew(const LibertyCell *cell,
|
||||
float in_slew,
|
||||
void maxCapSlew(float in_slew,
|
||||
const Pvt *pvt,
|
||||
float &slew,
|
||||
float &cap) const;
|
||||
|
|
@ -96,16 +93,12 @@ protected:
|
|||
float load_cap,
|
||||
float in_slew,
|
||||
float related_out_cap) const;
|
||||
float findValue(const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float findValue(const Pvt *pvt,
|
||||
const TableModel *model,
|
||||
float in_slew,
|
||||
float load_cap,
|
||||
float related_out_cap) const;
|
||||
string reportTableLookup(const char *result_name,
|
||||
const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
const TableModel *model,
|
||||
float in_slew,
|
||||
|
|
@ -133,19 +126,18 @@ protected:
|
|||
class CheckTableModel : public CheckTimingModel
|
||||
{
|
||||
public:
|
||||
explicit CheckTableModel(TableModel *model,
|
||||
explicit CheckTableModel(LibertyCell *cell,
|
||||
TableModel *model,
|
||||
TableModel *sigma_models[EarlyLate::index_count]);
|
||||
virtual ~CheckTableModel();
|
||||
void checkDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
void checkDelay(const Pvt *pvt,
|
||||
float from_slew,
|
||||
float to_slew,
|
||||
float related_out_cap,
|
||||
bool pocv_enabled,
|
||||
// Return values.
|
||||
ArcDelay &margin) const override;
|
||||
string reportCheckDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
string reportCheckDelay(const Pvt *pvt,
|
||||
float from_slew,
|
||||
const char *from_slew_annotation,
|
||||
float to_slew,
|
||||
|
|
@ -160,9 +152,7 @@ public:
|
|||
|
||||
protected:
|
||||
void setIsScaled(bool is_scaled) override;
|
||||
float findValue(const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float findValue(const Pvt *pvt,
|
||||
const TableModel *model,
|
||||
float from_slew,
|
||||
float to_slew,
|
||||
|
|
@ -179,8 +169,6 @@ protected:
|
|||
float in_slew,
|
||||
float related_out_cap) const;
|
||||
string reportTableDelay(const char *result_name,
|
||||
const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
const TableModel *model,
|
||||
float from_slew,
|
||||
|
|
@ -217,14 +205,12 @@ public:
|
|||
float value2,
|
||||
float value3) const;
|
||||
// Table interpolated lookup with scale factor.
|
||||
float findValue(const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
float findValue(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float value1,
|
||||
float value2,
|
||||
float value3) const;
|
||||
string reportValue(const char *result_name,
|
||||
const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float value1,
|
||||
|
|
@ -237,11 +223,9 @@ public:
|
|||
Report *report) const;
|
||||
|
||||
protected:
|
||||
float scaleFactor(const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
float scaleFactor(const LibertyCell *cell,
|
||||
const Pvt *pvt) const;
|
||||
string reportPvtScaleFactor(const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
string reportPvtScaleFactor(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
int digits) const;
|
||||
|
||||
|
|
@ -280,7 +264,6 @@ public:
|
|||
float axis_value2,
|
||||
float axis_value3) const;
|
||||
virtual string reportValue(const char *result_name,
|
||||
const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float value1,
|
||||
|
|
@ -306,7 +289,6 @@ public:
|
|||
float axis_value2,
|
||||
float axis_value3) const override;
|
||||
string reportValue(const char *result_name,
|
||||
const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float value1,
|
||||
|
|
@ -342,7 +324,6 @@ public:
|
|||
float value2,
|
||||
float value3) const override;
|
||||
string reportValue(const char *result_name,
|
||||
const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float value1,
|
||||
|
|
@ -389,7 +370,6 @@ public:
|
|||
float value2,
|
||||
float value3) const override;
|
||||
string reportValue(const char *result_name,
|
||||
const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float value1,
|
||||
|
|
@ -436,7 +416,6 @@ public:
|
|||
float value2,
|
||||
float value3) const override;
|
||||
string reportValue(const char *result_name,
|
||||
const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float value1,
|
||||
|
|
|
|||
|
|
@ -29,21 +29,21 @@ using std::string;
|
|||
class TimingModel
|
||||
{
|
||||
public:
|
||||
TimingModel(LibertyCell *cell);
|
||||
virtual ~TimingModel() {}
|
||||
|
||||
protected:
|
||||
virtual void setIsScaled(bool is_scaled) = 0;
|
||||
|
||||
friend class LibertyCell;
|
||||
protected:
|
||||
LibertyCell *cell_;
|
||||
};
|
||||
|
||||
// Abstract base class for LinearModel and TableModel.
|
||||
class GateTimingModel : public TimingModel
|
||||
{
|
||||
public:
|
||||
GateTimingModel(LibertyCell *cell);
|
||||
// Gate delay calculation.
|
||||
virtual void gateDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
virtual void gateDelay(const Pvt *pvt,
|
||||
float in_slew,
|
||||
float load_cap,
|
||||
float related_out_cap,
|
||||
|
|
@ -51,32 +51,29 @@ public:
|
|||
// Return values.
|
||||
ArcDelay &gate_delay,
|
||||
Slew &drvr_slew) const = 0;
|
||||
virtual string reportGateDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
virtual string reportGateDelay(const Pvt *pvt,
|
||||
float in_slew,
|
||||
float load_cap,
|
||||
float related_out_cap,
|
||||
bool pocv_enabled,
|
||||
int digits) const = 0;
|
||||
virtual float driveResistance(const LibertyCell *cell,
|
||||
const Pvt *pvt) const = 0;
|
||||
virtual float driveResistance(const Pvt *pvt) const = 0;
|
||||
};
|
||||
|
||||
// Abstract base class for timing check timing models.
|
||||
class CheckTimingModel : public TimingModel
|
||||
{
|
||||
public:
|
||||
CheckTimingModel(LibertyCell *cell);
|
||||
// Timing check margin delay calculation.
|
||||
virtual void checkDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
virtual void checkDelay(const Pvt *pvt,
|
||||
float from_slew,
|
||||
float to_slew,
|
||||
float related_out_cap,
|
||||
bool pocv_enabled,
|
||||
// Return values.
|
||||
ArcDelay &margin) const = 0;
|
||||
virtual string reportCheckDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
virtual string reportCheckDelay(const Pvt *pvt,
|
||||
float from_slew,
|
||||
const char *from_slew_annotation,
|
||||
float to_slew,
|
||||
|
|
|
|||
|
|
@ -131,9 +131,7 @@ InternalPowerModel::power(const LibertyCell *cell,
|
|||
float axis_value1, axis_value2, axis_value3;
|
||||
findAxisValues(in_slew, load_cap,
|
||||
axis_value1, axis_value2, axis_value3);
|
||||
const LibertyLibrary *library = cell->libertyLibrary();
|
||||
return model_->findValue(library, cell, pvt,
|
||||
axis_value1, axis_value2, axis_value3);
|
||||
return model_->findValue(cell, pvt, axis_value1, axis_value2, axis_value3);
|
||||
}
|
||||
else
|
||||
return 0.0;
|
||||
|
|
@ -151,8 +149,8 @@ InternalPowerModel::reportPower(const LibertyCell *cell,
|
|||
findAxisValues(in_slew, load_cap,
|
||||
axis_value1, axis_value2, axis_value3);
|
||||
const LibertyLibrary *library = cell->libertyLibrary();
|
||||
return model_->reportValue("Power", library, cell, pvt,
|
||||
axis_value1, nullptr, axis_value2, axis_value3,
|
||||
return model_->reportValue("Power", cell, pvt, axis_value1, nullptr,
|
||||
axis_value2, axis_value3,
|
||||
library->units()->powerUnit(), digits);
|
||||
}
|
||||
return "";
|
||||
|
|
|
|||
|
|
@ -94,12 +94,12 @@ LibertyLibrary::LibertyLibrary(const char *name,
|
|||
addTableTemplate(scalar_template, type);
|
||||
}
|
||||
|
||||
for (auto tr_index : RiseFall::rangeIndex()) {
|
||||
wire_slew_degradation_tbls_[tr_index] = nullptr;
|
||||
input_threshold_[tr_index] = input_threshold_default_;
|
||||
output_threshold_[tr_index] = output_threshold_default_;
|
||||
slew_lower_threshold_[tr_index] = slew_lower_threshold_default_;
|
||||
slew_upper_threshold_[tr_index] = slew_upper_threshold_default_;
|
||||
for (auto rf_index : RiseFall::rangeIndex()) {
|
||||
wire_slew_degradation_tbls_[rf_index] = nullptr;
|
||||
input_threshold_[rf_index] = input_threshold_default_;
|
||||
output_threshold_[rf_index] = output_threshold_default_;
|
||||
slew_lower_threshold_[rf_index] = slew_lower_threshold_default_;
|
||||
slew_upper_threshold_[rf_index] = slew_upper_threshold_default_;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -111,8 +111,8 @@ LibertyLibrary::~LibertyLibrary()
|
|||
scale_factors_map_.deleteContents();
|
||||
delete scale_factors_;
|
||||
|
||||
for (auto tr_index : RiseFall::rangeIndex()) {
|
||||
TableModel *model = wire_slew_degradation_tbls_[tr_index];
|
||||
for (auto rf_index : RiseFall::rangeIndex()) {
|
||||
TableModel *model = wire_slew_degradation_tbls_[rf_index];
|
||||
delete model;
|
||||
}
|
||||
operating_conditions_.deleteContents();
|
||||
|
|
@ -289,7 +289,7 @@ LibertyLibrary::scaleFactor(ScaleFactorType type,
|
|||
|
||||
float
|
||||
LibertyLibrary::scaleFactor(ScaleFactorType type,
|
||||
int tr_index,
|
||||
int rf_index,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *pvt) const
|
||||
{
|
||||
|
|
@ -299,18 +299,18 @@ LibertyLibrary::scaleFactor(ScaleFactorType type,
|
|||
// All scale factors are unity for nominal pvt.
|
||||
if (pvt) {
|
||||
ScaleFactors *scale_factors = nullptr;
|
||||
// Cell level scale factors have precidence over library scale factors.
|
||||
// Cell level scale factors have precedence over library scale factors.
|
||||
if (cell)
|
||||
scale_factors = cell->scaleFactors();
|
||||
if (scale_factors == nullptr)
|
||||
scale_factors = scale_factors_;
|
||||
if (scale_factors) {
|
||||
float process_scale = 1.0F + (pvt->process() - nominal_process_)
|
||||
* scale_factors->scale(type, ScaleFactorPvt::process, tr_index);
|
||||
* scale_factors->scale(type, ScaleFactorPvt::process, rf_index);
|
||||
float temp_scale = 1.0F + (pvt->temperature() - nominal_temperature_)
|
||||
* scale_factors->scale(type, ScaleFactorPvt::temp, tr_index);
|
||||
* scale_factors->scale(type, ScaleFactorPvt::temp, rf_index);
|
||||
float volt_scale = 1.0F + (pvt->voltage() - nominal_voltage_)
|
||||
* scale_factors->scale(type, ScaleFactorPvt::volt, tr_index);
|
||||
* scale_factors->scale(type, ScaleFactorPvt::volt, rf_index);
|
||||
float scale = process_scale * temp_scale * volt_scale;
|
||||
return scale;
|
||||
}
|
||||
|
|
@ -322,10 +322,10 @@ void
|
|||
LibertyLibrary::setWireSlewDegradationTable(TableModel *model,
|
||||
RiseFall *rf)
|
||||
{
|
||||
int tr_index = rf->index();
|
||||
if (wire_slew_degradation_tbls_[tr_index])
|
||||
delete wire_slew_degradation_tbls_[tr_index];
|
||||
wire_slew_degradation_tbls_[tr_index] = model;
|
||||
int rf_index = rf->index();
|
||||
if (wire_slew_degradation_tbls_[rf_index])
|
||||
delete wire_slew_degradation_tbls_[rf_index];
|
||||
wire_slew_degradation_tbls_[rf_index] = model;
|
||||
}
|
||||
|
||||
TableModel *
|
||||
|
|
@ -335,36 +335,32 @@ LibertyLibrary::wireSlewDegradationTable(const RiseFall *rf) const
|
|||
}
|
||||
|
||||
float
|
||||
LibertyLibrary::degradeWireSlew(const LibertyCell *cell,
|
||||
const RiseFall *rf,
|
||||
const Pvt *pvt,
|
||||
LibertyLibrary::degradeWireSlew(const RiseFall *rf,
|
||||
float in_slew,
|
||||
float wire_delay) const
|
||||
{
|
||||
const TableModel *model = wireSlewDegradationTable(rf);
|
||||
if (model)
|
||||
return degradeWireSlew(cell, pvt, model, in_slew, wire_delay);
|
||||
return degradeWireSlew(model, in_slew, wire_delay);
|
||||
else
|
||||
return in_slew;
|
||||
}
|
||||
|
||||
float
|
||||
LibertyLibrary::degradeWireSlew(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
const TableModel *model,
|
||||
LibertyLibrary::degradeWireSlew(const TableModel *model,
|
||||
float in_slew,
|
||||
float wire_delay) const
|
||||
{
|
||||
switch (model->order()) {
|
||||
case 0:
|
||||
return model->findValue(this, cell, pvt, 0.0, 0.0, 0.0);
|
||||
return model->findValue(0.0, 0.0, 0.0);
|
||||
case 1: {
|
||||
TableAxisPtr axis1 = model->axis1();
|
||||
TableAxisVariable var1 = axis1->variable();
|
||||
if (var1 == TableAxisVariable::output_pin_transition)
|
||||
return model->findValue(this, cell, pvt, in_slew, 0.0, 0.0);
|
||||
return model->findValue(in_slew, 0.0, 0.0);
|
||||
else if (var1 == TableAxisVariable::connect_delay)
|
||||
return model->findValue(this, cell, pvt, wire_delay, 0.0, 0.0);
|
||||
return model->findValue(wire_delay, 0.0, 0.0);
|
||||
else {
|
||||
criticalError(231, "unsupported slew degradation table axes");
|
||||
return 0.0;
|
||||
|
|
@ -377,10 +373,10 @@ LibertyLibrary::degradeWireSlew(const LibertyCell *cell,
|
|||
TableAxisVariable var2 = axis2->variable();
|
||||
if (var1 == TableAxisVariable::output_pin_transition
|
||||
&& var2 == TableAxisVariable::connect_delay)
|
||||
return model->findValue(this, cell, pvt, in_slew, wire_delay, 0.0);
|
||||
return model->findValue(in_slew, wire_delay, 0.0);
|
||||
else if (var1 == TableAxisVariable::connect_delay
|
||||
&& var2 == TableAxisVariable::output_pin_transition)
|
||||
return model->findValue(this, cell, pvt, wire_delay, in_slew, 0.0);
|
||||
return model->findValue(wire_delay, in_slew, 0.0);
|
||||
else {
|
||||
criticalError(232, "unsupported slew degradation table axes");
|
||||
return 0.0;
|
||||
|
|
@ -2580,13 +2576,12 @@ 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()
|
||||
: MinMax::max();
|
||||
delays.setValue(rf, min_max, delay);
|
||||
delays.setValue(rf, min_max, delayAsFloat(delay));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1670,13 +1670,15 @@ LibertyReader::visitScaleFactor(LibertyAttr *attr)
|
|||
void
|
||||
LibertyReader::beginOpCond(LibertyGroup *group)
|
||||
{
|
||||
const char *name = group->firstName();
|
||||
if (name) {
|
||||
op_cond_ = new OperatingConditions(name);
|
||||
library_->addOperatingConditions(op_cond_);
|
||||
if (library_) {
|
||||
const char *name = group->firstName();
|
||||
if (name) {
|
||||
op_cond_ = new OperatingConditions(name);
|
||||
library_->addOperatingConditions(op_cond_);
|
||||
}
|
||||
else
|
||||
libWarn(68, group, "operating_conditions missing name.");
|
||||
}
|
||||
else
|
||||
libWarn(68, group, "operating_conditions missing name.");
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1863,9 +1865,11 @@ LibertyReader::beginCell(LibertyGroup *group)
|
|||
const char *name = group->firstName();
|
||||
if (name) {
|
||||
debugPrint(debug_, "liberty", 1, "cell %s", name);
|
||||
cell_ = builder_.makeCell(library_, name, filename_);
|
||||
in_bus_ = false;
|
||||
in_bundle_ = false;
|
||||
if (library_) {
|
||||
cell_ = builder_.makeCell(library_, name, filename_);
|
||||
in_bus_ = false;
|
||||
in_bundle_ = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
libWarn(78, group, "cell missing name.");
|
||||
|
|
@ -1935,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);
|
||||
|
|
@ -2200,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:
|
||||
|
|
@ -2219,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];
|
||||
|
|
@ -2230,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];
|
||||
|
|
@ -2241,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_,
|
||||
|
|
@ -2277,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]));
|
||||
}
|
||||
}
|
||||
|
|
@ -2520,7 +2526,7 @@ LibertyReader::endOutputCurrentRiseFall(LibertyGroup *group)
|
|||
slew_axis->findAxisIndex(waveform->slew(), slew_index, slew_exists);
|
||||
cap_axis->findAxisIndex(waveform->cap(), cap_index, cap_exists);
|
||||
if (slew_exists && cap_exists) {
|
||||
size_t index = slew_index * slew_axis->size() + cap_index;
|
||||
size_t index = slew_index * cap_axis->size() + cap_index;
|
||||
current_waveforms[index] = waveform->stealCurrents();
|
||||
(*ref_times)[slew_index] = waveform->referenceTime();
|
||||
}
|
||||
|
|
@ -4196,7 +4202,7 @@ LibertyReader::beginTable(LibertyGroup *group,
|
|||
float scale)
|
||||
{
|
||||
const char *template_name = group->firstName();
|
||||
if (template_name) {
|
||||
if (library_ && template_name) {
|
||||
tbl_template_ = library_->findTableTemplate(template_name, type);
|
||||
if (tbl_template_) {
|
||||
axis_[0] = tbl_template_->axis1();
|
||||
|
|
@ -4385,7 +4391,7 @@ LibertyReader::endLut(LibertyGroup *)
|
|||
void
|
||||
LibertyReader::beginTestCell(LibertyGroup *group)
|
||||
{
|
||||
if (cell_->testCell())
|
||||
if (cell_ && cell_->testCell())
|
||||
libWarn(169, group, "cell %s test_cell redefinition.", cell_->name());
|
||||
else {
|
||||
test_cell_ = new TestCell;
|
||||
|
|
|
|||
|
|
@ -784,7 +784,7 @@ public:
|
|||
TableModel *transition(RiseFall *rf);
|
||||
void setTransition(RiseFall *rf,
|
||||
TableModel *model);
|
||||
void makeTimingModels(LibertyLibrary *library,
|
||||
void makeTimingModels(LibertyCell *cell,
|
||||
LibertyReader *visitor);
|
||||
void setDelaySigma(RiseFall *rf,
|
||||
EarlyLate *early_late,
|
||||
|
|
@ -801,8 +801,9 @@ public:
|
|||
OutputWaveforms *output_current);
|
||||
|
||||
protected:
|
||||
void makeLinearModels(LibertyLibrary *library);
|
||||
void makeTableModels(LibertyReader *reader);
|
||||
void makeLinearModels(LibertyCell *cell);
|
||||
void makeTableModels(LibertyCell *cell,
|
||||
LibertyReader *reader);
|
||||
|
||||
TimingArcAttrsPtr attrs_;
|
||||
const char *related_output_port_name_;
|
||||
|
|
|
|||
|
|
@ -21,16 +21,17 @@
|
|||
|
||||
namespace sta {
|
||||
|
||||
GateLinearModel::GateLinearModel(float intrinsic,
|
||||
GateLinearModel::GateLinearModel(LibertyCell *cell,
|
||||
float intrinsic,
|
||||
float resistance) :
|
||||
GateTimingModel(cell),
|
||||
intrinsic_(intrinsic),
|
||||
resistance_(resistance)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
GateLinearModel::gateDelay(const LibertyCell *,
|
||||
const Pvt *,
|
||||
GateLinearModel::gateDelay(const Pvt *,
|
||||
float,
|
||||
float load_cap,
|
||||
float,
|
||||
|
|
@ -44,15 +45,14 @@ GateLinearModel::gateDelay(const LibertyCell *,
|
|||
}
|
||||
|
||||
string
|
||||
GateLinearModel::reportGateDelay(const LibertyCell *cell,
|
||||
const Pvt *,
|
||||
GateLinearModel::reportGateDelay(const Pvt *,
|
||||
float,
|
||||
float load_cap,
|
||||
float,
|
||||
bool,
|
||||
int digits) const
|
||||
{
|
||||
const LibertyLibrary *library = cell->libertyLibrary();
|
||||
const LibertyLibrary *library = cell_->libertyLibrary();
|
||||
const Units *units = library->units();
|
||||
const Unit *time_unit = units->timeUnit();
|
||||
const Unit *res_unit = units->resistanceUnit();
|
||||
|
|
@ -70,8 +70,7 @@ GateLinearModel::reportGateDelay(const LibertyCell *cell,
|
|||
}
|
||||
|
||||
float
|
||||
GateLinearModel::driveResistance(const LibertyCell *,
|
||||
const Pvt *) const
|
||||
GateLinearModel::driveResistance(const Pvt *) const
|
||||
{
|
||||
return resistance_;
|
||||
}
|
||||
|
|
@ -81,14 +80,15 @@ GateLinearModel::setIsScaled(bool)
|
|||
{
|
||||
}
|
||||
|
||||
CheckLinearModel::CheckLinearModel(float intrinsic) :
|
||||
CheckLinearModel::CheckLinearModel(LibertyCell *cell,
|
||||
float intrinsic) :
|
||||
CheckTimingModel(cell),
|
||||
intrinsic_(intrinsic)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CheckLinearModel::checkDelay(const LibertyCell *,
|
||||
const Pvt *,
|
||||
CheckLinearModel::checkDelay(const Pvt *,
|
||||
float,
|
||||
float,
|
||||
float,
|
||||
|
|
@ -99,8 +99,7 @@ CheckLinearModel::checkDelay(const LibertyCell *,
|
|||
}
|
||||
|
||||
string
|
||||
CheckLinearModel::reportCheckDelay(const LibertyCell *cell,
|
||||
const Pvt *,
|
||||
CheckLinearModel::reportCheckDelay(const Pvt *,
|
||||
float,
|
||||
const char *,
|
||||
float,
|
||||
|
|
@ -108,7 +107,7 @@ CheckLinearModel::reportCheckDelay(const LibertyCell *cell,
|
|||
bool,
|
||||
int digits) const
|
||||
{
|
||||
const LibertyLibrary *library = cell->libertyLibrary();
|
||||
const LibertyLibrary *library = cell_->libertyLibrary();
|
||||
const Units *units = library->units();
|
||||
const Unit *time_unit = units->timeUnit();
|
||||
string result = "Check = ";
|
||||
|
|
|
|||
|
|
@ -34,19 +34,26 @@ using std::make_shared;
|
|||
static void
|
||||
deleteSigmaModels(TableModel *models[EarlyLate::index_count]);
|
||||
static string
|
||||
reportPvt(const LibertyLibrary *library,
|
||||
const Pvt *pvt,
|
||||
reportPvt(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
int digits);
|
||||
static void
|
||||
appendSpaces(string &result,
|
||||
int count);
|
||||
|
||||
GateTableModel::GateTableModel(TableModel *delay_model,
|
||||
TimingModel::TimingModel(LibertyCell *cell) :
|
||||
cell_(cell)
|
||||
{
|
||||
}
|
||||
|
||||
GateTableModel::GateTableModel(LibertyCell *cell,
|
||||
TableModel *delay_model,
|
||||
TableModel *delay_sigma_models[EarlyLate::index_count],
|
||||
TableModel *slew_model,
|
||||
TableModel *slew_sigma_models[EarlyLate::index_count],
|
||||
ReceiverModelPtr receiver_model,
|
||||
OutputWaveforms *output_waveforms) :
|
||||
GateTimingModel(cell),
|
||||
delay_model_(delay_model),
|
||||
slew_model_(slew_model),
|
||||
receiver_model_(receiver_model),
|
||||
|
|
@ -94,8 +101,7 @@ GateTableModel::setIsScaled(bool is_scaled)
|
|||
}
|
||||
|
||||
void
|
||||
GateTableModel::gateDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
GateTableModel::gateDelay(const Pvt *pvt,
|
||||
float in_slew,
|
||||
float load_cap,
|
||||
float related_out_cap,
|
||||
|
|
@ -104,30 +110,23 @@ GateTableModel::gateDelay(const LibertyCell *cell,
|
|||
ArcDelay &gate_delay,
|
||||
Slew &drvr_slew) const
|
||||
{
|
||||
const LibertyLibrary *library = cell->libertyLibrary();
|
||||
float delay = findValue(library, cell, pvt, delay_model_, in_slew,
|
||||
load_cap, related_out_cap);
|
||||
float delay = findValue(pvt, delay_model_, in_slew, load_cap, related_out_cap);
|
||||
float sigma_early = 0.0;
|
||||
float sigma_late = 0.0;
|
||||
if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()])
|
||||
sigma_early = findValue(library, cell, pvt,
|
||||
delay_sigma_models_[EarlyLate::earlyIndex()],
|
||||
sigma_early = findValue(pvt, delay_sigma_models_[EarlyLate::earlyIndex()],
|
||||
in_slew, load_cap, related_out_cap);
|
||||
if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()])
|
||||
sigma_late = findValue(library, cell, pvt,
|
||||
delay_sigma_models_[EarlyLate::lateIndex()],
|
||||
sigma_late = findValue(pvt, delay_sigma_models_[EarlyLate::lateIndex()],
|
||||
in_slew, load_cap, related_out_cap);
|
||||
gate_delay = makeDelay(delay, sigma_early, sigma_late);
|
||||
|
||||
float slew = findValue(library, cell, pvt, slew_model_, in_slew,
|
||||
load_cap, related_out_cap);
|
||||
float slew = findValue(pvt, slew_model_, in_slew, load_cap, related_out_cap);
|
||||
if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()])
|
||||
sigma_early = findValue(library, cell, pvt,
|
||||
slew_sigma_models_[EarlyLate::earlyIndex()],
|
||||
sigma_early = findValue(pvt, slew_sigma_models_[EarlyLate::earlyIndex()],
|
||||
in_slew, load_cap, related_out_cap);
|
||||
if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()])
|
||||
sigma_late = findValue(library, cell, pvt,
|
||||
slew_sigma_models_[EarlyLate::lateIndex()],
|
||||
sigma_late = findValue(pvt, slew_sigma_models_[EarlyLate::lateIndex()],
|
||||
in_slew, load_cap, related_out_cap);
|
||||
// Clip negative slews to zero.
|
||||
if (slew < 0.0)
|
||||
|
|
@ -136,39 +135,36 @@ GateTableModel::gateDelay(const LibertyCell *cell,
|
|||
}
|
||||
|
||||
string
|
||||
GateTableModel::reportGateDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
GateTableModel::reportGateDelay(const Pvt *pvt,
|
||||
float in_slew,
|
||||
float load_cap,
|
||||
float related_out_cap,
|
||||
bool pocv_enabled,
|
||||
int digits) const
|
||||
{
|
||||
const LibertyLibrary *library = cell->libertyLibrary();
|
||||
string result = reportPvt(library, pvt, digits);
|
||||
result += reportTableLookup("Delay", library, cell, pvt, delay_model_, in_slew,
|
||||
string result = reportPvt(cell_, pvt, digits);
|
||||
result += reportTableLookup("Delay", pvt, delay_model_, in_slew,
|
||||
load_cap, related_out_cap, digits);
|
||||
if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()])
|
||||
result += reportTableLookup("Delay sigma(early)", library, cell, pvt,
|
||||
result += reportTableLookup("Delay sigma(early)", pvt,
|
||||
delay_sigma_models_[EarlyLate::earlyIndex()],
|
||||
in_slew, load_cap, related_out_cap, digits);
|
||||
if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()])
|
||||
result += reportTableLookup("Delay sigma(late)", library, cell, pvt,
|
||||
result += reportTableLookup("Delay sigma(late)", pvt,
|
||||
delay_sigma_models_[EarlyLate::lateIndex()],
|
||||
in_slew, load_cap, related_out_cap, digits);
|
||||
result += '\n';
|
||||
result += reportTableLookup("Slew", library, cell, pvt, slew_model_, in_slew,
|
||||
result += reportTableLookup("Slew", pvt, slew_model_, in_slew,
|
||||
load_cap, related_out_cap, digits);
|
||||
if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()])
|
||||
result += reportTableLookup("Slew sigma(early)", library, cell, pvt,
|
||||
result += reportTableLookup("Slew sigma(early)", pvt,
|
||||
slew_sigma_models_[EarlyLate::earlyIndex()],
|
||||
in_slew, load_cap, related_out_cap, digits);
|
||||
if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()])
|
||||
result += reportTableLookup("Slew sigma(late)", library, cell, pvt,
|
||||
result += reportTableLookup("Slew sigma(late)", pvt,
|
||||
slew_sigma_models_[EarlyLate::lateIndex()],
|
||||
in_slew, load_cap, related_out_cap, digits);
|
||||
float drvr_slew = findValue(library, cell, pvt, slew_model_, in_slew,
|
||||
load_cap, related_out_cap);
|
||||
float drvr_slew = findValue(pvt, slew_model_, in_slew, load_cap, related_out_cap);
|
||||
if (drvr_slew < 0.0)
|
||||
result += "Negative slew clipped to 0.0\n";
|
||||
return result;
|
||||
|
|
@ -176,8 +172,6 @@ GateTableModel::reportGateDelay(const LibertyCell *cell,
|
|||
|
||||
string
|
||||
GateTableModel::reportTableLookup(const char *result_name,
|
||||
const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
const TableModel *model,
|
||||
float in_slew,
|
||||
|
|
@ -189,17 +183,16 @@ GateTableModel::reportTableLookup(const char *result_name,
|
|||
float axis_value1, axis_value2, axis_value3;
|
||||
findAxisValues(model, in_slew, load_cap, related_out_cap,
|
||||
axis_value1, axis_value2, axis_value3);
|
||||
return model->reportValue(result_name, library, cell, pvt,
|
||||
axis_value1, nullptr, axis_value2, axis_value3,
|
||||
const LibertyLibrary *library = cell_->libertyLibrary();
|
||||
return model->reportValue(result_name, cell_, pvt, axis_value1, nullptr,
|
||||
axis_value2, axis_value3,
|
||||
library->units()->timeUnit(), digits);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
float
|
||||
GateTableModel::findValue(const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
GateTableModel::findValue(const Pvt *pvt,
|
||||
const TableModel *model,
|
||||
float in_slew,
|
||||
float load_cap,
|
||||
|
|
@ -209,8 +202,7 @@ GateTableModel::findValue(const LibertyLibrary *library,
|
|||
float axis_value1, axis_value2, axis_value3;
|
||||
findAxisValues(model, in_slew, load_cap, related_out_cap,
|
||||
axis_value1, axis_value2, axis_value3);
|
||||
return model->findValue(library, cell, pvt,
|
||||
axis_value1, axis_value2, axis_value3);
|
||||
return model->findValue(cell_, pvt, axis_value1, axis_value2, axis_value3);
|
||||
}
|
||||
else
|
||||
return 0.0;
|
||||
|
|
@ -264,42 +256,36 @@ GateTableModel::findAxisValues(const TableModel *model,
|
|||
// Use slew/Cload for the highest Cload, which approximates output
|
||||
// admittance as the "drive".
|
||||
float
|
||||
GateTableModel::driveResistance(const LibertyCell *cell,
|
||||
const Pvt *pvt) const
|
||||
GateTableModel::driveResistance(const Pvt *pvt) const
|
||||
{
|
||||
float slew, cap;
|
||||
maxCapSlew(cell, 0.0, pvt, slew, cap);
|
||||
maxCapSlew(0.0, pvt, slew, cap);
|
||||
return slew / cap;
|
||||
}
|
||||
|
||||
void
|
||||
GateTableModel::maxCapSlew(const LibertyCell *cell,
|
||||
float in_slew,
|
||||
GateTableModel::maxCapSlew(float in_slew,
|
||||
const Pvt *pvt,
|
||||
float &slew,
|
||||
float &cap) const
|
||||
{
|
||||
const LibertyLibrary *library = cell->libertyLibrary();
|
||||
TableAxisPtr axis1 = slew_model_->axis1();
|
||||
TableAxisPtr axis2 = slew_model_->axis2();
|
||||
TableAxisPtr axis3 = slew_model_->axis3();
|
||||
if (axis1
|
||||
&& axis1->variable() == TableAxisVariable::total_output_net_capacitance) {
|
||||
cap = axis1->axisValue(axis1->size() - 1);
|
||||
slew = findValue(library, cell, pvt, slew_model_,
|
||||
in_slew, cap, 0.0);
|
||||
slew = findValue(pvt, slew_model_, in_slew, cap, 0.0);
|
||||
}
|
||||
else if (axis2
|
||||
&& axis2->variable()==TableAxisVariable::total_output_net_capacitance) {
|
||||
cap = axis2->axisValue(axis2->size() - 1);
|
||||
slew = findValue(library, cell, pvt, slew_model_,
|
||||
in_slew, cap, 0.0);
|
||||
slew = findValue(pvt, slew_model_, in_slew, cap, 0.0);
|
||||
}
|
||||
else if (axis3
|
||||
&& axis3->variable()==TableAxisVariable::total_output_net_capacitance) {
|
||||
cap = axis3->axisValue(axis3->size() - 1);
|
||||
slew = findValue(library, cell, pvt, slew_model_,
|
||||
in_slew, cap, 0.0);
|
||||
slew = findValue(pvt, slew_model_, in_slew, cap, 0.0);
|
||||
}
|
||||
else {
|
||||
// Table not dependent on capacitance.
|
||||
|
|
@ -399,8 +385,10 @@ ReceiverModel::checkAxes(TablePtr table)
|
|||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
CheckTableModel::CheckTableModel(TableModel *model,
|
||||
CheckTableModel::CheckTableModel(LibertyCell *cell,
|
||||
TableModel *model,
|
||||
TableModel *sigma_models[EarlyLate::index_count]) :
|
||||
CheckTimingModel(cell),
|
||||
model_(model)
|
||||
{
|
||||
for (auto el_index : EarlyLate::rangeIndex())
|
||||
|
|
@ -420,8 +408,7 @@ CheckTableModel::setIsScaled(bool is_scaled)
|
|||
}
|
||||
|
||||
void
|
||||
CheckTableModel::checkDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
CheckTableModel::checkDelay(const Pvt *pvt,
|
||||
float from_slew,
|
||||
float to_slew,
|
||||
float related_out_cap,
|
||||
|
|
@ -430,18 +417,14 @@ CheckTableModel::checkDelay(const LibertyCell *cell,
|
|||
ArcDelay &margin) const
|
||||
{
|
||||
if (model_) {
|
||||
const LibertyLibrary *library = cell->libertyLibrary();
|
||||
float mean = findValue(library, cell, pvt, model_,
|
||||
from_slew, to_slew, related_out_cap);
|
||||
float mean = findValue(pvt, model_, from_slew, to_slew, related_out_cap);
|
||||
float sigma_early = 0.0;
|
||||
float sigma_late = 0.0;
|
||||
if (pocv_enabled && sigma_models_[EarlyLate::earlyIndex()])
|
||||
sigma_early = findValue(library, cell, pvt,
|
||||
sigma_models_[EarlyLate::earlyIndex()],
|
||||
sigma_early = findValue(pvt, sigma_models_[EarlyLate::earlyIndex()],
|
||||
from_slew, to_slew, related_out_cap);
|
||||
if (pocv_enabled && sigma_models_[EarlyLate::lateIndex()])
|
||||
sigma_late = findValue(library, cell, pvt,
|
||||
sigma_models_[EarlyLate::lateIndex()],
|
||||
sigma_late = findValue(pvt, sigma_models_[EarlyLate::lateIndex()],
|
||||
from_slew, to_slew, related_out_cap);
|
||||
margin = makeDelay(mean, sigma_early, sigma_late);
|
||||
}
|
||||
|
|
@ -450,9 +433,7 @@ CheckTableModel::checkDelay(const LibertyCell *cell,
|
|||
}
|
||||
|
||||
float
|
||||
CheckTableModel::findValue(const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
CheckTableModel::findValue(const Pvt *pvt,
|
||||
const TableModel *model,
|
||||
float from_slew,
|
||||
float to_slew,
|
||||
|
|
@ -462,16 +443,14 @@ CheckTableModel::findValue(const LibertyLibrary *library,
|
|||
float axis_value1, axis_value2, axis_value3;
|
||||
findAxisValues(from_slew, to_slew, related_out_cap,
|
||||
axis_value1, axis_value2, axis_value3);
|
||||
return model->findValue(library, cell, pvt,
|
||||
axis_value1, axis_value2, axis_value3);
|
||||
return model->findValue(cell_, pvt, axis_value1, axis_value2, axis_value3);
|
||||
}
|
||||
else
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
string
|
||||
CheckTableModel::reportCheckDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
CheckTableModel::reportCheckDelay(const Pvt *pvt,
|
||||
float from_slew,
|
||||
const char *from_slew_annotation,
|
||||
float to_slew,
|
||||
|
|
@ -479,17 +458,16 @@ CheckTableModel::reportCheckDelay(const LibertyCell *cell,
|
|||
bool pocv_enabled,
|
||||
int digits) const
|
||||
{
|
||||
const LibertyLibrary *library = cell->libertyLibrary();
|
||||
string result = reportTableDelay("Check", library, cell, pvt, model_,
|
||||
string result = reportTableDelay("Check", pvt, model_,
|
||||
from_slew, from_slew_annotation, to_slew,
|
||||
related_out_cap, digits);
|
||||
if (pocv_enabled && sigma_models_[EarlyLate::earlyIndex()])
|
||||
result += reportTableDelay("Check sigma early", library, cell, pvt,
|
||||
result += reportTableDelay("Check sigma early", pvt,
|
||||
sigma_models_[EarlyLate::earlyIndex()],
|
||||
from_slew, from_slew_annotation, to_slew,
|
||||
related_out_cap, digits);
|
||||
if (pocv_enabled && sigma_models_[EarlyLate::lateIndex()])
|
||||
result += reportTableDelay("Check sigma late", library, cell, pvt,
|
||||
result += reportTableDelay("Check sigma late", pvt,
|
||||
sigma_models_[EarlyLate::lateIndex()],
|
||||
from_slew, from_slew_annotation, to_slew,
|
||||
related_out_cap, digits);
|
||||
|
|
@ -498,8 +476,6 @@ CheckTableModel::reportCheckDelay(const LibertyCell *cell,
|
|||
|
||||
string
|
||||
CheckTableModel::reportTableDelay(const char *result_name,
|
||||
const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
const TableModel *model,
|
||||
float from_slew,
|
||||
|
|
@ -512,10 +488,11 @@ CheckTableModel::reportTableDelay(const char *result_name,
|
|||
float axis_value1, axis_value2, axis_value3;
|
||||
findAxisValues(from_slew, to_slew, related_out_cap,
|
||||
axis_value1, axis_value2, axis_value3);
|
||||
string result = reportPvt(library, pvt, digits);
|
||||
result += model_->reportValue(result_name, library, cell, pvt,
|
||||
string result = reportPvt(cell_, pvt, digits);
|
||||
result += model_->reportValue(result_name, cell_, pvt,
|
||||
axis_value1, from_slew_annotation, axis_value2,
|
||||
axis_value3, library->units()->timeUnit(), digits);
|
||||
axis_value3,
|
||||
cell_->libertyLibrary()->units()->timeUnit(), digits);
|
||||
return result;
|
||||
}
|
||||
return "";
|
||||
|
|
@ -665,20 +642,26 @@ TableModel::value(size_t axis_index1,
|
|||
}
|
||||
|
||||
float
|
||||
TableModel::findValue(const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
TableModel::findValue(float axis_value1,
|
||||
float axis_value2,
|
||||
float axis_value3) const
|
||||
{
|
||||
return table_->findValue(axis_value1, axis_value2, axis_value3);
|
||||
}
|
||||
|
||||
float
|
||||
TableModel::findValue(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float axis_value1,
|
||||
float axis_value2,
|
||||
float axis_value3) const
|
||||
{
|
||||
return table_->findValue(axis_value1, axis_value2, axis_value3)
|
||||
* scaleFactor(library, cell, pvt);
|
||||
* scaleFactor(cell, pvt);
|
||||
}
|
||||
|
||||
float
|
||||
TableModel::scaleFactor(const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
TableModel::scaleFactor(const LibertyCell *cell,
|
||||
const Pvt *pvt) const
|
||||
{
|
||||
if (is_scaled_)
|
||||
|
|
@ -686,13 +669,12 @@ TableModel::scaleFactor(const LibertyLibrary *library,
|
|||
// nominal pvt.
|
||||
return 1.0F;
|
||||
else
|
||||
return library->scaleFactor(static_cast<ScaleFactorType>(scale_factor_type_),
|
||||
rf_index_, cell, pvt);
|
||||
return cell->libertyLibrary()->scaleFactor(static_cast<ScaleFactorType>(scale_factor_type_),
|
||||
rf_index_, cell, pvt);
|
||||
}
|
||||
|
||||
string
|
||||
TableModel::reportValue(const char *result_name,
|
||||
const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float value1,
|
||||
|
|
@ -702,24 +684,24 @@ TableModel::reportValue(const char *result_name,
|
|||
const Unit *table_unit,
|
||||
int digits) const
|
||||
{
|
||||
string result = table_->reportValue("Table value", library, cell, pvt, value1,
|
||||
string result = table_->reportValue("Table value", cell, pvt, value1,
|
||||
comment1, value2, value3, table_unit, digits);
|
||||
|
||||
result += reportPvtScaleFactor(library, cell, pvt, digits);
|
||||
result += reportPvtScaleFactor(cell, pvt, digits);
|
||||
|
||||
result += result_name;
|
||||
result += " = ";
|
||||
result += table_unit->asString(findValue(library, cell, pvt,
|
||||
value1, value2, value3), digits);
|
||||
result += table_unit->asString(findValue(cell, pvt, value1, value2, value3), digits);
|
||||
result += '\n';
|
||||
return result;
|
||||
}
|
||||
|
||||
static string
|
||||
reportPvt(const LibertyLibrary *library,
|
||||
reportPvt(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
int digits)
|
||||
{
|
||||
const LibertyLibrary *library = cell->libertyLibrary();
|
||||
if (pvt == nullptr)
|
||||
pvt = library->defaultOperatingConditions();
|
||||
if (pvt) {
|
||||
|
|
@ -734,18 +716,17 @@ reportPvt(const LibertyLibrary *library,
|
|||
}
|
||||
|
||||
string
|
||||
TableModel::reportPvtScaleFactor(const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
TableModel::reportPvtScaleFactor(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
int digits) const
|
||||
{
|
||||
if (pvt == nullptr)
|
||||
pvt = library->defaultOperatingConditions();
|
||||
pvt = cell->libertyLibrary()->defaultOperatingConditions();
|
||||
if (pvt) {
|
||||
string result;
|
||||
stringPrint(result, "PVT scale factor = %.*f\n",
|
||||
digits,
|
||||
scaleFactor(library, cell, pvt));
|
||||
scaleFactor(cell, pvt));
|
||||
return result;
|
||||
}
|
||||
return "";
|
||||
|
|
@ -777,7 +758,6 @@ Table0::findValue(float,
|
|||
|
||||
string
|
||||
Table0::reportValue(const char *result_name,
|
||||
const LibertyLibrary *,
|
||||
const LibertyCell *,
|
||||
const Pvt *,
|
||||
float value1,
|
||||
|
|
@ -930,9 +910,8 @@ Table1::findValueClipZero(float axis_value1) const
|
|||
}
|
||||
|
||||
string
|
||||
Table1::reportValue(const char *result_name, const
|
||||
LibertyLibrary *library,
|
||||
const LibertyCell *,
|
||||
Table1::reportValue(const char *result_name,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *,
|
||||
float value1,
|
||||
const char *comment1,
|
||||
|
|
@ -941,7 +920,7 @@ Table1::reportValue(const char *result_name, const
|
|||
const Unit *table_unit,
|
||||
int digits) const
|
||||
{
|
||||
const Units *units = library->units();
|
||||
const Units *units = cell->libertyLibrary()->units();
|
||||
const Unit *unit1 = axis1_->unit(units);
|
||||
string result = "Table is indexed by\n ";
|
||||
result += axis1_->variableString();
|
||||
|
|
@ -1098,8 +1077,7 @@ Table2::findValue(float axis_value1,
|
|||
|
||||
string
|
||||
Table2::reportValue(const char *result_name,
|
||||
const LibertyLibrary *library,
|
||||
const LibertyCell *,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *,
|
||||
float value1,
|
||||
const char *comment1,
|
||||
|
|
@ -1108,7 +1086,7 @@ Table2::reportValue(const char *result_name,
|
|||
const Unit *table_unit,
|
||||
int digits) const
|
||||
{
|
||||
const Units *units = library->units();
|
||||
const Units *units = cell->libertyLibrary()->units();
|
||||
const Unit *unit1 = axis1_->unit(units);
|
||||
const Unit *unit2 = axis2_->unit(units);
|
||||
string result = "------- ";
|
||||
|
|
@ -1289,8 +1267,7 @@ Table3::findValue(float axis_value1,
|
|||
// 0.40 | 0.20 0.30
|
||||
string
|
||||
Table3::reportValue(const char *result_name,
|
||||
const LibertyLibrary *library,
|
||||
const LibertyCell *,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *,
|
||||
float value1,
|
||||
const char *comment1,
|
||||
|
|
@ -1299,7 +1276,7 @@ Table3::reportValue(const char *result_name,
|
|||
const Unit *table_unit,
|
||||
int digits) const
|
||||
{
|
||||
const Units *units = library->units();
|
||||
const Units *units = cell->libertyLibrary()->units();
|
||||
const Unit *unit1 = axis1_->unit(units);
|
||||
const Unit *unit2 = axis2_->unit(units);
|
||||
const Unit *unit3 = axis3_->unit(units);
|
||||
|
|
@ -1662,11 +1639,11 @@ OutputWaveforms::timeCurrent(float slew,
|
|||
{
|
||||
size_t slew_index = slew_axis_->findAxisIndex(slew);
|
||||
size_t cap_index = cap_axis_->findAxisIndex(cap);
|
||||
size_t slew_count = slew_axis_->size();
|
||||
size_t wave_index00 = slew_index * slew_count + cap_index;
|
||||
size_t wave_index01 = slew_index * slew_count + (cap_index + 1);
|
||||
size_t wave_index10 = (slew_index + 1) * slew_count + cap_index;
|
||||
size_t wave_index11 = (slew_index + 1) * slew_count + (cap_index + 1);
|
||||
size_t cap_count = cap_axis_->size();
|
||||
size_t wave_index00 = slew_index * cap_count + cap_index;
|
||||
size_t wave_index01 = slew_index * cap_count + (cap_index + 1);
|
||||
size_t wave_index10 = (slew_index + 1) * cap_count + cap_index;
|
||||
size_t wave_index11 = (slew_index + 1) * cap_count + (cap_index + 1);
|
||||
|
||||
const Table1 *waveform00 = current_waveforms_[wave_index00];
|
||||
const Table1 *waveform01 = current_waveforms_[wave_index01];
|
||||
|
|
@ -1733,11 +1710,11 @@ OutputWaveforms::voltageTime(float slew,
|
|||
{
|
||||
size_t slew_index = slew_axis_->findAxisIndex(slew);
|
||||
size_t cap_index = cap_axis_->findAxisIndex(cap);
|
||||
size_t slew_count = slew_axis_->size();
|
||||
size_t wave_index00 = slew_index * slew_count + cap_index;
|
||||
size_t wave_index01 = slew_index * slew_count + (cap_index + 1);
|
||||
size_t wave_index10 = (slew_index + 1) * slew_count + cap_index;
|
||||
size_t wave_index11 = (slew_index + 1) * slew_count + (cap_index + 1);
|
||||
size_t cap_count = cap_axis_->size();
|
||||
size_t wave_index00 = slew_index * cap_count + cap_index;
|
||||
size_t wave_index01 = slew_index * cap_count + (cap_index + 1);
|
||||
size_t wave_index10 = (slew_index + 1) * cap_count + cap_index;
|
||||
size_t wave_index11 = (slew_index + 1) * cap_count + (cap_index + 1);
|
||||
float cap0 = cap_axis_->axisValue(cap_index);
|
||||
float cap1 = cap_axis_->axisValue(cap_index + 1);
|
||||
|
||||
|
|
@ -1858,11 +1835,11 @@ OutputWaveforms::voltageCurrent(float slew,
|
|||
{
|
||||
size_t slew_index = slew_axis_->findAxisIndex(slew);
|
||||
size_t cap_index = cap_axis_->findAxisIndex(cap);
|
||||
size_t slew_count = slew_axis_->size();
|
||||
size_t wave_index00 = slew_index * slew_count + cap_index;
|
||||
size_t wave_index01 = slew_index * slew_count + (cap_index + 1);
|
||||
size_t wave_index10 = (slew_index + 1) * slew_count + cap_index;
|
||||
size_t wave_index11 = (slew_index + 1) * slew_count + (cap_index + 1);
|
||||
size_t cap_count = cap_axis_->size();
|
||||
size_t wave_index00 = slew_index * cap_count + cap_index;
|
||||
size_t wave_index01 = slew_index * cap_count + (cap_index + 1);
|
||||
size_t wave_index10 = (slew_index + 1) * cap_count + cap_index;
|
||||
size_t wave_index11 = (slew_index + 1) * cap_count + (cap_index + 1);
|
||||
float cap0 = cap_axis_->axisValue(cap_index);
|
||||
float cap1 = cap_axis_->axisValue(cap_index + 1);
|
||||
|
||||
|
|
|
|||
|
|
@ -149,10 +149,8 @@ float
|
|||
TimingArc::driveResistance() const
|
||||
{
|
||||
GateTimingModel *model = dynamic_cast<GateTimingModel*>(model_);
|
||||
if (model) {
|
||||
LibertyCell *cell = set_->libertyCell();
|
||||
return model->driveResistance(cell, nullptr);
|
||||
}
|
||||
if (model)
|
||||
return model->driveResistance(nullptr);
|
||||
else
|
||||
return 0.0;
|
||||
}
|
||||
|
|
@ -162,11 +160,9 @@ TimingArc::intrinsicDelay() const
|
|||
{
|
||||
GateTimingModel *model = dynamic_cast<GateTimingModel*>(model_);
|
||||
if (model) {
|
||||
LibertyCell *cell = set_->libertyCell();
|
||||
ArcDelay arc_delay;
|
||||
Slew slew;
|
||||
model->gateDelay(cell, nullptr, 0.0, 0.0, 0.0, false,
|
||||
arc_delay, slew);
|
||||
model->gateDelay(nullptr, 0.0, 0.0, 0.0, false, arc_delay, slew);
|
||||
return arc_delay;
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
// OpenSTA, Static Timing Analyzer
|
||||
// Copyright (c) 2023, Parallax Software, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "TimingModel.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
GateTimingModel::GateTimingModel(LibertyCell *cell) :
|
||||
TimingModel(cell)
|
||||
{
|
||||
}
|
||||
|
||||
CheckTimingModel::CheckTimingModel(LibertyCell *cell) :
|
||||
TimingModel(cell)
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
@ -176,6 +176,11 @@ TimingRole::destroy()
|
|||
non_seq_setup_ = nullptr;
|
||||
delete non_seq_hold_;
|
||||
non_seq_hold_ = nullptr;
|
||||
delete clock_tree_path_min_;
|
||||
clock_tree_path_min_ = nullptr;
|
||||
delete clock_tree_path_max_;
|
||||
clock_tree_path_max_ = nullptr;
|
||||
|
||||
timing_roles_.clear();
|
||||
}
|
||||
|
||||
|
|
|
|||
545
power/Power.cc
545
power/Power.cc
|
|
@ -17,7 +17,7 @@
|
|||
#include "Power.hh"
|
||||
|
||||
#include <algorithm> // max
|
||||
#include <cmath> // aps
|
||||
#include <cmath> // abs
|
||||
|
||||
#include "Debug.hh"
|
||||
#include "EnumNameMap.hh"
|
||||
|
|
@ -47,6 +47,13 @@
|
|||
#include "Bfs.hh"
|
||||
#include "ClkNetwork.hh"
|
||||
|
||||
#if CUDD
|
||||
#include "cudd.h"
|
||||
#else
|
||||
#define Cudd_Init(ignore1, ignore2, ignore3, ignore4, ignore5) nullptr
|
||||
#define Cudd_Quit(ignore1)
|
||||
#endif
|
||||
|
||||
// Related liberty not supported:
|
||||
// library
|
||||
// default_cell_leakage_power : 0;
|
||||
|
|
@ -71,15 +78,32 @@ isPositiveUnate(const LibertyCell *cell,
|
|||
const LibertyPort *from,
|
||||
const LibertyPort *to);
|
||||
|
||||
static EnumNameMap<PwrActivityOrigin> pwr_activity_origin_map =
|
||||
{{PwrActivityOrigin::global, "global"},
|
||||
{PwrActivityOrigin::input, "input"},
|
||||
{PwrActivityOrigin::user, "user"},
|
||||
{PwrActivityOrigin::vcd, "vcd"},
|
||||
{PwrActivityOrigin::propagated, "propagated"},
|
||||
{PwrActivityOrigin::clock, "clock"},
|
||||
{PwrActivityOrigin::constant, "constant"},
|
||||
{PwrActivityOrigin::defaulted, "defaulted"},
|
||||
{PwrActivityOrigin::unknown, "unknown"}};
|
||||
|
||||
Power::Power(StaState *sta) :
|
||||
StaState(sta),
|
||||
global_activity_{0.0, 0.0, PwrActivityOrigin::unknown},
|
||||
input_activity_{0.1, 0.5, PwrActivityOrigin::input},
|
||||
seq_activity_map_(100, SeqPinHash(network_), SeqPinEqual()),
|
||||
activities_valid_(false)
|
||||
activities_valid_(false),
|
||||
cudd_mgr_(Cudd_Init(0, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0))
|
||||
{
|
||||
}
|
||||
|
||||
Power::~Power()
|
||||
{
|
||||
Cudd_Quit(cudd_mgr_);
|
||||
}
|
||||
|
||||
void
|
||||
Power::setGlobalActivity(float activity,
|
||||
float duty)
|
||||
|
|
@ -111,9 +135,9 @@ Power::setInputPortActivity(const Port *input_port,
|
|||
|
||||
void
|
||||
Power::setUserActivity(const Pin *pin,
|
||||
float activity,
|
||||
float duty,
|
||||
PwrActivityOrigin origin)
|
||||
float activity,
|
||||
float duty,
|
||||
PwrActivityOrigin origin)
|
||||
{
|
||||
user_activity_map_[pin] = {activity, duty, origin};
|
||||
activities_valid_ = false;
|
||||
|
|
@ -135,6 +159,11 @@ void
|
|||
Power::setActivity(const Pin *pin,
|
||||
PwrActivity &activity)
|
||||
{
|
||||
debugPrint(debug_, "power_activity", 3, "set %s %.2e %.2f %s",
|
||||
network_->pathName(pin),
|
||||
activity.activity(),
|
||||
activity.duty(),
|
||||
pwr_activity_origin_map.find(activity.origin()));
|
||||
activity_map_[pin] = activity;
|
||||
}
|
||||
|
||||
|
|
@ -168,7 +197,7 @@ Power::hasSeqActivity(const Instance *reg,
|
|||
return seq_activity_map_.hasKey(SeqPin(reg, output));
|
||||
}
|
||||
|
||||
PwrActivity
|
||||
PwrActivity &
|
||||
Power::seqActivity(const Instance *reg,
|
||||
LibertyPort *output)
|
||||
{
|
||||
|
|
@ -331,7 +360,7 @@ private:
|
|||
bool setActivityCheck(const Pin *pin,
|
||||
PwrActivity &activity);
|
||||
|
||||
static constexpr float change_tolerance_ = .01;
|
||||
static constexpr float change_tolerance_ = .001;
|
||||
InstanceSet visited_regs_;
|
||||
float max_change_;
|
||||
Power *power_;
|
||||
|
|
@ -370,10 +399,6 @@ PropActivityVisitor::visit(Vertex *vertex)
|
|||
bool changed = false;
|
||||
if (power_->hasUserActivity(pin)) {
|
||||
PwrActivity &activity = power_->userActivity(pin);
|
||||
debugPrint(debug_, "power_activity", 3, "set %s %.2e %.2f",
|
||||
vertex->name(network_),
|
||||
activity.activity(),
|
||||
activity.duty());
|
||||
changed = setActivityCheck(pin, activity);
|
||||
}
|
||||
else {
|
||||
|
|
@ -397,12 +422,8 @@ PropActivityVisitor::visit(Vertex *vertex)
|
|||
if (port) {
|
||||
FuncExpr *func = port->function();
|
||||
if (func) {
|
||||
PwrActivity activity = power_->evalActivity(func, inst);
|
||||
PwrActivity activity = power_->evalActivity(func, inst);
|
||||
changed = setActivityCheck(pin, activity);
|
||||
debugPrint(debug_, "power_activity", 3, "set %s %.2e %.2f",
|
||||
vertex->name(network_),
|
||||
activity.activity(),
|
||||
activity.duty());
|
||||
}
|
||||
if (port->isClockGateOut()) {
|
||||
const Pin *enable, *clk, *gclk;
|
||||
|
|
@ -491,6 +512,210 @@ Power::clockGatePins(const Instance *inst,
|
|||
delete pin_iter;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
#if CUDD
|
||||
|
||||
PwrActivity
|
||||
Power::evalActivity(FuncExpr *expr,
|
||||
const Instance *inst)
|
||||
{
|
||||
LibertyPort *func_port = expr->port();
|
||||
if (func_port && func_port->direction()->isInternal())
|
||||
return findSeqActivity(inst, func_port);
|
||||
else {
|
||||
DdNode *bdd = funcBdd(expr);
|
||||
float duty = evalBddDuty(bdd, inst);
|
||||
float activity = evalBddActivity(bdd, inst);
|
||||
|
||||
Cudd_RecursiveDeref(cudd_mgr_, bdd);
|
||||
clearVarMap();
|
||||
return PwrActivity(activity, duty, PwrActivityOrigin::propagated);
|
||||
}
|
||||
}
|
||||
|
||||
// Find duty when from_port is sensitized.
|
||||
float
|
||||
Power::evalDiffDuty(FuncExpr *expr,
|
||||
LibertyPort *from_port,
|
||||
const Instance *inst)
|
||||
{
|
||||
DdNode *bdd = funcBdd(expr);
|
||||
DdNode *var_node = bdd_port_var_map_[from_port];
|
||||
unsigned var_index = Cudd_NodeReadIndex(var_node);
|
||||
DdNode *diff = Cudd_bddBooleanDiff(cudd_mgr_, bdd, var_index);
|
||||
Cudd_Ref(diff);
|
||||
float duty = evalBddDuty(diff, inst);
|
||||
|
||||
Cudd_RecursiveDeref(cudd_mgr_, diff);
|
||||
Cudd_RecursiveDeref(cudd_mgr_, bdd);
|
||||
clearVarMap();
|
||||
return duty;
|
||||
}
|
||||
|
||||
DdNode *
|
||||
Power::funcBdd(const FuncExpr *expr)
|
||||
{
|
||||
DdNode *left = nullptr;
|
||||
DdNode *right = nullptr;
|
||||
DdNode *result = nullptr;
|
||||
switch (expr->op()) {
|
||||
case FuncExpr::op_port: {
|
||||
LibertyPort *port = expr->port();
|
||||
result = ensureNode(port);
|
||||
break;
|
||||
}
|
||||
case FuncExpr::op_not:
|
||||
left = funcBdd(expr->left());
|
||||
if (left)
|
||||
result = Cudd_Not(left);
|
||||
break;
|
||||
case FuncExpr::op_or:
|
||||
left = funcBdd(expr->left());
|
||||
right = funcBdd(expr->right());
|
||||
if (left && right)
|
||||
result = Cudd_bddOr(cudd_mgr_, left, right);
|
||||
else if (left)
|
||||
result = left;
|
||||
else if (right)
|
||||
result = right;
|
||||
break;
|
||||
case FuncExpr::op_and:
|
||||
left = funcBdd(expr->left());
|
||||
right = funcBdd(expr->right());
|
||||
if (left && right)
|
||||
result = Cudd_bddAnd(cudd_mgr_, left, right);
|
||||
else if (left)
|
||||
result = left;
|
||||
else if (right)
|
||||
result = right;
|
||||
break;
|
||||
case FuncExpr::op_xor:
|
||||
left = funcBdd(expr->left());
|
||||
right = funcBdd(expr->right());
|
||||
if (left && right)
|
||||
result = Cudd_bddXor(cudd_mgr_, left, right);
|
||||
else if (left)
|
||||
result = left;
|
||||
else if (right)
|
||||
result = right;
|
||||
break;
|
||||
case FuncExpr::op_one:
|
||||
result = Cudd_ReadOne(cudd_mgr_);
|
||||
break;
|
||||
case FuncExpr::op_zero:
|
||||
result = Cudd_ReadLogicZero(cudd_mgr_);
|
||||
break;
|
||||
default:
|
||||
report_->critical(596, "unknown function operator");
|
||||
}
|
||||
if (result)
|
||||
Cudd_Ref(result);
|
||||
if (left)
|
||||
Cudd_RecursiveDeref(cudd_mgr_, left);
|
||||
if (right)
|
||||
Cudd_RecursiveDeref(cudd_mgr_, right);
|
||||
return result;
|
||||
}
|
||||
|
||||
DdNode *
|
||||
Power::ensureNode(LibertyPort *port)
|
||||
{
|
||||
DdNode *bdd = bdd_port_var_map_.findKey(port);
|
||||
if (bdd == nullptr) {
|
||||
bdd = Cudd_bddNewVar(cudd_mgr_);
|
||||
bdd_port_var_map_[port] = bdd;
|
||||
unsigned var_index = Cudd_NodeReadIndex(bdd);
|
||||
bdd_var_idx_port_map_[var_index] = port;
|
||||
Cudd_Ref(bdd);
|
||||
debugPrint(debug_, "power_activity", 2, "%s var %d", port->name(), var_index);
|
||||
}
|
||||
return bdd;
|
||||
}
|
||||
|
||||
void
|
||||
Power::clearVarMap()
|
||||
{
|
||||
for (auto port_node : bdd_port_var_map_) {
|
||||
DdNode *var_node = port_node.second;
|
||||
Cudd_RecursiveDeref(cudd_mgr_, var_node);
|
||||
}
|
||||
bdd_port_var_map_.clear();
|
||||
bdd_var_idx_port_map_.clear();
|
||||
}
|
||||
|
||||
// As suggested by
|
||||
// https://stackoverflow.com/questions/63326728/cudd-printminterm-accessing-the-individual-minterms-in-the-sum-of-products
|
||||
float
|
||||
Power::evalBddDuty(DdNode *bdd,
|
||||
const Instance *inst)
|
||||
{
|
||||
if (Cudd_IsConstant(bdd)) {
|
||||
if (bdd == Cudd_ReadOne(cudd_mgr_))
|
||||
return 1.0;
|
||||
else if (bdd == Cudd_ReadLogicZero(cudd_mgr_))
|
||||
return 0.0;
|
||||
else
|
||||
criticalError(1100, "unknown cudd constant");
|
||||
}
|
||||
else {
|
||||
float duty0 = evalBddDuty(Cudd_E(bdd), inst);
|
||||
float duty1 = evalBddDuty(Cudd_T(bdd), inst);
|
||||
unsigned int index = Cudd_NodeReadIndex(bdd);
|
||||
int var_index = Cudd_ReadPerm(cudd_mgr_, index);
|
||||
LibertyPort *port = bdd_var_idx_port_map_[var_index];
|
||||
if (port->direction()->isInternal())
|
||||
return findSeqActivity(inst, port).duty();
|
||||
else {
|
||||
const Pin *pin = findLinkPin(inst, port);
|
||||
if (pin) {
|
||||
PwrActivity var_activity = findActivity(pin);
|
||||
float var_duty = var_activity.duty();
|
||||
float duty = duty0 * (1.0 - var_duty) + duty1 * var_duty;
|
||||
if (Cudd_IsComplement(bdd))
|
||||
duty = 1.0 - duty;
|
||||
return duty;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// https://www.brown.edu/Departments/Engineering/Courses/engn2912/Lectures/LP-02-logic-power-est.pdf
|
||||
// F(x0, x1, .. ) is sensitized when F(Xi=1) xor F(Xi=0)
|
||||
// F(Xi=1), F(Xi=0) are the cofactors of F wrt Xi.
|
||||
float
|
||||
Power::evalBddActivity(DdNode *bdd,
|
||||
const Instance *inst)
|
||||
{
|
||||
float activity = 0.0;
|
||||
for (auto port_var : bdd_port_var_map_) {
|
||||
LibertyPort *port = port_var.first;
|
||||
const Pin *pin = findLinkPin(inst, port);
|
||||
if (pin) {
|
||||
PwrActivity var_activity = findActivity(pin);
|
||||
DdNode *var_node = port_var.second;
|
||||
unsigned int var_index = Cudd_NodeReadIndex(var_node);
|
||||
DdNode *diff = Cudd_bddBooleanDiff(cudd_mgr_, bdd, var_index);
|
||||
Cudd_Ref(diff);
|
||||
float diff_duty = evalBddDuty(diff, inst);
|
||||
Cudd_RecursiveDeref(cudd_mgr_, diff);
|
||||
float var_act = var_activity.activity() * diff_duty;
|
||||
activity += var_act;
|
||||
const Clock *clk = findClk(pin);
|
||||
float clk_period = clk ? clk->period() : 1.0;
|
||||
debugPrint(debug_, "power_activity", 3, "var %s %.3e * %.3f = %.3e",
|
||||
port->name(),
|
||||
var_activity.activity() / clk_period,
|
||||
diff_duty,
|
||||
var_act / clk_period);
|
||||
}
|
||||
}
|
||||
return activity;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
PwrActivity
|
||||
Power::evalActivity(FuncExpr *expr,
|
||||
const Instance *inst)
|
||||
|
|
@ -519,8 +744,11 @@ Power::evalActivity(FuncExpr *expr,
|
|||
return findSeqActivity(inst, port);
|
||||
else {
|
||||
Pin *pin = findLinkPin(inst, port);
|
||||
if (pin)
|
||||
return findActivity(pin);
|
||||
if (pin) {
|
||||
PwrActivity activity = findActivity(pin);
|
||||
activity.setOrigin(PwrActivityOrigin::propagated);
|
||||
return activity;
|
||||
}
|
||||
}
|
||||
return PwrActivity(0.0, 0.0, PwrActivityOrigin::constant);
|
||||
}
|
||||
|
|
@ -539,7 +767,8 @@ Power::evalActivity(FuncExpr *expr,
|
|||
float p1 = 1.0 - activity1.duty();
|
||||
float p2 = 1.0 - activity2.duty();
|
||||
return PwrActivity(activity1.activity() * p2 + activity2.activity() * p1,
|
||||
1.0 - p1 * p2,
|
||||
// d1 + d2 - d1 * d2
|
||||
1.0 - p1 * p2,
|
||||
PwrActivityOrigin::propagated);
|
||||
}
|
||||
case FuncExpr::op_and: {
|
||||
|
|
@ -574,6 +803,23 @@ Power::evalActivity(FuncExpr *expr,
|
|||
return PwrActivity();
|
||||
}
|
||||
|
||||
// Eval activity of difference(expr) wrt cofactor port.
|
||||
float
|
||||
Power::evalDiffDuty(FuncExpr *expr,
|
||||
LibertyPort *cofactor_port,
|
||||
const Instance *inst)
|
||||
{
|
||||
// Activity of positive/negative cofactors.
|
||||
PwrActivity pos = evalActivity(expr, inst, cofactor_port, true);
|
||||
PwrActivity neg = evalActivity(expr, inst, cofactor_port, false);
|
||||
// difference = xor(pos, neg).
|
||||
float p1 = pos.duty() * (1.0 - neg.duty());
|
||||
float p2 = neg.duty() * (1.0 - pos.duty());
|
||||
return p1 + p2;
|
||||
}
|
||||
|
||||
#endif // CUDD
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
|
|
@ -684,6 +930,7 @@ Power::seedRegOutputActivities(const Instance *reg,
|
|||
activity.setActivity(1.0);
|
||||
if (invert)
|
||||
activity.setDuty(1.0 - activity.duty());
|
||||
activity.setOrigin(PwrActivityOrigin::propagated);
|
||||
setSeqActivity(reg, output, activity);
|
||||
}
|
||||
}
|
||||
|
|
@ -696,29 +943,9 @@ Power::power(const Instance *inst,
|
|||
const Corner *corner)
|
||||
{
|
||||
PowerResult result;
|
||||
MinMax *mm = MinMax::max();
|
||||
const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(mm);
|
||||
const Clock *inst_clk = findInstClk(inst);
|
||||
InstancePinIterator *pin_iter = network_->pinIterator(inst);
|
||||
while (pin_iter->hasNext()) {
|
||||
const Pin *to_pin = pin_iter->next();
|
||||
const LibertyPort *to_port = network_->libertyPort(to_pin);
|
||||
if (to_port) {
|
||||
float load_cap = to_port->direction()->isAnyOutput()
|
||||
? graph_delay_calc_->loadCap(to_pin, dcalc_ap)
|
||||
: 0.0;
|
||||
PwrActivity activity = findClkedActivity(to_pin, inst_clk);
|
||||
if (to_port->direction()->isAnyOutput()) {
|
||||
findSwitchingPower(cell, to_port, activity, load_cap, corner, result);
|
||||
findOutputInternalPower(to_pin, to_port, inst, cell, activity,
|
||||
load_cap, corner, result);
|
||||
}
|
||||
if (to_port->direction()->isAnyInput())
|
||||
findInputInternalPower(to_pin, to_port, inst, cell, activity,
|
||||
load_cap, corner, result);
|
||||
}
|
||||
}
|
||||
delete pin_iter;
|
||||
findInternalPower(inst, cell, corner, inst_clk, result);
|
||||
findSwitchingPower(inst, cell, corner, inst_clk, result);
|
||||
findLeakagePower(inst, cell, corner, result);
|
||||
return result;
|
||||
}
|
||||
|
|
@ -731,16 +958,47 @@ Power::findInstClk(const Instance *inst)
|
|||
while (pin_iter->hasNext()) {
|
||||
const Pin *pin = pin_iter->next();
|
||||
const Clock *clk = findClk(pin);
|
||||
if (clk)
|
||||
if (clk) {
|
||||
inst_clk = clk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete pin_iter;
|
||||
return inst_clk;
|
||||
}
|
||||
|
||||
void
|
||||
Power::findInternalPower(const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
const Corner *corner,
|
||||
const Clock *inst_clk,
|
||||
// Return values.
|
||||
PowerResult &result)
|
||||
{
|
||||
const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(MinMax::max());
|
||||
InstancePinIterator *pin_iter = network_->pinIterator(inst);
|
||||
while (pin_iter->hasNext()) {
|
||||
const Pin *to_pin = pin_iter->next();
|
||||
LibertyPort *to_port = network_->libertyPort(to_pin);
|
||||
if (to_port) {
|
||||
float load_cap = to_port->direction()->isAnyOutput()
|
||||
? graph_delay_calc_->loadCap(to_pin, dcalc_ap)
|
||||
: 0.0;
|
||||
PwrActivity activity = findClkedActivity(to_pin, inst_clk);
|
||||
if (to_port->direction()->isAnyOutput())
|
||||
findOutputInternalPower(to_port, inst, cell, activity,
|
||||
load_cap, corner, result);
|
||||
if (to_port->direction()->isAnyInput())
|
||||
findInputInternalPower(to_pin, to_port, inst, cell, activity,
|
||||
load_cap, corner, result);
|
||||
}
|
||||
}
|
||||
delete pin_iter;
|
||||
}
|
||||
|
||||
void
|
||||
Power::findInputInternalPower(const Pin *pin,
|
||||
const LibertyPort *port,
|
||||
LibertyPort *port,
|
||||
const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
PwrActivity &activity,
|
||||
|
|
@ -755,16 +1013,14 @@ Power::findInputInternalPower(const Pin *pin,
|
|||
if (corner_cell && corner_port) {
|
||||
const InternalPowerSeq &internal_pwrs = corner_cell->internalPowers(corner_port);
|
||||
if (!internal_pwrs.empty()) {
|
||||
debugPrint(debug_, "power", 2, "internal input %s/%s (%s)",
|
||||
debugPrint(debug_, "power", 2, "internal input %s/%s cap %s",
|
||||
network_->pathName(inst),
|
||||
port->name(),
|
||||
corner_cell->name());
|
||||
units_->capacitanceUnit()->asString(load_cap));
|
||||
debugPrint(debug_, "power", 2, " when act/ns duty energy power");
|
||||
const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(MinMax::max());
|
||||
const Pvt *pvt = dcalc_ap->operatingConditions();
|
||||
Vertex *vertex = graph_->pinLoadVertex(pin);
|
||||
debugPrint(debug_, "power", 2, " cap = %s",
|
||||
units_->capacitanceUnit()->asString(load_cap));
|
||||
debugPrint(debug_, "power", 2, " when act/ns duty energy power");
|
||||
float internal = 0.0;
|
||||
for (InternalPower *pwr : internal_pwrs) {
|
||||
const char *related_pg_pin = pwr->relatedPgPin();
|
||||
|
|
@ -783,13 +1039,13 @@ Power::findInputInternalPower(const Pin *pin,
|
|||
float duty = 1.0; // fallback default
|
||||
FuncExpr *when = pwr->when();
|
||||
if (when) {
|
||||
LibertyPort *out_corner_port = findExprOutPort(when);
|
||||
const LibertyPort *out_corner_port = findExprOutPort(when);
|
||||
if (out_corner_port) {
|
||||
const LibertyPort *out_port = findLinkPort(cell, out_corner_port);
|
||||
LibertyPort *out_port = findLinkPort(cell, out_corner_port);
|
||||
if (out_port) {
|
||||
FuncExpr *func = out_port->function();
|
||||
if (func && func->hasPort(port))
|
||||
duty = evalActivityDifference(func, inst, port).duty();
|
||||
duty = evalDiffDuty(func, port, inst);
|
||||
else
|
||||
duty = evalActivity(when, inst).duty();
|
||||
}
|
||||
|
|
@ -858,26 +1114,8 @@ Power::findExprOutPort(FuncExpr *expr)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// Eval activity of differenc(expr) wrt cofactor port.
|
||||
PwrActivity
|
||||
Power::evalActivityDifference(FuncExpr *expr,
|
||||
const Instance *inst,
|
||||
const LibertyPort *cofactor_port)
|
||||
{
|
||||
// Activity of positive/negative cofactors.
|
||||
PwrActivity pos = evalActivity(expr, inst, cofactor_port, true);
|
||||
PwrActivity neg = evalActivity(expr, inst, cofactor_port, false);
|
||||
// difference = xor(pos, neg).
|
||||
float p1 = pos.duty() * (1.0 - neg.duty());
|
||||
float p2 = neg.duty() * (1.0 - pos.duty());
|
||||
return PwrActivity(pos.activity() * p1 + neg.activity() * p2,
|
||||
p1 + p2,
|
||||
PwrActivityOrigin::propagated);
|
||||
}
|
||||
|
||||
void
|
||||
Power::findOutputInternalPower(const Pin *to_pin,
|
||||
const LibertyPort *to_port,
|
||||
Power::findOutputInternalPower(const LibertyPort *to_port,
|
||||
const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
PwrActivity &to_activity,
|
||||
|
|
@ -886,45 +1124,48 @@ Power::findOutputInternalPower(const Pin *to_pin,
|
|||
// Return values.
|
||||
PowerResult &result)
|
||||
{
|
||||
debugPrint(debug_, "power", 2, "internal output %s/%s (%s)",
|
||||
debugPrint(debug_, "power", 2, "internal output %s/%s cap %s",
|
||||
network_->pathName(inst),
|
||||
to_port->name(),
|
||||
cell->name());
|
||||
units_->capacitanceUnit()->asString(load_cap));
|
||||
const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(MinMax::max());
|
||||
const Pvt *pvt = dcalc_ap->operatingConditions();
|
||||
LibertyCell *corner_cell = cell->cornerCell(dcalc_ap);
|
||||
const LibertyPort *to_corner_port = to_port->cornerPort(dcalc_ap);
|
||||
debugPrint(debug_, "power", 2, " cap = %s",
|
||||
units_->capacitanceUnit()->asString(load_cap));
|
||||
FuncExpr *func = to_port->function();
|
||||
|
||||
map<const char*, float, StringLessIf> pg_duty_sum;
|
||||
for (InternalPower *pwr : corner_cell->internalPowers(to_corner_port)) {
|
||||
float duty = findInputDuty(to_pin, inst, func, pwr);
|
||||
const char *related_pg_pin = pwr->relatedPgPin();
|
||||
// Note related_pg_pin may be null.
|
||||
pg_duty_sum[related_pg_pin] += duty;
|
||||
const LibertyPort *from_corner_port = pwr->relatedPort();
|
||||
if (from_corner_port) {
|
||||
const Pin *from_pin = findLinkPin(inst, from_corner_port);
|
||||
float from_activity = findActivity(from_pin).activity();
|
||||
float duty = findInputDuty(inst, func, pwr);
|
||||
const char *related_pg_pin = pwr->relatedPgPin();
|
||||
// Note related_pg_pin may be null.
|
||||
pg_duty_sum[related_pg_pin] += from_activity * duty;
|
||||
}
|
||||
}
|
||||
|
||||
debugPrint(debug_, "power", 2,
|
||||
" when act/ns duty wgt energy power");
|
||||
float internal = 0.0;
|
||||
for (InternalPower *pwr : corner_cell->internalPowers(to_corner_port)) {
|
||||
FuncExpr *when = pwr->when();
|
||||
const char *related_pg_pin = pwr->relatedPgPin();
|
||||
float duty = findInputDuty(to_pin, inst, func, pwr);
|
||||
float duty = findInputDuty(inst, func, pwr);
|
||||
Vertex *from_vertex = nullptr;
|
||||
bool positive_unate = true;
|
||||
const LibertyPort *from_corner_port = pwr->relatedPort();
|
||||
const Pin *from_pin = nullptr;
|
||||
if (from_corner_port) {
|
||||
positive_unate = isPositiveUnate(corner_cell, from_corner_port, to_corner_port);
|
||||
const Pin *from_pin = findLinkPin(inst, from_corner_port);
|
||||
if (from_pin) {
|
||||
from_pin = findLinkPin(inst, from_corner_port);
|
||||
if (from_pin)
|
||||
from_vertex = graph_->pinLoadVertex(from_pin);
|
||||
}
|
||||
}
|
||||
float energy = 0.0;
|
||||
int rf_count = 0;
|
||||
debugPrint(debug_, "power", 2,
|
||||
" when act/ns duty wgt energy power");
|
||||
for (RiseFall *to_rf : RiseFall::range()) {
|
||||
// Use unateness to find from_rf.
|
||||
RiseFall *from_rf = positive_unate ? to_rf : to_rf->opposite();
|
||||
|
|
@ -943,11 +1184,13 @@ Power::findOutputInternalPower(const Pin *to_pin,
|
|||
float weight = 0.0;
|
||||
if (duty_sum_iter != pg_duty_sum.end()) {
|
||||
float duty_sum = duty_sum_iter->second;
|
||||
if (duty_sum != 0.0)
|
||||
weight = duty / duty_sum;
|
||||
if (duty_sum != 0.0 && from_pin) {
|
||||
float from_activity = findActivity(from_pin).activity();
|
||||
weight = from_activity * duty / duty_sum;
|
||||
}
|
||||
}
|
||||
float port_internal = weight * energy * to_activity.activity();
|
||||
debugPrint(debug_, "power", 2, "%3s -> %-3s %6s %.2f %.2f %.2f %9.2e %9.2e %s",
|
||||
debugPrint(debug_, "power", 2, "%3s -> %-3s %6s %.3f %.3f %.3f %9.2e %9.2e %s",
|
||||
from_corner_port ? from_corner_port->name() : "-" ,
|
||||
to_port->name(),
|
||||
when ? when->asString() : "",
|
||||
|
|
@ -963,33 +1206,21 @@ Power::findOutputInternalPower(const Pin *to_pin,
|
|||
}
|
||||
|
||||
float
|
||||
Power::findInputDuty(const Pin *to_pin,
|
||||
const Instance *inst,
|
||||
FuncExpr *func,
|
||||
InternalPower *pwr)
|
||||
Power::findInputDuty(const Instance *inst,
|
||||
FuncExpr *func,
|
||||
InternalPower *pwr)
|
||||
|
||||
{
|
||||
const LibertyPort *from_corner_port = pwr->relatedPort();
|
||||
if (from_corner_port) {
|
||||
const LibertyPort *from_port = findLinkPort(network_->libertyCell(inst),
|
||||
from_corner_port);
|
||||
LibertyPort *from_port = findLinkPort(network_->libertyCell(inst),
|
||||
from_corner_port);
|
||||
const Pin *from_pin = network_->findPin(inst, from_port);
|
||||
if (from_pin) {
|
||||
FuncExpr *when = pwr->when();
|
||||
Vertex *from_vertex = graph_->pinLoadVertex(from_pin);
|
||||
if (func && func->hasPort(from_port)) {
|
||||
float from_activity = findActivity(from_pin).activity();
|
||||
float to_activity = findActivity(to_pin).activity();
|
||||
float duty1 = evalActivityDifference(func, inst, from_port).duty();
|
||||
float duty = 0.0;
|
||||
if (to_activity != 0.0F) {
|
||||
duty = from_activity * duty1 / to_activity;
|
||||
// Activities can get very small from multiplying probabilities
|
||||
// through deep chains of logic. Dividing by very close to zero values
|
||||
// can result in NaN/Inf depending on numerator.
|
||||
if (!isnormal(duty))
|
||||
duty = 0.0;
|
||||
}
|
||||
float duty = evalDiffDuty(func, from_port, inst);
|
||||
return duty;
|
||||
}
|
||||
else if (when)
|
||||
|
|
@ -1036,6 +1267,44 @@ isPositiveUnate(const LibertyCell *cell,
|
|||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
Power::findSwitchingPower(const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
const Corner *corner,
|
||||
const Clock *inst_clk,
|
||||
// Return values.
|
||||
PowerResult &result)
|
||||
{
|
||||
const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(MinMax::max());
|
||||
LibertyCell *corner_cell = cell->cornerCell(dcalc_ap);
|
||||
InstancePinIterator *pin_iter = network_->pinIterator(inst);
|
||||
while (pin_iter->hasNext()) {
|
||||
const Pin *to_pin = pin_iter->next();
|
||||
const LibertyPort *to_port = network_->libertyPort(to_pin);
|
||||
if (to_port) {
|
||||
float load_cap = to_port->direction()->isAnyOutput()
|
||||
? graph_delay_calc_->loadCap(to_pin, dcalc_ap)
|
||||
: 0.0;
|
||||
PwrActivity activity = findClkedActivity(to_pin, inst_clk);
|
||||
if (to_port->direction()->isAnyOutput()) {
|
||||
float volt = portVoltage(corner_cell, to_port, dcalc_ap);
|
||||
float switching = .5 * load_cap * volt * volt * activity.activity();
|
||||
debugPrint(debug_, "power", 2, "switching %s/%s activity = %.2e volt = %.2f %.3e",
|
||||
cell->name(),
|
||||
to_port->name(),
|
||||
activity.activity(),
|
||||
volt,
|
||||
switching);
|
||||
result.switching() += switching;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete pin_iter;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void
|
||||
Power::findLeakagePower(const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
|
|
@ -1097,29 +1366,6 @@ Power::findLeakagePower(const Instance *inst,
|
|||
result.leakage() += leakage;
|
||||
}
|
||||
|
||||
void
|
||||
Power::findSwitchingPower(LibertyCell *cell,
|
||||
const LibertyPort *to_port,
|
||||
PwrActivity &activity,
|
||||
float load_cap,
|
||||
const Corner *corner,
|
||||
// Return values.
|
||||
PowerResult &result)
|
||||
{
|
||||
MinMax *mm = MinMax::max();
|
||||
const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(mm);
|
||||
LibertyCell *corner_cell = cell->cornerCell(dcalc_ap);
|
||||
float volt = portVoltage(corner_cell, to_port, dcalc_ap);
|
||||
float switching = .5 * load_cap * volt * volt * activity.activity();
|
||||
debugPrint(debug_, "power", 2, "switching %s/%s activity = %.2e volt = %.2f %.3e",
|
||||
cell->name(),
|
||||
to_port->name(),
|
||||
activity.activity(),
|
||||
volt,
|
||||
switching);
|
||||
result.switching() += switching;
|
||||
}
|
||||
|
||||
PwrActivity
|
||||
Power::findClkedActivity(const Pin *pin)
|
||||
{
|
||||
|
|
@ -1159,7 +1405,9 @@ Power::findActivity(const Pin *pin)
|
|||
if (activity.origin() != PwrActivityOrigin::unknown)
|
||||
return activity;
|
||||
}
|
||||
return PwrActivity(2.0, 0.5, PwrActivityOrigin::clock);
|
||||
const Clock *clk = findClk(pin);
|
||||
float duty = clockDuty(clk);
|
||||
return PwrActivity(2.0, duty, PwrActivityOrigin::clock);
|
||||
}
|
||||
else if (global_activity_.isSet())
|
||||
return global_activity_;
|
||||
|
|
@ -1171,6 +1419,25 @@ Power::findActivity(const Pin *pin)
|
|||
return PwrActivity(0.0, 0.0, PwrActivityOrigin::unknown);
|
||||
}
|
||||
|
||||
float
|
||||
Power::clockDuty(const Clock *clk)
|
||||
{
|
||||
if (clk->isGenerated()) {
|
||||
const Clock *master = clk->masterClk();
|
||||
if (master == nullptr)
|
||||
return 0.5; // punt
|
||||
else
|
||||
return clockDuty(master);
|
||||
}
|
||||
else {
|
||||
const FloatSeq *waveform = clk->waveform();
|
||||
float rise_time = (*waveform)[0];
|
||||
float fall_time = (*waveform)[1];
|
||||
float duty = (fall_time - rise_time) / clk->period();
|
||||
return duty;
|
||||
}
|
||||
}
|
||||
|
||||
PwrActivity
|
||||
Power::findSeqActivity(const Instance *inst,
|
||||
LibertyPort *port)
|
||||
|
|
@ -1178,11 +1445,11 @@ Power::findSeqActivity(const Instance *inst,
|
|||
if (global_activity_.isSet())
|
||||
return global_activity_;
|
||||
else if (hasSeqActivity(inst, port)) {
|
||||
PwrActivity activity = seqActivity(inst, port);
|
||||
PwrActivity &activity = seqActivity(inst, port);
|
||||
if (activity.origin() != PwrActivityOrigin::unknown)
|
||||
return activity;
|
||||
}
|
||||
return input_activity_;
|
||||
return PwrActivity(0.0, 0.0, PwrActivityOrigin::unknown);
|
||||
}
|
||||
|
||||
float
|
||||
|
|
@ -1272,16 +1539,6 @@ PowerResult::incr(PowerResult &result)
|
|||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
static EnumNameMap<PwrActivityOrigin> pwr_activity_origin_map =
|
||||
{{PwrActivityOrigin::global, "global"},
|
||||
{PwrActivityOrigin::input, "input"},
|
||||
{PwrActivityOrigin::user, "user"},
|
||||
{PwrActivityOrigin::propagated, "propagated"},
|
||||
{PwrActivityOrigin::clock, "clock"},
|
||||
{PwrActivityOrigin::constant, "constant"},
|
||||
{PwrActivityOrigin::defaulted, "defaulted"},
|
||||
{PwrActivityOrigin::unknown, "unknown"}};
|
||||
|
||||
PwrActivity::PwrActivity(float activity,
|
||||
float duty,
|
||||
PwrActivityOrigin origin) :
|
||||
|
|
@ -1311,6 +1568,12 @@ PwrActivity::setDuty(float duty)
|
|||
duty_ = duty;
|
||||
}
|
||||
|
||||
void
|
||||
PwrActivity::setOrigin(PwrActivityOrigin origin)
|
||||
{
|
||||
origin_ = origin;
|
||||
}
|
||||
|
||||
void
|
||||
PwrActivity::set(float activity,
|
||||
float duty,
|
||||
|
|
|
|||
|
|
@ -18,12 +18,16 @@
|
|||
|
||||
#include <utility>
|
||||
|
||||
#include "StaConfig.hh" // CUDD
|
||||
#include "UnorderedMap.hh"
|
||||
#include "Network.hh"
|
||||
#include "SdcClass.hh"
|
||||
#include "PowerClass.hh"
|
||||
#include "StaState.hh"
|
||||
|
||||
struct DdNode;
|
||||
struct DdManager;
|
||||
|
||||
namespace sta {
|
||||
|
||||
class Sta;
|
||||
|
|
@ -34,6 +38,8 @@ class BfsFwdIterator;
|
|||
class Vertex;
|
||||
|
||||
typedef std::pair<const Instance*, LibertyPort*> SeqPin;
|
||||
typedef Map<LibertyPort*, DdNode*> BddPortVarMap;
|
||||
typedef Map<unsigned, LibertyPort*> BddVarIdxPortMap;
|
||||
|
||||
class SeqPinHash
|
||||
{
|
||||
|
|
@ -62,6 +68,7 @@ class Power : public StaState
|
|||
{
|
||||
public:
|
||||
Power(StaState *sta);
|
||||
~Power();
|
||||
void power(const Corner *corner,
|
||||
// Return values.
|
||||
PowerResult &total,
|
||||
|
|
@ -100,8 +107,8 @@ protected:
|
|||
PwrActivity &activity);
|
||||
bool hasSeqActivity(const Instance *reg,
|
||||
LibertyPort *output);
|
||||
PwrActivity seqActivity(const Instance *reg,
|
||||
LibertyPort *output);
|
||||
PwrActivity &seqActivity(const Instance *reg,
|
||||
LibertyPort *output);
|
||||
bool hasActivity(const Pin *pin);
|
||||
void setActivity(const Pin *pin,
|
||||
PwrActivity &activity);
|
||||
|
|
@ -109,8 +116,14 @@ protected:
|
|||
PowerResult power(const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
const Corner *corner);
|
||||
void findInternalPower(const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
const Corner *corner,
|
||||
const Clock *inst_clk,
|
||||
// Return values.
|
||||
PowerResult &result);
|
||||
void findInputInternalPower(const Pin *to_pin,
|
||||
const LibertyPort *to_port,
|
||||
LibertyPort *to_port,
|
||||
const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
PwrActivity &to_activity,
|
||||
|
|
@ -118,8 +131,7 @@ protected:
|
|||
const Corner *corner,
|
||||
// Return values.
|
||||
PowerResult &result);
|
||||
void findOutputInternalPower(const Pin *to_pin,
|
||||
const LibertyPort *to_port,
|
||||
void findOutputInternalPower(const LibertyPort *to_port,
|
||||
const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
PwrActivity &to_activity,
|
||||
|
|
@ -132,18 +144,18 @@ protected:
|
|||
const Corner *corner,
|
||||
// Return values.
|
||||
PowerResult &result);
|
||||
void findSwitchingPower(LibertyCell *cell,
|
||||
const LibertyPort *to_port,
|
||||
PwrActivity &activity,
|
||||
float load_cap,
|
||||
const Corner *corner,
|
||||
// Return values.
|
||||
PowerResult &result);
|
||||
void findSwitchingPower(const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
const Corner *corner,
|
||||
const Clock *inst_clk,
|
||||
// Return values.
|
||||
PowerResult &result);
|
||||
float getSlew(Vertex *vertex,
|
||||
const RiseFall *rf,
|
||||
const Corner *corner);
|
||||
const Clock *findInstClk(const Instance *inst);
|
||||
const Clock *findClk(const Pin *to_pin);
|
||||
float clockDuty(const Clock *clk);
|
||||
PwrActivity findClkedActivity(const Pin *pin,
|
||||
const Clock *inst_clk);
|
||||
PwrActivity findActivity(const Pin *pin);
|
||||
|
|
@ -169,13 +181,12 @@ protected:
|
|||
const LibertyPort *cofactor_port,
|
||||
bool cofactor_positive);
|
||||
LibertyPort *findExprOutPort(FuncExpr *expr);
|
||||
float findInputDuty(const Pin *to_pin,
|
||||
const Instance *inst,
|
||||
float findInputDuty(const Instance *inst,
|
||||
FuncExpr *func,
|
||||
InternalPower *pwr);
|
||||
PwrActivity evalActivityDifference(FuncExpr *expr,
|
||||
const Instance *inst,
|
||||
const LibertyPort *cofactor_port);
|
||||
float evalDiffDuty(FuncExpr *expr,
|
||||
LibertyPort *from_port,
|
||||
const Instance *inst);
|
||||
LibertyPort *findLinkPort(const LibertyCell *cell,
|
||||
const LibertyPort *corner_port);
|
||||
Pin *findLinkPin(const Instance *inst,
|
||||
|
|
@ -186,6 +197,14 @@ protected:
|
|||
const Pin *&clk,
|
||||
const Pin *&gclk) const;
|
||||
|
||||
DdNode *funcBdd(const FuncExpr *expr);
|
||||
DdNode *ensureNode(LibertyPort *port);
|
||||
void clearVarMap();
|
||||
float evalBddActivity(DdNode *bdd,
|
||||
const Instance *inst);
|
||||
float evalBddDuty(DdNode *bdd,
|
||||
const Instance *inst);
|
||||
|
||||
private:
|
||||
// Port/pin activities set by set_pin_activity.
|
||||
// set_pin_activity -global
|
||||
|
|
@ -198,6 +217,11 @@ private:
|
|||
PwrActivityMap activity_map_;
|
||||
PwrSeqActivityMap seq_activity_map_;
|
||||
bool activities_valid_;
|
||||
|
||||
DdManager *cudd_mgr_;
|
||||
BddPortVarMap bdd_port_var_map_;
|
||||
BddVarIdxPortMap bdd_var_idx_port_map_;
|
||||
|
||||
static constexpr int max_activity_passes_ = 100;
|
||||
|
||||
friend class PropActivityVisitor;
|
||||
|
|
|
|||
|
|
@ -180,6 +180,7 @@ ReadVcdActivities::setVarActivity(const char *pin_name,
|
|||
{
|
||||
const Pin *pin = sdc_network_->findPin(pin_name);
|
||||
if (pin) {
|
||||
debugPrint(debug_, "read_vcd_activities", 3, "%s values", pin_name);
|
||||
double transition_count, activity, duty;
|
||||
findVarActivity(var_values, value_bit,
|
||||
transition_count, activity, duty);
|
||||
|
|
@ -191,11 +192,8 @@ ReadVcdActivities::setVarActivity(const char *pin_name,
|
|||
duty);
|
||||
if (sdc_->isLeafPinClock(pin))
|
||||
checkClkPeriod(pin, transition_count);
|
||||
else {
|
||||
power_->setUserActivity(pin, activity, duty,
|
||||
PwrActivityOrigin::user);
|
||||
annotated_pins_.insert(pin);
|
||||
}
|
||||
power_->setUserActivity(pin, activity, duty, PwrActivityOrigin::vcd);
|
||||
annotated_pins_.insert(pin);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -208,16 +206,13 @@ ReadVcdActivities::findVarActivity(const VcdValues &var_values,
|
|||
double &duty)
|
||||
{
|
||||
transition_count = 0.0;
|
||||
char prev_value = var_values[0].value();
|
||||
char prev_value = var_values[0].value(value_bit);
|
||||
VcdTime prev_time = var_values[0].time();
|
||||
VcdTime high_time = 0;
|
||||
for (const VcdValue &var_value : var_values) {
|
||||
VcdTime time = var_value.time();
|
||||
char value = var_value.value();
|
||||
if (value == '\0') {
|
||||
uint64_t bus_value = var_value.busValue();
|
||||
value = ((bus_value >> value_bit) & 0x1) ? '1' : '0';
|
||||
}
|
||||
char value = var_value.value(value_bit);
|
||||
debugPrint(debug_, "read_vcd_activities", 3, " %llu %c", time, value);
|
||||
if (prev_value == '1')
|
||||
high_time += time - prev_time;
|
||||
if (value != prev_value)
|
||||
|
|
|
|||
|
|
@ -201,4 +201,13 @@ VcdValue::VcdValue(VcdTime time,
|
|||
{
|
||||
}
|
||||
|
||||
char
|
||||
VcdValue::value(int value_bit) const
|
||||
{
|
||||
if (value_ == '\0')
|
||||
return ((bus_value_ >> value_bit) & 0x1) ? '1' : '0';
|
||||
else
|
||||
return value_;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,6 +146,7 @@ public:
|
|||
VcdTime time() const { return time_; }
|
||||
char value() const { return value_; }
|
||||
uint64_t busValue() const { return bus_value_; }
|
||||
char value(int value_bit) const;
|
||||
|
||||
private:
|
||||
VcdTime time_;
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ VcdReader::parseVarValues()
|
|||
string token = getToken();
|
||||
while (!token.empty()) {
|
||||
char char0 = toupper(token[0]);
|
||||
if (char0 == '#') {
|
||||
if (char0 == '#' && token.size() > 1) {
|
||||
prev_time_ = time_;
|
||||
time_ = stoll(token.substr(1));
|
||||
if (time_ > prev_time_)
|
||||
|
|
|
|||
|
|
@ -118,8 +118,8 @@ void
|
|||
Clock::makeClkEdges()
|
||||
{
|
||||
clk_edges_ = new ClockEdge*[RiseFall::index_count];
|
||||
for (auto tr : RiseFall::range()) {
|
||||
clk_edges_[tr->index()] = new ClockEdge(this, tr);
|
||||
for (auto rf : RiseFall::range()) {
|
||||
clk_edges_[rf->index()] = new ClockEdge(this, rf);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()];
|
||||
|
|
|
|||
|
|
@ -143,17 +143,19 @@ BfsIterator::visit(Level to_level,
|
|||
&& levelLessOrEqual(first_level_, to_level)) {
|
||||
VertexSeq &level_vertices = queue_[first_level_];
|
||||
incrLevel(first_level_);
|
||||
if (!level_vertices.empty()) {
|
||||
for (auto vertex : level_vertices) {
|
||||
if (vertex) {
|
||||
vertex->setBfsInQueue(bfs_index_, false);
|
||||
visitor->visit(vertex);
|
||||
visit_count++;
|
||||
}
|
||||
// Note that ArrivalVisitor::enqueueRefPinInputDelays may enqueue
|
||||
// vertices at this level so range iteration fails if the vector grows.
|
||||
while (!level_vertices.empty()) {
|
||||
Vertex *vertex = level_vertices.back();
|
||||
level_vertices.pop_back();
|
||||
if (vertex) {
|
||||
vertex->setBfsInQueue(bfs_index_, false);
|
||||
visitor->visit(vertex);
|
||||
visit_count++;
|
||||
}
|
||||
level_vertices.clear();
|
||||
visitor->levelFinished();
|
||||
}
|
||||
level_vertices.clear();
|
||||
visitor->levelFinished();
|
||||
}
|
||||
return visit_count;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
#include "PortDirection.hh"
|
||||
#include "Corner.hh"
|
||||
#include "DcalcAnalysisPt.hh"
|
||||
#include "dcalc/GraphDelayCalc1.hh"
|
||||
#include "GraphDelayCalc.hh"
|
||||
#include "Sdc.hh"
|
||||
#include "StaState.hh"
|
||||
#include "Graph.hh"
|
||||
|
|
@ -528,19 +528,19 @@ MakeTimingModel::findClkInsertionDelays()
|
|||
size_t clk_count = clks->size();
|
||||
if (clk_count == 1) {
|
||||
for (const Clock *clk : *clks) {
|
||||
TimingArcAttrsPtr attrs = nullptr;
|
||||
ClkDelays delays;
|
||||
sta_->findClkDelays(clk, delays);
|
||||
for (const MinMax *min_max : MinMax::range()) {
|
||||
TimingArcAttrsPtr attrs = nullptr;
|
||||
for (const RiseFall *clk_rf : RiseFall::range()) {
|
||||
int clk_rf_index = clk_rf->index();
|
||||
float delay = min_max->initValue();
|
||||
for (const int end_rf_index : RiseFall::rangeIndex()) {
|
||||
float delay1;
|
||||
Delay delay1;
|
||||
bool exists;
|
||||
delays[clk_rf_index][end_rf_index].value(min_max, delay1, exists);
|
||||
if (exists)
|
||||
delay = min_max->minMax(delay, delay1);
|
||||
delay = min_max->minMax(delay, delayAsFloat(delay1));
|
||||
}
|
||||
TimingModel *model = makeGateModelScalar(delay, clk_rf);
|
||||
if (attrs == nullptr)
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -60,15 +60,14 @@ Sim::Sim(StaState *sta) :
|
|||
invalid_load_pins_(network_),
|
||||
instances_with_const_pins_(network_),
|
||||
instances_to_annotate_(network_),
|
||||
// cacheSize = 2^15
|
||||
cudd_manager_(Cudd_Init(0, 0, CUDD_UNIQUE_SLOTS, 32768, 0))
|
||||
cudd_mgr_(Cudd_Init(0, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0))
|
||||
{
|
||||
}
|
||||
|
||||
Sim::~Sim()
|
||||
{
|
||||
delete observer_;
|
||||
Cudd_Quit(cudd_manager_);
|
||||
Cudd_Quit(cudd_mgr_);
|
||||
}
|
||||
|
||||
#if CUDD
|
||||
|
|
@ -88,11 +87,11 @@ Sim::functionSense(const FuncExpr *expr,
|
|||
LibertyPort *input_port = network_->libertyPort(input_pin);
|
||||
DdNode *input_node = ensureNode(input_port);
|
||||
unsigned int input_index = Cudd_NodeReadIndex(input_node);
|
||||
increasing = (Cudd_Increasing(cudd_manager_, bdd, input_index)
|
||||
== Cudd_ReadOne(cudd_manager_));
|
||||
decreasing = (Cudd_Decreasing(cudd_manager_, bdd, input_index)
|
||||
== Cudd_ReadOne(cudd_manager_));
|
||||
Cudd_RecursiveDeref(cudd_manager_, bdd);
|
||||
increasing = (Cudd_Increasing(cudd_mgr_, bdd, input_index)
|
||||
== Cudd_ReadOne(cudd_mgr_));
|
||||
decreasing = (Cudd_Decreasing(cudd_mgr_, bdd, input_index)
|
||||
== Cudd_ReadOne(cudd_mgr_));
|
||||
Cudd_RecursiveDeref(cudd_mgr_, bdd);
|
||||
clearSymtab();
|
||||
}
|
||||
TimingSense sense;
|
||||
|
|
@ -113,7 +112,7 @@ Sim::clearSymtab() const
|
|||
{
|
||||
for (auto name_node : symtab_) {
|
||||
DdNode *sym_node = name_node.second;
|
||||
Cudd_RecursiveDeref(cudd_manager_, sym_node);
|
||||
Cudd_RecursiveDeref(cudd_mgr_, sym_node);
|
||||
}
|
||||
symtab_.clear();
|
||||
}
|
||||
|
|
@ -125,12 +124,12 @@ Sim::evalExpr(const FuncExpr *expr,
|
|||
UniqueLock lock(cudd_lock_);
|
||||
DdNode *bdd = funcBdd(expr, inst);
|
||||
LogicValue value = LogicValue::unknown;
|
||||
if (bdd == Cudd_ReadLogicZero(cudd_manager_))
|
||||
if (bdd == Cudd_ReadLogicZero(cudd_mgr_))
|
||||
value = LogicValue::zero;
|
||||
else if (bdd == Cudd_ReadOne(cudd_manager_))
|
||||
else if (bdd == Cudd_ReadOne(cudd_mgr_))
|
||||
value = LogicValue::one;
|
||||
if (bdd) {
|
||||
Cudd_RecursiveDeref(cudd_manager_, bdd);
|
||||
Cudd_RecursiveDeref(cudd_mgr_, bdd);
|
||||
clearSymtab();
|
||||
}
|
||||
return value;
|
||||
|
|
@ -153,10 +152,10 @@ Sim::funcBdd(const FuncExpr *expr,
|
|||
LogicValue value = logicValue(pin);
|
||||
switch (value) {
|
||||
case LogicValue::zero:
|
||||
result = Cudd_ReadLogicZero(cudd_manager_);
|
||||
result = Cudd_ReadLogicZero(cudd_mgr_);
|
||||
break;
|
||||
case LogicValue::one:
|
||||
result = Cudd_ReadOne(cudd_manager_);
|
||||
result = Cudd_ReadOne(cudd_mgr_);
|
||||
break;
|
||||
default:
|
||||
result = ensureNode(port);
|
||||
|
|
@ -174,7 +173,7 @@ Sim::funcBdd(const FuncExpr *expr,
|
|||
left = funcBdd(expr->left(), inst);
|
||||
right = funcBdd(expr->right(), inst);
|
||||
if (left && right)
|
||||
result = Cudd_bddOr(cudd_manager_, left, right);
|
||||
result = Cudd_bddOr(cudd_mgr_, left, right);
|
||||
else if (left)
|
||||
result = left;
|
||||
else if (right)
|
||||
|
|
@ -184,7 +183,7 @@ Sim::funcBdd(const FuncExpr *expr,
|
|||
left = funcBdd(expr->left(), inst);
|
||||
right = funcBdd(expr->right(), inst);
|
||||
if (left && right)
|
||||
result = Cudd_bddAnd(cudd_manager_, left, right);
|
||||
result = Cudd_bddAnd(cudd_mgr_, left, right);
|
||||
else if (left)
|
||||
result = left;
|
||||
else if (right)
|
||||
|
|
@ -194,17 +193,17 @@ Sim::funcBdd(const FuncExpr *expr,
|
|||
left = funcBdd(expr->left(), inst);
|
||||
right = funcBdd(expr->right(), inst);
|
||||
if (left && right)
|
||||
result = Cudd_bddXor(cudd_manager_, left, right);
|
||||
result = Cudd_bddXor(cudd_mgr_, left, right);
|
||||
else if (left)
|
||||
result = left;
|
||||
else if (right)
|
||||
result = right;
|
||||
break;
|
||||
case FuncExpr::op_one:
|
||||
result = Cudd_ReadOne(cudd_manager_);
|
||||
result = Cudd_ReadOne(cudd_mgr_);
|
||||
break;
|
||||
case FuncExpr::op_zero:
|
||||
result = Cudd_ReadLogicZero(cudd_manager_);
|
||||
result = Cudd_ReadLogicZero(cudd_mgr_);
|
||||
break;
|
||||
default:
|
||||
report_->critical(596, "unknown function operator");
|
||||
|
|
@ -212,9 +211,9 @@ Sim::funcBdd(const FuncExpr *expr,
|
|||
if (result)
|
||||
Cudd_Ref(result);
|
||||
if (left)
|
||||
Cudd_RecursiveDeref(cudd_manager_, left);
|
||||
Cudd_RecursiveDeref(cudd_mgr_, left);
|
||||
if (right)
|
||||
Cudd_RecursiveDeref(cudd_manager_, right);
|
||||
Cudd_RecursiveDeref(cudd_mgr_, right);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -224,7 +223,7 @@ Sim::ensureNode(LibertyPort *port) const
|
|||
const char *port_name = port->name();
|
||||
DdNode *node = symtab_.findKey(port_name);
|
||||
if (node == nullptr) {
|
||||
node = Cudd_bddNewVar(cudd_manager_);
|
||||
node = Cudd_bddNewVar(cudd_mgr_);
|
||||
symtab_[port_name] = node;
|
||||
Cudd_Ref(node);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,16 +129,14 @@ protected:
|
|||
InstanceSet instances_with_const_pins_;
|
||||
InstanceSet instances_to_annotate_;
|
||||
|
||||
#ifdef CUDD
|
||||
DdNode *funcBdd(const FuncExpr *expr,
|
||||
const Instance *inst) const;
|
||||
DdNode *ensureNode(LibertyPort *port) const;
|
||||
void clearSymtab() const;
|
||||
|
||||
DdManager *cudd_manager_;
|
||||
DdManager *cudd_mgr_;
|
||||
mutable BddSymbolTable symtab_;
|
||||
mutable std::mutex cudd_lock_;
|
||||
#endif // CUDD
|
||||
};
|
||||
|
||||
// Abstract base class for Sim value change observer.
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
#include "parasitics/ReportParasiticAnnotation.hh"
|
||||
#include "DelayCalc.hh"
|
||||
#include "ArcDelayCalc.hh"
|
||||
#include "dcalc/GraphDelayCalc1.hh"
|
||||
#include "GraphDelayCalc.hh"
|
||||
#include "sdf/SdfWriter.hh"
|
||||
#include "Levelize.hh"
|
||||
#include "Sim.hh"
|
||||
|
|
@ -414,7 +414,7 @@ Sta::makeArcDelayCalc()
|
|||
void
|
||||
Sta::makeGraphDelayCalc()
|
||||
{
|
||||
graph_delay_calc_ = new GraphDelayCalc1(this);
|
||||
graph_delay_calc_ = new GraphDelayCalc(this);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -3789,22 +3789,11 @@ Sta::connectedCap(const Pin *drvr_pin,
|
|||
float &pin_cap,
|
||||
float &wire_cap) const
|
||||
{
|
||||
pin_cap = 0.0;
|
||||
wire_cap = 0.0;
|
||||
bool cap_exists = false;
|
||||
const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
|
||||
Parasitic *parasitic = arc_delay_calc_->findParasitic(drvr_pin, rf, dcalc_ap);
|
||||
float ap_pin_cap = 0.0;
|
||||
float ap_wire_cap = 0.0;
|
||||
graph_delay_calc_->loadCap(drvr_pin, parasitic, rf, dcalc_ap,
|
||||
ap_pin_cap, ap_wire_cap);
|
||||
pin_cap, wire_cap);
|
||||
arc_delay_calc_->finishDrvrPin();
|
||||
if (!cap_exists
|
||||
|| min_max->compare(ap_pin_cap, pin_cap)) {
|
||||
pin_cap = ap_pin_cap;
|
||||
wire_cap = ap_wire_cap;
|
||||
cap_exists = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
Loading…
Reference in New Issue