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 "Stats.hh"
18 #include "PortDirection.hh"
19 #include "Network.hh"
20 #include "Graph.hh"
21 #include "DisabledPorts.hh"
22 #include "PortDelay.hh"
23 #include "ClockLatency.hh"
24 #include "Sdc.hh"
25 
26 namespace sta {
27 
28 static void
29 annotateGraphDisabledWireEdge(Pin *from_pin,
30 			      Pin *to_pin,
31 			      Graph *graph);
32 
33 // Annotate constraints to the timing graph.
34 void
annotateGraph()35 Sdc::annotateGraph()
36 {
37   Stats stats(debug_, report_);
38   // All output pins are considered constrained because
39   // they may be downstream from a set_min/max_delay -from that
40   // does not have a set_output_delay.
41   annotateGraphConstrainOutputs();
42   annotateDisables();
43   annotateGraphOutputDelays();
44   annotateGraphDataChecks();
45   annotateHierClkLatency();
46   stats.report("Annotate constraints to graph");
47 }
48 
49 void
annotateGraphConstrainOutputs()50 Sdc::annotateGraphConstrainOutputs()
51 {
52   Instance *top_inst = network_->topInstance();
53   InstancePinIterator *pin_iter = network_->pinIterator(top_inst);
54   while (pin_iter->hasNext()) {
55     Pin *pin = pin_iter->next();
56     if (network_->direction(pin)->isAnyOutput())
57       annotateGraphConstrained(pin);
58   }
59   delete pin_iter;
60 }
61 
62 void
annotateDisables()63 Sdc::annotateDisables()
64 {
65   PinSet::Iterator pin_iter(disabled_pins_);
66   while (pin_iter.hasNext()) {
67     Pin *pin = pin_iter.next();
68     annotateGraphDisabled(pin);
69   }
70 
71   if (!disabled_lib_ports_.empty()) {
72     VertexIterator vertex_iter(graph_);
73     while (vertex_iter.hasNext()) {
74       Vertex *vertex = vertex_iter.next();
75       Pin *pin = vertex->pin();
76       LibertyPort *port = network_->libertyPort(pin);
77       if (disabled_lib_ports_.hasKey(port))
78 	annotateGraphDisabled(pin);
79     }
80   }
81 
82   Instance *top_inst = network_->topInstance();
83   PortSet::Iterator port_iter(disabled_ports_);
84   while (port_iter.hasNext()) {
85     Port *port = port_iter.next();
86     Pin *pin = network_->findPin(top_inst, port);
87     annotateGraphDisabled(pin);
88   }
89 
90   PinPairSet::Iterator pair_iter(disabled_wire_edges_);
91   while (pair_iter.hasNext()) {
92     PinPair *pair = pair_iter.next();
93     annotateGraphDisabledWireEdge(pair->first, pair->second, graph_);
94   }
95 
96   EdgeSet::Iterator edge_iter(disabled_edges_);
97   while (edge_iter.hasNext()) {
98     Edge *edge = edge_iter.next();
99     edge->setIsDisabledConstraint(true);
100   }
101 
102   DisabledInstancePortsMap::Iterator disable_inst_iter(disabled_inst_ports_);
103   while (disable_inst_iter.hasNext()) {
104     DisabledInstancePorts *disabled_inst = disable_inst_iter.next();
105     setEdgeDisabledInstPorts(disabled_inst);
106   }
107 }
108 
109 class DisableHpinEdgeVisitor : public HierPinThruVisitor
110 {
111 public:
112   DisableHpinEdgeVisitor(Graph *graph);
113   virtual void visit(Pin *from_pin,
114 		     Pin *to_pin);
115 
116 protected:
117   bool annotate_;
118   Graph *graph_;
119 
120 private:
121   DISALLOW_COPY_AND_ASSIGN(DisableHpinEdgeVisitor);
122 };
123 
DisableHpinEdgeVisitor(Graph * graph)124 DisableHpinEdgeVisitor::DisableHpinEdgeVisitor(Graph *graph) :
125   HierPinThruVisitor(),
126   graph_(graph)
127 {
128 }
129 
130 void
visit(Pin * from_pin,Pin * to_pin)131 DisableHpinEdgeVisitor::visit(Pin *from_pin,
132 			      Pin *to_pin)
133 {
134   annotateGraphDisabledWireEdge(from_pin, to_pin, graph_);
135 }
136 
137 static void
annotateGraphDisabledWireEdge(Pin * from_pin,Pin * to_pin,Graph * graph)138 annotateGraphDisabledWireEdge(Pin *from_pin,
139 			      Pin *to_pin,
140 			      Graph *graph)
141 {
142   Vertex *from_vertex = graph->pinDrvrVertex(from_pin);
143   Vertex *to_vertex = graph->pinLoadVertex(to_pin);
144   if (from_vertex && to_vertex) {
145     VertexOutEdgeIterator edge_iter(from_vertex, graph);
146     while (edge_iter.hasNext()) {
147       Edge *edge = edge_iter.next();
148       if (edge->isWire()
149 	  && edge->to(graph) == to_vertex)
150 	edge->setIsDisabledConstraint(true);
151     }
152   }
153 }
154 
155 void
annotateGraphDisabled(const Pin * pin)156 Sdc::annotateGraphDisabled(const Pin *pin)
157 {
158   Vertex *vertex, *bidirect_drvr_vertex;
159   graph_->pinVertices(pin, vertex, bidirect_drvr_vertex);
160   vertex->setIsDisabledConstraint(true);
161   if (bidirect_drvr_vertex)
162     bidirect_drvr_vertex->setIsDisabledConstraint(true);
163 }
164 
165 void
setEdgeDisabledInstPorts(DisabledInstancePorts * disabled_inst)166 Sdc::setEdgeDisabledInstPorts(DisabledInstancePorts *disabled_inst)
167 {
168   setEdgeDisabledInstPorts(disabled_inst, disabled_inst->instance());
169 }
170 
171 void
setEdgeDisabledInstPorts(DisabledPorts * disabled_port,Instance * inst)172 Sdc::setEdgeDisabledInstPorts(DisabledPorts *disabled_port,
173 			      Instance *inst)
174 {
175   if (disabled_port->all()) {
176     InstancePinIterator *pin_iter = network_->pinIterator(inst);
177     while (pin_iter->hasNext()) {
178       Pin *pin = pin_iter->next();
179       // set_disable_timing instance does not disable timing checks.
180       setEdgeDisabledInstFrom(pin, false);
181     }
182     delete pin_iter;
183   }
184 
185   // Disable from pins.
186   LibertyPortSet::Iterator from_iter(disabled_port->from());
187   while (from_iter.hasNext()) {
188     LibertyPort *from_port = from_iter.next();
189     Pin *from_pin = network_->findPin(inst, from_port);
190     if (from_pin)
191       setEdgeDisabledInstFrom(from_pin, true);
192   }
193 
194   // Disable to pins.
195   LibertyPortSet::Iterator to_iter(disabled_port->to());
196   while (to_iter.hasNext()) {
197     LibertyPort *to_port = to_iter.next();
198     Pin *to_pin = network_->findPin(inst, to_port);
199     if (to_pin) {
200       if (network_->direction(to_pin)->isAnyOutput()) {
201 	Vertex *vertex = graph_->pinDrvrVertex(to_pin);
202 	if (vertex) {
203 	  VertexInEdgeIterator edge_iter(vertex, graph_);
204 	  while (edge_iter.hasNext()) {
205 	    Edge *edge = edge_iter.next();
206 	    edge->setIsDisabledConstraint(true);
207 	  }
208 	}
209       }
210     }
211   }
212 
213   // Disable from/to pins.
214   LibertyPortPairSet::Iterator from_to_iter(disabled_port->fromTo());
215   while (from_to_iter.hasNext()) {
216     LibertyPortPair *pair = from_to_iter.next();
217     const LibertyPort *from_port = pair->first;
218     const LibertyPort *to_port = pair->second;
219     Pin *from_pin = network_->findPin(inst, from_port);
220     Pin *to_pin = network_->findPin(inst, to_port);
221     if (from_pin && network_->direction(from_pin)->isAnyInput()
222 	&& to_pin) {
223       Vertex *from_vertex = graph_->pinLoadVertex(from_pin);
224       Vertex *to_vertex = graph_->pinDrvrVertex(to_pin);
225       if (from_vertex && to_vertex) {
226 	VertexOutEdgeIterator edge_iter(from_vertex, graph_);
227 	while (edge_iter.hasNext()) {
228 	  Edge *edge = edge_iter.next();
229 	  if (edge->to(graph_) == to_vertex)
230 	    edge->setIsDisabledConstraint(true);
231 	}
232       }
233     }
234   }
235 }
236 
237 void
setEdgeDisabledInstFrom(Pin * from_pin,bool disable_checks)238 Sdc::setEdgeDisabledInstFrom(Pin *from_pin,
239 			     bool disable_checks)
240 {
241   if (network_->direction(from_pin)->isAnyInput()) {
242     Vertex *from_vertex = graph_->pinLoadVertex(from_pin);
243     if (from_vertex) {
244       VertexOutEdgeIterator edge_iter(from_vertex, graph_);
245       while (edge_iter.hasNext()) {
246 	Edge *edge = edge_iter.next();
247 	if (disable_checks
248 	    || !edge->role()->isTimingCheck())
249 	  edge->setIsDisabledConstraint(true);
250       }
251     }
252   }
253 }
254 
255 void
annotateGraphOutputDelays()256 Sdc::annotateGraphOutputDelays()
257 {
258   for (OutputDelay *output_delay : output_delays_) {
259     for (Pin *lpin : output_delay->leafPins())
260       annotateGraphConstrained(lpin);
261   }
262 }
263 
264 void
annotateGraphDataChecks()265 Sdc::annotateGraphDataChecks()
266 {
267   DataChecksMap::Iterator data_checks_iter(data_checks_to_map_);
268   while (data_checks_iter.hasNext()) {
269     DataCheckSet *checks = data_checks_iter.next();
270     DataCheckSet::Iterator check_iter(checks);
271     // There may be multiple data checks on a single pin,
272     // but we only need to mark it as constrained once.
273     if (check_iter.hasNext()) {
274       DataCheck *check = check_iter.next();
275       annotateGraphConstrained(check->to());
276     }
277   }
278 }
279 
280 void
annotateGraphConstrained(const PinSet * pins)281 Sdc::annotateGraphConstrained(const PinSet *pins)
282 {
283   PinSet::ConstIterator pin_iter(pins);
284   while (pin_iter.hasNext()) {
285     const Pin *pin = pin_iter.next();
286     annotateGraphConstrained(pin);
287   }
288 }
289 
290 void
annotateGraphConstrained(const InstanceSet * insts)291 Sdc::annotateGraphConstrained(const InstanceSet *insts)
292 {
293   InstanceSet::ConstIterator inst_iter(insts);
294   while (inst_iter.hasNext()) {
295     const Instance *inst = inst_iter.next();
296     annotateGraphConstrained(inst);
297   }
298 }
299 
300 void
annotateGraphConstrained(const Instance * inst)301 Sdc::annotateGraphConstrained(const Instance *inst)
302 {
303   InstancePinIterator *pin_iter = network_->pinIterator(inst);
304   while (pin_iter->hasNext()) {
305     Pin *pin = pin_iter->next();
306     if (network_->direction(pin)->isAnyInput())
307       annotateGraphConstrained(pin);
308   }
309   delete pin_iter;
310 }
311 
312 void
annotateGraphConstrained(const Pin * pin)313 Sdc::annotateGraphConstrained(const Pin *pin)
314 {
315   Vertex *vertex, *bidirect_drvr_vertex;
316   graph_->pinVertices(pin, vertex, bidirect_drvr_vertex);
317   // Pin may be hierarchical and have no vertex.
318   if (vertex)
319     vertex->setIsConstrained(true);
320   if (bidirect_drvr_vertex)
321     bidirect_drvr_vertex->setIsConstrained(true);
322 }
323 
324 void
annotateHierClkLatency()325 Sdc::annotateHierClkLatency()
326 {
327   ClockLatencies::Iterator latency_iter(clk_latencies_);
328   while (latency_iter.hasNext()) {
329     ClockLatency *latency = latency_iter.next();
330     const Pin *pin = latency->pin();
331     if (pin && network_->isHierarchical(pin))
332       annotateHierClkLatency(pin, latency);
333   }
334 }
335 
336 void
annotateHierClkLatency(const Pin * hpin,ClockLatency * latency)337 Sdc::annotateHierClkLatency(const Pin *hpin,
338 			    ClockLatency *latency)
339 {
340   EdgesThruHierPinIterator edge_iter(hpin, network_, graph_);
341   while (edge_iter.hasNext()) {
342     Edge *edge = edge_iter.next();
343     edge_clk_latency_[edge] = latency;
344   }
345 }
346 
347 ClockLatency *
clockLatency(Edge * edge) const348 Sdc::clockLatency(Edge *edge) const
349 {
350   return edge_clk_latency_.findKey(edge);
351 }
352 
353 void
clockLatency(Edge * edge,const RiseFall * rf,const MinMax * min_max,float & latency,bool & exists) const354 Sdc::clockLatency(Edge *edge,
355 		  const RiseFall *rf,
356 		  const MinMax *min_max,
357 		  // Return values.
358 		  float &latency,
359 		  bool &exists) const
360 {
361   ClockLatency *latencies = edge_clk_latency_.findKey(edge);
362   if (latencies)
363     latencies->delay(rf, min_max, latency, exists);
364   else {
365     latency = 0.0;
366     exists = false;
367   }
368 }
369 
370 ////////////////////////////////////////////////////////////////
371 
372 void
removeGraphAnnotations()373 Sdc::removeGraphAnnotations()
374 {
375   VertexIterator vertex_iter(graph_);
376   while (vertex_iter.hasNext()) {
377     Vertex *vertex = vertex_iter.next();
378     vertex->setIsDisabledConstraint(false);
379     vertex->setIsConstrained(false);
380 
381     VertexOutEdgeIterator edge_iter(vertex, graph_);
382     while (edge_iter.hasNext()) {
383       Edge *edge = edge_iter.next();
384       edge->setIsDisabledConstraint(false);
385     }
386   }
387   edge_clk_latency_.clear();
388 }
389 
390 void
searchPreamble()391 Sdc::searchPreamble()
392 {
393   ensureClkHpinDisables();
394   ensureClkGroupExclusions();
395 }
396 
397 } // namespace
398