1 // OpenSTA, Static Timing Analyzer
2 // Copyright (c) 2021, Parallax Software, Inc.
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <https://www.gnu.org/licenses/>.
16
17 #include "LumpedCapDelayCalc.hh"
18
19 #include "Debug.hh"
20 #include "Units.hh"
21 #include "TimingArc.hh"
22 #include "TimingModel.hh"
23 #include "Liberty.hh"
24 #include "Network.hh"
25 #include "Sdc.hh"
26 #include "Parasitics.hh"
27 #include "DcalcAnalysisPt.hh"
28 #include "GraphDelayCalc.hh"
29
30 namespace sta {
31
32 ArcDelayCalc *
makeLumpedCapDelayCalc(StaState * sta)33 makeLumpedCapDelayCalc(StaState *sta)
34 {
35 return new LumpedCapDelayCalc(sta);
36 }
37
LumpedCapDelayCalc(StaState * sta)38 LumpedCapDelayCalc::LumpedCapDelayCalc(StaState *sta) :
39 ArcDelayCalc(sta)
40 {
41 }
42
43 ArcDelayCalc *
copy()44 LumpedCapDelayCalc::copy()
45 {
46 return new LumpedCapDelayCalc(this);
47 }
48
49 Parasitic *
findParasitic(const Pin * drvr_pin,const RiseFall * rf,const DcalcAnalysisPt * dcalc_ap)50 LumpedCapDelayCalc::findParasitic(const Pin *drvr_pin,
51 const RiseFall *rf,
52 const DcalcAnalysisPt *dcalc_ap)
53 {
54 // set_load has precidence over parasitics.
55 if (!sdc_->drvrPinHasWireCap(drvr_pin)) {
56 Parasitic *parasitic = nullptr;
57 const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
58 if (parasitics_->haveParasitics()) {
59 // Prefer PiElmore.
60 parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap);
61 if (parasitic)
62 return parasitic;
63
64 Parasitic *parasitic_network =
65 parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
66 if (parasitic_network) {
67 parasitics_->reduceToPiElmore(parasitic_network, drvr_pin,
68 dcalc_ap->operatingConditions(),
69 dcalc_ap->corner(),
70 dcalc_ap->constraintMinMax(),
71 parasitic_ap);
72 parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap);
73 reduced_parasitic_drvrs_.push_back(drvr_pin);
74 return parasitic;
75 }
76 }
77
78 const MinMax *cnst_min_max = dcalc_ap->constraintMinMax();
79 Wireload *wireload = sdc_->wireloadDefaulted(cnst_min_max);
80 if (wireload) {
81 float pin_cap, wire_cap, fanout;
82 bool has_wire_cap;
83 graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap,
84 pin_cap, wire_cap, fanout, has_wire_cap);
85 parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload,
86 fanout, pin_cap,
87 dcalc_ap->operatingConditions(),
88 dcalc_ap->corner(),
89 cnst_min_max,
90 parasitic_ap);
91 // Estimated parasitics are not recorded in the "database", so
92 // it for deletion after the drvr pin delay calc is finished.
93 if (parasitic)
94 unsaved_parasitics_.push_back(parasitic);
95 return parasitic;
96 }
97 }
98 return nullptr;
99 }
100
101 ReducedParasiticType
reducedParasiticType() const102 LumpedCapDelayCalc::reducedParasiticType() const
103 {
104 return ReducedParasiticType::pi_elmore;
105 }
106
107 void
finishDrvrPin()108 LumpedCapDelayCalc::finishDrvrPin()
109 {
110 for (auto parasitic : unsaved_parasitics_)
111 parasitics_->deleteUnsavedParasitic(parasitic);
112 unsaved_parasitics_.clear();
113 for (auto drvr_pin : reduced_parasitic_drvrs_)
114 parasitics_->deleteDrvrReducedParasitics(drvr_pin);
115 reduced_parasitic_drvrs_.clear();
116 }
117
118 void
inputPortDelay(const Pin *,float in_slew,const RiseFall * rf,Parasitic *,const DcalcAnalysisPt *)119 LumpedCapDelayCalc::inputPortDelay(const Pin *, float in_slew,
120 const RiseFall *rf,
121 Parasitic *,
122 const DcalcAnalysisPt *)
123 {
124 drvr_slew_ = in_slew;
125 drvr_rf_ = rf;
126 drvr_library_ = network_->defaultLibertyLibrary();
127 multi_drvr_slew_factor_ = 1.0F;
128 }
129
130 float
ceff(const LibertyCell *,TimingArc *,const Slew &,float load_cap,Parasitic *,float,const Pvt *,const DcalcAnalysisPt *)131 LumpedCapDelayCalc::ceff(const LibertyCell *,
132 TimingArc *,
133 const Slew &,
134 float load_cap,
135 Parasitic *,
136 float,
137 const Pvt *,
138 const DcalcAnalysisPt *)
139 {
140 return load_cap;
141 }
142
143 void
gateDelay(const LibertyCell * drvr_cell,TimingArc * arc,const Slew & in_slew,float load_cap,Parasitic *,float related_out_cap,const Pvt * pvt,const DcalcAnalysisPt * dcalc_ap,ArcDelay & gate_delay,Slew & drvr_slew)144 LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell,
145 TimingArc *arc,
146 const Slew &in_slew,
147 float load_cap,
148 Parasitic *,
149 float related_out_cap,
150 const Pvt *pvt,
151 const DcalcAnalysisPt *dcalc_ap,
152 // Return values.
153 ArcDelay &gate_delay,
154 Slew &drvr_slew)
155 {
156 GateTimingModel *model = gateModel(arc, dcalc_ap);
157 debugPrint(debug_, "delay_calc", 3,
158 " in_slew = %s load_cap = %s related_load_cap = %s lumped",
159 delayAsString(in_slew, this),
160 units()->capacitanceUnit()->asString(load_cap),
161 units()->capacitanceUnit()->asString(related_out_cap));
162 if (model) {
163 ArcDelay gate_delay1;
164 Slew drvr_slew1;
165 float in_slew1 = delayAsFloat(in_slew);
166 model->gateDelay(drvr_cell, pvt, in_slew1, load_cap, related_out_cap,
167 pocv_enabled_, gate_delay1, drvr_slew1);
168 gate_delay = gate_delay1;
169 drvr_slew = drvr_slew1;
170 drvr_slew_ = drvr_slew1;
171 }
172 else {
173 gate_delay = delay_zero;
174 drvr_slew = delay_zero;
175 drvr_slew_ = 0.0;
176 }
177 drvr_rf_ = arc->toTrans()->asRiseFall();
178 drvr_library_ = drvr_cell->libertyLibrary();
179 multi_drvr_slew_factor_ = 1.0F;
180 }
181
182 void
loadDelay(const Pin * load_pin,ArcDelay & wire_delay,Slew & load_slew)183 LumpedCapDelayCalc::loadDelay(const Pin *load_pin,
184 ArcDelay &wire_delay,
185 Slew &load_slew)
186 {
187 Delay wire_delay1 = 0.0;
188 Slew load_slew1 = drvr_slew_ * multi_drvr_slew_factor_;
189 thresholdAdjust(load_pin, wire_delay1, load_slew1);
190 wire_delay = wire_delay1;
191 load_slew = load_slew1;
192 }
193
194 void
thresholdAdjust(const Pin * load_pin,ArcDelay & load_delay,Slew & load_slew)195 LumpedCapDelayCalc::thresholdAdjust(const Pin *load_pin,
196 ArcDelay &load_delay,
197 Slew &load_slew)
198 {
199 LibertyLibrary *load_library = thresholdLibrary(load_pin);
200 if (load_library
201 && drvr_library_
202 && load_library != drvr_library_) {
203 float drvr_vth = drvr_library_->outputThreshold(drvr_rf_);
204 float load_vth = load_library->inputThreshold(drvr_rf_);
205 float drvr_slew_delta = drvr_library_->slewUpperThreshold(drvr_rf_)
206 - drvr_library_->slewLowerThreshold(drvr_rf_);
207 float load_delay_delta =
208 delayAsFloat(load_slew) * ((load_vth - drvr_vth) / drvr_slew_delta);
209 load_delay += (drvr_rf_ == RiseFall::rise())
210 ? load_delay_delta
211 : -load_delay_delta;
212 float load_slew_delta = load_library->slewUpperThreshold(drvr_rf_)
213 - load_library->slewLowerThreshold(drvr_rf_);
214 float drvr_slew_derate = drvr_library_->slewDerateFromLibrary();
215 float load_slew_derate = load_library->slewDerateFromLibrary();
216 load_slew = load_slew * ((load_slew_delta / load_slew_derate)
217 / (drvr_slew_delta / drvr_slew_derate));
218 }
219 }
220
221 LibertyLibrary *
thresholdLibrary(const Pin * load_pin)222 LumpedCapDelayCalc::thresholdLibrary(const Pin *load_pin)
223 {
224 if (network_->isTopLevelPort(load_pin))
225 // Input/output slews use the default (first read) library
226 // for slew thresholds.
227 return network_->defaultLibertyLibrary();
228 else {
229 LibertyPort *lib_port = network_->libertyPort(load_pin);
230 if (lib_port)
231 return lib_port->libertyCell()->libertyLibrary();
232 else
233 return network_->defaultLibertyLibrary();
234 }
235 }
236
237 void
reportGateDelay(const LibertyCell * drvr_cell,TimingArc * arc,const Slew & in_slew,float load_cap,Parasitic *,float related_out_cap,const Pvt * pvt,const DcalcAnalysisPt * dcalc_ap,int digits,string * result)238 LumpedCapDelayCalc::reportGateDelay(const LibertyCell *drvr_cell,
239 TimingArc *arc,
240 const Slew &in_slew,
241 float load_cap,
242 Parasitic *,
243 float related_out_cap,
244 const Pvt *pvt,
245 const DcalcAnalysisPt *dcalc_ap,
246 int digits,
247 string *result)
248 {
249 GateTimingModel *model = gateModel(arc, dcalc_ap);
250 if (model) {
251 float in_slew1 = delayAsFloat(in_slew);
252 model->reportGateDelay(drvr_cell, pvt, in_slew1, load_cap,
253 related_out_cap, false, digits, result);
254 }
255 }
256
257 void
checkDelay(const LibertyCell * cell,TimingArc * arc,const Slew & from_slew,const Slew & to_slew,float related_out_cap,const Pvt * pvt,const DcalcAnalysisPt * dcalc_ap,ArcDelay & margin)258 LumpedCapDelayCalc::checkDelay(const LibertyCell *cell,
259 TimingArc *arc,
260 const Slew &from_slew,
261 const Slew &to_slew,
262 float related_out_cap,
263 const Pvt *pvt,
264 const DcalcAnalysisPt *dcalc_ap,
265 // Return values.
266 ArcDelay &margin)
267 {
268 CheckTimingModel *model = checkModel(arc, dcalc_ap);
269 if (model) {
270 float from_slew1 = delayAsFloat(from_slew);
271 float to_slew1 = delayAsFloat(to_slew);
272 model->checkDelay(cell, pvt, from_slew1, to_slew1, related_out_cap,
273 pocv_enabled_, margin);
274 }
275 else
276 margin = delay_zero;
277 }
278
279 void
reportCheckDelay(const LibertyCell * cell,TimingArc * arc,const Slew & from_slew,const char * from_slew_annotation,const Slew & to_slew,float related_out_cap,const Pvt * pvt,const DcalcAnalysisPt * dcalc_ap,int digits,string * result)280 LumpedCapDelayCalc::reportCheckDelay(const LibertyCell *cell,
281 TimingArc *arc,
282 const Slew &from_slew,
283 const char *from_slew_annotation,
284 const Slew &to_slew,
285 float related_out_cap,
286 const Pvt *pvt,
287 const DcalcAnalysisPt *dcalc_ap,
288 int digits,
289 string *result)
290 {
291 CheckTimingModel *model = checkModel(arc, dcalc_ap);
292 if (model) {
293 float from_slew1 = delayAsFloat(from_slew);
294 float to_slew1 = delayAsFloat(to_slew);
295 model->reportCheckDelay(cell, pvt, from_slew1, from_slew_annotation, to_slew1,
296 related_out_cap, false, digits, result);
297 }
298 }
299
300 void
setMultiDrvrSlewFactor(float factor)301 LumpedCapDelayCalc::setMultiDrvrSlewFactor(float factor)
302 {
303 multi_drvr_slew_factor_ = factor;
304 }
305
306 } // namespace
307