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