OpenSTA/parasitics/EstimateParasitics.cc

240 lines
6.8 KiB
C++
Raw Normal View History

2018-09-28 17:54:21 +02:00
// OpenSTA, Static Timing Analyzer
2020-03-07 03:50:37 +01:00
// Copyright (c) 2020, Parallax Software, Inc.
2018-09-28 17:54:21 +02:00
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
2020-04-05 23:53:44 +02:00
#include "EstimateParasitics.hh"
2020-04-05 20:35:51 +02:00
2020-04-05 23:53:44 +02:00
#include "Wireload.hh"
#include "Liberty.hh"
#include "Network.hh"
#include "Sdc.hh"
#include "Parasitics.hh"
2018-09-28 17:54:21 +02:00
namespace sta {
// For multiple driver nets, output pin capacitances are treated as
// loads when driven by a different pin.
void
EstimateParasitics::estimatePiElmore(const Pin *drvr_pin,
2019-11-11 23:30:19 +01:00
const RiseFall *rf,
2018-09-28 17:54:21 +02:00
const Wireload *wireload,
float fanout,
float net_pin_cap,
const OperatingConditions *op_cond,
const Corner *corner,
const MinMax *min_max,
const StaState *sta,
float &c2,
float &rpi,
float &c1,
float &elmore_res,
float &elmore_cap,
bool &elmore_use_load_cap)
{
float wireload_cap, wireload_res;
wireload->findWireload(fanout, op_cond, wireload_cap, wireload_res);
2019-03-13 01:25:53 +01:00
WireloadTree tree = WireloadTree::unknown;
2018-09-28 17:54:21 +02:00
if (op_cond)
tree = op_cond->wireloadTree();
switch (tree) {
2019-03-13 01:25:53 +01:00
case WireloadTree::worst_case:
2018-09-28 17:54:21 +02:00
estimatePiElmoreWorst(drvr_pin, wireload_cap, wireload_res,
2019-11-11 23:30:19 +01:00
fanout, net_pin_cap, rf, op_cond, corner,
2018-09-28 17:54:21 +02:00
min_max, sta,
c2, rpi, c1, elmore_res,
elmore_cap, elmore_use_load_cap);
break;
2019-03-13 01:25:53 +01:00
case WireloadTree::balanced:
case WireloadTree::unknown:
2018-09-28 17:54:21 +02:00
estimatePiElmoreBalanced(drvr_pin, wireload_cap, wireload_res,
2019-11-11 23:30:19 +01:00
fanout, net_pin_cap, rf, op_cond,
2018-09-28 17:54:21 +02:00
corner, min_max,sta,
c2, rpi, c1, elmore_res,
elmore_cap, elmore_use_load_cap);
break;
2019-03-13 01:25:53 +01:00
case WireloadTree::best_case:
2019-11-11 23:30:19 +01:00
estimatePiElmoreBest(drvr_pin, wireload_cap, net_pin_cap, rf,
2018-09-28 17:54:21 +02:00
op_cond, corner, min_max,
c2, rpi, c1, elmore_res, elmore_cap,
elmore_use_load_cap);
break;
}
}
// No wire resistance, so load is lumped capacitance.
void
EstimateParasitics::estimatePiElmoreBest(const Pin *,
float wireload_cap,
float net_pin_cap,
2019-11-11 23:30:19 +01:00
const RiseFall *,
2018-09-28 17:54:21 +02:00
const OperatingConditions *,
const Corner *,
const MinMax *,
float &c2,
float &rpi,
float &c1,
float &elmore_res,
float &elmore_cap,
bool &elmore_use_load_cap) const
{
c2 = wireload_cap + net_pin_cap;
rpi = 0.0;
c1 = 0.0;
elmore_res = 0.0;
elmore_cap = 0.0;
elmore_use_load_cap = false;
}
// All load capacitance (except driver pin cap) is on the far side of
// the resistor.
void
EstimateParasitics::estimatePiElmoreWorst(const Pin *drvr_pin,
float wireload_cap,
float wireload_res,
float,
float net_pin_cap,
2019-11-11 23:30:19 +01:00
const RiseFall *rf,
2018-09-28 17:54:21 +02:00
const OperatingConditions *op_cond,
const Corner *corner,
const MinMax *min_max,
const StaState *sta,
float &c2,
float &rpi,
float &c1,
float &elmore_res,
float &elmore_cap,
bool &elmore_use_load_cap)
{
Sdc *sdc = sta->sdc();
float drvr_pin_cap = 0.0;
2019-11-11 23:30:19 +01:00
drvr_pin_cap = sdc->pinCapacitance(drvr_pin, rf, op_cond, corner, min_max);
2018-09-28 17:54:21 +02:00
c2 = drvr_pin_cap;
rpi = wireload_res;
c1 = net_pin_cap - drvr_pin_cap + wireload_cap;
elmore_res = wireload_res;
elmore_cap = c1;
elmore_use_load_cap = false;
}
// Each load capacitance and wireload cap/fanout has resistance/fanout
// connecting it to the driver.
// Use O'Brien/Savarino reduction to rspf (pi elmore) model.
void
EstimateParasitics::estimatePiElmoreBalanced(const Pin *drvr_pin,
float wireload_cap,
float wireload_res,
float fanout,
float net_pin_cap,
2019-11-11 23:30:19 +01:00
const RiseFall *rf,
2018-09-28 17:54:21 +02:00
const OperatingConditions *op_cond,
const Corner *corner,
const MinMax *min_max,
const StaState *sta,
float &c2,
float &rpi,
float &c1,
float &elmore_res,
float &elmore_cap,
bool &elmore_use_load_cap)
{
2020-06-06 07:02:54 +02:00
if (wireload_res == 0.0
|| fanout == 0) {
2018-09-28 17:54:21 +02:00
// No resistance, so load is capacitance only.
c2 = wireload_cap + net_pin_cap;
rpi = 0.0;
c1 = 0.0;
elmore_res = 0.0;
elmore_cap = 0.0;
elmore_use_load_cap = false;
}
else {
Sdc *sdc = sta->sdc();
Network *network = sta->network();
2020-12-14 02:21:35 +01:00
Report *report = sta->report();
2018-09-28 17:54:21 +02:00
double res_fanout = wireload_res / fanout;
double cap_fanout = wireload_cap / fanout;
// Find admittance moments.
double y1 = 0.0;
double y2 = 0.0;
double y3 = 0.0;
2019-11-11 23:30:19 +01:00
y1 = sdc->pinCapacitance(drvr_pin, rf, op_cond, corner, min_max);
2018-09-28 17:54:21 +02:00
PinConnectedPinIterator *load_iter =
network->connectedPinIterator(drvr_pin);
while (load_iter->hasNext()) {
const Pin *load_pin = load_iter->next();
// Bidirects don't count themselves as loads.
if (load_pin != drvr_pin && network->isLoad(load_pin)) {
Port *port = network->port(load_pin);
double load_cap = 0.0;
if (network->isLeaf(load_pin))
2019-11-11 23:30:19 +01:00
load_cap = sdc->pinCapacitance(load_pin, rf, op_cond,
2018-09-28 17:54:21 +02:00
corner, min_max);
else if (network->isTopLevelPort(load_pin))
2019-11-11 23:30:19 +01:00
load_cap = sdc->portExtCap(port, rf, min_max);
2018-09-28 17:54:21 +02:00
else
2020-12-20 19:21:50 +01:00
report->critical(597, "load pin not leaf or top level");
2018-09-28 17:54:21 +02:00
double cap = load_cap + cap_fanout;
double y2_ = res_fanout * cap * cap;
y1 += cap;
y2 += -y2_;
y3 += y2_ * res_fanout * cap;
}
}
delete load_iter;
2019-04-01 18:05:07 +02:00
if (y3 == 0) {
// No loads.
c1 = 0.0;
c2 = 0.0;
rpi = 0.0;
}
else {
c1 = static_cast<float>(y2 * y2 / y3);
c2 = static_cast<float>(y1 - y2 * y2 / y3);
rpi = static_cast<float>(-y3 * y3 / (y2 * y2 * y2));
}
2018-09-28 17:54:21 +02:00
elmore_res = static_cast<float>(res_fanout);
elmore_cap = static_cast<float>(cap_fanout);
elmore_use_load_cap = true;
}
}
#if 0
static void
selectWireload(Network *network)
{
// Look for a default wireload selection group.
WireloadSelection *selection;
float area = instanceArea(network->topInstance(), network);
Wireload *wireload = selection->findWireload(area);
}
static float
instanceArea(Instance *inst,
Network *network)
{
float area = 0.0;
LeafInstanceIterator *inst_iter = network->leafInstanceIterator();
while (network->hasNext(inst_iter)) {
Instance *leaf = network->next(inst_iter);
area += network->cell(leaf)->area();
}
return area;
}
#endif
} // namespace