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