OpenSTA/dcalc/LumpedCapDelayCalc.cc

300 lines
8.7 KiB
C++
Raw Normal View History

2018-09-28 17:54:21 +02:00
// OpenSTA, Static Timing Analyzer
2019-01-01 21:26:11 +01:00
// Copyright (c) 2019, Parallax Software, Inc.
2018-09-28 17:54:21 +02:00
//
// 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 "Machine.hh"
#include "Debug.hh"
#include "Units.hh"
#include "TimingArc.hh"
#include "TimingModel.hh"
#include "Liberty.hh"
#include "Network.hh"
#include "Sdc.hh"
#include "Parasitics.hh"
#include "DcalcAnalysisPt.hh"
#include "GraphDelayCalc.hh"
#include "LumpedCapDelayCalc.hh"
namespace sta {
ArcDelayCalc *
makeLumpedCapDelayCalc(StaState *sta)
{
return new LumpedCapDelayCalc(sta);
}
LumpedCapDelayCalc::LumpedCapDelayCalc(StaState *sta) :
ArcDelayCalc(sta)
{
}
ArcDelayCalc *
LumpedCapDelayCalc::copy()
{
return new LumpedCapDelayCalc(this);
}
Parasitic *
2018-09-28 17:54:21 +02:00
LumpedCapDelayCalc::findParasitic(const Pin *drvr_pin,
2019-11-11 23:30:19 +01:00
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap)
2018-09-28 17:54:21 +02:00
{
// set_load has precidence over parasitics.
if (!sdc_->drvrPinHasWireCap(drvr_pin)) {
2019-04-19 03:01:10 +02:00
Parasitic *parasitic = nullptr;
2018-09-28 17:54:21 +02:00
const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
2019-04-19 03:01:10 +02:00
if (parasitics_->haveParasitics()) {
// Prefer PiElmore.
2019-11-11 23:30:19 +01:00
parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap);
2019-04-19 03:01:10 +02:00
if (parasitic)
return parasitic;
Parasitic *parasitic_network =
parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
if (parasitic_network) {
parasitics_->reduceToPiElmore(parasitic_network, drvr_pin,
dcalc_ap->operatingConditions(),
dcalc_ap->corner(),
dcalc_ap->constraintMinMax(),
parasitic_ap);
2019-11-11 23:30:19 +01:00
parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap);
2019-04-19 03:01:10 +02:00
reduced_parasitic_drvrs_.push_back(drvr_pin);
return parasitic;
}
2018-09-28 17:54:21 +02:00
}
const MinMax *cnst_min_max = dcalc_ap->constraintMinMax();
Wireload *wireload = sdc_->wireloadDefaulted(cnst_min_max);
if (wireload) {
float pin_cap, wire_cap, fanout;
bool has_wire_cap;
2019-11-11 23:30:19 +01:00
graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap,
pin_cap, wire_cap, fanout, has_wire_cap);
2019-11-11 23:30:19 +01:00
parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload,
fanout, pin_cap,
dcalc_ap->operatingConditions(),
dcalc_ap->corner(),
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.
unsaved_parasitics_.push_back(parasitic);
return parasitic;
2018-09-28 17:54:21 +02:00
}
}
return nullptr;
2018-09-28 17:54:21 +02:00
}
void
LumpedCapDelayCalc::finishDrvrPin()
2018-09-28 17:54:21 +02:00
{
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();
2018-09-28 17:54:21 +02:00
}
void
LumpedCapDelayCalc::inputPortDelay(const Pin *, float in_slew,
2019-11-11 23:30:19 +01:00
const RiseFall *rf,
2018-09-28 17:54:21 +02:00
Parasitic *,
const DcalcAnalysisPt *)
{
drvr_slew_ = in_slew;
2019-11-11 23:30:19 +01:00
drvr_rf_ = rf;
2018-09-28 17:54:21 +02:00
drvr_library_ = network_->defaultLibertyLibrary();
multi_drvr_slew_factor_ = 1.0F;
}
2018-11-26 18:15:52 +01:00
float
LumpedCapDelayCalc::ceff(const LibertyCell *,
TimingArc *,
const Slew &,
float load_cap,
Parasitic *,
float,
const Pvt *,
const DcalcAnalysisPt *)
{
return load_cap;
}
2018-09-28 17:54:21 +02:00
void
LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell,
TimingArc *arc,
const Slew &in_slew,
float load_cap,
Parasitic *,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew)
{
GateTimingModel *model = gateModel(arc, dcalc_ap);
debugPrint3(debug_, "delay_calc", 3,
" in_slew = %s load_cap = %s related_load_cap = %s lumped\n",
2019-01-27 08:03:01 +01:00
delayAsString(in_slew, this),
2018-09-28 17:54:21 +02:00
units()->capacitanceUnit()->asString(load_cap),
units()->capacitanceUnit()->asString(related_out_cap));
if (model) {
2018-11-26 18:15:52 +01:00
ArcDelay gate_delay1;
Slew drvr_slew1;
2018-09-28 17:54:21 +02:00
float in_slew1 = delayAsFloat(in_slew);
model->gateDelay(drvr_cell, pvt, in_slew1, load_cap, related_out_cap,
2019-01-27 08:03:01 +01:00
pocv_enabled_, gate_delay1, drvr_slew1);
2018-09-28 17:54:21 +02:00
gate_delay = gate_delay1;
drvr_slew = drvr_slew1;
drvr_slew_ = drvr_slew1;
}
else {
gate_delay = delay_zero;
drvr_slew = delay_zero;
drvr_slew_ = 0.0;
}
2019-11-11 23:30:19 +01:00
drvr_rf_ = arc->toTrans()->asRiseFall();
2018-09-28 17:54:21 +02:00
drvr_library_ = drvr_cell->libertyLibrary();
multi_drvr_slew_factor_ = 1.0F;
}
void
LumpedCapDelayCalc::loadDelay(const Pin *load_pin,
ArcDelay &wire_delay,
Slew &load_slew)
{
Delay wire_delay1 = 0.0;
Slew load_slew1 = drvr_slew_ * multi_drvr_slew_factor_;
thresholdAdjust(load_pin, wire_delay1, load_slew1);
wire_delay = wire_delay1;
load_slew = load_slew1 * multi_drvr_slew_factor_;
}
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_) {
2019-11-11 23:30:19 +01:00
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_);
2018-09-28 17:54:21 +02:00
float load_delay_delta =
delayAsFloat(load_slew) * ((load_vth - drvr_vth) / drvr_slew_delta);
2019-11-11 23:30:19 +01:00
load_delay += (drvr_rf_ == RiseFall::rise())
2018-09-28 17:54:21 +02:00
? load_delay_delta
: -load_delay_delta;
2019-11-11 23:30:19 +01:00
float load_slew_delta = load_library->slewUpperThreshold(drvr_rf_)
- load_library->slewLowerThreshold(drvr_rf_);
2018-09-28 17:54:21 +02:00
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();
}
}
void
LumpedCapDelayCalc::reportGateDelay(const LibertyCell *drvr_cell,
TimingArc *arc,
const Slew &in_slew,
float load_cap,
Parasitic *,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
int digits,
string *result)
{
GateTimingModel *model = gateModel(arc, dcalc_ap);
if (model) {
float in_slew1 = delayAsFloat(in_slew);
model->reportGateDelay(drvr_cell, pvt, in_slew1, load_cap,
2019-01-27 08:03:01 +01:00
related_out_cap, false, digits, result);
2018-09-28 17:54:21 +02:00
}
}
2018-11-26 18:15:52 +01:00
void
2018-09-28 17:54:21 +02:00
LumpedCapDelayCalc::checkDelay(const LibertyCell *cell,
TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
2018-11-26 18:15:52 +01:00
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &margin)
2018-09-28 17:54:21 +02:00
{
CheckTimingModel *model = checkModel(arc, dcalc_ap);
if (model) {
float from_slew1 = delayAsFloat(from_slew);
float to_slew1 = delayAsFloat(to_slew);
2019-01-27 08:03:01 +01:00
model->checkDelay(cell, pvt, from_slew1, to_slew1, related_out_cap,
2019-06-04 17:12:22 +02:00
pocv_enabled_, margin);
2018-09-28 17:54:21 +02:00
}
else
2018-11-26 18:15:52 +01:00
margin = delay_zero;
2018-09-28 17:54:21 +02:00
}
void
LumpedCapDelayCalc::reportCheckDelay(const LibertyCell *cell,
TimingArc *arc,
const Slew &from_slew,
const char *from_slew_annotation,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
int digits,
string *result)
{
CheckTimingModel *model = checkModel(arc, dcalc_ap);
if (model) {
float from_slew1 = delayAsFloat(from_slew);
float to_slew1 = delayAsFloat(to_slew);
model->reportCheckDelay(cell, pvt, from_slew1, from_slew_annotation, to_slew1,
2019-01-27 08:03:01 +01:00
related_out_cap, false, digits, result);
2018-09-28 17:54:21 +02:00
}
}
void
LumpedCapDelayCalc::setMultiDrvrSlewFactor(float factor)
{
multi_drvr_slew_factor_ = factor;
}
} // namespace