1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: drcquick.c
6 * Design-rule check tool: hierarchical checker
7 * WRitten by: Steven M. Rubin, Static Free Software
8 *
9 * Copyright (c) 2002 Static Free Software.
10 *
11 * Electric(tm) is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * Electric(tm) is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Electric(tm); see the file COPYING. If not, write to
23 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24 * Boston, Mass 02111-1307, USA.
25 *
26 * Static Free Software
27 * 4119 Alpine Road
28 * Portola Valley, California 94028
29 * info@staticfreesoft.com
30 */
31
32 #include "config.h"
33 #if DRCTOOL
34
35 #include "global.h"
36 #include "egraphics.h"
37 #include "tech.h"
38 #include "tecgen.h"
39 #include "drc.h"
40 #include "efunction.h"
41 #include "usr.h"
42 #include <math.h>
43
44 /*
45 * This is the "quick" DRC which does full hierarchical examination of the circuit.
46 *
47 * The "quick" DRC works as follows:
48 * It first examines every primitive node and arc in the cell
49 * For each layer on these objects, it examines everything surrounding it, even in subcells
50 * R-trees are used to limit search.
51 * Where cell instances are found, the contents are examined recursively
52 * It next examines every cell instance in the cell
53 * All other instances within the surrounding area are considered
54 * When another instance is found, the two instances are examined for interaction
55 * A cache is kept of instance pairs in specified configurations to speed-up arrays
56 * All objects in the other instance that are inside the bounds of the first are considered
57 * The other instance is hierarchically examined to locate primitives in the area of consideration
58 * For each layer on each primitive object found in the other instance,
59 * Examine the contents of the first instance for interactions about that layer
60 *
61 * Since Electric understands connectivity, it uses this information to determine whether two layers
62 * are connected or not. However, if such global connectivity is propagated in the standard Electric
63 * way (placing numbers on exports, descending into the cell, and pulling the numbers onto local networks)
64 * then it is not possible to decompose the DRC for multiple processors, since two different processors
65 * may want to write global network information on the same local networks at once.
66 *
67 * To solve this problem, the "quick" DRC determines how many instances of each cell exist. For every
68 * network in every cell, an array is built that is as large as the number of instances of that cell.
69 * This array contains the global network number for that each instance of the cell. The algorithm for
70 * building these arrays is quick (1 second for a million-transistor chip) and the memory requirement
71 * is not excessive (8 megabytes for a million-transistor chip). It uses the CHECKINST and CHECKPROTO
72 * objects.
73 */
74
75 /* #define ALLERRORS 1 */ /* uncomment to generate all errors instead of first on object */
76 #define VALIDATENETWORKS 1 /* comment out when we believe this works */
77
78 #define MAXCHECKOBJECTS 50 /* number to hand-out to each processor */
79 #define NONET -1
80
81 /* the different types of errors */
82 #define SPACINGERROR 1
83 #define MINWIDTHERROR 2
84 #define NOTCHERROR 3
85 #define MINSIZEERROR 4
86 #define BADLAYERERROR 5
87 #define LAYERSURROUNDERROR 6
88
89 /*
90 * The CHECKINST object sits on every cell instance in the library.
91 * It helps determine network information on a global scale.
92 * It takes a "global-index" parameter, inherited from above (intially zero).
93 * It then computes its own index number as follows:
94 * thisindex = global-index * multiplier + localindex + offset
95 * This individual index is used to lookup an entry on each network in the cell
96 * (an array is stored on each network, giving its global net number).
97 */
98 #define NOCHECKINST ((CHECKINST *)-1)
99
100 typedef struct
101 {
102 INTBIG localindex;
103 INTBIG multiplier;
104 INTBIG offset;
105 } CHECKINST;
106
107
108 /*
109 * The CHECKPROTO object is placed on every cell and is used only temporarily
110 * to number the instances.
111 */
112 #define NOCHECKPROTO ((CHECKPROTO *)-1)
113
114 typedef struct Icheckproto
115 {
116 INTBIG timestamp; /* time stamp for counting within a particular parent */
117 INTBIG instancecount; /* number of instances of this cell in a particular parent */
118 INTBIG hierinstancecount; /* total number of instances of this cell, hierarchically */
119 INTBIG totalpercell; /* number of instances of this cell in a particular parent */
120 BOOLEAN cellchecked; /* true if this cell has been checked */
121 BOOLEAN cellparameterized; /* true if this cell has parameters */
122 NODEINST *firstincell; /* head of list of instances in a particular parent */
123 struct Icheckproto *nextcheckproto; /* next in list of these modules found */
124 } CHECKPROTO;
125
126 /*
127 * The CHECKSTATE object exists for each processor and has global information for that thread.
128 */
129 typedef struct
130 {
131 POLYLIST *cellinstpolylist;
132 POLYLIST *nodeinstpolylist;
133 POLYLIST *arcinstpolylist;
134 POLYLIST *subpolylist;
135 POLYLIST *cropnodepolylist;
136 POLYLIST *croparcpolylist;
137 POLYLIST *layerlookpolylist;
138 POLYLIST *activecroppolylist;
139 POLYGON *checkdistpoly1rebuild;
140 POLYGON *checkdistpoly2rebuild;
141 INTBIG globalindex;
142 NODEINST *tinynodeinst;
143 GEOM *tinyobj;
144 void *hierarchybasesnapshot; /* traversal path at start of instance interaction check */
145 void *hierarchytempsnapshot; /* traversal path when at bottom of one interaction check */
146 } CHECKSTATE;
147
148
149 /*
150 * The INSTINTER object records interactions between two cell instances and prevents checking
151 * them multiple times.
152 */
153 #define NOINSTINTER ((INSTINTER *)-1)
154
155 typedef struct
156 {
157 NODEPROTO *cell1, *cell2; /* the two cell instances being compared */
158 INTBIG rot1, trn1; /* orientation of cell instance 1 */
159 INTBIG rot2, trn2; /* orientation of cell instance 2 */
160 INTBIG dx, dy; /* distance from instance 1 to instance 2 */
161 } INSTINTER;
162
163 static INSTINTER **dr_quickinstinter; /* an array of interactions that have been checked */
164 static INTBIG dr_quickinstintertotal = 0; /* size of interaction array */
165 static INTBIG dr_quickinstintercount = 0; /* number of entries in interaction array */
166 static INSTINTER *dr_quickinstinterfree = NOINSTINTER; /* an array of interactions that have been checked */
167
168 typedef struct
169 {
170 NODEPROTO *cell;
171 POLYGON *poly;
172 INTBIG lx, hx, ly, hy;
173 } DRCEXCLUSION;
174
175 static INTBIG dr_quickexclusioncount; /* number of areas being excluded */
176 static INTBIG dr_quickexclusiontotal = 0; /* number of polygons allocated in exclusion list */
177 static DRCEXCLUSION *dr_quickexclusionlist; /* list of excluded polygons */
178 static BOOLEAN dr_quickexclusionwarned; /* true if user warned about overflow */
179
180 static BOOLEAN dr_quickparalleldrc; /* true if doing DRC on multiple processes */
181 static INTBIG dr_quicknumprocesses; /* number of processes for doing DRC */
182 static INTBIG dr_quickmainthread; /* the main thread */
183 static CHECKSTATE **dr_quickstate; /* one for each process */
184 static void *dr_quickmutexnode = 0; /* for locking node distribution */
185 static void *dr_quickmutexio = 0; /* for locking I/O */
186 static void *dr_quickmutexinteract = 0; /* for locking interaction checks */
187 static void **dr_quickprocessdone; /* lock to tell when process is done */
188 static INTBIG dr_quickstatecount = 0; /* number of per-process state blocks */
189
190 static NODEINST *dr_quickparallelcellinst; /* next cell instance to be checked */
191 static NODEINST *dr_quickparallelnodeinst; /* next primitive node to be checked */
192 static ARCINST *dr_quickparallelarcinst; /* next arc to be checked */
193
194 static INTBIG dr_quickchecktimestamp;
195 static INTBIG dr_quickchecknetnumber;
196 static INTBIG dr_quickcheckunconnetnumber;
197 static CHECKPROTO *dr_quickcheckprotofree = NOCHECKPROTO;
198 static CHECKINST *dr_quickcheckinstfree = NOCHECKINST;
199 static INTBIG dr_quickoptions; /* DRC options for this run */
200 static INTBIG dr_quickinteractiondistance; /* maximum area to examine (based on worst design rule) */
201 static INTBIG dr_quickerrorsfound; /* number of errors found */
202 static INTBIG dr_quickarealx; /* low X of area being checked (if checking in area) */
203 static INTBIG dr_quickareahx; /* high X of area being checked (if checking in area) */
204 static INTBIG dr_quickarealy; /* low Y of area being checked (if checking in area) */
205 static INTBIG dr_quickareahy; /* high Y of area being checked (if checking in area) */
206 static BOOLEAN dr_quickjustarea; /* true if checking in an area only */
207
208 /* for figuring out which layers are valid for DRC */
209 TECHNOLOGY *dr_curtech = NOTECHNOLOGY; /* currently technology with cached layer info */
210 static INTBIG dr_layertotal = 0; /* number of layers in cached technology */
211 BOOLEAN *dr_layersvalid; /* list of valid layers in cached technology */
212
213 /* for tracking which layers interact with which nodes */
214 static TECHNOLOGY *dr_quicklayerintertech = NOTECHNOLOGY;
215 static INTBIG dr_quicklayerinternodehashsize = 0;
216 static NODEPROTO **dr_quicklayerinternodehash;
217 static BOOLEAN **dr_quicklayerinternodetable;
218 static INTBIG dr_quicklayerinterarchashsize = 0;
219 static ARCPROTO **dr_quicklayerinterarchash;
220 static BOOLEAN **dr_quicklayerinterarctable;
221
222 static void dr_quickaccumulateexclusion(INTBIG depth, NODEPROTO **cell, XARRAY *trans);
223 static BOOLEAN dr_quickactiveontransistor(POLYGON *poly1, INTBIG layer1, INTBIG net1,
224 POLYGON *poly2, INTBIG layer2, INTBIG net2, TECHNOLOGY *tech, NODEPROTO *cell, INTBIG globalindex);
225 static BOOLEAN dr_quickactiveontransistorrecurse(INTBIG blx, INTBIG bhx, INTBIG bly, INTBIG bhy,
226 INTBIG net1, INTBIG net2, NODEPROTO *cell, INTBIG globalindex, XARRAY trans);
227 static CHECKINST *dr_quickalloccheckinst(void);
228 static CHECKPROTO *dr_quickalloccheckproto(void);
229 static INSTINTER *dr_quickallocinstinter(void);
230 static BOOLEAN dr_quickbadbox(POLYGON *poly, INTBIG layer, INTBIG net, TECHNOLOGY *tech, GEOM *geom,
231 XARRAY trans, NODEPROTO *cell, INTBIG globalindex, CHECKSTATE *state);
232 static BOOLEAN dr_quickbadboxinarea(POLYGON *poly, INTBIG layer, TECHNOLOGY *tech, INTBIG net, GEOM *geom, XARRAY trans,
233 INTBIG globalindex,
234 INTBIG lxbound, INTBIG hxbound, INTBIG lybound, INTBIG hybound, NODEPROTO *cell, INTBIG cellglobalindex,
235 NODEPROTO *topcell, INTBIG topglobalindex, XARRAY toptrans, INTBIG minsize, BOOLEAN basemulti,
236 CHECKSTATE *state, BOOLEAN sameinstance);
237 static BOOLEAN dr_quickbadsubbox(POLYGON *poly, INTBIG layer, INTBIG net, TECHNOLOGY *tech, GEOM *geom, XARRAY trans,
238 INTBIG globalindex, NODEPROTO *cell, NODEINST *oni, INTBIG topglobalindex, CHECKSTATE *state);
239 static void dr_quickbuildlayerinteractions(TECHNOLOGY *tech);
240 static BOOLEAN dr_quickcheckarcinst(ARCINST *ai, INTBIG globalindex, CHECKSTATE *state);
241 static BOOLEAN dr_quickcheckdist(TECHNOLOGY *tech, NODEPROTO *cell, INTBIG globalindex,
242 POLYGON *poly1, INTBIG layer1, INTBIG net1, GEOM *geom1, XARRAY trans1, INTBIG globalindex1,
243 POLYGON *poly2, INTBIG layer2, INTBIG net2, GEOM *geom2, XARRAY trans2, INTBIG globalindex2,
244 BOOLEAN con, INTBIG dist, INTBIG edge, CHAR *rule, CHECKSTATE *state);
245 static void dr_quickcheckenumerateinstances(NODEPROTO *cell);
246 static void dr_quickcheckenumeratenetworks(NODEPROTO *cell, INTBIG globalindex);
247 static BOOLEAN dr_quickcheckcellinst(NODEINST *ni, INTBIG globalindex, CHECKSTATE *state);
248 static BOOLEAN dr_quickcheckcellinstcontents(INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy, NODEPROTO *np,
249 XARRAY uptrans, INTBIG globalindex, NODEINST *oni, INTBIG topglobalindex, CHECKSTATE *state);
250 static BOOLEAN dr_quickcheckgeomagainstinstance(GEOM *geom, NODEINST *ni, CHECKSTATE *state);
251 static BOOLEAN dr_quickcheckinteraction(NODEINST *ni1, NODEINST *ni2, INSTINTER **dii);
252 static BOOLEAN dr_quickchecklayerwitharc(INTBIG layer, ARCPROTO *ap);
253 static BOOLEAN dr_quickchecklayerwithnode(INTBIG layer, NODEPROTO *np);
254 static BOOLEAN dr_quickcheckminwidth(GEOM *geom, INTBIG layer, POLYGON *poly, TECHNOLOGY *tech, CHECKSTATE *state);
255 static BOOLEAN dr_quickchecknodeinst(NODEINST *ni, INTBIG globalindex, CHECKSTATE *state);
256 static void dr_quickchecktheseinstances(NODEPROTO *cell, INTBIG count,
257 NODEINST **nodestocheck, BOOLEAN *validity);
258 static INTBIG dr_quickcheckthiscell(NODEPROTO *cell, INTBIG globalindex, INTBIG lx, INTBIG hx,
259 INTBIG ly, INTBIG hy, BOOLEAN justarea);
260 static void dr_quickclearinstancecache(void);
261 static void dr_quickcropactivearc(ARCINST *ai, POLYLIST *plist, CHECKSTATE *state);
262 static BOOLEAN dr_quickcroparcinst(ARCINST *ai, INTBIG lay, XARRAY transin,
263 INTBIG *lx, INTBIG *hx, INTBIG *ly, INTBIG *hy, CHECKSTATE *state);
264 static INTBIG dr_quickcropbox(INTBIG *lx, INTBIG *hx, INTBIG *ly, INTBIG *hy, INTBIG bx, INTBIG ux, INTBIG by,
265 INTBIG uy, INTBIG nlx, INTBIG nhx, INTBIG nly, INTBIG nhy);
266 static BOOLEAN dr_quickcropnodeinst(NODEINST *ni, INTBIG globalindex, CHECKSTATE *state,
267 XARRAY trans, INTBIG nlx, INTBIG nhx, INTBIG nly, INTBIG nhy,
268 INTBIG nlayer, INTBIG nnet, GEOM *ngeom, INTBIG *lx, INTBIG *hx, INTBIG *ly, INTBIG *hy);
269 static void *dr_quickdothread(void *argument);
270 static INSTINTER *dr_quickfindinteraction(INSTINTER *dii);
271 static INTBIG dr_quickfindinterveningpoints(POLYGON*, POLYGON*, INTBIG*, INTBIG*, INTBIG*, INTBIG*);
272 static BOOLEAN dr_quickfindparameters(NODEPROTO *cell);
273 static void dr_quickfreecheckinst(CHECKINST *ci);
274 static void dr_quickfreecheckproto(CHECKPROTO *cp);
275 static void dr_quickfreeinstinter(INSTINTER *dii);
276 static void dr_quickgetarcpolys(ARCINST *ai, POLYLIST *plist, XARRAY trans);
277 static INTBIG dr_quickgetnetnumber(PORTPROTO *pp, NODEINST *ni, INTBIG globalindex);
278 static INTBIG dr_quickgetnextparallelgeoms(GEOM **list, CHECKSTATE *state);
279 static void dr_quickgetnodeEpolys(NODEINST *ni, POLYLIST *plist, XARRAY trans);
280 static void dr_quickgetnodepolys(NODEINST *ni, POLYLIST *plist, XARRAY trans);
281 static INTBIG dr_quickhalfcropbox(INTBIG *lx, INTBIG *hx, INTBIG *ly, INTBIG *hy,
282 INTBIG bx, INTBIG ux, INTBIG by, INTBIG uy);
283 static BOOLEAN dr_quickinsertinteraction(INSTINTER *dii);
284 static BOOLEAN dr_quickismulticut(NODEINST *ni);
285 static BOOLEAN dr_quicklookforlayer(NODEPROTO *cell, INTBIG layer, XARRAY moretrans, CHECKSTATE *state,
286 INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy, INTBIG xf1, INTBIG yf1, BOOLEAN *p1found,
287 INTBIG xf2, INTBIG yf2, BOOLEAN *p2found, INTBIG xf3, INTBIG yf3, BOOLEAN *p3found);
288 static BOOLEAN dr_quicklookforpoints(INTBIG xf1, INTBIG yf1, INTBIG xf2, INTBIG yf2,
289 INTBIG layer, NODEPROTO *cell, BOOLEAN needboth, CHECKSTATE *state);
290 static BOOLEAN dr_quickmakestateblocks(INTBIG numstates);
291 static BOOLEAN dr_quickobjtouch(GEOM *geom1, GEOM *geom2);
292 static void dr_quickreporterror(INTBIG errtype, TECHNOLOGY *tech, CHAR *msg,
293 NODEPROTO *cell, INTBIG limit, INTBIG actual, CHAR *rule,
294 POLYGON *poly1, GEOM *geom1, INTBIG layer1, INTBIG net1,
295 POLYGON *poly2, GEOM *geom2, INTBIG layer2, INTBIG net2);
296
297 #define MAXHIERARCHYDEPTH 100
298
299 /*
300 * This is the entry point for DRC.
301 *
302 * Routine to do a hierarchical DRC check on cell "cell".
303 * If "count" is zero, check the entire cell.
304 * If "count" is nonzero, only check that many instances (in "nodestocheck") and set the
305 * entry in "validity" TRUE if it is DRC clean.
306 * If "justarea" is TRUE, only check in the selected area.
307 */
dr_quickcheck(NODEPROTO * cell,INTBIG count,NODEINST ** nodestocheck,BOOLEAN * validity,BOOLEAN justarea)308 void dr_quickcheck(NODEPROTO *cell, INTBIG count, NODEINST **nodestocheck, BOOLEAN *validity,
309 BOOLEAN justarea)
310 {
311 REGISTER NODEPROTO *np, *snp;
312 REGISTER NODEINST *ni;
313 REGISTER CHECKINST *ci;
314 REGISTER CHECKPROTO *cp, *ocp;
315 REGISTER LIBRARY *lib;
316 REGISTER NETWORK *net;
317 REGISTER TECHNOLOGY *tech;
318 REGISTER VARIABLE *var;
319 REGISTER INTBIG totalnetworks, i, l, *netnumbers, errorcount;
320 INTBIG lx, hx, ly, hy;
321 float t;
322 NODEPROTO *cellarray[MAXHIERARCHYDEPTH];
323 XARRAY xarrayarray[MAXHIERARCHYDEPTH];
324
325 /* start the clock */
326 starttimer();
327
328 /* get the current DRC options */
329 dr_quickoptions = dr_getoptionsvalue();
330
331 /* see if DRC will be done with multiple processes */
332 if (graphicshas(CANDOTHREADS) && (dr_quickoptions&DRCMULTIPROC) != 0)
333 {
334 dr_quicknumprocesses = (dr_quickoptions&DRCNUMPROC) >> DRCNUMPROCSH;
335 } else
336 {
337 dr_quicknumprocesses = 1;
338 }
339
340 /* if checking specific instances, adjust options and processor count */
341 if (count > 0)
342 {
343 dr_quickoptions |= DRCFIRSTERROR;
344 dr_quicknumprocesses = 1;
345 }
346
347 /* cache valid layers for this technology */
348 tech = cell->tech;
349 dr_cachevalidlayers(tech);
350 dr_quickbuildlayerinteractions(tech);
351
352 /* clean out the cache of instances */
353 dr_quickclearinstancecache();
354
355 /* determine maximum DRC interaction distance */
356 dr_quickinteractiondistance = 0;
357 for(i = 0; i < tech->layercount; i++)
358 {
359 l = maxdrcsurround(tech, cell->lib, i);
360 if (l > dr_quickinteractiondistance) dr_quickinteractiondistance = l;
361 }
362
363 /* initialize all cells for hierarchical network numbering */
364 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
365 {
366 if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
367 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
368 {
369 cp = dr_quickalloccheckproto();
370 cp->instancecount = 0;
371 cp->timestamp = 0;
372 cp->hierinstancecount = 0;
373 cp->totalpercell = 0;
374 cp->cellchecked = FALSE;
375 cp->cellparameterized = FALSE;
376 for(i=0; i<np->numvar; i++)
377 {
378 var = &np->firstvar[i];
379 if (TDGETISPARAM(var->textdescript) != 0) break;
380 }
381 if (i < np->numvar) cp->cellparameterized = TRUE;
382 np->temp1 = (INTBIG)cp;
383 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
384 {
385 if (ni->proto->primindex != 0) continue;
386
387 /* ignore documentation icons */
388 if (isiconof(ni->proto, np)) continue;
389
390 ci = dr_quickalloccheckinst();
391 if (ci == NOCHECKINST) return;
392 ni->temp1 = (INTBIG)ci;
393 }
394 }
395 }
396
397 /* see if any parameters are used below this cell */
398 if (dr_quickfindparameters(cell))
399 {
400 /* parameters found: cannot use multiple processors */
401 ttyputmsg(_("Parameterized layout being used: multiprocessor decomposition disabled"));
402 dr_quicknumprocesses = 1;
403 }
404
405 /* now recursively examine, setting information on all instances */
406 cp = (CHECKPROTO *)cell->temp1;
407 cp->hierinstancecount = 1;
408 dr_quickchecktimestamp = 0;
409 dr_quickcheckenumerateinstances(cell);
410
411 /* now allocate space for hierarchical network arrays */
412 totalnetworks = 0;
413 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
414 {
415 if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
416 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
417 {
418 cp = (CHECKPROTO *)np->temp1;
419 if (cp->hierinstancecount > 0)
420 {
421 /* allocate net number lists for every net in the cell */
422 for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
423 {
424 netnumbers = (INTBIG *)emalloc(cp->hierinstancecount * SIZEOFINTBIG,
425 dr_tool->cluster);
426 net->temp1 = (INTBIG)netnumbers;
427 for(i=0; i<cp->hierinstancecount; i++) netnumbers[i] = 0;
428 totalnetworks += cp->hierinstancecount;
429 }
430 }
431 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
432 {
433 if (ni->proto->primindex != 0) continue;
434
435 /* ignore documentation icons */
436 if (isiconof(ni->proto, np)) continue;
437
438 ci = (CHECKINST *)ni->temp1;
439 ocp = (CHECKPROTO *)ni->proto->temp1;
440 ci->offset = ocp->totalpercell;
441 }
442 dr_quickchecktimestamp++;
443 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
444 {
445 if (ni->proto->primindex != 0) continue;
446
447 /* ignore documentation icons */
448 if (isiconof(ni->proto, np)) continue;
449
450 ocp = (CHECKPROTO *)ni->proto->temp1;
451 if (ocp->timestamp != dr_quickchecktimestamp)
452 {
453 ci = (CHECKINST *)ni->temp1;
454 ocp->timestamp = dr_quickchecktimestamp;
455 ocp->totalpercell += cp->hierinstancecount * ci->multiplier;
456 }
457 }
458 }
459 }
460
461 /* now fill in the hierarchical network arrays */
462 dr_quickchecktimestamp = 0;
463 dr_quickchecknetnumber = 1;
464 for(net = cell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
465 net->temp2 = dr_quickchecknetnumber++;
466 dr_quickcheckenumeratenetworks(cell, 0);
467 dr_quickcheckunconnetnumber = dr_quickchecknetnumber;
468
469 #ifdef VALIDATENETWORKS /* assert: all network numbers must be filled-in */
470 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
471 {
472 if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
473 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
474 {
475 cp = (CHECKPROTO *)np->temp1;
476 if (cp->hierinstancecount > 0)
477 {
478 /* allocate net number lists for every net in the cell */
479 for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
480 {
481 netnumbers = (INTBIG *)net->temp1;
482 for(i=0; i<cp->hierinstancecount; i++)
483 if (netnumbers[i] == 0)
484 ttyputmsg(x_("Missing network numbers on network %s in cell %s"),
485 describenetwork(net), describenodeproto(np));
486 }
487 }
488 }
489 }
490 #endif
491
492 if (count <= 0)
493 {
494 t = endtimer();
495 ttyputmsg(_("Found %ld networks, allocated %ld bytes for network numbering (took %s)"),
496 dr_quickchecknetnumber, totalnetworks*SIZEOFINTBIG, explainduration(t));
497 }
498
499 /* now search for DRC exclusion areas */
500 dr_quickexclusioncount = 0;
501 cellarray[0] = cell;
502 dr_quickexclusionwarned = FALSE;
503 transid(xarrayarray[0]);
504 dr_quickaccumulateexclusion(1, cellarray, xarrayarray);
505
506 if (justarea)
507 {
508 snp = us_getareabounds(&lx, &hx, &ly, &hy);
509 if (snp != cell)
510 {
511 ttyputmsg(_("Cannot check selection: it is not in the current cell"));
512 justarea = FALSE;
513 }
514 } else lx = hx = ly = hy = 0;
515
516 /* initialize for multiple processors */
517 if (dr_quickmakestateblocks(dr_quicknumprocesses)) return;
518 if (ensurevalidmutex(&dr_quickmutexnode, TRUE)) return;
519 if (ensurevalidmutex(&dr_quickmutexio, TRUE)) return;
520 if (ensurevalidmutex(&dr_quickmutexinteract, TRUE)) return;
521 if (dr_quicknumprocesses <= 1) dr_quickparalleldrc = FALSE; else
522 {
523 dr_quickparalleldrc = TRUE;
524 dr_quickmainthread = dr_quicknumprocesses - 1;
525 }
526
527 /* now do the DRC */
528 initerrorlogging(_("DRC"));
529 if (count == 0)
530 {
531 /* just do standard DRC here */
532 if (!dr_quickparalleldrc) begintraversehierarchy();
533 (void)dr_quickcheckthiscell(cell, 0, lx, hx, ly, hy, justarea);
534 if (!dr_quickparalleldrc) endtraversehierarchy();
535 } else
536 {
537 /* check only these "count" instances */
538 dr_quickchecktheseinstances(cell, count, nodestocheck, validity);
539 }
540
541 /* sort the errors by layer */
542 if (count <= 0)
543 {
544 sorterrors();
545 errorcount = numerrors();
546 t = endtimer();
547 if (t > 60.0 && (us_useroptions&BEEPAFTERLONGJOB) != 0)
548 ttybeep(SOUNDBEEP, TRUE);
549 ttyputmsg(_("%ld errors found (took %s)"), errorcount, explainduration(t));
550 }
551 termerrorlogging(TRUE);
552
553 /* deallocate temporary memory used in DRC */
554 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
555 {
556 if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
557 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
558 {
559 cp = (CHECKPROTO *)np->temp1;
560 if (cp->hierinstancecount > 0)
561 {
562 /* free net number lists on every net in the cell */
563 for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
564 {
565 netnumbers = (INTBIG*)net->temp1;
566 efree((CHAR *)netnumbers);
567 }
568 }
569 dr_quickfreecheckproto(cp);
570 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
571 {
572 if (ni->proto->primindex != 0) continue;
573
574 /* ignore documentation icons */
575 if (isiconof(ni->proto, np)) continue;
576
577 ci = (CHECKINST *)ni->temp1;
578 dr_quickfreecheckinst(ci);
579 }
580 }
581 }
582 }
583
584 /*
585 * Routine to cleanup memory used by the quick-DRC.
586 */
dr_quickterm(void)587 void dr_quickterm(void)
588 {
589 REGISTER INTBIG i;
590 REGISTER INSTINTER *dii;
591 REGISTER CHECKPROTO *cp;
592 REGISTER CHECKINST *ci;
593
594 if (dr_quicklayerinternodehashsize > 0)
595 {
596 for(i=0; i<dr_quicklayerinternodehashsize; i++)
597 if (dr_quicklayerinternodetable[i] != 0)
598 efree((CHAR *)dr_quicklayerinternodetable[i]);
599 efree((CHAR *)dr_quicklayerinternodetable);
600 efree((CHAR *)dr_quicklayerinternodehash);
601 }
602 if (dr_quicklayerinterarchashsize > 0)
603 {
604 for(i=0; i<dr_quicklayerinterarchashsize; i++)
605 if (dr_quicklayerinterarctable[i] != 0)
606 efree((CHAR *)dr_quicklayerinterarctable[i]);
607 efree((CHAR *)dr_quicklayerinterarctable);
608 efree((CHAR *)dr_quicklayerinterarchash);
609 }
610 if (dr_layertotal > 0)
611 efree((CHAR *)dr_layersvalid);
612 dr_quickclearinstancecache();
613 while (dr_quickinstinterfree != NOINSTINTER)
614 {
615 dii = dr_quickinstinterfree;
616 dr_quickinstinterfree = (INSTINTER *)dii->cell1;
617 efree((CHAR *)dii);
618 }
619 if (dr_quickinstintertotal > 0)
620 efree((CHAR *)dr_quickinstinter);
621 while (dr_quickcheckprotofree != NOCHECKPROTO)
622 {
623 cp = dr_quickcheckprotofree;
624 dr_quickcheckprotofree = cp->nextcheckproto;
625 efree((CHAR *)cp);
626 }
627 while (dr_quickcheckinstfree != NOCHECKINST)
628 {
629 ci = dr_quickcheckinstfree;
630 dr_quickcheckinstfree = (CHECKINST *)ci->localindex;
631 efree((CHAR *)ci);
632 }
633
634 /* free DRC exclusion areas */
635 for(i=0; i<dr_quickexclusiontotal; i++)
636 freepolygon(dr_quickexclusionlist[i].poly);
637 if (dr_quickexclusiontotal > 0) efree((CHAR *)dr_quickexclusionlist);
638
639 /* free per-processor state blocks */
640 for(i=0; i<dr_quickstatecount; i++)
641 {
642 freepolylist(dr_quickstate[i]->cellinstpolylist);
643 freepolylist(dr_quickstate[i]->nodeinstpolylist);
644 freepolylist(dr_quickstate[i]->arcinstpolylist);
645 freepolylist(dr_quickstate[i]->subpolylist);
646 freepolylist(dr_quickstate[i]->cropnodepolylist);
647 freepolylist(dr_quickstate[i]->croparcpolylist);
648 freepolylist(dr_quickstate[i]->layerlookpolylist);
649 freepolylist(dr_quickstate[i]->activecroppolylist);
650 killhierarchicaltraversal(dr_quickstate[i]->hierarchybasesnapshot);
651 killhierarchicaltraversal(dr_quickstate[i]->hierarchytempsnapshot);
652 efree((CHAR *)dr_quickstate[i]);
653 }
654 if (dr_quickstatecount > 0)
655 {
656 efree((CHAR *)dr_quickstate);
657 efree((CHAR *)dr_quickprocessdone);
658 }
659 }
660
661 /*************************** QUICK DRC CELL EXAMINATION ***************************/
662
663 /*
664 * Routine to check the contents of cell "cell" with global network index "globalindex".
665 * Returns positive if errors are found, zero if no errors are found, negative on internal error.
666 */
dr_quickcheckthiscell(NODEPROTO * cell,INTBIG globalindex,INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy,BOOLEAN justarea)667 INTBIG dr_quickcheckthiscell(NODEPROTO *cell, INTBIG globalindex, INTBIG lx, INTBIG hx,
668 INTBIG ly, INTBIG hy, BOOLEAN justarea)
669 {
670 REGISTER CHECKPROTO *cp;
671 REGISTER CHECKINST *ci;
672 REGISTER NODEPROTO *np;
673 REGISTER BOOLEAN allsubcellsstillok;
674 REGISTER NODEINST *ni;
675 REGISTER VARIABLE *var;
676 REGISTER INTBIG localindex, retval, errcount, localerrors, i;
677 float elapsed;
678 REGISTER UINTBIG lastgooddate, lastchangedate;
679
680 /* first check all subcells */
681 allsubcellsstillok = TRUE;
682 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
683 {
684 np = ni->proto;
685 if (np->primindex != 0) continue;
686
687 /* ignore documentation icons */
688 if (isiconof(ni->proto, cell)) continue;
689
690 /* ignore if not in the area */
691 if (justarea)
692 {
693 if (ni->geom->lowx >= hx || ni->geom->highx <= lx ||
694 ni->geom->lowy >= hy || ni->geom->highy <= ly) continue;
695 }
696
697 cp = (CHECKPROTO *)np->temp1;
698 if (cp->cellchecked && !cp->cellparameterized) continue;
699
700 /* recursively check the subcell */
701 ci = (CHECKINST *)ni->temp1;
702 localindex = globalindex * ci->multiplier + ci->localindex + ci->offset;
703 if (!dr_quickparalleldrc) downhierarchy(ni, np, 0);
704 retval = dr_quickcheckthiscell(np, localindex, 0, 0, 0, 0, FALSE);
705 if (!dr_quickparalleldrc) uphierarchy();
706 if (retval < 0) return(-1);
707 if (retval > 0) allsubcellsstillok = FALSE;
708 }
709
710 /* prepare to check cell */
711 cp = (CHECKPROTO *)cell->temp1;
712 cp->cellchecked = TRUE;
713
714 /* if the cell hasn't changed since the last good check, stop now */
715 if (allsubcellsstillok)
716 {
717 var = getvalkey((INTBIG)cell, VNODEPROTO, VINTEGER, dr_lastgooddrckey);
718 if (var != NOVARIABLE)
719 {
720 lastgooddate = (UINTBIG)var->addr;
721 lastchangedate = cell->revisiondate;
722 if (lastchangedate <= lastgooddate) return(0);
723 }
724 }
725
726 /* announce progress */
727 ttyputmsg(_("Checking cell %s"), describenodeproto(cell));
728
729 /* remember how many errors there are on entry */
730 errcount = numerrors();
731
732 /* now look at every primitive node and arc here */
733 dr_quickerrorsfound = 0;
734 dr_quickparallelcellinst = cell->firstnodeinst;
735 dr_quickparallelnodeinst = cell->firstnodeinst;
736 dr_quickparallelarcinst = cell->firstarcinst;
737 dr_quickjustarea = justarea;
738 dr_quickarealx = lx; dr_quickareahx = hx;
739 dr_quickarealy = ly; dr_quickareahy = hy;
740 if (dr_quickparalleldrc && dr_quicknumprocesses > 1)
741 {
742 /* code cannot be called by multiple procesors: uses globals */
743 NOT_REENTRANT;
744
745 /* break up into multiple processes */
746 setmultiprocesslocks(TRUE);
747
748 /* startup extra threads */
749 for(i=0; i<dr_quicknumprocesses; i++)
750 {
751 /* mark this process as "still running" */
752 dr_quickstate[i]->globalindex = globalindex;
753 emutexlock(dr_quickprocessdone[i]);
754 if (i == dr_quickmainthread)
755 {
756 /* the last process is run locally, not in a new thread */
757 (void)dr_quickdothread((void *)i);
758 } else
759 {
760 /* create a thread to run this one */
761 enewthread(dr_quickdothread, (void *)i);
762 }
763 }
764
765 /* now wait for all processes to finish */
766 for(i=0; i<dr_quicknumprocesses; i++)
767 {
768 emutexlock(dr_quickprocessdone[i]);
769 emutexunlock(dr_quickprocessdone[i]);
770 }
771 setmultiprocesslocks(FALSE);
772 } else
773 {
774 dr_quickstate[0]->globalindex = globalindex;
775 (void)dr_quickdothread(0);
776 }
777
778 /* if there were no errors, remember that */
779 elapsed = endtimer();
780 localerrors = numerrors() - errcount;
781 if (localerrors == 0)
782 {
783 (void)setvalkey((INTBIG)cell, VNODEPROTO, dr_lastgooddrckey,
784 (INTBIG)getcurrenttime(), VINTEGER);
785 ttyputmsg(_(" No errors found (%s so far)"), explainduration(elapsed));
786 } else
787 {
788 ttyputmsg(_(" FOUND %ld ERRORS (%s so far)"), localerrors,
789 explainduration(elapsed));
790 }
791
792 return(dr_quickerrorsfound);
793 }
794
795 /*
796 * routine to check the design rules about nodeinst "ni". Only check those
797 * other objects whose geom pointers are greater than this one (i.e. only
798 * check any pair of objects once).
799 * Returns true if an error was found.
800 */
dr_quickchecknodeinst(NODEINST * ni,INTBIG globalindex,CHECKSTATE * state)801 BOOLEAN dr_quickchecknodeinst(NODEINST *ni, INTBIG globalindex, CHECKSTATE *state)
802 {
803 REGISTER INTBIG tot, j, actual, minsize, fun;
804 REGISTER NODEPROTO *cell;
805 REGISTER BOOLEAN ret, errorsfound;
806 XARRAY trans;
807 CHAR *rule;
808 INTBIG minx, miny, lx, hx, ly, hy;
809 REGISTER INTBIG net;
810 REGISTER POLYGON *poly;
811
812 cell = ni->parent;
813 makerot(ni, trans);
814
815 /* get all of the polygons on this node */
816 fun = nodefunction(ni);
817 dr_quickgetnodeEpolys(ni, state->nodeinstpolylist, trans);
818 tot = state->nodeinstpolylist->polylistcount;
819
820 /* examine the polygons on this node */
821 errorsfound = FALSE;
822 for(j=0; j<tot; j++)
823 {
824 poly = state->nodeinstpolylist->polygons[j];
825 if (poly->layer < 0) continue;
826
827 /* determine network for this polygon */
828 net = dr_quickgetnetnumber(poly->portproto, ni, globalindex);
829 ret = dr_quickbadbox(poly, poly->layer, net, ni->proto->tech, ni->geom, trans, cell, globalindex, state);
830 if (ret)
831 {
832 if ((dr_quickoptions&DRCFIRSTERROR) != 0) return(TRUE);
833 errorsfound = TRUE;
834 }
835 ret = dr_quickcheckminwidth(ni->geom, poly->layer, poly, ni->proto->tech, state);
836 if (ret)
837 {
838 if ((dr_quickoptions&DRCFIRSTERROR) != 0) return(TRUE);
839 errorsfound = TRUE;
840 }
841 if (poly->tech == dr_curtech && !dr_layersvalid[poly->layer])
842 {
843 dr_quickreporterror(BADLAYERERROR, dr_curtech, 0, cell, 0, 0, 0,
844 poly, ni->geom, poly->layer, NONET, NOPOLYGON, NOGEOM, 0, NONET);
845 if ((dr_quickoptions&DRCFIRSTERROR) != 0) return(TRUE);
846 errorsfound = TRUE;
847 }
848
849 #ifdef SURROUNDRULES
850 /* check surround if this layer is from a pure-layer node */
851 if (fun == NPNODE)
852 {
853 count = drcsurroundrules(poly->tech, poly->layer, &surlayers, &surdist, &surrules);
854 for(i=0; i<count; i++)
855 {
856 if (dr_quickfindsurround(poly, surlayers[i], surdist[i], cell, state)) continue;
857 dr_quickreporterror(LAYERSURROUNDERROR, dr_curtech, 0, cell, surdist[i], 0,
858 surrules[i], poly, ni->geom, poly->layer, NONET,
859 NOPOLYGON, NOGEOM, surlayers[i], NONET);
860 if ((dr_quickoptions&DRCFIRSTERROR) != 0) return(TRUE);
861 errorsfound = TRUE;
862 }
863 }
864 #endif
865 }
866
867 /* check node for minimum size */
868 drcminnodesize(ni->proto, cell->lib, &minx, &miny, &rule);
869 if (minx > 0 && miny > 0)
870 {
871 if (ni->highx-ni->lowx < minx || ni->highy-ni->lowy < miny)
872 {
873 nodesizeoffset(ni, &lx, &ly, &hx, &hy);
874 if (minx - (ni->highx-ni->lowx) > miny - (ni->highy-ni->lowy))
875 {
876 minsize = minx - lx - hx;
877 actual = ni->highx - ni->lowx - lx - hx;
878 } else
879 {
880 minsize = miny - ly - hy;
881 actual = ni->highy - ni->lowy - ly - hy;
882 }
883 dr_quickreporterror(MINSIZEERROR, ni->proto->tech, 0, cell, minsize, actual, rule,
884 NOPOLYGON, ni->geom, 0, NONET, NOPOLYGON, NOGEOM, 0, NONET);
885 }
886 }
887 return(errorsfound);
888 }
889
890 /*
891 * routine to check the design rules about arcinst "ai".
892 * Returns true if errors were found.
893 */
dr_quickcheckarcinst(ARCINST * ai,INTBIG globalindex,CHECKSTATE * state)894 BOOLEAN dr_quickcheckarcinst(ARCINST *ai, INTBIG globalindex, CHECKSTATE *state)
895 {
896 REGISTER INTBIG tot, j;
897 REGISTER BOOLEAN ret, errorsfound;
898 REGISTER INTBIG net;
899 REGISTER POLYGON *poly;
900
901 /* ignore arcs with no topology */
902 if (ai->network == NONETWORK) return(FALSE);
903
904 /* get all of the polygons on this arc */
905 dr_quickgetarcpolys(ai, state->arcinstpolylist, el_matid);
906 dr_quickcropactivearc(ai, state->arcinstpolylist, state);
907 tot = state->arcinstpolylist->polylistcount;
908
909 /* examine the polygons on this arc */
910 errorsfound = FALSE;
911 for(j=0; j<tot; j++)
912 {
913 poly = state->arcinstpolylist->polygons[j];
914 if (poly->layer < 0) continue;
915 net = ((INTBIG *)ai->network->temp1)[globalindex];
916 ret = dr_quickbadbox(poly, poly->layer, net, ai->proto->tech, ai->geom, el_matid, ai->parent, globalindex, state);
917 if (ret)
918 {
919 if ((dr_quickoptions&DRCFIRSTERROR) != 0) return(TRUE);
920 errorsfound = TRUE;
921 }
922 ret = dr_quickcheckminwidth(ai->geom, poly->layer, poly, ai->proto->tech, state);
923 if (ret)
924 {
925 if ((dr_quickoptions&DRCFIRSTERROR) != 0) return(TRUE);
926 errorsfound = TRUE;
927 }
928 if (poly->tech == dr_curtech && !dr_layersvalid[poly->layer])
929 {
930 dr_quickreporterror(BADLAYERERROR, dr_curtech, 0, ai->parent, 0, 0, 0,
931 poly, ai->geom, poly->layer, NONET, NOPOLYGON, NOGEOM, 0, NONET);
932 if ((dr_quickoptions&DRCFIRSTERROR) != 0) return(TRUE);
933 errorsfound = TRUE;
934 }
935 }
936 return(errorsfound);
937 }
938
939 /*
940 * routine to check the design rules about cell instance "ni". Only check other
941 * instances, and only check the parts of each that are within striking range.
942 * Returns true if an error was found.
943 */
dr_quickcheckcellinst(NODEINST * ni,INTBIG globalindex,CHECKSTATE * state)944 BOOLEAN dr_quickcheckcellinst(NODEINST *ni, INTBIG globalindex, CHECKSTATE *state)
945 {
946 REGISTER INTBIG lx, hx, ly, hy, search, localindex;
947 INTBIG sublx, subhx, subly, subhy;
948 REGISTER GEOM *geom;
949 REGISTER NODEINST *oni;
950 XARRAY rtrans, ttrans, downtrans, uptrans;
951 REGISTER CHECKINST *ci;
952 INSTINTER *dii;
953
954 /* get current position in traversal hierarchy */
955 gethierarchicaltraversal(state->hierarchybasesnapshot);
956
957 /* look for other instances surrounding this one */
958 lx = ni->geom->lowx - dr_quickinteractiondistance;
959 hx = ni->geom->highx + dr_quickinteractiondistance;
960 ly = ni->geom->lowy - dr_quickinteractiondistance;
961 hy = ni->geom->highy + dr_quickinteractiondistance;
962 search = initsearch(lx, hx, ly, hy, ni->parent);
963 for(;;)
964 {
965 geom = nextobject(search);
966 if (geom == NOGEOM) break;
967 if (!geom->entryisnode) continue;
968 oni = geom->entryaddr.ni;
969
970 /* only check other nodes that are numerically higher (so each pair is only checked once) */
971 if ((INTBIG)oni <= (INTBIG)ni) continue;
972 if (oni->proto->primindex != 0) continue;
973
974 /* see if this configuration of instances has already been done */
975 if (dr_quickcheckinteraction(ni, oni, &dii)) continue;
976
977 /* found other instance "oni", look for everything in "ni" that is near it */
978 sublx = oni->geom->lowx - dr_quickinteractiondistance;
979 subhx = oni->geom->highx + dr_quickinteractiondistance;
980 subly = oni->geom->lowy - dr_quickinteractiondistance;
981 subhy = oni->geom->highy + dr_quickinteractiondistance;
982 makerotI(ni, rtrans);
983 maketransI(ni, ttrans);
984 transmult(rtrans, ttrans, downtrans);
985 xformbox(&sublx, &subhx, &subly, &subhy, downtrans);
986
987 maketrans(ni, ttrans);
988 makerot(ni, rtrans);
989 transmult(ttrans, rtrans, uptrans);
990
991 ci = (CHECKINST *)ni->temp1;
992 localindex = globalindex * ci->multiplier + ci->localindex + ci->offset;
993
994 /* recursively search instance "ni" in the vicinity of "oni" */
995 if (!dr_quickparalleldrc) downhierarchy(ni, ni->proto, 0);
996 (void)dr_quickcheckcellinstcontents(sublx, subhx, subly, subhy, ni->proto, uptrans,
997 localindex, oni, globalindex, state);
998 if (!dr_quickparalleldrc) uphierarchy();
999 }
1000 return(FALSE);
1001 }
1002
1003 /*
1004 * Routine to recursively examine the area (lx-hx, ly-hy) in cell "np" with global index "globalindex".
1005 * The objects that are found are transformed by "uptrans" to be in the space of a top-level cell.
1006 * They are then compared with objects in "oni" (which is in that top-level cell),
1007 * which has global index "topglobalindex".
1008 */
dr_quickcheckcellinstcontents(INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy,NODEPROTO * np,XARRAY uptrans,INTBIG globalindex,NODEINST * oni,INTBIG topglobalindex,CHECKSTATE * state)1009 BOOLEAN dr_quickcheckcellinstcontents(INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy, NODEPROTO *np,
1010 XARRAY uptrans, INTBIG globalindex, NODEINST *oni, INTBIG topglobalindex, CHECKSTATE *state)
1011 {
1012 REGISTER INTBIG subsearch, tot, j, net, localindex;
1013 INTBIG sublx, subhx, subly, subhy;
1014 REGISTER GEOM *geom;
1015 REGISTER NODEINST *ni;
1016 REGISTER ARCINST *ai;
1017 REGISTER BOOLEAN errorsfound, ret;
1018 XARRAY rtrans, ttrans, trans, subuptrans;
1019 REGISTER CHECKINST *ci;
1020 REGISTER POLYGON *poly;
1021
1022 errorsfound = FALSE;
1023 subsearch = initsearch(lx, hx, ly, hy, np);
1024 for(;;)
1025 {
1026 geom = nextobject(subsearch);
1027 if (geom == NOGEOM) break;
1028 if (geom->entryisnode)
1029 {
1030 ni = geom->entryaddr.ni;
1031 if (ni->proto->primindex == 0)
1032 {
1033 sublx = lx; subhx = hx;
1034 subly = ly; subhy = hy;
1035 makerotI(ni, rtrans);
1036 maketransI(ni, ttrans);
1037 transmult(rtrans, ttrans, trans);
1038 xformbox(&sublx, &subhx, &subly, &subhy, trans);
1039
1040 maketrans(ni, ttrans);
1041 makerot(ni, rtrans);
1042 transmult(ttrans, rtrans, trans);
1043 transmult(trans, uptrans, subuptrans);
1044
1045 ci = (CHECKINST *)ni->temp1;
1046 localindex = globalindex * ci->multiplier + ci->localindex + ci->offset;
1047
1048 if (!dr_quickparalleldrc) downhierarchy(ni, ni->proto, 0);
1049 dr_quickcheckcellinstcontents(sublx, subhx, subly, subhy, ni->proto,
1050 subuptrans, localindex, oni, topglobalindex, state);
1051 if (!dr_quickparalleldrc) uphierarchy();
1052 } else
1053 {
1054 makerot(ni, rtrans);
1055 transmult(rtrans, uptrans, trans);
1056 dr_quickgetnodeEpolys(ni, state->cellinstpolylist, trans);
1057 tot = state->cellinstpolylist->polylistcount;
1058 for(j=0; j<tot; j++)
1059 {
1060 poly = state->cellinstpolylist->polygons[j];
1061 if (poly->layer < 0) continue;
1062
1063 /* determine network for this polygon */
1064 net = dr_quickgetnetnumber(poly->portproto, ni, globalindex);
1065 ret = dr_quickbadsubbox(poly, poly->layer, net, ni->proto->tech, ni->geom, trans,
1066 globalindex, np, oni, topglobalindex, state);
1067 if (ret)
1068 {
1069 if ((dr_quickoptions&DRCFIRSTERROR) != 0)
1070 {
1071 termsearch(subsearch);
1072 return(TRUE);
1073 }
1074 errorsfound = TRUE;
1075 }
1076 }
1077 }
1078 } else
1079 {
1080 ai = geom->entryaddr.ai;
1081 dr_quickgetarcpolys(ai, state->cellinstpolylist, uptrans);
1082 dr_quickcropactivearc(ai, state->cellinstpolylist, state);
1083 tot = state->cellinstpolylist->polylistcount;
1084 for(j=0; j<tot; j++)
1085 {
1086 poly = state->cellinstpolylist->polygons[j];
1087 if (poly->layer < 0) continue;
1088 if (ai->network == NONETWORK) net = NONET; else
1089 net = ((INTBIG *)ai->network->temp1)[globalindex];
1090 ret = dr_quickbadsubbox(poly, poly->layer, net, ai->proto->tech, ai->geom, uptrans,
1091 globalindex, np, oni, topglobalindex, state);
1092 if (ret)
1093 {
1094 if ((dr_quickoptions&DRCFIRSTERROR) != 0)
1095 {
1096 termsearch(subsearch);
1097 return(TRUE);
1098 }
1099 errorsfound = TRUE;
1100 }
1101 }
1102 }
1103 }
1104 return(errorsfound);
1105 }
1106
1107 /*
1108 * Routine to examine polygon "poly" layer "layer" network "net" technology "tech" geometry "geom"
1109 * which is in cell "cell" and has global index "globalindex".
1110 * The polygon is compared against things inside node "oni", and that node's parent has global index "topglobalindex".
1111 */
dr_quickbadsubbox(POLYGON * poly,INTBIG layer,INTBIG net,TECHNOLOGY * tech,GEOM * geom,XARRAY trans,INTBIG globalindex,NODEPROTO * cell,NODEINST * oni,INTBIG topglobalindex,CHECKSTATE * state)1112 BOOLEAN dr_quickbadsubbox(POLYGON *poly, INTBIG layer, INTBIG net, TECHNOLOGY *tech, GEOM *geom, XARRAY trans,
1113 INTBIG globalindex, NODEPROTO *cell, NODEINST *oni, INTBIG topglobalindex, CHECKSTATE *state)
1114 {
1115 REGISTER BOOLEAN basemulti, retval;
1116 REGISTER INTBIG minsize, bound, lxbound, hxbound, lybound, hybound, localindex;
1117 INTBIG lx, hx, ly, hy;
1118 XARRAY rtrans, ttrans, downtrans, uptrans;
1119 REGISTER CHECKINST *ci;
1120
1121 /* see how far around the box it is necessary to search */
1122 bound = maxdrcsurround(tech, cell->lib, layer);
1123 if (bound < 0) return(FALSE);
1124
1125 /* get bounds */
1126 getbbox(poly, &lx, &hx, &ly, &hy);
1127 makerotI(oni, rtrans);
1128 maketransI(oni, ttrans);
1129 transmult(rtrans, ttrans, downtrans);
1130 xformbox(&lx, &hx, &ly, &hy, downtrans);
1131 minsize = polyminsize(poly);
1132
1133 maketrans(oni, ttrans);
1134 makerot(oni, rtrans);
1135 transmult(ttrans, rtrans, uptrans);
1136
1137 ci = (CHECKINST *)oni->temp1;
1138 localindex = topglobalindex * ci->multiplier + ci->localindex + ci->offset;
1139
1140 /* determine if original object has multiple contact cuts */
1141 if (geom->entryisnode) basemulti = dr_quickismulticut(geom->entryaddr.ni); else
1142 basemulti = FALSE;
1143
1144 /* remember the current position in the hierarchy traversal and set the base one */
1145 gethierarchicaltraversal(state->hierarchytempsnapshot);
1146 sethierarchicaltraversal(state->hierarchybasesnapshot);
1147
1148 /* search in the area surrounding the box */
1149 lxbound = lx-bound; hxbound = hx+bound;
1150 lybound = ly-bound; hybound = hy+bound;
1151 retval = dr_quickbadboxinarea(poly, layer, tech, net, geom, trans, globalindex,
1152 lxbound, hxbound, lybound, hybound, oni->proto, localindex,
1153 oni->parent, topglobalindex, uptrans, minsize, basemulti, state, FALSE);
1154
1155 /* restore the proper hierarchy traversal position */
1156 sethierarchicaltraversal(state->hierarchytempsnapshot);
1157 return(retval);
1158 }
1159
1160 /*
1161 * Routine to examine a polygon to see if it has any errors with its surrounding area.
1162 * The polygon is "poly" on layer "layer" on network "net" from technology "tech" from object "geom".
1163 * Checking looks in cell "cell" global index "globalindex".
1164 * Object "geom" can be transformed to the space of this cell with "trans".
1165 * Returns TRUE if a spacing error is found relative to anything surrounding it at or below
1166 * this hierarchical level.
1167 */
dr_quickbadbox(POLYGON * poly,INTBIG layer,INTBIG net,TECHNOLOGY * tech,GEOM * geom,XARRAY trans,NODEPROTO * cell,INTBIG globalindex,CHECKSTATE * state)1168 BOOLEAN dr_quickbadbox(POLYGON *poly, INTBIG layer, INTBIG net, TECHNOLOGY *tech, GEOM *geom,
1169 XARRAY trans, NODEPROTO *cell, INTBIG globalindex, CHECKSTATE *state)
1170 {
1171 REGISTER BOOLEAN basemulti;
1172 REGISTER INTBIG minsize, bound, lxbound, hxbound, lybound, hybound;
1173 INTBIG lx, hx, ly, hy;
1174
1175 /* see how far around the box it is necessary to search */
1176 bound = maxdrcsurround(tech, cell->lib, layer);
1177 if (bound < 0) return(FALSE);
1178
1179 /* get bounds */
1180 getbbox(poly, &lx, &hx, &ly, &hy);
1181 minsize = polyminsize(poly);
1182
1183 /* determine if original object has multiple contact cuts */
1184 if (geom->entryisnode) basemulti = dr_quickismulticut(geom->entryaddr.ni); else
1185 basemulti = FALSE;
1186
1187 /* search in the area surrounding the box */
1188 lxbound = lx-bound; hxbound = hx+bound;
1189 lybound = ly-bound; hybound = hy+bound;
1190 return(dr_quickbadboxinarea(poly, layer, tech, net, geom, trans, globalindex,
1191 lxbound, hxbound, lybound, hybound, cell, globalindex,
1192 cell, globalindex, el_matid, minsize, basemulti, state, TRUE));
1193 }
1194
1195 /*
1196 * Routine to recursively examine a polygon to see if it has any errors with its surrounding area.
1197 * The polygon is "poly" on layer "layer" from technology "tech" on network "net" from object "geom"
1198 * which is associated with global index "globalindex".
1199 * Checking looks in the area (lxbound-hxbound, lybound-hybound) in cell "cell" global index "cellglobalindex".
1200 * The polygon coordinates are in the space of cell "topcell", global index "topglobalindex",
1201 * and objects in "cell" can be transformed by "toptrans" to get to this space.
1202 * The base object, in "geom" can be transformed by "trans" to get to this space.
1203 * The minimum size of this polygon is "minsize" and "basemulti" is TRUE if it comes from a multicut contact.
1204 * If the two objects are in the same cell instance (nonhierarchical DRC), then "sameinstance" is TRUE.
1205 * If they are from different instances, then "sameinstance" is FALSE.
1206 *
1207 * Returns TRUE if errors are found.
1208 */
dr_quickbadboxinarea(POLYGON * poly,INTBIG layer,TECHNOLOGY * tech,INTBIG net,GEOM * geom,XARRAY trans,INTBIG globalindex,INTBIG lxbound,INTBIG hxbound,INTBIG lybound,INTBIG hybound,NODEPROTO * cell,INTBIG cellglobalindex,NODEPROTO * topcell,INTBIG topglobalindex,XARRAY toptrans,INTBIG minsize,BOOLEAN basemulti,CHECKSTATE * state,BOOLEAN sameinstance)1209 BOOLEAN dr_quickbadboxinarea(POLYGON *poly, INTBIG layer, TECHNOLOGY *tech, INTBIG net, GEOM *geom, XARRAY trans,
1210 INTBIG globalindex,
1211 INTBIG lxbound, INTBIG hxbound, INTBIG lybound, INTBIG hybound, NODEPROTO *cell, INTBIG cellglobalindex,
1212 NODEPROTO *topcell, INTBIG topglobalindex, XARRAY toptrans, INTBIG minsize, BOOLEAN basemulti,
1213 CHECKSTATE *state, BOOLEAN sameinstance)
1214 {
1215 REGISTER GEOM *ngeom;
1216 REGISTER NODEPROTO *np;
1217 REGISTER ARCINST *ai;
1218 REGISTER NODEINST *ni;
1219 REGISTER ARCPROTO *ap;
1220 REGISTER BOOLEAN touch, ret, multi;
1221 REGISTER INTBIG nnet, search, dist, j, tot, nminsize,
1222 localindex, count;
1223 REGISTER POLYGON *npoly;
1224 XARRAY rtrans, ttrans, subtrans, temptrans;
1225 CHAR *rule;
1226 REGISTER BOOLEAN con;
1227 INTBIG edge, slx, shx, sly, shy, rlxbound, rhxbound, rlybound, rhybound;
1228 REGISTER CHECKINST *ci;
1229
1230 rlxbound = lxbound; rhxbound = hxbound;
1231 rlybound = lybound; rhybound = hybound;
1232 xformbox(&rlxbound, &rhxbound, &rlybound, &rhybound, toptrans);
1233
1234 search = initsearch(lxbound, hxbound, lybound, hybound, cell);
1235 count = 0;
1236 for(;;)
1237 {
1238 ngeom = nextobject(search);
1239 if (ngeom == NOGEOM) break;
1240 if (sameinstance && (ngeom == geom)) continue;
1241 if (ngeom->entryisnode)
1242 {
1243 ni = ngeom->entryaddr.ni;
1244 np = ni->proto;
1245
1246 /* ignore nodes that are not primitive */
1247 if (np->primindex == 0)
1248 {
1249 /* instance found: look inside it for offending geometry */
1250 makerotI(ni, rtrans);
1251 maketransI(ni, ttrans);
1252 transmult(rtrans, ttrans, temptrans);
1253 slx = lxbound; shx = hxbound;
1254 sly = lybound; shy = hybound;
1255 xformbox(&slx, &shx, &sly, ­, temptrans);
1256
1257 ci = (CHECKINST *)ni->temp1;
1258 localindex = cellglobalindex * ci->multiplier + ci->localindex + ci->offset;
1259
1260 maketrans(ni, ttrans);
1261 makerot(ni, rtrans);
1262 transmult(ttrans, rtrans, temptrans);
1263 transmult(temptrans, toptrans, subtrans);
1264
1265 /* compute localindex */
1266 if (!dr_quickparalleldrc) downhierarchy(ni, np, 0);
1267 dr_quickbadboxinarea(poly, layer, tech, net, geom, trans, globalindex,
1268 slx, shx, sly, shy, np, localindex,
1269 topcell, topglobalindex, subtrans, minsize, basemulti, state, sameinstance);
1270 if (!dr_quickparalleldrc) uphierarchy();
1271 } else
1272 {
1273 /* don't check between technologies */
1274 if (np->tech != tech) continue;
1275
1276 /* see if this type of node can interact with this layer */
1277 if (!dr_quickchecklayerwithnode(layer, np)) continue;
1278
1279 /* see if the objects directly touch */
1280 touch = dr_quickobjtouch(ngeom, geom);
1281
1282 /* prepare to examine every layer in this nodeinst */
1283 makerot(ni, rtrans);
1284 transmult(rtrans, toptrans, subtrans);
1285
1286 /* get the shape of each nodeinst layer */
1287 dr_quickgetnodeEpolys(ni, state->subpolylist, subtrans);
1288 tot = state->subpolylist->polylistcount;
1289 multi = basemulti;
1290 if (!multi) multi = dr_quickismulticut(ni);
1291 for(j=0; j<tot; j++)
1292 {
1293 npoly = state->subpolylist->polygons[j];
1294
1295 /* can't do this because "lxbound..." is local but the poly bounds are global */
1296 if (state->subpolylist->lx[j] > rhxbound ||
1297 state->subpolylist->hx[j] < rlxbound ||
1298 state->subpolylist->ly[j] > rhybound ||
1299 state->subpolylist->hy[j] < rlybound) continue;
1300 if (npoly->layer < 0) continue;
1301
1302 /* determine network for this polygon */
1303 nnet = dr_quickgetnetnumber(npoly->portproto, ni, cellglobalindex);
1304
1305 /* see whether the two objects are electrically connected */
1306 if (nnet != NONET && nnet == net) con = TRUE; else con = FALSE;
1307
1308 /* if they connect electrically and adjoin, don't check */
1309 if (con && touch) continue;
1310
1311 nminsize = polyminsize(npoly);
1312 dist = dr_adjustedmindist(tech, cell->lib, layer, minsize,
1313 npoly->layer, nminsize, con, multi, &edge, &rule);
1314 if (dist < 0) continue;
1315
1316 /* check the distance */
1317 ret = dr_quickcheckdist(tech, topcell, topglobalindex,
1318 poly, layer, net, geom, trans, globalindex,
1319 npoly, npoly->layer, nnet, ngeom, subtrans, cellglobalindex,
1320 con, dist, edge, rule, state);
1321 #ifndef ALLERRORS
1322 if (ret)
1323 {
1324 termsearch(search);
1325 return(TRUE);
1326 }
1327 #endif
1328 }
1329 }
1330 } else
1331 {
1332 ai = ngeom->entryaddr.ai; ap = ai->proto;
1333
1334 /* don't check between technologies */
1335 if (ap->tech != tech) continue;
1336
1337 /* see if this type of arc can interact with this layer */
1338 if (!dr_quickchecklayerwitharc(layer, ap)) continue;
1339
1340 /* see if the objects directly touch */
1341 touch = dr_quickobjtouch(ngeom, geom);
1342
1343 /* see whether the two objects are electrically connected */
1344 nnet = ((INTBIG *)ai->network->temp1)[cellglobalindex];
1345 if (net != NONET && nnet == net) con = TRUE; else con = FALSE;
1346
1347 /* if they connect electrically and adjoin, don't check */
1348 if (con && touch) continue;
1349
1350 /* get the shape of each arcinst layer */
1351 dr_quickgetarcpolys(ai, state->subpolylist, toptrans);
1352 dr_quickcropactivearc(ai, state->subpolylist, state);
1353 tot = state->subpolylist->polylistcount;
1354 multi = basemulti;
1355 for(j=0; j<tot; j++)
1356 {
1357 npoly = state->subpolylist->polygons[j];
1358
1359 /* can't do this because "lxbound..." is local but the poly bounds are global */
1360 if (state->subpolylist->lx[j] > rhxbound ||
1361 state->subpolylist->hx[j] < rlxbound ||
1362 state->subpolylist->ly[j] > rhybound ||
1363 state->subpolylist->hy[j] < rlybound) continue;
1364 if (npoly->layer < 0) continue;
1365
1366 /* see how close they can get */
1367 nminsize = polyminsize(npoly);
1368 dist = dr_adjustedmindist(tech, cell->lib, layer,
1369 minsize, npoly->layer, nminsize, con, multi, &edge, &rule);
1370 if (dist < 0) continue;
1371
1372 /* check the distance */
1373 ret = dr_quickcheckdist(tech, topcell, topglobalindex,
1374 poly, layer, net, geom, trans, globalindex,
1375 npoly, npoly->layer, nnet, ngeom, toptrans, cellglobalindex,
1376 con, dist, edge, rule, state);
1377 #ifndef ALLERRORS
1378 if (ret)
1379 {
1380 termsearch(search);
1381 return(TRUE);
1382 }
1383 #endif
1384 }
1385 }
1386 }
1387 return(FALSE);
1388 }
1389
1390 /* #define DEBUGDRC 1 */
1391
1392 /*
1393 * Routine to compare:
1394 * polygon "poly1" layer "layer1" network "net1" object "geom1"
1395 * with:
1396 * polygon "poly2" layer "layer2" network "net2" object "geom2"
1397 * The polygons are both in technology "tech" and are in the space of cell "cell"
1398 * which has global index "globalindex".
1399 * Note that to transform object "geom1" to this space, use "trans1" and to transform
1400 * object "geom2" to this space, use "trans2".
1401 * They are connected if "con" is nonzero.
1402 * They cannot be less than "dist" apart (if "edge" is nonzero, check edges only)
1403 * and the rule for this is "rule".
1404 *
1405 * Returns TRUE if an error has been found.
1406 */
dr_quickcheckdist(TECHNOLOGY * tech,NODEPROTO * cell,INTBIG globalindex,POLYGON * poly1,INTBIG layer1,INTBIG net1,GEOM * geom1,XARRAY trans1,INTBIG globalindex1,POLYGON * poly2,INTBIG layer2,INTBIG net2,GEOM * geom2,XARRAY trans2,INTBIG globalindex2,BOOLEAN con,INTBIG dist,INTBIG edge,CHAR * rule,CHECKSTATE * state)1407 BOOLEAN dr_quickcheckdist(TECHNOLOGY *tech, NODEPROTO *cell, INTBIG globalindex,
1408 POLYGON *poly1, INTBIG layer1, INTBIG net1, GEOM *geom1, XARRAY trans1, INTBIG globalindex1,
1409 POLYGON *poly2, INTBIG layer2, INTBIG net2, GEOM *geom2, XARRAY trans2, INTBIG globalindex2,
1410 BOOLEAN con, INTBIG dist, INTBIG edge, CHAR *rule, CHECKSTATE *state)
1411 {
1412 REGISTER BOOLEAN isbox1, isbox2, needboth, maytouch;
1413 INTBIG lx1, hx1, ly1, hy1, lx2, hx2, ly2, hy2, xf1, yf1, xf2, yf2;
1414 CHAR *msg, *sizerule;
1415 void *infstr;
1416 REGISTER POLYGON *origpoly1, *origpoly2;
1417 REGISTER INTBIG pdx, pdy, pd, pdedge, fun, errtype, minwidth,
1418 lxb, hxb, lyb, hyb, actual, intervening;
1419 #ifdef DEBUGDRC
1420 REGISTER BOOLEAN debug;
1421 #endif
1422 #ifdef ALLERRORS
1423 REGISTER BOOLEAN returnflag;
1424 returnflag = FALSE;
1425 #endif
1426
1427 /* turn off flag that the nodeinst may be undersized */
1428 state->tinynodeinst = NONODEINST;
1429
1430 origpoly1 = poly1;
1431 origpoly2 = poly2;
1432 isbox1 = isbox(poly1, &lx1, &hx1, &ly1, &hy1);
1433 if (!isbox1) getbbox(poly1, &lx1, &hx1, &ly1, &hy1);
1434 isbox2 = isbox(poly2, &lx2, &hx2, &ly2, &hy2);
1435 if (!isbox2) getbbox(poly2, &lx2, &hx2, &ly2, &hy2);
1436 #ifdef DEBUGDRC
1437 debug=FALSE;
1438 if (layer1 == 9 && layer2 == 9) debug = TRUE;
1439 if (layer2 == 9 && layer1 == 9) debug = TRUE;
1440 if (debug)
1441 {
1442 CHAR *layername1, *layername2;
1443 void *infstr; CHAR *pt;
1444
1445 layername1 = layername(tech, layer1);
1446 layername2 = layername(tech, layer2);
1447 ttyputmsg("Comparing layer %s on %s is %s<=X<=%s and %s<=Y<=%s", layername1, geomname(geom1), latoa(lx1,0), latoa(hx1,0), latoa(ly1,0), latoa(hy1,0));
1448 ttyputmsg(" with layer %s on %s is %s<=X<=%s and %s<=Y<=%s", layername2, geomname(geom2), latoa(lx2,0), latoa(hx2,0), latoa(ly2,0), latoa(hy2,0));
1449 asktool(us_tool, x_("clear"));
1450 asktool(us_tool, x_("show-area"), lx1, hx1, ly1, hy1, (INTBIG)cell);
1451 asktool(us_tool, x_("show-area"), lx2, hx2, ly2, hy2, (INTBIG)cell);
1452 asktool(us_tool, x_("show-line"), lx2, ly2, hx2, hy2, (INTBIG)cell);
1453 asktool(us_tool, x_("show-line"), lx2, hy2, hx2, ly2, (INTBIG)cell);
1454 infstr = initinfstr();
1455 formatinfstr(infstr, x_("Layers %s and %s:"), layername1, layername2);
1456 pt = ttygetline(returninfstr(infstr));
1457 if (pt == 0 || *pt == 'q') debug = FALSE;
1458 }
1459 #endif
1460
1461 /*
1462 * special rule for allowing touching:
1463 * the layers are the same and either:
1464 * they connect and are *NOT* contact layers
1465 * or:
1466 * they don't connect and are implant layers (substrate/well)
1467 */
1468 maytouch = FALSE;
1469 if (samelayer(tech, layer1, layer2))
1470 {
1471 fun = layerfunction(tech, layer1) & LFTYPE;
1472 if (con)
1473 {
1474 if (!layeriscontact(fun)) maytouch = TRUE;
1475 } else
1476 {
1477 if (fun == LFSUBSTRATE || fun == LFWELL || fun == LFIMPLANT) maytouch = TRUE;
1478 }
1479 }
1480
1481 /* special code if both polygons are manhattan */
1482 if (isbox1 && isbox2)
1483 {
1484 /* manhattan */
1485 pdx = maxi(lx2-hx1, lx1-hx2);
1486 pdy = maxi(ly2-hy1, ly1-hy2);
1487 if (pdx == 0 && pdy == 0) pd = 1; else
1488 pd = maxi(pdx, pdy);
1489 if (maytouch)
1490 {
1491 /* they are electrically connected: see if they touch */
1492 if (pd <= 0)
1493 {
1494 /* they are electrically connected and they touch: look for minimum size errors */
1495 minwidth = drcminwidth(tech, cell->lib, layer1, &sizerule);
1496 lxb = maxi(lx1, lx2);
1497 hxb = mini(hx1, hx2);
1498 lyb = maxi(ly1, ly2);
1499 hyb = mini(hy1, hy2);
1500 actual = computedistance(lxb, lyb, hxb, hyb);
1501 if (actual != 0 && actual < minwidth)
1502 {
1503 if (hxb-lxb > hyb-lyb)
1504 {
1505 /* horizontal abutment: check for minimum width */
1506 if (!dr_quicklookforpoints(lxb-1, lyb-1, lxb-1, hyb+1, layer1, cell, TRUE, state) &&
1507 !dr_quicklookforpoints(hxb+1, lyb-1, hxb+1, hyb+1, layer1, cell, TRUE, state))
1508 {
1509 lyb -= minwidth/2; hyb += minwidth/2;
1510 state->checkdistpoly1rebuild->xv[0] = lxb;
1511 state->checkdistpoly1rebuild->yv[0] = lyb;
1512 state->checkdistpoly1rebuild->xv[1] = hxb;
1513 state->checkdistpoly1rebuild->yv[1] = hyb;
1514 state->checkdistpoly1rebuild->count = 2;
1515 state->checkdistpoly1rebuild->style = FILLEDRECT;
1516 dr_quickreporterror(MINWIDTHERROR, tech, 0, cell, minwidth,
1517 actual, sizerule, state->checkdistpoly1rebuild,
1518 geom1, layer1, NONET, NOPOLYGON, NOGEOM, 0, NONET);
1519 #ifdef ALLERRORS
1520 returnflag = TRUE;
1521 #else
1522 return(TRUE);
1523 #endif
1524 }
1525 } else
1526 {
1527 /* vertical abutment: check for minimum width */
1528 if (!dr_quicklookforpoints(lxb-1, lyb-1, hxb+1, lyb-1, layer1, cell, TRUE, state) &&
1529 !dr_quicklookforpoints(lxb-1, hyb+1, hxb+1, hyb+1, layer1, cell, TRUE, state))
1530 {
1531 lxb -= minwidth/2; hxb += minwidth/2;
1532 state->checkdistpoly1rebuild->xv[0] = lxb;
1533 state->checkdistpoly1rebuild->yv[0] = lyb;
1534 state->checkdistpoly1rebuild->xv[1] = hxb;
1535 state->checkdistpoly1rebuild->yv[1] = hyb;
1536 state->checkdistpoly1rebuild->count = 2;
1537 state->checkdistpoly1rebuild->style = FILLEDRECT;
1538 dr_quickreporterror(MINWIDTHERROR, tech, 0, cell, minwidth,
1539 actual, sizerule, state->checkdistpoly1rebuild,
1540 geom1, layer1, NONET, NOPOLYGON, NOGEOM, 0, NONET);
1541 #ifdef ALLERRORS
1542 returnflag = TRUE;
1543 #else
1544 return(TRUE);
1545 #endif
1546 }
1547 }
1548 }
1549 }
1550 }
1551
1552 /* crop out parts of any arc that is covered by an adjoining node */
1553 if (geom1->entryisnode)
1554 {
1555 if (dr_quickcropnodeinst(geom1->entryaddr.ni, globalindex1, state, trans1,
1556 lx1, hx1, ly1, hy1, layer2, net2, geom2, &lx2, &hx2, &ly2, &hy2))
1557 {
1558 #ifndef ALLERRORS
1559 return(FALSE);
1560 #endif
1561 }
1562 } else
1563 {
1564 if (dr_quickcroparcinst(geom1->entryaddr.ai, layer1, trans1, &lx1, &hx1, &ly1, &hy1, state))
1565 {
1566 #ifndef ALLERRORS
1567 return(FALSE);
1568 #endif
1569 }
1570 }
1571 if (geom2->entryisnode)
1572 {
1573 if (dr_quickcropnodeinst(geom2->entryaddr.ni, globalindex2, state, trans2,
1574 lx2, hx2, ly2, hy2, layer1, net1, geom1, &lx1, &hx1, &ly1, &hy1))
1575 {
1576 #ifndef ALLERRORS
1577 return(FALSE);
1578 #endif
1579 }
1580 } else
1581 {
1582 if (dr_quickcroparcinst(geom2->entryaddr.ai, layer2, trans2, &lx2, &hx2, &ly2, &hy2, state))
1583 {
1584 #ifndef ALLERRORS
1585 return(FALSE);
1586 #endif
1587 }
1588 }
1589 #ifdef DEBUGDRC
1590 if (debug)
1591 {
1592 void *infstr; CHAR *pt;
1593
1594 asktool(us_tool, x_("clear"));
1595 asktool(us_tool, x_("show-area"), lx1, hx1, ly1, hy1, (INTBIG)cell);
1596 asktool(us_tool, x_("show-area"), lx2, hx2, ly2, hy2, (INTBIG)cell);
1597 asktool(us_tool, x_("show-line"), lx2, ly2, hx2, hy2, (INTBIG)cell);
1598 asktool(us_tool, x_("show-line"), lx2, hy2, hx2, ly2, (INTBIG)cell);
1599 infstr = initinfstr();
1600 formatinfstr(infstr, x_("Cropped:"));
1601 pt = ttygetline(returninfstr(infstr));
1602 if (pt == 0 || *pt == 'q') debug = FALSE;
1603 }
1604 #endif
1605
1606 makerectpoly(lx1, hx1, ly1, hy1, state->checkdistpoly1rebuild);
1607 state->checkdistpoly1rebuild->style = FILLED;
1608 makerectpoly(lx2, hx2, ly2, hy2, state->checkdistpoly2rebuild);
1609 state->checkdistpoly2rebuild->style = FILLED;
1610 poly1 = state->checkdistpoly1rebuild;
1611 poly2 = state->checkdistpoly2rebuild;
1612
1613 /* compute the distance */
1614 if (edge != 0)
1615 {
1616 /* calculate the spacing between the box edges */
1617 pdedge = mini(
1618 mini(mini(abs(lx1-lx2), abs(lx1-hx2)), mini(abs(hx1-lx2), abs(hx1-hx2))),
1619 mini(mini(abs(ly1-ly2), abs(ly1-hy2)), mini(abs(hy1-ly2), abs(hy1-hy2))));
1620 pd = maxi(pd, pdedge);
1621 } else
1622 {
1623 pdx = maxi(lx2-hx1, lx1-hx2);
1624 pdy = maxi(ly2-hy1, ly1-hy2);
1625 if (pdx == 0 && pdy == 0) pd = 1; else
1626 {
1627 pd = maxi(pdx, pdy);
1628 if (pd < dist && pd > 0) pd = polyseparation(poly1, poly2);
1629 }
1630 }
1631 } else
1632 {
1633 /* nonmanhattan */
1634 switch (poly1->style)
1635 {
1636 case FILLEDRECT:
1637 case CLOSEDRECT:
1638 maketruerect(poly1);
1639 break;
1640 case FILLED:
1641 case CLOSED:
1642 case CROSSED:
1643 case OPENED:
1644 case OPENEDT1:
1645 case OPENEDT2:
1646 case OPENEDT3:
1647 case VECTORS:
1648 break;
1649 default:
1650 return(FALSE);
1651 }
1652
1653 switch (poly2->style)
1654 {
1655 case FILLEDRECT:
1656 case CLOSEDRECT:
1657 maketruerect(poly2);
1658 break;
1659 case FILLED:
1660 case CLOSED:
1661 case CROSSED:
1662 case OPENED:
1663 case OPENEDT1:
1664 case OPENEDT2:
1665 case OPENEDT3:
1666 case VECTORS:
1667 break;
1668 default:
1669 return(FALSE);
1670 }
1671
1672 /* make sure polygons don't intersect */
1673 if (polyintersect(poly1, poly2)) pd = 0; else
1674 {
1675 /* find distance between polygons */
1676 pd = polyseparation(poly1, poly2);
1677 }
1678 }
1679
1680 /* see if the design rule is met */
1681 if (pd >= dist)
1682 {
1683 #ifndef ALLERRORS
1684 return(FALSE);
1685 #endif
1686 }
1687 errtype = SPACINGERROR;
1688 #ifdef DEBUGDRC
1689 if (debug) ttyputmsg("distance=%s but limit=%s", latoa(pd,0), latoa(dist,0));
1690 #endif
1691
1692 /*
1693 * special case: ignore errors between two active layers connected
1694 * to either side of a field-effect transistor that is inside of
1695 * the error area.
1696 */
1697 if (dr_quickactiveontransistor(poly1, layer1, net1,
1698 poly2, layer2, net2, tech, cell, globalindex))
1699 {
1700 #ifndef ALLERRORS
1701 return(FALSE);
1702 #endif
1703 }
1704 #ifdef DEBUGDRC
1705 if (debug) ttyputmsg("Active-on-transistor rule didn't help");
1706 #endif
1707
1708 /* special cases if the layers are the same */
1709 if (samelayer(tech, layer1, layer2))
1710 {
1711 /* special case: check for "notch" */
1712 if (maytouch)
1713 {
1714 /* if they touch, it is acceptable */
1715 if (pd <= 0)
1716 {
1717 #ifndef ALLERRORS
1718 return(FALSE);
1719 #endif
1720 }
1721
1722 /* see if the notch is filled */
1723 intervening = dr_quickfindinterveningpoints(poly1, poly2, &xf1, &yf1, &xf2, &yf2);
1724 if (intervening == 0)
1725 {
1726 #ifndef ALLERRORS
1727 return(FALSE);
1728 #endif
1729 }
1730 if (intervening == 1) needboth = FALSE; else
1731 needboth = TRUE;
1732 if (dr_quicklookforpoints(xf1, yf1, xf2, yf2, layer1, cell, needboth, state))
1733 {
1734 #ifndef ALLERRORS
1735 return(FALSE);
1736 #endif
1737 }
1738
1739 /* look further if on the same net and diagonally separate (1 intervening point) */
1740 if (net1 == net2 && intervening == 1)
1741 {
1742 #ifndef ALLERRORS
1743 return(FALSE);
1744 #endif
1745 }
1746 errtype = NOTCHERROR;
1747 }
1748 }
1749 #ifdef DEBUGDRC
1750 if (debug) ttygetline("Touching rules didn't help. THIS IS AN ERROR");
1751 #endif
1752
1753 msg = 0;
1754 if (state->tinynodeinst != NONODEINST)
1755 {
1756 /* see if the node/arc that failed was involved in the error */
1757 if ((state->tinynodeinst->geom == geom1 || state->tinynodeinst->geom == geom2) &&
1758 (state->tinyobj == geom1 || state->tinyobj == geom2))
1759 {
1760 infstr = initinfstr();
1761 if (dr_quickparalleldrc)
1762 emutexlock(dr_quickmutexio); /* BEGIN critical section */
1763 formatinfstr(infstr, _("%s is too small for the %s"),
1764 describenodeinst(state->tinynodeinst), geomname(state->tinyobj));
1765 if (dr_quickparalleldrc)
1766 emutexunlock(dr_quickmutexio); /* END critical section */
1767 (void)allocstring(&msg, returninfstr(infstr), dr_tool->cluster);
1768 }
1769 }
1770
1771 dr_quickreporterror(errtype, tech, msg, cell, dist, pd, rule,
1772 origpoly1, geom1, layer1, net1,
1773 origpoly2, geom2, layer2, net2);
1774 #ifdef ALLERRORS
1775 return(returnflag);
1776 #else
1777 return(TRUE);
1778 #endif
1779 }
1780
1781 /*************************** QUICK DRC SEE IF INSTANCES CAUSE ERRORS ***************************/
1782
1783 /*
1784 * Routine to examine, in cell "cell", the "count" instances in "nodestocheck".
1785 * If they are DRC clean, set the associated entry in "validity" to TRUE.
1786 */
dr_quickchecktheseinstances(NODEPROTO * cell,INTBIG count,NODEINST ** nodestocheck,BOOLEAN * validity)1787 void dr_quickchecktheseinstances(NODEPROTO *cell, INTBIG count, NODEINST **nodestocheck, BOOLEAN *validity)
1788 {
1789 REGISTER INTBIG lx, hx, ly, hy, search, globalindex, localindex, i, j;
1790 INTBIG sublx, subhx, subly, subhy;
1791 REGISTER GEOM *geom;
1792 REGISTER NODEINST *ni, *oni;
1793 XARRAY rtrans, ttrans, downtrans, uptrans;
1794 REGISTER CHECKINST *ci;
1795 REGISTER CHECKSTATE *state;
1796
1797 globalindex = 0;
1798 state = dr_quickstate[0];
1799 state->globalindex = globalindex;
1800
1801 /* loop through all of the instances to be checked */
1802 for(i=0; i<count; i++)
1803 {
1804 ni = nodestocheck[i];
1805 validity[i] = TRUE;
1806
1807 /* look for other instances surrounding this one */
1808 lx = ni->geom->lowx - dr_quickinteractiondistance;
1809 hx = ni->geom->highx + dr_quickinteractiondistance;
1810 ly = ni->geom->lowy - dr_quickinteractiondistance;
1811 hy = ni->geom->highy + dr_quickinteractiondistance;
1812 search = initsearch(lx, hx, ly, hy, ni->parent);
1813 for(;;)
1814 {
1815 geom = nextobject(search);
1816 if (geom == NOGEOM) break;
1817 if (!geom->entryisnode)
1818 {
1819 if (dr_quickcheckgeomagainstinstance(geom, ni, state))
1820 {
1821 validity[i] = FALSE;
1822 termsearch(search);
1823 break;
1824 }
1825 continue;
1826 }
1827 oni = geom->entryaddr.ni;
1828 if (oni->proto->primindex != 0)
1829 {
1830 /* found a primitive node: check it against the instance contents */
1831 if (dr_quickcheckgeomagainstinstance(geom, ni, state))
1832 {
1833 validity[i] = FALSE;
1834 termsearch(search);
1835 break;
1836 }
1837 continue;
1838 }
1839
1840 /* ignore if it is one of the instances in the list */
1841 for(j=0; j<count; j++)
1842 if (oni == nodestocheck[j]) break;
1843 if (j < count) continue;
1844
1845 /* found other instance "oni", look for everything in "ni" that is near it */
1846 sublx = oni->geom->lowx - dr_quickinteractiondistance;
1847 subhx = oni->geom->highx + dr_quickinteractiondistance;
1848 subly = oni->geom->lowy - dr_quickinteractiondistance;
1849 subhy = oni->geom->highy + dr_quickinteractiondistance;
1850 makerotI(ni, rtrans);
1851 maketransI(ni, ttrans);
1852 transmult(rtrans, ttrans, downtrans);
1853 xformbox(&sublx, &subhx, &subly, &subhy, downtrans);
1854
1855 maketrans(ni, ttrans);
1856 makerot(ni, rtrans);
1857 transmult(ttrans, rtrans, uptrans);
1858
1859 ci = (CHECKINST *)ni->temp1;
1860 localindex = globalindex * ci->multiplier + ci->localindex + ci->offset;
1861
1862 /* recursively search instance "ni" in the vicinity of "oni" */
1863 if (dr_quickcheckcellinstcontents(sublx, subhx, subly, subhy, ni->proto, uptrans,
1864 localindex, oni, globalindex, dr_quickstate[0]))
1865 {
1866 /* errors were found: bail */
1867 validity[i] = FALSE;
1868 termsearch(search);
1869 break;
1870 }
1871 }
1872 }
1873 }
1874
1875 /*
1876 * Routine to check primitive object "geom" (an arcinst or primitive nodeinst) against cell instance "ni".
1877 * Returns TRUE if there are design-rule violations in their interaction.
1878 */
dr_quickcheckgeomagainstinstance(GEOM * geom,NODEINST * ni,CHECKSTATE * state)1879 BOOLEAN dr_quickcheckgeomagainstinstance(GEOM *geom, NODEINST *ni, CHECKSTATE *state)
1880 {
1881 REGISTER NODEPROTO *np, *subcell;
1882 REGISTER ARCINST *oai;
1883 REGISTER NODEINST *oni;
1884 REGISTER TECHNOLOGY *tech;
1885 REGISTER BOOLEAN basemulti;
1886 REGISTER INTBIG tot, j, bound, net, minsize, localindex, globalindex;
1887 INTBIG lx, hx, ly, hy, slx, shx, sly, shy;
1888 XARRAY rtrans, ttrans, temptrans, subtrans, trans;
1889 REGISTER POLYGON *poly;
1890 REGISTER CHECKINST *ci;
1891
1892 np = ni->proto;
1893 globalindex = 0;
1894 subcell = geomparent(geom);
1895 if (geom->entryisnode)
1896 {
1897 /* get all of the polygons on this node */
1898 oni = geom->entryaddr.ni;
1899 makerot(oni, trans);
1900 dr_quickgetnodeEpolys(oni, state->nodeinstpolylist, trans);
1901 basemulti = dr_quickismulticut(oni);
1902 tech = oni->proto->tech;
1903 } else
1904 {
1905 oai = geom->entryaddr.ai;
1906 transid(trans);
1907 dr_quickgetarcpolys(oai, state->nodeinstpolylist, trans);
1908 basemulti = FALSE;
1909 tech = oai->proto->tech;
1910 }
1911 tot = state->nodeinstpolylist->polylistcount;
1912
1913 ci = (CHECKINST *)ni->temp1;
1914 localindex = globalindex * ci->multiplier + ci->localindex + ci->offset;
1915
1916 /* examine the polygons on this node */
1917 for(j=0; j<tot; j++)
1918 {
1919 poly = state->nodeinstpolylist->polygons[j];
1920 if (poly->layer < 0) continue;
1921
1922 /* see how far around the box it is necessary to search */
1923 bound = maxdrcsurround(tech, subcell->lib, poly->layer);
1924 if (bound < 0) continue;
1925
1926 /* determine network for this polygon */
1927 if (geom->entryisnode)
1928 {
1929 net = dr_quickgetnetnumber(poly->portproto, oni, globalindex);
1930 } else
1931 {
1932 net = ((INTBIG *)oai->network->temp1)[globalindex];
1933 }
1934
1935 /* determine if original object has multiple contact cuts */
1936 minsize = polyminsize(poly);
1937
1938 /* determine area to search inside of cell to check this layer */
1939 getbbox(poly, &lx, &hx, &ly, &hy);
1940 slx = lx-bound; shx = hx+bound;
1941 sly = ly-bound; shy = hy+bound;
1942 makerotI(ni, rtrans);
1943 maketransI(ni, ttrans);
1944 transmult(rtrans, ttrans, temptrans);
1945 xformbox(&slx, &shx, &sly, ­, temptrans);
1946
1947 maketrans(ni, ttrans);
1948 makerot(ni, rtrans);
1949 transmult(ttrans, rtrans, subtrans);
1950
1951 /* see if this polygon has errors in the cell */
1952 if (dr_quickbadboxinarea(poly, poly->layer, tech, net, geom, trans, globalindex,
1953 slx, shx, sly, shy, np, localindex,
1954 subcell, globalindex, subtrans, minsize, basemulti, state, FALSE)) return(TRUE);
1955 }
1956 return(FALSE);
1957 }
1958
1959 /*************************** QUICK DRC CACHE OF INSTANCE INTERACTIONS ***************************/
1960
1961 /*
1962 * Routine to look for an interaction between instances "ni1" and "ni2". If it is found,
1963 * return TRUE. If not found, add to the list and return FALSE. In either case,
1964 * sets "thedii" to the address of the interaction object for this instance pair.
1965 */
dr_quickcheckinteraction(NODEINST * ni1,NODEINST * ni2,INSTINTER ** thedii)1966 BOOLEAN dr_quickcheckinteraction(NODEINST *ni1, NODEINST *ni2, INSTINTER **thedii)
1967 {
1968 REGISTER NODEINST *swapni;
1969 REGISTER INSTINTER **newlist, **oldlist;
1970 INSTINTER *dii;
1971 REGISTER BOOLEAN found;
1972 REGISTER INTBIG newtotal, oldtotal, i;
1973 REGISTER CHECKPROTO *cp;
1974
1975 /* must recheck parameterized instances always */
1976 *thedii = NOINSTINTER;
1977 cp = (CHECKPROTO *)ni1->proto->temp1;
1978 if (cp->cellparameterized) return(FALSE);
1979 cp = (CHECKPROTO *)ni2->proto->temp1;
1980 if (cp->cellparameterized) return(FALSE);
1981
1982 /* keep the instances in proper numeric order */
1983 if ((INTBIG)ni1 < (INTBIG)ni2)
1984 {
1985 swapni = ni1; ni1 = ni2; ni2 = swapni;
1986 } else if (ni1 == ni2)
1987 {
1988 if (ni1->rotation + ni1->transpose*3600 < ni2->rotation + ni2->transpose*3600)
1989 {
1990 swapni = ni1; ni1 = ni2; ni2 = swapni;
1991 }
1992 }
1993
1994 /* BEGIN critical section */
1995 if (dr_quickparalleldrc) emutexlock(dr_quickmutexinteract);
1996
1997 /* get essential information about their interaction */
1998 dii = dr_quickallocinstinter();
1999 if (dii == NOINSTINTER) return(FALSE);
2000 dii->cell1 = ni1->proto;
2001 dii->rot1 = ni1->rotation;
2002 dii->trn1 = ni1->transpose;
2003
2004 dii->cell2 = ni2->proto;
2005 dii->rot2 = ni2->rotation;
2006 dii->trn2 = ni2->transpose;
2007 dii->dx = (ni2->lowx + ni2->highx - (ni1->lowx + ni1->highx)) / 2;
2008 dii->dy = (ni2->lowy + ni2->highy - (ni1->lowy + ni1->highy)) / 2;
2009
2010 /* if found, stop now */
2011 *thedii = dr_quickfindinteraction(dii);
2012 if (*thedii != NOINSTINTER)
2013 {
2014 dr_quickfreeinstinter(dii);
2015
2016 /* END critical section */
2017 if (dr_quickparalleldrc) emutexunlock(dr_quickmutexinteract);
2018 return(TRUE);
2019 }
2020
2021 /* build a hash code to locate this interaction */
2022 if (dr_quickinstintercount*2 >= dr_quickinstintertotal)
2023 {
2024 newtotal = dr_quickinstintertotal * 2;
2025 if (dr_quickinstintercount*2 >= newtotal)
2026 newtotal = dr_quickinstintercount+50;
2027 newtotal = pickprime(newtotal);
2028 newlist = (INSTINTER **)emalloc(newtotal * (sizeof (INSTINTER *)), dr_tool->cluster);
2029 if (newlist == 0)
2030 {
2031 if (dr_quickparalleldrc) emutexunlock(dr_quickmutexinteract);
2032 return(FALSE);
2033 }
2034 for(i=0; i<newtotal; i++)
2035 newlist[i] = NOINSTINTER;
2036 oldlist = dr_quickinstinter;
2037 oldtotal = dr_quickinstintertotal;
2038 dr_quickinstinter = newlist;
2039 dr_quickinstintertotal = newtotal;
2040
2041 /* reinsert former entries */
2042 dr_quickinstintercount = 0;
2043 for(i=0; i<oldtotal; i++)
2044 if (oldlist[i] != NOINSTINTER)
2045 dr_quickinsertinteraction(oldlist[i]);
2046 if (oldtotal > 0) efree((CHAR *)oldlist);
2047 }
2048
2049 /* see if this entry is there */
2050 found = FALSE;
2051 *thedii = dr_quickfindinteraction(dii);
2052 if (*thedii != NOINSTINTER)
2053 {
2054 dr_quickfreeinstinter(dii);
2055 found = TRUE;
2056 } else
2057 {
2058 /* insert it now */
2059 (void)dr_quickinsertinteraction(dii);
2060 *thedii = dii;
2061 }
2062
2063 /* END critical section */
2064 if (dr_quickparalleldrc) emutexunlock(dr_quickmutexinteract);
2065 return(found);
2066 }
2067
2068 /*
2069 * Routine to remove all instance interaction information.
2070 */
dr_quickclearinstancecache(void)2071 void dr_quickclearinstancecache(void)
2072 {
2073 REGISTER INTBIG i;
2074
2075 for(i=0; i<dr_quickinstintertotal; i++)
2076 {
2077 if (dr_quickinstinter[i] == NOINSTINTER) continue;
2078 dr_quickfreeinstinter(dr_quickinstinter[i]);
2079 dr_quickinstinter[i] = NOINSTINTER;
2080 }
2081 }
2082
2083 /*
2084 * Routine to look for the instance-interaction in "dii" in the global list of instances interactions
2085 * that have already been checked. Returns the entry if it is found, NOINSTINTER if not.
2086 */
dr_quickfindinteraction(INSTINTER * dii)2087 INSTINTER *dr_quickfindinteraction(INSTINTER *dii)
2088 {
2089 REGISTER INTBIG hash, i;
2090 REGISTER INSTINTER *diientry;
2091
2092 if (dr_quickinstintertotal == 0) return(NOINSTINTER);
2093 hash = abs(((INTBIG)dii->cell1 + dii->rot1 + dii->trn1 +
2094 (INTBIG)dii->cell2 + dii->rot2 + dii->trn2 + dii->dx + dii->dy) %
2095 dr_quickinstintertotal);
2096 for(i=0; i<dr_quickinstintertotal; i++)
2097 {
2098 diientry = dr_quickinstinter[hash];
2099 if (diientry == NOINSTINTER) break;
2100 if (diientry->cell1 == dii->cell1 && diientry->rot1 == dii->rot1 && diientry->trn1 == dii->trn1 &&
2101 diientry->cell2 == dii->cell2 && diientry->rot2 == dii->rot2 && diientry->trn2 == dii->trn2 &&
2102 diientry->dx == dii->dx && diientry->dy == dii->dy) return(diientry);
2103 hash++;
2104 if (hash >= dr_quickinstintertotal) hash = 0;
2105 }
2106 return(NOINSTINTER);
2107 }
2108
2109 /*
2110 * Routine to insert the instance-interaction in "dii" into the global list of instances interactions
2111 * that have already been checked. Returns TRUE if there is no room.
2112 */
dr_quickinsertinteraction(INSTINTER * dii)2113 BOOLEAN dr_quickinsertinteraction(INSTINTER *dii)
2114 {
2115 REGISTER INTBIG hash, i;
2116
2117 hash = abs(((INTBIG)dii->cell1 + dii->rot1 + dii->trn1 +
2118 (INTBIG)dii->cell2 + dii->rot2 + dii->trn2 + dii->dx + dii->dy) %
2119 dr_quickinstintertotal);
2120 for(i=0; i<dr_quickinstintertotal; i++)
2121 {
2122 if (dr_quickinstinter[hash] == NOINSTINTER)
2123 {
2124 dr_quickinstinter[hash] = dii;
2125 dr_quickinstintercount++;
2126 return(FALSE);
2127 }
2128 hash++;
2129 if (hash >= dr_quickinstintertotal) hash = 0;
2130 }
2131 return(TRUE);
2132 }
2133
dr_quickallocinstinter(void)2134 INSTINTER *dr_quickallocinstinter(void)
2135 {
2136 REGISTER INSTINTER *dii;
2137
2138 if (dr_quickinstinterfree == NOINSTINTER)
2139 {
2140 dii = (INSTINTER *)emalloc(sizeof (INSTINTER), dr_tool->cluster);
2141 if (dii == 0) return(NOINSTINTER);
2142 } else
2143 {
2144 dii = dr_quickinstinterfree;
2145 dr_quickinstinterfree = (INSTINTER *)dii->cell1;
2146 }
2147 return(dii);
2148 }
2149
2150 /*
2151 * Routine to free INSTINTER object "dii".
2152 */
dr_quickfreeinstinter(INSTINTER * dii)2153 void dr_quickfreeinstinter(INSTINTER *dii)
2154 {
2155 dii->cell1 = (NODEPROTO *)dr_quickinstinterfree;
2156 dr_quickinstinterfree = dii;
2157 }
2158
2159 /*************************** QUICK DRC MULTIPROCESSOR SUPPORT ***************************/
2160
2161 /*
2162 * Routine to initialize the various state blocks and interlocks to prepare for multiprocessor
2163 * DRC using "numstates" processors. Returns TRUE on error.
2164 */
dr_quickmakestateblocks(INTBIG numstates)2165 BOOLEAN dr_quickmakestateblocks(INTBIG numstates)
2166 {
2167 REGISTER INTBIG i;
2168 REGISTER CHECKSTATE **newstates;
2169 REGISTER void **newlocks;
2170
2171 /* code cannot be called by multiple procesors: uses globals */
2172 NOT_REENTRANT;
2173
2174 if (numstates <= dr_quickstatecount) return(FALSE);
2175 newstates = (CHECKSTATE **)emalloc(numstates * (sizeof (CHECKSTATE *)), dr_tool->cluster);
2176 if (newstates == 0) return(TRUE);
2177 newlocks = (void **)emalloc(numstates * (sizeof (void *)), dr_tool->cluster);
2178 if (newlocks == 0) return(TRUE);
2179 for(i=0; i<dr_quickstatecount; i++)
2180 {
2181 newstates[i] = dr_quickstate[i];
2182 newlocks[i] = dr_quickprocessdone[i];
2183 }
2184 for(i=dr_quickstatecount; i<numstates; i++)
2185 {
2186 newstates[i] = (CHECKSTATE *)emalloc(sizeof(CHECKSTATE), dr_tool->cluster);
2187 if (newstates[i] == 0) return(TRUE);
2188
2189 newstates[i]->cellinstpolylist = allocpolylist(dr_tool->cluster);
2190 if (newstates[i]->cellinstpolylist == 0) return(TRUE);
2191
2192 newstates[i]->nodeinstpolylist = allocpolylist(dr_tool->cluster);
2193 if (newstates[i]->nodeinstpolylist == 0) return(TRUE);
2194
2195 newstates[i]->arcinstpolylist = allocpolylist(dr_tool->cluster);
2196 if (newstates[i]->arcinstpolylist == 0) return(TRUE);
2197
2198 newstates[i]->subpolylist = allocpolylist(dr_tool->cluster);
2199 if (newstates[i]->subpolylist == 0) return(TRUE);
2200
2201 newstates[i]->cropnodepolylist = allocpolylist(dr_tool->cluster);
2202 if (newstates[i]->cropnodepolylist == 0) return(TRUE);
2203
2204 newstates[i]->croparcpolylist = allocpolylist(dr_tool->cluster);
2205 if (newstates[i]->croparcpolylist == 0) return(TRUE);
2206
2207 newstates[i]->layerlookpolylist = allocpolylist(dr_tool->cluster);
2208 if (newstates[i]->layerlookpolylist == 0) return(TRUE);
2209
2210 newstates[i]->activecroppolylist = allocpolylist(dr_tool->cluster);
2211 if (newstates[i]->activecroppolylist == 0) return(TRUE);
2212
2213 newstates[i]->checkdistpoly1rebuild = NOPOLYGON;
2214 (void)needstaticpolygon(&newstates[i]->checkdistpoly1rebuild, 4, dr_tool->cluster);
2215 newstates[i]->checkdistpoly2rebuild = NOPOLYGON;
2216 (void)needstaticpolygon(&newstates[i]->checkdistpoly2rebuild, 4, dr_tool->cluster);
2217
2218 newstates[i]->hierarchybasesnapshot = newhierarchicaltraversal();
2219 newstates[i]->hierarchytempsnapshot = newhierarchicaltraversal();
2220
2221 newlocks[i] = 0;
2222 if (ensurevalidmutex(&newlocks[i], TRUE)) return(TRUE);
2223 }
2224 if (dr_quickstatecount > 0)
2225 {
2226 efree((CHAR *)dr_quickstate);
2227 efree((CHAR *)dr_quickprocessdone);
2228 }
2229 dr_quickstate = newstates;
2230 dr_quickprocessdone = newlocks;
2231 dr_quickstatecount = numstates;
2232 return(FALSE);
2233 }
2234
2235 /*
2236 * Routine to return the next set of nodes or arcs to check.
2237 * Returns the number of objects to check (up to MAXCHECKOBJECTS)
2238 * and places them in "list".
2239 */
dr_quickgetnextparallelgeoms(GEOM ** list,CHECKSTATE * state)2240 INTBIG dr_quickgetnextparallelgeoms(GEOM **list, CHECKSTATE *state)
2241 {
2242 REGISTER NODEINST *ni;
2243 REGISTER ARCINST *ai;
2244 REGISTER INTBIG i;
2245
2246 /* grab a bunch of primitive nodes first */
2247 i = 0;
2248 if (dr_quickparallelnodeinst != NONODEINST)
2249 {
2250 /* only the main thread can call "stopping" */
2251 if (state == dr_quickstate[dr_quickmainthread])
2252 (void)stopping(STOPREASONDRC);
2253
2254 /* all threads check whether interrupt has been requested */
2255 if (el_pleasestop != 0)
2256 {
2257 dr_quickparallelnodeinst = NONODEINST;
2258 dr_quickparallelcellinst = NONODEINST;
2259 dr_quickparallelarcinst = NOARCINST;
2260 return(0);
2261 }
2262
2263 /* if errors were found and only the first is requested, stop now */
2264 if (dr_quickerrorsfound && (dr_quickoptions&DRCFIRSTERROR) != 0)
2265 {
2266 dr_quickparallelnodeinst = NONODEINST;
2267 dr_quickparallelcellinst = NONODEINST;
2268 dr_quickparallelarcinst = NOARCINST;
2269 return(0);
2270 }
2271
2272 emutexlock(dr_quickmutexnode);
2273 for(;;)
2274 {
2275 ni = dr_quickparallelnodeinst;
2276 if (ni == NONODEINST) break;
2277 dr_quickparallelnodeinst = ni->nextnodeinst;
2278
2279 /* ignore cell instances */
2280 if (ni->proto->primindex == 0) continue;
2281
2282 /* ignore if not in requested area */
2283 if (dr_quickjustarea)
2284 {
2285 if (ni->geom->lowx >= dr_quickareahx || ni->geom->highx <= dr_quickarealx ||
2286 ni->geom->lowy >= dr_quickareahy || ni->geom->highy <= dr_quickarealy) continue;
2287 }
2288
2289 list[i] = ni->geom;
2290 i++;
2291 if (i >= MAXCHECKOBJECTS) break;
2292 }
2293 emutexunlock(dr_quickmutexnode);
2294 if (i > 0) return(i);
2295 }
2296
2297 /* grab a bunch of arcs next */
2298 if (dr_quickparallelarcinst != NOARCINST)
2299 {
2300 /* only the main thread can call "stopping" */
2301 if (state == dr_quickstate[dr_quickmainthread])
2302 (void)stopping(STOPREASONDRC);
2303
2304 /* all threads check whether interrupt has been requested */
2305 if (el_pleasestop != 0)
2306 {
2307 dr_quickparallelnodeinst = NONODEINST;
2308 dr_quickparallelcellinst = NONODEINST;
2309 dr_quickparallelarcinst = NOARCINST;
2310 return(0);
2311 }
2312
2313 /* if errors were found and only the first is requested, stop now */
2314 if (dr_quickerrorsfound && (dr_quickoptions&DRCFIRSTERROR) != 0)
2315 {
2316 dr_quickparallelnodeinst = NONODEINST;
2317 dr_quickparallelcellinst = NONODEINST;
2318 dr_quickparallelarcinst = NOARCINST;
2319 return(0);
2320 }
2321
2322 emutexlock(dr_quickmutexnode);
2323 for(;;)
2324 {
2325 ai = dr_quickparallelarcinst;
2326 if (ai == NOARCINST) break;
2327 dr_quickparallelarcinst = ai->nextarcinst;
2328
2329 /* ignore if not in requested area */
2330 if (dr_quickjustarea)
2331 {
2332 if (ai->geom->lowx >= dr_quickareahx || ai->geom->highx <= dr_quickarealx ||
2333 ai->geom->lowy >= dr_quickareahy || ai->geom->highy <= dr_quickarealy) continue;
2334 }
2335
2336 list[i] = ai->geom;
2337 i++;
2338 if (i >= MAXCHECKOBJECTS) break;
2339 }
2340 emutexunlock(dr_quickmutexnode);
2341 if (i > 0) return(i);
2342 }
2343
2344 /* grab cell instances, one at a time */
2345 if (dr_quickparallelcellinst == NONODEINST) return(0);
2346
2347 /* only the main thread can call "stopping" */
2348 if (state == dr_quickstate[dr_quickmainthread])
2349 (void)stopping(STOPREASONDRC);
2350
2351 /* all threads check whether interrupt has been requested */
2352 if (el_pleasestop != 0)
2353 {
2354 dr_quickparallelnodeinst = NONODEINST;
2355 dr_quickparallelcellinst = NONODEINST;
2356 dr_quickparallelarcinst = NOARCINST;
2357 return(0);
2358 }
2359
2360 /* if errors were found and only the first is requested, stop now */
2361 if (dr_quickerrorsfound && (dr_quickoptions&DRCFIRSTERROR) != 0)
2362 {
2363 dr_quickparallelnodeinst = NONODEINST;
2364 dr_quickparallelcellinst = NONODEINST;
2365 dr_quickparallelarcinst = NOARCINST;
2366 return(0);
2367 }
2368
2369 emutexlock(dr_quickmutexnode);
2370 for(;;)
2371 {
2372 ni = dr_quickparallelcellinst;
2373 if (ni == NONODEINST) break;
2374 dr_quickparallelcellinst = ni->nextnodeinst;
2375
2376 /* only want cell instances */
2377 if (ni->proto->primindex != 0) continue;
2378
2379 /* ignore if not in requested area */
2380 if (dr_quickjustarea)
2381 {
2382 if (ni->geom->lowx >= dr_quickareahx || ni->geom->highx <= dr_quickarealx ||
2383 ni->geom->lowy >= dr_quickareahy || ni->geom->highy <= dr_quickarealy) continue;
2384 }
2385
2386 list[0] = ni->geom;
2387 i++;
2388 break;
2389 }
2390 emutexunlock(dr_quickmutexnode);
2391 return(i);
2392 }
2393
2394 /*
2395 * Routine to run a thread that repeatedly fetches a node and analyzes it.
2396 */
dr_quickdothread(void * argument)2397 void *dr_quickdothread(void *argument)
2398 {
2399 REGISTER NODEINST *ni;
2400 REGISTER ARCINST *ai;
2401 REGISTER GEOM *geom;
2402 REGISTER BOOLEAN ret;
2403 GEOM *list[MAXCHECKOBJECTS];
2404 REGISTER INTBIG i, count, globalindex;
2405 REGISTER CHECKSTATE *state;
2406
2407 state = dr_quickstate[(INTBIG)argument];
2408 globalindex = state->globalindex;
2409 for(;;)
2410 {
2411 count = dr_quickgetnextparallelgeoms(list, state);
2412 if (count == 0) break;
2413 for(i=0; i<count; i++)
2414 {
2415 geom = list[i];
2416 if (geom->entryisnode)
2417 {
2418 ni = geom->entryaddr.ni;
2419 if (ni->proto->primindex == 0)
2420 {
2421 ret = dr_quickcheckcellinst(ni, globalindex, state);
2422 } else
2423 {
2424 ret = dr_quickchecknodeinst(ni, globalindex, state);
2425 }
2426 } else
2427 {
2428 ai = geom->entryaddr.ai;
2429 ret = dr_quickcheckarcinst(ai, globalindex, state);
2430 }
2431 if (ret)
2432 {
2433 dr_quickerrorsfound++;
2434 if ((dr_quickoptions&DRCFIRSTERROR) != 0) break;
2435 }
2436 }
2437 }
2438
2439 /* mark this process as "done" */
2440 emutexunlock(dr_quickprocessdone[(INTBIG)argument]);
2441 return(0);
2442 }
2443
2444 /************************* QUICK DRC HIERARCHICAL NETWORK BUILDING *************************/
2445
2446 /*
2447 * Routine to recursively examine the hierarchy below cell "cell" and fill in the
2448 * CHECKINST objects on every cell instance. Uses the CHECKPROTO objects
2449 * to keep track of cell usage.
2450 */
dr_quickcheckenumerateinstances(NODEPROTO * cell)2451 void dr_quickcheckenumerateinstances(NODEPROTO *cell)
2452 {
2453 REGISTER NODEINST *ni;
2454 REGISTER CHECKINST *ci;
2455 REGISTER CHECKPROTO *cp, *firstcp;
2456
2457 /* number all of the instances in this cell */
2458 dr_quickchecktimestamp++;
2459 firstcp = NOCHECKPROTO;
2460 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2461 {
2462 if (ni->proto->primindex != 0) continue;
2463
2464 /* ignore documentation icons */
2465 if (isiconof(ni->proto, cell)) continue;
2466
2467 cp = (CHECKPROTO *)ni->proto->temp1;
2468 if (cp->timestamp != dr_quickchecktimestamp)
2469 {
2470 cp->timestamp = dr_quickchecktimestamp;
2471 cp->instancecount = 0;
2472 cp->firstincell = NONODEINST;
2473 cp->nextcheckproto = firstcp;
2474 firstcp = cp;
2475 }
2476 ci = (CHECKINST *)ni->temp1;
2477 ci->localindex = cp->instancecount++;
2478 ni->temp2 = (INTBIG)cp->firstincell;
2479 cp->firstincell = ni;
2480 }
2481
2482 /* update the counts for this cell */
2483 for(cp = firstcp; cp != NOCHECKPROTO; cp = cp->nextcheckproto)
2484 {
2485 cp->hierinstancecount += cp->instancecount;
2486 for(ni = cp->firstincell; ni != NONODEINST; ni = (NODEINST *)ni->temp2)
2487 {
2488 ci = (CHECKINST *)ni->temp1;
2489 ci->multiplier = cp->instancecount;
2490 }
2491 }
2492
2493 /* now recurse */
2494 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2495 {
2496 if (ni->proto->primindex != 0) continue;
2497
2498 /* ignore documentation icons */
2499 if (isiconof(ni->proto, cell)) continue;
2500
2501 dr_quickcheckenumerateinstances(ni->proto);
2502 }
2503 }
2504
dr_quickcheckenumeratenetworks(NODEPROTO * cell,INTBIG globalindex)2505 void dr_quickcheckenumeratenetworks(NODEPROTO *cell, INTBIG globalindex)
2506 {
2507 REGISTER NODEINST *ni;
2508 REGISTER NODEPROTO *subcell;
2509 REGISTER CHECKINST *ci;
2510 REGISTER PORTARCINST *pi;
2511 REGISTER PORTEXPINST *pe;
2512 REGISTER ARCINST *ai;
2513 REGISTER NETWORK *net;
2514 REGISTER INTBIG localindex, *netnumbers;
2515
2516 #ifdef VALIDATENETWORKS /* assert: index must be valid */
2517 REGISTER CHECKPROTO *cp;
2518 cp = (CHECKPROTO *)cell->temp1;
2519 if (globalindex >= cp->hierinstancecount)
2520 ttyputmsg(x_("Invalid global index (%d) in cell %s (limit is %d)"), globalindex,
2521 describenodeproto(cell), cp->hierinstancecount);
2522 #endif
2523
2524 /* store all network information in the appropriate place */
2525 for(net = cell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
2526 {
2527 netnumbers = (INTBIG *)net->temp1;
2528
2529 #ifdef VALIDATENETWORKS /* assert: must only fill each entry once */
2530 if (netnumbers[globalindex] != 0)
2531 ttyputmsg(x_("Duplicate network index (%d) on network %s in cell %s"), globalindex,
2532 describenetwork(net), describenodeproto(cell));
2533 #endif
2534 netnumbers[globalindex] = net->temp2;
2535 }
2536
2537 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2538 {
2539 if (ni->proto->primindex != 0) continue;
2540
2541 /* ignore documentation icons */
2542 if (isiconof(ni->proto, cell)) continue;
2543
2544 /* compute the index of this instance */
2545 ci = (CHECKINST *)ni->temp1;
2546 localindex = globalindex * ci->multiplier + ci->localindex + ci->offset;
2547
2548 /* propagate down the hierarchy */
2549 subcell = ni->proto;
2550 for(net = subcell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
2551 net->temp2 = 0;
2552 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
2553 {
2554 ai = pi->conarcinst;
2555 if (ai->network == NONETWORK) continue;
2556 pi->proto->network->temp2 = ai->network->temp2;
2557 }
2558 for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
2559 {
2560 if (pe->proto->network->temp2 == 0)
2561 pe->proto->network->temp2 = pe->exportproto->network->temp2;
2562 }
2563 for(net = subcell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
2564 if (net->temp2 == 0) net->temp2 = dr_quickchecknetnumber++;
2565 dr_quickcheckenumeratenetworks(subcell, localindex);
2566 }
2567 }
2568
2569 /*
2570 * Routine to allocate a "CHECKINST" object. Returns NOCHECKINST on error.
2571 */
dr_quickalloccheckinst(void)2572 CHECKINST *dr_quickalloccheckinst(void)
2573 {
2574 REGISTER CHECKINST *ci;
2575
2576 if (dr_quickcheckinstfree == NOCHECKINST)
2577 {
2578 ci = (CHECKINST *)emalloc(sizeof (CHECKINST), dr_tool->cluster);
2579 if (ci == 0) return(NOCHECKINST);
2580 } else
2581 {
2582 ci = dr_quickcheckinstfree;
2583 dr_quickcheckinstfree = (CHECKINST *)ci->localindex;
2584 }
2585 return(ci);
2586 }
2587
2588 /*
2589 * Routine to free CHECKINST object "ci".
2590 */
dr_quickfreecheckinst(CHECKINST * ci)2591 void dr_quickfreecheckinst(CHECKINST *ci)
2592 {
2593 ci->localindex = (INTBIG)dr_quickcheckinstfree;
2594 dr_quickcheckinstfree = ci;
2595 }
2596
2597 /*
2598 * Routine to allocate a "CHECKPROTO" object. Returns NOCHECKPROTO on error.
2599 */
dr_quickalloccheckproto(void)2600 CHECKPROTO *dr_quickalloccheckproto(void)
2601 {
2602 REGISTER CHECKPROTO *cp;
2603
2604 if (dr_quickcheckprotofree == NOCHECKPROTO)
2605 {
2606 cp = (CHECKPROTO *)emalloc(sizeof (CHECKPROTO), dr_tool->cluster);
2607 if (cp == 0) return(NOCHECKPROTO);
2608 } else
2609 {
2610 cp = dr_quickcheckprotofree;
2611 dr_quickcheckprotofree = cp->nextcheckproto;
2612 }
2613 return(cp);
2614 }
2615
2616 /*
2617 * Routine to free CHECKPROTO object "cp".
2618 */
dr_quickfreecheckproto(CHECKPROTO * cp)2619 void dr_quickfreecheckproto(CHECKPROTO *cp)
2620 {
2621 cp->nextcheckproto = dr_quickcheckprotofree;
2622 dr_quickcheckprotofree = cp;
2623 }
2624
2625 /*********************************** QUICK DRC SUPPORT ***********************************/
2626
2627 /*
2628 * Routine to ensure that polygon "poly" on layer "layer" from object "geom" in
2629 * technology "tech" meets minimum width rules. If it is too narrow, other layers
2630 * in the vicinity are checked to be sure it is indeed an error. Returns true
2631 * if an error is found.
2632 */
dr_quickcheckminwidth(GEOM * geom,INTBIG layer,POLYGON * poly,TECHNOLOGY * tech,CHECKSTATE * state)2633 BOOLEAN dr_quickcheckminwidth(GEOM *geom, INTBIG layer, POLYGON *poly, TECHNOLOGY *tech, CHECKSTATE *state)
2634 {
2635 REGISTER INTBIG minwidth, actual;
2636 INTBIG lx, hx, ly, hy, ix, iy;
2637 CHAR *rule;
2638 double rang, roang, fdx, fdy;
2639 BOOLEAN p1found, p2found, p3found;
2640 REGISTER double ang, oang, perpang;
2641 REGISTER NODEPROTO *cell;
2642 REGISTER INTBIG xl1, yl1, xl2, yl2, xl3, yl3, xr1, yr1, xr2, yr2, xr3, yr3,
2643 cx, cy, fx, fy, tx, ty, ofx, ofy, otx, oty, i, j;
2644
2645 cell = geomparent(geom);
2646 minwidth = drcminwidth(tech, cell->lib, layer, &rule);
2647 if (minwidth < 0) return(FALSE);
2648
2649 /* simpler analysis if manhattan */
2650 if (isbox(poly, &lx, &hx, &ly, &hy))
2651 {
2652 if (hx - lx >= minwidth && hy - ly >= minwidth) return(FALSE);
2653 if (hx - lx < minwidth)
2654 {
2655 actual = hx - lx;
2656 xl1 = xl2 = xl3 = lx - 1;
2657 xr1 = xr2 = xr3 = hx + 1;
2658 yl1 = yr1 = ly;
2659 yl2 = yr2 = hy;
2660 yl3 = yr3 = (yl1+yl2)/2;
2661 } else
2662 {
2663 actual = hy - ly;
2664 xl1 = xr1 = lx;
2665 xl2 = xr2 = hx;
2666 xl3 = xr3 = (xl1+xl2)/2;
2667 yl1 = yl2 = yl3 = ly - 1;
2668 yr1 = yr2 = yr3 = hy + 1;
2669 }
2670
2671 /* see if there is more of this layer adjoining on either side */
2672 p1found = p2found = p3found = FALSE;
2673 if (dr_quicklookforlayer(cell, layer, el_matid, state, lx-1, hx+1, ly-1, hy+1,
2674 xl1, yl1, &p1found, xl2, yl2, &p2found, xl3, yl3, &p3found)) return(FALSE);
2675
2676 p1found = p2found = p3found = FALSE;
2677 if (dr_quicklookforlayer(cell, layer, el_matid, state, lx-1, hx+1, ly-1, hy+1,
2678 xr1, yr1, &p1found, xr2, yr2, &p2found, xr3, yr3, &p3found)) return(FALSE);
2679
2680 dr_quickreporterror(MINWIDTHERROR, tech, 0, cell, minwidth, actual, rule,
2681 poly, geom, layer, NONET, NOPOLYGON, NOGEOM, 0, NONET);
2682 return(TRUE);
2683 }
2684
2685 /* nonmanhattan polygon: stop now if it has no size */
2686 switch (poly->style)
2687 {
2688 case FILLED:
2689 case CLOSED:
2690 case CROSSED:
2691 case OPENED:
2692 case OPENEDT1:
2693 case OPENEDT2:
2694 case OPENEDT3:
2695 case VECTORS:
2696 break;
2697 default:
2698 return(FALSE);
2699 }
2700
2701 /* simple check of nonmanhattan polygon for minimum width */
2702 getbbox(poly, &lx, &hx, &ly, &hy);
2703 actual = mini(hx-lx, hy-ly);
2704 if (actual < minwidth)
2705 {
2706 dr_quickreporterror(MINWIDTHERROR, tech, 0, cell, minwidth, actual, rule,
2707 poly, geom, layer, NONET, NOPOLYGON, NOGEOM, 0, NONET);
2708 return(TRUE);
2709 }
2710
2711 /* check distance of each line's midpoint to perpendicular opposite point */
2712 for(i=0; i<poly->count; i++)
2713 {
2714 if (i == 0)
2715 {
2716 fx = poly->xv[poly->count-1]; fy = poly->yv[poly->count-1];
2717 } else
2718 {
2719 fx = poly->xv[i-1]; fy = poly->yv[i-1];
2720 }
2721 tx = poly->xv[i]; ty = poly->yv[i];
2722 if (fx == tx && fy == ty) continue;
2723 ang = ffigureangle(fx, fy, tx, ty);
2724 cx = (fx + tx) / 2;
2725 cy = (fy + ty) / 2;
2726 perpang = ang + EPI/2;
2727 for(j=0; j<poly->count; j++)
2728 {
2729 if (j == i) continue;
2730 if (j == 0)
2731 {
2732 ofx = poly->xv[poly->count-1]; ofy = poly->yv[poly->count-1];
2733 } else
2734 {
2735 ofx = poly->xv[j-1]; ofy = poly->yv[j-1];
2736 }
2737 otx = poly->xv[j]; oty = poly->yv[j];
2738 if (ofx == otx && ofy == oty) continue;
2739 oang = ffigureangle(ofx, ofy, otx, oty);
2740 rang = ang; while (rang > EPI) rang -= EPI;
2741 roang = oang; while (roang > EPI) roang -= EPI;
2742 if (doublesequal(oang, roang))
2743 {
2744 /* lines are parallel: see if they are colinear */
2745 if (isonline(fx, fy, tx, ty, ofx, ofy)) continue;
2746 if (isonline(fx, fy, tx, ty, otx, oty)) continue;
2747 if (isonline(ofx, ofy, otx, oty, fx, fy)) continue;
2748 if (isonline(ofx, ofy, otx, oty, tx, ty)) continue;
2749 }
2750 if (fintersect(cx, cy, perpang, ofx, ofy, oang, &ix, &iy) < 0) continue;
2751 if (ix < mini(ofx, otx) || ix > maxi(ofx, otx)) continue;
2752 if (iy < mini(ofy, oty) || iy > maxi(ofy, oty)) continue;
2753 fdx = cx - ix; fdy = cy - iy;
2754 actual = rounddouble(sqrt(fdx*fdx + fdy*fdy));
2755
2756 /* becuase this is done in integer, accuracy may suffer */
2757 actual += 2;
2758
2759 if (actual < minwidth)
2760 {
2761 /* look between the points to see if it is minimum width or notch */
2762 if (isinside((cx+ix)/2, (cy+iy)/2, poly))
2763 {
2764 dr_quickreporterror(MINWIDTHERROR, tech, 0, cell, minwidth,
2765 actual, rule, poly, geom, layer, NONET, NOPOLYGON, NOGEOM, 0, NONET);
2766 } else
2767 {
2768 dr_quickreporterror(NOTCHERROR, tech, 0, cell, minwidth,
2769 actual, rule, poly, geom, layer, NONET, poly, geom, layer, NONET);
2770 }
2771 return(TRUE);
2772 }
2773 }
2774 }
2775 return(FALSE);
2776 }
2777
2778 /*
2779 * Routine to examine the hierarchy below cell "cell" and return TRUE if any of it is
2780 * parameterized.
2781 */
dr_quickfindparameters(NODEPROTO * cell)2782 BOOLEAN dr_quickfindparameters(NODEPROTO *cell)
2783 {
2784 REGISTER NODEINST *ni;
2785 REGISTER NODEPROTO *np;
2786 REGISTER CHECKPROTO *cp;
2787
2788 cp = (CHECKPROTO *)cell->temp1;
2789 if (cp->cellparameterized) return(TRUE);
2790 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2791 {
2792 np = ni->proto;
2793 if (np->primindex != 0) continue;
2794 if (isiconof(np, cell)) continue;
2795 if (dr_quickfindparameters(np)) return(TRUE);
2796 }
2797 return(FALSE);
2798 }
2799
2800 /*
2801 * Routine to determine whether node "ni" is a multiple cut contact.
2802 */
dr_quickismulticut(NODEINST * ni)2803 BOOLEAN dr_quickismulticut(NODEINST *ni)
2804 {
2805 REGISTER NODEPROTO *np;
2806 REGISTER TECHNOLOGY *tech;
2807 TECH_NODES *thistn;
2808 INTBIG fewer, cutcount;
2809 POLYLOOP mypl;
2810
2811 np = ni->proto;
2812 if (np->primindex == 0) return(FALSE);
2813 tech = np->tech;
2814 thistn = tech->nodeprotos[np->primindex-1];
2815 if (thistn->special != MULTICUT) return(FALSE);
2816 cutcount = tech_moscutcount(ni, thistn->f1, thistn->f2, thistn->f3, thistn->f4,
2817 &fewer, &mypl);
2818 if (cutcount > 1) return(TRUE);
2819 return(FALSE);
2820 }
2821
2822 /*
2823 * routine to tell whether the objects at geometry modules "geom1" and "geom2"
2824 * touch directly (that is, an arcinst connected to a nodeinst). The routine
2825 * returns true if they touch
2826 */
dr_quickobjtouch(GEOM * geom1,GEOM * geom2)2827 BOOLEAN dr_quickobjtouch(GEOM *geom1, GEOM *geom2)
2828 {
2829 REGISTER GEOM *temp;
2830 REGISTER NODEINST *ni;
2831 REGISTER ARCINST *ai;
2832 REGISTER INTBIG i;
2833
2834 if (geom1->entryisnode)
2835 {
2836 if (geom2->entryisnode) return(FALSE);
2837 temp = geom1; geom1 = geom2; geom2 = temp;
2838 }
2839 if (!geom2->entryisnode)
2840 return(FALSE);
2841
2842 /* see if the arcinst at "geom1" touches the nodeinst at "geom2" */
2843 ni = geom2->entryaddr.ni;
2844 ai = geom1->entryaddr.ai;
2845 for(i=0; i<2; i++)
2846 if (ai->end[i].nodeinst == ni)
2847 return(TRUE);
2848 return(FALSE);
2849 }
2850
2851 /*
2852 * Routine to find two points between polygons "poly1" and "poly2" that can be used to test
2853 * for notches. The points are returned in (xf1,yf1) and (xf2,yf2). Returns zero if no
2854 * points exist in the gap between the polygons (becuase they don't have common facing edges).
2855 * Returns 1 if only one of the reported points needs to be filled (because the polygons meet
2856 * at a point). Returns 2 if both reported points need to be filled.
2857 */
dr_quickfindinterveningpoints(POLYGON * poly1,POLYGON * poly2,INTBIG * xf1,INTBIG * yf1,INTBIG * xf2,INTBIG * yf2)2858 INTBIG dr_quickfindinterveningpoints(POLYGON *poly1, POLYGON *poly2, INTBIG *xf1, INTBIG *yf1,
2859 INTBIG *xf2, INTBIG *yf2)
2860 {
2861 REGISTER BOOLEAN isbox1, isbox2;
2862 INTBIG lx1, hx1, ly1, hy1, lx2, hx2, ly2, hy2;
2863 REGISTER INTBIG xc, yc;
2864
2865 isbox1 = isbox(poly1, &lx1, &hx1, &ly1, &hy1);
2866 isbox2 = isbox(poly2, &lx2, &hx2, &ly2, &hy2);
2867 if (isbox1 && isbox2)
2868 {
2869 /* handle vertical gap between polygons */
2870 if (lx1 > hx2 || lx2 > hx1)
2871 {
2872 /* see if the polygons are horizontally aligned */
2873 if (ly1 <= hy2 && ly2 <= hy1)
2874 {
2875 if (lx1 > hx2) *xf1 = *xf2 = (lx1 + hx2) / 2; else
2876 *xf1 = *xf2 = (lx2 + hx1) / 2;
2877 *yf1 = maxi(ly1, ly2);
2878 *yf2 = mini(hy1, hy2);
2879 return(2);
2880 }
2881 } else if (ly1 > hy2 || ly2 > hy1)
2882 {
2883 /* see if the polygons are horizontally aligned */
2884 if (lx1 <= hx2 && lx2 <= hx1)
2885 {
2886 if (ly1 > hy2) *yf1 = *yf2 = (ly1 + hy2) / 2; else
2887 *yf1 = *yf2 = (ly2 + hy1) / 2;
2888 *xf1 = maxi(lx1, lx2);
2889 *xf2 = mini(hx1, hx2);
2890 return(2);
2891 }
2892 } else if ((lx1 == hx2 || lx2 == hx1) || (ly1 == hy2 || ly2 == hy2))
2893 {
2894 /* handle touching at a point */
2895 if (lx1 == hx2) xc = lx1; else
2896 xc = lx2;
2897 if (ly1 == hy2) yc = ly1; else
2898 yc = ly2;
2899 *xf1 = xc + 1; *yf1 = yc + 1;
2900 *xf2 = xc - 1; *yf2 = yc - 1;
2901 if ((*xf1 < lx1 || *xf1 > hx1 || *yf1 < ly1 || *yf1 > hy1) &&
2902 (*xf1 < lx2 || *xf1 > hx2 || *yf1 < ly2 || *yf1 > hy2)) return(1);
2903 *xf1 = xc + 1; *yf1 = yc - 1;
2904 *xf2 = xc - 1; *yf2 = yc + 1;
2905 return(1);
2906 }
2907
2908 /* handle manhattan objects that are on a diagonal */
2909 if (lx1 > hx2)
2910 {
2911 if (ly1 > hy2)
2912 {
2913 *xf1 = lx1; *yf1 = ly1;
2914 *xf2 = hx2; *yf2 = hy2;
2915 return(1);
2916 }
2917 if (ly2 > hy1)
2918 {
2919 *xf1 = lx1; *yf1 = hy1;
2920 *xf2 = hx2; *yf2 = ly2;
2921 return(1);
2922 }
2923 }
2924 if (lx2 > hx1)
2925 {
2926 if (ly1 > hy2)
2927 {
2928 *xf1 = hx1; *yf1 = hy1;
2929 *xf2 = lx2; *yf2 = ly2;
2930 return(1);
2931 }
2932 if (ly2 > hy1)
2933 {
2934 *xf1 = hx1; *yf1 = ly1;
2935 *xf2 = lx2; *yf2 = hy2;
2936 return(1);
2937 }
2938 }
2939 }
2940
2941 /* boxes don't line up or this is a nonmanhattan situation */
2942 *xf1 = (lx1 + hx1) / 2; *yf1 = (ly2 + hy2) / 2;
2943 *xf2 = (lx2 + hx2) / 2; *yf2 = (ly1 + hy1) / 2;
2944 return(1);
2945 }
2946
2947 /*
2948 * Routine to explore the points (xf1,yf1) and (xf2,yf2) to see if there is
2949 * geometry on layer "layer" (in or below cell "cell"). Returns true if there is.
2950 * If "needboth" is true, both points must have geometry, otherwise only 1 needs it.
2951 */
dr_quicklookforpoints(INTBIG xf1,INTBIG yf1,INTBIG xf2,INTBIG yf2,INTBIG layer,NODEPROTO * cell,BOOLEAN needboth,CHECKSTATE * state)2952 BOOLEAN dr_quicklookforpoints(INTBIG xf1, INTBIG yf1, INTBIG xf2, INTBIG yf2,
2953 INTBIG layer, NODEPROTO *cell, BOOLEAN needboth, CHECKSTATE *state)
2954 {
2955 INTBIG xf3, yf3, flx, fhx, fly, fhy;
2956 BOOLEAN p1found, p2found, p3found, allfound;
2957
2958 xf3 = (xf1+xf2) / 2;
2959 yf3 = (yf1+yf2) / 2;
2960
2961 /* compute bounds for searching inside cells */
2962 flx = mini(xf1, xf2); fhx = maxi(xf1, xf2);
2963 fly = mini(yf1, yf2); fhy = maxi(yf1, yf2);
2964
2965 /* search the cell for geometry that fills the notch */
2966 p1found = p2found = p3found = FALSE;
2967 allfound = dr_quicklookforlayer(cell, layer, el_matid, state, flx, fhx, fly, fhy,
2968 xf1, yf1, &p1found, xf2, yf2, &p2found, xf3, yf3, &p3found);
2969 if (needboth)
2970 {
2971 if (allfound) return(TRUE);
2972 } else
2973 {
2974 if (p1found || p2found) return(TRUE);
2975 }
2976
2977 return(FALSE);
2978 }
2979
2980 /*
2981 * Routine to examine cell "cell" in the area (lx<=X<=hx, ly<=Y<=hy) for objects
2982 * on layer "layer". Apply transformation "moretrans" to the objects. If polygons are
2983 * found at (xf1,yf1) or (xf2,yf2) or (xf3,yf3) then sets "p1found/p2found/p3found" to 1.
2984 * If all locations are found, returns true.
2985 */
dr_quicklookforlayer(NODEPROTO * cell,INTBIG layer,XARRAY moretrans,CHECKSTATE * state,INTBIG lx,INTBIG hx,INTBIG ly,INTBIG hy,INTBIG xf1,INTBIG yf1,BOOLEAN * p1found,INTBIG xf2,INTBIG yf2,BOOLEAN * p2found,INTBIG xf3,INTBIG yf3,BOOLEAN * p3found)2986 BOOLEAN dr_quicklookforlayer(NODEPROTO *cell, INTBIG layer, XARRAY moretrans, CHECKSTATE *state,
2987 INTBIG lx, INTBIG hx, INTBIG ly, INTBIG hy, INTBIG xf1, INTBIG yf1, BOOLEAN *p1found,
2988 INTBIG xf2, INTBIG yf2, BOOLEAN *p2found, INTBIG xf3, INTBIG yf3, BOOLEAN *p3found)
2989 {
2990 REGISTER INTBIG sea, i, tot;
2991 REGISTER GEOM *g;
2992 REGISTER NODEINST *ni;
2993 REGISTER ARCINST *ai;
2994 REGISTER BOOLEAN reasonable;
2995 INTBIG newlx, newhx, newly, newhy;
2996 XARRAY trans, rot, bound;
2997 REGISTER POLYGON *poly;
2998
2999 sea = initsearch(lx, hx, ly, hy, cell);
3000 for(;;)
3001 {
3002 g = nextobject(sea);
3003 if (g == NOGEOM) break;
3004 if (g->entryisnode)
3005 {
3006 ni = g->entryaddr.ni;
3007 if (ni->proto->primindex == 0)
3008 {
3009 /* compute bounding area inside of sub-cell */
3010 makerotI(ni, rot);
3011 maketransI(ni, trans);
3012 transmult(rot, trans, bound);
3013 newlx = lx; newly = ly; newhx = hx; newhy = hy;
3014 xformbox(&newlx, &newhx, &newly, &newhy, bound);
3015
3016 /* compute new matrix for sub-cell examination */
3017 maketrans(ni, trans);
3018 makerot(ni, rot);
3019 transmult(trans, rot, bound);
3020 transmult(bound, moretrans, trans);
3021 if (dr_quicklookforlayer(ni->proto, layer, trans, state, newlx, newhx, newly, newhy,
3022 xf1, yf1, p1found, xf2, yf2, p2found, xf3, yf3, p3found))
3023 {
3024 termsearch(sea);
3025 return(TRUE);
3026 }
3027 continue;
3028 }
3029 makerot(ni, rot);
3030 transmult(rot, moretrans, bound);
3031 if ((dr_quickoptions&DRCREASONABLE) != 0) reasonable = TRUE; else reasonable = FALSE;
3032 tot = allnodepolys(ni, state->layerlookpolylist, NOWINDOWPART, reasonable);
3033 for(i=0; i<tot; i++)
3034 {
3035 poly = state->layerlookpolylist->polygons[i];
3036 if (!samelayer(poly->tech, poly->layer, layer)) continue;
3037 xformpoly(poly, bound);
3038 if (isinside(xf1, yf1, poly)) *p1found = TRUE;
3039 if (isinside(xf2, yf2, poly)) *p2found = TRUE;
3040 if (isinside(xf3, yf3, poly)) *p3found = TRUE;
3041 }
3042 } else
3043 {
3044 ai = g->entryaddr.ai;
3045 tot = allarcpolys(ai, state->layerlookpolylist, NOWINDOWPART);
3046 for(i=0; i<tot; i++)
3047 {
3048 poly = state->layerlookpolylist->polygons[i];
3049 if (!samelayer(poly->tech, poly->layer, layer)) continue;
3050 xformpoly(poly, moretrans);
3051 if (isinside(xf1, yf1, poly)) *p1found = TRUE;
3052 if (isinside(xf2, yf2, poly)) *p2found = TRUE;
3053 if (isinside(xf3, yf3, poly)) *p3found = TRUE;
3054 }
3055 }
3056 if (*p1found && *p2found && *p3found)
3057 {
3058 termsearch(sea);
3059 return(TRUE);
3060 }
3061 }
3062 return(FALSE);
3063 }
3064
3065 /*
3066 * routine to see if the two boxes are active elements, connected to opposite
3067 * sides of a field-effect transistor that resides inside of the box area.
3068 * Returns true if so.
3069 */
dr_quickactiveontransistor(POLYGON * poly1,INTBIG layer1,INTBIG net1,POLYGON * poly2,INTBIG layer2,INTBIG net2,TECHNOLOGY * tech,NODEPROTO * cell,INTBIG globalindex)3070 BOOLEAN dr_quickactiveontransistor(POLYGON *poly1, INTBIG layer1, INTBIG net1,
3071 POLYGON *poly2, INTBIG layer2, INTBIG net2, TECHNOLOGY *tech, NODEPROTO *cell, INTBIG globalindex)
3072 {
3073 REGISTER INTBIG blx, bhx, bly, bhy, fun;
3074 INTBIG lx1, hx1, ly1, hy1, lx2, hx2, ly2, hy2;
3075
3076 /* networks must be different */
3077 if (net1 == net2) return(FALSE);
3078
3079 /* layers must be active or active contact */
3080 fun = layerfunction(tech, layer1);
3081 if ((fun&LFTYPE) != LFDIFF)
3082 {
3083 if (!layeriscontact(fun) || (fun&LFCONDIFF) == 0) return(FALSE);
3084 }
3085 fun = layerfunction(tech, layer2);
3086 if ((fun&LFTYPE) != LFDIFF)
3087 {
3088 if (!layeriscontact(fun) || (fun&LFCONDIFF) == 0) return(FALSE);
3089 }
3090
3091 /* search for intervening transistor in the cell */
3092 getbbox(poly1, &lx1, &hx1, &ly1, &hy1);
3093 getbbox(poly2, &lx2, &hx2, &ly2, &hy2);
3094 blx = mini(lx1,lx2); bhx = maxi(hx1,hx2);
3095 bly = mini(ly1,ly2); bhy = maxi(hy1,hy2);
3096 return(dr_quickactiveontransistorrecurse(blx, bhx, bly, bhy, net1, net2, cell, globalindex, el_matid));
3097 }
3098
dr_quickactiveontransistorrecurse(INTBIG blx,INTBIG bhx,INTBIG bly,INTBIG bhy,INTBIG net1,INTBIG net2,NODEPROTO * cell,INTBIG globalindex,XARRAY trans)3099 BOOLEAN dr_quickactiveontransistorrecurse(INTBIG blx, INTBIG bhx, INTBIG bly, INTBIG bhy,
3100 INTBIG net1, INTBIG net2, NODEPROTO *cell, INTBIG globalindex, XARRAY trans)
3101 {
3102 REGISTER INTBIG sea, net, cx, cy, localindex;
3103 REGISTER BOOLEAN on1, on2, ret;
3104 REGISTER GEOM *g;
3105 REGISTER NODEINST *ni;
3106 REGISTER NODEPROTO *np;
3107 REGISTER PORTPROTO *badport;
3108 REGISTER PORTARCINST *pi;
3109 INTBIG slx, shx, sly, shy;
3110 XARRAY rtrans, ttrans, temptrans;
3111 REGISTER CHECKINST *ci;
3112
3113 sea = initsearch(blx, bhx, bly, bhy, cell);
3114 if (sea < 0) return(FALSE);
3115 for(;;)
3116 {
3117 g = nextobject(sea);
3118 if (g == NOGEOM) break;
3119 if (!g->entryisnode) continue;
3120 ni = g->entryaddr.ni;
3121 np = ni->proto;
3122 if (np->primindex == 0)
3123 {
3124 makerotI(ni, rtrans);
3125 maketransI(ni, ttrans);
3126 transmult(rtrans, ttrans, temptrans);
3127 slx = blx; shx = bhx;
3128 sly = bly; shy = bhy;
3129 xformbox(&slx, &shx, &sly, ­, temptrans);
3130
3131 ci = (CHECKINST *)ni->temp1;
3132 localindex = globalindex * ci->multiplier + ci->localindex + ci->offset;
3133
3134 if (!dr_quickparalleldrc) downhierarchy(ni, np, 0);
3135 ret = dr_quickactiveontransistorrecurse(slx, shx, sly, shy,
3136 net1, net2, np, localindex, trans);
3137 if (!dr_quickparalleldrc) uphierarchy();
3138 if (ret)
3139 {
3140 termsearch(sea);
3141 return(TRUE);
3142 }
3143 continue;
3144 }
3145
3146 /* must be a transistor */
3147 if (!isfet(g)) continue;
3148
3149 /* must be inside of the bounding box of the desired layers */
3150 cx = (ni->geom->lowx + ni->geom->highx) / 2;
3151 cy = (ni->geom->lowy + ni->geom->highy) / 2;
3152 if (cx < blx || cx > bhx || cy < bly || cy > bhy) continue;
3153
3154 /* determine the poly port */
3155 badport = ni->proto->firstportproto;
3156
3157 on1 = on2 = FALSE;
3158 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
3159 {
3160 /* ignore connections on poly/gate */
3161 if (pi->proto->network == badport->network) continue;
3162
3163 net = ((INTBIG *)pi->conarcinst->network->temp1)[globalindex];
3164 if (net == NONET) continue;
3165 if (net == net1) on1 = TRUE;
3166 if (net == net2) on2 = TRUE;
3167 }
3168
3169 /* if either side is not connected, ignore this */
3170 if (!on1 || !on2) continue;
3171
3172 /* transistor found that connects to both actives */
3173 termsearch(sea);
3174 return(TRUE);
3175 }
3176 return(FALSE);
3177 }
3178
3179 /*
3180 * routine to crop the box in the reference parameters (lx-hx, ly-hy)
3181 * against the box in (bx-ux, by-uy). If the box is cropped into oblivion,
3182 * the routine returns 1. If the boxes overlap but cannot be cleanly cropped,
3183 * the routine returns -1. Otherwise the box is cropped and zero is returned
3184 */
dr_quickcropbox(INTBIG * lx,INTBIG * hx,INTBIG * ly,INTBIG * hy,INTBIG bx,INTBIG ux,INTBIG by,INTBIG uy,INTBIG nlx,INTBIG nhx,INTBIG nly,INTBIG nhy)3185 INTBIG dr_quickcropbox(INTBIG *lx, INTBIG *hx, INTBIG *ly, INTBIG *hy, INTBIG bx, INTBIG ux, INTBIG by,
3186 INTBIG uy, INTBIG nlx, INTBIG nhx, INTBIG nly, INTBIG nhy)
3187 {
3188 REGISTER INTBIG xoverlap, yoverlap;
3189
3190 /* if the two boxes don't touch, just return */
3191 if (bx >= *hx || by >= *hy || ux <= *lx || uy <= *ly) return(0);
3192
3193 /* if the box to be cropped is within the other, say so */
3194 if (bx <= *lx && ux >= *hx && by <= *ly && uy >= *hy) return(1);
3195
3196 /* see which direction is being cropped */
3197 xoverlap = mini(*hx, ux) - maxi(*lx, bx);
3198 yoverlap = mini(*hy, uy) - maxi(*ly, by);
3199 if (xoverlap > yoverlap)
3200 {
3201 /* one above the other: crop in Y */
3202 if (bx <= *lx && ux >= *hx)
3203 {
3204 /* it covers in X...do the crop */
3205 if (uy >= *hy) *hy = by;
3206 if (by <= *ly) *ly = uy;
3207 if (*hy <= *ly) return(1);
3208 return(0);
3209 }
3210 } else
3211 {
3212 /* one next to the other: crop in X */
3213 if (by <= *ly && uy >= *hy)
3214 {
3215 /* it covers in Y...crop in X */
3216 if (ux >= *hx) *hx = bx;
3217 if (bx <= *lx) *lx = ux;
3218 if (*hx <= *lx) return(1);
3219 return(0);
3220 }
3221 }
3222 return(-1);
3223 }
3224
3225 /*
3226 * routine to crop the box in the reference parameters (lx-hx, ly-hy)
3227 * against the box in (bx-ux, by-uy). If the box is cropped into oblivion,
3228 * the routine returns 1. If the boxes overlap but cannot be cleanly cropped,
3229 * the routine returns -1. Otherwise the box is cropped and zero is returned
3230 */
dr_quickhalfcropbox(INTBIG * lx,INTBIG * hx,INTBIG * ly,INTBIG * hy,INTBIG bx,INTBIG ux,INTBIG by,INTBIG uy)3231 INTBIG dr_quickhalfcropbox(INTBIG *lx, INTBIG *hx, INTBIG *ly, INTBIG *hy,
3232 INTBIG bx, INTBIG ux, INTBIG by, INTBIG uy)
3233 {
3234 REGISTER BOOLEAN crops;
3235 REGISTER INTBIG lxe, hxe, lye, hye, biggestext;
3236
3237 /* if the two boxes don't touch, just return */
3238 if (bx >= *hx || by >= *hy || ux <= *lx || uy <= *ly) return(0);
3239
3240 /* if the box to be cropped is within the other, figure out which half to remove */
3241 if (bx <= *lx && ux >= *hx && by <= *ly && uy >= *hy)
3242 {
3243 lxe = *lx - bx; hxe = ux - *hx;
3244 lye = *ly - by; hye = uy - *hy;
3245 biggestext = maxi(maxi(lxe, hxe), maxi(lye, hye));
3246 if (biggestext == 0) return(1);
3247 if (lxe == biggestext)
3248 {
3249 *lx = (*lx + ux) / 2;
3250 if (*lx >= *hx) return(1);
3251 return(0);
3252 }
3253 if (hxe == biggestext)
3254 {
3255 *hx = (*hx + bx) / 2;
3256 if (*hx <= *lx) return(1);
3257 return(0);
3258 }
3259 if (lye == biggestext)
3260 {
3261 *ly = (*ly + uy) / 2;
3262 if (*ly >= *hy) return(1);
3263 return(0);
3264 }
3265 if (hye == biggestext)
3266 {
3267 *hy = (*hy + by) / 2;
3268 if (*hy <= *ly) return(1);
3269 return(0);
3270 }
3271 }
3272
3273 /* reduce (lx-hx,ly-hy) by (bx-ux,by-uy) */
3274 crops = FALSE;
3275 if (bx <= *lx && ux >= *hx)
3276 {
3277 /* it covers in X...crop in Y */
3278 if (uy >= *hy) *hy = (*hy + by) / 2;
3279 if (by <= *ly) *ly = (*ly + uy) / 2;
3280 crops = TRUE;
3281 }
3282 if (by <= *ly && uy >= *hy)
3283 {
3284 /* it covers in Y...crop in X */
3285 if (ux >= *hx) *hx = (*hx + bx) / 2;
3286 if (bx <= *lx) *lx = (*lx + ux) / 2;
3287 crops = TRUE;
3288 }
3289 if (!crops) return(-1);
3290 return(0);
3291 }
3292
3293 /*
3294 * routine to crop the box on layer "nlayer", electrical index "nnet"
3295 * and bounds (lx-hx, ly-hy) against the nodeinst "ni". The geometry in nodeinst "ni"
3296 * that is being checked runs from (nlx-nhx, nly-nhy). Only those layers
3297 * in the nodeinst that are the same layer and the same electrical network
3298 * are checked. The routine returns true if the bounds are reduced
3299 * to nothing.
3300 */
dr_quickcropnodeinst(NODEINST * ni,INTBIG globalindex,CHECKSTATE * state,XARRAY trans,INTBIG nlx,INTBIG nhx,INTBIG nly,INTBIG nhy,INTBIG nlayer,INTBIG nnet,GEOM * ngeom,INTBIG * lx,INTBIG * hx,INTBIG * ly,INTBIG * hy)3301 BOOLEAN dr_quickcropnodeinst(NODEINST *ni, INTBIG globalindex, CHECKSTATE *state,
3302 XARRAY trans, INTBIG nlx, INTBIG nhx, INTBIG nly, INTBIG nhy,
3303 INTBIG nlayer, INTBIG nnet, GEOM *ngeom, INTBIG *lx, INTBIG *hx, INTBIG *ly, INTBIG *hy)
3304 {
3305 INTBIG xl, xh, yl, yh;
3306 REGISTER INTBIG tot, j, isconnected, net;
3307 REGISTER BOOLEAN allgone;
3308 REGISTER INTBIG temp;
3309 REGISTER POLYGON *poly;
3310
3311 dr_quickgetnodeEpolys(ni, state->cropnodepolylist, trans);
3312 tot = state->cropnodepolylist->polylistcount;
3313 if (tot < 0) return(FALSE);
3314 isconnected = 0;
3315 for(j=0; j<tot; j++)
3316 {
3317 poly = state->cropnodepolylist->polygons[j];
3318 if (!samelayer(poly->tech, poly->layer, nlayer)) continue;
3319 if (nnet != NONET)
3320 {
3321 if (poly->portproto == NOPORTPROTO) continue;
3322
3323 /* determine network for this polygon */
3324 net = dr_quickgetnetnumber(poly->portproto, ni, globalindex);
3325 if (net != NONET && net != nnet) continue;
3326 }
3327 isconnected++;
3328 break;
3329 }
3330 if (isconnected == 0) return(FALSE);
3331
3332 /* get the description of the nodeinst layers */
3333 allgone = FALSE;
3334 dr_quickgetnodepolys(ni, state->cropnodepolylist, trans);
3335 tot = state->cropnodepolylist->polylistcount;
3336 if (tot < 0) return(FALSE);
3337
3338 if (gettrace(ni) != NOVARIABLE)
3339 {
3340 /* node is defined with an outline: use advanced methods to crop */
3341 void *merge;
3342
3343 merge = mergenew(dr_tool->cluster);
3344 makerectpoly(*lx, *hx, *ly, *hy, state->checkdistpoly1rebuild);
3345 mergeaddpolygon(merge, nlayer, el_curtech, state->checkdistpoly1rebuild);
3346 for(j=0; j<tot; j++)
3347 {
3348 poly = state->cropnodepolylist->polygons[j];
3349 if (!samelayer(poly->tech, poly->layer, nlayer)) continue;
3350 mergesubpolygon(merge, nlayer, el_curtech, poly);
3351 }
3352 if (!mergebbox(merge, lx, hx, ly, hy))
3353 allgone = TRUE;
3354 mergedelete(merge);
3355 } else
3356 {
3357 for(j=0; j<tot; j++)
3358 {
3359 poly = state->cropnodepolylist->polygons[j];
3360 if (!samelayer(poly->tech, poly->layer, nlayer)) continue;
3361
3362 /* warning: does not handle arbitrary polygons, only boxes */
3363 if (!isbox(poly, &xl, &xh, &yl, &yh)) continue;
3364 temp = dr_quickcropbox(lx, hx, ly, hy, xl, xh, yl, yh, nlx, nhx, nly, nhy);
3365 if (temp > 0) { allgone = TRUE; break; }
3366 if (temp < 0)
3367 {
3368 state->tinynodeinst = ni;
3369 state->tinyobj = ngeom;
3370 }
3371 }
3372 }
3373 return(allgone);
3374 }
3375
3376 /*
3377 * routine to crop away any part of layer "lay" of arcinst "ai" that coincides
3378 * with a similar layer on a connecting nodeinst. The bounds of the arcinst
3379 * are in the reference parameters (lx-hx, ly-hy). The routine returns false
3380 * normally, 1 if the arcinst is cropped into oblivion.
3381 */
dr_quickcroparcinst(ARCINST * ai,INTBIG lay,XARRAY transin,INTBIG * lx,INTBIG * hx,INTBIG * ly,INTBIG * hy,CHECKSTATE * state)3382 BOOLEAN dr_quickcroparcinst(ARCINST *ai, INTBIG lay, XARRAY transin, INTBIG *lx, INTBIG *hx, INTBIG *ly, INTBIG *hy, CHECKSTATE *state)
3383 {
3384 INTBIG xl, xh, yl, yh;
3385 XARRAY trans, ttrans, rtrans, xtemp;
3386 REGISTER INTBIG i, j, tot;
3387 REGISTER INTBIG temp;
3388 REGISTER NODEINST *ni;
3389 REGISTER NODEPROTO *np;
3390 REGISTER PORTPROTO *pp;
3391 REGISTER POLYGON *poly;
3392
3393 for(i=0; i<2; i++)
3394 {
3395 /* find the primitive nodeinst at the true end of the portinst */
3396 ni = ai->end[i].nodeinst; np = ni->proto;
3397 pp = ai->end[i].portarcinst->proto;
3398 makerot(ni, xtemp);
3399 transmult(xtemp, transin, trans);
3400 while (np->primindex == 0)
3401 {
3402 maketrans(ni, ttrans);
3403 transmult(ttrans, trans, xtemp);
3404 ni = pp->subnodeinst; np = ni->proto;
3405 pp = pp->subportproto;
3406 makerot(ni, rtrans);
3407 transmult(rtrans, xtemp, trans);
3408 }
3409 dr_quickgetnodepolys(ni, state->croparcpolylist, trans);
3410 tot = state->croparcpolylist->polylistcount;
3411 for(j=0; j<tot; j++)
3412 {
3413 poly = state->croparcpolylist->polygons[j];
3414 if (!samelayer(poly->tech, poly->layer, lay)) continue;
3415
3416 /* warning: does not handle arbitrary polygons, only boxes */
3417 if (!isbox(poly, &xl, &xh, &yl, &yh)) continue;
3418 temp = dr_quickhalfcropbox(lx, hx, ly, hy, xl, xh, yl, yh);
3419 if (temp > 0) return(TRUE);
3420 if (temp < 0)
3421 {
3422 state->tinynodeinst = ni;
3423 state->tinyobj = ai->geom;
3424 }
3425 }
3426 }
3427 return(FALSE);
3428 }
3429
3430 /*
3431 * routine to see if polygons in "plist" (describing arc "ai") should be cropped against a
3432 * connecting transistor. Crops the polygon if so.
3433 */
dr_quickcropactivearc(ARCINST * ai,POLYLIST * plist,CHECKSTATE * state)3434 void dr_quickcropactivearc(ARCINST *ai, POLYLIST *plist, CHECKSTATE *state)
3435 {
3436 REGISTER INTBIG i, j, k, fun, tot, ntot;
3437 INTBIG lx, hx, ly, hy, nlx, nhx, nly, nhy;
3438 REGISTER NODEINST *ni;
3439 REGISTER POLYGON *poly, *npoly, *swappoly;
3440 REGISTER BOOLEAN cropped;
3441 XARRAY trans;
3442
3443 /* look for an active layer in this arc */
3444 tot = plist->polylistcount;
3445 for(j=0; j<tot; j++)
3446 {
3447 poly = plist->polygons[j];
3448 fun = layerfunction(poly->tech, poly->layer);
3449 if ((fun&LFTYPE) == LFDIFF) break;
3450 }
3451 if (j >= tot) return;
3452
3453 /* must be manhattan */
3454 if (!isbox(poly, &lx, &hx, &ly, &hy)) return;
3455
3456 /* search for adjoining transistor in the cell */
3457 cropped = FALSE;
3458 for(i=0; i<2; i++)
3459 {
3460 ni = ai->end[i].nodeinst;
3461 if (!isfet(ni->geom)) continue;
3462
3463 /* crop the arc against this transistor */
3464 makerot(ni, trans);
3465 dr_quickgetnodepolys(ni, state->activecroppolylist, trans);
3466 ntot = state->activecroppolylist->polylistcount;
3467 for(k=0; k<ntot; k++)
3468 {
3469 npoly = state->activecroppolylist->polygons[k];
3470 if (npoly->tech != poly->tech || npoly->layer != poly->layer) continue;
3471 if (!isbox(npoly, &nlx, &nhx, &nly, &nhy)) continue;
3472 if (dr_quickhalfcropbox(&lx, &hx, &ly, &hy, nlx, nhx, nly, nhy) == 1)
3473 {
3474 /* remove this polygon from consideration */
3475 swappoly = plist->polygons[j];
3476 plist->polygons[j] = plist->polygons[tot-1];
3477 plist->polygons[tot-1] = swappoly;
3478 plist->polylistcount--;
3479 return;
3480 }
3481 cropped = TRUE;
3482 }
3483 }
3484 if (cropped) makerectpoly(lx, hx, ly, hy, poly);
3485 }
3486
3487 /*
3488 * These routines get all the polygons in a primitive instance, and
3489 * store them in the POLYLIST structure.
3490 */
dr_quickgetnodeEpolys(NODEINST * ni,POLYLIST * plist,XARRAY trans)3491 void dr_quickgetnodeEpolys(NODEINST *ni, POLYLIST *plist, XARRAY trans)
3492 {
3493 REGISTER INTBIG j;
3494 BOOLEAN convertpseudo, onlyreasonable;
3495 REGISTER POLYGON *poly;
3496
3497 convertpseudo = FALSE;
3498 if (((ni->proto->userbits&NFUNCTION) >> NFUNCTIONSH) == NPPIN)
3499 {
3500 if (ni->firstportarcinst == NOPORTARCINST &&
3501 ni->firstportexpinst != NOPORTEXPINST)
3502 convertpseudo = TRUE;
3503 }
3504 if ((dr_quickoptions&DRCREASONABLE) != 0) onlyreasonable = TRUE; else
3505 onlyreasonable = FALSE;
3506 plist->polylistcount = allnodeEpolys(ni, plist, NOWINDOWPART, onlyreasonable);
3507 for(j = 0; j < plist->polylistcount; j++)
3508 {
3509 poly = plist->polygons[j];
3510 xformpoly(poly, trans);
3511 getbbox(poly, &plist->lx[j], &plist->hx[j], &plist->ly[j], &plist->hy[j]);
3512 if (convertpseudo)
3513 poly->layer = nonpseudolayer(poly->layer, poly->tech);
3514 }
3515 }
3516
dr_quickgetnodepolys(NODEINST * ni,POLYLIST * plist,XARRAY trans)3517 void dr_quickgetnodepolys(NODEINST *ni, POLYLIST *plist, XARRAY trans)
3518 {
3519 REGISTER INTBIG j;
3520 REGISTER POLYGON *poly;
3521 BOOLEAN onlyreasonable;
3522
3523 if ((dr_quickoptions&DRCREASONABLE) != 0) onlyreasonable = TRUE; else
3524 onlyreasonable = FALSE;
3525 plist->polylistcount = allnodepolys(ni, plist, NOWINDOWPART, onlyreasonable);
3526 for(j = 0; j < plist->polylistcount; j++)
3527 {
3528 poly = plist->polygons[j];
3529 xformpoly(poly, trans);
3530 getbbox(poly, &plist->lx[j], &plist->hx[j], &plist->ly[j], &plist->hy[j]);
3531 }
3532 }
3533
dr_quickgetarcpolys(ARCINST * ai,POLYLIST * plist,XARRAY trans)3534 void dr_quickgetarcpolys(ARCINST *ai, POLYLIST *plist, XARRAY trans)
3535 {
3536 REGISTER INTBIG j;
3537 REGISTER POLYGON *poly;
3538
3539 plist->polylistcount = allarcpolys(ai, plist, NOWINDOWPART);
3540 for(j = 0; j < plist->polylistcount; j++)
3541 {
3542 poly = plist->polygons[j];
3543 xformpoly(poly, trans);
3544 getbbox(poly, &plist->lx[j], &plist->hx[j], &plist->ly[j], &plist->hy[j]);
3545 }
3546 }
3547
dr_cachevalidlayers(TECHNOLOGY * tech)3548 void dr_cachevalidlayers(TECHNOLOGY *tech)
3549 {
3550 REGISTER NODEPROTO *np;
3551 REGISTER NODEINST *ni;
3552 REGISTER ARCPROTO *ap;
3553 REGISTER ARCINST *ai;
3554 REGISTER INTBIG i, tot;
3555 NODEINST node;
3556 ARCINST arc;
3557 REGISTER POLYGON *poly;
3558
3559 if (tech == NOTECHNOLOGY) return;
3560 if (dr_curtech == tech) return;
3561
3562 /* code cannot be called by multiple procesors: uses globals */
3563 NOT_REENTRANT;
3564
3565 dr_curtech = tech;
3566
3567 /* determine the layers that are being used */
3568 if (tech->layercount > dr_layertotal)
3569 {
3570 if (dr_layertotal > 0)
3571 efree((CHAR *)dr_layersvalid);
3572 dr_layertotal = 0;
3573 dr_layersvalid = (BOOLEAN *)emalloc(tech->layercount * (sizeof (BOOLEAN)), dr_tool->cluster);
3574 dr_layertotal = tech->layercount;
3575 }
3576 for(i=0; i < tech->layercount; i++)
3577 dr_layersvalid[i] = FALSE;
3578 poly = allocpolygon(4, dr_tool->cluster);
3579 for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
3580 {
3581 if ((np->userbits&NNOTUSED) != 0) continue;
3582 ni = &node; initdummynode(ni);
3583 ni->proto = np;
3584 ni->lowx = np->lowx;
3585 ni->highx = np->highx;
3586 ni->lowy = np->lowy;
3587 ni->highy = np->highy;
3588 tot = nodepolys(ni, 0, NOWINDOWPART);
3589 for(i=0; i<tot; i++)
3590 {
3591 shapenodepoly(ni, i, poly);
3592 if (poly->tech != tech) continue;
3593 dr_layersvalid[poly->layer] = TRUE;
3594 }
3595 }
3596 for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
3597 {
3598 if ((ap->userbits&ANOTUSED) != 0) continue;
3599 ai = &arc; initdummyarc(ai);
3600 ai->proto = ap;
3601 ai->end[0].xpos = 0; ai->end[0].ypos = 0;
3602 ai->end[1].xpos = 10000; ai->end[0].ypos = 0;
3603 ai->width = ap->nominalwidth;
3604 tot = arcpolys(ai, NOWINDOWPART);
3605 for(i=0; i<tot; i++)
3606 {
3607 shapearcpoly(ai, i, poly);
3608 if (poly->tech != tech) continue;
3609 dr_layersvalid[poly->layer] = TRUE;
3610 }
3611 }
3612 freepolygon(poly);
3613 }
3614
3615 /*
3616 * Routine to determine the minimum distance between "layer1" and "layer2" in technology
3617 * "tech" and library "lib". If "con" is true, the layers are connected. Also forces
3618 * connectivity for same-implant layers.
3619 */
dr_adjustedmindist(TECHNOLOGY * tech,LIBRARY * lib,INTBIG layer1,INTBIG size1,INTBIG layer2,INTBIG size2,BOOLEAN con,BOOLEAN multi,INTBIG * edge,CHAR ** rule)3620 INTBIG dr_adjustedmindist(TECHNOLOGY *tech, LIBRARY *lib, INTBIG layer1, INTBIG size1,
3621 INTBIG layer2, INTBIG size2, BOOLEAN con, BOOLEAN multi, INTBIG *edge, CHAR **rule)
3622 {
3623 INTBIG dist, fun;
3624
3625 /* if they are implant on the same layer, they connect */
3626 if (!con && layer1 == layer2)
3627 {
3628 fun = layerfunction(tech, layer1) & LFTYPE;
3629 /* treat all wells as connected */
3630 if (!con)
3631 {
3632 if (fun == LFSUBSTRATE || fun == LFWELL || fun == LFIMPLANT) con = TRUE;
3633 }
3634 }
3635
3636 /* see how close they can get */
3637 dist = drcmindistance(tech, lib, layer1, size1, layer2, size2, con, multi, edge, rule);
3638 return(dist);
3639 }
3640
3641 /*
3642 * Routine to return the network number for port "pp" on node "ni", given that the node is
3643 * in a cell with global index "globalindex".
3644 */
dr_quickgetnetnumber(PORTPROTO * pp,NODEINST * ni,INTBIG globalindex)3645 INTBIG dr_quickgetnetnumber(PORTPROTO *pp, NODEINST *ni, INTBIG globalindex)
3646 {
3647 REGISTER PORTARCINST *pi;
3648 REGISTER PORTEXPINST *pe;
3649 REGISTER INTBIG netnumber;
3650
3651 if (pp == NOPORTPROTO) return(-1);
3652
3653 /* see if there is an arc connected */
3654 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
3655 if (pi->proto->network == pp->network)
3656 return(((INTBIG *)pi->conarcinst->network->temp1)[globalindex]);
3657
3658 /* see if there is an export connected */
3659 for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
3660 if (pe->proto->network == pp->network)
3661 return(((INTBIG *)pe->exportproto->network->temp1)[globalindex]);
3662
3663 /* generate a new unique network number */
3664 netnumber = dr_quickcheckunconnetnumber++;
3665 if (dr_quickcheckunconnetnumber < dr_quickchecknetnumber)
3666 dr_quickcheckunconnetnumber = dr_quickchecknetnumber;
3667 return(netnumber);
3668 }
3669
3670 /***************** LAYER INTERACTIONS ******************/
3671
3672 /*
3673 * Routine to build the internal data structures that tell which layers interact with
3674 * which primitive nodes in technology "tech".
3675 */
dr_quickbuildlayerinteractions(TECHNOLOGY * tech)3676 void dr_quickbuildlayerinteractions(TECHNOLOGY *tech)
3677 {
3678 REGISTER INTBIG i, tot, index, tablesize, dist, layer;
3679 INTBIG edge;
3680 REGISTER NODEPROTO *np;
3681 REGISTER NODEINST *ni;
3682 REGISTER ARCPROTO *ap;
3683 REGISTER ARCINST *ai;
3684 NODEINST node;
3685 ARCINST arc;
3686 REGISTER POLYGON *poly;
3687
3688 /* code cannot be called by multiple procesors: uses globals */
3689 NOT_REENTRANT;
3690
3691 dr_quicklayerintertech = tech;
3692
3693 /* build the node table */
3694 tablesize = pickprime(tech->nodeprotocount * 2);
3695 if (tablesize > dr_quicklayerinternodehashsize)
3696 {
3697 if (dr_quicklayerinternodehashsize > 0)
3698 {
3699 for(i=0; i<dr_quicklayerinternodehashsize; i++)
3700 if (dr_quicklayerinternodetable[i] != 0)
3701 efree((CHAR *)dr_quicklayerinternodetable[i]);
3702 efree((CHAR *)dr_quicklayerinternodetable);
3703 efree((CHAR *)dr_quicklayerinternodehash);
3704 }
3705 dr_quicklayerinternodehashsize = 0;
3706 dr_quicklayerinternodehash = (NODEPROTO **)emalloc(tablesize * (sizeof (NODEPROTO *)),
3707 dr_tool->cluster);
3708 if (dr_quicklayerinternodehash == 0) return;
3709 dr_quicklayerinternodetable = (BOOLEAN **)emalloc(tablesize * (sizeof (BOOLEAN *)),
3710 dr_tool->cluster);
3711 if (dr_quicklayerinternodetable == 0) return;
3712 dr_quicklayerinternodehashsize = tablesize;
3713 }
3714 for(i=0; i<dr_quicklayerinternodehashsize; i++)
3715 {
3716 dr_quicklayerinternodehash[i] = NONODEPROTO;
3717 dr_quicklayerinternodetable[i] = 0;
3718 }
3719
3720 poly = allocpolygon(4, dr_tool->cluster);
3721 for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
3722 {
3723 index = abs(((INTBIG)np) % dr_quicklayerinternodehashsize);
3724 for(i=0; i<dr_quicklayerinternodehashsize; i++)
3725 {
3726 if (dr_quicklayerinternodehash[index] == NONODEPROTO) break;
3727 index++;
3728 if (index >= dr_quicklayerinternodehashsize) index = 0;
3729 }
3730 dr_quicklayerinternodehash[index] = np;
3731 dr_quicklayerinternodetable[index] = (BOOLEAN *)emalloc(tech->layercount * (sizeof (BOOLEAN)),
3732 dr_tool->cluster);
3733 for(i=0; i<tech->layercount; i++) dr_quicklayerinternodetable[index][i] = FALSE;
3734
3735 /* fill in the layers that interact with this node */
3736 ni = &node; initdummynode(ni);
3737 ni->proto = np;
3738 ni->lowx = np->lowx;
3739 ni->highx = np->highx;
3740 ni->lowy = np->lowy;
3741 ni->highy = np->highy;
3742 tot = nodepolys(ni, 0, NOWINDOWPART);
3743 for(i=0; i<tot; i++)
3744 {
3745 shapenodepoly(ni, i, poly);
3746 if (poly->tech != tech) continue;
3747 for(layer = 0; layer < tech->layercount; layer++)
3748 {
3749 dist = drcmindistance(tech, el_curlib, layer, K1, poly->layer, K1,
3750 FALSE, FALSE, &edge, 0);
3751 if (dist < 0) continue;
3752 dr_quicklayerinternodetable[index][layer] = TRUE;
3753 }
3754 }
3755 }
3756
3757 /* build the arc table */
3758 tablesize = pickprime(tech->arcprotocount * 2);
3759 if (tablesize > dr_quicklayerinterarchashsize)
3760 {
3761 if (dr_quicklayerinterarchashsize > 0)
3762 {
3763 for(i=0; i<dr_quicklayerinterarchashsize; i++)
3764 if (dr_quicklayerinterarctable[i] != 0)
3765 efree((CHAR *)dr_quicklayerinterarctable[i]);
3766 efree((CHAR *)dr_quicklayerinterarctable);
3767 efree((CHAR *)dr_quicklayerinterarchash);
3768 }
3769 dr_quicklayerinterarchashsize = 0;
3770 dr_quicklayerinterarchash = (ARCPROTO **)emalloc(tablesize * (sizeof (ARCPROTO *)),
3771 dr_tool->cluster);
3772 if (dr_quicklayerinterarchash == 0) return;
3773 dr_quicklayerinterarctable = (BOOLEAN **)emalloc(tablesize * (sizeof (BOOLEAN *)),
3774 dr_tool->cluster);
3775 if (dr_quicklayerinterarctable == 0) return;
3776 dr_quicklayerinterarchashsize = tablesize;
3777 }
3778 for(i=0; i<dr_quicklayerinterarchashsize; i++)
3779 {
3780 dr_quicklayerinterarchash[i] = NOARCPROTO;
3781 dr_quicklayerinterarctable[i] = 0;
3782 }
3783
3784 for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
3785 {
3786 index = abs(((INTBIG)ap) % dr_quicklayerinterarchashsize);
3787 for(i=0; i<dr_quicklayerinterarchashsize; i++)
3788 {
3789 if (dr_quicklayerinterarchash[index] == NOARCPROTO) break;
3790 index++;
3791 if (index >= dr_quicklayerinterarchashsize) index = 0;
3792 }
3793 dr_quicklayerinterarchash[index] = ap;
3794 dr_quicklayerinterarctable[index] = (BOOLEAN *)emalloc(tech->layercount * (sizeof (BOOLEAN)),
3795 dr_tool->cluster);
3796 for(i=0; i<tech->layercount; i++) dr_quicklayerinterarctable[index][i] = FALSE;
3797
3798 /* fill in the layers that interact with this arc */
3799 ai = &arc; initdummyarc(ai);
3800 ai->proto = ap;
3801 ai->end[0].xpos = 0; ai->end[0].ypos = 0;
3802 ai->end[1].xpos = 10000; ai->end[0].ypos = 0;
3803 ai->width = ap->nominalwidth;
3804 tot = arcpolys(ai, NOWINDOWPART);
3805 for(i=0; i<tot; i++)
3806 {
3807 shapearcpoly(ai, i, poly);
3808 if (poly->tech != tech) continue;
3809 for(layer = 0; layer < tech->layercount; layer++)
3810 {
3811 dist = drcmindistance(tech, el_curlib, layer, K1, poly->layer, K1,
3812 FALSE, FALSE, &edge, 0);
3813 if (dist < 0) continue;
3814 dr_quicklayerinterarctable[index][layer] = TRUE;
3815 }
3816 }
3817 }
3818 freepolygon(poly);
3819 }
3820
3821 /*
3822 * Routine to determine whether layer "layer" interacts in any way with a node of type "np".
3823 * If not, returns FALSE.
3824 */
dr_quickchecklayerwithnode(INTBIG layer,NODEPROTO * np)3825 BOOLEAN dr_quickchecklayerwithnode(INTBIG layer, NODEPROTO *np)
3826 {
3827 REGISTER INTBIG index, i;
3828
3829 if (np->primindex == 0) return(FALSE);
3830 if (np->tech != dr_quicklayerintertech)
3831 {
3832 dr_quickbuildlayerinteractions(np->tech);
3833 }
3834 if (dr_quicklayerinternodehashsize <= 0) return(TRUE);
3835
3836 /* find this node in the table */
3837 index = abs(((INTBIG)np) % dr_quicklayerinternodehashsize);
3838 for(i=0; i<dr_quicklayerinternodehashsize; i++)
3839 {
3840 if (dr_quicklayerinternodehash[index] == np) break;
3841 index++;
3842 if (index >= dr_quicklayerinternodehashsize) index = 0;
3843 }
3844 if (i >= dr_quicklayerinternodehashsize) return(FALSE);
3845 return(dr_quicklayerinternodetable[index][layer]);
3846 }
3847
3848 /*
3849 * Routine to determine whether layer "layer" interacts in any way with an arc of type "ap".
3850 * If not, returns FALSE.
3851 */
dr_quickchecklayerwitharc(INTBIG layer,ARCPROTO * ap)3852 BOOLEAN dr_quickchecklayerwitharc(INTBIG layer, ARCPROTO *ap)
3853 {
3854 REGISTER INTBIG index, i;
3855
3856 if (ap->tech != dr_quicklayerintertech)
3857 {
3858 dr_quickbuildlayerinteractions(ap->tech);
3859 }
3860 if (dr_quicklayerinterarchashsize <= 0) return(TRUE);
3861
3862 /* find this arc in the table */
3863 index = abs(((INTBIG)ap) % dr_quicklayerinterarchashsize);
3864 for(i=0; i<dr_quicklayerinterarchashsize; i++)
3865 {
3866 if (dr_quicklayerinterarchash[index] == ap) break;
3867 index++;
3868 if (index >= dr_quicklayerinterarchashsize) index = 0;
3869 }
3870 if (i >= dr_quicklayerinterarchashsize) return(FALSE);
3871 return(dr_quicklayerinterarctable[index][layer]);
3872 }
3873
3874 /*
3875 * Routine to recursively scan cell "cell" (transformed with "trans") searching
3876 * for DRC Exclusion nodes. Each node is added to the global list "dr_quickexclusionlist".
3877 */
dr_quickaccumulateexclusion(INTBIG depth,NODEPROTO ** celllist,XARRAY * translist)3878 void dr_quickaccumulateexclusion(INTBIG depth, NODEPROTO **celllist, XARRAY *translist)
3879 {
3880 REGISTER NODEINST *ni;
3881 REGISTER NODEPROTO *cell;
3882 REGISTER INTBIG i, j, k, newtotal;
3883 REGISTER POLYGON *poly;
3884 REGISTER DRCEXCLUSION *newlist;
3885 XARRAY transr, transt, transtemp;
3886
3887 cell = celllist[depth-1];
3888 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
3889 {
3890 if (ni->proto == gen_drcprim)
3891 {
3892 /* create a DRC exclusion for every cell up the hierarchy */
3893 for(j=0; j<depth; j++)
3894 {
3895 if (j != depth-1) continue; /* exlusion should only be for the current hierarchy */
3896
3897 /* make sure there is a place to put the polygon */
3898 if (dr_quickexclusioncount >= dr_quickexclusiontotal)
3899 {
3900 newtotal = dr_quickexclusiontotal * 2;
3901 if (newtotal <= dr_quickexclusioncount) newtotal = dr_quickexclusioncount + 10;
3902 newlist = (DRCEXCLUSION *)emalloc(newtotal * (sizeof (DRCEXCLUSION)), dr_tool->cluster);
3903 if (newlist == 0) break;
3904 for(i=0; i<dr_quickexclusiontotal; i++)
3905 newlist[i] = dr_quickexclusionlist[i];
3906 for(i=dr_quickexclusiontotal; i<newtotal; i++)
3907 newlist[i].poly = allocpolygon(4, dr_tool->cluster);
3908 if (dr_quickexclusiontotal > 0) efree((CHAR *)dr_quickexclusionlist);
3909 dr_quickexclusionlist = newlist;
3910 dr_quickexclusiontotal = newtotal;
3911 }
3912
3913 /* extract the information about this DRC exclusion node */
3914 poly = dr_quickexclusionlist[dr_quickexclusioncount].poly;
3915 dr_quickexclusionlist[dr_quickexclusioncount].cell = celllist[j];
3916 (void)nodepolys(ni, 0, NOWINDOWPART);
3917 shapenodepoly(ni, 0, poly);
3918 makerot(ni, transr);
3919 xformpoly(poly, transr);
3920 for(k=depth-1; k>j; k--)
3921 xformpoly(poly, translist[k]);
3922 getbbox(poly, &dr_quickexclusionlist[dr_quickexclusioncount].lx,
3923 &dr_quickexclusionlist[dr_quickexclusioncount].hx,
3924 &dr_quickexclusionlist[dr_quickexclusioncount].ly,
3925 &dr_quickexclusionlist[dr_quickexclusioncount].hy);
3926
3927 /* see if it is already in the list */
3928 for(i=0; i<dr_quickexclusioncount; i++)
3929 {
3930 if (dr_quickexclusionlist[i].cell != celllist[j]) continue;
3931 if (dr_quickexclusionlist[i].lx != dr_quickexclusionlist[dr_quickexclusioncount].lx ||
3932 dr_quickexclusionlist[i].hx != dr_quickexclusionlist[dr_quickexclusioncount].hx ||
3933 dr_quickexclusionlist[i].ly != dr_quickexclusionlist[dr_quickexclusioncount].ly ||
3934 dr_quickexclusionlist[i].hy != dr_quickexclusionlist[dr_quickexclusioncount].hy)
3935 continue;
3936 break;
3937 }
3938 if (i >= dr_quickexclusioncount)
3939 dr_quickexclusioncount++;
3940 }
3941 continue;
3942 }
3943
3944 if (ni->proto->primindex == 0)
3945 {
3946 /* examine contents */
3947 maketrans(ni, transt);
3948 makerot(ni, transr);
3949 transmult(transt, transr, transtemp);
3950
3951 if (depth >= MAXHIERARCHYDEPTH)
3952 {
3953 if (!dr_quickexclusionwarned)
3954 ttyputerr(_("Depth of circuit exceeds %ld: unable to locate all DRC exclusion areas"),
3955 MAXHIERARCHYDEPTH);
3956 dr_quickexclusionwarned = TRUE;
3957 continue;
3958 }
3959 celllist[depth] = ni->proto;
3960 transcpy(transtemp, translist[depth]);
3961 dr_quickaccumulateexclusion(depth+1, celllist, translist);
3962 }
3963 }
3964 }
3965
3966 /*********************************** QUICK DRC ERROR REPORTING ***********************************/
3967
3968 /* Adds details about an error to the error list */
dr_quickreporterror(INTBIG errtype,TECHNOLOGY * tech,CHAR * msg,NODEPROTO * cell,INTBIG limit,INTBIG actual,CHAR * rule,POLYGON * poly1,GEOM * geom1,INTBIG layer1,INTBIG net1,POLYGON * poly2,GEOM * geom2,INTBIG layer2,INTBIG net2)3969 void dr_quickreporterror(INTBIG errtype, TECHNOLOGY *tech, CHAR *msg,
3970 NODEPROTO *cell, INTBIG limit, INTBIG actual, CHAR *rule,
3971 POLYGON *poly1, GEOM *geom1, INTBIG layer1, INTBIG net1,
3972 POLYGON *poly2, GEOM *geom2, INTBIG layer2, INTBIG net2)
3973 {
3974 REGISTER NODEPROTO *np1, *np2;
3975 REGISTER VARIABLE *var;
3976 REGISTER INTBIG i, len, sortlayer, lambda;
3977 REGISTER BOOLEAN showgeom;
3978 REGISTER GEOM *p1, *p2;
3979 REGISTER void *err, *infstr;
3980 REGISTER CHAR *errmsg;
3981 REGISTER POLYGON *poly;
3982 INTBIG lx, hx, ly, hy, lx2, hx2, ly2, hy2;
3983
3984 /* if this error is being ignored, don't record it */
3985 var = getvalkey((INTBIG)cell, VNODEPROTO, VGEOM|VISARRAY, dr_ignore_listkey);
3986 if (var != NOVARIABLE)
3987 {
3988 len = getlength(var);
3989 for(i=0; i<len; i += 2)
3990 {
3991 p1 = ((GEOM **)var->addr)[i];
3992 p2 = ((GEOM **)var->addr)[i+1];
3993 if (p1 == geom1 && p2 == geom2) return;
3994 if (p1 == geom2 && p2 == geom1) return;
3995 }
3996 }
3997
3998 /* if this error is in an ignored area, don't record it */
3999 if (dr_quickexclusioncount > 0)
4000 {
4001 /* determine the bounding box of the error */
4002 getbbox(poly1, &lx, &hx, &ly, &hy);
4003 if (poly2 != NOPOLYGON)
4004 {
4005 getbbox(poly2, &lx2, &hx2, &ly2, &hy2);
4006 if (lx2 < lx) lx = lx2;
4007 if (hx2 > hx) hx = hx2;
4008 if (ly2 < ly) ly = ly2;
4009 if (hy2 > hy) hy = hy2;
4010 }
4011 for(i=0; i<dr_quickexclusioncount; i++)
4012 {
4013 if (cell != dr_quickexclusionlist[i].cell) continue;
4014 poly = dr_quickexclusionlist[i].poly;
4015 if (isinside(lx, ly, poly) && isinside(lx, hy, poly) &&
4016 isinside(hx, ly, poly) && isinside(hx, hy, poly)) return;
4017 }
4018 }
4019
4020 lambda = lambdaofcell(cell);
4021
4022 /* BEGIN critical section */
4023 if (dr_quickparalleldrc) emutexlock(dr_quickmutexio);
4024
4025 /* describe the error */
4026 infstr = initinfstr();
4027 np1 = geomparent(geom1);
4028 if (errtype == SPACINGERROR || errtype == NOTCHERROR)
4029 {
4030 /* describe spacing width error */
4031 if (errtype == SPACINGERROR) addstringtoinfstr(infstr, _("Spacing")); else
4032 addstringtoinfstr(infstr, _("Notch"));
4033 if (layer1 == layer2)
4034 formatinfstr(infstr, _(" (layer %s)"), layername(tech, layer1));
4035 addstringtoinfstr(infstr, x_(": "));
4036 np2 = geomparent(geom2);
4037 if (np1 != np2)
4038 {
4039 formatinfstr(infstr, _("cell %s, "), describenodeproto(np1));
4040 } else if (np1 != cell)
4041 {
4042 formatinfstr(infstr, _("[in cell %s] "), describenodeproto(np1));
4043 }
4044 if (geom1->entryisnode)
4045 formatinfstr(infstr, _("node %s"), describenodeinst(geom1->entryaddr.ni)); else
4046 formatinfstr(infstr, _("arc %s"), describearcinst(geom1->entryaddr.ai));
4047 if (layer1 != layer2)
4048 formatinfstr(infstr, _(", layer %s"), layername(tech, layer1));
4049
4050 if (actual < 0) addstringtoinfstr(infstr, _(" OVERLAPS ")); else
4051 if (actual == 0) addstringtoinfstr(infstr, _(" TOUCHES ")); else
4052 formatinfstr(infstr, _(" LESS (BY %s) THAN %s TO "), latoa(limit-actual, lambda),
4053 latoa(limit, lambda));
4054
4055 if (np1 != np2)
4056 formatinfstr(infstr, _("cell %s, "), describenodeproto(np2));
4057 if (geom2->entryisnode)
4058 formatinfstr(infstr, _("node %s"), describenodeinst(geom2->entryaddr.ni)); else
4059 formatinfstr(infstr, _("arc %s"), describearcinst(geom2->entryaddr.ai));
4060 if (layer1 != layer2)
4061 formatinfstr(infstr, _(", layer %s"), layername(tech, layer2));
4062 if (msg != NULL)
4063 {
4064 addstringtoinfstr(infstr, x_("; "));
4065 addstringtoinfstr(infstr, msg);
4066 }
4067 sortlayer = mini(layer1, layer2);
4068 } else
4069 {
4070 /* describe minimum width/size or layer error */
4071 switch (errtype)
4072 {
4073 case MINWIDTHERROR:
4074 addstringtoinfstr(infstr, _("Minimum width error:"));
4075 break;
4076 case MINSIZEERROR:
4077 addstringtoinfstr(infstr, _("Minimum size error:"));
4078 break;
4079 case BADLAYERERROR:
4080 formatinfstr(infstr, _("Invalid layer (%s):"), layername(tech, layer1));
4081 break;
4082 case LAYERSURROUNDERROR:
4083 addstringtoinfstr(infstr, _("Layer surround error:"));
4084 break;
4085 }
4086 formatinfstr(infstr, _(" cell %s"), describenodeproto(np1));
4087 if (geom1->entryisnode)
4088 {
4089 formatinfstr(infstr, _(", node %s"), describenodeinst(geom1->entryaddr.ni));
4090 } else
4091 {
4092 formatinfstr(infstr, _(", arc %s"), describearcinst(geom1->entryaddr.ai));
4093 }
4094 if (errtype == MINWIDTHERROR)
4095 {
4096 formatinfstr(infstr, _(", layer %s"), layername(tech, layer1));
4097 formatinfstr(infstr, _(" LESS THAN %s WIDE (IS %s)"),
4098 latoa(limit, lambda), latoa(actual, lambda));
4099 } else if (errtype == MINSIZEERROR)
4100 {
4101 formatinfstr(infstr, _(" LESS THAN %s IN SIZE (IS %s)"),
4102 latoa(limit, lambda), latoa(actual, lambda));
4103 } else if (errtype == LAYERSURROUNDERROR)
4104 {
4105 formatinfstr(infstr, _(", layer %s"), layername(tech, layer1));
4106 formatinfstr(infstr, _(" NEEDS SURROUND OF LAYER %s BY %s"),
4107 layername(tech, layer2), latoa(limit, lambda));
4108 }
4109 sortlayer = layer1;
4110 }
4111 if (rule != 0) formatinfstr(infstr, _(" [rule %s]"), rule);
4112 errmsg = returninfstr(infstr);
4113 if (dr_logerrors)
4114 {
4115 err = logerror(errmsg, cell, sortlayer);
4116 showgeom = TRUE;
4117 if (poly1 != NOPOLYGON) { showgeom = FALSE; addpolytoerror(err, poly1); }
4118 if (poly2 != NOPOLYGON) { showgeom = FALSE; addpolytoerror(err, poly2); }
4119 addgeomtoerror(err, geom1, showgeom, 0, 0);
4120 if (geom2 != NOGEOM) addgeomtoerror(err, geom2, showgeom, 0, 0);
4121 } else
4122 {
4123 ttyputerr(x_("%s"), errmsg);
4124 }
4125
4126 /* END critical section */
4127 if (dr_quickparalleldrc) emutexunlock(dr_quickmutexio);
4128 }
4129
4130 #endif /* DRCTOOL - at top */
4131