ArcDelayCalc api update for multiple drivers

commit a78442d7d6672bfcbea5f5007803ab27891b9eab
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Jan 7 13:40:02 2024 -0700

    rm OutputWaveforms::currentVoltage

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

commit 074e1c93d4957425c0f2a3afdfce8f0e06ff98a1
Author: James Cherry <cherry@parallaxsw.com>
Date:   Wed Dec 13 16:49:08 2023 -0700

    MultiDrvrNet remove instead of update

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

commit 0f6deec2ffcbe85a1c473525b93f6a6514692181
Author: James Cherry <cherry@parallaxsw.com>
Date:   Wed Dec 13 16:43:24 2023 -0700

    MultiDrvrNet remove instead of update

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

commit 2f5f48fe09bacd101d1e909f45e087ba8c620561
Author: James Cherry <cherry@parallaxsw.com>
Date:   Mon Dec 11 09:24:54 2023 -0700

    compile errors

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

commit e8fc4292e325f7ac10bd8e5d57b5a8111abb05ed
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sat Dec 9 18:25:04 2023 -0700

    ArcDcalcWaveforms

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

commit be114b10adca194d80ac9529e8635c11ed9c1c32
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sat Dec 9 11:34:59 2023 -0700

    GraphDelayCalc::findDriverArcDelays

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

commit 7b71e137b088c1293e628e594dde6a8223927ee8
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sat Dec 9 10:39:30 2023 -0700

    GraphDelayCalc::findDriverArcDelays

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

commit b13a791cd57c5b9f9b454b3cf22959fbe3b9667e
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Dec 8 13:14:09 2023 -0700

    unused arg

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

commit abf90ca7c08fd349cfb68554bdeae5a9c3b91a23
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Dec 8 13:12:52 2023 -0700

    unused arg

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

commit 6bda70448ef133586594503d78b8838421f7a52d
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Dec 8 13:10:04 2023 -0700

    gateDelay rm pvt arg

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

commit 2f51ed07fa14f039a048c3a146ca1b017fb45f16
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Dec 8 10:24:57 2023 -0700

    dcalc api

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

commit 362950b9d9aa52f3c331c1007a6ee6a34140812e
Author: James Cherry <cherry@parallaxsw.com>
Date:   Wed Dec 6 17:00:45 2023 -0700

    ArcDcalcResult gateDelay

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

commit 91f1307ac04752e00dfde42b34e84f66fdb60a57
Author: James Cherry <cherry@parallaxsw.com>
Date:   Mon Dec 4 17:22:40 2023 -0700

    ArcDcalcArg/Result

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

commit 74d289e450edf54b1a9215b92c85b1d6a011820d
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Dec 1 17:45:04 2023 -0700

    multi drvr init

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

commit c956838aba74c2f27280253f0452e0350bb05c33
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Dec 1 12:10:23 2023 -0800

    arc dcalc api

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

commit 5aa2c42833e5f68e901d4ac61d8bef426252e5ab
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Nov 30 15:42:43 2023 -0800

    dcalc api

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

commit 434327b7d80fdf8fe3410390c88b299b46e9139b
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Nov 30 11:36:21 2023 -0800

    arc api

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

commit 263e1dee49d7133653fbe0bad9b8243ba5259548
Author: James Cherry <cherry@parallaxsw.com>
Date:   Wed Nov 29 18:48:32 2023 -0800

    ArcDelayCalc api

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

commit a9f05513c09564d75cb377a5a89399a250ab5d6b
Author: James Cherry <cherry@parallaxsw.com>
Date:   Mon Nov 27 10:48:59 2023 -0800

    ArcDelayCalc api

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

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2024-01-07 13:44:04 -07:00
parent 6ee4340de8
commit 03afb36d01
33 changed files with 1619 additions and 1566 deletions

View File

