Merge remote-tracking branch 'parallax/master'

Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
This commit is contained in:
Matt Liberty 2023-11-23 17:39:41 -08:00
commit 94e86553c1
54 changed files with 2953 additions and 2944 deletions

View File

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

View File

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

132
dcalc/DelayCalcBase.cc Normal file
View File

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

View File

@ -16,32 +16,48 @@
#pragma once
#include "LumpedCapDelayCalc.hh"
#include "ArcDelayCalc.hh"
namespace sta {
// Base class for delay calculators with RC wire delay.
class RCDelayCalc : public LumpedCapDelayCalc
class DelayCalcBase : public ArcDelayCalc
{
public:
RCDelayCalc(StaState *sta);
ArcDelayCalc *copy() override;
explicit DelayCalcBase(StaState *sta);
void inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap) override;
void finishDrvrPin() override;
protected:
void gateDelayInit(const TimingArc *arc,
const Slew &in_slew,
const Parasitic *drvr_parasitic);
// Find the liberty library to use for logic/slew thresholds.
LibertyLibrary *thresholdLibrary(const Pin *load_pin);
// Adjust load_delay and load_slew from driver thresholds to load thresholds.
void thresholdAdjust(const Pin *load_pin,
ArcDelay &load_delay,
Slew &load_slew);
// Helper function for input ports driving dspf parasitic.
void dspfWireDelaySlew(const Pin *load_pin,
float elmore,
ArcDelay &wire_delay,
Slew &load_slew);
Slew drvr_slew_;
const LibertyCell *drvr_cell_;
const LibertyLibrary *drvr_library_;
const Parasitic *drvr_parasitic_;
bool input_port_;
const RiseFall *drvr_rf_;
// Parasitics returned by findParasitic that are reduced or estimated
// that can be deleted after delay calculation for the driver pin
// is finished.
Vector<Parasitic*> unsaved_parasitics_;
Vector<const Pin *> reduced_parasitic_drvrs_;
};
} // namespace

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -40,7 +40,7 @@ makeLumpedCapDelayCalc(StaState *sta)
}
LumpedCapDelayCalc::LumpedCapDelayCalc(StaState *sta) :
ArcDelayCalc(sta)
ParallelDelayCalc(sta)
{
}
@ -82,9 +82,9 @@ LumpedCapDelayCalc::findParasitic(const Pin *drvr_pin,
Wireload *wireload = sdc_->wireload(cnst_min_max);
if (wireload) {
float pin_cap, wire_cap, fanout;
bool has_wire_cap;
bool has_net_load;
graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap,
pin_cap, wire_cap, fanout, has_wire_cap);
pin_cap, wire_cap, fanout, has_net_load);
parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload,
fanout, pin_cap,
dcalc_ap->operatingConditions(),
@ -107,32 +107,8 @@ LumpedCapDelayCalc::reducedParasiticType() const
return ReducedParasiticType::pi_elmore;
}
void
LumpedCapDelayCalc::finishDrvrPin()
{
for (auto parasitic : unsaved_parasitics_)
parasitics_->deleteUnsavedParasitic(parasitic);
unsaved_parasitics_.clear();
for (auto drvr_pin : reduced_parasitic_drvrs_)
parasitics_->deleteDrvrReducedParasitics(drvr_pin);
reduced_parasitic_drvrs_.clear();
}
void
LumpedCapDelayCalc::inputPortDelay(const Pin *, float in_slew,
const RiseFall *rf,
const Parasitic *,
const DcalcAnalysisPt *)
{
drvr_slew_ = in_slew;
drvr_rf_ = rf;
drvr_library_ = network_->defaultLibertyLibrary();
multi_drvr_slew_factor_ = 1.0F;
}
float
LumpedCapDelayCalc::ceff(const LibertyCell *,
const TimingArc *,
LumpedCapDelayCalc::ceff(const TimingArc *,
const Slew &,
float load_cap,
const Parasitic *,
@ -144,11 +120,10 @@ LumpedCapDelayCalc::ceff(const LibertyCell *,
}
void
LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell,
const TimingArc *arc,
LumpedCapDelayCalc::gateDelay(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
@ -156,6 +131,7 @@ LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell,
ArcDelay &gate_delay,
Slew &drvr_slew)
{
gateDelayInit(arc, in_slew, drvr_parasitic);
GateTimingModel *model = gateModel(arc, dcalc_ap);
debugPrint(debug_, "delay_calc", 3,
" in_slew = %s load_cap = %s related_load_cap = %s lumped",
@ -169,7 +145,7 @@ LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell,
// NaNs cause seg faults during table lookup.
if (isnan(load_cap) || isnan(related_out_cap) || isnan(delayAsFloat(in_slew)))
report_->error(710, "gate delay input variable is NaN");
model->gateDelay(drvr_cell, pvt, in_slew1, load_cap, related_out_cap,
model->gateDelay(pvt, in_slew1, load_cap, related_out_cap,
pocv_enabled_, gate_delay1, drvr_slew1);
gate_delay = gate_delay1;
drvr_slew = drvr_slew1;
@ -180,9 +156,6 @@ LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell,
drvr_slew = delay_zero;
drvr_slew_ = 0.0;
}
drvr_rf_ = arc->toEdge()->asRiseFall();
drvr_library_ = drvr_cell->libertyLibrary();
multi_drvr_slew_factor_ = 1.0F;
}
void
@ -197,52 +170,8 @@ LumpedCapDelayCalc::loadDelay(const Pin *load_pin,
load_slew = load_slew1;
}
void
LumpedCapDelayCalc::thresholdAdjust(const Pin *load_pin,
ArcDelay &load_delay,
Slew &load_slew)
{
LibertyLibrary *load_library = thresholdLibrary(load_pin);
if (load_library
&& drvr_library_
&& load_library != drvr_library_) {
float drvr_vth = drvr_library_->outputThreshold(drvr_rf_);
float load_vth = load_library->inputThreshold(drvr_rf_);
float drvr_slew_delta = drvr_library_->slewUpperThreshold(drvr_rf_)
- drvr_library_->slewLowerThreshold(drvr_rf_);
float load_delay_delta =
delayAsFloat(load_slew) * ((load_vth - drvr_vth) / drvr_slew_delta);
load_delay += (drvr_rf_ == RiseFall::rise())
? load_delay_delta
: -load_delay_delta;
float load_slew_delta = load_library->slewUpperThreshold(drvr_rf_)
- load_library->slewLowerThreshold(drvr_rf_);
float drvr_slew_derate = drvr_library_->slewDerateFromLibrary();
float load_slew_derate = load_library->slewDerateFromLibrary();
load_slew = load_slew * ((load_slew_delta / load_slew_derate)
/ (drvr_slew_delta / drvr_slew_derate));
}
}
LibertyLibrary *
LumpedCapDelayCalc::thresholdLibrary(const Pin *load_pin)
{
if (network_->isTopLevelPort(load_pin))
// Input/output slews use the default (first read) library
// for slew thresholds.
return network_->defaultLibertyLibrary();
else {
LibertyPort *lib_port = network_->libertyPort(load_pin);
if (lib_port)
return lib_port->libertyCell()->libertyLibrary();
else
return network_->defaultLibertyLibrary();
}
}
string
LumpedCapDelayCalc::reportGateDelay(const LibertyCell *drvr_cell,
const TimingArc *arc,
LumpedCapDelayCalc::reportGateDelay(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *,
@ -254,15 +183,14 @@ LumpedCapDelayCalc::reportGateDelay(const LibertyCell *drvr_cell,
GateTimingModel *model = gateModel(arc, dcalc_ap);
if (model) {
float in_slew1 = delayAsFloat(in_slew);
return model->reportGateDelay(drvr_cell, pvt, in_slew1, load_cap,
related_out_cap, false, digits);
return model->reportGateDelay(pvt, in_slew1, load_cap, related_out_cap,
false, digits);
}
return "";
}
void
LumpedCapDelayCalc::checkDelay(const LibertyCell *cell,
const TimingArc *arc,
LumpedCapDelayCalc::checkDelay(const TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
@ -275,16 +203,14 @@ LumpedCapDelayCalc::checkDelay(const LibertyCell *cell,
if (model) {
float from_slew1 = delayAsFloat(from_slew);
float to_slew1 = delayAsFloat(to_slew);
model->checkDelay(cell, pvt, from_slew1, to_slew1, related_out_cap,
pocv_enabled_, margin);
model->checkDelay(pvt, from_slew1, to_slew1, related_out_cap, pocv_enabled_, margin);
}
else
margin = delay_zero;
}
string
LumpedCapDelayCalc::reportCheckDelay(const LibertyCell *cell,
const TimingArc *arc,
LumpedCapDelayCalc::reportCheckDelay(const TimingArc *arc,
const Slew &from_slew,
const char *from_slew_annotation,
const Slew &to_slew,
@ -297,16 +223,10 @@ LumpedCapDelayCalc::reportCheckDelay(const LibertyCell *cell,
if (model) {
float from_slew1 = delayAsFloat(from_slew);
float to_slew1 = delayAsFloat(to_slew);
return model->reportCheckDelay(cell, pvt, from_slew1, from_slew_annotation, to_slew1,
related_out_cap, false, digits);
return model->reportCheckDelay(pvt, from_slew1, from_slew_annotation,
to_slew1, related_out_cap, false, digits);
}
return "";
}
void
LumpedCapDelayCalc::setMultiDrvrSlewFactor(float factor)
{
multi_drvr_slew_factor_ = factor;
}
} // namespace

View File

@ -16,13 +16,13 @@
#pragma once
#include "ArcDelayCalc.hh"
#include "ParallelDelayCalc.hh"
namespace sta {
// Liberty table model lumped capacitance arc delay calculator.
// Wire delays are zero.
class LumpedCapDelayCalc : public ArcDelayCalc
class LumpedCapDelayCalc : public ParallelDelayCalc
{
public:
LumpedCapDelayCalc(StaState *sta);
@ -31,13 +31,7 @@ public:
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
ReducedParasiticType reducedParasiticType() const override;
void inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap) override;
void gateDelay(const LibertyCell *drvr_cell,
const TimingArc *arc,
void gateDelay(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
@ -47,9 +41,7 @@ public:
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew) override;
void setMultiDrvrSlewFactor(float factor) override;
float ceff(const LibertyCell *drvr_cell,
const TimingArc *arc,
float ceff(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
@ -60,8 +52,7 @@ public:
// Return values.
ArcDelay &wire_delay,
Slew &load_slew) override;
void checkDelay(const LibertyCell *cell,
const TimingArc *arc,
void checkDelay(const TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
@ -69,8 +60,7 @@ public:
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &margin) override;
string reportGateDelay(const LibertyCell *drvr_cell,
const TimingArc *arc,
string reportGateDelay(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
@ -78,8 +68,7 @@ public:
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
int digits) override;
string reportCheckDelay(const LibertyCell *cell,
const TimingArc *arc,
string reportCheckDelay(const TimingArc *arc,
const Slew &from_slew,
const char *from_slew_annotation,
const Slew &to_slew,
@ -87,25 +76,8 @@ public:
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
int digits) override;
void finishDrvrPin() override;
protected:
// Find the liberty library to use for logic/slew thresholds.
LibertyLibrary *thresholdLibrary(const Pin *load_pin);
// Adjust load_delay and load_slew from driver thresholds to load thresholds.
void thresholdAdjust(const Pin *load_pin,
ArcDelay &load_delay,
Slew &load_slew);
Slew drvr_slew_;
float multi_drvr_slew_factor_;
const LibertyLibrary *drvr_library_;
const RiseFall *drvr_rf_;
// Parasitics returned by findParasitic that are reduced or estimated
// that can be deleted after delay calculation for the driver pin
// is finished.
Vector<Parasitic*> unsaved_parasitics_;
Vector<const Pin *> reduced_parasitic_drvrs_;
};
ArcDelayCalc *

171
dcalc/ParallelDelayCalc.cc Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -61,8 +61,7 @@ UnitDelayCalc::inputPortDelay(const Pin *,
}
void
UnitDelayCalc::gateDelay(const LibertyCell *,
const TimingArc *,
UnitDelayCalc::gateDelay(const TimingArc *,
const Slew &,
float,
const Parasitic *,
@ -75,6 +74,29 @@ UnitDelayCalc::gateDelay(const LibertyCell *,
drvr_slew = 0.0;
}
void
UnitDelayCalc::findParallelGateDelays(const MultiDrvrNet *,
GraphDelayCalc *)
{
}
void
UnitDelayCalc::parallelGateDelay(const Pin *,
const TimingArc *,
const Slew &,
float,
const Parasitic *,
float,
const Pvt *,
const DcalcAnalysisPt *,
// Return values.
ArcDelay &gate_delay,
Slew &gate_slew)
{
gate_delay = units_->timeUnit()->scale();
gate_slew = 0.0;
}
void
UnitDelayCalc::loadDelay(const Pin *,
ArcDelay &wire_delay,
@ -85,8 +107,7 @@ UnitDelayCalc::loadDelay(const Pin *,
}
float
UnitDelayCalc::ceff(const LibertyCell *,
const TimingArc *,
UnitDelayCalc::ceff(const TimingArc *,
const Slew &,
float,
const Parasitic *,
@ -98,8 +119,7 @@ UnitDelayCalc::ceff(const LibertyCell *,
}
string
UnitDelayCalc::reportGateDelay(const LibertyCell *,
const TimingArc *,
UnitDelayCalc::reportGateDelay(const TimingArc *,
const Slew &,
float,
const Parasitic *,
@ -114,8 +134,7 @@ UnitDelayCalc::reportGateDelay(const LibertyCell *,
}
void
UnitDelayCalc::checkDelay(const LibertyCell *,
const TimingArc *,
UnitDelayCalc::checkDelay(const TimingArc *,
const Slew &,
const Slew &,
float,
@ -128,8 +147,7 @@ UnitDelayCalc::checkDelay(const LibertyCell *,
}
string
UnitDelayCalc::reportCheckDelay(const LibertyCell *,
const TimingArc *,
UnitDelayCalc::reportCheckDelay(const TimingArc *,
const Slew &,
const char *,
const Slew &,

View File

@ -35,8 +35,7 @@ public:
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap) override;
void gateDelay(const LibertyCell *drvr_cell,
const TimingArc *arc,
void gateDelay(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
@ -46,21 +45,32 @@ public:
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew) override;
void findParallelGateDelays(const MultiDrvrNet *multi_drvr,
GraphDelayCalc *dcalc) override;
// Retrieve the delay and slew for one parallel gate.
void parallelGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &from_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &gate_slew) override;
void loadDelay(const Pin *load_pin,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew) override;
void setMultiDrvrSlewFactor(float) override {}
float ceff(const LibertyCell *drvr_cell,
const TimingArc *arc,
float ceff(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap) override;
void checkDelay(const LibertyCell *cell,
const TimingArc *arc,
void checkDelay(const TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
@ -68,8 +78,7 @@ public:
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &margin) override;
string reportGateDelay(const LibertyCell *drvr_cell,
const TimingArc *arc,
string reportGateDelay(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
@ -77,8 +86,7 @@ public:
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
int digits) override;
string reportCheckDelay(const LibertyCell *cell,
const TimingArc *arc,
string reportCheckDelay(const TimingArc *arc,
const Slew &from_slew,
const char *from_slew_annotation,
const Slew &to_slew,

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -94,12 +94,12 @@ LibertyLibrary::LibertyLibrary(const char *name,
addTableTemplate(scalar_template, type);
}
for (auto tr_index : RiseFall::rangeIndex()) {
wire_slew_degradation_tbls_[tr_index] = nullptr;
input_threshold_[tr_index] = input_threshold_default_;
output_threshold_[tr_index] = output_threshold_default_;
slew_lower_threshold_[tr_index] = slew_lower_threshold_default_;
slew_upper_threshold_[tr_index] = slew_upper_threshold_default_;
for (auto rf_index : RiseFall::rangeIndex()) {
wire_slew_degradation_tbls_[rf_index] = nullptr;
input_threshold_[rf_index] = input_threshold_default_;
output_threshold_[rf_index] = output_threshold_default_;
slew_lower_threshold_[rf_index] = slew_lower_threshold_default_;
slew_upper_threshold_[rf_index] = slew_upper_threshold_default_;
}
}
@ -111,8 +111,8 @@ LibertyLibrary::~LibertyLibrary()
scale_factors_map_.deleteContents();
delete scale_factors_;
for (auto tr_index : RiseFall::rangeIndex()) {
TableModel *model = wire_slew_degradation_tbls_[tr_index];
for (auto rf_index : RiseFall::rangeIndex()) {
TableModel *model = wire_slew_degradation_tbls_[rf_index];
delete model;
}
operating_conditions_.deleteContents();
@ -289,7 +289,7 @@ LibertyLibrary::scaleFactor(ScaleFactorType type,
float
LibertyLibrary::scaleFactor(ScaleFactorType type,
int tr_index,
int rf_index,
const LibertyCell *cell,
const Pvt *pvt) const
{
@ -299,18 +299,18 @@ LibertyLibrary::scaleFactor(ScaleFactorType type,
// All scale factors are unity for nominal pvt.
if (pvt) {
ScaleFactors *scale_factors = nullptr;
// Cell level scale factors have precidence over library scale factors.
// Cell level scale factors have precedence over library scale factors.
if (cell)
scale_factors = cell->scaleFactors();
if (scale_factors == nullptr)
scale_factors = scale_factors_;
if (scale_factors) {
float process_scale = 1.0F + (pvt->process() - nominal_process_)
* scale_factors->scale(type, ScaleFactorPvt::process, tr_index);
* scale_factors->scale(type, ScaleFactorPvt::process, rf_index);
float temp_scale = 1.0F + (pvt->temperature() - nominal_temperature_)
* scale_factors->scale(type, ScaleFactorPvt::temp, tr_index);
* scale_factors->scale(type, ScaleFactorPvt::temp, rf_index);
float volt_scale = 1.0F + (pvt->voltage() - nominal_voltage_)
* scale_factors->scale(type, ScaleFactorPvt::volt, tr_index);
* scale_factors->scale(type, ScaleFactorPvt::volt, rf_index);
float scale = process_scale * temp_scale * volt_scale;
return scale;
}
@ -322,10 +322,10 @@ void
LibertyLibrary::setWireSlewDegradationTable(TableModel *model,
RiseFall *rf)
{
int tr_index = rf->index();
if (wire_slew_degradation_tbls_[tr_index])
delete wire_slew_degradation_tbls_[tr_index];
wire_slew_degradation_tbls_[tr_index] = model;
int rf_index = rf->index();
if (wire_slew_degradation_tbls_[rf_index])
delete wire_slew_degradation_tbls_[rf_index];
wire_slew_degradation_tbls_[rf_index] = model;
}
TableModel *
@ -335,36 +335,32 @@ LibertyLibrary::wireSlewDegradationTable(const RiseFall *rf) const
}
float
LibertyLibrary::degradeWireSlew(const LibertyCell *cell,
const RiseFall *rf,
const Pvt *pvt,
LibertyLibrary::degradeWireSlew(const RiseFall *rf,
float in_slew,
float wire_delay) const
{
const TableModel *model = wireSlewDegradationTable(rf);
if (model)
return degradeWireSlew(cell, pvt, model, in_slew, wire_delay);
return degradeWireSlew(model, in_slew, wire_delay);
else
return in_slew;
}
float
LibertyLibrary::degradeWireSlew(const LibertyCell *cell,
const Pvt *pvt,
const TableModel *model,
LibertyLibrary::degradeWireSlew(const TableModel *model,
float in_slew,
float wire_delay) const
{
switch (model->order()) {
case 0:
return model->findValue(this, cell, pvt, 0.0, 0.0, 0.0);
return model->findValue(0.0, 0.0, 0.0);
case 1: {
TableAxisPtr axis1 = model->axis1();
TableAxisVariable var1 = axis1->variable();
if (var1 == TableAxisVariable::output_pin_transition)
return model->findValue(this, cell, pvt, in_slew, 0.0, 0.0);
return model->findValue(in_slew, 0.0, 0.0);
else if (var1 == TableAxisVariable::connect_delay)
return model->findValue(this, cell, pvt, wire_delay, 0.0, 0.0);
return model->findValue(wire_delay, 0.0, 0.0);
else {
criticalError(231, "unsupported slew degradation table axes");
return 0.0;
@ -377,10 +373,10 @@ LibertyLibrary::degradeWireSlew(const LibertyCell *cell,
TableAxisVariable var2 = axis2->variable();
if (var1 == TableAxisVariable::output_pin_transition
&& var2 == TableAxisVariable::connect_delay)
return model->findValue(this, cell, pvt, in_slew, wire_delay, 0.0);
return model->findValue(in_slew, wire_delay, 0.0);
else if (var1 == TableAxisVariable::connect_delay
&& var2 == TableAxisVariable::output_pin_transition)
return model->findValue(this, cell, pvt, wire_delay, in_slew, 0.0);
return model->findValue(wire_delay, in_slew, 0.0);
else {
criticalError(232, "unsupported slew degradation table axes");
return 0.0;
@ -2580,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;
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

31
liberty/TimingModel.cc Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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