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:
parent
6ee4340de8
commit
03afb36d01
|
|
@ -62,6 +62,7 @@ set(STA_SOURCE
|
||||||
app/StaMain.cc
|
app/StaMain.cc
|
||||||
|
|
||||||
dcalc/ArcDelayCalc.cc
|
dcalc/ArcDelayCalc.cc
|
||||||
|
dcalc/ArcDcalcWaveforms.cc
|
||||||
dcalc/ArnoldiDelayCalc.cc
|
dcalc/ArnoldiDelayCalc.cc
|
||||||
dcalc/ArnoldiReduce.cc
|
dcalc/ArnoldiReduce.cc
|
||||||
dcalc/DcalcAnalysisPt.cc
|
dcalc/DcalcAnalysisPt.cc
|
||||||
|
|
@ -73,7 +74,6 @@ set(STA_SOURCE
|
||||||
dcalc/LumpedCapDelayCalc.cc
|
dcalc/LumpedCapDelayCalc.cc
|
||||||
dcalc/NetCaps.cc
|
dcalc/NetCaps.cc
|
||||||
dcalc/ParallelDelayCalc.cc
|
dcalc/ParallelDelayCalc.cc
|
||||||
dcalc/SlewDegradeDelayCalc.cc
|
|
||||||
dcalc/UnitDelayCalc.cc
|
dcalc/UnitDelayCalc.cc
|
||||||
|
|
||||||
graph/DelayFloat.cc
|
graph/DelayFloat.cc
|
||||||
|
|
|
||||||
|
|
@ -14,14 +14,30 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#pragma once
|
#include "ArcDcalcWaveforms.hh"
|
||||||
|
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
class ArcDelayCalc;
|
Table1
|
||||||
class StaState;
|
ArcDcalcWaveforms::inputWaveform(const Pin *,
|
||||||
|
const RiseFall *,
|
||||||
|
const Corner *,
|
||||||
|
const MinMax *)
|
||||||
|
{
|
||||||
|
return Table1();
|
||||||
|
}
|
||||||
|
|
||||||
ArcDelayCalc *
|
Table1
|
||||||
makeSlewDegradeDelayCalc(StaState *sta);
|
ArcDcalcWaveforms::drvrRampWaveform(const Pin *,
|
||||||
|
const RiseFall *,
|
||||||
|
const Pin *,
|
||||||
|
const RiseFall *,
|
||||||
|
const Pin *,
|
||||||
|
const Corner *,
|
||||||
|
const MinMax *)
|
||||||
|
{
|
||||||
|
return Table1();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
@ -16,10 +16,6 @@
|
||||||
|
|
||||||
#include "ArcDelayCalc.hh"
|
#include "ArcDelayCalc.hh"
|
||||||
|
|
||||||
#include "TimingModel.hh"
|
|
||||||
#include "TimingArc.hh"
|
|
||||||
#include "GraphDelayCalc.hh"
|
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
ArcDelayCalc::ArcDelayCalc(StaState *sta):
|
ArcDelayCalc::ArcDelayCalc(StaState *sta):
|
||||||
|
|
@ -27,27 +23,114 @@ ArcDelayCalc::ArcDelayCalc(StaState *sta):
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
TimingModel *
|
void
|
||||||
ArcDelayCalc::model(const TimingArc *arc,
|
ArcDelayCalc::gateDelay(const TimingArc *arc,
|
||||||
const DcalcAnalysisPt *dcalc_ap) const
|
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();
|
LoadPinIndexMap load_pin_index_map(network_);
|
||||||
const TimingArc *corner_arc = arc->cornerArc(dcalc_ap->libertyIndex());
|
ArcDcalcResult dcalc_result = gateDelay(nullptr, arc, in_slew, load_cap, parasitic,
|
||||||
return corner_arc->model(op_cond);
|
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 *
|
ArcDcalcArg::ArcDcalcArg(const Pin *drvr_pin,
|
||||||
ArcDelayCalc::checkModel(const TimingArc *arc,
|
Edge *edge,
|
||||||
const DcalcAnalysisPt *dcalc_ap) const
|
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
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,6 @@ struct timing_table
|
||||||
const LibertyCell *cell;
|
const LibertyCell *cell;
|
||||||
const Pvt *pvt;
|
const Pvt *pvt;
|
||||||
float in_slew;
|
float in_slew;
|
||||||
float relcap;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -117,32 +117,26 @@ public:
|
||||||
Parasitic *findParasitic(const Pin *drvr_pin,
|
Parasitic *findParasitic(const Pin *drvr_pin,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const DcalcAnalysisPt *dcalc_ap) override;
|
const DcalcAnalysisPt *dcalc_ap) override;
|
||||||
ReducedParasiticType reducedParasiticType() const override;
|
ArcDcalcResult inputPortDelay(const Pin *port_pin,
|
||||||
void inputPortDelay(const Pin *port_pin,
|
float in_slew,
|
||||||
float in_slew,
|
const RiseFall *rf,
|
||||||
const RiseFall *rf,
|
const Parasitic *parasitic,
|
||||||
const Parasitic *parasitic,
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
const DcalcAnalysisPt *dcalc_ap) override;
|
const DcalcAnalysisPt *dcalc_ap) override;
|
||||||
void gateDelay(const TimingArc *arc,
|
ArcDcalcResult gateDelay(const Pin *drvr_pin,
|
||||||
const Slew &in_slew,
|
const TimingArc *arc,
|
||||||
float load_cap,
|
const Slew &in_slew,
|
||||||
const Parasitic *drvr_parasitic,
|
// Pass in load_cap or parasitic.
|
||||||
float related_out_cap,
|
float load_cap,
|
||||||
const Pvt *pvt,
|
const Parasitic *parasitic,
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
// Return values.
|
const DcalcAnalysisPt *dcalc_ap) override;
|
||||||
ArcDelay &gate_delay,
|
string reportGateDelay(const Pin *drvr_pin,
|
||||||
Slew &drvr_slew) override;
|
const TimingArc *arc,
|
||||||
void loadDelay(const Pin *load_pin,
|
|
||||||
// Return values.
|
|
||||||
ArcDelay &wire_delay,
|
|
||||||
Slew &load_slew) override;
|
|
||||||
string reportGateDelay(const TimingArc *arc,
|
|
||||||
const Slew &in_slew,
|
const Slew &in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
const Parasitic *drvr_parasitic,
|
const Parasitic *parasitic,
|
||||||
float related_out_cap,
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
const Pvt *pvt,
|
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
const DcalcAnalysisPt *dcalc_ap,
|
||||||
int digits) override;
|
int digits) override;
|
||||||
void delay_work_set_thresholds(delay_work *D,
|
void delay_work_set_thresholds(delay_work *D,
|
||||||
|
|
@ -152,14 +146,12 @@ public:
|
||||||
double derate);
|
double derate);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void gateDelaySlew(const LibertyCell *drvr_cell,
|
ArcDcalcResult gateDelaySlew(const LibertyCell *drvr_cell,
|
||||||
const GateTableModel *table_model,
|
const TimingArc *arc,
|
||||||
const Slew &in_slew,
|
const GateTableModel *table_model,
|
||||||
float related_out_cap,
|
const Slew &in_slew,
|
||||||
const Pvt *pvt,
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
// Return values.
|
const Pvt *pvt);
|
||||||
ArcDelay &gate_delay,
|
|
||||||
Slew &drvr_slew);
|
|
||||||
void ar1_ceff_delay(delay_work *D,
|
void ar1_ceff_delay(delay_work *D,
|
||||||
timing_table *tab,
|
timing_table *tab,
|
||||||
arnoldi1 *mod,
|
arnoldi1 *mod,
|
||||||
|
|
@ -224,7 +216,6 @@ private:
|
||||||
double *_delayV;
|
double *_delayV;
|
||||||
double *_slewV;
|
double *_slewV;
|
||||||
int pin_n_;
|
int pin_n_;
|
||||||
bool input_port_;
|
|
||||||
ArnoldiReduce *reduce_;
|
ArnoldiReduce *reduce_;
|
||||||
delay_work *delay_work_;
|
delay_work *delay_work_;
|
||||||
};
|
};
|
||||||
|
|
@ -306,25 +297,20 @@ ArnoldiDelayCalc::findParasitic(const Pin *drvr_pin,
|
||||||
return parasitic;
|
return parasitic;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReducedParasiticType
|
ArcDcalcResult
|
||||||
ArnoldiDelayCalc::reducedParasiticType() const
|
ArnoldiDelayCalc::inputPortDelay(const Pin *,
|
||||||
|
float in_slew,
|
||||||
|
const RiseFall *rf,
|
||||||
|
const Parasitic *parasitic,
|
||||||
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
|
const DcalcAnalysisPt *)
|
||||||
{
|
{
|
||||||
return ReducedParasiticType::arnoldi;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ArnoldiDelayCalc::inputPortDelay(const Pin *drvr_pin,
|
|
||||||
float in_slew,
|
|
||||||
const RiseFall *rf,
|
|
||||||
const Parasitic *parasitic,
|
|
||||||
const DcalcAnalysisPt *dcalc_ap)
|
|
||||||
{
|
|
||||||
LumpedCapDelayCalc::inputPortDelay(drvr_pin, in_slew, rf, parasitic, dcalc_ap);
|
|
||||||
rcmodel_ = nullptr;
|
rcmodel_ = nullptr;
|
||||||
_delayV[0] = 0.0;
|
_delayV[0] = 0.0;
|
||||||
_slewV[0] = in_slew;
|
_slewV[0] = in_slew;
|
||||||
|
|
||||||
int j;
|
LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
|
||||||
|
ArcDcalcResult dcalc_result(load_pin_index_map.size());
|
||||||
if (parasitic) {
|
if (parasitic) {
|
||||||
rcmodel_ = reinterpret_cast<rcmodel*>(const_cast<Parasitic*>(parasitic));
|
rcmodel_ = reinterpret_cast<rcmodel*>(const_cast<Parasitic*>(parasitic));
|
||||||
pin_n_ = rcmodel_->n;
|
pin_n_ = rcmodel_->n;
|
||||||
|
|
@ -335,69 +321,67 @@ ArnoldiDelayCalc::inputPortDelay(const Pin *drvr_pin,
|
||||||
_delayV = (double*)realloc(_delayV,_pinNmax * sizeof(double));
|
_delayV = (double*)realloc(_delayV,_pinNmax * sizeof(double));
|
||||||
_slewV = (double*)realloc(_slewV,_pinNmax * sizeof(double));
|
_slewV = (double*)realloc(_slewV,_pinNmax * sizeof(double));
|
||||||
}
|
}
|
||||||
pin_n_ = 1;
|
|
||||||
|
|
||||||
pin_n_ = rcmodel_->n;
|
pin_n_ = rcmodel_->n;
|
||||||
double slew_derate = drvr_library_->slewDerateFromLibrary();
|
double slew_derate = drvr_library->slewDerateFromLibrary();
|
||||||
double lo_thresh = drvr_library_->slewLowerThreshold(drvr_rf_);
|
double lo_thresh = drvr_library->slewLowerThreshold(rf);
|
||||||
double hi_thresh = drvr_library_->slewUpperThreshold(drvr_rf_);
|
double hi_thresh = drvr_library->slewUpperThreshold(rf);
|
||||||
bool rising = (drvr_rf_ == RiseFall::rise());
|
bool rising = (rf == RiseFall::rise());
|
||||||
delay_work_set_thresholds(delay_work_, lo_thresh, hi_thresh, rising,
|
delay_work_set_thresholds(delay_work_, lo_thresh, hi_thresh, rising, slew_derate);
|
||||||
slew_derate);
|
|
||||||
delay_c *c = delay_work_->c;
|
delay_c *c = delay_work_->c;
|
||||||
double c_log = c->vlg;
|
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);
|
double elmore = rcmodel_->elmore(j);
|
||||||
_delayV[j] = 0.6931472*elmore;
|
double wire_delay = 0.6931472*elmore;
|
||||||
_slewV[j] = in_slew + c_log*elmore/slew_derate;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ArnoldiDelayCalc::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_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);
|
|
||||||
else
|
else
|
||||||
LumpedCapDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic,
|
dcalc_result = makeResult(drvr_library, rf, 0.0, in_slew, load_pin_index_map);
|
||||||
related_out_cap, pvt, dcalc_ap,
|
return dcalc_result;
|
||||||
gate_delay, drvr_slew);
|
|
||||||
drvr_slew_ = drvr_slew;
|
|
||||||
multi_drvr_slew_factor_ = 1.0F;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
ArcDcalcResult
|
||||||
|
ArnoldiDelayCalc::gateDelay(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)
|
||||||
|
{
|
||||||
|
const LibertyCell *drvr_cell = arc->from()->libertyCell();
|
||||||
|
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
|
||||||
|
return LumpedCapDelayCalc::gateDelay(drvr_pin, arc, in_slew, load_cap,
|
||||||
|
parasitic, load_pin_index_map, dcalc_ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArcDcalcResult
|
||||||
ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell,
|
ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell,
|
||||||
|
const TimingArc *arc,
|
||||||
const GateTableModel *table_model,
|
const GateTableModel *table_model,
|
||||||
const Slew &in_slew,
|
const Slew &in_slew,
|
||||||
float related_out_cap,
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
const Pvt *pvt,
|
const Pvt *pvt)
|
||||||
// Return values.
|
|
||||||
ArcDelay &gate_delay,
|
|
||||||
Slew &drvr_slew)
|
|
||||||
{
|
{
|
||||||
pin_n_ = rcmodel_->n;
|
pin_n_ = rcmodel_->n;
|
||||||
if (pin_n_ >= _pinNmax) {
|
if (pin_n_ >= _pinNmax) {
|
||||||
|
|
@ -407,12 +391,15 @@ ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell,
|
||||||
_slewV = (double*)realloc(_slewV,_pinNmax * sizeof(double));
|
_slewV = (double*)realloc(_slewV,_pinNmax * sizeof(double));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArcDcalcResult dcalc_result(load_pin_index_map.size());
|
||||||
pin_n_ = rcmodel_->n;
|
pin_n_ = rcmodel_->n;
|
||||||
if (table_model) {
|
const RiseFall *rf = arc->toEdge()->asRiseFall();
|
||||||
double slew_derate = drvr_library_->slewDerateFromLibrary();
|
if (table_model && rf) {
|
||||||
double lo_thresh = drvr_library_->slewLowerThreshold(drvr_rf_);
|
const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary();
|
||||||
double hi_thresh = drvr_library_->slewUpperThreshold(drvr_rf_);
|
double slew_derate = drvr_library->slewDerateFromLibrary();
|
||||||
bool rising = (drvr_rf_ == RiseFall::rise());
|
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,
|
delay_work_set_thresholds(delay_work_, lo_thresh, hi_thresh, rising,
|
||||||
slew_derate);
|
slew_derate);
|
||||||
if (rcmodel_->order > 0) {
|
if (rcmodel_->order > 0) {
|
||||||
|
|
@ -421,48 +408,43 @@ ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell,
|
||||||
tab.cell = drvr_cell;
|
tab.cell = drvr_cell;
|
||||||
tab.pvt = pvt;
|
tab.pvt = pvt;
|
||||||
tab.in_slew = delayAsFloat(in_slew);
|
tab.in_slew = delayAsFloat(in_slew);
|
||||||
tab.relcap = related_out_cap;
|
|
||||||
ar1_ceff_delay(delay_work_, &tab, rcmodel_,
|
ar1_ceff_delay(delay_work_, &tab, rcmodel_,
|
||||||
_delayV, _slewV);
|
_delayV, _slewV);
|
||||||
}
|
}
|
||||||
gate_delay = _delayV[0];
|
dcalc_result.setGateDelay(_delayV[0]);
|
||||||
drvr_slew = _slewV[0];
|
dcalc_result.setDrvrSlew(_slewV[0]);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
if (rcmodel_) {
|
||||||
ArnoldiDelayCalc::loadDelay(const Pin *load_pin,
|
for (int i = 0; i < rcmodel_->n; i++) {
|
||||||
// Return values.
|
const Pin *load_pin = rcmodel_->pinV[i];
|
||||||
ArcDelay &wire_delay,
|
auto load_idx_itr = load_pin_index_map.find(load_pin);
|
||||||
Slew &load_slew)
|
if (load_idx_itr != load_pin_index_map.end()) {
|
||||||
{
|
size_t load_idx = load_idx_itr->second;
|
||||||
// This does not appear to handle input port parasitics correctly.
|
ArcDelay wire_delay = _delayV[i] - _delayV[0];
|
||||||
wire_delay = 0.0;
|
Slew load_slew = _slewV[i];
|
||||||
load_slew = drvr_slew_ * multi_drvr_slew_factor_;
|
thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
|
||||||
if (rcmodel_) {
|
dcalc_result.setWireDelay(load_idx, wire_delay);
|
||||||
// HACK
|
dcalc_result.setLoadSlew(load_idx, load_slew);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
thresholdAdjust(load_pin, wire_delay, load_slew);
|
return dcalc_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
string
|
string
|
||||||
ArnoldiDelayCalc::reportGateDelay(const TimingArc *,
|
ArnoldiDelayCalc::reportGateDelay(const Pin *drvr_pin,
|
||||||
const Slew &,
|
const TimingArc *arc,
|
||||||
float,
|
const Slew &in_slew,
|
||||||
const Parasitic *,
|
float load_cap,
|
||||||
float,
|
const Parasitic *parasitic,
|
||||||
const Pvt *,
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
const DcalcAnalysisPt *,
|
const DcalcAnalysisPt *dcalc_ap,
|
||||||
int)
|
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;
|
c1 = ctot;
|
||||||
ArcDelay d1;
|
ArcDelay d1;
|
||||||
Slew s1;
|
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);
|
tlohi = slew_derate*delayAsFloat(s1);
|
||||||
r = tlohi/(c_log*c1);
|
r = tlohi/(c_log*c1);
|
||||||
if (rdelay>0.0 && r > rdelay)
|
if (rdelay>0.0 && r > rdelay)
|
||||||
|
|
@ -1332,7 +1314,7 @@ ArnoldiDelayCalc::ra_get_s(delay_work *D,
|
||||||
double tlohi,smin,s;
|
double tlohi,smin,s;
|
||||||
ArcDelay d1;
|
ArcDelay d1;
|
||||||
Slew s1;
|
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);
|
tlohi = slew_derate*delayAsFloat(s1);
|
||||||
smin = r*c*c_smin; // c_smin = ra_hinv((1-vhi)/vhi-log(vhi)) + log(vhi);
|
smin = r*c*c_smin; // c_smin = ra_hinv((1-vhi)/vhi-log(vhi)) + log(vhi);
|
||||||
if (c_log*r*c >= tlohi) {
|
if (c_log*r*c >= tlohi) {
|
||||||
|
|
@ -1365,8 +1347,8 @@ ArnoldiDelayCalc::ra_rdelay_1(timing_table *tab,
|
||||||
return 0.0;
|
return 0.0;
|
||||||
ArcDelay d1, d2;
|
ArcDelay d1, d2;
|
||||||
Slew s1, s2;
|
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, c1, 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, c2, pocv_enabled_, d2, s2);
|
||||||
double dt50 = delayAsFloat(d1)-delayAsFloat(d2);
|
double dt50 = delayAsFloat(d1)-delayAsFloat(d2);
|
||||||
if (dt50 <= 0.0)
|
if (dt50 <= 0.0)
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
|
@ -1418,8 +1400,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
|
||||||
units_->timeUnit()->asString(s));
|
units_->timeUnit()->asString(s));
|
||||||
thix = ra_solve_for_t(p,s,vhi);
|
thix = ra_solve_for_t(p,s,vhi);
|
||||||
tlox = ra_solve_for_t(p,s,vlo);
|
tlox = ra_solve_for_t(p,s,vlo);
|
||||||
tab->table->gateDelay(tab->pvt,tab->in_slew, ctot, tab->relcap, pocv_enabled_,
|
tab->table->gateDelay(tab->pvt,tab->in_slew, ctot, pocv_enabled_, df, sf);
|
||||||
df, sf);
|
|
||||||
debugPrint(debug_, "arnoldi", 1, "table slew (in_slew %s ctot %s) = %s",
|
debugPrint(debug_, "arnoldi", 1, "table slew (in_slew %s ctot %s) = %s",
|
||||||
units_->timeUnit()->asString(tab->in_slew),
|
units_->timeUnit()->asString(tab->in_slew),
|
||||||
units_->capacitanceUnit()->asString(ctot),
|
units_->capacitanceUnit()->asString(ctot),
|
||||||
|
|
@ -1430,7 +1411,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
|
||||||
units_->timeUnit()->asString(tlox-thix));
|
units_->timeUnit()->asString(tlox-thix));
|
||||||
}
|
}
|
||||||
ceff = ctot;
|
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);
|
df, sf);
|
||||||
t50_sy = delayAsFloat(df);
|
t50_sy = delayAsFloat(df);
|
||||||
t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5);
|
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_->timeUnit()->asString(ceff_time),
|
||||||
units_->capacitanceUnit()->asString(ceff));
|
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_sy = delayAsFloat(df);
|
||||||
t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5);
|
t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5);
|
||||||
for (j=0;j<mod->n;j++) {
|
for (j=0;j<mod->n;j++) {
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@
|
||||||
#include "StringUtil.hh"
|
#include "StringUtil.hh"
|
||||||
#include "UnitDelayCalc.hh"
|
#include "UnitDelayCalc.hh"
|
||||||
#include "LumpedCapDelayCalc.hh"
|
#include "LumpedCapDelayCalc.hh"
|
||||||
#include "SlewDegradeDelayCalc.hh"
|
|
||||||
#include "DmpDelayCalc.hh"
|
#include "DmpDelayCalc.hh"
|
||||||
#include "ArnoldiDelayCalc.hh"
|
#include "ArnoldiDelayCalc.hh"
|
||||||
|
|
||||||
|
|
@ -35,7 +34,6 @@ registerDelayCalcs()
|
||||||
{
|
{
|
||||||
registerDelayCalc("unit", makeUnitDelayCalc);
|
registerDelayCalc("unit", makeUnitDelayCalc);
|
||||||
registerDelayCalc("lumped_cap", makeLumpedCapDelayCalc);
|
registerDelayCalc("lumped_cap", makeLumpedCapDelayCalc);
|
||||||
registerDelayCalc("slew_degrade", makeSlewDegradeDelayCalc);
|
|
||||||
registerDelayCalc("dmp_ceff_elmore", makeDmpCeffElmoreDelayCalc);
|
registerDelayCalc("dmp_ceff_elmore", makeDmpCeffElmoreDelayCalc);
|
||||||
registerDelayCalc("dmp_ceff_two_pole", makeDmpCeffTwoPoleDelayCalc);
|
registerDelayCalc("dmp_ceff_two_pole", makeDmpCeffTwoPoleDelayCalc);
|
||||||
registerDelayCalc("arnoldi", makeArnoldiDelayCalc);
|
registerDelayCalc("arnoldi", makeArnoldiDelayCalc);
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include "Sta.hh"
|
#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);
|
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
|
%} // inline
|
||||||
|
|
|
||||||
|
|
@ -18,16 +18,52 @@
|
||||||
|
|
||||||
#include "Liberty.hh"
|
#include "Liberty.hh"
|
||||||
#include "TimingArc.hh"
|
#include "TimingArc.hh"
|
||||||
|
#include "TimingModel.hh"
|
||||||
|
#include "TableModel.hh"
|
||||||
#include "Network.hh"
|
#include "Network.hh"
|
||||||
#include "Parasitics.hh"
|
#include "Parasitics.hh"
|
||||||
|
#include "Sdc.hh"
|
||||||
|
#include "DcalcAnalysisPt.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
|
using std::log;
|
||||||
|
|
||||||
DelayCalcBase::DelayCalcBase(StaState *sta) :
|
DelayCalcBase::DelayCalcBase(StaState *sta) :
|
||||||
ArcDelayCalc(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
|
void
|
||||||
DelayCalcBase::finishDrvrPin()
|
DelayCalcBase::finishDrvrPin()
|
||||||
{
|
{
|
||||||
|
|
@ -39,74 +75,53 @@ DelayCalcBase::finishDrvrPin()
|
||||||
reduced_parasitic_drvrs_.clear();
|
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
|
// For DSPF on an input port the elmore delay is used as the time
|
||||||
// constant of an exponential waveform. The delay to the logic
|
// constant of an exponential waveform. The delay to the logic
|
||||||
// threshold and slew are computed for the exponential waveform.
|
// threshold and slew are computed for the exponential waveform.
|
||||||
// Note that this uses the driver thresholds and relies on
|
// Note that this uses the driver thresholds and relies on
|
||||||
// thresholdAdjust to convert the delay and slew to the load's thresholds.
|
// thresholdAdjust to convert the delay and slew to the load's thresholds.
|
||||||
void
|
void
|
||||||
DelayCalcBase::dspfWireDelaySlew(const Pin *,
|
DelayCalcBase::dspfWireDelaySlew(const Pin *load_pin,
|
||||||
|
const RiseFall *rf,
|
||||||
|
Slew drvr_slew,
|
||||||
float elmore,
|
float elmore,
|
||||||
ArcDelay &wire_delay,
|
ArcDelay &wire_delay,
|
||||||
Slew &load_slew)
|
Slew &load_slew)
|
||||||
{
|
{
|
||||||
float vth = drvr_library_->inputThreshold(drvr_rf_);
|
|
||||||
float vl = drvr_library_->slewLowerThreshold(drvr_rf_);
|
LibertyLibrary *load_library = thresholdLibrary(load_pin);
|
||||||
float vh = drvr_library_->slewUpperThreshold(drvr_rf_);
|
float vth = load_library->inputThreshold(rf);
|
||||||
float slew_derate = drvr_library_->slewDerateFromLibrary();
|
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);
|
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
|
void
|
||||||
DelayCalcBase::thresholdAdjust(const Pin *load_pin,
|
DelayCalcBase::thresholdAdjust(const Pin *load_pin,
|
||||||
|
const LibertyLibrary *drvr_library,
|
||||||
|
const RiseFall *rf,
|
||||||
ArcDelay &load_delay,
|
ArcDelay &load_delay,
|
||||||
Slew &load_slew)
|
Slew &load_slew)
|
||||||
{
|
{
|
||||||
LibertyLibrary *load_library = thresholdLibrary(load_pin);
|
LibertyLibrary *load_library = thresholdLibrary(load_pin);
|
||||||
if (load_library
|
if (load_library
|
||||||
&& drvr_library_
|
&& drvr_library
|
||||||
&& load_library != drvr_library_) {
|
&& load_library != drvr_library) {
|
||||||
float drvr_vth = drvr_library_->outputThreshold(drvr_rf_);
|
float drvr_vth = drvr_library->outputThreshold(rf);
|
||||||
float load_vth = load_library->inputThreshold(drvr_rf_);
|
float load_vth = load_library->inputThreshold(rf);
|
||||||
float drvr_slew_delta = drvr_library_->slewUpperThreshold(drvr_rf_)
|
float drvr_slew_delta = drvr_library->slewUpperThreshold(rf)
|
||||||
- drvr_library_->slewLowerThreshold(drvr_rf_);
|
- drvr_library->slewLowerThreshold(rf);
|
||||||
float load_delay_delta =
|
float load_delay_delta =
|
||||||
delayAsFloat(load_slew) * ((load_vth - drvr_vth) / drvr_slew_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
|
||||||
: -load_delay_delta;
|
: -load_delay_delta;
|
||||||
float load_slew_delta = load_library->slewUpperThreshold(drvr_rf_)
|
float load_slew_delta = load_library->slewUpperThreshold(rf)
|
||||||
- load_library->slewLowerThreshold(drvr_rf_);
|
- load_library->slewLowerThreshold(rf);
|
||||||
float drvr_slew_derate = drvr_library_->slewDerateFromLibrary();
|
float drvr_slew_derate = drvr_library->slewDerateFromLibrary();
|
||||||
float load_slew_derate = load_library->slewDerateFromLibrary();
|
float load_slew_derate = load_library->slewDerateFromLibrary();
|
||||||
load_slew = load_slew * ((load_slew_delta / load_slew_derate)
|
load_slew = load_slew * ((load_slew_delta / load_slew_derate)
|
||||||
/ (drvr_slew_delta / drvr_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
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -20,39 +20,58 @@
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
|
class GateTableModel;
|
||||||
|
|
||||||
class DelayCalcBase : public ArcDelayCalc
|
class DelayCalcBase : public ArcDelayCalc
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit DelayCalcBase(StaState *sta);
|
explicit DelayCalcBase(StaState *sta);
|
||||||
void inputPortDelay(const Pin *port_pin,
|
void finishDrvrPin() override;
|
||||||
float in_slew,
|
|
||||||
const RiseFall *rf,
|
ArcDelay checkDelay(const Pin *check_pin,
|
||||||
const Parasitic *parasitic,
|
const TimingArc *arc,
|
||||||
|
const Slew &from_slew,
|
||||||
|
const Slew &to_slew,
|
||||||
|
float related_out_cap,
|
||||||
const DcalcAnalysisPt *dcalc_ap) override;
|
const DcalcAnalysisPt *dcalc_ap) override;
|
||||||
void finishDrvrPin() 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:
|
protected:
|
||||||
void gateDelayInit(const TimingArc *arc,
|
GateTimingModel *gateModel(const TimingArc *arc,
|
||||||
const Slew &in_slew,
|
const DcalcAnalysisPt *dcalc_ap) const;
|
||||||
const Parasitic *drvr_parasitic);
|
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.
|
// Find the liberty library to use for logic/slew thresholds.
|
||||||
LibertyLibrary *thresholdLibrary(const Pin *load_pin);
|
LibertyLibrary *thresholdLibrary(const Pin *load_pin);
|
||||||
// Adjust load_delay and load_slew from driver thresholds to load thresholds.
|
// Adjust load_delay and load_slew from driver thresholds to load thresholds.
|
||||||
void thresholdAdjust(const Pin *load_pin,
|
void thresholdAdjust(const Pin *load_pin,
|
||||||
|
const LibertyLibrary *drvr_library,
|
||||||
|
const RiseFall *rf,
|
||||||
ArcDelay &load_delay,
|
ArcDelay &load_delay,
|
||||||
Slew &load_slew);
|
Slew &load_slew);
|
||||||
// Helper function for input ports driving dspf parasitic.
|
// Helper function for input ports driving dspf parasitic.
|
||||||
void dspfWireDelaySlew(const Pin *load_pin,
|
void dspfWireDelaySlew(const Pin *load_pin,
|
||||||
float elmore,
|
const RiseFall *rf,
|
||||||
|
Slew drvr_slew,
|
||||||
|
float elmore,
|
||||||
|
// Return values.
|
||||||
ArcDelay &wire_delay,
|
ArcDelay &wire_delay,
|
||||||
Slew &load_slew);
|
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
|
// Parasitics returned by findParasitic that are reduced or estimated
|
||||||
// that can be deleted after delay calculation for the driver pin
|
// that can be deleted after delay calculation for the driver pin
|
||||||
// is finished.
|
// is finished.
|
||||||
|
|
|
||||||
159
dcalc/DmpCeff.cc
159
dcalc/DmpCeff.cc
|
|
@ -88,7 +88,6 @@ gateModelRd(const LibertyCell *cell,
|
||||||
double in_slew,
|
double in_slew,
|
||||||
double c2,
|
double c2,
|
||||||
double c1,
|
double c1,
|
||||||
float related_out_cap,
|
|
||||||
const Pvt *pvt,
|
const Pvt *pvt,
|
||||||
bool pocv_enabled);
|
bool pocv_enabled);
|
||||||
static void
|
static void
|
||||||
|
|
@ -155,7 +154,6 @@ public:
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
double rd,
|
double rd,
|
||||||
double in_slew,
|
double in_slew,
|
||||||
float related_out_cap,
|
|
||||||
double c2,
|
double c2,
|
||||||
double rpi,
|
double rpi,
|
||||||
double c1);
|
double c1);
|
||||||
|
|
@ -235,7 +233,6 @@ protected:
|
||||||
const Pvt *pvt_;
|
const Pvt *pvt_;
|
||||||
const GateTableModel *gate_model_;
|
const GateTableModel *gate_model_;
|
||||||
double in_slew_;
|
double in_slew_;
|
||||||
float related_out_cap_;
|
|
||||||
double c2_;
|
double c2_;
|
||||||
double rpi_;
|
double rpi_;
|
||||||
double c1_;
|
double c1_;
|
||||||
|
|
@ -319,7 +316,6 @@ DmpAlg::init(const LibertyLibrary *drvr_library,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
double rd,
|
double rd,
|
||||||
double in_slew,
|
double in_slew,
|
||||||
float related_out_cap,
|
|
||||||
// Pi model.
|
// Pi model.
|
||||||
double c2,
|
double c2,
|
||||||
double rpi,
|
double rpi,
|
||||||
|
|
@ -331,7 +327,6 @@ DmpAlg::init(const LibertyLibrary *drvr_library,
|
||||||
gate_model_ = gate_model;
|
gate_model_ = gate_model;
|
||||||
rd_ = rd;
|
rd_ = rd;
|
||||||
in_slew_ = in_slew;
|
in_slew_ = in_slew;
|
||||||
related_out_cap_ = related_out_cap;
|
|
||||||
c2_ = c2;
|
c2_ = c2;
|
||||||
rpi_ = rpi;
|
rpi_ = rpi;
|
||||||
c1_ = c1;
|
c1_ = c1;
|
||||||
|
|
@ -381,8 +376,8 @@ DmpAlg::gateCapDelaySlew(double ceff,
|
||||||
{
|
{
|
||||||
ArcDelay model_delay;
|
ArcDelay model_delay;
|
||||||
Slew model_slew;
|
Slew model_slew;
|
||||||
gate_model_->gateDelay(pvt_, in_slew_, ceff, related_out_cap_,
|
gate_model_->gateDelay(pvt_, in_slew_, ceff, pocv_enabled_,
|
||||||
pocv_enabled_, model_delay, model_slew);
|
model_delay, model_slew);
|
||||||
delay = delayAsFloat(model_delay);
|
delay = delayAsFloat(model_delay);
|
||||||
slew = delayAsFloat(model_slew);
|
slew = delayAsFloat(model_slew);
|
||||||
}
|
}
|
||||||
|
|
@ -696,7 +691,6 @@ public:
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
double rd,
|
double rd,
|
||||||
double in_slew,
|
double in_slew,
|
||||||
float related_out_cap,
|
|
||||||
double c2,
|
double c2,
|
||||||
double rpi,
|
double rpi,
|
||||||
double c1);
|
double c1);
|
||||||
|
|
@ -729,14 +723,13 @@ DmpCap::init(const LibertyLibrary *drvr_library,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
double rd,
|
double rd,
|
||||||
double in_slew,
|
double in_slew,
|
||||||
float related_out_cap,
|
|
||||||
double c2,
|
double c2,
|
||||||
double rpi,
|
double rpi,
|
||||||
double c1)
|
double c1)
|
||||||
{
|
{
|
||||||
debugPrint(debug_, "dmp_ceff", 3, "Using DMP cap");
|
debugPrint(debug_, "dmp_ceff", 3, "Using DMP cap");
|
||||||
DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf,
|
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;
|
ceff_ = c1 + c2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -810,7 +803,6 @@ public:
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
double rd,
|
double rd,
|
||||||
double in_slew,
|
double in_slew,
|
||||||
float related_out_cap,
|
|
||||||
double c2,
|
double c2,
|
||||||
double rpi,
|
double rpi,
|
||||||
double c1);
|
double c1);
|
||||||
|
|
@ -870,14 +862,13 @@ DmpPi::init(const LibertyLibrary *drvr_library,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
double rd,
|
double rd,
|
||||||
double in_slew,
|
double in_slew,
|
||||||
float related_out_cap,
|
|
||||||
double c2,
|
double c2,
|
||||||
double rpi,
|
double rpi,
|
||||||
double c1)
|
double c1)
|
||||||
{
|
{
|
||||||
debugPrint(debug_, "dmp_ceff", 3, "Using DMP Pi");
|
debugPrint(debug_, "dmp_ceff", 3, "Using DMP Pi");
|
||||||
DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf, rd,
|
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.
|
// Find poles/zeros.
|
||||||
z1_ = 1.0 / (rpi_ * c1_);
|
z1_ = 1.0 / (rpi_ * c1_);
|
||||||
|
|
@ -1144,7 +1135,6 @@ public:
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
double rd,
|
double rd,
|
||||||
double in_slew,
|
double in_slew,
|
||||||
float related_out_cap,
|
|
||||||
double c2,
|
double c2,
|
||||||
double rpi,
|
double rpi,
|
||||||
double c1);
|
double c1);
|
||||||
|
|
@ -1187,14 +1177,13 @@ DmpZeroC2::init(const LibertyLibrary *drvr_library,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
double rd,
|
double rd,
|
||||||
double in_slew,
|
double in_slew,
|
||||||
float related_out_cap,
|
|
||||||
double c2,
|
double c2,
|
||||||
double rpi,
|
double rpi,
|
||||||
double c1)
|
double c1)
|
||||||
{
|
{
|
||||||
debugPrint(debug_, "dmp_ceff", 3, "Using DMP C2=0");
|
debugPrint(debug_, "dmp_ceff", 3, "Using DMP C2=0");
|
||||||
DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf, rd,
|
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;
|
ceff_ = c1;
|
||||||
|
|
||||||
z1_ = 1.0 / (rpi_ * c1_);
|
z1_ = 1.0 / (rpi_ * c1_);
|
||||||
|
|
@ -1543,64 +1532,58 @@ DmpCeffDelayCalc::~DmpCeffDelayCalc()
|
||||||
delete dmp_zero_c2_;
|
delete dmp_zero_c2_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
ArcDcalcResult
|
||||||
DmpCeffDelayCalc::inputPortDelay(const Pin *port_pin,
|
DmpCeffDelayCalc::gateDelay(const Pin *drvr_pin,
|
||||||
float in_slew,
|
const TimingArc *arc,
|
||||||
const RiseFall *rf,
|
const Slew &in_slew,
|
||||||
const Parasitic *parasitic,
|
float load_cap,
|
||||||
const DcalcAnalysisPt *dcalc_ap)
|
const Parasitic *parasitic,
|
||||||
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
|
const DcalcAnalysisPt *dcalc_ap)
|
||||||
{
|
{
|
||||||
dmp_alg_ = nullptr;
|
const RiseFall *rf = arc->toEdge()->asRiseFall();
|
||||||
LumpedCapDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
DmpCeffDelayCalc::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_rf_ = arc->toEdge()->asRiseFall();
|
|
||||||
const LibertyCell *drvr_cell = arc->from()->libertyCell();
|
const LibertyCell *drvr_cell = arc->from()->libertyCell();
|
||||||
drvr_library_ = drvr_cell->libertyLibrary();
|
const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary();
|
||||||
drvr_parasitic_ = drvr_parasitic;
|
|
||||||
|
|
||||||
GateTimingModel *model = gateModel(arc, dcalc_ap);
|
GateTableModel *table_model = gateTableModel(arc, dcalc_ap);
|
||||||
GateTableModel *table_model = dynamic_cast<GateTableModel*>(model);
|
if (table_model && parasitic) {
|
||||||
if (table_model && drvr_parasitic) {
|
|
||||||
float in_slew1 = delayAsFloat(in_slew);
|
float in_slew1 = delayAsFloat(in_slew);
|
||||||
float c2, rpi, c1;
|
float c2, rpi, c1;
|
||||||
parasitics_->piModel(drvr_parasitic, c2, rpi, c1);
|
parasitics_->piModel(parasitic, c2, rpi, c1);
|
||||||
if (isnan(c2) || isnan(c1) || isnan(rpi))
|
if (isnan(c2) || isnan(c1) || isnan(rpi))
|
||||||
report_->error(618, "parasitic Pi model has NaNs.");
|
report_->error(618, "parasitic Pi model has NaNs.");
|
||||||
setCeffAlgorithm(drvr_library_, drvr_cell, pvt, table_model,
|
setCeffAlgorithm(drvr_library, drvr_cell, pinPvt(drvr_pin, dcalc_ap),
|
||||||
drvr_rf_, in_slew1, related_out_cap,
|
table_model, rf, in_slew1, c2, rpi, c1);
|
||||||
c2, rpi, c1);
|
double gate_delay, drvr_slew;
|
||||||
double dmp_gate_delay, dmp_drvr_slew;
|
gateDelaySlew(gate_delay, drvr_slew);
|
||||||
gateDelaySlew(dmp_gate_delay, dmp_drvr_slew);
|
ArcDcalcResult dcalc_result(load_pin_index_map.size());
|
||||||
gate_delay = dmp_gate_delay;
|
dcalc_result.setGateDelay(gate_delay);
|
||||||
drvr_slew = dmp_drvr_slew;
|
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 {
|
else {
|
||||||
LumpedCapDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic,
|
ArcDcalcResult dcalc_result =
|
||||||
related_out_cap, pvt, dcalc_ap,
|
LumpedCapDelayCalc::gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic,
|
||||||
gate_delay, drvr_slew);
|
load_pin_index_map, dcalc_ap);
|
||||||
if (drvr_parasitic
|
if (parasitic
|
||||||
&& !unsuppored_model_warned_) {
|
&& !unsuppored_model_warned_) {
|
||||||
unsuppored_model_warned_ = true;
|
unsuppored_model_warned_ = true;
|
||||||
report_->warn(1, "cell %s delay model not supported on SPF parasitics by DMP delay calculator",
|
report_->warn(1, "cell %s delay model not supported on SPF parasitics by DMP delay calculator",
|
||||||
drvr_cell->name());
|
drvr_cell->name());
|
||||||
}
|
}
|
||||||
|
return dcalc_result;
|
||||||
}
|
}
|
||||||
drvr_slew_ = drvr_slew;
|
|
||||||
multi_drvr_slew_factor_ = 1.0F;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1610,7 +1593,6 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library,
|
||||||
const GateTableModel *gate_model,
|
const GateTableModel *gate_model,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
double in_slew,
|
double in_slew,
|
||||||
float related_out_cap,
|
|
||||||
double c2,
|
double c2,
|
||||||
double rpi,
|
double rpi,
|
||||||
double c1)
|
double c1)
|
||||||
|
|
@ -1618,7 +1600,7 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library,
|
||||||
double rd = 0.0;
|
double rd = 0.0;
|
||||||
if (gate_model) {
|
if (gate_model) {
|
||||||
rd = gateModelRd(drvr_cell, gate_model, rf, in_slew, c2, c1,
|
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.
|
// Zero Rd means the table is constant and thus independent of load cap.
|
||||||
if (rd < 1e-2
|
if (rd < 1e-2
|
||||||
// Rpi is small compared to Rd, which makes the load capacitive.
|
// Rpi is small compared to Rd, which makes the load capacitive.
|
||||||
|
|
@ -1635,7 +1617,7 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library,
|
||||||
else
|
else
|
||||||
dmp_alg_ = dmp_cap_;
|
dmp_alg_ = dmp_cap_;
|
||||||
dmp_alg_->init(drvr_library, drvr_cell, pvt, gate_model,
|
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,
|
debugPrint(debug_, "dmp_ceff", 3,
|
||||||
" DMP in_slew = %s c2 = %s rpi = %s c1 = %s Rd = %s (%s alg)",
|
" DMP in_slew = %s c2 = %s rpi = %s c1 = %s Rd = %s (%s alg)",
|
||||||
units_->timeUnit()->asString(in_slew),
|
units_->timeUnit()->asString(in_slew),
|
||||||
|
|
@ -1646,51 +1628,29 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library,
|
||||||
dmp_alg_->name());
|
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
|
string
|
||||||
DmpCeffDelayCalc::reportGateDelay(const TimingArc *arc,
|
DmpCeffDelayCalc::reportGateDelay(const Pin *drvr_pin,
|
||||||
|
const TimingArc *arc,
|
||||||
const Slew &in_slew,
|
const Slew &in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
const Parasitic *drvr_parasitic,
|
const Parasitic *parasitic,
|
||||||
float related_out_cap,
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
const Pvt *pvt,
|
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
const DcalcAnalysisPt *dcalc_ap,
|
||||||
int digits)
|
int digits)
|
||||||
{
|
{
|
||||||
ArcDelay gate_delay;
|
gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic, load_pin_index_map, dcalc_ap);
|
||||||
Slew drvr_slew;
|
|
||||||
gateDelay(arc, in_slew, load_cap, drvr_parasitic, related_out_cap, pvt, dcalc_ap,
|
|
||||||
gate_delay, drvr_slew);
|
|
||||||
GateTimingModel *model = gateModel(arc, dcalc_ap);
|
GateTimingModel *model = gateModel(arc, dcalc_ap);
|
||||||
float c_eff = 0.0;
|
float c_eff = 0.0;
|
||||||
string result;
|
string result;
|
||||||
if (drvr_parasitic_ && dmp_alg_) {
|
if (parasitic && dmp_alg_) {
|
||||||
c_eff = dmp_alg_->ceff();
|
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 LibertyLibrary *drvr_library = drvr_cell->libertyLibrary();
|
||||||
const Units *units = drvr_library->units();
|
const Units *units = drvr_library->units();
|
||||||
const Unit *cap_unit = units->capacitanceUnit();
|
const Unit *cap_unit = units->capacitanceUnit();
|
||||||
const Unit *res_unit = units->resistanceUnit();
|
const Unit *res_unit = units->resistanceUnit();
|
||||||
float c2, rpi, c1;
|
float c2, rpi, c1;
|
||||||
parasitics_->piModel(drvr_parasitic_, c2, rpi, c1);
|
parasitics_->piModel(parasitic, c2, rpi, c1);
|
||||||
result += "Pi model C2=";
|
result += "Pi model C2=";
|
||||||
result += cap_unit->asString(c2, digits);
|
result += cap_unit->asString(c2, digits);
|
||||||
result += " Rpi=";
|
result += " Rpi=";
|
||||||
|
|
@ -1705,7 +1665,7 @@ DmpCeffDelayCalc::reportGateDelay(const TimingArc *arc,
|
||||||
c_eff = load_cap;
|
c_eff = load_cap;
|
||||||
if (model) {
|
if (model) {
|
||||||
float in_slew1 = delayAsFloat(in_slew);
|
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);
|
pocv_enabled_, digits);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -1718,7 +1678,6 @@ gateModelRd(const LibertyCell *cell,
|
||||||
double in_slew,
|
double in_slew,
|
||||||
double c2,
|
double c2,
|
||||||
double c1,
|
double c1,
|
||||||
float related_out_cap,
|
|
||||||
const Pvt *pvt,
|
const Pvt *pvt,
|
||||||
bool pocv_enabled)
|
bool pocv_enabled)
|
||||||
{
|
{
|
||||||
|
|
@ -1726,8 +1685,8 @@ gateModelRd(const LibertyCell *cell,
|
||||||
float cap2 = cap1 + 1e-15;
|
float cap2 = cap1 + 1e-15;
|
||||||
ArcDelay d1, d2;
|
ArcDelay d1, d2;
|
||||||
Slew s1, s2;
|
Slew s1, s2;
|
||||||
gate_model->gateDelay(pvt, in_slew, cap1, related_out_cap, pocv_enabled, d1, s1);
|
gate_model->gateDelay(pvt, in_slew, cap1, pocv_enabled, d1, s1);
|
||||||
gate_model->gateDelay(pvt, in_slew, cap2, related_out_cap, pocv_enabled, d2, s2);
|
gate_model->gateDelay(pvt, in_slew, cap2, pocv_enabled, d2, s2);
|
||||||
double vth = cell->libertyLibrary()->outputThreshold(rf);
|
double vth = cell->libertyLibrary()->outputThreshold(rf);
|
||||||
float rd = -log(vth) * abs(delayAsFloat(d1) - delayAsFloat(d2)) / (cap2 - cap1);
|
float rd = -log(vth) * abs(delayAsFloat(d1) - delayAsFloat(d2)) / (cap2 - cap1);
|
||||||
return rd;
|
return rd;
|
||||||
|
|
@ -1741,10 +1700,10 @@ DmpCeffDelayCalc::gateDelaySlew(double &delay,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
DmpCeffDelayCalc::loadDelaySlew(const Pin *load_pin,
|
DmpCeffDelayCalc::loadDelaySlewElmore(const Pin *load_pin,
|
||||||
double elmore,
|
double elmore,
|
||||||
ArcDelay &delay,
|
ArcDelay &delay,
|
||||||
Slew &slew)
|
Slew &slew)
|
||||||
{
|
{
|
||||||
if (dmp_alg_)
|
if (dmp_alg_)
|
||||||
dmp_alg_->loadDelaySlew(load_pin, elmore, delay, slew);
|
dmp_alg_->loadDelaySlew(load_pin, elmore, delay, slew);
|
||||||
|
|
|
||||||
|
|
@ -34,45 +34,39 @@ class DmpCeffDelayCalc : public LumpedCapDelayCalc
|
||||||
public:
|
public:
|
||||||
DmpCeffDelayCalc(StaState *sta);
|
DmpCeffDelayCalc(StaState *sta);
|
||||||
virtual ~DmpCeffDelayCalc();
|
virtual ~DmpCeffDelayCalc();
|
||||||
virtual void inputPortDelay(const Pin *port_pin,
|
ArcDcalcResult gateDelay(const Pin *drvr_pin,
|
||||||
float in_slew,
|
const TimingArc *arc,
|
||||||
const RiseFall *rf,
|
const Slew &in_slew,
|
||||||
const Parasitic *parasitic,
|
float load_cap,
|
||||||
const DcalcAnalysisPt *dcalc_ap);
|
const Parasitic *parasitic,
|
||||||
virtual void gateDelay(const TimingArc *arc,
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
const Slew &in_slew,
|
const DcalcAnalysisPt *dcalc_ap) override;
|
||||||
float load_cap,
|
string reportGateDelay(const Pin *drvr_pin,
|
||||||
const Parasitic *drvr_parasitic,
|
const TimingArc *arc,
|
||||||
float related_out_cap,
|
const Slew &in_slew,
|
||||||
const Pvt *pvt,
|
float load_cap,
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
const Parasitic *parasitic,
|
||||||
// return values
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
ArcDelay &gate_delay,
|
const DcalcAnalysisPt *dcalc_ap,
|
||||||
Slew &drvr_slew);
|
int digits) override;
|
||||||
virtual float ceff(const TimingArc *arc,
|
void copyState(const StaState *sta) override;
|
||||||
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);
|
|
||||||
|
|
||||||
protected:
|
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);
|
double &slew);
|
||||||
void loadDelaySlew(const Pin *load_pin,
|
void loadDelaySlewElmore(const Pin *load_pin,
|
||||||
double elmore,
|
double elmore,
|
||||||
ArcDelay &delay,
|
ArcDelay &delay,
|
||||||
Slew &slew);
|
Slew &slew);
|
||||||
// Select the appropriate special case Dartu/Menezes/Pileggi algorithm.
|
// Select the appropriate special case Dartu/Menezes/Pileggi algorithm.
|
||||||
void setCeffAlgorithm(const LibertyLibrary *library,
|
void setCeffAlgorithm(const LibertyLibrary *library,
|
||||||
const LibertyCell *cell,
|
const LibertyCell *cell,
|
||||||
|
|
@ -80,7 +74,6 @@ protected:
|
||||||
const GateTableModel *gate_model,
|
const GateTableModel *gate_model,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
double in_slew,
|
double in_slew,
|
||||||
float related_out_cap,
|
|
||||||
double c2,
|
double c2,
|
||||||
double rpi,
|
double rpi,
|
||||||
double c1);
|
double c1);
|
||||||
|
|
|
||||||
|
|
@ -35,9 +35,22 @@ class DmpCeffElmoreDelayCalc : public DmpCeffDelayCalc
|
||||||
public:
|
public:
|
||||||
DmpCeffElmoreDelayCalc(StaState *sta);
|
DmpCeffElmoreDelayCalc(StaState *sta);
|
||||||
ArcDelayCalc *copy() override;
|
ArcDelayCalc *copy() override;
|
||||||
void loadDelay(const Pin *load_pin,
|
ArcDcalcResult inputPortDelay(const Pin *port_pin,
|
||||||
ArcDelay &wire_delay,
|
float in_slew,
|
||||||
Slew &load_slew) override;
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
ArcDelayCalc *
|
ArcDelayCalc *
|
||||||
|
|
@ -57,26 +70,54 @@ DmpCeffElmoreDelayCalc::copy()
|
||||||
return new DmpCeffElmoreDelayCalc(this);
|
return new DmpCeffElmoreDelayCalc(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
ArcDcalcResult
|
||||||
DmpCeffElmoreDelayCalc::loadDelay(const Pin *load_pin,
|
DmpCeffElmoreDelayCalc::inputPortDelay(const Pin *,
|
||||||
ArcDelay &wire_delay,
|
float in_slew,
|
||||||
Slew &load_slew)
|
const RiseFall *rf,
|
||||||
|
const Parasitic *parasitic,
|
||||||
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
|
const DcalcAnalysisPt *)
|
||||||
{
|
{
|
||||||
ArcDelay wire_delay1 = 0.0;
|
ArcDcalcResult dcalc_result(load_pin_index_map.size());
|
||||||
Slew load_slew1 = drvr_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;
|
||||||
|
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::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)
|
||||||
|
{
|
||||||
|
wire_delay = 0.0;
|
||||||
|
load_slew = drvr_slew;
|
||||||
bool elmore_exists = false;
|
bool elmore_exists = false;
|
||||||
float elmore = 0.0;
|
float elmore = 0.0;
|
||||||
if (drvr_parasitic_)
|
if (parasitic)
|
||||||
parasitics_->findElmore(drvr_parasitic_, load_pin, elmore, elmore_exists);
|
parasitics_->findElmore(parasitic, load_pin, elmore, elmore_exists);
|
||||||
if (elmore_exists) {
|
if (elmore_exists)
|
||||||
if (input_port_)
|
loadDelaySlewElmore(load_pin, elmore, wire_delay, load_slew);
|
||||||
dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1);
|
thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
|
||||||
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_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -91,28 +132,31 @@ public:
|
||||||
Parasitic *findParasitic(const Pin *drvr_pin,
|
Parasitic *findParasitic(const Pin *drvr_pin,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const DcalcAnalysisPt *dcalc_ap) override;
|
const DcalcAnalysisPt *dcalc_ap) override;
|
||||||
ReducedParasiticType reducedParasiticType() const override;
|
ArcDcalcResult inputPortDelay(const Pin *port_pin,
|
||||||
void inputPortDelay(const Pin *port_pin,
|
float in_slew,
|
||||||
float in_slew,
|
const RiseFall *rf,
|
||||||
const RiseFall *rf,
|
const Parasitic *parasitic,
|
||||||
const Parasitic *parasitic,
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
const DcalcAnalysisPt *dcalc_ap) override;
|
const DcalcAnalysisPt *dcalc_ap) override;
|
||||||
void gateDelay(const TimingArc *arc,
|
ArcDcalcResult gateDelay(const Pin *drvr_pin,
|
||||||
const Slew &in_slew,
|
const TimingArc *arc,
|
||||||
float load_cap,
|
const Slew &in_slew,
|
||||||
const Parasitic *drvr_parasitic,
|
float load_cap,
|
||||||
float related_out_cap,
|
const Parasitic *parasitic,
|
||||||
const Pvt *pvt,
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
const DcalcAnalysisPt *dcalc_ap) override;
|
||||||
// Return values.
|
|
||||||
ArcDelay &gate_delay,
|
|
||||||
Slew &drvr_slew) override;
|
|
||||||
void loadDelay(const Pin *load_pin,
|
|
||||||
ArcDelay &wire_delay,
|
|
||||||
Slew &load_slew) override;
|
|
||||||
|
|
||||||
private:
|
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 p1,
|
||||||
double k1,
|
double k1,
|
||||||
ArcDelay &wire_delay,
|
ArcDelay &wire_delay,
|
||||||
|
|
@ -211,57 +255,81 @@ DmpCeffTwoPoleDelayCalc::findParasitic(const Pin *drvr_pin,
|
||||||
return parasitic;
|
return parasitic;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReducedParasiticType
|
ArcDcalcResult
|
||||||
DmpCeffTwoPoleDelayCalc::reducedParasiticType() const
|
DmpCeffTwoPoleDelayCalc::inputPortDelay(const Pin *,
|
||||||
|
float in_slew,
|
||||||
|
const RiseFall *rf,
|
||||||
|
const Parasitic *parasitic,
|
||||||
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
|
const DcalcAnalysisPt *)
|
||||||
{
|
{
|
||||||
return ReducedParasiticType::pi_pole_residue2;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArcDcalcResult
|
||||||
|
DmpCeffTwoPoleDelayCalc::gateDelay(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)
|
||||||
|
{
|
||||||
|
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
|
void
|
||||||
DmpCeffTwoPoleDelayCalc::inputPortDelay(const Pin *port_pin,
|
DmpCeffTwoPoleDelayCalc::loadDelaySlew(const Pin *load_pin,
|
||||||
float in_slew,
|
double drvr_slew,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const Parasitic *parasitic,
|
const LibertyLibrary *drvr_library,
|
||||||
const DcalcAnalysisPt *dcalc_ap)
|
const Parasitic *parasitic,
|
||||||
|
// Return values.
|
||||||
|
ArcDelay &wire_delay,
|
||||||
|
Slew &load_slew)
|
||||||
{
|
{
|
||||||
parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(parasitic);
|
parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(parasitic);
|
||||||
DmpCeffDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
DmpCeffTwoPoleDelayCalc::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)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
DmpCeffTwoPoleDelayCalc::loadDelay(const Pin *load_pin,
|
|
||||||
ArcDelay &wire_delay,
|
|
||||||
Slew &load_slew)
|
|
||||||
{
|
|
||||||
// Should handle PiElmore parasitic.
|
// Should handle PiElmore parasitic.
|
||||||
ArcDelay wire_delay1 = 0.0;
|
wire_delay = 0.0;
|
||||||
Slew load_slew1 = drvr_slew_;
|
load_slew = drvr_slew;
|
||||||
Parasitic *pole_residue = 0;
|
Parasitic *pole_residue = 0;
|
||||||
if (parasitic_is_pole_residue_)
|
if (parasitic_is_pole_residue_)
|
||||||
pole_residue = parasitics_->findPoleResidue(drvr_parasitic_, load_pin);
|
pole_residue = parasitics_->findPoleResidue(parasitic, load_pin);
|
||||||
if (pole_residue) {
|
if (pole_residue) {
|
||||||
size_t pole_count = parasitics_->poleResidueCount(pole_residue);
|
size_t pole_count = parasitics_->poleResidueCount(pole_residue);
|
||||||
if (pole_count >= 1) {
|
if (pole_count >= 1) {
|
||||||
|
|
@ -272,37 +340,31 @@ DmpCeffTwoPoleDelayCalc::loadDelay(const Pin *load_pin,
|
||||||
&& residue1.imag() == 0.0) {
|
&& residue1.imag() == 0.0) {
|
||||||
float p1 = pole1.real();
|
float p1 = pole1.real();
|
||||||
float k1 = residue1.real();
|
float k1 = residue1.real();
|
||||||
if (input_port_) {
|
if (pole_count >= 2)
|
||||||
float elmore = 1.0F / p1;
|
loadDelay(drvr_slew, pole_residue, p1, k1, wire_delay, load_slew);
|
||||||
// Input port with no external driver.
|
else {
|
||||||
dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1);
|
float elmore = 1.0F / p1;
|
||||||
}
|
wire_delay = elmore;
|
||||||
else {
|
load_slew = drvr_slew;
|
||||||
if (pole_count >= 2)
|
}
|
||||||
loadDelay(pole_residue, p1, k1, wire_delay1, load_slew1);
|
|
||||||
else {
|
|
||||||
float elmore = 1.0F / p1;
|
|
||||||
wire_delay1 = elmore;
|
|
||||||
load_slew1 = drvr_slew_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
thresholdAdjust(load_pin, wire_delay1, load_slew1);
|
thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
|
||||||
wire_delay = wire_delay1;
|
|
||||||
load_slew = load_slew1 * multi_drvr_slew_factor_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
DmpCeffTwoPoleDelayCalc::loadDelay(Parasitic *pole_residue,
|
DmpCeffTwoPoleDelayCalc::loadDelay(double drvr_slew,
|
||||||
double p1, double k1,
|
Parasitic *pole_residue,
|
||||||
ArcDelay &wire_delay,
|
double p1,
|
||||||
|
double k1,
|
||||||
|
// Return values.
|
||||||
|
ArcDelay &wire_delay,
|
||||||
Slew &load_slew)
|
Slew &load_slew)
|
||||||
{
|
{
|
||||||
ComplexFloat pole2, residue2;
|
ComplexFloat pole2, residue2;
|
||||||
parasitics_->poleResidue(pole_residue, 1, pole2, residue2);
|
parasitics_->poleResidue(pole_residue, 1, pole2, residue2);
|
||||||
if (!delayZero(drvr_slew_)
|
if (!delayZero(drvr_slew)
|
||||||
&& pole2.imag() == 0.0
|
&& pole2.imag() == 0.0
|
||||||
&& residue2.imag() == 0.0) {
|
&& residue2.imag() == 0.0) {
|
||||||
double p2 = pole2.real();
|
double p2 = pole2.real();
|
||||||
|
|
@ -311,7 +373,7 @@ DmpCeffTwoPoleDelayCalc::loadDelay(Parasitic *pole_residue,
|
||||||
double k2_p2_2 = k2 / (p2 * p2);
|
double k2_p2_2 = k2 / (p2 * p2);
|
||||||
double B = k1_p1_2 + k2_p2_2;
|
double B = k1_p1_2 + k2_p2_2;
|
||||||
// Convert tt to 0:1 range.
|
// 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)
|
double y_tt = (tt - B + k1_p1_2 * exp(-p1 * tt)
|
||||||
+ k2_p2_2 * exp(-p2 * tt)) / 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)
|
wire_delay = loadDelay(vth_, p1, p2, k1, k2, B, k1_p1_2, k2_p2_2, tt, y_tt)
|
||||||
|
|
|
||||||
|
|
@ -183,25 +183,10 @@ GraphDelayCalc::deleteVertexBefore(Vertex *vertex)
|
||||||
invalid_delays_->erase(vertex);
|
invalid_delays_->erase(vertex);
|
||||||
MultiDrvrNet *multi_drvr = multiDrvrNet(vertex);
|
MultiDrvrNet *multi_drvr = multiDrvrNet(vertex);
|
||||||
if (multi_drvr) {
|
if (multi_drvr) {
|
||||||
VertexSet *drvrs = multi_drvr->drvrs();
|
// Don't bother incrementally updating MultiDrvrNet.
|
||||||
drvrs->erase(vertex);
|
for (Vertex *drvr_vertex : *multi_drvr->drvrs())
|
||||||
multi_drvr_net_map_.erase(vertex);
|
multi_drvr_net_map_.erase(drvr_vertex);
|
||||||
if (drvrs->empty())
|
delete multi_drvr;
|
||||||
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();
|
const MinMax *slew_min_max = dcalc_ap->slewMinMax();
|
||||||
if (!drvr_vertex->slewAnnotated(rf, slew_min_max))
|
if (!drvr_vertex->slewAnnotated(rf, slew_min_max))
|
||||||
graph_->setSlew(drvr_vertex, rf, ap_index, slew);
|
graph_->setSlew(drvr_vertex, rf, ap_index, slew);
|
||||||
arc_delay_calc->inputPortDelay(drvr_pin, delayAsFloat(slew), rf,
|
LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex);
|
||||||
parasitic, dcalc_ap);
|
ArcDcalcResult dcalc_result =
|
||||||
annotateLoadDelays(drvr_vertex, rf, drive_delay, false, dcalc_ap,
|
arc_delay_calc->inputPortDelay(drvr_pin, delayAsFloat(slew), rf, parasitic,
|
||||||
arc_delay_calc);
|
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();
|
arc_delay_calc->finishDrvrPin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -417,10 +404,12 @@ GraphDelayCalc::seedNoDrvrSlew(Vertex *drvr_vertex,
|
||||||
if (!drvr_vertex->slewAnnotated(rf, slew_min_max))
|
if (!drvr_vertex->slewAnnotated(rf, slew_min_max))
|
||||||
graph_->setSlew(drvr_vertex, rf, ap_index, slew);
|
graph_->setSlew(drvr_vertex, rf, ap_index, slew);
|
||||||
Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin, rf, dcalc_ap);
|
Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin, rf, dcalc_ap);
|
||||||
arc_delay_calc->inputPortDelay(drvr_pin, delayAsFloat(slew), rf,
|
LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex);
|
||||||
parasitic, dcalc_ap);
|
ArcDcalcResult dcalc_result =
|
||||||
annotateLoadDelays(drvr_vertex, rf, delay_zero, false, dcalc_ap,
|
arc_delay_calc->inputPortDelay(drvr_pin, delayAsFloat(slew), rf, parasitic,
|
||||||
arc_delay_calc);
|
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();
|
arc_delay_calc->finishDrvrPin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -531,25 +520,26 @@ GraphDelayCalc::findInputArcDelay(const Pin *drvr_pin,
|
||||||
arc->to()->name(),
|
arc->to()->name(),
|
||||||
arc->toEdge()->asString(),
|
arc->toEdge()->asString(),
|
||||||
arc->role()->asString());
|
arc->role()->asString());
|
||||||
RiseFall *drvr_rf = arc->toEdge()->asRiseFall();
|
const RiseFall *drvr_rf = arc->toEdge()->asRiseFall();
|
||||||
if (drvr_rf) {
|
if (drvr_rf) {
|
||||||
DcalcAPIndex ap_index = dcalc_ap->index();
|
DcalcAPIndex ap_index = dcalc_ap->index();
|
||||||
const Pvt *pvt = dcalc_ap->operatingConditions();
|
Parasitic *parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, dcalc_ap);
|
||||||
Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf,
|
float load_cap = loadCap(drvr_pin, parasitic, drvr_rf, dcalc_ap);
|
||||||
dcalc_ap);
|
|
||||||
float load_cap = loadCap(drvr_pin, drvr_parasitic, drvr_rf, dcalc_ap);
|
|
||||||
|
|
||||||
ArcDelay intrinsic_delay;
|
LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex);
|
||||||
Slew intrinsic_slew;
|
ArcDcalcResult intrinsic_result =
|
||||||
arc_delay_calc_->gateDelay(arc, Slew(from_slew), 0.0, 0, 0.0, pvt, dcalc_ap,
|
arc_delay_calc_->gateDelay(drvr_pin, arc, Slew(from_slew), 0.0, nullptr,
|
||||||
intrinsic_delay, intrinsic_slew);
|
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);
|
||||||
|
ArcDelay gate_delay = gate_result.gateDelay();
|
||||||
|
Slew gate_slew = gate_result.drvrSlew();
|
||||||
|
|
||||||
// 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;
|
ArcDelay load_delay = gate_delay - intrinsic_delay;
|
||||||
debugPrint(debug_, "delay_calc", 3,
|
debugPrint(debug_, "delay_calc", 3,
|
||||||
" gate delay = %s intrinsic = %s slew = %s",
|
" gate delay = %s intrinsic = %s slew = %s",
|
||||||
|
|
@ -557,8 +547,8 @@ GraphDelayCalc::findInputArcDelay(const Pin *drvr_pin,
|
||||||
delayAsString(intrinsic_delay, this),
|
delayAsString(intrinsic_delay, this),
|
||||||
delayAsString(gate_slew, this));
|
delayAsString(gate_slew, this));
|
||||||
graph_->setSlew(drvr_vertex, drvr_rf, ap_index, gate_slew);
|
graph_->setSlew(drvr_vertex, drvr_rf, ap_index, gate_slew);
|
||||||
annotateLoadDelays(drvr_vertex, drvr_rf, load_delay, false, dcalc_ap,
|
annotateLoadDelays(drvr_vertex, drvr_rf, gate_result, load_pin_index_map,
|
||||||
arc_delay_calc_);
|
load_delay, false, dcalc_ap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -651,19 +641,12 @@ GraphDelayCalc::findDriverDelays(Vertex *drvr_vertex,
|
||||||
{
|
{
|
||||||
bool delay_changed = false;
|
bool delay_changed = false;
|
||||||
MultiDrvrNet *multi_drvr = findMultiDrvrNet(drvr_vertex);
|
MultiDrvrNet *multi_drvr = findMultiDrvrNet(drvr_vertex);
|
||||||
if (multi_drvr
|
if (multi_drvr == nullptr
|
||||||
&& multi_drvr->parallelGates(network_)) {
|
|| (multi_drvr
|
||||||
Vertex *dcalc_drvr = multi_drvr->dcalcDrvr();
|
&& (!multi_drvr->parallelGates(network_)
|
||||||
if (drvr_vertex == dcalc_drvr) {
|
|| 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);
|
initLoadSlews(drvr_vertex);
|
||||||
delay_changed = findDriverDelays1(drvr_vertex, nullptr, arc_delay_calc);
|
delay_changed |= findDriverDelays1(drvr_vertex, multi_drvr, arc_delay_calc);
|
||||||
}
|
}
|
||||||
arc_delay_calc->finishDrvrPin();
|
arc_delay_calc->finishDrvrPin();
|
||||||
return delay_changed;
|
return delay_changed;
|
||||||
|
|
@ -763,10 +746,17 @@ GraphDelayCalc::findDriverDelays1(Vertex *drvr_vertex,
|
||||||
MultiDrvrNet *multi_drvr,
|
MultiDrvrNet *multi_drvr,
|
||||||
ArcDelayCalc *arc_delay_calc)
|
ArcDelayCalc *arc_delay_calc)
|
||||||
{
|
{
|
||||||
const Pin *drvr_pin = drvr_vertex->pin();
|
|
||||||
Instance *drvr_inst = network_->instance(drvr_pin);
|
|
||||||
initSlew(drvr_vertex);
|
initSlew(drvr_vertex);
|
||||||
initWireDelays(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 delay_changed = false;
|
||||||
bool has_delays = false;
|
bool has_delays = false;
|
||||||
VertexInEdgeIterator edge_iter(drvr_vertex, graph_);
|
VertexInEdgeIterator edge_iter(drvr_vertex, graph_);
|
||||||
|
|
@ -777,8 +767,8 @@ GraphDelayCalc::findDriverDelays1(Vertex *drvr_vertex,
|
||||||
if (search_pred_->searchFrom(from_vertex)
|
if (search_pred_->searchFrom(from_vertex)
|
||||||
&& search_pred_->searchThru(edge)
|
&& search_pred_->searchThru(edge)
|
||||||
&& !edge->role()->isLatchDtoQ()) {
|
&& !edge->role()->isLatchDtoQ()) {
|
||||||
delay_changed |= findDriverEdgeDelays(drvr_inst, drvr_pin, drvr_vertex,
|
delay_changed |= findDriverEdgeDelays(drvr_vertex, multi_drvr, edge,
|
||||||
multi_drvr, edge, arc_delay_calc);
|
arc_delay_calc);
|
||||||
has_delays = true;
|
has_delays = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -812,53 +802,329 @@ GraphDelayCalc::findLatchEdgeDelays(Edge *edge)
|
||||||
Instance *drvr_inst = network_->instance(drvr_pin);
|
Instance *drvr_inst = network_->instance(drvr_pin);
|
||||||
debugPrint(debug_, "delay_calc", 2, "find latch D->Q %s",
|
debugPrint(debug_, "delay_calc", 2, "find latch D->Q %s",
|
||||||
sdc_network_->pathName(drvr_inst));
|
sdc_network_->pathName(drvr_inst));
|
||||||
bool delay_changed = findDriverEdgeDelays(drvr_inst, drvr_pin, drvr_vertex,
|
bool delay_changed = findDriverEdgeDelays(drvr_vertex, nullptr, edge,
|
||||||
nullptr, edge, arc_delay_calc_);
|
arc_delay_calc_);
|
||||||
if (delay_changed && observer_)
|
if (delay_changed && observer_)
|
||||||
observer_->delayChangedTo(drvr_vertex);
|
observer_->delayChangedTo(drvr_vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
GraphDelayCalc::findDriverEdgeDelays(const Instance *drvr_inst,
|
GraphDelayCalc::findDriverEdgeDelays(Vertex *drvr_vertex,
|
||||||
const Pin *drvr_pin,
|
|
||||||
Vertex *drvr_vertex,
|
|
||||||
const MultiDrvrNet *multi_drvr,
|
const MultiDrvrNet *multi_drvr,
|
||||||
Edge *edge,
|
Edge *edge,
|
||||||
ArcDelayCalc *arc_delay_calc)
|
ArcDelayCalc *arc_delay_calc)
|
||||||
{
|
{
|
||||||
Vertex *in_vertex = edge->from(graph_);
|
Vertex *from_vertex = edge->from(graph_);
|
||||||
const TimingArcSet *arc_set = edge->timingArcSet();
|
const TimingArcSet *arc_set = edge->timingArcSet();
|
||||||
const LibertyPort *related_out_port = arc_set->relatedOut();
|
|
||||||
const Pin *related_out_pin = 0;
|
|
||||||
bool delay_changed = false;
|
bool delay_changed = false;
|
||||||
if (related_out_port)
|
PinSeq load_pins = loadPins(drvr_vertex);
|
||||||
related_out_pin = network_->findPin(drvr_inst, related_out_port);
|
LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex);
|
||||||
for (auto dcalc_ap : corners_->dcalcAnalysisPts()) {
|
for (auto dcalc_ap : corners_->dcalcAnalysisPts()) {
|
||||||
const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax());
|
for (const TimingArc *arc : arc_set->arcs())
|
||||||
if (pvt == nullptr)
|
delay_changed |= findDriverArcDelays(drvr_vertex, multi_drvr, edge, arc,
|
||||||
pvt = dcalc_ap->operatingConditions();
|
load_pin_index_map, dcalc_ap,
|
||||||
for (TimingArc *arc : arc_set->arcs()) {
|
arc_delay_calc);
|
||||||
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);
|
|
||||||
}
|
|
||||||
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_) {
|
if (delay_changed && observer_) {
|
||||||
observer_->delayChangedFrom(in_vertex);
|
observer_->delayChangedFrom(from_vertex);
|
||||||
observer_->delayChangedFrom(drvr_vertex);
|
observer_->delayChangedFrom(drvr_vertex);
|
||||||
}
|
}
|
||||||
return delay_changed;
|
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
|
float
|
||||||
GraphDelayCalc::loadCap(const Pin *drvr_pin,
|
GraphDelayCalc::loadCap(const Pin *drvr_pin,
|
||||||
const DcalcAnalysisPt *dcalc_ap) const
|
const DcalcAnalysisPt *dcalc_ap) const
|
||||||
|
|
@ -866,9 +1132,8 @@ GraphDelayCalc::loadCap(const Pin *drvr_pin,
|
||||||
const MinMax *min_max = dcalc_ap->constraintMinMax();
|
const MinMax *min_max = dcalc_ap->constraintMinMax();
|
||||||
float load_cap = 0.0;
|
float load_cap = 0.0;
|
||||||
for (auto drvr_rf : RiseFall::range()) {
|
for (auto drvr_rf : RiseFall::range()) {
|
||||||
Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf,
|
Parasitic *parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, dcalc_ap);
|
||||||
dcalc_ap);
|
float cap = loadCap(drvr_pin, parasitic, drvr_rf, dcalc_ap, nullptr);
|
||||||
float cap = loadCap(drvr_pin, drvr_parasitic, drvr_rf, dcalc_ap, nullptr);
|
|
||||||
arc_delay_calc_->finishDrvrPin();
|
arc_delay_calc_->finishDrvrPin();
|
||||||
if (min_max->compare(cap, load_cap))
|
if (min_max->compare(cap, load_cap))
|
||||||
load_cap = cap;
|
load_cap = cap;
|
||||||
|
|
@ -881,24 +1146,24 @@ GraphDelayCalc::loadCap(const Pin *drvr_pin,
|
||||||
const RiseFall *drvr_rf,
|
const RiseFall *drvr_rf,
|
||||||
const DcalcAnalysisPt *dcalc_ap) const
|
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);
|
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;
|
return cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
GraphDelayCalc::loadCap(const Pin *drvr_pin,
|
GraphDelayCalc::loadCap(const Pin *drvr_pin,
|
||||||
const Parasitic *drvr_parasitic,
|
const Parasitic *parasitic,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const DcalcAnalysisPt *dcalc_ap) const
|
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
|
float
|
||||||
GraphDelayCalc::loadCap(const Pin *drvr_pin,
|
GraphDelayCalc::loadCap(const Pin *drvr_pin,
|
||||||
const Parasitic *drvr_parasitic,
|
const Parasitic *parasitic,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
const DcalcAnalysisPt *dcalc_ap,
|
||||||
const MultiDrvrNet *multi_drvr) const
|
const MultiDrvrNet *multi_drvr) const
|
||||||
|
|
@ -912,13 +1177,13 @@ GraphDelayCalc::loadCap(const Pin *drvr_pin,
|
||||||
else
|
else
|
||||||
netCaps(drvr_pin, rf, dcalc_ap,
|
netCaps(drvr_pin, rf, dcalc_ap,
|
||||||
pin_cap, wire_cap, fanout, has_net_load);
|
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;
|
return wire_cap + pin_cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GraphDelayCalc::loadCap(const Pin *drvr_pin,
|
GraphDelayCalc::loadCap(const Pin *drvr_pin,
|
||||||
const Parasitic *drvr_parasitic,
|
const Parasitic *parasitic,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
const DcalcAnalysisPt *dcalc_ap,
|
||||||
// Return values.
|
// Return values.
|
||||||
|
|
@ -930,23 +1195,23 @@ GraphDelayCalc::loadCap(const Pin *drvr_pin,
|
||||||
// Find pin and external pin/wire capacitance.
|
// Find pin and external pin/wire capacitance.
|
||||||
netCaps(drvr_pin, rf, dcalc_ap,
|
netCaps(drvr_pin, rf, dcalc_ap,
|
||||||
pin_cap, wire_cap, fanout, has_net_load);
|
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
|
void
|
||||||
GraphDelayCalc::loadCap(const Parasitic *drvr_parasitic,
|
GraphDelayCalc::loadCap(const Parasitic *parasitic,
|
||||||
bool has_net_load,
|
bool has_net_load,
|
||||||
// Return values.
|
// Return values.
|
||||||
float &pin_cap,
|
float &pin_cap,
|
||||||
float &wire_cap) const
|
float &wire_cap) const
|
||||||
{
|
{
|
||||||
// set_load net has precidence over parasitics.
|
// set_load net has precidence over parasitics.
|
||||||
if (!has_net_load && drvr_parasitic) {
|
if (!has_net_load && parasitic) {
|
||||||
if (parasitics_->isParasiticNetwork(drvr_parasitic))
|
if (parasitics_->isParasiticNetwork(parasitic))
|
||||||
wire_cap += parasitics_->capacitance(drvr_parasitic);
|
wire_cap += parasitics_->capacitance(parasitic);
|
||||||
else {
|
else {
|
||||||
// PiModel includes both pin and external caps.
|
// PiModel includes both pin and external caps.
|
||||||
float cap = parasitics_->capacitance(drvr_parasitic);
|
float cap = parasitics_->capacitance(parasitic);
|
||||||
if (pin_cap > cap) {
|
if (pin_cap > cap) {
|
||||||
pin_cap = 0.0;
|
pin_cap = 0.0;
|
||||||
wire_cap = cap;
|
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.
|
// Use clock slew for register/latch clk->q edges.
|
||||||
Slew
|
Slew
|
||||||
GraphDelayCalc::edgeFromSlew(const Vertex *from_vertex,
|
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());
|
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
|
void
|
||||||
GraphDelayCalc::findCheckEdgeDelays(Edge *edge,
|
GraphDelayCalc::findCheckEdgeDelays(Edge *edge,
|
||||||
ArcDelayCalc *arc_delay_calc)
|
ArcDelayCalc *arc_delay_calc)
|
||||||
|
|
@ -1227,9 +1355,6 @@ GraphDelayCalc::findCheckEdgeDelays(Edge *edge,
|
||||||
for (auto dcalc_ap : corners_->dcalcAnalysisPts()) {
|
for (auto dcalc_ap : corners_->dcalcAnalysisPts()) {
|
||||||
DcalcAPIndex ap_index = dcalc_ap->index();
|
DcalcAPIndex ap_index = dcalc_ap->index();
|
||||||
if (!graph_->arcDelayAnnotated(edge, arc, 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,
|
const Slew &from_slew = checkEdgeClkSlew(from_vertex, from_rf,
|
||||||
dcalc_ap);
|
dcalc_ap);
|
||||||
int slew_index = dcalc_ap->checkDataSlewIndex();
|
int slew_index = dcalc_ap->checkDataSlewIndex();
|
||||||
|
|
@ -1253,9 +1378,9 @@ GraphDelayCalc::findCheckEdgeDelays(Edge *edge,
|
||||||
related_out_parasitic,
|
related_out_parasitic,
|
||||||
to_rf, dcalc_ap);
|
to_rf, dcalc_ap);
|
||||||
}
|
}
|
||||||
ArcDelay check_delay;
|
ArcDelay check_delay = arc_delay_calc->checkDelay(to_pin, arc, from_slew,
|
||||||
arc_delay_calc->checkDelay(arc, from_slew, to_slew, related_out_cap,
|
to_slew, related_out_cap,
|
||||||
pvt, dcalc_ap, check_delay);
|
dcalc_ap);
|
||||||
debugPrint(debug_, "delay_calc", 3,
|
debugPrint(debug_, "delay_calc", 3,
|
||||||
" check_delay = %s",
|
" check_delay = %s",
|
||||||
delayAsString(check_delay, this));
|
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
|
string
|
||||||
GraphDelayCalc::reportDelayCalc(const Edge *edge,
|
GraphDelayCalc::reportDelayCalc(const Edge *edge,
|
||||||
const TimingArc *arc,
|
const TimingArc *arc,
|
||||||
|
|
@ -1341,9 +1425,6 @@ GraphDelayCalc::reportDelayCalc(const Edge *edge,
|
||||||
const TimingArcSet *arc_set = edge->timingArcSet();
|
const TimingArcSet *arc_set = edge->timingArcSet();
|
||||||
string result;
|
string result;
|
||||||
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
|
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 *from_rf = arc->fromEdge()->asRiseFall();
|
||||||
RiseFall *to_rf = arc->toEdge()->asRiseFall();
|
RiseFall *to_rf = arc->toEdge()->asRiseFall();
|
||||||
if (from_rf && to_rf) {
|
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);
|
const Slew &to_slew = graph_->slew(to_vertex, to_rf, slew_index);
|
||||||
bool from_ideal_clk = clk_network_->isIdealClock(from_vertex->pin());
|
bool from_ideal_clk = clk_network_->isIdealClock(from_vertex->pin());
|
||||||
const char *from_slew_annotation = from_ideal_clk ? " (ideal clock)" : nullptr;
|
const char *from_slew_annotation = from_ideal_clk ? " (ideal clock)" : nullptr;
|
||||||
result = arc_delay_calc_->reportCheckDelay(arc, from_slew, from_slew_annotation,
|
result = arc_delay_calc_->reportCheckDelay(to_pin, arc, from_slew,
|
||||||
to_slew, related_out_cap, pvt,
|
from_slew_annotation, to_slew,
|
||||||
dcalc_ap, digits);
|
related_out_cap, dcalc_ap, digits);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Parasitic *to_parasitic =
|
Parasitic *to_parasitic =
|
||||||
arc_delay_calc_->findParasitic(to_pin, to_rf, dcalc_ap);
|
arc_delay_calc_->findParasitic(to_pin, to_rf, dcalc_ap);
|
||||||
const Slew &from_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap);
|
const Slew &from_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap);
|
||||||
float load_cap = loadCap(to_pin, to_parasitic, to_rf, dcalc_ap);
|
float load_cap = loadCap(to_pin, to_parasitic, to_rf, dcalc_ap);
|
||||||
result = arc_delay_calc_->reportGateDelay(arc, from_slew, load_cap, to_parasitic,
|
LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(to_vertex);
|
||||||
related_out_cap, pvt, dcalc_ap, digits);
|
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();
|
arc_delay_calc_->finishDrvrPin();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -101,132 +101,88 @@ LumpedCapDelayCalc::findParasitic(const Pin *drvr_pin,
|
||||||
return parasitic;
|
return parasitic;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReducedParasiticType
|
ArcDcalcResult
|
||||||
LumpedCapDelayCalc::reducedParasiticType() const
|
LumpedCapDelayCalc::inputPortDelay(const Pin *,
|
||||||
|
float in_slew,
|
||||||
|
const RiseFall *rf,
|
||||||
|
const Parasitic *,
|
||||||
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
|
const DcalcAnalysisPt *)
|
||||||
{
|
{
|
||||||
return ReducedParasiticType::pi_elmore;
|
const LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
|
||||||
|
return makeResult(drvr_library,rf, 0.0, in_slew, load_pin_index_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
ArcDcalcResult
|
||||||
LumpedCapDelayCalc::ceff(const TimingArc *,
|
LumpedCapDelayCalc::gateDelay(const Pin *drvr_pin,
|
||||||
const Slew &,
|
const TimingArc *arc,
|
||||||
float load_cap,
|
|
||||||
const Parasitic *,
|
|
||||||
float,
|
|
||||||
const Pvt *,
|
|
||||||
const DcalcAnalysisPt *)
|
|
||||||
{
|
|
||||||
return load_cap;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
LumpedCapDelayCalc::gateDelay(const TimingArc *arc,
|
|
||||||
const Slew &in_slew,
|
const Slew &in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
const Parasitic *drvr_parasitic,
|
const Parasitic *,
|
||||||
float related_out_cap,
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
const Pvt *pvt,
|
const DcalcAnalysisPt *dcalc_ap)
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
|
||||||
// Return values.
|
|
||||||
ArcDelay &gate_delay,
|
|
||||||
Slew &drvr_slew)
|
|
||||||
{
|
{
|
||||||
gateDelayInit(arc, in_slew, drvr_parasitic);
|
|
||||||
GateTimingModel *model = gateModel(arc, dcalc_ap);
|
GateTimingModel *model = gateModel(arc, dcalc_ap);
|
||||||
debugPrint(debug_, "delay_calc", 3,
|
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),
|
delayAsString(in_slew, this),
|
||||||
units()->capacitanceUnit()->asString(load_cap),
|
units()->capacitanceUnit()->asString(load_cap));
|
||||||
units()->capacitanceUnit()->asString(related_out_cap));
|
const RiseFall *rf = arc->toEdge()->asRiseFall();
|
||||||
|
const LibertyLibrary *drvr_library = arc->to()->libertyLibrary();
|
||||||
if (model) {
|
if (model) {
|
||||||
ArcDelay gate_delay1;
|
ArcDelay gate_delay;
|
||||||
Slew drvr_slew1;
|
Slew drvr_slew;
|
||||||
float in_slew1 = delayAsFloat(in_slew);
|
float in_slew1 = delayAsFloat(in_slew);
|
||||||
// NaNs cause seg faults during table lookup.
|
// 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");
|
report_->error(710, "gate delay input variable is NaN");
|
||||||
model->gateDelay(pvt, in_slew1, load_cap, related_out_cap,
|
model->gateDelay(pinPvt(drvr_pin, dcalc_ap), in_slew1, load_cap, pocv_enabled_,
|
||||||
pocv_enabled_, gate_delay1, drvr_slew1);
|
gate_delay, drvr_slew);
|
||||||
gate_delay = gate_delay1;
|
return makeResult(drvr_library, rf, gate_delay, drvr_slew, load_pin_index_map);
|
||||||
drvr_slew = drvr_slew1;
|
|
||||||
drvr_slew_ = drvr_slew1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
gate_delay = delay_zero;
|
|
||||||
drvr_slew = delay_zero;
|
|
||||||
drvr_slew_ = 0.0;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
return makeResult(drvr_library, rf, delay_zero, delay_zero, load_pin_index_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
ArcDcalcResult
|
||||||
LumpedCapDelayCalc::loadDelay(const Pin *load_pin,
|
LumpedCapDelayCalc::makeResult(const LibertyLibrary *drvr_library,
|
||||||
ArcDelay &wire_delay,
|
const RiseFall *rf,
|
||||||
Slew &load_slew)
|
ArcDelay gate_delay,
|
||||||
|
Slew drvr_slew,
|
||||||
|
const LoadPinIndexMap &load_pin_index_map)
|
||||||
{
|
{
|
||||||
Delay wire_delay1 = 0.0;
|
ArcDcalcResult dcalc_result(load_pin_index_map.size());
|
||||||
Slew load_slew1 = drvr_slew_ * multi_drvr_slew_factor_;
|
dcalc_result.setGateDelay(gate_delay);
|
||||||
thresholdAdjust(load_pin, wire_delay1, load_slew1);
|
dcalc_result.setDrvrSlew(drvr_slew);
|
||||||
wire_delay = wire_delay1;
|
|
||||||
load_slew = load_slew1;
|
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
|
string
|
||||||
LumpedCapDelayCalc::reportGateDelay(const TimingArc *arc,
|
LumpedCapDelayCalc::reportGateDelay(const Pin *check_pin,
|
||||||
const Slew &in_slew,
|
const TimingArc *arc,
|
||||||
float load_cap,
|
const Slew &in_slew,
|
||||||
const Parasitic *,
|
float load_cap,
|
||||||
float related_out_cap,
|
const Parasitic *,
|
||||||
const Pvt *pvt,
|
const LoadPinIndexMap &,
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
const DcalcAnalysisPt *dcalc_ap,
|
||||||
int digits)
|
int digits)
|
||||||
{
|
{
|
||||||
GateTimingModel *model = gateModel(arc, dcalc_ap);
|
GateTimingModel *model = gateModel(arc, dcalc_ap);
|
||||||
if (model) {
|
if (model) {
|
||||||
float in_slew1 = delayAsFloat(in_slew);
|
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);
|
false, digits);
|
||||||
}
|
}
|
||||||
return "";
|
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
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -30,54 +30,34 @@ public:
|
||||||
Parasitic *findParasitic(const Pin *drvr_pin,
|
Parasitic *findParasitic(const Pin *drvr_pin,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const DcalcAnalysisPt *dcalc_ap) override;
|
const DcalcAnalysisPt *dcalc_ap) override;
|
||||||
ReducedParasiticType reducedParasiticType() const override;
|
ArcDcalcResult inputPortDelay(const Pin *port_pin,
|
||||||
void gateDelay(const TimingArc *arc,
|
float in_slew,
|
||||||
const Slew &in_slew,
|
const RiseFall *rf,
|
||||||
float load_cap,
|
const Parasitic *parasitic,
|
||||||
const Parasitic *drvr_parasitic,
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
float related_out_cap,
|
const DcalcAnalysisPt *dcalc_ap) override;
|
||||||
const Pvt *pvt,
|
ArcDcalcResult gateDelay(const Pin *drvr_pin,
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
const TimingArc *arc,
|
||||||
// Return values.
|
const Slew &in_slew,
|
||||||
ArcDelay &gate_delay,
|
float load_cap,
|
||||||
Slew &drvr_slew) override;
|
const Parasitic *parasitic,
|
||||||
float ceff(const TimingArc *arc,
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
const Slew &in_slew,
|
const DcalcAnalysisPt *dcalc_ap) override;
|
||||||
float load_cap,
|
string reportGateDelay(const Pin *drvr_pin,
|
||||||
const Parasitic *drvr_parasitic,
|
const TimingArc *arc,
|
||||||
float related_out_cap,
|
|
||||||
const Pvt *pvt,
|
|
||||||
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,
|
|
||||||
const Slew &in_slew,
|
const Slew &in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
const Parasitic *drvr_parasitic,
|
const Parasitic *parasitic,
|
||||||
float related_out_cap,
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
const Pvt *pvt,
|
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
const DcalcAnalysisPt *dcalc_ap,
|
||||||
int digits) override;
|
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 DcalcAnalysisPt *dcalc_ap,
|
|
||||||
int digits) override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
ArcDcalcResult makeResult(const LibertyLibrary *drvr_library,
|
||||||
|
const RiseFall *rf,
|
||||||
|
ArcDelay gate_delay,
|
||||||
|
Slew drvr_slew,
|
||||||
|
const LoadPinIndexMap &load_pin_index_map);
|
||||||
};
|
};
|
||||||
|
|
||||||
ArcDelayCalc *
|
ArcDelayCalc *
|
||||||
|
|
|
||||||
|
|
@ -31,141 +31,65 @@ ParallelDelayCalc::ParallelDelayCalc(StaState *sta):
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
ArcDcalcResultSeq
|
||||||
ParallelDelayCalc::inputPortDelay(const Pin *drvr_pin,
|
ParallelDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args,
|
||||||
float in_slew,
|
float load_cap,
|
||||||
const RiseFall *rf,
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
const Parasitic *parasitic,
|
const DcalcAnalysisPt *dcalc_ap)
|
||||||
const DcalcAnalysisPt *dcalc_ap)
|
|
||||||
{
|
{
|
||||||
DelayCalcBase::inputPortDelay(drvr_pin, in_slew, rf, parasitic, dcalc_ap);
|
size_t drvr_count = dcalc_args.size();
|
||||||
multi_drvr_slew_factor_ = 1.0;
|
ArcDcalcResultSeq dcalc_results(drvr_count);
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ParallelDelayCalc::gateDelayInit(const TimingArc *arc,
|
|
||||||
const Slew &in_slew,
|
|
||||||
const Parasitic *drvr_parasitic)
|
|
||||||
{
|
|
||||||
DelayCalcBase::gateDelayInit(arc, in_slew, drvr_parasitic);
|
|
||||||
multi_drvr_slew_factor_ = 1.0F;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ParallelDelayCalc::findParallelGateDelays(const MultiDrvrNet *multi_drvr,
|
|
||||||
GraphDelayCalc *dcalc)
|
|
||||||
{
|
|
||||||
int count = RiseFall::index_count * corners_->dcalcAnalysisPtCount();
|
|
||||||
parallel_delays_.resize(count);
|
|
||||||
parallel_slews_.resize(count);
|
|
||||||
for (auto dcalc_ap : corners_->dcalcAnalysisPts()) {
|
|
||||||
for (auto drvr_rf : RiseFall::range()) {
|
|
||||||
DcalcAPIndex ap_index = dcalc_ap->index();
|
|
||||||
int drvr_rf_index = drvr_rf->index();
|
|
||||||
int index = ap_index * RiseFall::index_count + drvr_rf_index;
|
|
||||||
findMultiDrvrGateDelay(multi_drvr, drvr_rf, dcalc_ap, dcalc,
|
|
||||||
parallel_delays_[index],
|
|
||||||
parallel_slews_[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ParallelDelayCalc::findMultiDrvrGateDelay(const MultiDrvrNet *multi_drvr,
|
|
||||||
const RiseFall *drvr_rf,
|
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
|
||||||
GraphDelayCalc *dcalc,
|
|
||||||
// Return values.
|
|
||||||
ArcDelay ¶llel_delay,
|
|
||||||
Slew ¶llel_slew)
|
|
||||||
{
|
|
||||||
ArcDelay delay_sum = 0.0;
|
|
||||||
Slew slew_sum = 0.0;
|
Slew slew_sum = 0.0;
|
||||||
for (Vertex *drvr_vertex : *multi_drvr->drvrs()) {
|
ArcDelay load_delay_sum = 0.0;
|
||||||
Pin *drvr_pin = drvr_vertex->pin();
|
vector<ArcDelay> intrinsic_delays(dcalc_args.size());
|
||||||
Instance *drvr_inst = network_->instance(drvr_pin);
|
vector<ArcDelay> load_delays(dcalc_args.size());
|
||||||
const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax());
|
for (size_t drvr_idx = 0; drvr_idx < drvr_count; drvr_idx++) {
|
||||||
if (pvt == nullptr)
|
ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx];
|
||||||
pvt = dcalc_ap->operatingConditions();
|
ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx];
|
||||||
VertexInEdgeIterator edge_iter(drvr_vertex, graph_);
|
const Pin *drvr_pin = dcalc_arg.drvrPin();
|
||||||
while (edge_iter.hasNext()) {
|
const TimingArc *arc = dcalc_arg.arc();
|
||||||
Edge *edge = edge_iter.next();
|
Slew in_slew = dcalc_arg.inSlew();
|
||||||
TimingArcSet *arc_set = edge->timingArcSet();
|
|
||||||
const LibertyPort *related_out_port = arc_set->relatedOut();
|
ArcDcalcResult intrinsic_result =
|
||||||
for (TimingArc *arc : arc_set->arcs()) {
|
arc_delay_calc_->gateDelay(drvr_pin, arc, in_slew, 0.0, nullptr,
|
||||||
RiseFall *arc_rf = arc->toEdge()->asRiseFall();
|
load_pin_index_map, dcalc_ap);
|
||||||
if (arc_rf == drvr_rf) {
|
ArcDelay intrinsic_delay = intrinsic_result.gateDelay();
|
||||||
Vertex *from_vertex = edge->from(graph_);
|
intrinsic_delays[drvr_idx] = intrinsic_result.gateDelay();
|
||||||
RiseFall *from_rf = arc->fromEdge()->asRiseFall();
|
|
||||||
Slew from_slew = dcalc->edgeFromSlew(from_vertex, from_rf,
|
ArcDcalcResult gate_result = arc_delay_calc_->gateDelay(drvr_pin, arc,
|
||||||
edge, dcalc_ap);
|
in_slew, load_cap,
|
||||||
ArcDelay intrinsic_delay;
|
dcalc_arg.parasitic(),
|
||||||
Slew intrinsic_slew;
|
load_pin_index_map,
|
||||||
gateDelay(arc, from_slew, 0.0, 0, 0.0, pvt, dcalc_ap,
|
dcalc_ap);
|
||||||
intrinsic_delay, intrinsic_slew);
|
ArcDelay gate_delay = gate_result.gateDelay();
|
||||||
Parasitic *parasitic = findParasitic(drvr_pin, drvr_rf, dcalc_ap);
|
Slew drvr_slew = gate_result.drvrSlew();
|
||||||
const Pin *related_out_pin = 0;
|
ArcDelay load_delay = gate_delay - intrinsic_delay;
|
||||||
float related_out_cap = 0.0;
|
load_delays[drvr_idx] = load_delay;
|
||||||
if (related_out_port) {
|
|
||||||
Instance *inst = network_->instance(drvr_pin);
|
if (!delayZero(load_delay))
|
||||||
related_out_pin = network_->findPin(inst, related_out_port);
|
load_delay_sum += 1.0 / load_delay;
|
||||||
if (related_out_pin) {
|
if (!delayZero(drvr_slew))
|
||||||
Parasitic *related_out_parasitic = findParasitic(related_out_pin,
|
slew_sum += 1.0 / drvr_slew;
|
||||||
drvr_rf,
|
|
||||||
dcalc_ap);
|
dcalc_result.setLoadCount(load_pin_index_map.size());
|
||||||
related_out_cap = dcalc->loadCap(related_out_pin,
|
for (auto load_pin_index : load_pin_index_map) {
|
||||||
related_out_parasitic,
|
size_t load_idx = load_pin_index.second;
|
||||||
drvr_rf, dcalc_ap);
|
dcalc_result.setWireDelay(load_idx, gate_result.wireDelay(load_idx));
|
||||||
}
|
dcalc_result.setLoadSlew(load_idx, gate_result.loadSlew(load_idx));
|
||||||
}
|
|
||||||
float load_cap = dcalc->loadCap(drvr_pin, parasitic,
|
|
||||||
drvr_rf, dcalc_ap);
|
|
||||||
ArcDelay gate_delay;
|
|
||||||
Slew gate_slew;
|
|
||||||
gateDelay(arc, from_slew, load_cap, parasitic,
|
|
||||||
related_out_cap, pvt, dcalc_ap,
|
|
||||||
gate_delay, gate_slew);
|
|
||||||
delay_sum += 1.0F / (gate_delay - intrinsic_delay);
|
|
||||||
slew_sum += 1.0F / gate_slew;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
parallel_delay = 1.0F / delay_sum;
|
|
||||||
parallel_slew = 1.0F / slew_sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
ArcDelay gate_load_delay = delayZero(load_delay_sum)
|
||||||
ParallelDelayCalc::parallelGateDelay(const Pin *,
|
? delay_zero
|
||||||
const TimingArc *arc,
|
: 1.0 / load_delay_sum;
|
||||||
const Slew &from_slew,
|
ArcDelay drvr_slew = delayZero(slew_sum) ? delay_zero : 1.0 / slew_sum;
|
||||||
float load_cap,
|
|
||||||
const Parasitic *drvr_parasitic,
|
|
||||||
float related_out_cap,
|
|
||||||
const Pvt *pvt,
|
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
|
||||||
// Return values.
|
|
||||||
ArcDelay &gate_delay,
|
|
||||||
Slew &gate_slew)
|
|
||||||
{
|
|
||||||
ArcDelay intrinsic_delay;
|
|
||||||
Slew intrinsic_slew;
|
|
||||||
gateDelay(arc, from_slew, 0.0, 0, 0.0, pvt, dcalc_ap,
|
|
||||||
intrinsic_delay, intrinsic_slew);
|
|
||||||
const RiseFall *drvr_rf = arc->toEdge()->asRiseFall();
|
|
||||||
int index = dcalc_ap->index() * RiseFall::index_count + drvr_rf->index();
|
|
||||||
ArcDelay parallel_delay = parallel_delays_[index];
|
|
||||||
Slew parallel_slew = parallel_slews_[index];
|
|
||||||
gate_delay = parallel_delay + intrinsic_delay;
|
|
||||||
gate_slew = parallel_slew;
|
|
||||||
|
|
||||||
Delay gate_delay1;
|
for (size_t drvr_idx = 0; drvr_idx < drvr_count; drvr_idx++) {
|
||||||
Slew gate_slew1;
|
ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx];
|
||||||
gateDelay(arc, from_slew, load_cap, drvr_parasitic,
|
dcalc_result.setGateDelay(intrinsic_delays[drvr_idx] + gate_load_delay);
|
||||||
related_out_cap, pvt, dcalc_ap,
|
dcalc_result.setDrvrSlew(drvr_slew);
|
||||||
gate_delay1, gate_slew1);
|
}
|
||||||
float factor = delayRatio(gate_slew, gate_slew1);
|
return dcalc_results;
|
||||||
multi_drvr_slew_factor_ = factor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -17,52 +17,21 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "DelayCalcBase.hh"
|
#include "DelayCalcBase.hh"
|
||||||
|
|
||||||
namespace sta {
|
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
|
class ParallelDelayCalc : public DelayCalcBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit ParallelDelayCalc(StaState *sta);
|
ParallelDelayCalc(StaState *sta);
|
||||||
void inputPortDelay(const Pin *port_pin,
|
ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &dcalc_args,
|
||||||
float in_slew,
|
float load_cap,
|
||||||
const RiseFall *rf,
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
const Parasitic *parasitic,
|
const DcalcAnalysisPt *dcalc_ap) override;
|
||||||
const DcalcAnalysisPt *dcalc_ap) override;
|
|
||||||
void gateDelayInit(const TimingArc *arc,
|
|
||||||
const Slew &in_slew,
|
|
||||||
const Parasitic *drvr_parasitic);
|
|
||||||
void findParallelGateDelays(const MultiDrvrNet *multi_drvr,
|
|
||||||
GraphDelayCalc *dcalc) override;
|
|
||||||
void parallelGateDelay(const Pin *drvr_pin,
|
|
||||||
const TimingArc *arc,
|
|
||||||
const Slew &from_slew,
|
|
||||||
float load_cap,
|
|
||||||
const Parasitic *drvr_parasitic,
|
|
||||||
float related_out_cap,
|
|
||||||
const Pvt *pvt,
|
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
|
||||||
// Return values.
|
|
||||||
ArcDelay &gate_delay,
|
|
||||||
Slew &gate_slew) override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void findMultiDrvrGateDelay(const MultiDrvrNet *multi_drvr,
|
|
||||||
const RiseFall *drvr_rf,
|
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
|
||||||
GraphDelayCalc *dcalc,
|
|
||||||
// Return values.
|
|
||||||
ArcDelay ¶llel_delay,
|
|
||||||
Slew ¶llel_slew);
|
|
||||||
|
|
||||||
// [drvr_rf->index][dcalc_ap->index]
|
|
||||||
vector<ArcDelay> parallel_delays_;
|
|
||||||
// [drvr_rf->index][dcalc_ap->index]
|
|
||||||
vector<Slew> parallel_slews_;
|
|
||||||
float multi_drvr_slew_factor_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -45,86 +45,65 @@ UnitDelayCalc::findParasitic(const Pin *,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReducedParasiticType
|
ArcDcalcResult
|
||||||
UnitDelayCalc::reducedParasiticType() const
|
|
||||||
{
|
|
||||||
return ReducedParasiticType::none;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
UnitDelayCalc::inputPortDelay(const Pin *,
|
UnitDelayCalc::inputPortDelay(const Pin *,
|
||||||
float,
|
float,
|
||||||
const RiseFall *,
|
const RiseFall *,
|
||||||
const Parasitic *,
|
const Parasitic *,
|
||||||
const DcalcAnalysisPt *)
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
|
const DcalcAnalysisPt *)
|
||||||
{
|
{
|
||||||
|
return unitDelayResult(load_pin_index_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
ArcDcalcResult
|
||||||
UnitDelayCalc::gateDelay(const TimingArc *,
|
UnitDelayCalc::gateDelay(const Pin *,
|
||||||
|
const TimingArc *,
|
||||||
const Slew &,
|
const Slew &,
|
||||||
float,
|
float,
|
||||||
const Parasitic *,
|
const Parasitic *,
|
||||||
float,
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
const Pvt *, const DcalcAnalysisPt *,
|
const DcalcAnalysisPt *)
|
||||||
// Return values.
|
|
||||||
ArcDelay &gate_delay, Slew &drvr_slew)
|
|
||||||
{
|
{
|
||||||
gate_delay = units_->timeUnit()->scale();
|
return unitDelayResult(load_pin_index_map);
|
||||||
drvr_slew = 0.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
ArcDcalcResultSeq
|
||||||
UnitDelayCalc::findParallelGateDelays(const MultiDrvrNet *,
|
UnitDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args,
|
||||||
GraphDelayCalc *)
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
ArcDcalcResult
|
||||||
UnitDelayCalc::parallelGateDelay(const Pin *,
|
UnitDelayCalc::unitDelayResult(const LoadPinIndexMap &load_pin_index_map)
|
||||||
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();
|
size_t load_count = load_pin_index_map.size();
|
||||||
gate_slew = 0.0;
|
ArcDcalcResult dcalc_result(load_count);
|
||||||
}
|
dcalc_result.setGateDelay(units_->timeUnit()->scale());
|
||||||
|
dcalc_result.setDrvrSlew(0.0);
|
||||||
void
|
for (size_t load_idx = 0; load_idx < load_count; load_idx++) {
|
||||||
UnitDelayCalc::loadDelay(const Pin *,
|
dcalc_result.setWireDelay(load_idx, 0.0);
|
||||||
ArcDelay &wire_delay,
|
dcalc_result.setLoadSlew(load_idx, 0.0);
|
||||||
Slew &load_slew)
|
}
|
||||||
{
|
return dcalc_result;
|
||||||
wire_delay = 0.0;
|
|
||||||
load_slew = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
float
|
|
||||||
UnitDelayCalc::ceff(const TimingArc *,
|
|
||||||
const Slew &,
|
|
||||||
float,
|
|
||||||
const Parasitic *,
|
|
||||||
float,
|
|
||||||
const Pvt *,
|
|
||||||
const DcalcAnalysisPt *)
|
|
||||||
{
|
|
||||||
return 0.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string
|
string
|
||||||
UnitDelayCalc::reportGateDelay(const TimingArc *,
|
UnitDelayCalc::reportGateDelay(const Pin *,
|
||||||
|
const TimingArc *,
|
||||||
const Slew &,
|
const Slew &,
|
||||||
float,
|
float,
|
||||||
const Parasitic *,
|
const Parasitic *,
|
||||||
float,
|
const LoadPinIndexMap &,
|
||||||
const Pvt *,
|
|
||||||
const DcalcAnalysisPt *,
|
const DcalcAnalysisPt *,
|
||||||
int)
|
int)
|
||||||
{
|
{
|
||||||
|
|
@ -133,26 +112,24 @@ UnitDelayCalc::reportGateDelay(const TimingArc *,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
ArcDelay
|
||||||
UnitDelayCalc::checkDelay(const TimingArc *,
|
UnitDelayCalc::checkDelay(const Pin *,
|
||||||
|
const TimingArc *,
|
||||||
const Slew &,
|
const Slew &,
|
||||||
const Slew &,
|
const Slew &,
|
||||||
float,
|
float,
|
||||||
const Pvt *,
|
const DcalcAnalysisPt *)
|
||||||
const DcalcAnalysisPt *,
|
|
||||||
// Return values.
|
|
||||||
ArcDelay &margin)
|
|
||||||
{
|
{
|
||||||
margin = units_->timeUnit()->scale();
|
return units_->timeUnit()->scale();
|
||||||
}
|
}
|
||||||
|
|
||||||
string
|
string
|
||||||
UnitDelayCalc::reportCheckDelay(const TimingArc *,
|
UnitDelayCalc::reportCheckDelay(const Pin *,
|
||||||
|
const TimingArc *,
|
||||||
const Slew &,
|
const Slew &,
|
||||||
const char *,
|
const char *,
|
||||||
const Slew &,
|
const Slew &,
|
||||||
float,
|
float,
|
||||||
const Pvt *,
|
|
||||||
const DcalcAnalysisPt *,
|
const DcalcAnalysisPt *,
|
||||||
int)
|
int)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -29,72 +29,50 @@ public:
|
||||||
Parasitic *findParasitic(const Pin *drvr_pin,
|
Parasitic *findParasitic(const Pin *drvr_pin,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const DcalcAnalysisPt *dcalc_ap) override;
|
const DcalcAnalysisPt *dcalc_ap) override;
|
||||||
ReducedParasiticType reducedParasiticType() const override;
|
ArcDcalcResult inputPortDelay(const Pin *port_pin,
|
||||||
void inputPortDelay(const Pin *port_pin,
|
float in_slew,
|
||||||
float in_slew,
|
const RiseFall *rf,
|
||||||
const RiseFall *rf,
|
const Parasitic *parasitic,
|
||||||
const Parasitic *parasitic,
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
|
const DcalcAnalysisPt *dcalc_ap) override;
|
||||||
|
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;
|
||||||
|
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 DcalcAnalysisPt *dcalc_ap) override;
|
const DcalcAnalysisPt *dcalc_ap) override;
|
||||||
void gateDelay(const TimingArc *arc,
|
string reportGateDelay(const Pin *drvr_pin,
|
||||||
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,
|
|
||||||
const TimingArc *arc,
|
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,
|
|
||||||
float load_cap,
|
|
||||||
const Parasitic *drvr_parasitic,
|
|
||||||
float related_out_cap,
|
|
||||||
const Pvt *pvt,
|
|
||||||
const DcalcAnalysisPt *dcalc_ap) 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,
|
|
||||||
const Slew &in_slew,
|
const Slew &in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
const Parasitic *drvr_parasitic,
|
const Parasitic *parasitic,
|
||||||
float related_out_cap,
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
const Pvt *pvt,
|
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
const DcalcAnalysisPt *dcalc_ap,
|
||||||
int digits) override;
|
int digits) override;
|
||||||
string reportCheckDelay(const TimingArc *arc,
|
string reportCheckDelay(const Pin *check_pin,
|
||||||
|
const TimingArc *arc,
|
||||||
const Slew &from_slew,
|
const Slew &from_slew,
|
||||||
const char *from_slew_annotation,
|
const char *from_slew_annotation,
|
||||||
const Slew &to_slew,
|
const Slew &to_slew,
|
||||||
float related_out_cap,
|
float related_out_cap,
|
||||||
const Pvt *pvt,
|
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
const DcalcAnalysisPt *dcalc_ap,
|
||||||
int digits) override;
|
int digits) override;
|
||||||
void finishDrvrPin() override;
|
void finishDrvrPin() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ArcDcalcResult unitDelayResult(const LoadPinIndexMap &load_pin_index_map);
|
||||||
};
|
};
|
||||||
|
|
||||||
ArcDelayCalc *
|
ArcDelayCalc *
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,14 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "MinMax.hh"
|
#include "MinMax.hh"
|
||||||
#include "LibertyClass.hh"
|
#include "LibertyClass.hh"
|
||||||
|
#include "TimingArc.hh"
|
||||||
|
#include "TableModel.hh"
|
||||||
#include "NetworkClass.hh"
|
#include "NetworkClass.hh"
|
||||||
|
#include "GraphClass.hh"
|
||||||
#include "Delay.hh"
|
#include "Delay.hh"
|
||||||
#include "ParasiticsClass.hh"
|
#include "ParasiticsClass.hh"
|
||||||
#include "StaState.hh"
|
#include "StaState.hh"
|
||||||
|
|
@ -30,18 +34,77 @@ namespace sta {
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
using std::map;
|
||||||
|
|
||||||
|
class Corner;
|
||||||
class Parasitic;
|
class Parasitic;
|
||||||
class DcalcAnalysisPt;
|
class DcalcAnalysisPt;
|
||||||
class MultiDrvrNet;
|
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.
|
// Delay calculator class hierarchy.
|
||||||
// ArcDelayCalc
|
// ArcDelayCalc
|
||||||
// UnitDelayCalc
|
// UnitDelayCalc
|
||||||
// DelayCalcBase
|
// DelayCalcBase
|
||||||
// ParallelDelayCalc
|
// ParallelDelayCalc
|
||||||
// LumpedCapDelayCalc
|
// LumpedCapDelayCalc
|
||||||
// SlewDegradeDelayCalc
|
|
||||||
// DmpCeffDelayCalc
|
// DmpCeffDelayCalc
|
||||||
// DmpCeffElmoreDelayCalc
|
// DmpCeffElmoreDelayCalc
|
||||||
// DmpCeffTwoPoleDelayCalc
|
// DmpCeffTwoPoleDelayCalc
|
||||||
|
|
@ -61,95 +124,68 @@ public:
|
||||||
virtual Parasitic *findParasitic(const Pin *drvr_pin,
|
virtual Parasitic *findParasitic(const Pin *drvr_pin,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const DcalcAnalysisPt *dcalc_ap) = 0;
|
const DcalcAnalysisPt *dcalc_ap) = 0;
|
||||||
virtual ReducedParasiticType reducedParasiticType() const = 0;
|
|
||||||
// Find the wire delays and slews for an input port without a driving cell.
|
// Find the wire delays and slews for an input port without a driving cell.
|
||||||
// This call primarily initializes the load delay/slew iterator.
|
// 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,
|
float in_slew,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const Parasitic *parasitic,
|
const Parasitic *parasitic,
|
||||||
const DcalcAnalysisPt *dcalc_ap) = 0;
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
|
const DcalcAnalysisPt *dcalc_ap) = 0;
|
||||||
|
|
||||||
// Find the delay and slew for arc driving drvr_pin.
|
// 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,
|
virtual void gateDelay(const TimingArc *arc,
|
||||||
const Slew &in_slew,
|
const Slew &in_slew,
|
||||||
// Pass in load_cap or drvr_parasitic.
|
|
||||||
float load_cap,
|
float load_cap,
|
||||||
const Parasitic *drvr_parasitic,
|
const Parasitic *parasitic,
|
||||||
float related_out_cap,
|
float related_out_cap,
|
||||||
const Pvt *pvt,
|
const Pvt *pvt,
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
const DcalcAnalysisPt *dcalc_ap,
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &gate_delay,
|
ArcDelay &gate_delay,
|
||||||
Slew &drvr_slew) = 0;
|
Slew &drvr_slew) __attribute__ ((deprecated));
|
||||||
|
|
||||||
// Find gate delays and slews for parallel gates.
|
// Find gate delays and slews for parallel gates.
|
||||||
virtual void findParallelGateDelays(const MultiDrvrNet *multi_drvr,
|
virtual ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &args,
|
||||||
GraphDelayCalc *dcalc) = 0;
|
float load_cap,
|
||||||
// Retrieve the delay and slew for one parallel gate.
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
virtual void parallelGateDelay(const Pin *drvr_pin,
|
const DcalcAnalysisPt *dcalc_ap) = 0;
|
||||||
const TimingArc *arc,
|
|
||||||
const Slew &from_slew,
|
|
||||||
float load_cap,
|
|
||||||
const Parasitic *drvr_parasitic,
|
|
||||||
float related_out_cap,
|
|
||||||
const Pvt *pvt,
|
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
|
||||||
// Return values.
|
|
||||||
ArcDelay &gate_delay,
|
|
||||||
Slew &gate_slew) = 0;
|
|
||||||
// Find the wire delay and load slew of a load pin.
|
|
||||||
// Called after inputPortDelay or gateDelay.
|
|
||||||
virtual void loadDelay(const Pin *load_pin,
|
|
||||||
// Return values.
|
|
||||||
ArcDelay &wire_delay,
|
|
||||||
Slew &load_slew) = 0;
|
|
||||||
// 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 DcalcAnalysisPt *dcalc_ap) = 0;
|
|
||||||
|
|
||||||
// Find the delay for a timing check arc given the arc's
|
// Find the delay for a timing check arc given the arc's
|
||||||
// from/clock, to/data slews and related output pin parasitic.
|
// from/clock, to/data slews and related output pin parasitic.
|
||||||
virtual void checkDelay(const TimingArc *arc,
|
virtual ArcDelay checkDelay(const Pin *check_pin,
|
||||||
const Slew &from_slew,
|
const TimingArc *arc,
|
||||||
const Slew &to_slew,
|
const Slew &from_slew,
|
||||||
float related_out_cap,
|
const Slew &to_slew,
|
||||||
const Pvt *pvt,
|
float related_out_cap,
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
const DcalcAnalysisPt *dcalc_ap) = 0;
|
||||||
// Return values.
|
|
||||||
ArcDelay &margin) = 0;
|
|
||||||
// Report delay and slew calculation.
|
// 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,
|
const Slew &in_slew,
|
||||||
// Pass in load_cap or drvr_parasitic.
|
|
||||||
float load_cap,
|
float load_cap,
|
||||||
const Parasitic *drvr_parasitic,
|
const Parasitic *parasitic,
|
||||||
float related_out_cap,
|
const LoadPinIndexMap &load_pin_index_map,
|
||||||
const Pvt *pvt,
|
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
const DcalcAnalysisPt *dcalc_ap,
|
||||||
int digits) = 0;
|
int digits) = 0;
|
||||||
// Report timing check delay calculation.
|
// 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 Slew &from_slew,
|
||||||
const char *from_slew_annotation,
|
const char *from_slew_annotation,
|
||||||
const Slew &to_slew,
|
const Slew &to_slew,
|
||||||
float related_out_cap,
|
float related_out_cap,
|
||||||
const Pvt *pvt,
|
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
const DcalcAnalysisPt *dcalc_ap,
|
||||||
int digits) = 0;
|
int digits) = 0;
|
||||||
virtual void finishDrvrPin() = 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
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,12 @@
|
||||||
#include "DcalcAnalysisPt.hh"
|
#include "DcalcAnalysisPt.hh"
|
||||||
#include "StaState.hh"
|
#include "StaState.hh"
|
||||||
#include "Delay.hh"
|
#include "Delay.hh"
|
||||||
|
#include "ArcDelayCalc.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
using std::map;
|
||||||
|
|
||||||
class DelayCalcObserver;
|
class DelayCalcObserver;
|
||||||
class MultiDrvrNet;
|
class MultiDrvrNet;
|
||||||
|
|
@ -79,7 +81,7 @@ public:
|
||||||
// pin_cap = net pin capacitances + port external pin capacitance,
|
// pin_cap = net pin capacitances + port external pin capacitance,
|
||||||
// wire_cap = annotated net capacitance + port external wire capacitance.
|
// wire_cap = annotated net capacitance + port external wire capacitance.
|
||||||
virtual void loadCap(const Pin *drvr_pin,
|
virtual void loadCap(const Pin *drvr_pin,
|
||||||
const Parasitic *drvr_parasitic,
|
const Parasitic *parasitic,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
const DcalcAnalysisPt *dcalc_ap,
|
||||||
// Return values.
|
// Return values.
|
||||||
|
|
@ -87,11 +89,11 @@ public:
|
||||||
float &wire_cap) const;
|
float &wire_cap) const;
|
||||||
// Load pin_cap + wire_cap including parasitic.
|
// Load pin_cap + wire_cap including parasitic.
|
||||||
virtual float loadCap(const Pin *drvr_pin,
|
virtual float loadCap(const Pin *drvr_pin,
|
||||||
const Parasitic *drvr_parasitic,
|
const Parasitic *parasitic,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const DcalcAnalysisPt *dcalc_ap) const;
|
const DcalcAnalysisPt *dcalc_ap) const;
|
||||||
float loadCap(const Pin *drvr_pin,
|
float loadCap(const Pin *drvr_pin,
|
||||||
const Parasitic *drvr_parasitic,
|
const Parasitic *parasitic,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
const DcalcAnalysisPt *dcalc_ap,
|
||||||
const MultiDrvrNet *multi_drvr) const;
|
const MultiDrvrNet *multi_drvr) const;
|
||||||
|
|
@ -103,9 +105,13 @@ public:
|
||||||
float &wire_cap,
|
float &wire_cap,
|
||||||
float &fanout,
|
float &fanout,
|
||||||
bool &has_set_load) const;
|
bool &has_set_load) const;
|
||||||
float ceff(Edge *edge,
|
PinSeq loadPins(Vertex *drvr_vertex);
|
||||||
TimingArc *arc,
|
LoadPinIndexMap makeLoadPinIndexMap(Vertex *drvr_vertex);
|
||||||
const DcalcAnalysisPt *dcalc_ap);
|
void findDriverArcDelays(Vertex *drvr_vertex,
|
||||||
|
Edge *edge,
|
||||||
|
const TimingArc *arc,
|
||||||
|
const DcalcAnalysisPt *dcalc_ap,
|
||||||
|
ArcDelayCalc *arc_delay_calc);
|
||||||
// Precedence:
|
// Precedence:
|
||||||
// SDF annotation
|
// SDF annotation
|
||||||
// Liberty library
|
// Liberty library
|
||||||
|
|
@ -176,12 +182,29 @@ protected:
|
||||||
MultiDrvrNet *multi_drvr,
|
MultiDrvrNet *multi_drvr,
|
||||||
ArcDelayCalc *arc_delay_calc);
|
ArcDelayCalc *arc_delay_calc);
|
||||||
void initLoadSlews(Vertex *drvr_vertex);
|
void initLoadSlews(Vertex *drvr_vertex);
|
||||||
bool findDriverEdgeDelays(const Instance *drvr_inst,
|
bool findDriverEdgeDelays(Vertex *drvr_vertex,
|
||||||
const Pin *drvr_pin,
|
|
||||||
Vertex *drvr_vertex,
|
|
||||||
const MultiDrvrNet *multi_drvr,
|
const MultiDrvrNet *multi_drvr,
|
||||||
Edge *edge,
|
Edge *edge,
|
||||||
ArcDelayCalc *arc_delay_calc);
|
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 initWireDelays(Vertex *drvr_vertex);
|
||||||
void initRootSlews(Vertex *vertex);
|
void initRootSlews(Vertex *vertex);
|
||||||
void zeroSlewAndWireDelays(Vertex *drvr_vertex);
|
void zeroSlewAndWireDelays(Vertex *drvr_vertex);
|
||||||
|
|
@ -189,23 +212,24 @@ protected:
|
||||||
ArcDelayCalc *arc_delay_calc,
|
ArcDelayCalc *arc_delay_calc,
|
||||||
bool propagate);
|
bool propagate);
|
||||||
void enqueueTimingChecksEdges(Vertex *vertex);
|
void enqueueTimingChecksEdges(Vertex *vertex);
|
||||||
bool findArcDelay(const Pin *drvr_pin,
|
bool annotateDelaysSlews(Edge *edge,
|
||||||
Vertex *drvr_vertex,
|
const TimingArc *arc,
|
||||||
const TimingArc *arc,
|
ArcDcalcResult &dcalc_result,
|
||||||
const Parasitic *drvr_parasitic,
|
LoadPinIndexMap &load_pin_index_map,
|
||||||
float related_out_cap,
|
const DcalcAnalysisPt *dcalc_ap);
|
||||||
Vertex *from_vertex,
|
|
||||||
Edge *edge,
|
bool annotateDelaySlew(Edge *edge,
|
||||||
const Pvt *pvt,
|
const TimingArc *arc,
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
ArcDelay &gate_delay,
|
||||||
const MultiDrvrNet *multi_drvr,
|
Slew &gate_slew,
|
||||||
ArcDelayCalc *arc_delay_calc);
|
const DcalcAnalysisPt *dcalc_ap);
|
||||||
void annotateLoadDelays(Vertex *drvr_vertex,
|
void annotateLoadDelays(Vertex *drvr_vertex,
|
||||||
const RiseFall *drvr_rf,
|
const RiseFall *drvr_rf,
|
||||||
const ArcDelay &extra_delay,
|
ArcDcalcResult &dcalc_result,
|
||||||
bool merge,
|
LoadPinIndexMap &load_pin_index_map,
|
||||||
const DcalcAnalysisPt *dcalc_ap,
|
const ArcDelay &extra_delay,
|
||||||
ArcDelayCalc *arc_delay_calc);
|
bool merge,
|
||||||
|
const DcalcAnalysisPt *dcalc_ap);
|
||||||
void findLatchEdgeDelays(Edge *edge);
|
void findLatchEdgeDelays(Edge *edge);
|
||||||
void findCheckEdgeDelays(Edge *edge,
|
void findCheckEdgeDelays(Edge *edge,
|
||||||
ArcDelayCalc *arc_delay_calc);
|
ArcDelayCalc *arc_delay_calc);
|
||||||
|
|
@ -215,7 +239,7 @@ protected:
|
||||||
const DcalcAnalysisPt *dcalc_ap);
|
const DcalcAnalysisPt *dcalc_ap);
|
||||||
bool bidirectDrvrSlewFromLoad(const Vertex *vertex) const;
|
bool bidirectDrvrSlewFromLoad(const Vertex *vertex) const;
|
||||||
MultiDrvrNet *multiDrvrNet(const Vertex *drvr_vertex) const;
|
MultiDrvrNet *multiDrvrNet(const Vertex *drvr_vertex) const;
|
||||||
void loadCap(const Parasitic *drvr_parasitic,
|
void loadCap(const Parasitic *parasitic,
|
||||||
bool has_set_load,
|
bool has_set_load,
|
||||||
// Return values.
|
// Return values.
|
||||||
float &pin_cap,
|
float &pin_cap,
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ public:
|
||||||
void gateDelay(const Pvt *pvt,
|
void gateDelay(const Pvt *pvt,
|
||||||
float in_slew,
|
float in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
float related_out_cap,
|
|
||||||
bool pocv_enabled,
|
bool pocv_enabled,
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &gate_delay,
|
ArcDelay &gate_delay,
|
||||||
|
|
@ -37,7 +36,6 @@ public:
|
||||||
string reportGateDelay(const Pvt *pvt,
|
string reportGateDelay(const Pvt *pvt,
|
||||||
float in_slew,
|
float in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
float related_out_cap,
|
|
||||||
bool pocv_enabled,
|
bool pocv_enabled,
|
||||||
int digits) const override;
|
int digits) const override;
|
||||||
float driveResistance(const Pvt *pvt) const override;
|
float driveResistance(const Pvt *pvt) const override;
|
||||||
|
|
@ -54,13 +52,11 @@ class CheckLinearModel : public CheckTimingModel
|
||||||
public:
|
public:
|
||||||
explicit CheckLinearModel(LibertyCell *cell,
|
explicit CheckLinearModel(LibertyCell *cell,
|
||||||
float intrinsic);
|
float intrinsic);
|
||||||
void checkDelay(const Pvt *pvt,
|
ArcDelay checkDelay(const Pvt *pvt,
|
||||||
float from_slew,
|
float from_slew,
|
||||||
float to_slew,
|
float to_slew,
|
||||||
float related_out_cap,
|
float related_out_cap,
|
||||||
bool pocv_enabled,
|
bool pocv_enabled) const override;
|
||||||
// Return values.
|
|
||||||
ArcDelay &margin) const override;
|
|
||||||
string reportCheckDelay(const Pvt *pvt,
|
string reportCheckDelay(const Pvt *pvt,
|
||||||
float from_slew,
|
float from_slew,
|
||||||
const char *from_slew_annotation,
|
const char *from_slew_annotation,
|
||||||
|
|
|
||||||
|
|
@ -62,15 +62,21 @@ public:
|
||||||
void gateDelay(const Pvt *pvt,
|
void gateDelay(const Pvt *pvt,
|
||||||
float in_slew,
|
float in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
float related_out_cap,
|
|
||||||
bool pocv_enabled,
|
bool pocv_enabled,
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &gate_delay,
|
ArcDelay &gate_delay,
|
||||||
Slew &drvr_slew) const override;
|
Slew &drvr_slew) const override;
|
||||||
|
// 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,
|
string reportGateDelay(const Pvt *pvt,
|
||||||
float in_slew,
|
float in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
float related_out_cap,
|
|
||||||
bool pocv_enabled,
|
bool pocv_enabled,
|
||||||
int digits) const override;
|
int digits) const override;
|
||||||
float driveResistance(const Pvt *pvt) const override;
|
float driveResistance(const Pvt *pvt) const override;
|
||||||
|
|
@ -130,13 +136,11 @@ public:
|
||||||
TableModel *model,
|
TableModel *model,
|
||||||
TableModel *sigma_models[EarlyLate::index_count]);
|
TableModel *sigma_models[EarlyLate::index_count]);
|
||||||
virtual ~CheckTableModel();
|
virtual ~CheckTableModel();
|
||||||
void checkDelay(const Pvt *pvt,
|
ArcDelay checkDelay(const Pvt *pvt,
|
||||||
float from_slew,
|
float from_slew,
|
||||||
float to_slew,
|
float to_slew,
|
||||||
float related_out_cap,
|
float related_out_cap,
|
||||||
bool pocv_enabled,
|
bool pocv_enabled) const override;
|
||||||
// Return values.
|
|
||||||
ArcDelay &margin) const override;
|
|
||||||
string reportCheckDelay(const Pvt *pvt,
|
string reportCheckDelay(const Pvt *pvt,
|
||||||
float from_slew,
|
float from_slew,
|
||||||
const char *from_slew_annotation,
|
const char *from_slew_annotation,
|
||||||
|
|
@ -504,9 +508,6 @@ public:
|
||||||
float voltageCurrent(float slew,
|
float voltageCurrent(float slew,
|
||||||
float cap,
|
float cap,
|
||||||
float volt);
|
float volt);
|
||||||
float currentVoltage(float slew,
|
|
||||||
float cap,
|
|
||||||
float current);
|
|
||||||
float referenceTime(float slew);
|
float referenceTime(float slew);
|
||||||
void setVdd(float vdd);
|
void setVdd(float vdd);
|
||||||
static bool checkAxes(const TableTemplate *tbl_template);
|
static bool checkAxes(const TableTemplate *tbl_template);
|
||||||
|
|
@ -536,7 +537,6 @@ private:
|
||||||
Table1Seq current_waveforms_;
|
Table1Seq current_waveforms_;
|
||||||
Table1Seq voltage_waveforms_;
|
Table1Seq voltage_waveforms_;
|
||||||
Table1Seq voltage_currents_;
|
Table1Seq voltage_currents_;
|
||||||
Table1Seq current_voltages_;
|
|
||||||
FloatTable voltage_times_;
|
FloatTable voltage_times_;
|
||||||
Table1 *ref_times_;
|
Table1 *ref_times_;
|
||||||
float vdd_;
|
float vdd_;
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,6 @@ public:
|
||||||
virtual void gateDelay(const Pvt *pvt,
|
virtual void gateDelay(const Pvt *pvt,
|
||||||
float in_slew,
|
float in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
float related_out_cap,
|
|
||||||
bool pocv_enabled,
|
bool pocv_enabled,
|
||||||
// Return values.
|
// Return values.
|
||||||
ArcDelay &gate_delay,
|
ArcDelay &gate_delay,
|
||||||
|
|
@ -54,7 +53,6 @@ public:
|
||||||
virtual string reportGateDelay(const Pvt *pvt,
|
virtual string reportGateDelay(const Pvt *pvt,
|
||||||
float in_slew,
|
float in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
float related_out_cap,
|
|
||||||
bool pocv_enabled,
|
bool pocv_enabled,
|
||||||
int digits) const = 0;
|
int digits) const = 0;
|
||||||
virtual float driveResistance(const Pvt *pvt) const = 0;
|
virtual float driveResistance(const Pvt *pvt) const = 0;
|
||||||
|
|
@ -66,13 +64,11 @@ class CheckTimingModel : public TimingModel
|
||||||
public:
|
public:
|
||||||
CheckTimingModel(LibertyCell *cell);
|
CheckTimingModel(LibertyCell *cell);
|
||||||
// Timing check margin delay calculation.
|
// Timing check margin delay calculation.
|
||||||
virtual void checkDelay(const Pvt *pvt,
|
virtual ArcDelay checkDelay(const Pvt *pvt,
|
||||||
float from_slew,
|
float from_slew,
|
||||||
float to_slew,
|
float to_slew,
|
||||||
float related_out_cap,
|
float related_out_cap,
|
||||||
bool pocv_enabled,
|
bool pocv_enabled) const = 0;
|
||||||
// Return values.
|
|
||||||
ArcDelay &margin) const = 0;
|
|
||||||
virtual string reportCheckDelay(const Pvt *pvt,
|
virtual string reportCheckDelay(const Pvt *pvt,
|
||||||
float from_slew,
|
float from_slew,
|
||||||
const char *from_slew_annotation,
|
const char *from_slew_annotation,
|
||||||
|
|
|
||||||
|
|
@ -2583,7 +2583,7 @@ LibertyPort::clockTreePathDelays()
|
||||||
GateTimingModel *gate_model = dynamic_cast<GateTimingModel*>(model);
|
GateTimingModel *gate_model = dynamic_cast<GateTimingModel*>(model);
|
||||||
ArcDelay delay;
|
ArcDelay delay;
|
||||||
Slew slew;
|
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 RiseFall *rf = arc->toEdge()->asRiseFall();
|
||||||
const MinMax *min_max = (role == TimingRole::clockTreePathMin())
|
const MinMax *min_max = (role == TimingRole::clockTreePathMin())
|
||||||
? MinMax::min()
|
? MinMax::min()
|
||||||
|
|
|
||||||
|
|
@ -182,17 +182,13 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell,
|
||||||
&& seq->data()->hasPort(from_port))
|
&& seq->data()->hasPort(from_port))
|
||||||
// Latch D->Q timing arcs.
|
// Latch D->Q timing arcs.
|
||||||
return makeLatchDtoQArcs(cell, from_port, to_port,
|
return makeLatchDtoQArcs(cell, from_port, to_port,
|
||||||
seq->data()->portTimingSense(from_port),
|
seq->data()->portTimingSense(from_port), attrs);
|
||||||
related_out, attrs);
|
|
||||||
else
|
else
|
||||||
return makeCombinationalArcs(cell, from_port, to_port, related_out,
|
return makeCombinationalArcs(cell, from_port, to_port, true, true, attrs);
|
||||||
true, true, attrs);
|
|
||||||
case TimingType::combinational_fall:
|
case TimingType::combinational_fall:
|
||||||
return makeCombinationalArcs(cell, from_port, to_port, related_out,
|
return makeCombinationalArcs(cell, from_port, to_port, false, true, attrs);
|
||||||
false, true, attrs);
|
|
||||||
case TimingType::combinational_rise:
|
case TimingType::combinational_rise:
|
||||||
return makeCombinationalArcs(cell, from_port, to_port, related_out,
|
return makeCombinationalArcs(cell, from_port, to_port, true, false, attrs);
|
||||||
true, false, attrs);
|
|
||||||
case TimingType::setup_rising:
|
case TimingType::setup_rising:
|
||||||
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
|
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
|
||||||
RiseFall::rise(), TimingRole::setup(),
|
RiseFall::rise(), TimingRole::setup(),
|
||||||
|
|
@ -210,17 +206,13 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell,
|
||||||
RiseFall::fall(), TimingRole::hold(),
|
RiseFall::fall(), TimingRole::hold(),
|
||||||
attrs);
|
attrs);
|
||||||
case TimingType::rising_edge:
|
case TimingType::rising_edge:
|
||||||
return makeRegLatchArcs(cell, from_port, to_port, related_out,
|
return makeRegLatchArcs(cell, from_port, to_port, RiseFall::rise(), attrs);
|
||||||
RiseFall::rise(), attrs);
|
|
||||||
case TimingType::falling_edge:
|
case TimingType::falling_edge:
|
||||||
return makeRegLatchArcs(cell, from_port, to_port, related_out,
|
return makeRegLatchArcs(cell, from_port, to_port, RiseFall::fall(), attrs);
|
||||||
RiseFall::fall(), attrs);
|
|
||||||
case TimingType::preset:
|
case TimingType::preset:
|
||||||
return makePresetClrArcs(cell, from_port, to_port, related_out,
|
return makePresetClrArcs(cell, from_port, to_port, RiseFall::rise(), attrs);
|
||||||
RiseFall::rise(), attrs);
|
|
||||||
case TimingType::clear:
|
case TimingType::clear:
|
||||||
return makePresetClrArcs(cell, from_port, to_port, related_out,
|
return makePresetClrArcs(cell, from_port, to_port, RiseFall::fall(), attrs);
|
||||||
RiseFall::fall(), attrs);
|
|
||||||
case TimingType::recovery_rising:
|
case TimingType::recovery_rising:
|
||||||
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
|
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
|
||||||
RiseFall::rise(),TimingRole::recovery(),
|
RiseFall::rise(),TimingRole::recovery(),
|
||||||
|
|
@ -238,23 +230,17 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell,
|
||||||
RiseFall::fall(), TimingRole::removal(),
|
RiseFall::fall(), TimingRole::removal(),
|
||||||
attrs);
|
attrs);
|
||||||
case TimingType::three_state_disable:
|
case TimingType::three_state_disable:
|
||||||
return makeTristateDisableArcs(cell, from_port, to_port, related_out,
|
return makeTristateDisableArcs(cell, from_port, to_port, true, true, attrs);
|
||||||
true, true, attrs);
|
|
||||||
case TimingType::three_state_disable_fall:
|
case TimingType::three_state_disable_fall:
|
||||||
return makeTristateDisableArcs(cell, from_port, to_port, related_out,
|
return makeTristateDisableArcs(cell, from_port, to_port, false, true, attrs);
|
||||||
false, true, attrs);
|
|
||||||
case TimingType::three_state_disable_rise:
|
case TimingType::three_state_disable_rise:
|
||||||
return makeTristateDisableArcs(cell, from_port, to_port, related_out,
|
return makeTristateDisableArcs(cell, from_port, to_port, true, false, attrs);
|
||||||
true, false, attrs);
|
|
||||||
case TimingType::three_state_enable:
|
case TimingType::three_state_enable:
|
||||||
return makeTristateEnableArcs(cell, from_port, to_port, related_out,
|
return makeTristateEnableArcs(cell, from_port, to_port, true, true, attrs);
|
||||||
true, true, attrs);
|
|
||||||
case TimingType::three_state_enable_fall:
|
case TimingType::three_state_enable_fall:
|
||||||
return makeTristateEnableArcs(cell, from_port, to_port, related_out,
|
return makeTristateEnableArcs(cell, from_port, to_port, false, true, attrs);
|
||||||
false, true, attrs);
|
|
||||||
case TimingType::three_state_enable_rise:
|
case TimingType::three_state_enable_rise:
|
||||||
return makeTristateEnableArcs(cell, from_port, to_port, related_out,
|
return makeTristateEnableArcs(cell, from_port, to_port, true, false, attrs);
|
||||||
true, false, attrs);
|
|
||||||
case TimingType::skew_falling:
|
case TimingType::skew_falling:
|
||||||
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
|
return makeFromTransitionArcs(cell, from_port, to_port, related_out,
|
||||||
RiseFall::fall(), TimingRole::skew(),
|
RiseFall::fall(), TimingRole::skew(),
|
||||||
|
|
@ -282,12 +268,10 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell,
|
||||||
TimingRole::nonSeqHold(),
|
TimingRole::nonSeqHold(),
|
||||||
attrs);
|
attrs);
|
||||||
case TimingType::min_clock_tree_path:
|
case TimingType::min_clock_tree_path:
|
||||||
return makeClockTreePathArcs(cell, to_port, related_out,
|
return makeClockTreePathArcs(cell, to_port, TimingRole::clockTreePathMin(),
|
||||||
TimingRole::clockTreePathMin(),
|
|
||||||
attrs);
|
attrs);
|
||||||
case TimingType::max_clock_tree_path:
|
case TimingType::max_clock_tree_path:
|
||||||
return makeClockTreePathArcs(cell, to_port, related_out,
|
return makeClockTreePathArcs(cell, to_port, TimingRole::clockTreePathMax(),
|
||||||
TimingRole::clockTreePathMax(),
|
|
||||||
attrs);
|
attrs);
|
||||||
case TimingType::min_pulse_width:
|
case TimingType::min_pulse_width:
|
||||||
case TimingType::minimum_period:
|
case TimingType::minimum_period:
|
||||||
|
|
@ -307,14 +291,13 @@ TimingArcSet *
|
||||||
LibertyBuilder::makeCombinationalArcs(LibertyCell *cell,
|
LibertyBuilder::makeCombinationalArcs(LibertyCell *cell,
|
||||||
LibertyPort *from_port,
|
LibertyPort *from_port,
|
||||||
LibertyPort *to_port,
|
LibertyPort *to_port,
|
||||||
LibertyPort *related_out,
|
|
||||||
bool to_rise,
|
bool to_rise,
|
||||||
bool to_fall,
|
bool to_fall,
|
||||||
TimingArcAttrsPtr attrs)
|
TimingArcAttrsPtr attrs)
|
||||||
{
|
{
|
||||||
FuncExpr *func = to_port->function();
|
FuncExpr *func = to_port->function();
|
||||||
FuncExpr *enable = to_port->tristateEnable();
|
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);
|
TimingRole::combinational(), attrs);
|
||||||
TimingSense sense = attrs->timingSense();
|
TimingSense sense = attrs->timingSense();
|
||||||
if (sense == TimingSense::unknown) {
|
if (sense == TimingSense::unknown) {
|
||||||
|
|
@ -393,11 +376,9 @@ LibertyBuilder::makeLatchDtoQArcs(LibertyCell *cell,
|
||||||
LibertyPort *from_port,
|
LibertyPort *from_port,
|
||||||
LibertyPort *to_port,
|
LibertyPort *to_port,
|
||||||
TimingSense sense,
|
TimingSense sense,
|
||||||
LibertyPort *related_out,
|
|
||||||
TimingArcAttrsPtr attrs)
|
TimingArcAttrsPtr attrs)
|
||||||
{
|
{
|
||||||
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port,
|
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port,
|
||||||
related_out,
|
|
||||||
TimingRole::latchDtoQ(), attrs);
|
TimingRole::latchDtoQ(), attrs);
|
||||||
TimingModel *model;
|
TimingModel *model;
|
||||||
RiseFall *to_rf = RiseFall::rise();
|
RiseFall *to_rf = RiseFall::rise();
|
||||||
|
|
@ -421,7 +402,6 @@ TimingArcSet *
|
||||||
LibertyBuilder::makeRegLatchArcs(LibertyCell *cell,
|
LibertyBuilder::makeRegLatchArcs(LibertyCell *cell,
|
||||||
LibertyPort *from_port,
|
LibertyPort *from_port,
|
||||||
LibertyPort *to_port,
|
LibertyPort *to_port,
|
||||||
LibertyPort *related_out,
|
|
||||||
RiseFall *from_rf,
|
RiseFall *from_rf,
|
||||||
TimingArcAttrsPtr attrs)
|
TimingArcAttrsPtr attrs)
|
||||||
{
|
{
|
||||||
|
|
@ -434,24 +414,24 @@ LibertyBuilder::makeRegLatchArcs(LibertyCell *cell,
|
||||||
if (seq->clock() && seq->clock()->hasPort(from_port)) {
|
if (seq->clock() && seq->clock()->hasPort(from_port)) {
|
||||||
TimingRole *role = seq->isRegister() ?
|
TimingRole *role = seq->isRegister() ?
|
||||||
TimingRole::regClkToQ() : TimingRole::latchEnToQ();
|
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);
|
from_rf, role, attrs);
|
||||||
}
|
}
|
||||||
else if (seq->isLatch()
|
else if (seq->isLatch()
|
||||||
&& seq->data()
|
&& seq->data()
|
||||||
&& seq->data()->hasPort(from_port))
|
&& 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);
|
from_rf, TimingRole::latchDtoQ(), attrs);
|
||||||
else if ((seq->clear() && seq->clear()->hasPort(from_port))
|
else if ((seq->clear() && seq->clear()->hasPort(from_port))
|
||||||
|| (seq->preset() && seq->preset()->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);
|
from_rf, TimingRole::regSetClr(), attrs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No associated ff/latch - assume register clk->q.
|
// No associated ff/latch - assume register clk->q.
|
||||||
cell->setHasInferedRegTimingArcs(true);
|
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);
|
from_rf, TimingRole::regClkToQ(), attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
TimingArcSet *
|
TimingArcSet *
|
||||||
|
|
@ -477,14 +457,13 @@ TimingArcSet *
|
||||||
LibertyBuilder::makePresetClrArcs(LibertyCell *cell,
|
LibertyBuilder::makePresetClrArcs(LibertyCell *cell,
|
||||||
LibertyPort *from_port,
|
LibertyPort *from_port,
|
||||||
LibertyPort *to_port,
|
LibertyPort *to_port,
|
||||||
LibertyPort *related_out,
|
|
||||||
RiseFall *to_rf,
|
RiseFall *to_rf,
|
||||||
TimingArcAttrsPtr attrs)
|
TimingArcAttrsPtr attrs)
|
||||||
{
|
{
|
||||||
TimingArcSet *arc_set = nullptr;
|
TimingArcSet *arc_set = nullptr;
|
||||||
TimingModel *model = attrs->model(to_rf);
|
TimingModel *model = attrs->model(to_rf);
|
||||||
if (model) {
|
if (model) {
|
||||||
arc_set = makeTimingArcSet(cell, from_port, to_port, related_out,
|
arc_set = makeTimingArcSet(cell, from_port, to_port,
|
||||||
TimingRole::regSetClr(), attrs);
|
TimingRole::regSetClr(), attrs);
|
||||||
RiseFall *opp_rf = to_rf->opposite();
|
RiseFall *opp_rf = to_rf->opposite();
|
||||||
switch (attrs->timingSense()) {
|
switch (attrs->timingSense()) {
|
||||||
|
|
@ -513,12 +492,11 @@ TimingArcSet *
|
||||||
LibertyBuilder::makeTristateEnableArcs(LibertyCell *cell,
|
LibertyBuilder::makeTristateEnableArcs(LibertyCell *cell,
|
||||||
LibertyPort *from_port,
|
LibertyPort *from_port,
|
||||||
LibertyPort *to_port,
|
LibertyPort *to_port,
|
||||||
LibertyPort *related_out,
|
|
||||||
bool to_rise,
|
bool to_rise,
|
||||||
bool to_fall,
|
bool to_fall,
|
||||||
TimingArcAttrsPtr attrs)
|
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);
|
TimingRole::tristateEnable(), attrs);
|
||||||
FuncExpr *tristate_enable = to_port->tristateEnable();
|
FuncExpr *tristate_enable = to_port->tristateEnable();
|
||||||
TimingSense sense = attrs->timingSense();
|
TimingSense sense = attrs->timingSense();
|
||||||
|
|
@ -584,13 +562,11 @@ TimingArcSet *
|
||||||
LibertyBuilder::makeTristateDisableArcs(LibertyCell *cell,
|
LibertyBuilder::makeTristateDisableArcs(LibertyCell *cell,
|
||||||
LibertyPort *from_port,
|
LibertyPort *from_port,
|
||||||
LibertyPort *to_port,
|
LibertyPort *to_port,
|
||||||
LibertyPort *related_out,
|
|
||||||
bool to_rise,
|
bool to_rise,
|
||||||
bool to_fall,
|
bool to_fall,
|
||||||
TimingArcAttrsPtr attrs)
|
TimingArcAttrsPtr attrs)
|
||||||
{
|
{
|
||||||
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port,
|
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port,
|
||||||
related_out,
|
|
||||||
TimingRole::tristateDisable(),
|
TimingRole::tristateDisable(),
|
||||||
attrs);
|
attrs);
|
||||||
TimingSense sense = attrs->timingSense();
|
TimingSense sense = attrs->timingSense();
|
||||||
|
|
@ -656,12 +632,10 @@ LibertyBuilder::makeTristateDisableArcs(LibertyCell *cell,
|
||||||
TimingArcSet *
|
TimingArcSet *
|
||||||
LibertyBuilder::makeClockTreePathArcs(LibertyCell *cell,
|
LibertyBuilder::makeClockTreePathArcs(LibertyCell *cell,
|
||||||
LibertyPort *to_port,
|
LibertyPort *to_port,
|
||||||
LibertyPort *related_out,
|
|
||||||
TimingRole *role,
|
TimingRole *role,
|
||||||
TimingArcAttrsPtr attrs)
|
TimingArcAttrsPtr attrs)
|
||||||
{
|
{
|
||||||
TimingArcSet *arc_set = makeTimingArcSet(cell, nullptr, to_port,
|
TimingArcSet *arc_set = makeTimingArcSet(cell, nullptr, to_port, role, attrs);
|
||||||
related_out, role, attrs);
|
|
||||||
for (auto to_rf : RiseFall::range()) {
|
for (auto to_rf : RiseFall::range()) {
|
||||||
TimingModel *model = attrs->model(to_rf);
|
TimingModel *model = attrs->model(to_rf);
|
||||||
if (model)
|
if (model)
|
||||||
|
|
@ -670,6 +644,16 @@ LibertyBuilder::makeClockTreePathArcs(LibertyCell *cell,
|
||||||
return arc_set;
|
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 *
|
TimingArcSet *
|
||||||
LibertyBuilder::makeTimingArcSet(LibertyCell *cell,
|
LibertyBuilder::makeTimingArcSet(LibertyCell *cell,
|
||||||
LibertyPort *from,
|
LibertyPort *from,
|
||||||
|
|
|
||||||
|
|
@ -75,13 +75,11 @@ public:
|
||||||
TimingArcSet *makeCombinationalArcs(LibertyCell *cell,
|
TimingArcSet *makeCombinationalArcs(LibertyCell *cell,
|
||||||
LibertyPort *from_port,
|
LibertyPort *from_port,
|
||||||
LibertyPort *to_port,
|
LibertyPort *to_port,
|
||||||
LibertyPort *related_out,
|
|
||||||
bool to_rise,
|
bool to_rise,
|
||||||
bool to_fall,
|
bool to_fall,
|
||||||
TimingArcAttrsPtr attrs);
|
TimingArcAttrsPtr attrs);
|
||||||
TimingArcSet *makeClockTreePathArcs(LibertyCell *cell,
|
TimingArcSet *makeClockTreePathArcs(LibertyCell *cell,
|
||||||
LibertyPort *to_port,
|
LibertyPort *to_port,
|
||||||
LibertyPort *related_out,
|
|
||||||
TimingRole *role,
|
TimingRole *role,
|
||||||
TimingArcAttrsPtr attrs);
|
TimingArcAttrsPtr attrs);
|
||||||
|
|
||||||
|
|
@ -105,6 +103,11 @@ protected:
|
||||||
ConcretePort *bus_port,
|
ConcretePort *bus_port,
|
||||||
const char *bus_name,
|
const char *bus_name,
|
||||||
int index);
|
int index);
|
||||||
|
virtual TimingArcSet *makeTimingArcSet(LibertyCell *cell,
|
||||||
|
LibertyPort *from,
|
||||||
|
LibertyPort *to,
|
||||||
|
TimingRole *role,
|
||||||
|
TimingArcAttrsPtr attrs);
|
||||||
virtual TimingArcSet *makeTimingArcSet(LibertyCell *cell,
|
virtual TimingArcSet *makeTimingArcSet(LibertyCell *cell,
|
||||||
LibertyPort *from,
|
LibertyPort *from,
|
||||||
LibertyPort *to,
|
LibertyPort *to,
|
||||||
|
|
@ -123,31 +126,26 @@ protected:
|
||||||
LibertyPort *from_port,
|
LibertyPort *from_port,
|
||||||
LibertyPort *to_port,
|
LibertyPort *to_port,
|
||||||
TimingSense sense,
|
TimingSense sense,
|
||||||
LibertyPort *related_out,
|
|
||||||
TimingArcAttrsPtr attrs);
|
TimingArcAttrsPtr attrs);
|
||||||
TimingArcSet *makeRegLatchArcs(LibertyCell *cell,
|
TimingArcSet *makeRegLatchArcs(LibertyCell *cell,
|
||||||
LibertyPort *from_port,
|
LibertyPort *from_port,
|
||||||
LibertyPort *to_port,
|
LibertyPort *to_port,
|
||||||
LibertyPort *related_out,
|
|
||||||
RiseFall *from_rf,
|
RiseFall *from_rf,
|
||||||
TimingArcAttrsPtr attrs);
|
TimingArcAttrsPtr attrs);
|
||||||
TimingArcSet *makePresetClrArcs(LibertyCell *cell,
|
TimingArcSet *makePresetClrArcs(LibertyCell *cell,
|
||||||
LibertyPort *from_port,
|
LibertyPort *from_port,
|
||||||
LibertyPort *to_port,
|
LibertyPort *to_port,
|
||||||
LibertyPort *related_out,
|
|
||||||
RiseFall *to_rf,
|
RiseFall *to_rf,
|
||||||
TimingArcAttrsPtr attrs);
|
TimingArcAttrsPtr attrs);
|
||||||
TimingArcSet *makeTristateEnableArcs(LibertyCell *cell,
|
TimingArcSet *makeTristateEnableArcs(LibertyCell *cell,
|
||||||
LibertyPort *from_port,
|
LibertyPort *from_port,
|
||||||
LibertyPort *to_port,
|
LibertyPort *to_port,
|
||||||
LibertyPort *related_out,
|
|
||||||
bool to_rise,
|
bool to_rise,
|
||||||
bool to_fall,
|
bool to_fall,
|
||||||
TimingArcAttrsPtr attrs);
|
TimingArcAttrsPtr attrs);
|
||||||
TimingArcSet *makeTristateDisableArcs(LibertyCell *cell,
|
TimingArcSet *makeTristateDisableArcs(LibertyCell *cell,
|
||||||
LibertyPort *from_port,
|
LibertyPort *from_port,
|
||||||
LibertyPort *to_port,
|
LibertyPort *to_port,
|
||||||
LibertyPort *related_out,
|
|
||||||
bool to_rise,
|
bool to_rise,
|
||||||
bool to_fall,
|
bool to_fall,
|
||||||
TimingArcAttrsPtr attrs);
|
TimingArcAttrsPtr attrs);
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@ void
|
||||||
GateLinearModel::gateDelay(const Pvt *,
|
GateLinearModel::gateDelay(const Pvt *,
|
||||||
float,
|
float,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
float,
|
|
||||||
bool,
|
bool,
|
||||||
// return values
|
// return values
|
||||||
ArcDelay &gate_delay,
|
ArcDelay &gate_delay,
|
||||||
|
|
@ -48,7 +47,6 @@ string
|
||||||
GateLinearModel::reportGateDelay(const Pvt *,
|
GateLinearModel::reportGateDelay(const Pvt *,
|
||||||
float,
|
float,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
float,
|
|
||||||
bool,
|
bool,
|
||||||
int digits) const
|
int digits) const
|
||||||
{
|
{
|
||||||
|
|
@ -87,15 +85,14 @@ CheckLinearModel::CheckLinearModel(LibertyCell *cell,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
ArcDelay
|
||||||
CheckLinearModel::checkDelay(const Pvt *,
|
CheckLinearModel::checkDelay(const Pvt *,
|
||||||
float,
|
float,
|
||||||
float,
|
float,
|
||||||
float,
|
float,
|
||||||
bool,
|
bool) const
|
||||||
ArcDelay &margin) const
|
|
||||||
{
|
{
|
||||||
margin = intrinsic_;
|
return intrinsic_;
|
||||||
}
|
}
|
||||||
|
|
||||||
string
|
string
|
||||||
|
|
|
||||||
|
|
@ -104,67 +104,77 @@ void
|
||||||
GateTableModel::gateDelay(const Pvt *pvt,
|
GateTableModel::gateDelay(const Pvt *pvt,
|
||||||
float in_slew,
|
float in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
float related_out_cap,
|
|
||||||
bool pocv_enabled,
|
bool pocv_enabled,
|
||||||
// return values
|
// return values
|
||||||
ArcDelay &gate_delay,
|
ArcDelay &gate_delay,
|
||||||
Slew &drvr_slew) const
|
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_early = 0.0;
|
||||||
float sigma_late = 0.0;
|
float sigma_late = 0.0;
|
||||||
if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()])
|
if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()])
|
||||||
sigma_early = findValue(pvt, 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()])
|
if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()])
|
||||||
sigma_late = findValue(pvt, 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);
|
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()])
|
if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()])
|
||||||
sigma_early = findValue(pvt, 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()])
|
if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()])
|
||||||
sigma_late = findValue(pvt, 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.
|
// Clip negative slews to zero.
|
||||||
if (slew < 0.0)
|
if (slew < 0.0)
|
||||||
slew = 0.0;
|
slew = 0.0;
|
||||||
drvr_slew = makeDelay(slew, sigma_early, sigma_late);
|
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
|
string
|
||||||
GateTableModel::reportGateDelay(const Pvt *pvt,
|
GateTableModel::reportGateDelay(const Pvt *pvt,
|
||||||
float in_slew,
|
float in_slew,
|
||||||
float load_cap,
|
float load_cap,
|
||||||
float related_out_cap,
|
|
||||||
bool pocv_enabled,
|
bool pocv_enabled,
|
||||||
int digits) const
|
int digits) const
|
||||||
{
|
{
|
||||||
string result = reportPvt(cell_, pvt, digits);
|
string result = reportPvt(cell_, pvt, digits);
|
||||||
result += reportTableLookup("Delay", pvt, delay_model_, in_slew,
|
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()])
|
if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()])
|
||||||
result += reportTableLookup("Delay sigma(early)", pvt,
|
result += reportTableLookup("Delay sigma(early)", pvt,
|
||||||
delay_sigma_models_[EarlyLate::earlyIndex()],
|
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()])
|
if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()])
|
||||||
result += reportTableLookup("Delay sigma(late)", pvt,
|
result += reportTableLookup("Delay sigma(late)", pvt,
|
||||||
delay_sigma_models_[EarlyLate::lateIndex()],
|
delay_sigma_models_[EarlyLate::lateIndex()],
|
||||||
in_slew, load_cap, related_out_cap, digits);
|
in_slew, load_cap, 0.0, digits);
|
||||||
result += '\n';
|
result += '\n';
|
||||||
result += reportTableLookup("Slew", pvt, slew_model_, in_slew,
|
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()])
|
if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()])
|
||||||
result += reportTableLookup("Slew sigma(early)", pvt,
|
result += reportTableLookup("Slew sigma(early)", pvt,
|
||||||
slew_sigma_models_[EarlyLate::earlyIndex()],
|
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()])
|
if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()])
|
||||||
result += reportTableLookup("Slew sigma(late)", pvt,
|
result += reportTableLookup("Slew sigma(late)", pvt,
|
||||||
slew_sigma_models_[EarlyLate::lateIndex()],
|
slew_sigma_models_[EarlyLate::lateIndex()],
|
||||||
in_slew, load_cap, related_out_cap, digits);
|
in_slew, load_cap, 0.0, digits);
|
||||||
float drvr_slew = findValue(pvt, slew_model_, in_slew, load_cap, related_out_cap);
|
float drvr_slew = findValue(pvt, slew_model_, in_slew, load_cap, 0.0);
|
||||||
if (drvr_slew < 0.0)
|
if (drvr_slew < 0.0)
|
||||||
result += "Negative slew clipped to 0.0\n";
|
result += "Negative slew clipped to 0.0\n";
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -407,14 +417,12 @@ CheckTableModel::setIsScaled(bool is_scaled)
|
||||||
model_->setIsScaled(is_scaled);
|
model_->setIsScaled(is_scaled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
ArcDelay
|
||||||
CheckTableModel::checkDelay(const Pvt *pvt,
|
CheckTableModel::checkDelay(const Pvt *pvt,
|
||||||
float from_slew,
|
float from_slew,
|
||||||
float to_slew,
|
float to_slew,
|
||||||
float related_out_cap,
|
float related_out_cap,
|
||||||
bool pocv_enabled,
|
bool pocv_enabled) const
|
||||||
// Return values.
|
|
||||||
ArcDelay &margin) const
|
|
||||||
{
|
{
|
||||||
if (model_) {
|
if (model_) {
|
||||||
float mean = findValue(pvt, model_, from_slew, to_slew, related_out_cap);
|
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()])
|
if (pocv_enabled && sigma_models_[EarlyLate::lateIndex()])
|
||||||
sigma_late = findValue(pvt, sigma_models_[EarlyLate::lateIndex()],
|
sigma_late = findValue(pvt, sigma_models_[EarlyLate::lateIndex()],
|
||||||
from_slew, to_slew, related_out_cap);
|
from_slew, to_slew, related_out_cap);
|
||||||
margin = makeDelay(mean, sigma_early, sigma_late);
|
return makeDelay(mean, sigma_early, sigma_late);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
margin = 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
|
|
@ -1577,7 +1585,6 @@ OutputWaveforms::~OutputWaveforms()
|
||||||
current_waveforms_.deleteContents();
|
current_waveforms_.deleteContents();
|
||||||
voltage_waveforms_.deleteContents();
|
voltage_waveforms_.deleteContents();
|
||||||
voltage_currents_.deleteContents();
|
voltage_currents_.deleteContents();
|
||||||
current_voltages_.deleteContents();
|
|
||||||
voltage_times_.deleteContents();
|
voltage_times_.deleteContents();
|
||||||
delete ref_times_;
|
delete ref_times_;
|
||||||
}
|
}
|
||||||
|
|
@ -1635,15 +1642,6 @@ OutputWaveforms::voltageCurrent(float slew,
|
||||||
return waveformValue(slew, cap, volt, voltage_currents_);
|
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
|
float
|
||||||
OutputWaveforms::waveformValue(float slew,
|
OutputWaveforms::waveformValue(float slew,
|
||||||
float cap,
|
float cap,
|
||||||
|
|
@ -1809,7 +1807,6 @@ OutputWaveforms::ensureVoltages()
|
||||||
size_t size = current_waveforms_.size();
|
size_t size = current_waveforms_.size();
|
||||||
voltage_waveforms_.resize(size);
|
voltage_waveforms_.resize(size);
|
||||||
voltage_currents_.resize(size);
|
voltage_currents_.resize(size);
|
||||||
current_voltages_.resize(size);
|
|
||||||
voltage_times_.resize(size);
|
voltage_times_.resize(size);
|
||||||
size_t cap_count = cap_axis_->size();
|
size_t cap_count = cap_axis_->size();
|
||||||
for (size_t slew_index = 0; slew_index < slew_axis_->size(); slew_index++) {
|
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);
|
Table1 *volt_currents = new Table1(currents1, volt_axis);
|
||||||
voltage_currents_[wave_index] = volt_currents;
|
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
|
// Sample the voltage waveform at uniform intervals to speed up
|
||||||
// voltage time lookup.
|
// voltage time lookup.
|
||||||
FloatSeq *voltage_times = new FloatSeq;
|
FloatSeq *voltage_times = new FloatSeq;
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ TimingArc::intrinsicDelay() const
|
||||||
if (model) {
|
if (model) {
|
||||||
ArcDelay arc_delay;
|
ArcDelay arc_delay;
|
||||||
Slew slew;
|
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;
|
return arc_delay;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -446,8 +446,7 @@ MakeTimingModel::makeInputOutputTimingArcs(const Pin *input_pin,
|
||||||
LibertyPort *output_port = modelPort(output_pin);
|
LibertyPort *output_port = modelPort(output_pin);
|
||||||
LibertyPort *input_port = modelPort(input_pin);
|
LibertyPort *input_port = modelPort(input_pin);
|
||||||
attrs->setTimingSense(output_delays.timingSense());
|
attrs->setTimingSense(output_delays.timingSense());
|
||||||
lib_builder_->makeCombinationalArcs(cell_, input_port,
|
lib_builder_->makeCombinationalArcs(cell_, input_port, output_port,
|
||||||
output_port, nullptr,
|
|
||||||
true, true, attrs);
|
true, true, attrs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -552,8 +551,7 @@ MakeTimingModel::findClkInsertionDelays()
|
||||||
TimingRole *role = (min_max == MinMax::min())
|
TimingRole *role = (min_max == MinMax::min())
|
||||||
? TimingRole::clockTreePathMin()
|
? TimingRole::clockTreePathMin()
|
||||||
: TimingRole::clockTreePathMax();
|
: TimingRole::clockTreePathMax();
|
||||||
lib_builder_->makeClockTreePathArcs(cell_, lib_port, nullptr,
|
lib_builder_->makeClockTreePathArcs(cell_, lib_port, role, attrs);
|
||||||
role, attrs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -655,7 +653,7 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin,
|
||||||
float output_load_cap = graph_delay_calc_->loadCap(output_pin, dcalc_ap);
|
float output_load_cap = graph_delay_calc_->loadCap(output_pin, dcalc_ap);
|
||||||
ArcDelay drvr_self_delay;
|
ArcDelay drvr_self_delay;
|
||||||
Slew drvr_self_slew;
|
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);
|
drvr_self_delay, drvr_self_slew);
|
||||||
|
|
||||||
const TableModel *drvr_table = drvr_gate_model->delayModel();
|
const TableModel *drvr_table = drvr_gate_model->delayModel();
|
||||||
|
|
@ -670,7 +668,7 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin,
|
||||||
// get slew from driver input pin
|
// get slew from driver input pin
|
||||||
ArcDelay gate_delay;
|
ArcDelay gate_delay;
|
||||||
Slew gate_slew;
|
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);
|
gate_delay, gate_slew);
|
||||||
// Remove the self delay driving the output pin net load cap.
|
// Remove the self delay driving the output pin net load cap.
|
||||||
load_values->push_back(delayAsFloat(delay + gate_delay
|
load_values->push_back(delayAsFloat(delay + gate_delay
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue