1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: ercantenna.c
6  * Electrical Rules Checking tool: Antenna Rules check
7  * Written by: Steven M. Rubin
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 /*
33  * Antenna rules are required by some IC manufacturers to ensure that the transistors of the
34  * chip are not destroyed during fabrication.  This is because, during fabrication, the wafer is
35  * bombarded with ions while making the polysilicon and metal layers.
36  * These ions must find a path to through the wafer (to the substrate and active layers at the bottom).
37  * If there is a large area of poly or metal, and if it connects ONLY to gates of transistors
38  * (not to source or drain or any other active material) then these ions will travel through
39  * the transistors.  If the ratio of the poly or metal layers to the area of the transistors
40  * is too large, the transistors will be fried.
41  */
42 
43 #include "config.h"
44 #if ERCTOOL
45 
46 #include "global.h"
47 #include "efunction.h"
48 #include "egraphics.h"
49 #include "edialogs.h"
50 #include "erc.h"
51 
52 /*
53  * Things to do:
54  *   Have errors show the gates, too
55  *   Progress indicator
56  *   Extended comment explaining what antenna is
57  */
58 /* #define DEBUGANTENNA 1 */			/* uncomment to debug */
59 
60 #define NOANTENNAOBJ ((ANTENNAOBJ *)-1)
61 
62 typedef struct Iantennaobj
63 {
64 	GEOM      *geom;		/* the object */
65 	INTBIG     depth;		/* the depth of hierarchy at this node */
66 	INTBIG     otherend;	/* end of arc to walk along */
67 	NODEINST **hierstack;	/* the hierarchical stack at this node */
68 	INTBIG     total;		/* total size of the hierarchical stack */
69 	struct Iantennaobj *nextantennaobj;
70 } ANTENNAOBJ;
71 
72 static ANTENNAOBJ *erc_antfirstspreadantennaobj;/* head of linked list of antenna objects to spread */
73 static ANTENNAOBJ *erc_antantennaobjfree = NOANTENNAOBJ;
74 
75 static POLYLIST   *erc_antpolylist = 0;			/* for gathering polygons */
76 static TECHNOLOGY *erc_anttech;					/* current technology being considered */
77 static INTBIG      erc_antlambda;				/* value of lambda for this technology */
78 static INTBIG     *erc_antlayerlevel;			/* level of each layer in the technology */
79 static INTBIG     *erc_antlayerforlevel;		/* layer associated with each antenna-check level */
80 static NODEPROTO  *erc_anttopcell;				/* top-level cell being checked */
81 static float       erc_antgatearea;				/* accumulated gate area */
82 static float       erc_antregionarea;			/* accumulated region area */
83 static void       *erc_anterror;				/* error report being generated */
84 static TECHNOLOGY *erc_antcachedtech = NOTECHNOLOGY;
85 static INTBIG     *erc_antcachedratios;
86 static INTBIG      erc_antworstratio;			/* the worst ratio found */
87 
88 static ANTENNAOBJ **erc_antpathhashtable;			/* the antenna objects hash table */
89 static INTBIG       erc_antpathhashtablesize = 0;	/* size of the antenna objects hash table */
90 static INTBIG       erc_antpathhashtablecount;		/* number of antenna objects in the hash table */
91        INTBIG       erc_antennaarcratiokey;			/* key for "ERC_antenna_arc_ratio" */
92 
93 /* the level meanings (for arcprotos and layers) */
94 #define ERCANTIGNORE     0
95 #define ERCANTDIFFUSION  1
96 #define ERCANTLEVEL1     2
97 
98 #define ERCANTPATHNULL   0		/* nothing found on the path */
99 #define ERCANTPATHGATE   1		/* found a gate on the path */
100 #define ERCANTPATHACTIVE 2		/* found active on the path */
101 
102 #define ERCDEFPOLYLIMIT  200	/* maximum ratio of poly to gate area */
103 #define ERCDEFMETALLIMIT 400	/* maximum ratio of metal to gate area */
104 
105 /* prototypes for local routines */
106 static void        erc_antcheckthiscell(NODEPROTO *cell, INTBIG level);
107 static INTBIG      erc_antfollownode(NODEINST *ni, PORTPROTO *pp, INTBIG level, XARRAY trans);
108 static void        erc_antgetpolygonarea(INTBIG layer, TECHNOLOGY *tech, INTBIG *x, INTBIG *y, INTBIG count);
109 static void        erc_antputpolygoninerror(INTBIG layer, TECHNOLOGY *tech, INTBIG *x, INTBIG *y, INTBIG count);
110 static ANTENNAOBJ *erc_antallocantennaobj(void);
111 static void        erc_antloadantennaobj(ANTENNAOBJ *ao, INTBIG depth, NODEINST **stack);
112 static void        erc_antaddantennaobj(ANTENNAOBJ *ao);
113 static BOOLEAN     erc_anthaveantennaobj(ANTENNAOBJ *ao);
114 static void        erc_antfreeantennaobj(ANTENNAOBJ *ao);
115 static INTBIG      erc_antfindarcs(NODEINST *ni, PORTPROTO *pp, INTBIG level, INTBIG depth, NODEINST **antstack);
116 static INTBIG      erc_antfindexports(NODEINST *ni, PORTPROTO *pp, INTBIG level, INTBIG depth, NODEINST **antstack);
117 static void        erc_antinsertantennaobj(ANTENNAOBJ *ao);
118 static INTBIG      erc_antgethash(ANTENNAOBJ *ao);
119 static INTBIG      erc_antratio(INTBIG level);
120 static BOOLEAN     erc_hasdiffusion(NODEINST *ni);
121 
122 /************************ CONTROL ***********************/
123 
124 /*
125  * Main entry point for antenna check rules.  Checks rules in cell "cell".
126  */
erc_antcheckcell(NODEPROTO * cell)127 void erc_antcheckcell(NODEPROTO *cell)
128 {
129 	REGISTER LIBRARY *lib;
130 	REGISTER INTBIG i, fun, level, highestlevel, lasterrorcount;
131 	REGISTER NODEPROTO *np;
132 	REGISTER ARCINST *ai;
133 	REGISTER ARCPROTO *ap;
134 	float t;
135 
136 	erc_anttopcell = cell;
137 	erc_anttech = cell->tech;
138 	erc_antlambda = el_curlib->lambda[erc_anttech->techindex];
139 
140 	/* clear marks on all arcs in all cells */
141 	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
142 	{
143 		for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
144 		{
145 			for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
146 				ai->temp1 = 0;
147 		}
148 	}
149 
150 	/* initialize properties of the arc prototypes */
151 	highestlevel = ERCANTLEVEL1;
152 	for(ap = erc_anttech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
153 	{
154 		ap->temp1 = ERCANTIGNORE;
155 		fun = (ap->userbits&AFUNCTION) >> AFUNCTIONSH;
156 		switch (fun)
157 		{
158 			case APDIFF:
159 			case APDIFFP:
160 			case APDIFFN:
161 			case APDIFFS:
162 			case APDIFFW:   ap->temp1 = ERCANTDIFFUSION;  break;
163 			case APPOLY1:   ap->temp1 = ERCANTLEVEL1;     break;
164 			case APMETAL1:  ap->temp1 = ERCANTLEVEL1+1;   break;
165 			case APMETAL2:  ap->temp1 = ERCANTLEVEL1+2;   break;
166 			case APMETAL3:  ap->temp1 = ERCANTLEVEL1+3;   break;
167 			case APMETAL4:  ap->temp1 = ERCANTLEVEL1+4;   break;
168 			case APMETAL5:  ap->temp1 = ERCANTLEVEL1+5;   break;
169 			case APMETAL6:  ap->temp1 = ERCANTLEVEL1+6;   break;
170 			case APMETAL7:  ap->temp1 = ERCANTLEVEL1+7;   break;
171 			case APMETAL8:  ap->temp1 = ERCANTLEVEL1+8;   break;
172 			case APMETAL9:  ap->temp1 = ERCANTLEVEL1+9;   break;
173 			case APMETAL10: ap->temp1 = ERCANTLEVEL1+10;  break;
174 			case APMETAL11: ap->temp1 = ERCANTLEVEL1+11;  break;
175 			case APMETAL12: ap->temp1 = ERCANTLEVEL1+12;  break;
176 		}
177 		if (ap->temp1 > highestlevel) highestlevel = ap->temp1;
178 	}
179 
180 	/* initialize the properties of the layers */
181 	erc_antlayerlevel = (INTBIG *)emalloc(erc_anttech->layercount * SIZEOFINTBIG, erc_tool->cluster);
182 	if (erc_antlayerlevel == 0) return;
183 	erc_antlayerforlevel = (INTBIG *)emalloc(erc_anttech->layercount * SIZEOFINTBIG, erc_tool->cluster);
184 	if (erc_antlayerforlevel == 0) return;
185 	for(i=0; i<erc_anttech->layercount; i++) erc_antlayerforlevel[i] = 0;
186 	for(i=erc_anttech->layercount-1; i>=0; i--)
187 	{
188 		erc_antlayerlevel[i] = ERCANTIGNORE;
189 		fun = layerfunction(erc_anttech, i);
190 		if ((fun&LFPSEUDO) != 0) continue;
191 		switch (fun&LFTYPE)
192 		{
193 			case LFDIFF:    erc_antlayerlevel[i] = ERCANTDIFFUSION;  break;
194 			case LFPOLY1:   erc_antlayerlevel[i] = ERCANTLEVEL1;     break;
195 			case LFMETAL1:  erc_antlayerlevel[i] = ERCANTLEVEL1+1;   break;
196 			case LFMETAL2:  erc_antlayerlevel[i] = ERCANTLEVEL1+2;   break;
197 			case LFMETAL3:  erc_antlayerlevel[i] = ERCANTLEVEL1+3;   break;
198 			case LFMETAL4:  erc_antlayerlevel[i] = ERCANTLEVEL1+4;   break;
199 			case LFMETAL5:  erc_antlayerlevel[i] = ERCANTLEVEL1+5;   break;
200 			case LFMETAL6:  erc_antlayerlevel[i] = ERCANTLEVEL1+6;   break;
201 			case LFMETAL7:  erc_antlayerlevel[i] = ERCANTLEVEL1+7;   break;
202 			case LFMETAL8:  erc_antlayerlevel[i] = ERCANTLEVEL1+8;   break;
203 			case LFMETAL9:  erc_antlayerlevel[i] = ERCANTLEVEL1+9;   break;
204 			case LFMETAL10: erc_antlayerlevel[i] = ERCANTLEVEL1+10;  break;
205 			case LFMETAL11: erc_antlayerlevel[i] = ERCANTLEVEL1+11;  break;
206 			case LFMETAL12: erc_antlayerlevel[i] = ERCANTLEVEL1+12;  break;
207 		}
208 		if (erc_antlayerlevel[i] > highestlevel) highestlevel = erc_antlayerlevel[i];
209 		erc_antlayerforlevel[erc_antlayerlevel[i]] = i;
210 	}
211 
212 	if (erc_antpolylist == 0)
213 		erc_antpolylist = allocpolylist(erc_tool->cluster);
214 
215 	/* start the clock */
216 	starttimer();
217 
218 	/* initialize error logging */
219 	initerrorlogging(x_("ERC antenna rules"));
220 
221 	/* now check the cell recursively */
222 	lasterrorcount = 0;
223 	erc_antworstratio = 0;
224 #ifdef DEBUGANTENNA
225 	level = ERCANTLEVEL1+2;
226 #else
227 	for(level = ERCANTLEVEL1; level <= highestlevel; level++)
228 #endif
229 	{
230 		ttyputmsg(_("Checking Antenna rules for %s..."),
231 			layername(erc_anttech, erc_antlayerforlevel[level]));
232 
233 		/* clear timestamps on all cell */
234 		for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
235 			for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
236 				np->temp1 = 0;
237 
238 		/* do the check for this level */
239 		erc_antcheckthiscell(cell, level);
240 		i = numerrors();
241 		if (i != lasterrorcount)
242 		{
243 			ttyputmsg(_("  Found %ld errors"), i - lasterrorcount);
244 			lasterrorcount = i;
245 		}
246 	}
247 
248 	t = endtimer();
249 	i = numerrors();
250 	ttyputmsg(_("Worst antenna ratio found is %ld"), erc_antworstratio);
251 	if (i == 0) ttyputmsg(_("No Antenna errors found (took %s)"), explainduration(t)); else
252 		ttyputmsg(_("Found %ld Antenna errors (took %s)"), i, explainduration(t));
253 
254 	/* finish error gathering */
255 	termerrorlogging(TRUE);
256 
257 	/* clean up */
258 	efree((CHAR *)erc_antlayerlevel);
259 	efree((CHAR *)erc_antlayerforlevel);
260 }
261 
erc_antterm(void)262 void erc_antterm(void)
263 {
264 	REGISTER ANTENNAOBJ *ao;
265 
266 	while (erc_antantennaobjfree != NOANTENNAOBJ)
267 	{
268 		ao = erc_antantennaobjfree;
269 		erc_antantennaobjfree = ao->nextantennaobj;
270 		if (ao->total > 0) efree((CHAR *)ao->hierstack);
271 		efree((CHAR *)ao);
272 	}
273 	if (erc_antpolylist != 0)
274 		freepolylist(erc_antpolylist);
275 	if (erc_antpathhashtablesize > 0)
276 		efree((CHAR *)erc_antpathhashtable);
277 	if (erc_antcachedtech != NOTECHNOLOGY)
278 		efree((CHAR *)erc_antcachedratios);
279 }
280 
281 /*
282  * Routine to check the contents of cell "cell", considering geometry on level "level" of antenna depth.
283  */
erc_antcheckthiscell(NODEPROTO * cell,INTBIG level)284 void erc_antcheckthiscell(NODEPROTO *cell, INTBIG level)
285 {
286 	REGISTER NODEINST *ni, *oni;
287 	REGISTER INTBIG found, ratio, neededratio, i, j, tot;
288 	REGISTER POLYGON *poly;
289 	REGISTER PORTARCINST *pi;
290 	REGISTER ANTENNAOBJ *ao;
291 	REGISTER PORTPROTO *pp;
292 	XARRAY trans, rtrans, ttrans, temptrans;
293 	REGISTER void *infstr, *vmerge;
294 
295 	/* examine every node and follow all relevant arcs */
296 	for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst) ni->temp1 = 0;
297 
298 	for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
299 	{
300 		if (ni->temp1 != 0) continue;
301 		ni->temp1 = 1;
302 
303 		/* check every connection on the node */
304 		for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
305 		{
306 			/* ignore if an arc on this port is already seen */
307 			for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
308 				if (pi->proto == pp && pi->conarcinst->temp1 != 0) break;
309 			if (pi != NOPORTARCINST) continue;
310 
311 			erc_antgatearea = 0.0;
312 			erc_antpathhashtablecount = 0;
313 			for(i=0; i<erc_antpathhashtablesize; i++) erc_antpathhashtable[i] = NOANTENNAOBJ;
314 
315 			found = erc_antfollownode(ni, pp, level, el_matid);
316 			if (found == ERCANTPATHGATE)
317 			{
318 				/* gather the geometry here */
319 				vmerge = 0;
320 				for(j=0; j<erc_antpathhashtablesize; j++)
321 				{
322 					ao = erc_antpathhashtable[j];
323 					if (ao == NOANTENNAOBJ) continue;
324 
325 					if (ao->geom->entryisnode)
326 					{
327 						oni = ao->geom->entryaddr.ni;
328 						makerot(oni, trans);
329 						for(i=ao->depth-1; i>=0; i--)
330 						{
331 							maketrans(ao->hierstack[i], ttrans);
332 							transmult(trans, ttrans, temptrans);
333 							makerot(ao->hierstack[i], rtrans);
334 							transmult(temptrans, rtrans, trans);
335 						}
336 
337 						tot = allnodeEpolys(oni, erc_antpolylist, NOWINDOWPART, TRUE);
338 						for(i=0; i<tot; i++)
339 						{
340 							poly = erc_antpolylist->polygons[i];
341 							if (poly->tech != erc_anttech) continue;
342 							if (erc_antlayerlevel[poly->layer] != level) continue;
343 							if (vmerge == 0)
344 								vmerge = mergenew(erc_tool->cluster);
345 							xformpoly(poly, trans);
346 							mergeaddpolygon(vmerge, poly->layer, poly->tech, poly);
347 						}
348 					} else
349 					{
350 						transid(trans);
351 						for(i=ao->depth-1; i>=0; i--)
352 						{
353 							maketrans(ao->hierstack[i], ttrans);
354 							transmult(trans, ttrans, temptrans);
355 							makerot(ao->hierstack[i], rtrans);
356 							transmult(temptrans, rtrans, trans);
357 						}
358 
359 						tot = allarcpolys(ao->geom->entryaddr.ai, erc_antpolylist, NOWINDOWPART);
360 						for(i=0; i<tot; i++)
361 						{
362 							poly = erc_antpolylist->polygons[i];
363 							if (poly->tech != erc_anttech) continue;
364 							if (erc_antlayerlevel[poly->layer] != level) continue;
365 							if (vmerge == 0)
366 								vmerge = mergenew(erc_tool->cluster);
367 							xformpoly(poly, trans);
368 							mergeaddpolygon(vmerge, poly->layer, poly->tech, poly);
369 						}
370 					}
371 				}
372 				if (vmerge != 0)
373 				{
374 					/* get the area of the antenna */
375 #ifdef DEBUGANTENNA
376 					asktool(us_tool, x_("clear"));
377 #endif
378 					erc_antregionarea = 0.0;
379 					mergeextract(vmerge, erc_antgetpolygonarea);
380 
381 					/* see if it is an antenna violation */
382 					ratio = (INTBIG)(erc_antregionarea / erc_antgatearea);
383 					neededratio = erc_antratio(level);
384 					if (ratio > erc_antworstratio) erc_antworstratio = ratio;
385 					if (ratio >= neededratio)
386 					{
387 						/* error */
388 						infstr = initinfstr();
389 						formatinfstr(infstr, _("layer %s has area %s; gates have area %s, ratio is %ld but limit is %ld"),
390 							layername(erc_anttech, erc_antlayerforlevel[level]),
391 							latoa((INTBIG)(erc_antregionarea/erc_antlambda), erc_antlambda),
392 							latoa((INTBIG)(erc_antgatearea/erc_antlambda), erc_antlambda),
393 							ratio, neededratio);
394 						erc_anterror = logerror(returninfstr(infstr), cell, 0);
395 						mergeextract(vmerge, erc_antputpolygoninerror);
396 					}
397 #ifdef DEBUGANTENNA
398 					infstr = initinfstr();
399 					formatinfstr(infstr, x_("Cell %s: Level %d: Gate size %s, Region size %s, ratio=%g"),
400 						describenodeproto(cell), level-1,
401 						latoa((INTBIG)(erc_antgatearea/erc_antlambda), erc_antlambda),
402 						latoa((INTBIG)(erc_antregionarea/erc_antlambda), erc_antlambda),
403 						erc_antregionarea / erc_antgatearea);
404 					if (*ttygetline(returninfstr(infstr)) == 'q') return;
405 #endif
406 					mergedelete(vmerge);
407 				}
408 			}
409 
410 			/* free the antenna object list */
411 			for(i=0; i<erc_antpathhashtablesize; i++)
412 			{
413 				ao = erc_antpathhashtable[i];
414 				if (ao == NOANTENNAOBJ) continue;
415 				erc_antfreeantennaobj(ao);
416 			}
417 		}
418 	}
419 
420 	/* now look at subcells */
421 	cell->temp1 = 1;
422 	for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
423 	{
424 		if (ni->proto->primindex != 0) continue;
425 		if (ni->proto->temp1 != 0) continue;
426 
427 		erc_antcheckthiscell(ni->proto, level);
428 	}
429 }
430 
431 /*
432  * Routine to follow node "ni" around the cell.
433  *    Returns ERCANTPATHNULL   if it found no gate or active on the path.
434  *    Returns ERCANTPATHGATE   if it found gates on the path.
435  *    Returns ERCANTPATHACTIVE if it found active on the path.
436  */
erc_antfollownode(NODEINST * ni,PORTPROTO * pp,INTBIG level,XARRAY trans)437 INTBIG erc_antfollownode(NODEINST *ni, PORTPROTO *pp, INTBIG level, XARRAY trans)
438 {
439 	REGISTER INTBIG depth, i, found;
440 	INTBIG length, width;
441 	REGISTER ARCINST *ai;
442 	REGISTER NODEINST *thisni;
443 	REGISTER BOOLEAN ret, seen;
444 	REGISTER ANTENNAOBJ *ao;
445 	NODEINST *antstack[200];
446 
447 	/* presume that nothing was found */
448 	ret = ERCANTPATHNULL;
449 	erc_antfirstspreadantennaobj = NOANTENNAOBJ;
450 	depth = 0;
451 
452 	/* keep walking along the nodes and arcs */
453 	for(;;)
454 	{
455 		/* if this is a subcell, recurse on it */
456 		ni->temp1 = 1;
457 		thisni = ni;
458 		while (thisni->proto->primindex == 0)
459 		{
460 			antstack[depth] = thisni;
461 			depth++;
462 			thisni = pp->subnodeinst;
463 			pp = pp->subportproto;
464 		}
465 
466 		/* see if we hit a transistor */
467 		seen = FALSE;
468 		if (isfet(thisni->geom))
469 		{
470 			/* stop tracing */
471 			if (thisni->proto->firstportproto->network == pp->network)
472 			{
473 				/* touching the gate side of the transistor */
474 				transistorsize(thisni, &length, &width);
475 				erc_antgatearea += (float)(length * width);
476 				ret = ERCANTPATHGATE;
477 			} else
478 			{
479 				/* touching the diffusion side of the transistor */
480 				return(ERCANTPATHACTIVE);
481 			}
482 		} else
483 		{
484 			/* normal primitive: propagate */
485 			if (erc_hasdiffusion(thisni)) return(ERCANTPATHACTIVE);
486 			ao = erc_antallocantennaobj();
487 			if (ao == NOANTENNAOBJ) return(ERCANTPATHACTIVE);
488 			erc_antloadantennaobj(ao, depth, antstack);
489 			ao->geom = ni->geom;
490 
491 			if (erc_anthaveantennaobj(ao))
492 			{
493 				/* already in the list: free this object */
494 				erc_antfreeantennaobj(ao);
495 				seen = TRUE;
496 			} else
497 			{
498 				/* not in the list: add it */
499 				erc_antaddantennaobj(ao);
500 			}
501 		}
502 
503 		/* look at all arcs on the node */
504 		if (!seen)
505 		{
506 			found = erc_antfindarcs(thisni, pp, level, depth, antstack);
507 			if (found == ERCANTPATHACTIVE) return(found);
508 			if (depth > 0)
509 			{
510 				found = erc_antfindexports(thisni, pp, level, depth, antstack);
511 				if (found == ERCANTPATHACTIVE) return(found);
512 			}
513 		}
514 
515 		/* look for an unspread antenna object and keep walking */
516 		if (erc_antfirstspreadantennaobj == NOANTENNAOBJ) break;
517 		ao = erc_antfirstspreadantennaobj;
518 		erc_antfirstspreadantennaobj = ao->nextantennaobj;
519 
520 		ai = ao->geom->entryaddr.ai;
521 		ni = ai->end[ao->otherend].nodeinst;
522 		pp = ai->end[ao->otherend].portarcinst->proto;
523 		depth = ao->depth;
524 		for(i=0; i<depth; i++)
525 			antstack[i] = ao->hierstack[i];
526 	}
527 	return(ret);
528 }
529 
530 /*
531  * Routine to return TRUE if node "ni" has diffusion on it.
532  */
erc_hasdiffusion(NODEINST * ni)533 BOOLEAN erc_hasdiffusion(NODEINST *ni)
534 {
535 	REGISTER INTBIG i, total, fun;
536 	static POLYGON *poly = NOPOLYGON;
537 
538 	/* get polygon */
539 	(void)needstaticpolygon(&poly, 4, io_tool->cluster);
540 
541 	/* stop if this is a pin */
542 	if (nodefunction(ni) == NPPIN) return(FALSE);
543 
544 	/* analyze to see if there is diffusion here */
545 	total = nodepolys(ni, 0, NOWINDOWPART);
546 	for(i=0; i<total; i++)
547 	{
548 		shapenodepoly(ni, i, poly);
549 		fun = layerfunction(poly->tech, poly->layer);
550 		if ((fun&LFTYPE) == LFDIFF) return(TRUE);
551 	}
552 	return(FALSE);
553 }
554 
erc_antfindarcs(NODEINST * ni,PORTPROTO * pp,INTBIG level,INTBIG depth,NODEINST ** antstack)555 INTBIG erc_antfindarcs(NODEINST *ni, PORTPROTO *pp, INTBIG level, INTBIG depth, NODEINST **antstack)
556 {
557 	REGISTER PORTARCINST *pi;
558 	REGISTER ARCINST *ai;
559 	REGISTER INTBIG other;
560 	REGISTER ANTENNAOBJ *ao;
561 
562 	for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
563 	{
564 		if (pi->proto != pp) continue;
565 		ai = pi->conarcinst;
566 
567 		/* see if it is the desired layer */
568 		if (ai->proto->temp1 == ERCANTIGNORE) continue;
569 		if (ai->proto->temp1 == ERCANTDIFFUSION) return(ERCANTPATHACTIVE);
570 		if (ai->proto->temp1 > level) continue;
571 
572 		/* make an antenna object for this arc */
573 		ai->temp1 = 1;
574 		ao = erc_antallocantennaobj();
575 		if (ao == NOANTENNAOBJ) return(ERCANTPATHACTIVE);
576 		erc_antloadantennaobj(ao, depth, antstack);
577 		ao->geom = ai->geom;
578 
579 		if (erc_anthaveantennaobj(ao))
580 		{
581 			erc_antfreeantennaobj(ao);
582 			continue;
583 		}
584 
585 		if (ai->end[0].portarcinst == pi) other = 1; else other = 0;
586 		ao->otherend = other;
587 		erc_antaddantennaobj(ao);
588 
589 		/* add to the list of "unspread" antenna objects */
590 		ao->nextantennaobj = erc_antfirstspreadantennaobj;
591 		erc_antfirstspreadantennaobj = ao;
592 	}
593 	return(ERCANTPATHNULL);
594 }
595 
erc_antfindexports(NODEINST * ni,PORTPROTO * pp,INTBIG level,INTBIG depth,NODEINST ** antstack)596 INTBIG erc_antfindexports(NODEINST *ni, PORTPROTO *pp, INTBIG level, INTBIG depth, NODEINST **antstack)
597 {
598 	REGISTER PORTEXPINST *pe;
599 	REGISTER INTBIG found;
600 
601 	depth--;
602 	for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
603 	{
604 		if (pe->proto != pp) continue;
605 		ni = antstack[depth];
606 		pp = pe->exportproto;
607 		found = erc_antfindarcs(ni, pp, level, depth, antstack);
608 		if (found == ERCANTPATHACTIVE) return(found);
609 		if (depth > 0)
610 		{
611 			found = erc_antfindexports(ni, pp, level, depth, antstack);
612 			if (found == ERCANTPATHACTIVE) return(found);
613 		}
614 	}
615 	return(ERCANTPATHNULL);
616 }
617 
618 /*
619  * Coroutine of polygon merging to obtain a polygon and store it in the error that is being logged.
620  */
erc_antputpolygoninerror(INTBIG layer,TECHNOLOGY * tech,INTBIG * xv,INTBIG * yv,INTBIG count)621 void erc_antputpolygoninerror(INTBIG layer, TECHNOLOGY *tech, INTBIG *xv, INTBIG *yv, INTBIG count)
622 {
623 	REGISTER INTBIG i, lasti, lastx, lasty, x, y;
624 
625 	for(i=0; i<count; i++)
626 	{
627 		if (i == 0) lasti = count-1; else lasti = i-1;
628 		lastx = xv[lasti];   lasty = yv[lasti];
629 		x = xv[i];           y = yv[i];
630 		addlinetoerror(erc_anterror, lastx, lasty, x, y);
631 	}
632 }
633 
634 /*
635  * Coroutine of polygon merging to obtain a polygon and accumulate its area.
636  */
erc_antgetpolygonarea(INTBIG layer,TECHNOLOGY * tech,INTBIG * xv,INTBIG * yv,INTBIG count)637 void erc_antgetpolygonarea(INTBIG layer, TECHNOLOGY *tech, INTBIG *xv, INTBIG *yv, INTBIG count)
638 {
639 	erc_antregionarea += areapoints(count, xv, yv);
640 #ifdef DEBUGANTENNA
641 	{
642 		REGISTER INTBIG i, lasti, lastx, lasty, x, y;
643 
644 		for(i=0; i<count; i++)
645 		{
646 			if (i == 0) lasti = count-1; else lasti = i-1;
647 			lastx = xv[lasti];   lasty = yv[lasti];
648 			x = xv[i];           y = yv[i];
649 			asktool(us_tool, x_("show-line"), lastx, lasty, x, y, (INTBIG)erc_anttopcell);
650 		}
651 	}
652 #endif
653 }
654 
erc_antgethash(ANTENNAOBJ * ao)655 INTBIG erc_antgethash(ANTENNAOBJ *ao)
656 {
657 	REGISTER INTBIG i, j;
658 
659 	i = ao->depth + (INTBIG)ao->geom;
660 	for(j=0; j<ao->depth; j++)
661 		i += (INTBIG)ao->hierstack[j];
662 	return(abs(i % erc_antpathhashtablesize));
663 }
664 
665 /*
666  * Routine to return TRUE if antenna object "ao" is already in the list.
667  */
erc_anthaveantennaobj(ANTENNAOBJ * ao)668 BOOLEAN erc_anthaveantennaobj(ANTENNAOBJ *ao)
669 {
670 	REGISTER ANTENNAOBJ *oao;
671 	REGISTER INTBIG i, j, index;
672 
673 	if (erc_antpathhashtablesize == 0) return(FALSE);
674 	index = erc_antgethash(ao);
675 	for(j=0; j<erc_antpathhashtablesize; j++)
676 	{
677 		oao = erc_antpathhashtable[index];
678 		if (oao == NOANTENNAOBJ) break;
679 
680 		if (oao->geom == ao->geom && oao->depth == ao->depth)
681 		{
682 			for(i=0; i<oao->depth; i++)
683 				if (oao->hierstack[i] != ao->hierstack[i]) break;
684 			if (i >= oao->depth) return(TRUE);
685 		}
686 		index++;
687 		if (index >= erc_antpathhashtablesize) index = 0;
688 	}
689 	return(FALSE);
690 }
691 
692 /*
693  * Routine to add antenna object "ao" to the list of antenna objects on this path.
694  */
erc_antaddantennaobj(ANTENNAOBJ * ao)695 void erc_antaddantennaobj(ANTENNAOBJ *ao)
696 {
697 	REGISTER INTBIG i, oldsize, newsize;
698 	REGISTER ANTENNAOBJ **newtable, **oldtable, *oao;
699 
700 	if (erc_antpathhashtablecount*2 >= erc_antpathhashtablesize)
701 	{
702 		/* expand the table */
703 		newsize = erc_antpathhashtablesize * 2;
704 		if (newsize <= erc_antpathhashtablecount*2) newsize = erc_antpathhashtablecount*2 + 50;
705 		newsize = pickprime(newsize);
706 		newtable = (ANTENNAOBJ **)emalloc(newsize * (sizeof (ANTENNAOBJ *)), erc_tool->cluster);
707 		if (newtable == 0) return;
708 
709 		for(i=0; i<newsize; i++)
710 			newtable[i] = NOANTENNAOBJ;
711 
712 		oldtable = erc_antpathhashtable;
713 		oldsize = erc_antpathhashtablesize;
714 
715 		erc_antpathhashtablesize = newsize;
716 		erc_antpathhashtable = newtable;
717 
718 		for(i=0; i<oldsize; i++)
719 		{
720 			oao = oldtable[i];
721 			if (oao == NOANTENNAOBJ) continue;
722 			erc_antinsertantennaobj(oao);
723 		}
724 
725 		if (oldsize > 0) efree((CHAR *)oldtable);
726 	}
727 	erc_antinsertantennaobj(ao);
728 	erc_antpathhashtablecount++;
729 }
730 
erc_antinsertantennaobj(ANTENNAOBJ * ao)731 void erc_antinsertantennaobj(ANTENNAOBJ *ao)
732 {
733 	REGISTER ANTENNAOBJ *oao;
734 	REGISTER INTBIG j, index;
735 
736 	index = erc_antgethash(ao);
737 	for(j=0; j<erc_antpathhashtablesize; j++)
738 	{
739 		oao = erc_antpathhashtable[index];
740 		if (oao == NOANTENNAOBJ)
741 		{
742 			erc_antpathhashtable[index] = ao;
743 			return;
744 		}
745 
746 		index++;
747 		if (index >= erc_antpathhashtablesize) index = 0;
748 	}
749 }
750 
751 /*
752  * Routine to load antenna object "ao" with the hierarchical stack in "stack" that is
753  * "depth" deep.
754  */
erc_antloadantennaobj(ANTENNAOBJ * ao,INTBIG depth,NODEINST ** stack)755 void erc_antloadantennaobj(ANTENNAOBJ *ao, INTBIG depth, NODEINST **stack)
756 {
757 	REGISTER INTBIG i;
758 
759 	ao->depth = depth;
760 	if (depth > ao->total)
761 	{
762 		if (ao->total > 0) efree((CHAR *)ao->hierstack);
763 		ao->total = 0;
764 		ao->hierstack = (NODEINST **)emalloc(depth * (sizeof (NODEINST *)), erc_tool->cluster);
765 		if (ao->hierstack == 0) return;
766 		ao->total = depth;
767 	}
768 	for(i=0; i<depth; i++) ao->hierstack[i] = stack[i];
769 }
770 
771 /*
772  * Routine to allocate an antenna object and return it.
773  */
erc_antallocantennaobj(void)774 ANTENNAOBJ *erc_antallocantennaobj(void)
775 {
776 	REGISTER ANTENNAOBJ *ao;
777 
778 	if (erc_antantennaobjfree != NOANTENNAOBJ)
779 	{
780 		ao = erc_antantennaobjfree;
781 		erc_antantennaobjfree = ao->nextantennaobj;
782 	} else
783 	{
784 		ao = (ANTENNAOBJ *)emalloc(sizeof (ANTENNAOBJ), erc_tool->cluster);
785 		if (ao == 0) return (NOANTENNAOBJ);
786 		ao->total = 0;
787 	}
788 	return(ao);
789 }
790 
791 /*
792  * Routine to free the antenna object "ao".
793  */
erc_antfreeantennaobj(ANTENNAOBJ * ao)794 void erc_antfreeantennaobj(ANTENNAOBJ *ao)
795 {
796 	ao->nextantennaobj = erc_antantennaobjfree;
797 	erc_antantennaobjfree = ao;
798 }
799 
800 /*
801  * Routine to return the maximum antenna ratio for analysis at level "level".
802  */
erc_antratio(INTBIG level)803 INTBIG erc_antratio(INTBIG level)
804 {
805 	REGISTER VARIABLE *var;
806 	REGISTER ARCPROTO *ap;
807 	REGISTER INTBIG fun, total, i, index;
808 
809 	if (erc_anttech != erc_antcachedtech)
810 	{
811 		total = 0;
812 		for(ap = erc_anttech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto) total++;
813 		if (erc_antcachedtech != NOTECHNOLOGY)
814 			efree((CHAR *)erc_antcachedratios);
815 		erc_antcachedratios = (INTBIG *)emalloc(total * SIZEOFINTBIG, erc_tool->cluster);
816 		if (erc_antcachedratios == 0) return(ERCDEFMETALLIMIT);
817 		for(i=0; i<total; i++) erc_antcachedratios[i] = ERCDEFMETALLIMIT;
818 
819 		var = getvalkey((INTBIG)erc_anttech, VTECHNOLOGY, VINTEGER|VISARRAY, erc_antennaarcratiokey);
820 
821 		for(ap = erc_anttech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
822 		{
823 			fun = (ap->userbits&AFUNCTION) >> AFUNCTIONSH;
824 			switch (fun)
825 			{
826 				case APPOLY1:   index = ERCANTLEVEL1;     break;
827 				case APMETAL1:  index = ERCANTLEVEL1+1;   break;
828 				case APMETAL2:  index = ERCANTLEVEL1+2;   break;
829 				case APMETAL3:  index = ERCANTLEVEL1+3;   break;
830 				case APMETAL4:  index = ERCANTLEVEL1+4;   break;
831 				case APMETAL5:  index = ERCANTLEVEL1+5;   break;
832 				case APMETAL6:  index = ERCANTLEVEL1+6;   break;
833 				case APMETAL7:  index = ERCANTLEVEL1+7;   break;
834 				case APMETAL8:  index = ERCANTLEVEL1+8;   break;
835 				case APMETAL9:  index = ERCANTLEVEL1+9;   break;
836 				case APMETAL10: index = ERCANTLEVEL1+10;  break;
837 				case APMETAL11: index = ERCANTLEVEL1+11;  break;
838 				case APMETAL12: index = ERCANTLEVEL1+12;  break;
839 				default:        index = 0;                break;
840 			}
841 			if (index == 0) continue;
842 			if (index == ERCANTLEVEL1) erc_antcachedratios[index-2] = ERCDEFPOLYLIMIT; else
843 				erc_antcachedratios[index-2] = ERCDEFMETALLIMIT;
844 			if (var != NOVARIABLE && ap->arcindex < getlength(var))
845 				erc_antcachedratios[index-2] = ((INTBIG *)var->addr)[ap->arcindex];
846 		}
847 		erc_antcachedtech = erc_anttech;
848 	}
849 	return(erc_antcachedratios[level-2]);
850 }
851 
852 /* Antenna Rules Options */
853 static DIALOGITEM erc_antruldialogitems[] =
854 {
855  /*  1 */ {0, {204,208,228,288}, BUTTON, N_("OK")},
856  /*  2 */ {0, {204,32,228,112}, BUTTON, N_("Cancel")},
857  /*  3 */ {0, {24,8,168,316}, SCROLL, x_("")},
858  /*  4 */ {0, {4,4,20,160}, MESSAGE, N_("Arcs in technology:")},
859  /*  5 */ {0, {4,160,20,316}, MESSAGE, x_("")},
860  /*  6 */ {0, {172,216,188,312}, EDITTEXT, x_("")},
861  /*  7 */ {0, {172,8,188,208}, MESSAGE, N_("Maximum antenna ratio:")}
862 };
863 static DIALOG erc_antruldialog = {{75,75,312,401}, N_("Antenna Rules Options"), 0, 7, erc_antruldialogitems, 0, 0};
864 
865 /* special items for the "ERC Options" dialog: */
866 #define DANT_ARCLIST     3		/* List of arcs (scroll) */
867 #define DANT_TECHNAME    5		/* Current technology name (stat text) */
868 #define DANT_NEWRATIO    6		/* New ratio for selected arc (edit text) */
869 
erc_antoptionsdlog(void)870 void erc_antoptionsdlog(void)
871 {
872 	REGISTER INTBIG itemHit, fun, amt, i, total, which, *original;
873 	REGISTER void *dia, *infstr;
874 	CHAR buf[50];
875 	REGISTER ARCPROTO *ap, **aplist;
876 	REGISTER VARIABLE *var;
877 
878 	dia = DiaInitDialog(&erc_antruldialog);
879 	if (dia == 0) return;
880 	DiaSetText(dia, DANT_TECHNAME, el_curtech->techname);
881 	DiaInitTextDialog(dia, DANT_ARCLIST, DiaNullDlogList, DiaNullDlogItem,
882 		DiaNullDlogDone, -1, SCSELMOUSE|SCREPORT);
883 	var = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VINTEGER|VISARRAY, erc_antennaarcratiokey);
884 	total = 0;
885 	for(ap = el_curtech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto) total++;
886 	if (total > 0)
887 	{
888 		original = (INTBIG *)emalloc(total * SIZEOFINTBIG, erc_tool->cluster);
889 		if (original == 0) return;
890 		aplist = (ARCPROTO **)emalloc(total * (sizeof (ARCPROTO *)), erc_tool->cluster);
891 		if (aplist == 0) return;
892 		for(i=0; i<total; i++) aplist[i] = NOARCPROTO;
893 	}
894 	i = 0;
895 	for(ap = el_curtech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
896 	{
897 		if ((ap->userbits&ANOTUSED) != 0) continue;
898 		fun = (ap->userbits&AFUNCTION) >> AFUNCTIONSH;
899 		if (fun == APPOLY1) amt = ERCDEFPOLYLIMIT; else
900 			amt = ERCDEFMETALLIMIT;
901 		if (var != NOVARIABLE && ap->arcindex < getlength(var))
902 			amt = ((INTBIG *)var->addr)[ap->arcindex];
903 		ap->temp1 = amt;
904 		aplist[i] = ap;
905 		original[i] = amt;
906 		i++;
907 		infstr = initinfstr();
908 		formatinfstr(infstr, x_("%s (%ld)"), ap->protoname, amt);
909 		DiaStuffLine(dia, DANT_ARCLIST, returninfstr(infstr));
910 	}
911 	DiaSelectLine(dia, DANT_ARCLIST, 0);
912 	if (aplist[0] != NOARCPROTO)
913 	{
914 		esnprintf(buf, 50, x_("%ld"), aplist[0]->temp1);
915 		DiaSetText(dia, DANT_NEWRATIO, buf);
916 	}
917 
918 	/* loop until done */
919 	for(;;)
920 	{
921 		itemHit = DiaNextHit(dia);
922 		if (itemHit == OK || itemHit == CANCEL) break;
923 		if (itemHit == DANT_ARCLIST)
924 		{
925 			which = DiaGetCurLine(dia, DANT_ARCLIST);
926 			if (aplist[which] == NOARCPROTO) continue;
927 			esnprintf(buf, 50, x_("%ld"), aplist[which]->temp1);
928 			DiaSetText(dia, DANT_NEWRATIO, buf);
929 			continue;
930 		}
931 		if (itemHit == DANT_NEWRATIO)
932 		{
933 			which = DiaGetCurLine(dia, DANT_ARCLIST);
934 			if (aplist[which] == NOARCPROTO) continue;
935 			aplist[which]->temp1 = eatoi(DiaGetText(dia, DANT_NEWRATIO));
936 			infstr = initinfstr();
937 			formatinfstr(infstr, x_("%s (%ld)"), aplist[which]->protoname, aplist[which]->temp1);
938 			DiaSetScrollLine(dia, DANT_ARCLIST, which, returninfstr(infstr));
939 			continue;
940 		}
941 	}
942 
943 	if (itemHit != CANCEL)
944 	{
945 		for(i=0; i<total; i++)
946 		{
947 			if (aplist[i] == NOARCPROTO) continue;
948 			if (aplist[i]->temp1 != original[i]) break;
949 		}
950 		if (i < total)
951 		{
952 			i = 0;
953 			for(ap = el_curtech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
954 				original[i++] = ap->temp1;
955 			setvalkey((INTBIG)el_curtech, VTECHNOLOGY, erc_antennaarcratiokey,
956 				(INTBIG)original, VINTEGER|VISARRAY|(total<<VLENGTHSH));
957 		}
958 	}
959 	DiaDoneDialog(dia);
960 }
961 
962 #endif  /* ERCTOOL - at top */
963