@ -62,6 +62,7 @@ set(STA_SOURCE
app/StaMain.cc
dcalc/ArcDelayCalc.cc
dcalc/ArcDcalcWaveforms.cc
dcalc/ArnoldiDelayCalc.cc
dcalc/ArnoldiReduce.cc
dcalc/DcalcAnalysisPt.cc
@ -73,7 +74,6 @@ set(STA_SOURCE
dcalc/LumpedCapDelayCalc.cc
dcalc/NetCaps.cc
dcalc/ParallelDelayCalc.cc
dcalc/SlewDegradeDelayCalc.cc
dcalc/UnitDelayCalc.cc
graph/DelayFloat.cc

View File

@ -14,14 +14,30 @@
// 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 "ArcDcalcWaveforms.hh"
namespace sta {
class ArcDelayCalc;
class StaState;
Table1
ArcDcalcWaveforms::inputWaveform(const Pin *,
const RiseFall *,
const Corner *,
const MinMax *)
{
return Table1();
}
ArcDelayCalc *
makeSlewDegradeDelayCalc(StaState *sta);
Table1
ArcDcalcWaveforms::drvrRampWaveform(const Pin *,
const RiseFall *,
const Pin *,
const RiseFall *,
const Pin *,
const Corner *,
const MinMax *)
{
return Table1();
}
} // namespace

View File

@ -0,0 +1,59 @@
// 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 "MinMax.hh"
#include "TableModel.hh"
#include "NetworkClass.hh"
namespace sta {
class Corner;
class DcalcAnalysisPt;
// Abstract class for the graph delay calculator traversal to interface
class ArcDcalcWaveforms
{
public:
virtual Table1 inputWaveform(const Pin *in_pin,
const RiseFall *in_rf,
const Corner *corner,
const MinMax *min_max);
virtual Table1 drvrWaveform(const Pin *in_pin,
const RiseFall *in_rf,
const Pin *drvr_pin,
const RiseFall *drvr_rf,
const Corner *corner,
const MinMax *min_max) = 0;
virtual Table1 loadWaveform(const Pin *in_pin,
const RiseFall *in_rf,
const Pin *drvr_pin,
const RiseFall *drvr_rf,
const Pin *load_pin,
const Corner *corner,
const MinMax *min_max) = 0;
virtual Table1 drvrRampWaveform(const Pin *in_pin,
const RiseFall *in_rf,
const Pin *drvr_pin,
const RiseFall *drvr_rf,
const Pin *load_pin,
const Corner *corner,
const MinMax *min_max);
};
} // namespace

View File

@ -16,10 +16,6 @@
#include "ArcDelayCalc.hh"
#include "TimingModel.hh"
#include "TimingArc.hh"
#include "GraphDelayCalc.hh"
namespace sta {
ArcDelayCalc::ArcDelayCalc(StaState *sta):
@ -27,27 +23,114 @@ ArcDelayCalc::ArcDelayCalc(StaState *sta):
{
}
TimingModel *
ArcDelayCalc::model(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const
void
ArcDelayCalc::gateDelay(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
float,
const Pvt *,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew)
{
const OperatingConditions *op_cond = dcalc_ap->operatingConditions();
const TimingArc *corner_arc = arc->cornerArc(dcalc_ap->libertyIndex());
return corner_arc->model(op_cond);
LoadPinIndexMap load_pin_index_map(network_);
ArcDcalcResult dcalc_result = gateDelay(nullptr, arc, in_slew, load_cap, parasitic,
load_pin_index_map, dcalc_ap);
gate_delay = dcalc_result.gateDelay();
drvr_slew = dcalc_result.drvrSlew();
}
GateTimingModel *
ArcDelayCalc::gateModel(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const
////////////////////////////////////////////////////////////////
ArcDcalcArg::ArcDcalcArg() :
drvr_pin_(nullptr),
edge_(nullptr),
arc_(nullptr),
in_slew_(0.0),
parasitic_(nullptr)
{
return dynamic_cast<GateTimingModel*>(model(arc, dcalc_ap));
}
CheckTimingModel *
ArcDelayCalc::checkModel(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const
ArcDcalcArg::ArcDcalcArg(const Pin *drvr_pin,
Edge *edge,
const TimingArc *arc,
const Slew in_slew,
const Parasitic *parasitic) :
drvr_pin_(drvr_pin),
edge_(edge),
arc_(arc),
in_slew_(in_slew),
parasitic_(parasitic)
{
return dynamic_cast<CheckTimingModel*>(model(arc, dcalc_ap));
}
void
ArcDcalcArg::setParasitic(const Parasitic *parasitic)
{
parasitic_ = parasitic;
}
////////////////////////////////////////////////////////////////
ArcDcalcResult::ArcDcalcResult() :
gate_delay_(0.0),
drvr_slew_(0.0)
{
}
ArcDcalcResult::ArcDcalcResult(size_t load_count) :
gate_delay_(0.0),
drvr_slew_(0.0)
{
wire_delays_.resize(load_count);
load_slews_.resize(load_count);
}
void
ArcDcalcResult::setGateDelay(ArcDelay gate_delay)
{
gate_delay_ = gate_delay;
}
void
ArcDcalcResult::setDrvrSlew(Slew drvr_slew)
{
drvr_slew_ = drvr_slew;
}
ArcDelay
ArcDcalcResult::wireDelay(size_t load_idx) const
{
return wire_delays_[load_idx];
}
void
ArcDcalcResult::setWireDelay(size_t load_idx,
ArcDelay wire_delay)
{
wire_delays_[load_idx] = wire_delay;
}
void
ArcDcalcResult::setLoadCount(size_t load_count)
{
wire_delays_.resize(load_count);
load_slews_.resize(load_count);
}
Slew
ArcDcalcResult::loadSlew(size_t load_idx) const
{
return load_slews_[load_idx];
}
void
ArcDcalcResult::setLoadSlew(size_t load_idx,
Slew load_slew)
{
load_slews_[load_idx] = load_slew;
}
} // namespace

View File

@ -74,7 +74,6 @@ struct timing_table
const LibertyCell *cell;
const Pvt *pvt;
float in_slew;
float relcap;
};
} // namespace

View File

@ -117,32 +117,26 @@ public:
Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
ReducedParasiticType reducedParasiticType() const override;
void inputPortDelay(const Pin *port_pin,
ArcDcalcResult inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
void gateDelay(const TimingArc *arc,
ArcDcalcResult gateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
// Pass in load_cap or parasitic.
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
string reportGateDelay(const Pin *drvr_pin,
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,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew) override;
string reportGateDelay(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
int digits) override;
void delay_work_set_thresholds(delay_work *D,
@ -152,14 +146,12 @@ public:
double derate);
private:
void gateDelaySlew(const LibertyCell *drvr_cell,
ArcDcalcResult gateDelaySlew(const LibertyCell *drvr_cell,
const TimingArc *arc,
const GateTableModel *table_model,
const Slew &in_slew,
float related_out_cap,
const Pvt *pvt,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew);
const LoadPinIndexMap &load_pin_index_map,
const Pvt *pvt);
void ar1_ceff_delay(delay_work *D,
timing_table *tab,
arnoldi1 *mod,
@ -224,7 +216,6 @@ private:
double *_delayV;
double *_slewV;
int pin_n_;
bool input_port_;
ArnoldiReduce *reduce_;
delay_work *delay_work_;
};
@ -306,25 +297,20 @@ ArnoldiDelayCalc::findParasitic(const Pin *drvr_pin,
return parasitic;
}
ReducedParasiticType
ArnoldiDelayCalc::reducedParasiticType() const
{
return ReducedParasiticType::arnoldi;
}
void
ArnoldiDelayCalc::inputPortDelay(const Pin *drvr_pin,
ArcDcalcResult
ArnoldiDelayCalc::inputPortDelay(const Pin *,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap)
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
{
LumpedCapDelayCalc::inputPortDelay(drvr_pin, in_slew, rf, parasitic, dcalc_ap);
rcmodel_ = nullptr;
_delayV[0] = 0.0;
_slewV[0] = in_slew;
int j;
LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
ArcDcalcResult dcalc_result(load_pin_index_map.size());
if (parasitic) {
rcmodel_ = reinterpret_cast<rcmodel*>(const_cast<Parasitic*>(parasitic));
pin_n_ = rcmodel_->n;
@ -335,69 +321,67 @@ ArnoldiDelayCalc::inputPortDelay(const Pin *drvr_pin,
_delayV = (double*)realloc(_delayV,_pinNmax * sizeof(double));
_slewV = (double*)realloc(_slewV,_pinNmax * sizeof(double));
}
pin_n_ = 1;
pin_n_ = rcmodel_->n;
double slew_derate = drvr_library_->slewDerateFromLibrary();
double lo_thresh = drvr_library_->slewLowerThreshold(drvr_rf_);
double hi_thresh = drvr_library_->slewUpperThreshold(drvr_rf_);
bool rising = (drvr_rf_ == RiseFall::rise());
delay_work_set_thresholds(delay_work_, lo_thresh, hi_thresh, rising,
slew_derate);
double slew_derate = drvr_library->slewDerateFromLibrary();
double lo_thresh = drvr_library->slewLowerThreshold(rf);
double hi_thresh = drvr_library->slewUpperThreshold(rf);
bool rising = (rf == RiseFall::rise());
delay_work_set_thresholds(delay_work_, lo_thresh, hi_thresh, rising, slew_derate);
delay_c *c = delay_work_->c;
double c_log = c->vlg;
for (j=1;j<pin_n_;j++) {
for (int j=1;j<pin_n_;j++) {
double elmore = rcmodel_->elmore(j);
_delayV[j] = 0.6931472*elmore;
_slewV[j] = in_slew + c_log*elmore/slew_derate;
double wire_delay = 0.6931472*elmore;
double load_slew = in_slew + c_log*elmore/slew_derate;
_delayV[j] = wire_delay;
_slewV[j] = load_slew;
const Pin *load_pin = rcmodel_->pinV[j];
auto load_idx_itr = load_pin_index_map.find(load_pin);
if (load_idx_itr != load_pin_index_map.end()) {
size_t load_idx = load_idx_itr->second;
dcalc_result.setWireDelay(load_idx, wire_delay);
dcalc_result.setLoadSlew(load_idx, load_slew);
}
}
}
else
dcalc_result = makeResult(drvr_library, rf, 0.0, in_slew, load_pin_index_map);
return dcalc_result;
}
void
ArnoldiDelayCalc::gateDelay(const TimingArc *arc,
ArcDcalcResult
ArnoldiDelayCalc::gateDelay(const Pin *drvr_pin,
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)
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
{
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 =
reinterpret_cast<ConcreteParasitic*>(const_cast<Parasitic*>(drvr_parasitic));
rcmodel_ = dynamic_cast<rcmodel*>(drvr_cparasitic);
GateTimingModel *model = gateModel(arc, dcalc_ap);
GateTableModel *table_model = dynamic_cast<GateTableModel*>(model);
if (table_model && rcmodel_)
gateDelaySlew(drvr_cell, table_model, in_slew,
related_out_cap, pvt,
gate_delay, drvr_slew);
ConcreteParasitic *cparasitic =
reinterpret_cast<ConcreteParasitic*>(const_cast<Parasitic*>(parasitic));
rcmodel_ = dynamic_cast<rcmodel*>(cparasitic);
GateTableModel *table_model = gateTableModel(arc, dcalc_ap);
if (table_model && rcmodel_) {
const Pvt *pvt = pinPvt(drvr_pin, dcalc_ap);
return gateDelaySlew(drvr_cell, arc, table_model, in_slew, load_pin_index_map, pvt);
}
else
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;
return LumpedCapDelayCalc::gateDelay(drvr_pin, arc, in_slew, load_cap,
parasitic, load_pin_index_map, dcalc_ap);
}
void
ArcDcalcResult
ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell,
const TimingArc *arc,
const GateTableModel *table_model,
const Slew &in_slew,
float related_out_cap,
const Pvt *pvt,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew)
const LoadPinIndexMap &load_pin_index_map,
const Pvt *pvt)
{
pin_n_ = rcmodel_->n;
if (pin_n_ >= _pinNmax) {
@ -407,12 +391,15 @@ ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell,
_slewV = (double*)realloc(_slewV,_pinNmax * sizeof(double));
}
ArcDcalcResult dcalc_result(load_pin_index_map.size());
pin_n_ = rcmodel_->n;
if (table_model) {
double slew_derate = drvr_library_->slewDerateFromLibrary();
double lo_thresh = drvr_library_->slewLowerThreshold(drvr_rf_);
double hi_thresh = drvr_library_->slewUpperThreshold(drvr_rf_);
bool rising = (drvr_rf_ == RiseFall::rise());
const RiseFall *rf = arc->toEdge()->asRiseFall();
if (table_model && rf) {
const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary();
double slew_derate = drvr_library->slewDerateFromLibrary();
double lo_thresh = drvr_library->slewLowerThreshold(rf);
double hi_thresh = drvr_library->slewUpperThreshold(rf);
bool rising = (rf == RiseFall::rise());
delay_work_set_thresholds(delay_work_, lo_thresh, hi_thresh, rising,
slew_derate);
if (rcmodel_->order > 0) {
@ -421,48 +408,43 @@ ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell,
tab.cell = drvr_cell;
tab.pvt = pvt;
tab.in_slew = delayAsFloat(in_slew);
tab.relcap = related_out_cap;
ar1_ceff_delay(delay_work_, &tab, rcmodel_,
_delayV, _slewV);
}
gate_delay = _delayV[0];
drvr_slew = _slewV[0];
}
}
dcalc_result.setGateDelay(_delayV[0]);
dcalc_result.setDrvrSlew(_slewV[0]);
void
ArnoldiDelayCalc::loadDelay(const Pin *load_pin,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew)
{
// This does not appear to handle input port parasitics correctly.
wire_delay = 0.0;
load_slew = drvr_slew_ * multi_drvr_slew_factor_;
if (rcmodel_) {
// HACK
for (int i = 0; i < rcmodel_->n; i++) {
if (rcmodel_->pinV[i] == load_pin) {
wire_delay = _delayV[i] - _delayV[0];
load_slew = _slewV[i] * multi_drvr_slew_factor_;
break;
const Pin *load_pin = rcmodel_->pinV[i];
auto load_idx_itr = load_pin_index_map.find(load_pin);
if (load_idx_itr != load_pin_index_map.end()) {
size_t load_idx = load_idx_itr->second;
ArcDelay wire_delay = _delayV[i] - _delayV[0];
Slew load_slew = _slewV[i];
thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
dcalc_result.setWireDelay(load_idx, wire_delay);
dcalc_result.setLoadSlew(load_idx, load_slew);
}
}
}
thresholdAdjust(load_pin, wire_delay, load_slew);
}
return dcalc_result;
}
string
ArnoldiDelayCalc::reportGateDelay(const TimingArc *,
const Slew &,
float,
const Parasitic *,
float,
const Pvt *,
const DcalcAnalysisPt *,
int)
ArnoldiDelayCalc::reportGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
int digits)
{
return "";
return LumpedCapDelayCalc::reportGateDelay(drvr_pin, arc, in_slew, load_cap,
parasitic, load_pin_index_map,
dcalc_ap, digits);
}
////////////////////////////////////////////////////////////////
@ -1310,7 +1292,7 @@ ArnoldiDelayCalc::ra_get_r(delay_work *D,
c1 = ctot;
ArcDelay d1;
Slew s1;
tab->table->gateDelay(tab->pvt, tab->in_slew, c1, tab->relcap, pocv_enabled_, d1, s1);
tab->table->gateDelay(tab->pvt, tab->in_slew, c1, pocv_enabled_, d1, s1);
tlohi = slew_derate*delayAsFloat(s1);
r = tlohi/(c_log*c1);
if (rdelay>0.0 && r > rdelay)
@ -1332,7 +1314,7 @@ ArnoldiDelayCalc::ra_get_s(delay_work *D,
double tlohi,smin,s;
ArcDelay d1;
Slew s1;
tab->table->gateDelay(tab->pvt, tab->in_slew, c, tab->relcap, pocv_enabled_, d1, s1);
tab->table->gateDelay(tab->pvt, tab->in_slew, c, 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) {
@ -1365,8 +1347,8 @@ ArnoldiDelayCalc::ra_rdelay_1(timing_table *tab,
return 0.0;
ArcDelay d1, d2;
Slew s1, 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);
tab->table->gateDelay(tab->pvt, tab->in_slew, c1, pocv_enabled_, d1, s1);
tab->table->gateDelay(tab->pvt, tab->in_slew, c2, pocv_enabled_, d2, s2);
double dt50 = delayAsFloat(d1)-delayAsFloat(d2);
if (dt50 <= 0.0)
return 0.0;
@ -1418,8 +1400,7 @@ 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->pvt,tab->in_slew, ctot, tab->relcap, pocv_enabled_,
df, sf);
tab->table->gateDelay(tab->pvt,tab->in_slew, ctot, 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),
@ -1430,7 +1411,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
units_->timeUnit()->asString(tlox-thix));
}
ceff = ctot;
tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, tab->relcap, pocv_enabled_,
tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, pocv_enabled_,
df, sf);
t50_sy = delayAsFloat(df);
t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5);
@ -1472,7 +1453,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
units_->timeUnit()->asString(ceff_time),
units_->capacitanceUnit()->asString(ceff));
tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, tab->relcap, pocv_enabled_, df, sf);
tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, 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++) {

View File

@ -20,7 +20,6 @@
#include "StringUtil.hh"
#include "UnitDelayCalc.hh"
#include "LumpedCapDelayCalc.hh"
#include "SlewDegradeDelayCalc.hh"
#include "DmpDelayCalc.hh"
#include "ArnoldiDelayCalc.hh"
@ -35,7 +34,6 @@ registerDelayCalcs()
{
registerDelayCalc("unit", makeUnitDelayCalc);
registerDelayCalc("lumped_cap", makeLumpedCapDelayCalc);
registerDelayCalc("slew_degrade", makeSlewDegradeDelayCalc);
registerDelayCalc("dmp_ceff_elmore", makeDmpCeffElmoreDelayCalc);
registerDelayCalc("dmp_ceff_two_pole", makeDmpCeffTwoPoleDelayCalc);
registerDelayCalc("arnoldi", makeArnoldiDelayCalc);

View File

@ -19,6 +19,8 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Sta.hh"
#include "ArcDelayCalc.hh"
#include "dcalc/ArcDcalcWaveforms.hh"
%}
@ -59,4 +61,76 @@ report_delay_calc_cmd(Edge *edge,
return Sta::sta()->reportDelayCalc(edge, arc, corner, min_max, digits);
}
////////////////////////////////////////////////////////////////
Table1
ccs_input_waveform(const Pin *in_pin,
const RiseFall *in_rf,
const Corner *corner,
const MinMax *min_max)
{
cmdLinkedNetwork();
Sta *sta = Sta::sta();
ArcDcalcWaveforms *arc_dcalc = dynamic_cast<ArcDcalcWaveforms*>(sta->arcDelayCalc());
if (arc_dcalc)
return arc_dcalc->inputWaveform(in_pin, in_rf, corner, min_max);
else
return Table1();
}
Table1
ccs_driver_waveform(const Pin *in_pin,
const RiseFall *in_rf,
const Pin *drvr_pin,
const RiseFall *drvr_rf,
const Corner *corner,
const MinMax *min_max)
{
cmdLinkedNetwork();
Sta *sta = Sta::sta();
ArcDcalcWaveforms *arc_dcalc = dynamic_cast<ArcDcalcWaveforms*>(sta->arcDelayCalc());
if (arc_dcalc)
return arc_dcalc->drvrWaveform(in_pin, in_rf, drvr_pin, drvr_rf, corner, min_max);
else
return Table1();
}
Table1
ccs_driver_ramp_waveform(const Pin *in_pin,
const RiseFall *in_rf,
const Pin *drvr_pin,
const RiseFall *drvr_rf,
const Pin *load_pin,
const Corner *corner,
const MinMax *min_max)
{
cmdLinkedNetwork();
Sta *sta = Sta::sta();
ArcDcalcWaveforms *arc_dcalc = dynamic_cast<ArcDcalcWaveforms*>(sta->arcDelayCalc());
if (arc_dcalc)
return arc_dcalc->drvrRampWaveform(in_pin, in_rf, drvr_pin, drvr_rf,
load_pin, corner, min_max);
else
return Table1();
}
Table1
ccs_load_waveform(const Pin *in_pin,
const RiseFall *in_rf,
const Pin *drvr_pin,
const RiseFall *drvr_rf,
const Pin *load_pin,
const Corner *corner,
const MinMax *min_max)
{
cmdLinkedNetwork();
Sta *sta = Sta::sta();
ArcDcalcWaveforms *arc_dcalc = dynamic_cast<ArcDcalcWaveforms*>(sta->arcDelayCalc());
if (arc_dcalc)
return arc_dcalc->loadWaveform(in_pin, in_rf, drvr_pin, drvr_rf,
load_pin, corner, min_max);
else
return Table1();
}
%} // inline

View File

@ -18,16 +18,52 @@
#include "Liberty.hh"
#include "TimingArc.hh"
#include "TimingModel.hh"
#include "TableModel.hh"
#include "Network.hh"
#include "Parasitics.hh"
#include "Sdc.hh"
#include "DcalcAnalysisPt.hh"
namespace sta {
using std::log;
DelayCalcBase::DelayCalcBase(StaState *sta) :
ArcDelayCalc(sta)
{
}
TimingModel *
DelayCalcBase::model(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const
{
const OperatingConditions *op_cond = dcalc_ap->operatingConditions();
const TimingArc *corner_arc = arc->cornerArc(dcalc_ap->libertyIndex());
return corner_arc->model(op_cond);
}
GateTimingModel *
DelayCalcBase::gateModel(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const
{
return dynamic_cast<GateTimingModel*>(model(arc, dcalc_ap));
}
GateTableModel *
DelayCalcBase::gateTableModel(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const
{
return dynamic_cast<GateTableModel*>(model(arc, dcalc_ap));
}
CheckTimingModel *
DelayCalcBase::checkModel(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const
{
return dynamic_cast<CheckTimingModel*>(model(arc, dcalc_ap));
}
void
DelayCalcBase::finishDrvrPin()
{
@ -39,74 +75,53 @@ DelayCalcBase::finishDrvrPin()
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 *,
DelayCalcBase::dspfWireDelaySlew(const Pin *load_pin,
const RiseFall *rf,
Slew drvr_slew,
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();
LibertyLibrary *load_library = thresholdLibrary(load_pin);
float vth = load_library->inputThreshold(rf);
float vl = load_library->slewLowerThreshold(rf);
float vh = load_library->slewUpperThreshold(rf);
float slew_derate = load_library->slewDerateFromLibrary();
wire_delay = -elmore * log(1.0 - vth);
load_slew = drvr_slew_ + elmore * log((1.0 - vl) / (1.0 - vh)) / slew_derate;
load_slew = drvr_slew + elmore * log((1.0 - vl) / (1.0 - vh)) / slew_derate;
load_slew = drvr_slew + elmore * log((1.0 - vl) / (1.0 - vh)) / slew_derate;
}
void
DelayCalcBase::thresholdAdjust(const Pin *load_pin,
const LibertyLibrary *drvr_library,
const RiseFall *rf,
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_);
&& drvr_library
&& load_library != drvr_library) {
float drvr_vth = drvr_library->outputThreshold(rf);
float load_vth = load_library->inputThreshold(rf);
float drvr_slew_delta = drvr_library->slewUpperThreshold(rf)
- drvr_library->slewLowerThreshold(rf);
float load_delay_delta =
delayAsFloat(load_slew) * ((load_vth - drvr_vth) / drvr_slew_delta);
load_delay += (drvr_rf_ == RiseFall::rise())
load_delay += (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_delta = load_library->slewUpperThreshold(rf)
- load_library->slewLowerThreshold(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));
@ -129,4 +144,55 @@ DelayCalcBase::thresholdLibrary(const Pin *load_pin)
}
}
ArcDelay
DelayCalcBase::checkDelay(const Pin *check_pin,
const TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap)
{
CheckTimingModel *model = checkModel(arc, dcalc_ap);
if (model) {
float from_slew1 = delayAsFloat(from_slew);
float to_slew1 = delayAsFloat(to_slew);
return model->checkDelay(pinPvt(check_pin, dcalc_ap), from_slew1, to_slew1,
related_out_cap, pocv_enabled_);
}
else
return delay_zero;
}
string
DelayCalcBase::reportCheckDelay(const Pin *check_pin,
const TimingArc *arc,
const Slew &from_slew,
const char *from_slew_annotation,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap,
int digits)
{
CheckTimingModel *model = checkModel(arc, dcalc_ap);
if (model) {
float from_slew1 = delayAsFloat(from_slew);
float to_slew1 = delayAsFloat(to_slew);
return model->reportCheckDelay(pinPvt(check_pin, dcalc_ap), from_slew1,
from_slew_annotation, to_slew1,
related_out_cap, false, digits);
}
return "";
}
const Pvt *
DelayCalcBase::pinPvt(const Pin *pin,
const DcalcAnalysisPt *dcalc_ap)
{
const Instance *drvr_inst = network_->instance(pin);
const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax());
if (pvt == nullptr)
pvt = dcalc_ap->operatingConditions();
return pvt;
}
} // namespace

View File

@ -20,39 +20,58 @@
namespace sta {
class GateTableModel;
class DelayCalcBase : public ArcDelayCalc
{
public:
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;
ArcDelay checkDelay(const Pin *check_pin,
const TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap) override;
string reportCheckDelay(const Pin *check_pin,
const TimingArc *arc,
const Slew &from_slew,
const char *from_slew_annotation,
const Slew &to_slew,
float related_out_cap,
const DcalcAnalysisPt *dcalc_ap,
int digits) override;
protected:
void gateDelayInit(const TimingArc *arc,
const Slew &in_slew,
const Parasitic *drvr_parasitic);
GateTimingModel *gateModel(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const;
GateTableModel *gateTableModel(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const;
CheckTimingModel *checkModel(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const;
TimingModel *model(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const;
// 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,
const LibertyLibrary *drvr_library,
const RiseFall *rf,
ArcDelay &load_delay,
Slew &load_slew);
// Helper function for input ports driving dspf parasitic.
void dspfWireDelaySlew(const Pin *load_pin,
const RiseFall *rf,
Slew drvr_slew,
float elmore,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew);
const Pvt *pinPvt(const Pin *pin,
const DcalcAnalysisPt *dcalc_ap);
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.

View File

@ -88,7 +88,6 @@ gateModelRd(const LibertyCell *cell,
double in_slew,
double c2,
double c1,
float related_out_cap,
const Pvt *pvt,
bool pocv_enabled);
static void
@ -155,7 +154,6 @@ public:
const RiseFall *rf,
double rd,
double in_slew,
float related_out_cap,
double c2,
double rpi,
double c1);
@ -235,7 +233,6 @@ protected:
const Pvt *pvt_;
const GateTableModel *gate_model_;
double in_slew_;
float related_out_cap_;
double c2_;
double rpi_;
double c1_;
@ -319,7 +316,6 @@ DmpAlg::init(const LibertyLibrary *drvr_library,
const RiseFall *rf,
double rd,
double in_slew,
float related_out_cap,
// Pi model.
double c2,
double rpi,
@ -331,7 +327,6 @@ DmpAlg::init(const LibertyLibrary *drvr_library,
gate_model_ = gate_model;
rd_ = rd;
in_slew_ = in_slew;
related_out_cap_ = related_out_cap;
c2_ = c2;
rpi_ = rpi;
c1_ = c1;
@ -381,8 +376,8 @@ DmpAlg::gateCapDelaySlew(double ceff,
{
ArcDelay model_delay;
Slew model_slew;
gate_model_->gateDelay(pvt_, in_slew_, ceff, related_out_cap_,
pocv_enabled_, model_delay, model_slew);
gate_model_->gateDelay(pvt_, in_slew_, ceff, pocv_enabled_,
model_delay, model_slew);
delay = delayAsFloat(model_delay);
slew = delayAsFloat(model_slew);
}
@ -696,7 +691,6 @@ public:
const RiseFall *rf,
double rd,
double in_slew,
float related_out_cap,
double c2,
double rpi,
double c1);
@ -729,14 +723,13 @@ DmpCap::init(const LibertyLibrary *drvr_library,
const RiseFall *rf,
double rd,
double in_slew,
float related_out_cap,
double c2,
double rpi,
double c1)
{
debugPrint(debug_, "dmp_ceff", 3, "Using DMP cap");
DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf,
rd, in_slew, related_out_cap, c2, rpi, c1);
rd, in_slew, c2, rpi, c1);
ceff_ = c1 + c2;
}
@ -810,7 +803,6 @@ public:
const RiseFall *rf,
double rd,
double in_slew,
float related_out_cap,
double c2,
double rpi,
double c1);
@ -870,14 +862,13 @@ DmpPi::init(const LibertyLibrary *drvr_library,
const RiseFall *rf,
double rd,
double in_slew,
float related_out_cap,
double c2,
double rpi,
double c1)
{
debugPrint(debug_, "dmp_ceff", 3, "Using DMP Pi");
DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf, rd,
in_slew, related_out_cap, c2, rpi, c1);
in_slew, c2, rpi, c1);
// Find poles/zeros.
z1_ = 1.0 / (rpi_ * c1_);
@ -1144,7 +1135,6 @@ public:
const RiseFall *rf,
double rd,
double in_slew,
float related_out_cap,
double c2,
double rpi,
double c1);
@ -1187,14 +1177,13 @@ DmpZeroC2::init(const LibertyLibrary *drvr_library,
const RiseFall *rf,
double rd,
double in_slew,
float related_out_cap,
double c2,
double rpi,
double c1)
{
debugPrint(debug_, "dmp_ceff", 3, "Using DMP C2=0");
DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf, rd,
in_slew, related_out_cap, c2, rpi, c1);
in_slew, c2, rpi, c1);
ceff_ = c1;
z1_ = 1.0 / (rpi_ * c1_);
@ -1543,64 +1532,58 @@ DmpCeffDelayCalc::~DmpCeffDelayCalc()
delete dmp_zero_c2_;
}
void
DmpCeffDelayCalc::inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap)
{
dmp_alg_ = nullptr;
LumpedCapDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap);
}
void
DmpCeffDelayCalc::gateDelay(const TimingArc *arc,
ArcDcalcResult
DmpCeffDelayCalc::gateDelay(const Pin *drvr_pin,
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)
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
{
input_port_ = false;
drvr_rf_ = arc->toEdge()->asRiseFall();
const RiseFall *rf = arc->toEdge()->asRiseFall();
const LibertyCell *drvr_cell = arc->from()->libertyCell();
drvr_library_ = drvr_cell->libertyLibrary();
drvr_parasitic_ = drvr_parasitic;
const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary();
GateTimingModel *model = gateModel(arc, dcalc_ap);
GateTableModel *table_model = dynamic_cast<GateTableModel*>(model);
if (table_model && drvr_parasitic) {
GateTableModel *table_model = gateTableModel(arc, dcalc_ap);
if (table_model && parasitic) {
float in_slew1 = delayAsFloat(in_slew);
float c2, rpi, c1;
parasitics_->piModel(drvr_parasitic, c2, rpi, c1);
parasitics_->piModel(parasitic, c2, rpi, c1);
if (isnan(c2) || isnan(c1) || isnan(rpi))
report_->error(618, "parasitic Pi model has NaNs.");
setCeffAlgorithm(drvr_library_, drvr_cell, pvt, table_model,
drvr_rf_, in_slew1, related_out_cap,
c2, rpi, c1);
double dmp_gate_delay, dmp_drvr_slew;
gateDelaySlew(dmp_gate_delay, dmp_drvr_slew);
gate_delay = dmp_gate_delay;
drvr_slew = dmp_drvr_slew;
setCeffAlgorithm(drvr_library, drvr_cell, pinPvt(drvr_pin, dcalc_ap),
table_model, rf, in_slew1, c2, rpi, c1);
double gate_delay, drvr_slew;
gateDelaySlew(gate_delay, drvr_slew);
ArcDcalcResult dcalc_result(load_pin_index_map.size());
dcalc_result.setGateDelay(gate_delay);
dcalc_result.setDrvrSlew(drvr_slew);
for (auto load_pin_index : load_pin_index_map) {
const Pin *load_pin = load_pin_index.first;
size_t load_idx = load_pin_index.second;
ArcDelay wire_delay;
Slew load_slew;
loadDelaySlew(load_pin, drvr_slew, rf, drvr_library, parasitic,
wire_delay, load_slew);
dcalc_result.setWireDelay(load_idx, wire_delay);
dcalc_result.setLoadSlew(load_idx, load_slew);
}
return dcalc_result;
}
else {
LumpedCapDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic,
related_out_cap, pvt, dcalc_ap,
gate_delay, drvr_slew);
if (drvr_parasitic
ArcDcalcResult dcalc_result =
LumpedCapDelayCalc::gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic,
load_pin_index_map, dcalc_ap);
if (parasitic
&& !unsuppored_model_warned_) {
unsuppored_model_warned_ = true;
report_->warn(1, "cell %s delay model not supported on SPF parasitics by DMP delay calculator",
drvr_cell->name());
}
return dcalc_result;
}
drvr_slew_ = drvr_slew;
multi_drvr_slew_factor_ = 1.0F;
}
void
@ -1610,7 +1593,6 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library,
const GateTableModel *gate_model,
const RiseFall *rf,
double in_slew,
float related_out_cap,
double c2,
double rpi,
double c1)
@ -1618,7 +1600,7 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library,
double rd = 0.0;
if (gate_model) {
rd = gateModelRd(drvr_cell, gate_model, rf, in_slew, c2, c1,
related_out_cap, pvt, pocv_enabled_);
pvt, pocv_enabled_);
// Zero Rd means the table is constant and thus independent of load cap.
if (rd < 1e-2
// Rpi is small compared to Rd, which makes the load capacitive.
@ -1635,7 +1617,7 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library,
else
dmp_alg_ = dmp_cap_;
dmp_alg_->init(drvr_library, drvr_cell, pvt, gate_model,
drvr_rf_, rd, in_slew, related_out_cap, c2, rpi, c1);
rf, rd, in_slew, c2, rpi, c1);
debugPrint(debug_, "dmp_ceff", 3,
" DMP in_slew = %s c2 = %s rpi = %s c1 = %s Rd = %s (%s alg)",
units_->timeUnit()->asString(in_slew),
@ -1646,51 +1628,29 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library,
dmp_alg_->name());
}
float
DmpCeffDelayCalc::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)
{
ArcDelay gate_delay;
Slew drvr_slew;
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();
else
return load_cap;
}
string
DmpCeffDelayCalc::reportGateDelay(const TimingArc *arc,
DmpCeffDelayCalc::reportGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
int digits)
{
ArcDelay gate_delay;
Slew drvr_slew;
gateDelay(arc, in_slew, load_cap, drvr_parasitic, related_out_cap, pvt, dcalc_ap,
gate_delay, drvr_slew);
gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic, load_pin_index_map, dcalc_ap);
GateTimingModel *model = gateModel(arc, dcalc_ap);
float c_eff = 0.0;
string result;
if (drvr_parasitic_ && dmp_alg_) {
if (parasitic && dmp_alg_) {
c_eff = dmp_alg_->ceff();
const LibertyCell *drvr_cell = arc->from()->libertyCell();
const LibertyCell *drvr_cell = arc->to()->libertyCell();
const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary();
const Units *units = drvr_library->units();
const Unit *cap_unit = units->capacitanceUnit();
const Unit *res_unit = units->resistanceUnit();
float c2, rpi, c1;
parasitics_->piModel(drvr_parasitic_, c2, rpi, c1);
parasitics_->piModel(parasitic, c2, rpi, c1);
result += "Pi model C2=";
result += cap_unit->asString(c2, digits);
result += " Rpi=";
@ -1705,7 +1665,7 @@ DmpCeffDelayCalc::reportGateDelay(const TimingArc *arc,
c_eff = load_cap;
if (model) {
float in_slew1 = delayAsFloat(in_slew);
result += model->reportGateDelay(pvt, in_slew1, c_eff, related_out_cap,
result += model->reportGateDelay(pinPvt(drvr_pin, dcalc_ap), in_slew1, c_eff,
pocv_enabled_, digits);
}
return result;
@ -1718,7 +1678,6 @@ gateModelRd(const LibertyCell *cell,
double in_slew,
double c2,
double c1,
float related_out_cap,
const Pvt *pvt,
bool pocv_enabled)
{
@ -1726,8 +1685,8 @@ gateModelRd(const LibertyCell *cell,
float cap2 = cap1 + 1e-15;
ArcDelay d1, d2;
Slew s1, 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);
gate_model->gateDelay(pvt, in_slew, cap1, pocv_enabled, d1, s1);
gate_model->gateDelay(pvt, in_slew, cap2, pocv_enabled, d2, s2);
double vth = cell->libertyLibrary()->outputThreshold(rf);
float rd = -log(vth) * abs(delayAsFloat(d1) - delayAsFloat(d2)) / (cap2 - cap1);
return rd;
@ -1741,7 +1700,7 @@ DmpCeffDelayCalc::gateDelaySlew(double &delay,
}
void
DmpCeffDelayCalc::loadDelaySlew(const Pin *load_pin,
DmpCeffDelayCalc::loadDelaySlewElmore(const Pin *load_pin,
double elmore,
ArcDelay &delay,
Slew &slew)

View File

@ -34,42 +34,36 @@ class DmpCeffDelayCalc : public LumpedCapDelayCalc
public:
DmpCeffDelayCalc(StaState *sta);
virtual ~DmpCeffDelayCalc();
virtual void inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
ArcDcalcResult gateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap);
virtual void gateDelay(const TimingArc *arc,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
string reportGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
// return values
ArcDelay &gate_delay,
Slew &drvr_slew);
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 TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
int digits);
virtual void copyState(const StaState *sta);
int digits) override;
void copyState(const StaState *sta) override;
protected:
void gateDelaySlew(double &delay,
virtual void loadDelaySlew(const Pin *load_pin,
double drvr_slew,
const RiseFall *rf,
const LibertyLibrary *drvr_library,
const Parasitic *parasitic,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew) = 0;
void gateDelaySlew(// Return values.
double &delay,
double &slew);
void loadDelaySlew(const Pin *load_pin,
void loadDelaySlewElmore(const Pin *load_pin,
double elmore,
ArcDelay &delay,
Slew &slew);
@ -80,7 +74,6 @@ protected:
const GateTableModel *gate_model,
const RiseFall *rf,
double in_slew,
float related_out_cap,
double c2,
double rpi,
double c1);

View File

@ -35,7 +35,20 @@ class DmpCeffElmoreDelayCalc : public DmpCeffDelayCalc
public:
DmpCeffElmoreDelayCalc(StaState *sta);
ArcDelayCalc *copy() override;
void loadDelay(const Pin *load_pin,
ArcDcalcResult inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
protected:
void loadDelaySlew(const Pin *load_pin,
double drvr_slew,
const RiseFall *rf,
const LibertyLibrary *drvr_library,
const Parasitic *parasitic,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew) override;
};
@ -57,26 +70,54 @@ DmpCeffElmoreDelayCalc::copy()
return new DmpCeffElmoreDelayCalc(this);
}
ArcDcalcResult
DmpCeffElmoreDelayCalc::inputPortDelay(const Pin *,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
{
ArcDcalcResult dcalc_result(load_pin_index_map.size());
LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
for (auto load_pin_index : load_pin_index_map) {
const Pin *load_pin = load_pin_index.first;
size_t load_idx = load_pin_index.second;
ArcDelay wire_delay = 0.0;
Slew load_slew = in_slew;
bool elmore_exists = false;
float elmore = 0.0;
if (parasitic)
parasitics_->findElmore(parasitic, load_pin, elmore, elmore_exists);
if (elmore_exists)
// Input port with no external driver.
dspfWireDelaySlew(load_pin, rf, in_slew, elmore, wire_delay, load_slew);
thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
dcalc_result.setWireDelay(load_idx, wire_delay);
dcalc_result.setLoadSlew(load_idx, load_slew);
}
return dcalc_result;
}
void
DmpCeffElmoreDelayCalc::loadDelay(const Pin *load_pin,
DmpCeffElmoreDelayCalc::loadDelaySlew(const Pin *load_pin,
double drvr_slew,
const RiseFall *rf,
const LibertyLibrary *drvr_library,
const Parasitic *parasitic,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew)
{
ArcDelay wire_delay1 = 0.0;
Slew load_slew1 = drvr_slew_;
wire_delay = 0.0;
load_slew = drvr_slew;
bool elmore_exists = false;
float elmore = 0.0;
if (drvr_parasitic_)
parasitics_->findElmore(drvr_parasitic_, load_pin, elmore, elmore_exists);
if (elmore_exists) {
if (input_port_)
dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1);
else
loadDelaySlew(load_pin, elmore, wire_delay1, load_slew1);
}
thresholdAdjust(load_pin, wire_delay1, load_slew1);
wire_delay = wire_delay1;
load_slew = load_slew1 * multi_drvr_slew_factor_;
if (parasitic)
parasitics_->findElmore(parasitic, load_pin, elmore, elmore_exists);
if (elmore_exists)
loadDelaySlewElmore(load_pin, elmore, wire_delay, load_slew);
thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
}
////////////////////////////////////////////////////////////////
@ -91,28 +132,31 @@ public:
Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
ReducedParasiticType reducedParasiticType() const override;
void inputPortDelay(const Pin *port_pin,
ArcDcalcResult inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
void gateDelay(const TimingArc *arc,
ArcDcalcResult gateDelay(const Pin *drvr_pin,
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;
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
private:
void loadDelay(Parasitic *pole_residue,
void loadDelaySlew(const Pin *load_pin,
double drvr_slew,
const RiseFall *rf,
const LibertyLibrary *drvr_library,
const Parasitic *parasitic,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew) override;
void loadDelay(double drvr_slew,
Parasitic *pole_residue,
double p1,
double k1,
ArcDelay &wire_delay,
@ -211,57 +255,81 @@ DmpCeffTwoPoleDelayCalc::findParasitic(const Pin *drvr_pin,
return parasitic;
}
ReducedParasiticType
DmpCeffTwoPoleDelayCalc::reducedParasiticType() const
{
return ReducedParasiticType::pi_pole_residue2;
}
void
DmpCeffTwoPoleDelayCalc::inputPortDelay(const Pin *port_pin,
ArcDcalcResult
DmpCeffTwoPoleDelayCalc::inputPortDelay(const Pin *,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap)
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
{
parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(parasitic);
DmpCeffDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap);
ArcDcalcResult dcalc_result(load_pin_index_map.size());
ArcDelay wire_delay = 0.0;
Slew load_slew = in_slew;
LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
for (auto load_pin_index : load_pin_index_map) {
const Pin *load_pin = load_pin_index.first;
size_t load_idx = load_pin_index.second;
if (parasitics_->isPiPoleResidue(parasitic)) {
const Parasitic *pole_residue = parasitics_->findPoleResidue(parasitic, load_pin);
if (pole_residue) {
size_t pole_count = parasitics_->poleResidueCount(pole_residue);
if (pole_count >= 1) {
ComplexFloat pole1, residue1;
// Find the 1st (elmore) pole.
parasitics_->poleResidue(pole_residue, 0, pole1, residue1);
if (pole1.imag() == 0.0
&& residue1.imag() == 0.0) {
float p1 = pole1.real();
float elmore = 1.0F / p1;
dspfWireDelaySlew(load_pin, rf, in_slew, elmore, wire_delay, load_slew);
thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
}
}
}
}
dcalc_result.setWireDelay(load_idx, wire_delay);
dcalc_result.setLoadSlew(load_idx, load_slew);
}
return dcalc_result;
}
void
DmpCeffTwoPoleDelayCalc::gateDelay(const TimingArc *arc,
ArcDcalcResult
DmpCeffTwoPoleDelayCalc::gateDelay(const Pin *drvr_pin,
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)
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
{
gateDelayInit(arc, in_slew, drvr_parasitic);
parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(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);
const LibertyLibrary *drvr_library = arc->to()->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();
return DmpCeffDelayCalc::gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic,
load_pin_index_map, dcalc_ap) ;
}
void
DmpCeffTwoPoleDelayCalc::loadDelay(const Pin *load_pin,
DmpCeffTwoPoleDelayCalc::loadDelaySlew(const Pin *load_pin,
double drvr_slew,
const RiseFall *rf,
const LibertyLibrary *drvr_library,
const Parasitic *parasitic,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew)
{
parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(parasitic);
// Should handle PiElmore parasitic.
ArcDelay wire_delay1 = 0.0;
Slew load_slew1 = drvr_slew_;
wire_delay = 0.0;
load_slew = drvr_slew;
Parasitic *pole_residue = 0;
if (parasitic_is_pole_residue_)
pole_residue = parasitics_->findPoleResidue(drvr_parasitic_, load_pin);
pole_residue = parasitics_->findPoleResidue(parasitic, load_pin);
if (pole_residue) {
size_t pole_count = parasitics_->poleResidueCount(pole_residue);
if (pole_count >= 1) {
@ -272,37 +340,31 @@ DmpCeffTwoPoleDelayCalc::loadDelay(const Pin *load_pin,
&& residue1.imag() == 0.0) {
float p1 = pole1.real();
float k1 = residue1.real();
if (input_port_) {
float elmore = 1.0F / p1;
// Input port with no external driver.
dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1);
}
else {
if (pole_count >= 2)
loadDelay(pole_residue, p1, k1, wire_delay1, load_slew1);
loadDelay(drvr_slew, pole_residue, p1, k1, wire_delay, load_slew);
else {
float elmore = 1.0F / p1;
wire_delay1 = elmore;
load_slew1 = drvr_slew_;
wire_delay = elmore;
load_slew = drvr_slew;
}
}
}
}
}
thresholdAdjust(load_pin, wire_delay1, load_slew1);
wire_delay = wire_delay1;
load_slew = load_slew1 * multi_drvr_slew_factor_;
thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
}
void
DmpCeffTwoPoleDelayCalc::loadDelay(Parasitic *pole_residue,
double p1, double k1,
DmpCeffTwoPoleDelayCalc::loadDelay(double drvr_slew,
Parasitic *pole_residue,
double p1,
double k1,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew)
{
ComplexFloat pole2, residue2;
parasitics_->poleResidue(pole_residue, 1, pole2, residue2);
if (!delayZero(drvr_slew_)
if (!delayZero(drvr_slew)
&& pole2.imag() == 0.0
&& residue2.imag() == 0.0) {
double p2 = pole2.real();
@ -311,7 +373,7 @@ DmpCeffTwoPoleDelayCalc::loadDelay(Parasitic *pole_residue,
double k2_p2_2 = k2 / (p2 * p2);
double B = k1_p1_2 + k2_p2_2;
// Convert tt to 0:1 range.
float tt = delayAsFloat(drvr_slew_) * slew_derate_ / (vh_ - vl_);
float tt = delayAsFloat(drvr_slew) * slew_derate_ / (vh_ - vl_);
double y_tt = (tt - B + k1_p1_2 * exp(-p1 * tt)
+ k2_p2_2 * exp(-p2 * tt)) / tt;
wire_delay = loadDelay(vth_, p1, p2, k1, k2, B, k1_p1_2, k2_p2_2, tt, y_tt)

View File

@ -183,25 +183,10 @@ GraphDelayCalc::deleteVertexBefore(Vertex *vertex)
invalid_delays_->erase(vertex);
MultiDrvrNet *multi_drvr = multiDrvrNet(vertex);
if (multi_drvr) {
VertexSet *drvrs = multi_drvr->drvrs();
drvrs->erase(vertex);
multi_drvr_net_map_.erase(vertex);
if (drvrs->empty())
// Don't bother incrementally updating MultiDrvrNet.
for (Vertex *drvr_vertex : *multi_drvr->drvrs())
multi_drvr_net_map_.erase(drvr_vertex);
delete multi_drvr;
else {
Level max_drvr_level = 0;
Vertex *max_drvr = nullptr;
for (Vertex *drvr_vertex : *drvrs) {
Level drvr_level = drvr_vertex->level();
if (max_drvr == nullptr
|| drvr_level > max_drvr_level) {
max_drvr = drvr_vertex;
max_drvr_level = drvr_level;
}
}
multi_drvr->setDcalcDrvr(max_drvr);
multi_drvr->findCaps(sdc_);
}
}
}
@ -391,10 +376,12 @@ GraphDelayCalc::seedNoDrvrCellSlew(Vertex *drvr_vertex,
const MinMax *slew_min_max = dcalc_ap->slewMinMax();
if (!drvr_vertex->slewAnnotated(rf, slew_min_max))
graph_->setSlew(drvr_vertex, rf, ap_index, slew);
arc_delay_calc->inputPortDelay(drvr_pin, delayAsFloat(slew), rf,
parasitic, dcalc_ap);
annotateLoadDelays(drvr_vertex, rf, drive_delay, false, dcalc_ap,
arc_delay_calc);
LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex);
ArcDcalcResult dcalc_result =
arc_delay_calc->inputPortDelay(drvr_pin, delayAsFloat(slew), rf, parasitic,
load_pin_index_map, dcalc_ap);
annotateLoadDelays(drvr_vertex, rf, dcalc_result, load_pin_index_map,
drive_delay, false, dcalc_ap);
arc_delay_calc->finishDrvrPin();
}
@ -417,10 +404,12 @@ GraphDelayCalc::seedNoDrvrSlew(Vertex *drvr_vertex,
if (!drvr_vertex->slewAnnotated(rf, slew_min_max))
graph_->setSlew(drvr_vertex, rf, ap_index, slew);
Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin, rf, dcalc_ap);
arc_delay_calc->inputPortDelay(drvr_pin, delayAsFloat(slew), rf,
parasitic, dcalc_ap);
annotateLoadDelays(drvr_vertex, rf, delay_zero, false, dcalc_ap,
arc_delay_calc);
LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex);
ArcDcalcResult dcalc_result =
arc_delay_calc->inputPortDelay(drvr_pin, delayAsFloat(slew), rf, parasitic,
load_pin_index_map, dcalc_ap);
annotateLoadDelays(drvr_vertex, rf, dcalc_result, load_pin_index_map, delay_zero,
false, dcalc_ap);
arc_delay_calc->finishDrvrPin();
}
@ -531,25 +520,26 @@ GraphDelayCalc::findInputArcDelay(const Pin *drvr_pin,
arc->to()->name(),
arc->toEdge()->asString(),
arc->role()->asString());
RiseFall *drvr_rf = arc->toEdge()->asRiseFall();
const RiseFall *drvr_rf = arc->toEdge()->asRiseFall();
if (drvr_rf) {
DcalcAPIndex ap_index = dcalc_ap->index();
const Pvt *pvt = dcalc_ap->operatingConditions();
Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf,
Parasitic *parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, dcalc_ap);
float load_cap = loadCap(drvr_pin, parasitic, drvr_rf, dcalc_ap);
LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex);
ArcDcalcResult intrinsic_result =
arc_delay_calc_->gateDelay(drvr_pin, arc, Slew(from_slew), 0.0, nullptr,
load_pin_index_map, dcalc_ap);
ArcDelay intrinsic_delay = intrinsic_result.gateDelay();
ArcDcalcResult gate_result = arc_delay_calc_->gateDelay(drvr_pin, arc,
Slew(from_slew), load_cap,
parasitic,
load_pin_index_map,
dcalc_ap);
float load_cap = loadCap(drvr_pin, drvr_parasitic, drvr_rf, dcalc_ap);
ArcDelay gate_delay = gate_result.gateDelay();
Slew gate_slew = gate_result.drvrSlew();
ArcDelay intrinsic_delay;
Slew intrinsic_slew;
arc_delay_calc_->gateDelay(arc, Slew(from_slew), 0.0, 0, 0.0, pvt, dcalc_ap,
intrinsic_delay, intrinsic_slew);
// For input drivers there is no instance to find a related_output_pin.
ArcDelay gate_delay;
Slew gate_slew;
arc_delay_calc_->gateDelay(arc, Slew(from_slew), load_cap,
drvr_parasitic, 0.0, pvt, dcalc_ap,
gate_delay, gate_slew);
ArcDelay load_delay = gate_delay - intrinsic_delay;
debugPrint(debug_, "delay_calc", 3,
" gate delay = %s intrinsic = %s slew = %s",
@ -557,8 +547,8 @@ GraphDelayCalc::findInputArcDelay(const Pin *drvr_pin,
delayAsString(intrinsic_delay, this),
delayAsString(gate_slew, this));
graph_->setSlew(drvr_vertex, drvr_rf, ap_index, gate_slew);
annotateLoadDelays(drvr_vertex, drvr_rf, load_delay, false, dcalc_ap,
arc_delay_calc_);
annotateLoadDelays(drvr_vertex, drvr_rf, gate_result, load_pin_index_map,
load_delay, false, dcalc_ap);
}
}
@ -651,20 +641,13 @@ GraphDelayCalc::findDriverDelays(Vertex *drvr_vertex,
{
bool delay_changed = false;
MultiDrvrNet *multi_drvr = findMultiDrvrNet(drvr_vertex);
if (multi_drvr
&& multi_drvr->parallelGates(network_)) {
Vertex *dcalc_drvr = multi_drvr->dcalcDrvr();
if (drvr_vertex == dcalc_drvr) {
if (multi_drvr == nullptr
|| (multi_drvr
&& (!multi_drvr->parallelGates(network_)
|| drvr_vertex == multi_drvr->dcalcDrvr()))) {
initLoadSlews(drvr_vertex);
arc_delay_calc->findParallelGateDelays(multi_drvr, this);
for (Vertex *drvr_vertex : *multi_drvr->drvrs())
delay_changed |= findDriverDelays1(drvr_vertex, multi_drvr, arc_delay_calc);
}
}
else {
initLoadSlews(drvr_vertex);
delay_changed = findDriverDelays1(drvr_vertex, nullptr, arc_delay_calc);
}
arc_delay_calc->finishDrvrPin();
return delay_changed;
}
@ -763,9 +746,16 @@ GraphDelayCalc::findDriverDelays1(Vertex *drvr_vertex,
MultiDrvrNet *multi_drvr,
ArcDelayCalc *arc_delay_calc)
{
const Pin *drvr_pin = drvr_vertex->pin();
Instance *drvr_inst = network_->instance(drvr_pin);
initSlew(drvr_vertex);
if (multi_drvr
&& multi_drvr->parallelGates(network_)) {
// Only init on the trigger driver.
if (drvr_vertex == multi_drvr->dcalcDrvr()) {
for (auto vertex : *multi_drvr->drvrs())
initWireDelays(vertex);
}
}
else
initWireDelays(drvr_vertex);
bool delay_changed = false;
bool has_delays = false;
@ -777,8 +767,8 @@ GraphDelayCalc::findDriverDelays1(Vertex *drvr_vertex,
if (search_pred_->searchFrom(from_vertex)
&& search_pred_->searchThru(edge)
&& !edge->role()->isLatchDtoQ()) {
delay_changed |= findDriverEdgeDelays(drvr_inst, drvr_pin, drvr_vertex,
multi_drvr, edge, arc_delay_calc);
delay_changed |= findDriverEdgeDelays(drvr_vertex, multi_drvr, edge,
arc_delay_calc);
has_delays = true;
}
}
@ -812,53 +802,329 @@ GraphDelayCalc::findLatchEdgeDelays(Edge *edge)
Instance *drvr_inst = network_->instance(drvr_pin);
debugPrint(debug_, "delay_calc", 2, "find latch D->Q %s",
sdc_network_->pathName(drvr_inst));
bool delay_changed = findDriverEdgeDelays(drvr_inst, drvr_pin, drvr_vertex,
nullptr, edge, arc_delay_calc_);
bool delay_changed = findDriverEdgeDelays(drvr_vertex, nullptr, edge,
arc_delay_calc_);
if (delay_changed && observer_)
observer_->delayChangedTo(drvr_vertex);
}
bool
GraphDelayCalc::findDriverEdgeDelays(const Instance *drvr_inst,
const Pin *drvr_pin,
Vertex *drvr_vertex,
GraphDelayCalc::findDriverEdgeDelays(Vertex *drvr_vertex,
const MultiDrvrNet *multi_drvr,
Edge *edge,
ArcDelayCalc *arc_delay_calc)
{
Vertex *in_vertex = edge->from(graph_);
Vertex *from_vertex = edge->from(graph_);
const TimingArcSet *arc_set = edge->timingArcSet();
const LibertyPort *related_out_port = arc_set->relatedOut();
const Pin *related_out_pin = 0;
bool delay_changed = false;
if (related_out_port)
related_out_pin = network_->findPin(drvr_inst, related_out_port);
PinSeq load_pins = loadPins(drvr_vertex);
LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex);
for (auto dcalc_ap : corners_->dcalcAnalysisPts()) {
const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax());
if (pvt == nullptr)
pvt = dcalc_ap->operatingConditions();
for (TimingArc *arc : arc_set->arcs()) {
const RiseFall *rf = arc->toEdge()->asRiseFall();
Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin, rf, dcalc_ap);
float related_out_cap = 0.0;
if (related_out_pin) {
Parasitic *related_out_parasitic =
arc_delay_calc->findParasitic(related_out_pin, rf, dcalc_ap);
related_out_cap = loadCap(related_out_pin, related_out_parasitic, rf, dcalc_ap);
for (const TimingArc *arc : arc_set->arcs())
delay_changed |= findDriverArcDelays(drvr_vertex, multi_drvr, edge, arc,
load_pin_index_map, dcalc_ap,
arc_delay_calc);
}
delay_changed |= findArcDelay(drvr_pin, drvr_vertex, arc, parasitic,
related_out_cap, in_vertex, edge, pvt, dcalc_ap,
multi_drvr, arc_delay_calc);
}
}
if (delay_changed && observer_) {
observer_->delayChangedFrom(in_vertex);
observer_->delayChangedFrom(from_vertex);
observer_->delayChangedFrom(drvr_vertex);
}
return delay_changed;
}
void
GraphDelayCalc::findDriverArcDelays(Vertex *drvr_vertex,
Edge *edge,
const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap,
ArcDelayCalc *arc_delay_calc)
{
MultiDrvrNet *multi_drvr = multiDrvrNet(drvr_vertex);
LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex);
findDriverArcDelays(drvr_vertex, multi_drvr, edge, arc,
load_pin_index_map, dcalc_ap,
arc_delay_calc);
}
bool
GraphDelayCalc::findDriverArcDelays(Vertex *drvr_vertex,
const MultiDrvrNet *multi_drvr,
Edge *edge,
const TimingArc *arc,
LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
ArcDelayCalc *arc_delay_calc)
{
bool delay_changed = false;
const RiseFall *from_rf = arc->fromEdge()->asRiseFall();
const RiseFall *drvr_rf = arc->toEdge()->asRiseFall();
if (from_rf && drvr_rf) {
const Pin *drvr_pin = drvr_vertex->pin();
Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin, drvr_rf,
dcalc_ap);
float load_cap = loadCap(drvr_pin, parasitic, drvr_rf, dcalc_ap, multi_drvr);
if (multi_drvr
&& multi_drvr->parallelGates(network_)) {
ArcDcalcArgSeq dcalc_args = makeArcDcalcArgs(drvr_vertex, multi_drvr,
edge, arc, dcalc_ap,
arc_delay_calc);
ArcDcalcResultSeq dcalc_results =
arc_delay_calc->gateDelays(dcalc_args, load_cap, load_pin_index_map,
dcalc_ap);
size_t drvr_count = multi_drvr->drvrs()->size();
for (size_t drvr_idx = 0; drvr_idx < drvr_count; drvr_idx++) {
ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx];
ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx];
delay_changed |= annotateDelaysSlews(dcalc_arg.edge(), dcalc_arg.arc(),
dcalc_result, load_pin_index_map,
dcalc_ap);
}
}
else {
Vertex *from_vertex = edge->from(graph_);
const Slew in_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap);
ArcDcalcResult dcalc_result = arc_delay_calc->gateDelay(drvr_pin, arc, in_slew,
load_cap, parasitic,
load_pin_index_map,
dcalc_ap);
delay_changed |= annotateDelaysSlews(edge, arc, dcalc_result,
load_pin_index_map, dcalc_ap);
}
}
return delay_changed;
}
ArcDcalcArgSeq
GraphDelayCalc::makeArcDcalcArgs(Vertex *drvr_vertex,
const MultiDrvrNet *multi_drvr,
Edge *edge,
const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap,
ArcDelayCalc *arc_delay_calc)
{
ArcDcalcArgSeq dcalc_args;
for (auto drvr_vertex1 : *multi_drvr->drvrs()) {
Edge *edge1;
const TimingArc *arc1;
if (drvr_vertex1 == drvr_vertex) {
edge1 = edge;
arc1 = arc;
}
else
findParallelEdge(drvr_vertex1, edge, arc, edge1, arc1);
Vertex *from_vertex = edge1->from(graph_);
const RiseFall *from_rf = arc1->fromEdge()->asRiseFall();
const RiseFall *drvr_rf = arc1->toEdge()->asRiseFall();
const Slew in_slew = edgeFromSlew(from_vertex, from_rf, edge1, dcalc_ap);
const Pin *drvr_pin1 = drvr_vertex1->pin();
Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin1, drvr_rf,
dcalc_ap);
dcalc_args.push_back(ArcDcalcArg(drvr_pin1, edge1, arc1, in_slew,
parasitic));
}
return dcalc_args;
}
// Find an edge/arc for parallel driver vertex to go along with the
// primary driver drvr_edge/drvr_arc.
void
GraphDelayCalc::findParallelEdge(Vertex *vertex,
Edge *drvr_edge,
const TimingArc *drvr_arc,
// Return values.
Edge *&edge,
const TimingArc *&arc)
{
LibertyCell *drvr_cell = network_->libertyCell(network_->instance(drvr_edge->to(graph_)->pin()));
LibertyCell *vertex_cell = network_->libertyCell(network_->instance(vertex->pin()));
if (vertex_cell == drvr_cell) {
// Homogeneous drivers.
arc = drvr_arc;
LibertyPort *from_port = network_->libertyPort(edge->from(graph_)->pin());
VertexInEdgeIterator edge_iter(vertex, graph_);
while (edge_iter.hasNext()) {
edge = edge_iter.next();
if (network_->libertyPort(edge->from(graph_)->pin()) == from_port)
return;
}
}
else {
VertexInEdgeIterator edge_iter(vertex, graph_);
while (edge_iter.hasNext()) {
edge = edge_iter.next();
for (TimingArc *arc1 : edge->timingArcSet()->arcs()) {
if (arc1->fromEdge() == drvr_arc->fromEdge()
&& arc1->toEdge() == drvr_arc->toEdge()) {
arc = arc1;
return;
}
}
}
}
edge = nullptr;
arc = nullptr;
}
bool
GraphDelayCalc::annotateDelaysSlews(Edge *edge,
const TimingArc *arc,
ArcDcalcResult &dcalc_result,
LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
{
bool delay_changed = annotateDelaySlew(edge, arc,
dcalc_result.gateDelay(),
dcalc_result.drvrSlew(), dcalc_ap);
if (!edge->role()->isLatchDtoQ()) {
Vertex *drvr_vertex = edge->to(graph_);
annotateLoadDelays(drvr_vertex, arc->toEdge()->asRiseFall(), dcalc_result,
load_pin_index_map, delay_zero, true, dcalc_ap);
}
return delay_changed;
}
// Annotate the gate delay and merge the slew at the driver pin.
// Annotate the wire delays from the gate output to
// each load pin, and the merge the slews at each load pin.
bool
GraphDelayCalc::annotateDelaySlew(Edge *edge,
const TimingArc *arc,
ArcDelay &gate_delay,
Slew &gate_slew,
const DcalcAnalysisPt *dcalc_ap)
{
bool delay_changed = false;
DcalcAPIndex ap_index = dcalc_ap->index();
debugPrint(debug_, "delay_calc", 3,
" %s %s -> %s %s (%s) corner:%s/%s",
arc->from()->name(),
arc->fromEdge()->asString(),
arc->to()->name(),
arc->toEdge()->asString(),
arc->role()->asString(),
dcalc_ap->corner()->name(),
dcalc_ap->delayMinMax()->asString());
debugPrint(debug_, "delay_calc", 3,
" gate delay = %s slew = %s",
delayAsString(gate_delay, this),
delayAsString(gate_slew, this));
Vertex *drvr_vertex = edge->to(graph_);
const RiseFall *drvr_rf = arc->toEdge()->asRiseFall();
// Merge slews.
const Slew &drvr_slew = graph_->slew(drvr_vertex, drvr_rf, ap_index);
const MinMax *slew_min_max = dcalc_ap->slewMinMax();
if (delayGreater(gate_slew, drvr_slew, dcalc_ap->slewMinMax(), this)
&& !drvr_vertex->slewAnnotated(drvr_rf, slew_min_max)
&& !edge->role()->isLatchDtoQ())
graph_->setSlew(drvr_vertex, drvr_rf, ap_index, gate_slew);
if (!graph_->arcDelayAnnotated(edge, arc, ap_index)) {
const ArcDelay &prev_gate_delay = graph_->arcDelay(edge,arc,ap_index);
float gate_delay1 = delayAsFloat(gate_delay);
float prev_gate_delay1 = delayAsFloat(prev_gate_delay);
if (prev_gate_delay1 == 0.0
|| (abs(gate_delay1 - prev_gate_delay1) / prev_gate_delay1
> incremental_delay_tolerance_))
delay_changed = true;
graph_->setArcDelay(edge, arc, ap_index, gate_delay);
}
return delay_changed;
}
// Annotate wire arc delays and load pin slews.
// extra_delay is additional wire delay to add to delay returned
// by the delay calculator.
void
GraphDelayCalc::annotateLoadDelays(Vertex *drvr_vertex,
const RiseFall *drvr_rf,
ArcDcalcResult &dcalc_result,
LoadPinIndexMap &load_pin_index_map,
const ArcDelay &extra_delay,
bool merge,
const DcalcAnalysisPt *dcalc_ap)
{
DcalcAPIndex ap_index = dcalc_ap->index();
const MinMax *slew_min_max = dcalc_ap->slewMinMax();
VertexOutEdgeIterator edge_iter(drvr_vertex, graph_);
while (edge_iter.hasNext()) {
Edge *wire_edge = edge_iter.next();
if (wire_edge->isWire()) {
Vertex *load_vertex = wire_edge->to(graph_);
Pin *load_pin = load_vertex->pin();
size_t load_idx = load_pin_index_map[load_pin];
ArcDelay wire_delay = dcalc_result.wireDelay(load_idx);
Slew load_slew = dcalc_result.loadSlew(load_idx);
debugPrint(debug_, "delay_calc", 3,
" %s load delay = %s slew = %s",
load_vertex->name(sdc_network_),
delayAsString(wire_delay, this),
delayAsString(load_slew, this));
if (!load_vertex->slewAnnotated(drvr_rf, slew_min_max)) {
if (drvr_vertex->slewAnnotated(drvr_rf, slew_min_max)) {
// Copy the driver slew to the load if it is annotated.
const Slew &drvr_slew = graph_->slew(drvr_vertex,drvr_rf,ap_index);
graph_->setSlew(load_vertex, drvr_rf, ap_index, drvr_slew);
}
else {
const Slew &slew = graph_->slew(load_vertex, drvr_rf, ap_index);
if (!merge
|| delayGreater(load_slew, slew, slew_min_max, this))
graph_->setSlew(load_vertex, drvr_rf, ap_index, load_slew);
}
}
if (!graph_->wireDelayAnnotated(wire_edge, drvr_rf, ap_index)) {
// Multiple timing arcs with the same output transition
// annotate the same wire edges so they must be combined
// rather than set.
const ArcDelay &delay = graph_->wireArcDelay(wire_edge, drvr_rf, ap_index);
Delay wire_delay_extra = extra_delay + wire_delay;
const MinMax *delay_min_max = dcalc_ap->delayMinMax();
if (!merge
|| delayGreater(wire_delay_extra, delay, delay_min_max, this)) {
graph_->setWireArcDelay(wire_edge, drvr_rf, ap_index, wire_delay_extra);
if (observer_)
observer_->delayChangedTo(load_vertex);
}
}
// Enqueue bidirect driver from load vertex.
if (sdc_->bidirectDrvrSlewFromLoad(load_pin))
iter_->enqueue(graph_->pinDrvrVertex(load_pin));
}
}
}
PinSeq
GraphDelayCalc::loadPins(Vertex *drvr_vertex)
{
PinSeq load_pins;
VertexOutEdgeIterator edge_iter(drvr_vertex, graph_);
while (edge_iter.hasNext()) {
Edge *wire_edge = edge_iter.next();
if (wire_edge->isWire()) {
Vertex *load_vertex = wire_edge->to(graph_);
load_pins.push_back(load_vertex->pin());
}
}
return load_pins;
}
LoadPinIndexMap
GraphDelayCalc::makeLoadPinIndexMap(Vertex *drvr_vertex)
{
LoadPinIndexMap load_pin_index_map(network_);
size_t load_idx = 0;
VertexOutEdgeIterator edge_iter(drvr_vertex, graph_);
while (edge_iter.hasNext()) {
Edge *wire_edge = edge_iter.next();
if (wire_edge->isWire()) {
Vertex *load_vertex = wire_edge->to(graph_);
const Pin *load_pin = load_vertex->pin();
load_pin_index_map[load_pin] = load_idx;
load_idx++;
}
}
return load_pin_index_map;
}
float
GraphDelayCalc::loadCap(const Pin *drvr_pin,
const DcalcAnalysisPt *dcalc_ap) const
@ -866,9 +1132,8 @@ GraphDelayCalc::loadCap(const Pin *drvr_pin,
const MinMax *min_max = dcalc_ap->constraintMinMax();
float load_cap = 0.0;
for (auto drvr_rf : RiseFall::range()) {
Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf,
dcalc_ap);
float cap = loadCap(drvr_pin, drvr_parasitic, drvr_rf, dcalc_ap, nullptr);
Parasitic *parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, dcalc_ap);
float cap = loadCap(drvr_pin, parasitic, drvr_rf, dcalc_ap, nullptr);
arc_delay_calc_->finishDrvrPin();
if (min_max->compare(cap, load_cap))
load_cap = cap;
@ -881,24 +1146,24 @@ GraphDelayCalc::loadCap(const Pin *drvr_pin,
const RiseFall *drvr_rf,
const DcalcAnalysisPt *dcalc_ap) const
{
Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf,
Parasitic *parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf,
dcalc_ap);
float cap = loadCap(drvr_pin, drvr_parasitic, drvr_rf, dcalc_ap, nullptr);
float cap = loadCap(drvr_pin, parasitic, drvr_rf, dcalc_ap, nullptr);
return cap;
}
float
GraphDelayCalc::loadCap(const Pin *drvr_pin,
const Parasitic *drvr_parasitic,
const Parasitic *parasitic,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) const
{
return loadCap(drvr_pin, drvr_parasitic, rf, dcalc_ap, nullptr);
return loadCap(drvr_pin, parasitic, rf, dcalc_ap, nullptr);
}
float
GraphDelayCalc::loadCap(const Pin *drvr_pin,
const Parasitic *drvr_parasitic,
const Parasitic *parasitic,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
const MultiDrvrNet *multi_drvr) const
@ -912,13 +1177,13 @@ GraphDelayCalc::loadCap(const Pin *drvr_pin,
else
netCaps(drvr_pin, rf, dcalc_ap,
pin_cap, wire_cap, fanout, has_net_load);
loadCap(drvr_parasitic, has_net_load, pin_cap, wire_cap);
loadCap(parasitic, has_net_load, pin_cap, wire_cap);
return wire_cap + pin_cap;
}
void
GraphDelayCalc::loadCap(const Pin *drvr_pin,
const Parasitic *drvr_parasitic,
const Parasitic *parasitic,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
@ -930,23 +1195,23 @@ GraphDelayCalc::loadCap(const Pin *drvr_pin,
// Find pin and external pin/wire capacitance.
netCaps(drvr_pin, rf, dcalc_ap,
pin_cap, wire_cap, fanout, has_net_load);
loadCap(drvr_parasitic, has_net_load, pin_cap, wire_cap);
loadCap(parasitic, has_net_load, pin_cap, wire_cap);
}
void
GraphDelayCalc::loadCap(const Parasitic *drvr_parasitic,
GraphDelayCalc::loadCap(const Parasitic *parasitic,
bool has_net_load,
// Return values.
float &pin_cap,
float &wire_cap) const
{
// set_load net has precidence over parasitics.
if (!has_net_load && drvr_parasitic) {
if (parasitics_->isParasiticNetwork(drvr_parasitic))
wire_cap += parasitics_->capacitance(drvr_parasitic);
if (!has_net_load && parasitic) {
if (parasitics_->isParasiticNetwork(parasitic))
wire_cap += parasitics_->capacitance(parasitic);
else {
// PiModel includes both pin and external caps.
float cap = parasitics_->capacitance(drvr_parasitic);
float cap = parasitics_->capacitance(parasitic);
if (pin_cap > cap) {
pin_cap = 0.0;
wire_cap = cap;
@ -1049,80 +1314,6 @@ GraphDelayCalc::initWireDelays(Vertex *drvr_vertex)
}
}
// Call the arc delay calculator to find the delay thru a single gate
// input to output timing arc, The wire delays from the gate output to
// each load pin, and the slew at each load pin. Annotate the graph
// with the results.
bool
GraphDelayCalc::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)
{
bool delay_changed = false;
RiseFall *from_rf = arc->fromEdge()->asRiseFall();
RiseFall *drvr_rf = arc->toEdge()->asRiseFall();
if (from_rf && drvr_rf) {
DcalcAPIndex ap_index = dcalc_ap->index();
debugPrint(debug_, "delay_calc", 3,
" %s %s -> %s %s (%s) corner:%s/%s",
arc->from()->name(),
arc->fromEdge()->asString(),
arc->to()->name(),
arc->toEdge()->asString(),
arc->role()->asString(),
dcalc_ap->corner()->name(),
dcalc_ap->delayMinMax()->asString());
// Delay calculation is done even when the gate delays/slews are
// annotated because the wire delays may not be annotated.
const Slew from_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap);
ArcDelay gate_delay;
Slew gate_slew;
float load_cap = loadCap(drvr_pin, drvr_parasitic, drvr_rf, dcalc_ap, multi_drvr);
if (multi_drvr
&& multi_drvr->parallelGates(network_))
arc_delay_calc->parallelGateDelay(drvr_pin, arc, from_slew, load_cap,
drvr_parasitic, related_out_cap, pvt, dcalc_ap,
gate_delay, gate_slew);
else
arc_delay_calc->gateDelay(arc, from_slew, load_cap, drvr_parasitic,
related_out_cap, pvt, dcalc_ap,
gate_delay, gate_slew);
debugPrint(debug_, "delay_calc", 3,
" gate delay = %s slew = %s",
delayAsString(gate_delay, this),
delayAsString(gate_slew, this));
// Merge slews.
const Slew &drvr_slew = graph_->slew(drvr_vertex, drvr_rf, ap_index);
const MinMax *slew_min_max = dcalc_ap->slewMinMax();
if (delayGreater(gate_slew, drvr_slew, dcalc_ap->slewMinMax(), this)
&& !drvr_vertex->slewAnnotated(drvr_rf, slew_min_max)
&& !edge->role()->isLatchDtoQ())
graph_->setSlew(drvr_vertex, drvr_rf, ap_index, gate_slew);
if (!graph_->arcDelayAnnotated(edge, arc, ap_index)) {
const ArcDelay &prev_gate_delay = graph_->arcDelay(edge,arc,ap_index);
float gate_delay1 = delayAsFloat(gate_delay);
float prev_gate_delay1 = delayAsFloat(prev_gate_delay);
if (prev_gate_delay1 == 0.0
|| (abs(gate_delay1 - prev_gate_delay1) / prev_gate_delay1
> incremental_delay_tolerance_))
delay_changed = true;
graph_->setArcDelay(edge, arc, ap_index, gate_delay);
}
if (!edge->role()->isLatchDtoQ())
annotateLoadDelays(drvr_vertex, drvr_rf, delay_zero, true, dcalc_ap,
arc_delay_calc);
}
return delay_changed;
}
// Use clock slew for register/latch clk->q edges.
Slew
GraphDelayCalc::edgeFromSlew(const Vertex *from_vertex,
@ -1139,69 +1330,6 @@ GraphDelayCalc::edgeFromSlew(const Vertex *from_vertex,
return graph_->slew(from_vertex, from_rf, dcalc_ap->index());
}
// Annotate wire arc delays and load pin slews.
// extra_delay is additional wire delay to add to delay returned
// by the delay calculator.
void
GraphDelayCalc::annotateLoadDelays(Vertex *drvr_vertex,
const RiseFall *drvr_rf,
const ArcDelay &extra_delay,
bool merge,
const DcalcAnalysisPt *dcalc_ap,
ArcDelayCalc *arc_delay_calc)
{
DcalcAPIndex ap_index = dcalc_ap->index();
const MinMax *slew_min_max = dcalc_ap->slewMinMax();
VertexOutEdgeIterator edge_iter(drvr_vertex, graph_);
while (edge_iter.hasNext()) {
Edge *wire_edge = edge_iter.next();
if (wire_edge->isWire()) {
Vertex *load_vertex = wire_edge->to(graph_);
Pin *load_pin = load_vertex->pin();
ArcDelay wire_delay;
Slew load_slew;
arc_delay_calc->loadDelay(load_pin, wire_delay, load_slew);
debugPrint(debug_, "delay_calc", 3,
" %s load delay = %s slew = %s",
load_vertex->name(sdc_network_),
delayAsString(wire_delay, this),
delayAsString(load_slew, this));
if (!load_vertex->slewAnnotated(drvr_rf, slew_min_max)) {
if (drvr_vertex->slewAnnotated(drvr_rf, slew_min_max)) {
// Copy the driver slew to the load if it is annotated.
const Slew &drvr_slew = graph_->slew(drvr_vertex,drvr_rf,ap_index);
graph_->setSlew(load_vertex, drvr_rf, ap_index, drvr_slew);
}
else {
const Slew &slew = graph_->slew(load_vertex, drvr_rf, ap_index);
if (!merge
|| delayGreater(load_slew, slew, slew_min_max, this))
graph_->setSlew(load_vertex, drvr_rf, ap_index, load_slew);
}
}
if (!graph_->wireDelayAnnotated(wire_edge, drvr_rf, ap_index)) {
// Multiple timing arcs with the same output transition
// annotate the same wire edges so they must be combined
// rather than set.
const ArcDelay &delay = graph_->wireArcDelay(wire_edge, drvr_rf,
ap_index);
Delay wire_delay_extra = extra_delay + wire_delay;
const MinMax *delay_min_max = dcalc_ap->delayMinMax();
if (!merge
|| delayGreater(wire_delay_extra, delay, delay_min_max, this)) {
graph_->setWireArcDelay(wire_edge, drvr_rf, ap_index,
wire_delay_extra);
if (observer_)
observer_->delayChangedTo(load_vertex);
}
}
// Enqueue bidirect driver from load vertex.
if (sdc_->bidirectDrvrSlewFromLoad(load_pin))
iter_->enqueue(graph_->pinDrvrVertex(load_pin));
}
}
}
void
GraphDelayCalc::findCheckEdgeDelays(Edge *edge,
ArcDelayCalc *arc_delay_calc)
@ -1227,9 +1355,6 @@ GraphDelayCalc::findCheckEdgeDelays(Edge *edge,
for (auto dcalc_ap : corners_->dcalcAnalysisPts()) {
DcalcAPIndex ap_index = dcalc_ap->index();
if (!graph_->arcDelayAnnotated(edge, arc, ap_index)) {
const Pvt *pvt = sdc_->pvt(inst,dcalc_ap->constraintMinMax());
if (pvt == nullptr)
pvt = dcalc_ap->operatingConditions();
const Slew &from_slew = checkEdgeClkSlew(from_vertex, from_rf,
dcalc_ap);
int slew_index = dcalc_ap->checkDataSlewIndex();
@ -1253,9 +1378,9 @@ GraphDelayCalc::findCheckEdgeDelays(Edge *edge,
related_out_parasitic,
to_rf, dcalc_ap);
}
ArcDelay check_delay;
arc_delay_calc->checkDelay(arc, from_slew, to_slew, related_out_cap,
pvt, dcalc_ap, check_delay);
ArcDelay check_delay = arc_delay_calc->checkDelay(to_pin, arc, from_slew,
to_slew, related_out_cap,
dcalc_ap);
debugPrint(debug_, "delay_calc", 3,
" check_delay = %s",
delayAsString(check_delay, this));
@ -1285,47 +1410,6 @@ GraphDelayCalc::checkEdgeClkSlew(const Vertex *from_vertex,
////////////////////////////////////////////////////////////////
float
GraphDelayCalc::ceff(Edge *edge,
TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap)
{
Vertex *from_vertex = edge->from(graph_);
Vertex *to_vertex = edge->to(graph_);
Pin *to_pin = to_vertex->pin();
Instance *inst = network_->instance(to_pin);
const TimingArcSet *arc_set = edge->timingArcSet();
float ceff = 0.0;
const Pvt *pvt = sdc_->pvt(inst, dcalc_ap->constraintMinMax());
if (pvt == nullptr)
pvt = dcalc_ap->operatingConditions();
RiseFall *from_rf = arc->fromEdge()->asRiseFall();
RiseFall *to_rf = arc->toEdge()->asRiseFall();
if (from_rf && to_rf) {
const LibertyPort *related_out_port = arc_set->relatedOut();
const Pin *related_out_pin = 0;
if (related_out_port)
related_out_pin = network_->findPin(inst, related_out_port);
float related_out_cap = 0.0;
if (related_out_pin) {
Parasitic *related_out_parasitic =
arc_delay_calc_->findParasitic(related_out_pin, to_rf, dcalc_ap);
related_out_cap = loadCap(related_out_pin, related_out_parasitic,
to_rf, dcalc_ap);
}
Parasitic *to_parasitic = arc_delay_calc_->findParasitic(to_pin, to_rf,
dcalc_ap);
const Slew &from_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap);
float load_cap = loadCap(to_pin, to_parasitic, to_rf, dcalc_ap);
ceff = arc_delay_calc_->ceff(arc, from_slew, load_cap, to_parasitic,
related_out_cap, pvt, dcalc_ap);
arc_delay_calc_->finishDrvrPin();
}
return ceff;
}
////////////////////////////////////////////////////////////////
string
GraphDelayCalc::reportDelayCalc(const Edge *edge,
const TimingArc *arc,
@ -1341,9 +1425,6 @@ GraphDelayCalc::reportDelayCalc(const Edge *edge,
const TimingArcSet *arc_set = edge->timingArcSet();
string result;
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
const Pvt *pvt = sdc_->pvt(inst, dcalc_ap->constraintMinMax());
if (pvt == nullptr)
pvt = dcalc_ap->operatingConditions();
RiseFall *from_rf = arc->fromEdge()->asRiseFall();
RiseFall *to_rf = arc->toEdge()->asRiseFall();
if (from_rf && to_rf) {
@ -1364,17 +1445,19 @@ GraphDelayCalc::reportDelayCalc(const Edge *edge,
const Slew &to_slew = graph_->slew(to_vertex, to_rf, slew_index);
bool from_ideal_clk = clk_network_->isIdealClock(from_vertex->pin());
const char *from_slew_annotation = from_ideal_clk ? " (ideal clock)" : nullptr;
result = arc_delay_calc_->reportCheckDelay(arc, from_slew, from_slew_annotation,
to_slew, related_out_cap, pvt,
dcalc_ap, digits);
result = arc_delay_calc_->reportCheckDelay(to_pin, arc, from_slew,
from_slew_annotation, to_slew,
related_out_cap, dcalc_ap, digits);
}
else {
Parasitic *to_parasitic =
arc_delay_calc_->findParasitic(to_pin, to_rf, dcalc_ap);
const Slew &from_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap);
float load_cap = loadCap(to_pin, to_parasitic, to_rf, dcalc_ap);
result = arc_delay_calc_->reportGateDelay(arc, from_slew, load_cap, to_parasitic,
related_out_cap, pvt, dcalc_ap, digits);
LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(to_vertex);
result = arc_delay_calc_->reportGateDelay(to_pin, arc, from_slew, load_cap,
to_parasitic, load_pin_index_map,
dcalc_ap, digits);
}
arc_delay_calc_->finishDrvrPin();
}

View File

@ -101,132 +101,88 @@ LumpedCapDelayCalc::findParasitic(const Pin *drvr_pin,
return parasitic;
}
ReducedParasiticType
LumpedCapDelayCalc::reducedParasiticType() const
{
return ReducedParasiticType::pi_elmore;
}
float
LumpedCapDelayCalc::ceff(const TimingArc *,
const Slew &,
float load_cap,
ArcDcalcResult
LumpedCapDelayCalc::inputPortDelay(const Pin *,
float in_slew,
const RiseFall *rf,
const Parasitic *,
float,
const Pvt *,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
{
return load_cap;
const LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
return makeResult(drvr_library,rf, 0.0, in_slew, load_pin_index_map);
}
void
LumpedCapDelayCalc::gateDelay(const TimingArc *arc,
ArcDcalcResult
LumpedCapDelayCalc::gateDelay(const Pin *drvr_pin,
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)
const Parasitic *,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap)
{
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",
" in_slew = %s load_cap = %s lumped",
delayAsString(in_slew, this),
units()->capacitanceUnit()->asString(load_cap),
units()->capacitanceUnit()->asString(related_out_cap));
units()->capacitanceUnit()->asString(load_cap));
const RiseFall *rf = arc->toEdge()->asRiseFall();
const LibertyLibrary *drvr_library = arc->to()->libertyLibrary();
if (model) {
ArcDelay gate_delay1;
Slew drvr_slew1;
ArcDelay gate_delay;
Slew drvr_slew;
float in_slew1 = delayAsFloat(in_slew);
// NaNs cause seg faults during table lookup.
if (isnan(load_cap) || isnan(related_out_cap) || isnan(delayAsFloat(in_slew)))
if (isnan(load_cap) || isnan(delayAsFloat(in_slew)))
report_->error(710, "gate delay input variable is NaN");
model->gateDelay(pvt, in_slew1, load_cap, related_out_cap,
pocv_enabled_, gate_delay1, drvr_slew1);
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;
model->gateDelay(pinPvt(drvr_pin, dcalc_ap), in_slew1, load_cap, pocv_enabled_,
gate_delay, drvr_slew);
return makeResult(drvr_library, rf, gate_delay, drvr_slew, load_pin_index_map);
}
else
return makeResult(drvr_library, rf, delay_zero, delay_zero, load_pin_index_map);
}
void
LumpedCapDelayCalc::loadDelay(const Pin *load_pin,
ArcDelay &wire_delay,
Slew &load_slew)
ArcDcalcResult
LumpedCapDelayCalc::makeResult(const LibertyLibrary *drvr_library,
const RiseFall *rf,
ArcDelay gate_delay,
Slew drvr_slew,
const LoadPinIndexMap &load_pin_index_map)
{
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;
ArcDcalcResult dcalc_result(load_pin_index_map.size());
dcalc_result.setGateDelay(gate_delay);
dcalc_result.setDrvrSlew(drvr_slew);
for (auto load_pin_index : load_pin_index_map) {
const Pin *load_pin = load_pin_index.first;
size_t load_idx = load_pin_index.second;
ArcDelay wire_delay = 0.0;
thresholdAdjust(load_pin, drvr_library, rf, wire_delay, drvr_slew);
dcalc_result.setWireDelay(load_idx, wire_delay);
dcalc_result.setLoadSlew(load_idx, drvr_slew);
}
return dcalc_result;
}
string
LumpedCapDelayCalc::reportGateDelay(const TimingArc *arc,
LumpedCapDelayCalc::reportGateDelay(const Pin *check_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *,
float related_out_cap,
const Pvt *pvt,
const LoadPinIndexMap &,
const DcalcAnalysisPt *dcalc_ap,
int digits)
{
GateTimingModel *model = gateModel(arc, dcalc_ap);
if (model) {
float in_slew1 = delayAsFloat(in_slew);
return model->reportGateDelay(pvt, in_slew1, load_cap, related_out_cap,
return model->reportGateDelay(pinPvt(check_pin, dcalc_ap), in_slew1, load_cap,
false, digits);
}
return "";
}
void
LumpedCapDelayCalc::checkDelay(const TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &margin)
{
CheckTimingModel *model = checkModel(arc, dcalc_ap);
if (model) {
float from_slew1 = delayAsFloat(from_slew);
float to_slew1 = delayAsFloat(to_slew);
model->checkDelay(pvt, from_slew1, to_slew1, related_out_cap, pocv_enabled_, margin);
}
else
margin = delay_zero;
}
string
LumpedCapDelayCalc::reportCheckDelay(const 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)
{
CheckTimingModel *model = checkModel(arc, dcalc_ap);
if (model) {
float from_slew1 = delayAsFloat(from_slew);
float to_slew1 = delayAsFloat(to_slew);
return model->reportCheckDelay(pvt, from_slew1, from_slew_annotation,
to_slew1, related_out_cap, false, digits);
}
return "";
}
} // namespace

View File

@ -30,54 +30,34 @@ public:
Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
ReducedParasiticType reducedParasiticType() const 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;
float ceff(const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
ArcDcalcResult inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
void loadDelay(const Pin *load_pin,
// Return values.
ArcDelay &wire_delay,
Slew &load_slew) override;
void checkDelay(const TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &margin) override;
string reportGateDelay(const TimingArc *arc,
ArcDcalcResult gateDelay(const Pin *drvr_pin,
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,
int digits) override;
string reportCheckDelay(const TimingArc *arc,
const Slew &from_slew,
const char *from_slew_annotation,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
string reportGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
int digits) override;
protected:
ArcDcalcResult makeResult(const LibertyLibrary *drvr_library,
const RiseFall *rf,
ArcDelay gate_delay,
Slew drvr_slew,
const LoadPinIndexMap &load_pin_index_map);
};
ArcDelayCalc *

View File

@ -31,141 +31,65 @@ ParallelDelayCalc::ParallelDelayCalc(StaState *sta):
{
}
void
ParallelDelayCalc::inputPortDelay(const Pin *drvr_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
ArcDcalcResultSeq
ParallelDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args,
float load_cap,
const LoadPinIndexMap &load_pin_index_map,
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;
size_t drvr_count = dcalc_args.size();
ArcDcalcResultSeq dcalc_results(drvr_count);
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,
ArcDelay load_delay_sum = 0.0;
vector<ArcDelay> intrinsic_delays(dcalc_args.size());
vector<ArcDelay> load_delays(dcalc_args.size());
for (size_t drvr_idx = 0; drvr_idx < drvr_count; drvr_idx++) {
ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx];
ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx];
const Pin *drvr_pin = dcalc_arg.drvrPin();
const TimingArc *arc = dcalc_arg.arc();
Slew in_slew = dcalc_arg.inSlew();
ArcDcalcResult intrinsic_result =
arc_delay_calc_->gateDelay(drvr_pin, arc, in_slew, 0.0, nullptr,
load_pin_index_map, dcalc_ap);
ArcDelay intrinsic_delay = intrinsic_result.gateDelay();
intrinsic_delays[drvr_idx] = intrinsic_result.gateDelay();
ArcDcalcResult gate_result = arc_delay_calc_->gateDelay(drvr_pin, arc,
in_slew, load_cap,
dcalc_arg.parasitic(),
load_pin_index_map,
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;
}
ArcDelay gate_delay = gate_result.gateDelay();
Slew drvr_slew = gate_result.drvrSlew();
ArcDelay load_delay = gate_delay - intrinsic_delay;
load_delays[drvr_idx] = load_delay;
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;
if (!delayZero(load_delay))
load_delay_sum += 1.0 / load_delay;
if (!delayZero(drvr_slew))
slew_sum += 1.0 / drvr_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;
dcalc_result.setLoadCount(load_pin_index_map.size());
for (auto load_pin_index : load_pin_index_map) {
size_t load_idx = load_pin_index.second;
dcalc_result.setWireDelay(load_idx, gate_result.wireDelay(load_idx));
dcalc_result.setLoadSlew(load_idx, gate_result.loadSlew(load_idx));
}
}
ArcDelay gate_load_delay = delayZero(load_delay_sum)
? delay_zero
: 1.0 / load_delay_sum;
ArcDelay drvr_slew = delayZero(slew_sum) ? delay_zero : 1.0 / slew_sum;
for (size_t drvr_idx = 0; drvr_idx < drvr_count; drvr_idx++) {
ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx];
dcalc_result.setGateDelay(intrinsic_delays[drvr_idx] + gate_load_delay);
dcalc_result.setDrvrSlew(drvr_slew);
}
return dcalc_results;
}
} // namespace

View File

@ -17,52 +17,21 @@
#pragma once
#include <vector>
#include <map>
#include "DelayCalcBase.hh"
namespace sta {
// Delay calculation for parallel gates based on using parallel drive resistance.
// Delay calculation for parallel gates 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,
ParallelDelayCalc(StaState *sta);
ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &dcalc_args,
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_;
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
};
} // namespace

View File

@ -1,141 +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 "SlewDegradeDelayCalc.hh"
#include "TimingArc.hh"
#include "Liberty.hh"
#include "Network.hh"
#include "Sdc.hh"
#include "Parasitics.hh"
#include "DcalcAnalysisPt.hh"
#include "LumpedCapDelayCalc.hh"
namespace sta {
// Liberty table model lumped capacitance arc delay calculator.
// Effective capacitance is the pi model total capacitance (C1+C2).
// Wire delays are elmore delays.
// Driver slews are degraded to loads by rise/fall transition_degradation
// tables.
class SlewDegradeDelayCalc : public LumpedCapDelayCalc
{
public:
SlewDegradeDelayCalc(StaState *sta);
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 LumpedCapDelayCalc::gateDelay;
using LumpedCapDelayCalc::reportGateDelay;
private:
const Pvt *pvt_;
};
ArcDelayCalc *
makeSlewDegradeDelayCalc(StaState *sta)
{
return new SlewDegradeDelayCalc(sta);
}
SlewDegradeDelayCalc::SlewDegradeDelayCalc(StaState *sta) :
LumpedCapDelayCalc(sta)
{
}
ArcDelayCalc *
SlewDegradeDelayCalc::copy()
{
return new SlewDegradeDelayCalc(this);
}
void
SlewDegradeDelayCalc::inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap)
{
pvt_ = dcalc_ap->operatingConditions();
LumpedCapDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap);
}
void
SlewDegradeDelayCalc::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)
{
input_port_ = false;
drvr_parasitic_ = drvr_parasitic;
drvr_rf_ = arc->toEdge()->asRiseFall();
drvr_cell_ = arc->from()->libertyCell();
drvr_library_ = drvr_cell_->libertyLibrary();
pvt_ = pvt;
LumpedCapDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic,
related_out_cap, pvt, dcalc_ap,
gate_delay, drvr_slew);
}
void
SlewDegradeDelayCalc::loadDelay(const Pin *load_pin,
ArcDelay &wire_delay,
Slew &load_slew)
{
ArcDelay wire_delay1 = 0.0;
Slew load_slew1 = drvr_slew_;
bool elmore_exists = false;
float elmore = 0.0;
if (drvr_parasitic_)
parasitics_->findElmore(drvr_parasitic_, load_pin, elmore, elmore_exists);
if (elmore_exists) {
if (drvr_library_ && drvr_library_->wireSlewDegradationTable(drvr_rf_)) {
wire_delay1 = elmore;
load_slew1 = drvr_library_->degradeWireSlew(drvr_rf_,
delayAsFloat(drvr_slew_),
delayAsFloat(wire_delay1));
}
dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1);
}
thresholdAdjust(load_pin, wire_delay1, load_slew1);
wire_delay = wire_delay1;
load_slew = load_slew1 * multi_drvr_slew_factor_;
}
} // namespace

View File

@ -45,86 +45,65 @@ UnitDelayCalc::findParasitic(const Pin *,
return nullptr;
}
ReducedParasiticType
UnitDelayCalc::reducedParasiticType() const
{
return ReducedParasiticType::none;
}
void
ArcDcalcResult
UnitDelayCalc::inputPortDelay(const Pin *,
float,
const RiseFall *,
const Parasitic *,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
{
return unitDelayResult(load_pin_index_map);
}
void
UnitDelayCalc::gateDelay(const TimingArc *,
const Slew &,
float,
const Parasitic *,
float,
const Pvt *, const DcalcAnalysisPt *,
// Return values.
ArcDelay &gate_delay, Slew &drvr_slew)
{
gate_delay = units_->timeUnit()->scale();
drvr_slew = 0.0;
}
void
UnitDelayCalc::findParallelGateDelays(const MultiDrvrNet *,
GraphDelayCalc *)
{
}
void
UnitDelayCalc::parallelGateDelay(const Pin *,
ArcDcalcResult
UnitDelayCalc::gateDelay(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,
Slew &load_slew)
{
wire_delay = 0.0;
load_slew = 0.0;
}
float
UnitDelayCalc::ceff(const TimingArc *,
const Slew &,
float,
const Parasitic *,
float,
const Pvt *,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
{
return 0.0;
return unitDelayResult(load_pin_index_map);
}
ArcDcalcResultSeq
UnitDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args,
float,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *)
{
size_t drvr_count = dcalc_args.size();
ArcDcalcResultSeq dcalc_results(drvr_count);
for (size_t drvr_idx = 0; drvr_idx < drvr_count; drvr_idx++) {
ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx];
dcalc_result = unitDelayResult(load_pin_index_map);
}
return dcalc_results;
}
ArcDcalcResult
UnitDelayCalc::unitDelayResult(const LoadPinIndexMap &load_pin_index_map)
{
size_t load_count = load_pin_index_map.size();
ArcDcalcResult dcalc_result(load_count);
dcalc_result.setGateDelay(units_->timeUnit()->scale());
dcalc_result.setDrvrSlew(0.0);
for (size_t load_idx = 0; load_idx < load_count; load_idx++) {
dcalc_result.setWireDelay(load_idx, 0.0);
dcalc_result.setLoadSlew(load_idx, 0.0);
}
return dcalc_result;
}
string
UnitDelayCalc::reportGateDelay(const TimingArc *,
UnitDelayCalc::reportGateDelay(const Pin *,
const TimingArc *,
const Slew &,
float,
const Parasitic *,
float,
const Pvt *,
const LoadPinIndexMap &,
const DcalcAnalysisPt *,
int)
{
@ -133,26 +112,24 @@ UnitDelayCalc::reportGateDelay(const TimingArc *,
return result;
}
void
UnitDelayCalc::checkDelay(const TimingArc *,
ArcDelay
UnitDelayCalc::checkDelay(const Pin *,
const TimingArc *,
const Slew &,
const Slew &,
float,
const Pvt *,
const DcalcAnalysisPt *,
// Return values.
ArcDelay &margin)
const DcalcAnalysisPt *)
{
margin = units_->timeUnit()->scale();
return units_->timeUnit()->scale();
}
string
UnitDelayCalc::reportCheckDelay(const TimingArc *,
UnitDelayCalc::reportCheckDelay(const Pin *,
const TimingArc *,
const Slew &,
const char *,
const Slew &,
float,
const Pvt *,
const DcalcAnalysisPt *,
int)
{

View File

@ -29,72 +29,50 @@ public:
Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
ReducedParasiticType reducedParasiticType() const override;
void inputPortDelay(const Pin *port_pin,
ArcDcalcResult inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
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 findParallelGateDelays(const MultiDrvrNet *multi_drvr,
GraphDelayCalc *dcalc) override;
// Retrieve the delay and slew for one parallel gate.
void parallelGateDelay(const Pin *drvr_pin,
ArcDcalcResult gateDelay(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;
float ceff(const TimingArc *arc,
const Slew &in_slew,
// Pass in load_cap or parasitic.
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
void checkDelay(const TimingArc *arc,
ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &args,
float load_cap,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) override;
ArcDelay checkDelay(const Pin *check_pin,
const TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &margin) override;
string reportGateDelay(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) override;
string reportGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
int digits) override;
string reportCheckDelay(const TimingArc *arc,
string reportCheckDelay(const Pin *check_pin,
const 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) override;
void finishDrvrPin() override;
protected:
ArcDcalcResult unitDelayResult(const LoadPinIndexMap &load_pin_index_map);
};
ArcDelayCalc *

View File

@ -18,10 +18,14 @@
#include <string>
#include <vector>
#include <map>
#include "MinMax.hh"
#include "LibertyClass.hh"
#include "TimingArc.hh"
#include "TableModel.hh"
#include "NetworkClass.hh"
#include "GraphClass.hh"
#include "Delay.hh"
#include "ParasiticsClass.hh"
#include "StaState.hh"
@ -30,18 +34,77 @@ namespace sta {
using std::string;
using std::vector;
using std::map;
class Corner;
class Parasitic;
class DcalcAnalysisPt;
class MultiDrvrNet;
// Driver load pin -> index in driver loads.
typedef map<const Pin *, size_t, PinIdLess> LoadPinIndexMap;
// Arguments for gate delay calculation delay/slew at one driver pin
// through one timing arc at one delay calc analysis point.
class ArcDcalcArg
{
public:
ArcDcalcArg();
ArcDcalcArg(const Pin *drvr_pin,
Edge *edge,
const TimingArc *arc,
const Slew in_slew,
const Parasitic *parasitic);
const Pin *drvrPin() const { return drvr_pin_; }
Edge *edge() const { return edge_; }
const TimingArc *arc() const { return arc_; }
Slew inSlew() const { return in_slew_; }
const Parasitic *parasitic() { return parasitic_; }
void setParasitic(const Parasitic *parasitic);
protected:
const Pin *drvr_pin_;
Edge *edge_;
const TimingArc *arc_;
Slew in_slew_;
const Parasitic *parasitic_;
};
// Arc delay calc result.
class ArcDcalcResult
{
public:
ArcDcalcResult();
ArcDcalcResult(size_t load_count);
void setLoadCount(size_t load_count);
ArcDelay &gateDelay() { return gate_delay_; }
void setGateDelay(ArcDelay gate_delay);
Slew &drvrSlew() { return drvr_slew_; }
void setDrvrSlew(Slew drvr_slew);
ArcDelay wireDelay(size_t load_idx) const;
void setWireDelay(size_t load_idx,
ArcDelay wire_delay);
Slew loadSlew(size_t load_idx) const;
void setLoadSlew(size_t load_idx,
Slew load_slew);
protected:
ArcDelay gate_delay_;
Slew drvr_slew_;
// Load wire delay and slews indexed by load pin index.
vector<ArcDelay> wire_delays_;
vector<Slew> load_slews_;
};
typedef vector<ArcDcalcArg> ArcDcalcArgSeq;
typedef vector<ArcDcalcResult> ArcDcalcResultSeq;
// Delay calculator class hierarchy.
// ArcDelayCalc
// UnitDelayCalc
// DelayCalcBase
// ParallelDelayCalc
// LumpedCapDelayCalc
// SlewDegradeDelayCalc
// DmpCeffDelayCalc
// DmpCeffElmoreDelayCalc
// DmpCeffTwoPoleDelayCalc
@ -61,95 +124,68 @@ public:
virtual Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) = 0;
virtual ReducedParasiticType reducedParasiticType() const = 0;
// Find the wire delays and slews for an input port without a driving cell.
// This call primarily initializes the load delay/slew iterator.
virtual void inputPortDelay(const Pin *port_pin,
virtual ArcDcalcResult inputPortDelay(const Pin *port_pin,
float in_slew,
const RiseFall *rf,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) = 0;
// Find the delay and slew for arc driving drvr_pin.
virtual ArcDcalcResult gateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
// Pass in load_cap or parasitic.
float load_cap,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) = 0;
virtual void gateDelay(const TimingArc *arc,
const Slew &in_slew,
// Pass in load_cap or drvr_parasitic.
float load_cap,
const Parasitic *drvr_parasitic,
const Parasitic *parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew) = 0;
Slew &drvr_slew) __attribute__ ((deprecated));
// 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,
virtual ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &args,
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;
// Ceff for parasitics with pi models.
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 LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap) = 0;
// 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 TimingArc *arc,
virtual ArcDelay checkDelay(const Pin *check_pin,
const TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &margin) = 0;
const DcalcAnalysisPt *dcalc_ap) = 0;
// Report delay and slew calculation.
virtual string reportGateDelay(const TimingArc *arc,
virtual string reportGateDelay(const Pin *drvr_pin,
const TimingArc *arc,
const Slew &in_slew,
// Pass in load_cap or drvr_parasitic.
float load_cap,
const Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const Parasitic *parasitic,
const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
int digits) = 0;
// Report timing check delay calculation.
virtual string reportCheckDelay(const TimingArc *arc,
virtual string reportCheckDelay(const Pin *check_pin,
const 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) = 0;
virtual void finishDrvrPin() = 0;
protected:
GateTimingModel *gateModel(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const;
CheckTimingModel *checkModel(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const;
TimingModel *model(const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) const;
};
} // namespace

View File

@ -25,10 +25,12 @@
#include "DcalcAnalysisPt.hh"
#include "StaState.hh"
#include "Delay.hh"
#include "ArcDelayCalc.hh"
namespace sta {
using std::vector;
using std::map;
class DelayCalcObserver;
class MultiDrvrNet;
@ -79,7 +81,7 @@ public:
// 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,
const Parasitic *drvr_parasitic,
const Parasitic *parasitic,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
@ -87,11 +89,11 @@ public:
float &wire_cap) const;
// Load pin_cap + wire_cap including parasitic.
virtual float loadCap(const Pin *drvr_pin,
const Parasitic *drvr_parasitic,
const Parasitic *parasitic,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) const;
float loadCap(const Pin *drvr_pin,
const Parasitic *drvr_parasitic,
const Parasitic *parasitic,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
const MultiDrvrNet *multi_drvr) const;
@ -103,9 +105,13 @@ public:
float &wire_cap,
float &fanout,
bool &has_set_load) const;
float ceff(Edge *edge,
TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap);
PinSeq loadPins(Vertex *drvr_vertex);
LoadPinIndexMap makeLoadPinIndexMap(Vertex *drvr_vertex);
void findDriverArcDelays(Vertex *drvr_vertex,
Edge *edge,
const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap,
ArcDelayCalc *arc_delay_calc);
// Precedence:
// SDF annotation
// Liberty library
@ -176,12 +182,29 @@ protected:
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,
bool findDriverEdgeDelays(Vertex *drvr_vertex,
const MultiDrvrNet *multi_drvr,
Edge *edge,
ArcDelayCalc *arc_delay_calc);
bool findDriverArcDelays(Vertex *drvr_vertex,
const MultiDrvrNet *multi_drvr,
Edge *edge,
const TimingArc *arc,
LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
ArcDelayCalc *arc_delay_calc);
ArcDcalcArgSeq makeArcDcalcArgs(Vertex *drvr_vertex,
const MultiDrvrNet *multi_drvr,
Edge *edge,
const TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap,
ArcDelayCalc *arc_delay_calc);
void findParallelEdge(Vertex *vertex,
Edge *drvr_edge,
const TimingArc *drvr_arc,
// Return values.
Edge *&edge,
const TimingArc *&arc);
void initWireDelays(Vertex *drvr_vertex);
void initRootSlews(Vertex *vertex);
void zeroSlewAndWireDelays(Vertex *drvr_vertex);
@ -189,23 +212,24 @@ protected:
ArcDelayCalc *arc_delay_calc,
bool propagate);
void enqueueTimingChecksEdges(Vertex *vertex);
bool findArcDelay(const Pin *drvr_pin,
Vertex *drvr_vertex,
bool annotateDelaysSlews(Edge *edge,
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);
ArcDcalcResult &dcalc_result,
LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap);
bool annotateDelaySlew(Edge *edge,
const TimingArc *arc,
ArcDelay &gate_delay,
Slew &gate_slew,
const DcalcAnalysisPt *dcalc_ap);
void annotateLoadDelays(Vertex *drvr_vertex,
const RiseFall *drvr_rf,
ArcDcalcResult &dcalc_result,
LoadPinIndexMap &load_pin_index_map,
const ArcDelay &extra_delay,
bool merge,
const DcalcAnalysisPt *dcalc_ap,
ArcDelayCalc *arc_delay_calc);
const DcalcAnalysisPt *dcalc_ap);
void findLatchEdgeDelays(Edge *edge);
void findCheckEdgeDelays(Edge *edge,
ArcDelayCalc *arc_delay_calc);
@ -215,7 +239,7 @@ protected:
const DcalcAnalysisPt *dcalc_ap);
bool bidirectDrvrSlewFromLoad(const Vertex *vertex) const;
MultiDrvrNet *multiDrvrNet(const Vertex *drvr_vertex) const;
void loadCap(const Parasitic *drvr_parasitic,
void loadCap(const Parasitic *parasitic,
bool has_set_load,
// Return values.
float &pin_cap,

View File

@ -29,7 +29,6 @@ public:
void gateDelay(const Pvt *pvt,
float in_slew,
float load_cap,
float related_out_cap,
bool pocv_enabled,
// Return values.
ArcDelay &gate_delay,
@ -37,7 +36,6 @@ public:
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 Pvt *pvt) const override;
@ -54,13 +52,11 @@ class CheckLinearModel : public CheckTimingModel
public:
explicit CheckLinearModel(LibertyCell *cell,
float intrinsic);
void checkDelay(const Pvt *pvt,
ArcDelay checkDelay(const Pvt *pvt,
float from_slew,
float to_slew,
float related_out_cap,
bool pocv_enabled,
// Return values.
ArcDelay &margin) const override;
bool pocv_enabled) const override;
string reportCheckDelay(const Pvt *pvt,
float from_slew,
const char *from_slew_annotation,

View File

@ -62,16 +62,22 @@ public:
void gateDelay(const Pvt *pvt,
float in_slew,
float load_cap,
float related_out_cap,
bool pocv_enabled,
// Return values.
ArcDelay &gate_delay,
Slew &drvr_slew) const override;
string reportGateDelay(const Pvt *pvt,
// related_out_cap arg removed.
void gateDelay(const Pvt *pvt,
float in_slew,
float load_cap,
float related_out_cap,
bool pocv_enabled,
ArcDelay &gate_delay,
Slew &drvr_slew) const __attribute__ ((deprecated));
string reportGateDelay(const Pvt *pvt,
float in_slew,
float load_cap,
bool pocv_enabled,
int digits) const override;
float driveResistance(const Pvt *pvt) const override;
@ -130,13 +136,11 @@ public:
TableModel *model,
TableModel *sigma_models[EarlyLate::index_count]);
virtual ~CheckTableModel();
void checkDelay(const Pvt *pvt,
ArcDelay checkDelay(const Pvt *pvt,
float from_slew,
float to_slew,
float related_out_cap,
bool pocv_enabled,
// Return values.
ArcDelay &margin) const override;
bool pocv_enabled) const override;
string reportCheckDelay(const Pvt *pvt,
float from_slew,
const char *from_slew_annotation,
@ -504,9 +508,6 @@ public:
float voltageCurrent(float slew,
float cap,
float volt);
float currentVoltage(float slew,
float cap,
float current);
float referenceTime(float slew);
void setVdd(float vdd);
static bool checkAxes(const TableTemplate *tbl_template);
@ -536,7 +537,6 @@ private:
Table1Seq current_waveforms_;
Table1Seq voltage_waveforms_;
Table1Seq voltage_currents_;
Table1Seq current_voltages_;
FloatTable voltage_times_;
Table1 *ref_times_;
float vdd_;

View File

@ -46,7 +46,6 @@ public:
virtual void gateDelay(const Pvt *pvt,
float in_slew,
float load_cap,
float related_out_cap,
bool pocv_enabled,
// Return values.
ArcDelay &gate_delay,
@ -54,7 +53,6 @@ public:
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 Pvt *pvt) const = 0;
@ -66,13 +64,11 @@ class CheckTimingModel : public TimingModel
public:
CheckTimingModel(LibertyCell *cell);
// Timing check margin delay calculation.
virtual void checkDelay(const Pvt *pvt,
virtual ArcDelay checkDelay(const Pvt *pvt,
float from_slew,
float to_slew,
float related_out_cap,
bool pocv_enabled,
// Return values.
ArcDelay &margin) const = 0;
bool pocv_enabled) const = 0;
virtual string reportCheckDelay(const Pvt *pvt,
float from_slew,
const char *from_slew_annotation,

View File

@ -2583,7 +2583,7 @@ LibertyPort::clockTreePathDelays()
GateTimingModel *gate_model = dynamic_cast<GateTimingModel*>(model);
ArcDelay delay;
Slew slew;
gate_model->gateDelay(nullptr, 0.0, 0.0, 0.0, false, delay, slew);
gate_model->gateDelay(nullptr, 0.0, 0.0, false, delay, slew);
const RiseFall *rf = arc->toEdge()->asRiseFall();
const MinMax *min_max = (role == TimingRole::clockTreePathMin())
? MinMax::min()

View File

@ -182,17 +182,13 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell,
&& seq->data()->hasPort(from_port))
// Latch D->Q timing arcs.
return makeLatchDtoQArcs(cell, from_port, to_port,
seq->data()->portTimingSense(from_port),
related_out, attrs);
seq->data()->portTimingSense(from_port), attrs);
else
return makeCombinationalArcs(cell, from_port, to_port, related_out,
true, true, attrs);
return makeCombinationalArcs(cell, from_port, to_port, true, true, attrs);
case TimingType::combinational_fall:
return makeCombinationalArcs(cell, from_port, to_port, related_out,
false, true, attrs);
return makeCombinationalArcs(cell, from_port, to_port, false, true, attrs);
case TimingType::combinational_rise:
return makeCombinationalArcs(cell, from_port, to_port, related_out,
true, false, attrs);
return makeCombinationalArcs(cell, from_port, to_port, true, false, attrs);
case TimingType::setup_rising:
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
RiseFall::rise(), TimingRole::setup(),
@ -210,17 +206,13 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell,
RiseFall::fall(), TimingRole::hold(),
attrs);
case TimingType::rising_edge:
return makeRegLatchArcs(cell, from_port, to_port, related_out,
RiseFall::rise(), attrs);
return makeRegLatchArcs(cell, from_port, to_port, RiseFall::rise(), attrs);
case TimingType::falling_edge:
return makeRegLatchArcs(cell, from_port, to_port, related_out,
RiseFall::fall(), attrs);
return makeRegLatchArcs(cell, from_port, to_port, RiseFall::fall(), attrs);
case TimingType::preset:
return makePresetClrArcs(cell, from_port, to_port, related_out,
RiseFall::rise(), attrs);
return makePresetClrArcs(cell, from_port, to_port, RiseFall::rise(), attrs);
case TimingType::clear:
return makePresetClrArcs(cell, from_port, to_port, related_out,
RiseFall::fall(), attrs);
return makePresetClrArcs(cell, from_port, to_port, RiseFall::fall(), attrs);
case TimingType::recovery_rising:
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
RiseFall::rise(),TimingRole::recovery(),
@ -238,23 +230,17 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell,
RiseFall::fall(), TimingRole::removal(),
attrs);
case TimingType::three_state_disable:
return makeTristateDisableArcs(cell, from_port, to_port, related_out,
true, true, attrs);
return makeTristateDisableArcs(cell, from_port, to_port, true, true, attrs);
case TimingType::three_state_disable_fall:
return makeTristateDisableArcs(cell, from_port, to_port, related_out,
false, true, attrs);
return makeTristateDisableArcs(cell, from_port, to_port, false, true, attrs);
case TimingType::three_state_disable_rise:
return makeTristateDisableArcs(cell, from_port, to_port, related_out,
true, false, attrs);
return makeTristateDisableArcs(cell, from_port, to_port, true, false, attrs);
case TimingType::three_state_enable:
return makeTristateEnableArcs(cell, from_port, to_port, related_out,
true, true, attrs);
return makeTristateEnableArcs(cell, from_port, to_port, true, true, attrs);
case TimingType::three_state_enable_fall:
return makeTristateEnableArcs(cell, from_port, to_port, related_out,
false, true, attrs);
return makeTristateEnableArcs(cell, from_port, to_port, false, true, attrs);
case TimingType::three_state_enable_rise:
return makeTristateEnableArcs(cell, from_port, to_port, related_out,
true, false, attrs);
return makeTristateEnableArcs(cell, from_port, to_port, true, false, attrs);
case TimingType::skew_falling:
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
RiseFall::fall(), TimingRole::skew(),
@ -282,12 +268,10 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell,
TimingRole::nonSeqHold(),
attrs);
case TimingType::min_clock_tree_path:
return makeClockTreePathArcs(cell, to_port, related_out,
TimingRole::clockTreePathMin(),
return makeClockTreePathArcs(cell, to_port, TimingRole::clockTreePathMin(),
attrs);
case TimingType::max_clock_tree_path:
return makeClockTreePathArcs(cell, to_port, related_out,
TimingRole::clockTreePathMax(),
return makeClockTreePathArcs(cell, to_port, TimingRole::clockTreePathMax(),
attrs);
case TimingType::min_pulse_width:
case TimingType::minimum_period:
@ -307,14 +291,13 @@ TimingArcSet *
LibertyBuilder::makeCombinationalArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
bool to_rise,
bool to_fall,
TimingArcAttrsPtr attrs)
{
FuncExpr *func = to_port->function();
FuncExpr *enable = to_port->tristateEnable();
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port, related_out,
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port,
TimingRole::combinational(), attrs);
TimingSense sense = attrs->timingSense();
if (sense == TimingSense::unknown) {
@ -393,11 +376,9 @@ LibertyBuilder::makeLatchDtoQArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
TimingSense sense,
LibertyPort *related_out,
TimingArcAttrsPtr attrs)
{
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port,
related_out,
TimingRole::latchDtoQ(), attrs);
TimingModel *model;
RiseFall *to_rf = RiseFall::rise();
@ -421,7 +402,6 @@ TimingArcSet *
LibertyBuilder::makeRegLatchArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
RiseFall *from_rf,
TimingArcAttrsPtr attrs)
{
@ -434,23 +414,23 @@ LibertyBuilder::makeRegLatchArcs(LibertyCell *cell,
if (seq->clock() && seq->clock()->hasPort(from_port)) {
TimingRole *role = seq->isRegister() ?
TimingRole::regClkToQ() : TimingRole::latchEnToQ();
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
return makeFromTransitionArcs(cell, from_port, to_port, nullptr,
from_rf, role, attrs);
}
else if (seq->isLatch()
&& seq->data()
&& seq->data()->hasPort(from_port))
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
return makeFromTransitionArcs(cell, from_port, to_port, nullptr,
from_rf, TimingRole::latchDtoQ(), attrs);
else if ((seq->clear() && seq->clear()->hasPort(from_port))
|| (seq->preset() && seq->preset()->hasPort(from_port)))
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
return makeFromTransitionArcs(cell, from_port, to_port, nullptr,
from_rf, TimingRole::regSetClr(), attrs);
}
}
// No associated ff/latch - assume register clk->q.
cell->setHasInferedRegTimingArcs(true);
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
return makeFromTransitionArcs(cell, from_port, to_port, nullptr,
from_rf, TimingRole::regClkToQ(), attrs);
}
@ -477,14 +457,13 @@ TimingArcSet *
LibertyBuilder::makePresetClrArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
RiseFall *to_rf,
TimingArcAttrsPtr attrs)
{
TimingArcSet *arc_set = nullptr;
TimingModel *model = attrs->model(to_rf);
if (model) {
arc_set = makeTimingArcSet(cell, from_port, to_port, related_out,
arc_set = makeTimingArcSet(cell, from_port, to_port,
TimingRole::regSetClr(), attrs);
RiseFall *opp_rf = to_rf->opposite();
switch (attrs->timingSense()) {
@ -513,12 +492,11 @@ TimingArcSet *
LibertyBuilder::makeTristateEnableArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
bool to_rise,
bool to_fall,
TimingArcAttrsPtr attrs)
{
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port, related_out,
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port,
TimingRole::tristateEnable(), attrs);
FuncExpr *tristate_enable = to_port->tristateEnable();
TimingSense sense = attrs->timingSense();
@ -584,13 +562,11 @@ TimingArcSet *
LibertyBuilder::makeTristateDisableArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
bool to_rise,
bool to_fall,
TimingArcAttrsPtr attrs)
{
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port,
related_out,
TimingRole::tristateDisable(),
attrs);
TimingSense sense = attrs->timingSense();
@ -656,12 +632,10 @@ LibertyBuilder::makeTristateDisableArcs(LibertyCell *cell,
TimingArcSet *
LibertyBuilder::makeClockTreePathArcs(LibertyCell *cell,
LibertyPort *to_port,
LibertyPort *related_out,
TimingRole *role,
TimingArcAttrsPtr attrs)
{
TimingArcSet *arc_set = makeTimingArcSet(cell, nullptr, to_port,
related_out, role, attrs);
TimingArcSet *arc_set = makeTimingArcSet(cell, nullptr, to_port, role, attrs);
for (auto to_rf : RiseFall::range()) {
TimingModel *model = attrs->model(to_rf);
if (model)
@ -670,6 +644,16 @@ LibertyBuilder::makeClockTreePathArcs(LibertyCell *cell,
return arc_set;
}
TimingArcSet *
LibertyBuilder::makeTimingArcSet(LibertyCell *cell,
LibertyPort *from,
LibertyPort *to,
TimingRole *role,
TimingArcAttrsPtr attrs)
{
return new TimingArcSet(cell, from, to, nullptr, role, attrs);
}
TimingArcSet *
LibertyBuilder::makeTimingArcSet(LibertyCell *cell,
LibertyPort *from,

View File

@ -75,13 +75,11 @@ public:
TimingArcSet *makeCombinationalArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
bool to_rise,
bool to_fall,
TimingArcAttrsPtr attrs);
TimingArcSet *makeClockTreePathArcs(LibertyCell *cell,
LibertyPort *to_port,
LibertyPort *related_out,
TimingRole *role,
TimingArcAttrsPtr attrs);
@ -105,6 +103,11 @@ protected:
ConcretePort *bus_port,
const char *bus_name,
int index);
virtual TimingArcSet *makeTimingArcSet(LibertyCell *cell,
LibertyPort *from,
LibertyPort *to,
TimingRole *role,
TimingArcAttrsPtr attrs);
virtual TimingArcSet *makeTimingArcSet(LibertyCell *cell,
LibertyPort *from,
LibertyPort *to,
@ -123,31 +126,26 @@ protected:
LibertyPort *from_port,
LibertyPort *to_port,
TimingSense sense,
LibertyPort *related_out,
TimingArcAttrsPtr attrs);
TimingArcSet *makeRegLatchArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
RiseFall *from_rf,
TimingArcAttrsPtr attrs);
TimingArcSet *makePresetClrArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
RiseFall *to_rf,
TimingArcAttrsPtr attrs);
TimingArcSet *makeTristateEnableArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
bool to_rise,
bool to_fall,
TimingArcAttrsPtr attrs);
TimingArcSet *makeTristateDisableArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
bool to_rise,
bool to_fall,
TimingArcAttrsPtr attrs);

View File

@ -34,7 +34,6 @@ void
GateLinearModel::gateDelay(const Pvt *,
float,
float load_cap,
float,
bool,
// return values
ArcDelay &gate_delay,
@ -48,7 +47,6 @@ string
GateLinearModel::reportGateDelay(const Pvt *,
float,
float load_cap,
float,
bool,
int digits) const
{
@ -87,15 +85,14 @@ CheckLinearModel::CheckLinearModel(LibertyCell *cell,
{
}
void
ArcDelay
CheckLinearModel::checkDelay(const Pvt *,
float,
float,
float,
bool,
ArcDelay &margin) const
bool) const
{
margin = intrinsic_;
return intrinsic_;
}
string

View File

@ -104,67 +104,77 @@ void
GateTableModel::gateDelay(const Pvt *pvt,
float in_slew,
float load_cap,
float related_out_cap,
bool pocv_enabled,
// return values
ArcDelay &gate_delay,
Slew &drvr_slew) const
{
float delay = findValue(pvt, delay_model_, in_slew, load_cap, related_out_cap);
float delay = findValue(pvt, delay_model_, in_slew, load_cap, 0.0);
float sigma_early = 0.0;
float sigma_late = 0.0;
if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()])
sigma_early = findValue(pvt, delay_sigma_models_[EarlyLate::earlyIndex()],
in_slew, load_cap, related_out_cap);
in_slew, load_cap, 0.0);
if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()])
sigma_late = findValue(pvt, delay_sigma_models_[EarlyLate::lateIndex()],
in_slew, load_cap, related_out_cap);
in_slew, load_cap, 0.0);
gate_delay = makeDelay(delay, sigma_early, sigma_late);
float slew = findValue(pvt, slew_model_, in_slew, load_cap, related_out_cap);
float slew = findValue(pvt, slew_model_, in_slew, load_cap, 0.0);
if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()])
sigma_early = findValue(pvt, slew_sigma_models_[EarlyLate::earlyIndex()],
in_slew, load_cap, related_out_cap);
in_slew, load_cap, 0.0);
if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()])
sigma_late = findValue(pvt, slew_sigma_models_[EarlyLate::lateIndex()],
in_slew, load_cap, related_out_cap);
in_slew, load_cap, 0.0);
// Clip negative slews to zero.
if (slew < 0.0)
slew = 0.0;
drvr_slew = makeDelay(slew, sigma_early, sigma_late);
}
void
GateTableModel::gateDelay(const Pvt *pvt,
float in_slew,
float load_cap,
float,
bool pocv_enabled,
ArcDelay &gate_delay,
Slew &drvr_slew) const
{
gateDelay(pvt, in_slew, load_cap, pocv_enabled, gate_delay, drvr_slew);
}
string
GateTableModel::reportGateDelay(const Pvt *pvt,
float in_slew,
float load_cap,
float related_out_cap,
bool pocv_enabled,
int digits) const
{
string result = reportPvt(cell_, pvt, digits);
result += reportTableLookup("Delay", pvt, delay_model_, in_slew,
load_cap, related_out_cap, digits);
load_cap, 0.0, digits);
if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()])
result += reportTableLookup("Delay sigma(early)", pvt,
delay_sigma_models_[EarlyLate::earlyIndex()],
in_slew, load_cap, related_out_cap, digits);
in_slew, load_cap, 0.0, digits);
if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()])
result += reportTableLookup("Delay sigma(late)", pvt,
delay_sigma_models_[EarlyLate::lateIndex()],
in_slew, load_cap, related_out_cap, digits);
in_slew, load_cap, 0.0, digits);
result += '\n';
result += reportTableLookup("Slew", pvt, slew_model_, in_slew,
load_cap, related_out_cap, digits);
load_cap, 9.0, digits);
if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()])
result += reportTableLookup("Slew sigma(early)", pvt,
slew_sigma_models_[EarlyLate::earlyIndex()],
in_slew, load_cap, related_out_cap, digits);
in_slew, load_cap, 0.0, digits);
if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()])
result += reportTableLookup("Slew sigma(late)", pvt,
slew_sigma_models_[EarlyLate::lateIndex()],
in_slew, load_cap, related_out_cap, digits);
float drvr_slew = findValue(pvt, slew_model_, in_slew, load_cap, related_out_cap);
in_slew, load_cap, 0.0, digits);
float drvr_slew = findValue(pvt, slew_model_, in_slew, load_cap, 0.0);
if (drvr_slew < 0.0)
result += "Negative slew clipped to 0.0\n";
return result;
@ -407,14 +417,12 @@ CheckTableModel::setIsScaled(bool is_scaled)
model_->setIsScaled(is_scaled);
}
void
ArcDelay
CheckTableModel::checkDelay(const Pvt *pvt,
float from_slew,
float to_slew,
float related_out_cap,
bool pocv_enabled,
// Return values.
ArcDelay &margin) const
bool pocv_enabled) const
{
if (model_) {
float mean = findValue(pvt, model_, from_slew, to_slew, related_out_cap);
@ -426,10 +434,10 @@ CheckTableModel::checkDelay(const Pvt *pvt,
if (pocv_enabled && 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);
return makeDelay(mean, sigma_early, sigma_late);
}
else
margin = 0.0;
return 0.0;
}
float
@ -1577,7 +1585,6 @@ OutputWaveforms::~OutputWaveforms()
current_waveforms_.deleteContents();
voltage_waveforms_.deleteContents();
voltage_currents_.deleteContents();
current_voltages_.deleteContents();
voltage_times_.deleteContents();
delete ref_times_;
}
@ -1635,15 +1642,6 @@ OutputWaveforms::voltageCurrent(float slew,
return waveformValue(slew, cap, volt, voltage_currents_);
}
float
OutputWaveforms::currentVoltage(float slew,
float cap,
float current)
{
ensureVoltages();
return waveformValue(slew, cap, current, current_voltages_);
}
float
OutputWaveforms::waveformValue(float slew,
float cap,
@ -1809,7 +1807,6 @@ OutputWaveforms::ensureVoltages()
size_t size = current_waveforms_.size();
voltage_waveforms_.resize(size);
voltage_currents_.resize(size);
current_voltages_.resize(size);
voltage_times_.resize(size);
size_t cap_count = cap_axis_->size();
for (size_t slew_index = 0; slew_index < slew_axis_->size(); slew_index++) {
@ -1858,14 +1855,6 @@ OutputWaveforms::findVoltages(size_t wave_index,
Table1 *volt_currents = new Table1(currents1, volt_axis);
voltage_currents_[wave_index] = volt_currents;
// Make current -> voltage table.
FloatSeq *axis_currents = new FloatSeq(*currents->values());
TableAxisPtr current_axis =
make_shared<TableAxis>(TableAxisVariable::input_voltage, axis_currents);
FloatSeq *volts1 = new FloatSeq(*volts);
Table1 *current_volts = new Table1(volts1, current_axis);
current_voltages_[wave_index] = current_volts;
// Sample the voltage waveform at uniform intervals to speed up
// voltage time lookup.
FloatSeq *voltage_times = new FloatSeq;

View File

@ -162,7 +162,7 @@ TimingArc::intrinsicDelay() const
if (model) {
ArcDelay arc_delay;
Slew slew;
model->gateDelay(nullptr, 0.0, 0.0, 0.0, false, arc_delay, slew);
model->gateDelay(nullptr, 0.0, 0.0, false, arc_delay, slew);
return arc_delay;
}
else

View File

@ -446,8 +446,7 @@ MakeTimingModel::makeInputOutputTimingArcs(const Pin *input_pin,
LibertyPort *output_port = modelPort(output_pin);
LibertyPort *input_port = modelPort(input_pin);
attrs->setTimingSense(output_delays.timingSense());
lib_builder_->makeCombinationalArcs(cell_, input_port,
output_port, nullptr,
lib_builder_->makeCombinationalArcs(cell_, input_port, output_port,
true, true, attrs);
}
}
@ -552,8 +551,7 @@ MakeTimingModel::findClkInsertionDelays()
TimingRole *role = (min_max == MinMax::min())
? TimingRole::clockTreePathMin()
: TimingRole::clockTreePathMax();
lib_builder_->makeClockTreePathArcs(cell_, lib_port, nullptr,
role, attrs);
lib_builder_->makeClockTreePathArcs(cell_, lib_port, role, attrs);
}
}
}
@ -655,7 +653,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(pvt, in_slew1, output_load_cap, 0.0, false,
drvr_gate_model->gateDelay(pvt, in_slew1, output_load_cap, false,
drvr_self_delay, drvr_self_slew);
const TableModel *drvr_table = drvr_gate_model->delayModel();
@ -670,7 +668,7 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin,
// get slew from driver input pin
ArcDelay gate_delay;
Slew gate_slew;
drvr_gate_model->gateDelay(pvt, in_slew1, load_cap, 0.0, false,
drvr_gate_model->gateDelay(pvt, in_slew1, load_cap, false,
gate_delay, gate_slew);
// Remove the self delay driving the output pin net load cap.
load_values->push_back(delayAsFloat(delay + gate_delay