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, &shy, 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, &shy, 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, &shy, 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