1 ///////////////////////////////////////////////////////////////////////////////
2 // BSD 3-Clause License
3 //
4 // Copyright (c) 2019, Nefelus Inc
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 // * Redistributions of source code must retain the above copyright notice, this
11 //   list of conditions and the following disclaimer.
12 //
13 // * Redistributions in binary form must reproduce the above copyright notice,
14 //   this list of conditions and the following disclaimer in the documentation
15 //   and/or other materials provided with the distribution.
16 //
17 // * Neither the name of the copyright holder nor the names of its
18 //   contributors may be used to endorse or promote products derived from
19 //   this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 // POSSIBILITY OF SUCH DAMAGE.
32 
33 #include "ZException.h"
34 #include "db.h"
35 #include "dbShape.h"
36 
37 namespace odb {
38 
isFiltered(unsigned filter,unsigned mask)39 inline bool isFiltered(unsigned filter, unsigned mask)
40 {
41   return (filter & mask) == mask;
42 }
43 
dbHierInstShapeItr(dbShapeItrCallback * callback)44 dbHierInstShapeItr::dbHierInstShapeItr(dbShapeItrCallback* callback)
45 {
46   _callback = callback;
47   assert(callback);
48 }
49 
iterate(dbInst * inst,unsigned filter)50 void dbHierInstShapeItr::iterate(dbInst* inst, unsigned filter)
51 {
52   _transforms.clear();
53   _transforms.push_back(dbTransform());
54   iterate_inst(inst, filter, 0);
55 }
56 
push_transform(dbTransform t)57 void dbHierInstShapeItr::push_transform(dbTransform t)
58 {
59   dbTransform top = _transforms.back();
60   top.concat(t);
61   _transforms.push_back(top);
62 }
63 
iterate_leaf(dbInst * inst,unsigned filter,int level)64 bool dbHierInstShapeItr::iterate_leaf(dbInst* inst, unsigned filter, int level)
65 {
66   if (isFiltered(filter, INST_OBS | INST_VIA | INST_PIN))
67     return true;
68 
69   _callback->beginInst(inst, level);
70 
71   int x, y;
72   inst->getOrigin(x, y);
73   push_transform(dbTransform(inst->getOrient(), Point(x, y)));
74   dbMaster* master = inst->getMaster();
75 
76   if (!isFiltered(filter, INST_OBS | INST_VIA)) {
77     _callback->beginObstructions(master);
78     dbSet<dbBox> boxes = master->getObstructions();
79     dbSet<dbBox>::iterator itr;
80     bool filter_via = isFiltered(filter, INST_VIA);
81     bool filter_obs = isFiltered(filter, INST_OBS);
82 
83     dbShape s;
84 
85     for (itr = boxes.begin(); itr != boxes.end(); ++itr) {
86       dbBox* box = *itr;
87 
88       if (box->isVia()) {
89         if (!filter_via) {
90           getShape(box, s);
91 
92           if (!_callback->nextBoxShape(box, s)) {
93             _transforms.pop_back();
94             _callback->endObstructions();
95             _callback->endInst();
96             return false;
97           }
98         }
99 
100       } else {
101         if (!filter_obs) {
102           getShape(box, s);
103 
104           if (!_callback->nextBoxShape(box, s)) {
105             _transforms.pop_back();
106             _callback->endObstructions();
107             _callback->endInst();
108             return false;
109           }
110         }
111       }
112     }
113 
114     _callback->endObstructions();
115   }
116 
117   if (!isFiltered(filter, INST_PIN)) {
118     dbSet<dbMTerm> mterms = master->getMTerms();
119     dbSet<dbMTerm>::iterator mitr;
120     dbShape s;
121 
122     for (mitr = mterms.begin(); mitr != mterms.end(); ++mitr) {
123       dbMTerm* mterm = *mitr;
124       _callback->beginMTerm(mterm);
125 
126       dbSet<dbMPin> mpins = mterm->getMPins();
127       dbSet<dbMPin>::iterator pitr;
128 
129       for (pitr = mpins.begin(); pitr != mpins.end(); ++pitr) {
130         dbMPin* pin = *pitr;
131         _callback->beginMPin(pin);
132 
133         dbSet<dbBox> geoms = pin->getGeometry();
134         dbSet<dbBox>::iterator gitr;
135 
136         for (gitr = geoms.begin(); gitr != geoms.end(); ++gitr) {
137           dbBox* box = *gitr;
138           getShape(box, s);
139 
140           if (!_callback->nextBoxShape(box, s)) {
141             _transforms.pop_back();
142             _callback->endMPin();
143             _callback->endMTerm();
144             _callback->endInst();
145             return false;
146           }
147         }
148 
149         _callback->endMPin();
150       }
151 
152       _callback->endMTerm();
153     }
154   }
155 
156   _transforms.pop_back();
157   _callback->endInst();
158   return true;
159 }
160 
iterate_inst(dbInst * inst,unsigned filter,int level)161 bool dbHierInstShapeItr::iterate_inst(dbInst* inst, unsigned filter, int level)
162 {
163   if (!inst->isHierarchical())
164     return iterate_leaf(inst, filter, level);
165 
166   _callback->beginInst(inst, level);
167 
168   int x, y;
169   inst->getOrigin(x, y);
170   push_transform(dbTransform(inst->getOrient(), Point(x, y)));
171   dbBlock* child = inst->getChild();
172   dbShape shape;
173 
174   if (!isFiltered(filter, BLOCK_PIN)) {
175     dbSet<dbBTerm> bterms = child->getBTerms();
176     dbSet<dbBTerm>::iterator bitr;
177 
178     for (bitr = bterms.begin(); bitr != bterms.end(); ++bitr) {
179       dbBTerm* bterm = *bitr;
180       dbSet<dbBPin> bpins = bterm->getBPins();
181       dbSet<dbBPin>::iterator pitr;
182 
183       for (pitr = bpins.begin(); pitr != bpins.end(); ++pitr) {
184         dbBPin* pin = *pitr;
185         _callback->beginBPin(pin);
186 
187         for (dbBox* box : pin->getBoxes()) {
188           getShape(box, shape);
189           if (!_callback->nextBoxShape(box, shape)) {
190             _transforms.pop_back();
191             _callback->endBPin();
192             _callback->endInst();
193             return false;
194           }
195         }
196 
197         _callback->endBPin();
198       }
199     }
200   }
201 
202   if (!isFiltered(filter, BLOCK_OBS)) {
203     dbSet<dbObstruction> obstructions = child->getObstructions();
204     dbSet<dbObstruction>::iterator oitr;
205 
206     for (oitr = obstructions.begin(); oitr != obstructions.end(); ++oitr) {
207       dbObstruction* obs = *oitr;
208       dbBox* box = obs->getBBox();
209       getShape(box, shape);
210       _callback->beginObstruction(obs);
211 
212       if (!_callback->nextBoxShape(box, shape)) {
213         _transforms.pop_back();
214         _callback->endObstruction();
215         _callback->endInst();
216         return false;
217       }
218 
219       _callback->endObstruction();
220     }
221   }
222 
223   dbSet<dbInst> insts = child->getInsts();
224   dbSet<dbInst>::iterator iitr;
225 
226   for (iitr = insts.begin(); iitr != insts.end(); ++iitr) {
227     dbInst* inst = *iitr;
228 
229     if (!iterate_inst(inst, filter, ++level)) {
230       _transforms.pop_back();
231       return false;
232     }
233   }
234 
235   dbSet<dbNet> nets = child->getNets();
236   dbSet<dbNet>::iterator nitr;
237 
238   for (nitr = nets.begin(); nitr != nets.end(); ++nitr) {
239     dbNet* net = *nitr;
240 
241     _callback->beginNet(net);
242 
243     bool draw_segments;
244     bool draw_vias;
245 
246     if (!drawNet(filter, net, draw_vias, draw_segments))
247       continue;
248 
249     if (!isFiltered(filter, NET_SWIRE)) {
250       if (!iterate_swires(filter, net, draw_vias, draw_segments)) {
251         _transforms.pop_back();
252         _callback->endNet();
253         _callback->endInst();
254         return false;
255       }
256     }
257 
258     if (!isFiltered(filter, NET_WIRE)) {
259       if (!iterate_wire(filter, net, draw_vias, draw_segments)) {
260         _transforms.pop_back();
261         _callback->endNet();
262         _callback->endInst();
263         return false;
264       }
265     }
266 
267     _callback->endNet();
268   }
269 
270   _transforms.pop_back();
271   _callback->endInst();
272   return true;
273 }
274 
drawNet(unsigned filter,dbNet * net,bool & draw_via,bool & draw_segment)275 bool dbHierInstShapeItr::drawNet(unsigned filter,
276                                  dbNet* net,
277                                  bool& draw_via,
278                                  bool& draw_segment)
279 {
280   dbSigType type = net->getSigType();
281   draw_via = false;
282   draw_segment = false;
283 
284   switch (type) {
285     case dbSigType::SCAN:
286     case dbSigType::ANALOG:
287     case dbSigType::TIEOFF:
288     case dbSigType::SIGNAL: {
289       if (isFiltered(filter, SIGNAL_WIRE | SIGNAL_VIA))
290         return false;
291 
292       if (!isFiltered(filter, SIGNAL_WIRE))
293         draw_segment = true;
294 
295       if (!isFiltered(filter, SIGNAL_VIA))
296         draw_via = true;
297 
298       return true;
299     }
300 
301     case dbSigType::POWER:
302     case dbSigType::GROUND: {
303       if (isFiltered(filter, POWER_WIRE | POWER_VIA))
304         return false;
305 
306       if (!isFiltered(filter, POWER_WIRE))
307         draw_segment = true;
308 
309       if (!isFiltered(filter, POWER_VIA))
310         draw_via = true;
311 
312       return true;
313     }
314 
315     case dbSigType::CLOCK: {
316       if (isFiltered(filter, CLOCK_WIRE | CLOCK_VIA))
317         return false;
318 
319       if (!isFiltered(filter, CLOCK_WIRE))
320         draw_segment = true;
321 
322       if (!isFiltered(filter, CLOCK_VIA))
323         draw_via = true;
324 
325       return true;
326     }
327 
328     case dbSigType::RESET: {
329       if (isFiltered(filter, RESET_WIRE | RESET_VIA))
330         return false;
331 
332       if (!isFiltered(filter, RESET_WIRE))
333         draw_segment = true;
334 
335       if (!isFiltered(filter, RESET_VIA))
336         draw_via = true;
337 
338       return true;
339     }
340   }
341 
342   draw_via = true;
343   draw_segment = true;
344   return true;
345 }
346 
iterate_swires(unsigned filter,dbNet * net,bool draw_vias,bool draw_segments)347 bool dbHierInstShapeItr::iterate_swires(unsigned filter,
348                                         dbNet* net,
349                                         bool draw_vias,
350                                         bool draw_segments)
351 {
352   dbSet<dbSWire> swires = net->getSWires();
353   dbSet<dbSWire>::iterator itr;
354 
355   for (itr = swires.begin(); itr != swires.end(); ++itr) {
356     dbSWire* swire = *itr;
357 
358     if (!iterate_swire(filter, swire, draw_vias, draw_segments))
359       return false;
360   }
361 
362   return true;
363 }
364 
iterate_swire(unsigned filter,dbSWire * swire,bool draw_vias,bool draw_segments)365 bool dbHierInstShapeItr::iterate_swire(unsigned filter,
366                                        dbSWire* swire,
367                                        bool draw_vias,
368                                        bool draw_segments)
369 {
370   _callback->beginSWire(swire);
371 
372   if (isFiltered(filter, NET_SBOX)) {
373     _callback->endSWire();
374     return true;
375   }
376 
377   dbSet<dbSBox> boxes = swire->getWires();
378   dbSet<dbSBox>::iterator itr;
379   dbShape shape;
380 
381   for (itr = boxes.begin(); itr != boxes.end(); ++itr) {
382     dbBox* box = *itr;
383 
384     if (box->isVia()) {
385       if (draw_vias == true) {
386         getShape(box, shape);
387 
388         if (!_callback->nextBoxShape(box, shape)) {
389           _callback->endSWire();
390           return false;
391         }
392       }
393     } else {
394       if (draw_segments == true) {
395         getShape(box, shape);
396 
397         if (!_callback->nextBoxShape(box, shape)) {
398           _callback->endSWire();
399           return false;
400         }
401       }
402     }
403   }
404 
405   _callback->endSWire();
406   return true;
407 }
408 
iterate_wire(unsigned filter,dbNet * net,bool draw_vias,bool draw_segments)409 bool dbHierInstShapeItr::iterate_wire(unsigned filter,
410                                       dbNet* net,
411                                       bool draw_vias,
412                                       bool draw_segments)
413 {
414   dbWire* wire = net->getWire();
415 
416   if (wire == NULL)
417     return true;
418 
419   _callback->beginWire(wire);
420 
421   if (isFiltered(filter, NET_WIRE_SHAPE)) {
422     _callback->endWire();
423     return true;
424   }
425 
426   dbShape shape;
427   dbWireShapeItr itr;
428 
429   for (itr.begin(wire); itr.next(shape);) {
430     if (shape.isVia()) {
431       if (draw_vias == true) {
432         transform(shape);
433 
434         if (!_callback->nextWireShape(wire, itr.getShapeId(), shape)) {
435           _callback->endWire();
436           return false;
437         }
438       }
439     } else {
440       if (draw_segments == true) {
441         transform(shape);
442 
443         if (!_callback->nextWireShape(wire, itr.getShapeId(), shape)) {
444           _callback->endWire();
445           return false;
446         }
447       }
448     }
449   }
450 
451   _callback->endWire();
452   return true;
453 }
454 
transform(dbShape & shape)455 void dbHierInstShapeItr::transform(dbShape& shape)
456 {
457   dbTransform& t = _transforms.back();
458   t.apply(shape._rect);
459 }
460 
getShape(dbBox * box,dbShape & shape)461 void dbHierInstShapeItr::getShape(dbBox* box, dbShape& shape)
462 {
463   Rect r;
464   box->getBox(r);
465   dbTransform& t = _transforms.back();
466   t.apply(r);
467 
468   if (!box->isVia()) {
469     shape.setSegment(box->getTechLayer(), r);
470   } else {
471     dbTechVia* tech_via = box->getTechVia();
472 
473     if (tech_via)
474       shape.setVia(tech_via, r);
475     else {
476       dbVia* via = box->getBlockVia();
477       assert(via);
478       shape.setVia(via, r);
479     }
480   }
481 }
482 
483 }  // namespace odb
484