1 /*--------------------------------------------------------------*/
2 /* antenna.c -- Compute the metal area to gate area for all */
3 /* routes and determine where antenna violations occur. Then, */
4 /* resolve the violations by routing from each violation to an */
5 /* antenna tap. */
6 /* */
7 /* To be done: If there are no antenna cells placed, or if */
8 /* the antenna route fails, or if the antenna violation is */
9 /* close to the limit, see if the route can be adjusted by */
10 /* moving the route to a higher layer near the gate. */
11 /*--------------------------------------------------------------*/
12 /* Written by Tim Edwards, May 2018 */
13 /*--------------------------------------------------------------*/
14
15 #include <ctype.h>
16 #include <stdio.h>
17 #include <math.h>
18 #include <stdarg.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <sys/types.h>
23 #include <regex.h>
24 #include <assert.h>
25
26 /* This entire file is dependent on the Tcl/Tk version */
27 #ifdef TCL_QROUTER
28 #include <tk.h>
29
30 #include "qrouter.h"
31 #include "qconfig.h"
32 #include "mask.h"
33 #include "maze.h"
34 #include "node.h"
35 #include "lef.h"
36 #include "def.h"
37 #include "point.h"
38
39 /* Node Hash Table routines taken from delay.c */
40 extern GATE FindGateNode(Tcl_HashTable *, NODE, int *);
41 extern void FreeNodeTable(Tcl_HashTable *);
42
43 extern int TotalRoutes;
44
45 /* Structure to hold information about an antenna error. */
46
47 typedef struct antennainfo_ *ANTENNAINFO;
48
49 struct antennainfo_ {
50 ANTENNAINFO next; /* Next antenna violation in the list. */
51 NET net; /* The net violating an antenna rule */
52 NODE node; /* A gate-end node that is in violation */
53 ROUTE route; /* A route that is part of the antenna */
54 int layer; /* Uppermost metal layer of the antenna */
55 };
56
57 /* Keep the list as a global variable so it can be accessed */
58 /* from doroute() (in qrouter.c) */
59
60 ANTENNAINFO AntennaList;
61
62 typedef struct annotateinfo_ *ANNOTATEINFO;
63
64 struct annotateinfo_ {
65 ANNOTATEINFO next;
66 NET net;
67 char *instance;
68 char *pin;
69 int flag; /* Flag for checking output status */
70 };
71
72 ANNOTATEINFO AnnotateList = NULL;
73
74 #define ANNO_INIT 0
75 #define ANNO_OUTPUT 1
76
77 /*----------------------------------------------------------------------*/
78 /* Report connection of a fixed antenna violation, given the net. */
79 /*----------------------------------------------------------------------*/
80
get_annotate_info(NET net,char ** pinptr)81 char *get_annotate_info(NET net, char **pinptr)
82 {
83 ANNOTATEINFO annotate;
84
85 for (annotate = AnnotateList; annotate; annotate = annotate->next) {
86 if (annotate->net->netnum == net->netnum) {
87 if (annotate->flag == ANNO_INIT) {
88 annotate->flag = ANNO_OUTPUT; /* Mark as having been output */
89 *pinptr = annotate->pin;
90 return annotate->instance;
91 }
92 }
93 }
94 *pinptr = NULL;
95 return NULL;
96 }
97
98 /*--------------------------------------------------------------*/
99 /* Regular expression matching of the given string in */
100 /* "antennacell" to the string "strtest". If the regular */
101 /* expression matches and the result is in the first character */
102 /* position of the string, then return TRUE (match), otherwise */
103 /* return FALSE (no match). */
104 /*--------------------------------------------------------------*/
105
106 u_char
string_match(char * antennacell,char * strtest)107 string_match(char *antennacell, char *strtest)
108 {
109 regex_t regex;
110 regmatch_t pmatch;
111 int reti;
112
113 /* Compile regular expression */
114 reti = regcomp(®ex, antennacell, 0);
115 if (reti) {
116 /* Assume this is not a regular expression and just run */
117 /* a straight string match. */
118 if (!strcasecmp(antennacell, strtest))
119 return TRUE;
120 else
121 return FALSE;
122 }
123
124 /* Execute regular expression */
125 reti = regexec(®ex, strtest, 1, &pmatch, 0);
126 regfree(®ex);
127
128 if (!reti) {
129 if (pmatch.rm_so == 0) /* Must match beginning of string */
130 return TRUE;
131 else
132 return FALSE;
133 }
134 else
135 return FALSE;
136 }
137
138 /*--------------------------------------------------------------*/
139 /* Find free antenna cells, and collect all the antenna taps */
140 /* into a single net, much like VDD_NET or GND_NET. */
141 /* */
142 /* Return the number of free antenna taps available in the */
143 /* layout. */
144 /* */
145 /* If the name of the antennacell ends in '*', then assume a */
146 /* wildcard character and match to any string beginning with */
147 /* the substring of antennacell. */
148 /*--------------------------------------------------------------*/
149
150 void
find_free_antenna_taps(char * antennacell)151 find_free_antenna_taps(char *antennacell)
152 {
153 int numtaps;
154 GATE ginst;
155 GATE gateginfo;
156 NODE noderec;
157 int netnum, i;
158
159 if (antennacell == NULL) {
160 Fprintf(stderr, "No antenna cell defined!\n");
161 return;
162 }
163 numtaps = 0;
164 for (ginst = Nlgates; ginst; ginst = ginst->next) {
165 gateginfo = ginst->gatetype;
166
167 if (string_match(antennacell, gateginfo->gatename)) {
168 /* Find an unassigned node. If there is not one, */
169 /* this is probably a routed (not free) cell. */
170 for (i = 0; i < ginst->nodes; i++) {
171 netnum = ginst->netnum[i];
172 noderec = ginst->noderec[i];
173 if ((netnum == 0) && (noderec == NULL)) {
174 ginst->netnum[i] = ANTENNA_NET;
175 ginst->noderec[i] = (NODE)calloc(1, sizeof(struct node_));
176 ginst->noderec[i]->netnum = ANTENNA_NET;
177 }
178 }
179 }
180 }
181 }
182
183 /*--------------------------------------------------------------*/
184 /* Similar to the routine above, but just count the free taps. */
185 /*--------------------------------------------------------------*/
186
187 int
count_free_antenna_taps(char * antennacell)188 count_free_antenna_taps(char *antennacell)
189 {
190 int numtaps;
191 GATE ginst;
192 GATE gateginfo;
193 int netnum, i;
194
195 numtaps = 0;
196 for (ginst = Nlgates; ginst; ginst = ginst->next) {
197 gateginfo = ginst->gatetype;
198
199 if (string_match(antennacell, gateginfo->gatename)) {
200 /* Find an unassigned node. If there is not one, */
201 /* this is probably a routed (not free) cell. */
202 for (i = 0; i < ginst->nodes; i++) {
203 netnum = ginst->netnum[i];
204 if (netnum == ANTENNA_NET)
205 numtaps++;
206 }
207 }
208 }
209 return numtaps;
210 }
211
212 /*--------------------------------------------------------------*/
213 /* After routing, the free antenna taps are all marked with the */
214 /* net number of the net just routed. To make them free again, */
215 /* change all but the one that was routed back to ANTENNA_NET. */
216 /* Identify the unused taps by finding the OBSVAL record with */
217 /* net set to netnum but not connected to the same node. */
218 /*--------------------------------------------------------------*/
219
revert_antenna_taps(int netnum,NODE node)220 void revert_antenna_taps(int netnum, NODE node)
221 {
222 int x, y, lay;
223 PROUTE *Pr;
224 NODEINFO lnode = NULL;
225
226 /* Clear all targets except for the one just routed */
227
228 for (lay = 0; lay < Num_layers; lay++)
229 for (x = 0; x < NumChannelsX; x++)
230 for (y = 0; y < NumChannelsY; y++)
231 if ((OBSVAL(x, y, lay) & NETNUM_MASK) == netnum) {
232 Pr = &OBS2VAL(x, y, lay);
233 if (Pr->flags & PR_TARGET) {
234 lnode = NODEIPTR(x, y, lay);
235 if ((lnode == NULL) || (lnode->nodesav != node)) {
236 OBSVAL(x, y, lay) &= ~(NETNUM_MASK | ROUTED_NET);
237 OBSVAL(x, y, lay) |= ANTENNA_NET;
238 }
239 }
240 }
241 }
242
243 /*--------------------------------------------------------------*/
244 /* States to track nodes as they are processed: */
245 /* */
246 /* NOT_VISITED : Node has not yet been processed. */
247 /* VISITED : Node was counted on this pass. */
248 /* PROCESSED : Node was counted on a previous pass. */
249 /* ANCHOR : Node is a source/drain connection. */
250 /*--------------------------------------------------------------*/
251
252 enum visit_states {NOT_VISITED = 0, VISITED, PROCESSED, ANCHOR};
253
254 /* Forward declarations */
255 float get_route_area_reverse(NET, ROUTE, int, u_char *, u_char,
256 Tcl_HashTable *, struct routeinfo_ *);
257 float get_route_area_forward(NET, ROUTE, int, u_char *, u_char,
258 Tcl_HashTable *, struct routeinfo_ *);
259 float get_route_area_reverse_fromseg(NET, ROUTE, SEG, int, u_char *, u_char,
260 Tcl_HashTable *, struct routeinfo_ *);
261
262 /*--------------------------------------------------------------*/
263 /* Determine the amount of metal in the route, starting at the */
264 /* route start point, and not moving past any point that is */
265 /* above "layer". Check all other unvisited routes in net to */
266 /* see if any connect to "rt". If so, check if they connect */
267 /* to a point that is part of the subnet below or at "layer". */
268 /* If they do, recursively run get_route_area_forward on that */
269 /* route. When done, return the total area of the subnet. */
270 /*--------------------------------------------------------------*/
271
272 float
get_route_area_forward_fromseg(NET net,ROUTE rt,SEG nseg,int layer,u_char * visited,u_char method,Tcl_HashTable * NodeTable,struct routeinfo_ * iroute)273 get_route_area_forward_fromseg(NET net, ROUTE rt, SEG nseg, int layer,
274 u_char *visited, u_char method, Tcl_HashTable *NodeTable,
275 struct routeinfo_ *iroute)
276 {
277 float area, length, width, thick;
278 int x, y, l, compat;
279 SEG seg, iseg, chkseg;
280 ROUTE rt2;
281 u_char found;
282
283 if (rt->flags & RT_VISITED) return 0.0;
284 rt->flags |= RT_VISITED;
285 area = 0.0;
286
287 /* If nseg is NULL then check from the beginning. */
288 if (nseg == NULL) nseg = rt->segments;
289
290 /* Check if the route beginning is a node */
291 if (nseg == rt->segments) {
292 if (rt->flags & RT_START_NODE) {
293 NODE node;
294 GATE g;
295 int i;
296
297 node = rt->start.node;
298
299 if (visited) {
300
301 /* If more than one route is connected to the node, */
302 /* then this node may have been visited already. */
303
304 if (visited[node->nodenum] == NOT_VISITED) {
305 g = FindGateNode(NodeTable, node, &i);
306 if (g->area[i] == 0.0) {
307 /* There's a diffusion diode here! */
308 visited[node->nodenum] = ANCHOR;
309 return 0.0;
310 } else {
311 /* Add this node to the list of nodes with gates */
312 /* attached to this antenna area. */
313 visited[node->nodenum] = VISITED;
314 }
315 }
316 }
317 else if ((method == ANTENNA_ROUTE) && (iroute != NULL)) {
318 set_node_to_net(node, PR_SOURCE, &iroute->glist[0], &iroute->bbox, 0);
319 }
320
321 /* Walk all other routes that start or end on this node */
322
323 for (rt2 = net->routes; rt2; rt2 = rt2->next) {
324 if (rt2->flags & RT_VISITED) continue;
325
326 if ((rt2->flags & RT_START_NODE) && (rt2->start.node == node)) {
327 /* The start point of rt2 connects to the same node */
328 area += get_route_area_forward(net, rt2, layer, visited,
329 method, NodeTable, NULL);
330 }
331 else if ((rt2->flags & RT_END_NODE) && (rt2->end.node == node)) {
332 /* The end point of rt2 connects to the same node */
333 for (iseg = rt2->segments; iseg && iseg->next; iseg = iseg->next);
334 area += get_route_area_reverse(net, rt2, layer, visited,
335 method, NodeTable, NULL);
336 }
337 }
338 }
339 }
340
341 for (seg = rt->segments; seg && (seg != nseg); seg = seg->next);
342 if (seg == NULL) return 0.0;
343
344 for (; seg; seg = seg->next) {
345
346 /* Once the layer goes above the current check layer, the search stops. */
347 if (method != ANTENNA_DISABLE)
348 if (seg->layer > layer) break;
349
350 /* Vias don't contribute to area, at least for now. */
351 if (seg->segtype & ST_VIA) continue;
352
353 /* For non-cumulative methods, only count area for */
354 /* those segments which are on the given check layer. */
355
356 if ((method == CALC_AREA) || (method == CALC_SIDEAREA))
357 if (seg->layer != layer)
358 continue;
359
360 /* method ANTENNA_ROUTE indicates that this routine was */
361 /* called as part of antenna routing. So set up this */
362 /* part of the route in a manner similar to the */
363 /* set_route_to_net() routine. */
364
365 if ((method == ANTENNA_ROUTE) && (iroute != NULL)) {
366 PROUTE *Pr;
367 POINT gpoint;
368
369 l = seg->layer;
370 x = seg->x1;
371 y = seg->y1;
372 while (1) {
373 Pr = &OBS2VAL(x, y, l);
374 Pr->flags = PR_SOURCE;
375 Pr->prdata.cost = 0;
376
377 if (~(Pr->flags & PR_ON_STACK)) {
378 Pr->flags |= PR_ON_STACK;
379 gpoint = allocPOINT();
380 gpoint->x1 = x;
381 gpoint->y1 = y;
382 gpoint->layer = l;
383 gpoint->next = iroute->glist[0];
384 iroute->glist[0] = gpoint;
385 }
386
387 if (x < iroute->bbox.x1) iroute->bbox.x1 = x;
388 if (x > iroute->bbox.x2) iroute->bbox.x2 = x;
389 if (y < iroute->bbox.y1) iroute->bbox.y1 = y;
390 if (y > iroute->bbox.y2) iroute->bbox.y2 = y;
391
392 // Move to next grid position in the segment
393 if (x == seg->x2 && y == seg->y2) break;
394 if (seg->x2 > seg->x1) x++;
395 else if (seg->x2 < seg->x1) x--;
396 if (seg->y2 > seg->y1) y++;
397 else if (seg->y2 < seg->y1) y--;
398 }
399 }
400 else if (method == ANTENNA_DISABLE) {
401 PROUTE *Pr;
402
403 l = seg->layer;
404 x = seg->x1;
405 y = seg->y1;
406 while (1) {
407 Pr = &OBS2VAL(x, y, l);
408 Pr->prdata.net = MAXNETNUM;
409 Pr->flags &= ~(PR_SOURCE | PR_TARGET | PR_COST);
410
411 // Move to next grid position in the segment
412 if (x == seg->x2 && y == seg->y2) break;
413 if (seg->x2 > seg->x1) x++;
414 else if (seg->x2 < seg->x1) x--;
415 if (seg->y2 > seg->y1) y++;
416 else if (seg->y2 < seg->y1) y--;
417 }
418 }
419 if ((method != ANTENNA_ROUTE) && (method != ANTENNA_DISABLE)) {
420
421 /* Note that one of x or y is zero, depending on segment orientation */
422 x = (seg->x2 - seg->x1);
423 y = (seg->y2 - seg->y1);
424 if (x < 0) x = -x;
425 if (y < 0) y = -y;
426
427 /* Note that "l" is a unitless grid dimension */
428 if (x == 0)
429 length = (float)y * (float)PitchY;
430 else
431 length = (float)x * (float)PitchX;
432
433 /* area is either the total top surface of the metal, */
434 /* or the total side surface of the metal (in um^2) */
435
436 width = LefGetRouteWidth(seg->layer);
437 if ((method == CALC_AREA) || (method == CALC_AGG_AREA))
438 area += (float)(length * width);
439 else if ((method == CALC_SIDEAREA) || (method == CALC_AGG_SIDEAREA)) {
440 thick = LefGetRouteThickness(seg->layer);
441 area += thick * 2.0 * (length + width);
442 }
443 }
444 }
445
446 /* Check other routes for intersection with this route */
447
448 for (rt2 = net->routes; rt2; rt2 = rt2->next) {
449 if (rt2->flags & RT_VISITED) continue;
450
451 if (!(rt2->flags & RT_START_NODE) && (rt2->start.route == rt)) {
452 /* The start point of rt2 connects somewhere on rt */
453 iseg = rt2->segments;
454 x = iseg->x1;
455 y = iseg->y1;
456 l = iseg->layer;
457 if (l > layer) continue;
458 }
459 else if (!(rt2->flags & RT_END_NODE) && (rt2->end.route == rt)) {
460 /* The end point of rt2 connects somewhere on rt */
461 for (iseg = rt2->segments; iseg && iseg->next; iseg = iseg->next);
462 x = iseg->x2;
463 y = iseg->y2;
464 l = iseg->layer;
465 if (l > layer) continue;
466 }
467 else
468 continue;
469
470 /* Must determine if rt2 intersects rt within the antenna area */
471
472 found = (u_char)0;
473 for (chkseg = rt->segments; chkseg && chkseg != seg; chkseg = chkseg->next) {
474 if (chkseg->segtype & ST_WIRE) {
475 if (iseg->segtype & ST_WIRE) {
476 compat = (l == chkseg->layer);
477 }
478 else {
479 compat = (l == chkseg->layer) || (l + 1 == chkseg->layer);
480 }
481 }
482 else {
483 if (iseg->segtype & ST_WIRE) {
484 compat = (l == chkseg->layer) || (l == chkseg->layer + 1);
485 }
486 else {
487 compat = (l == chkseg->layer) || (l == chkseg->layer + 1) ||
488 (l + 1 == chkseg->layer);
489 }
490 }
491 if (!compat) continue;
492
493 if (chkseg->segtype & ST_VIA) {
494 if ((chkseg->x1 == x) && (chkseg->y1 == y)) {
495 found = (u_char)1;
496 break;
497 }
498 }
499 else if (chkseg->x1 < chkseg->x2) {
500 if (chkseg->y1 == y) {
501 if ((chkseg->x1 <= x) && (chkseg->x2 >= x)) {
502 found = (u_char)1;
503 break;
504 }
505 }
506 }
507 else if (chkseg->x1 > chkseg->x2) {
508 if (chkseg->y1 == y) {
509 if ((chkseg->x1 >= x) && (chkseg->x2 <= x)) {
510 found = (u_char)1;
511 break;
512 }
513 }
514 }
515 else if (chkseg->y1 < chkseg->y2) {
516 if (chkseg->x1 == x) {
517 if ((chkseg->y1 <= y) && (chkseg->y2 >= y)) {
518 found = (u_char)1;
519 break;
520 }
521 }
522 }
523 else if (chkseg->y1 > chkseg->y2) {
524 if (chkseg->x1 == x) {
525 if ((chkseg->y1 >= y) && (chkseg->y2 <= y)) {
526 found = (u_char)1;
527 break;
528 }
529 }
530 }
531 }
532 if (found == (u_char)1) {
533 if (rt2->start.route == rt)
534 area += get_route_area_forward(net, rt2, layer, visited,
535 method, NodeTable, iroute);
536 else
537 area += get_route_area_reverse(net, rt2, layer, visited,
538 method, NodeTable, iroute);
539 }
540 }
541
542 /* The end of this route may be a node (so record it in visited) or */
543 /* a route (so walk it). */
544
545 if (seg == NULL) { /* If seg != NULL then we didn't reach the route end */
546 if (rt->flags & RT_END_NODE) {
547 NODE node;
548 GATE g;
549 int i;
550
551 node = rt->end.node;
552
553 /* Walk all other routes that start or end on this node */
554
555 for (rt2 = net->routes; rt2; rt2 = rt2->next) {
556 if (rt2->flags & RT_VISITED) continue;
557
558 if ((rt2->flags & RT_START_NODE) && (rt2->start.node == node)) {
559 /* The start point of rt2 connects to the same node */
560 area += get_route_area_forward(net, rt2, layer, visited,
561 method, NodeTable, NULL);
562 }
563 else if ((rt2->flags & RT_END_NODE) && (rt2->end.node == node)) {
564 /* The end point of rt2 connects to the same node */
565 for (iseg = rt2->segments; iseg && iseg->next; iseg = iseg->next);
566 area += get_route_area_reverse(net, rt2, layer, visited,
567 method, NodeTable, NULL);
568 }
569 }
570
571 g = FindGateNode(NodeTable, node, &i);
572 if (g == NULL) {
573 /* This should not happen */
574 Fprintf(stderr, "Error: net %s route end marked as node, but"
575 " no node found!\n", net->netname);
576 return 0.0;
577 }
578 if (g->area[i] == 0.0) {
579 /* There's a diffusion diode here! */
580 if (visited) visited[node->nodenum] = ANCHOR;
581 return 0.0;
582 } else {
583 /* Add this node to the list of nodes with gates */
584 /* attached to this antenna area. */
585 if (visited) visited[node->nodenum] = VISITED;
586 }
587 if ((method == ANTENNA_ROUTE) && (iroute != NULL)) {
588 set_node_to_net(node, PR_SOURCE, &iroute->glist[0], &iroute->bbox, 0);
589 }
590 }
591 else {
592 SEG rseg;
593
594 /* Back up seg to point to the last segment of the route */
595 for (seg = rt->segments; seg && seg->next; seg = seg->next);
596 x = seg->x2;
597 y = seg->y2;
598 l = seg->layer;
599
600 /* Find where on rt2 the segment lands, then search rt2 for */
601 /* antenna area forward and reverse from that segment. */
602
603 rt2 = rt->end.route;
604 assert( rt2 != NULL ) ;
605
606 for (rseg = rt2->segments; rseg; rseg = rseg->next) {
607 if (rseg->segtype & ST_WIRE) {
608 if (seg->segtype & ST_WIRE) {
609 compat = (l == rseg->layer);
610 }
611 else {
612 compat = (l == rseg->layer) || (l + 1 == rseg->layer);
613 }
614 }
615 else {
616 if (seg->segtype & ST_WIRE) {
617 compat = (l == rseg->layer) || (l == rseg->layer + 1);
618 }
619 else {
620 compat = (l == rseg->layer) || (l == rseg->layer + 1) ||
621 (l + 1 == rseg->layer);
622 }
623 }
624 if (compat) {
625 if (rseg->segtype & ST_VIA) {
626 if ((rseg->x2 == seg->x2) && (rseg->y2 == seg->y2))
627 break;
628 }
629 else if (rseg->x1 < rseg->x2) {
630 if (rseg->y2 == seg->y2) {
631 if ((rseg->x1 <= seg->x2) && (rseg->x2 >= seg->x2))
632 break;
633 }
634 }
635 else if (rseg->x1 > rseg->x2) {
636 if (rseg->y2 == seg->y2) {
637 if ((rseg->x1 >= seg->x2) && (rseg->x2 <= seg->x2))
638 break;
639 }
640 }
641 else if (rseg->y1 < rseg->y2) {
642 if (rseg->x2 == seg->x2) {
643 if ((rseg->y1 <= seg->y2) && (rseg->y2 >= seg->y2))
644 break;
645 }
646 }
647 else if (rseg->y1 > rseg->y2) {
648 if (rseg->x2 == seg->x2) {
649 if ((rseg->y1 >= seg->y2) && (rseg->y2 <= seg->y2))
650 break;
651 }
652 }
653 }
654 }
655 assert( rseg != NULL ) ;
656
657 if (rseg->next != NULL)
658 area += get_route_area_forward_fromseg(net, rt2, rseg->next,
659 layer, visited, method, NodeTable, iroute);
660 area += get_route_area_reverse_fromseg(net, rt2, rseg, layer,
661 visited, method, NodeTable, iroute);
662 }
663 }
664 return area;
665 }
666
667 /*--------------------------------------------------------------*/
668 /* Check route antenna forward from the beginning of the route. */
669 /*--------------------------------------------------------------*/
670
671 float
get_route_area_forward(NET net,ROUTE rt,int layer,u_char * visited,u_char method,Tcl_HashTable * NodeTable,struct routeinfo_ * iroute)672 get_route_area_forward(NET net, ROUTE rt, int layer, u_char *visited,
673 u_char method, Tcl_HashTable *NodeTable, struct routeinfo_ *iroute)
674 {
675 float area;
676
677 area = get_route_area_forward_fromseg(net, rt, NULL, layer, visited,
678 method, NodeTable, iroute);
679 return area;
680 }
681
682 /*--------------------------------------------------------------*/
683 /* This is the same as get_route_area_forward_fromseg, but is */
684 /* searching the path from end to beginning, so reverse the */
685 /* route first and then call get_route_area_forward_fromseg(). */
686 /*--------------------------------------------------------------*/
687
688 float
get_route_area_reverse_fromseg(NET net,ROUTE rt,SEG nseg,int layer,u_char * visited,u_char method,Tcl_HashTable * NodeTable,struct routeinfo_ * iroute)689 get_route_area_reverse_fromseg(NET net, ROUTE rt, SEG nseg, int layer,
690 u_char *visited, u_char method, Tcl_HashTable *NodeTable,
691 struct routeinfo_ *iroute)
692 {
693 SEG seg, dseg, newseg, firstseg, saveseg;
694 NODE savestartnode, saveendnode;
695 float area;
696 u_char saveflags;
697
698 firstseg = NULL;
699
700 /* Reverse the route */
701 for (seg = rt->segments; seg; seg = seg->next) {
702 newseg = (SEG)malloc(sizeof(struct seg_));
703 newseg->layer = seg->layer;
704 newseg->x1 = seg->x2;
705 newseg->x2 = seg->x1;
706 newseg->y1 = seg->y2;
707 newseg->y2 = seg->y1;
708 newseg->segtype = seg->segtype;
709 newseg->next = firstseg;
710 firstseg = newseg;
711 }
712
713 saveseg = rt->segments;
714
715 /* Replace the route segment with the reversed route */
716 rt->segments = firstseg;
717
718 /* Reverse the endpoint information */
719 savestartnode = rt->start.node;
720 saveendnode = rt->end.node;
721 rt->start.node = saveendnode;
722 rt->end.node = savestartnode;
723
724 /* Reverse the start/end flags */
725 saveflags = rt->flags & (RT_START_NODE | RT_END_NODE);
726 rt->flags &= ~(RT_START_NODE | RT_END_NODE);
727 if (saveflags & RT_START_NODE) rt->flags |= RT_END_NODE;
728 if (saveflags & RT_END_NODE) rt->flags |= RT_START_NODE;
729
730 area = get_route_area_forward_fromseg(net, rt, nseg, layer, visited,
731 method, NodeTable, iroute);
732
733 /* Replace the route segment with the original route */
734 rt->segments = saveseg;
735
736 /* Revert the endpoint information */
737 rt->start.node = savestartnode;
738 rt->end.node = saveendnode;
739
740 /* Revert the start/end flags */
741 rt->flags &= ~(RT_START_NODE | RT_END_NODE);
742 rt->flags |= saveflags;
743
744 /* Free the reversed route */
745 for (seg = firstseg; seg; ) {
746 dseg = seg->next;
747 free(seg);
748 seg = dseg;
749 }
750 return area;
751 }
752
753 /*--------------------------------------------------------------*/
754 /* Walk a route in reverse from end to start. */
755 /*--------------------------------------------------------------*/
756
757 float
get_route_area_reverse(NET net,ROUTE rt,int layer,u_char * visited,u_char method,Tcl_HashTable * NodeTable,struct routeinfo_ * iroute)758 get_route_area_reverse(NET net, ROUTE rt, int layer, u_char *visited,
759 u_char method, Tcl_HashTable *NodeTable,
760 struct routeinfo_ *iroute)
761 {
762 float area;
763 area = get_route_area_reverse_fromseg(net, rt, NULL, layer, visited,
764 method, NodeTable, iroute);
765 return area;
766 }
767
768 /*--------------------------------------------------------------*/
769 /* Find all antenna violations at a specific metal layer */
770 /*--------------------------------------------------------------*/
771
find_layer_antenna_violations(int layer,Tcl_HashTable * NodeTable)772 int find_layer_antenna_violations(int layer, Tcl_HashTable *NodeTable)
773 {
774 int numerrors, n, nn, numroutes, i, j, new, neterrors;
775 u_char *visited, method;
776 float antenna_ratio, thick;
777 GATE g;
778 NET net;
779 ROUTE rt, saveroute;
780 NODEINFO nodeptr;
781 NODE node, tnode;
782 SEG seg;
783 ANTENNAINFO newantenna;
784 float gate_area, metal_area, ratio, save_gate, save_metal, max_ratio;
785
786 numerrors = 0;
787
788 /* Get the metal layer record for this layer and find the metal */
789 /* area ratio limit and the method to be used for calculating */
790 /* metal area. */
791
792 method = LefGetRouteAntennaMethod(layer);
793 if (method == CALC_NONE) return 0; /* No antenna information in tech */
794 antenna_ratio = (float)LefGetRouteAreaRatio(layer);
795 thick = (float)LefGetRouteThickness(layer);
796 if (((method == CALC_SIDEAREA) || (method == CALC_AGG_SIDEAREA)) && (thick == 0.0))
797 return 0; /* Insufficient antenna information in tech */
798
799 /* Make a pass through all nets to find antenna violations */
800
801 for (n = 0; n < Numnets; n++) {
802 net = Nlnets[n];
803
804 if ((net->netnum == VDD_NET) || (net->netnum == GND_NET) ||
805 (net->netnum == ANTENNA_NET)) continue;
806
807 /* Ignore nets with no routes */
808 numroutes = 0;
809 for (rt = net->routes; rt; rt = rt->next) numroutes++;
810 if (numroutes == 0) continue;
811
812 /* Consider each terminal as a separate sub-net calculation. */
813 /* But if multiple terminals belong to the same sub-net, they */
814 /* are marked visited and ignored on subsequent calculations. */
815
816 visited = (u_char *)malloc(net->numnodes * sizeof(u_char));
817 for (node = net->netnodes; node != NULL; node = node->next) {
818 nn = node->nodenum;
819 visited[nn] = NOT_VISITED;
820 }
821
822 /* Make a pass through all nodes of the net. Where they are */
823 /* not connected together at "layer", these are individual */
824 /* sub-nets. */
825
826 neterrors = 0;
827 max_ratio = 0.0; /* For diagnostics only */
828 for (node = net->netnodes; node != NULL; node = node->next) {
829 nn = node->nodenum;
830 if (visited[nn] >= PROCESSED) continue; /* Already seen */
831
832 /* Find the gate area of this node */
833 g = FindGateNode(NodeTable, node, &i);
834 metal_area = 0.0;
835
836 if (g->area[i] == 0.0) {
837 visited[nn] = ANCHOR; /* Mark as S/D connection */
838 continue; /* No gate, so no violation */
839 }
840 else
841 visited[nn] = VISITED;
842
843 /* Clear visited flags for routes */
844
845 for (rt = net->routes; rt; rt = rt->next)
846 rt->flags &= ~RT_VISITED;
847
848 /* Find the route or routes that connect to this node */
849
850 for (rt = net->routes; rt; rt = rt->next) {
851 if ((rt->flags & RT_START_NODE) && (rt->start.node == node)) {
852 saveroute = rt;
853 metal_area += get_route_area_forward(net, rt, layer, visited,
854 method, NodeTable, NULL);
855 }
856 else if ((rt->flags & RT_END_NODE) && (rt->end.node == node)) {
857 saveroute = rt;
858 metal_area += get_route_area_reverse(net, rt, layer, visited,
859 method, NodeTable, NULL);
860 }
861 else continue;
862 }
863
864 /* Gate area is combined area of gates visited */
865
866 gate_area = 0.0;
867 for (tnode = net->netnodes; tnode != NULL; tnode = tnode->next) {
868 j = tnode->nodenum;
869 if (visited[j] == VISITED) {
870 g = FindGateNode(NodeTable, tnode, &i);
871 if (g->area[i] == 0.0) {
872 visited[j] = ANCHOR;
873 gate_area = 0.0;
874 break;
875 }
876 else
877 gate_area += g->area[i];
878 }
879
880 }
881
882 if (gate_area > 0.0) {
883 ratio = metal_area / gate_area;
884 if (ratio > max_ratio) {
885 max_ratio = ratio;
886 save_gate = gate_area;
887 save_metal = metal_area;
888 }
889
890 if (ratio > antenna_ratio) {
891
892 /* Record and report the violation */
893
894 numerrors++;
895 neterrors++;
896 if (Verbose > 1) {
897 Fprintf(stderr,
898 "Antenna violation on node %d of net %s at metal%d\n",
899 nn, net->netname, layer + 1);
900 }
901 if (Verbose > 2) {
902 Fprintf(stderr, "Metal area = %f, Gate area = %f, Ratio = %f\n",
903 metal_area, gate_area, ratio);
904 }
905 newantenna = (ANTENNAINFO)malloc(sizeof(struct antennainfo_));
906 newantenna->net = net;
907 newantenna->node = node;
908 newantenna->layer = layer;
909 newantenna->route = saveroute;
910 newantenna->next = AntennaList;
911 AntennaList = newantenna;
912 }
913 }
914
915 /* Mark gates as visited on previous pass */
916 for (tnode = net->netnodes; tnode != NULL; tnode = tnode->next) {
917 j = tnode->nodenum;
918 if (visited[j] == VISITED) visited[j] = PROCESSED;
919 }
920 }
921 free(visited);
922
923 if (Verbose > 3) {
924 /* Diagnostic */
925 if (neterrors == 0) {
926 if (max_ratio > 0.0)
927 Fprintf(stderr, "Worst case: Metal area = %f, Gate area = %f, "
928 "Ratio = %f\n", save_metal, save_gate, max_ratio);
929 }
930 }
931
932 /* Clear route visited flags */
933 for (rt = net->routes; rt; rt = rt->next)
934 rt->flags &= ~RT_VISITED;
935 }
936 return numerrors;
937 }
938
939 /*--------------------------------------------------------------*/
940 /* This routine is a combination of set_node_to_net(), */
941 /* set_routes_to_net(), and disable_node_nets() (see qrouter.c */
942 /* and maze.c), but walks the routes in the same manner used */
943 /* for finding the antenna violations. Set the antenna part of */
944 /* the net as SOURCE, the free antenna taps as TARGET, and the */
945 /* non-antenna portion of the net to an unused net number, */
946 /* which can be converted back after routing. */
947 /*--------------------------------------------------------------*/
948
set_antenna_to_net(int newflags,struct routeinfo_ * iroute,u_char stage,ANTENNAINFO violation,Tcl_HashTable * NodeTable)949 int set_antenna_to_net(int newflags, struct routeinfo_ *iroute,
950 u_char stage, ANTENNAINFO violation, Tcl_HashTable *NodeTable)
951 {
952 int x, y, lay, rval, layer;
953 PROUTE *Pr;
954 ROUTE rt, clrrt;
955 NODE node;
956 NET net;
957
958 /* Set the node and connected antenna metal routes to PR_SOURCE. */
959
960 rt = violation->route;
961 node = violation->node;
962 net = violation->net;
963 layer = violation->layer;
964
965 if ((rt->flags & RT_START_NODE) && (rt->start.node == node))
966 get_route_area_forward(net, rt, layer, NULL, ANTENNA_ROUTE, NodeTable,
967 iroute);
968 else if ((rt->flags & RT_END_NODE) && (rt->end.node == node))
969 get_route_area_reverse(net, rt, layer, NULL, ANTENNA_ROUTE, NodeTable,
970 iroute);
971 else {
972 /* This should not happen */
973 Fprintf(stderr, "Error: Antenna route and node do not connect!\n");
974 return 1;
975 }
976
977 /* Clear route visited flags for next pass */
978 for (clrrt = iroute->net->routes; clrrt; clrrt = clrrt->next)
979 clrrt->flags &= ~RT_VISITED;
980
981 /* Disable the remainder of the route */
982
983 if ((rt->flags & RT_START_NODE) && (rt->start.node == node))
984 get_route_area_forward(net, rt, layer, NULL, ANTENNA_DISABLE, NodeTable,
985 iroute);
986 else if ((rt->flags & RT_END_NODE) && (rt->end.node == node))
987 get_route_area_reverse(net, rt, layer, NULL, ANTENNA_DISABLE, NodeTable,
988 iroute);
989 else {
990 /* This should not happen */
991 Fprintf(stderr, "Error: Antenna route and node do not connect!\n");
992 return 1;
993 }
994
995 /* Done checking routes; clear route visited flags */
996 for (clrrt = iroute->net->routes; clrrt; clrrt = clrrt->next)
997 clrrt->flags &= ~RT_VISITED;
998
999 /* Set the antenna taps to the net number. */
1000 /* Routine is similar to set_powerbus_to_net(). */
1001
1002 rval = 0;
1003 for (lay = 0; lay < Num_layers; lay++)
1004 for (x = 0; x < NumChannelsX; x++)
1005 for (y = 0; y < NumChannelsY; y++)
1006 if ((OBSVAL(x, y, lay) & NETNUM_MASK) == ANTENNA_NET) {
1007 Pr = &OBS2VAL(x, y, lay);
1008 // Skip locations that have been purposefully disabled
1009 if (!(Pr->flags & PR_COST) && (Pr->prdata.net == MAXNETNUM))
1010 continue;
1011 else if (!(Pr->flags & PR_SOURCE)) {
1012 Pr->flags |= (PR_TARGET | PR_COST);
1013 Pr->prdata.cost = MAXRT;
1014 rval = 1;
1015 OBSVAL(x, y, lay) &= ~NETNUM_MASK;
1016 OBSVAL(x, y, lay) |= net->netnum;
1017 }
1018 }
1019
1020 return rval;
1021 }
1022
1023 /*--------------------------------------------------------------*/
1024 /* This routine is similar to route_setup() for the normal */
1025 /* stage routes, with changes for the antenna routing. */
1026 /* Set the node in the "violation" record to source, and set */
1027 /* all free antenna taps to destination. Add existing routes */
1028 /* to the source in the same manner as was used to find the */
1029 /* antenna violation in the first place (this is a subnet of */
1030 /* the complete net). Disable the remainder of the net. */
1031 /* Set all free antenna taps to the net number being routed, */
1032 /* then route like stage 1 power routing. */
1033 /*--------------------------------------------------------------*/
1034
antenna_setup(struct routeinfo_ * iroute,ANTENNAINFO violation,Tcl_HashTable * NodeTable)1035 int antenna_setup(struct routeinfo_ *iroute, ANTENNAINFO violation,
1036 Tcl_HashTable *NodeTable)
1037 {
1038 int i, j, netnum, rval;
1039 PROUTE *Pr;
1040
1041 for (i = 0; i < Num_layers; i++) {
1042 for (j = 0; j < NumChannelsX * NumChannelsY; j++) {
1043 netnum = Obs[i][j] & (~BLOCKED_MASK);
1044 Pr = &Obs2[i][j];
1045 if (netnum != 0) {
1046 Pr->flags = 0; // Clear all flags
1047 if (netnum == DRC_BLOCKAGE)
1048 Pr->prdata.net = netnum;
1049 else
1050 Pr->prdata.net = netnum & NETNUM_MASK;
1051 } else {
1052 Pr->flags = PR_COST; // This location is routable
1053 Pr->prdata.cost = MAXRT;
1054 }
1055 }
1056 }
1057
1058 // Fill out route information record
1059
1060 iroute->net = violation->net;
1061 iroute->rt = NULL;
1062 for (i = 0; i < 6; i++)
1063 iroute->glist[i] = NULL;
1064 iroute->nsrc = violation->node;
1065 iroute->nsrctap = iroute->nsrc->taps;
1066 iroute->maxcost = MAXRT;
1067 iroute->do_pwrbus = TRUE;
1068 iroute->pwrbus_src = 0;
1069
1070 iroute->bbox.x2 = iroute->bbox.y2 = 0;
1071 iroute->bbox.x1 = NumChannelsX;
1072 iroute->bbox.y1 = NumChannelsY;
1073
1074 rval = set_antenna_to_net(PR_SOURCE, iroute, 0, violation, NodeTable);
1075
1076 /* Unlikely that MASK_BBOX would be useful, since one does */
1077 /* not know if an antenna tap is inside the box or not. */
1078 /* Maybe if bounding box is expanded to encompass some */
1079 /* number of taps. . . */
1080
1081 // if (maskMode == MASK_NONE)
1082 fillMask((u_char)0);
1083 // else if (maskMode == MASK_BBOX)
1084 // createBboxMask(iroute->net, (u_char)Numpasses);
1085
1086 iroute->maxcost = 20;
1087 return rval;
1088 }
1089
1090 /*--------------------------------------------------------------*/
1091 /* The simplest way to fix an antenna violation is to find */
1092 /* a place in the antenna metal to break the antenna and pull */
1093 /* it up to a higher level of metal. Depending on the severity */
1094 /* of the antenna violation, this may need to be done more than */
1095 /* once. If no place to break the antenna is found, return -1 */
1096 /* for failure. */
1097 /*--------------------------------------------------------------*/
1098
simpleantennafix(ANTENNAINFO violation,Tcl_HashTable * NodeTable)1099 int simpleantennafix(ANTENNAINFO violation, Tcl_HashTable *NodeTable)
1100 {
1101 return -1; /* Antenna was not fixed */
1102 }
1103
1104 /*--------------------------------------------------------------*/
1105 /* Route from nets with antenna violations to the nearest */
1106 /* routable antenna cell tap. */
1107 /* */
1108 /* This routine is essentially the same as doroute() but with */
1109 /* some special handling related to the antenna taps, which */
1110 /* have much in common with VDD and GND taps but significant */
1111 /* differences as well. */
1112 /*--------------------------------------------------------------*/
1113
doantennaroute(ANTENNAINFO violation,Tcl_HashTable * NodeTable)1114 int doantennaroute(ANTENNAINFO violation, Tcl_HashTable *NodeTable)
1115 {
1116 NET net;
1117 NODE node;
1118 ROUTE rt1, lrt;
1119 int layer, i, result, savelayers;
1120 struct routeinfo_ iroute;
1121
1122 net = violation->net;
1123 node = violation->node;
1124 layer = violation->layer;
1125
1126 result = antenna_setup(&iroute, violation, NodeTable);
1127
1128 rt1 = createemptyroute();
1129 rt1->netnum = net->netnum;
1130 iroute.rt = rt1;
1131
1132 /* Force routing to be done at or below the antenna check layer. */
1133
1134 savelayers = Num_layers;
1135 Num_layers = violation->layer + 1;
1136
1137 result = route_segs(&iroute, 0, (u_char)0);
1138
1139 Num_layers = savelayers;
1140
1141 if (result < 0) {
1142 /* To do: Handle failures? */
1143 Fprintf(stderr, "Antenna anchoring route failed.\n");
1144 free(rt1);
1145 }
1146 else {
1147 TotalRoutes++;
1148 if (net->routes) {
1149 for (lrt = net->routes; lrt->next; lrt = lrt->next);
1150 lrt->next = rt1;
1151 }
1152 else {
1153 /* This should not happen */
1154 Fprintf(stderr, "Error: Net has no routes!\n");
1155 net->routes = rt1;
1156 }
1157 }
1158
1159 /* For power-bus-type routing, glist is not empty after routing */
1160 free_glist(&iroute);
1161
1162 /* Put free taps back to ANTENNA_NET */
1163 revert_antenna_taps(net->netnum, rt1->start.node);
1164
1165 return result;
1166 }
1167
1168 /*--------------------------------------------------------------*/
1169 /* Top level routine called from tclqrouter.c */
1170 /*--------------------------------------------------------------*/
1171
1172 void
resolve_antenna(char * antennacell,u_char do_fix)1173 resolve_antenna(char *antennacell, u_char do_fix)
1174 {
1175 FILE *fout;
1176 int numtaps, numerrors, numfixed, result;
1177 int layererrors;
1178 int layer, i, new;
1179 Tcl_HashTable NodeTable;
1180 Tcl_HashEntry *entry;
1181 GATE g;
1182 NET net;
1183 ROUTE rt;
1184 ANTENNAINFO nextviolation, FixedList = NULL, BadList = NULL;
1185
1186 numtaps = count_free_antenna_taps(antennacell);
1187 if (Verbose > 3) {
1188 Fprintf(stdout, "Number of free antenna taps = %d\n", numtaps);
1189 }
1190
1191 AntennaList = NULL;
1192 numerrors = 0;
1193 numfixed = 0;
1194
1195 /* Build a hash table of nodes, so the gate area can be found */
1196 /* quickly for any node by hash lookup. */
1197
1198 Tcl_InitHashTable(&NodeTable, TCL_ONE_WORD_KEYS);
1199
1200 for (g = Nlgates; g; g = g->next) {
1201 for (i = 0; i < g->nodes; i++) {
1202 GATENODE gn;
1203 gn = (GATENODE)malloc(sizeof(struct gatenode_));
1204 gn->idx = i;
1205 gn->gate = g;
1206 entry = Tcl_CreateHashEntry(&NodeTable, (char *)(*(g->noderec + i)), &new);
1207 Tcl_SetHashValue(entry, gn);
1208 }
1209 }
1210
1211 /* Working from the 1nd layer metal to the top, compute */
1212 /* route metal to gate area ratios. Mark each one when */
1213 /* done, as an antenna violation that has been fixed at, */
1214 /* say, metal2 can no longer be a violation on any higer */
1215 /* layer of metal. */
1216
1217 for (layer = 0; layer < Num_layers; layer++) {
1218 layererrors = find_layer_antenna_violations(layer, &NodeTable);
1219 numerrors += layererrors;
1220 if (Verbose > 2) {
1221 Fprintf(stdout, "Number of antenna errors on metal%d = %d\n",
1222 layer + 1, layererrors);
1223 }
1224
1225 /* Fix the violations found on this layer before moving */
1226 /* on to the next layer. */
1227
1228 while (AntennaList != NULL) {
1229 nextviolation = AntennaList->next;
1230
1231 if (do_fix) {
1232 result = simpleantennafix(AntennaList, &NodeTable);
1233 if (result == 0) {
1234 /* No antenna cell involved, so no backannotation */
1235 /* required. Remove the "route" record. */
1236 AntennaList->route = NULL;
1237 }
1238 else
1239 result = doantennaroute(AntennaList, &NodeTable);
1240 if (result >= 0) numfixed++;
1241 }
1242
1243 /* Move the error information to either the Fixed or Bad lists */
1244 if (result >= 0) {
1245 AntennaList->next = FixedList;
1246 FixedList = AntennaList;
1247 if (AntennaList->route != NULL) {
1248 /* Replace the route record with the last route */
1249 /* of the net, which was the route added to fix. */
1250 /* If the net requires more than one antenna */
1251 /* anchor, then routes won't be confused. */
1252 for (rt = AntennaList->net->routes; rt && rt->next; rt = rt->next);
1253 AntennaList->route = rt;
1254 }
1255 }
1256 else {
1257 AntennaList->next = BadList;
1258 BadList = AntennaList;
1259 }
1260 AntennaList = nextviolation;
1261 }
1262 }
1263
1264 if (Verbose > 0) {
1265 Fprintf(stdout, "Total number of antenna errors found = %d\n", numerrors);
1266 if (do_fix)
1267 Fprintf(stdout, "Total number of antenna errors fixed = %d\n", numfixed);
1268 }
1269 if (numtaps < numerrors) {
1270 if (numtaps == 0)
1271 Fprintf(stderr, "There are no antenna taps to use to correct "
1272 "antenna errors!\n");
1273 else {
1274 Fprintf(stderr, "There are not enough antenna taps to use to "
1275 "correct antenna errors!\n");
1276 Fprintf(stderr, "Number of errors = %d, number of taps = %d\n",
1277 numerrors, numtaps);
1278 Fprintf(stderr, "Increate the amount of unallocated antenna cells"
1279 " in the design.\n");
1280 }
1281 /* To do: Replace the error message with an ad-hoc solution to */
1282 /* pull routes up to a higher metal layer near the gate causing */
1283 /* the error. */
1284 }
1285
1286 /* Output the violation lists. The fixed violations need to be */
1287 /* known so that the additional connection to the net can be added */
1288 /* to the netlist for verification purposes. The unfixed */
1289 /* violations need to be reported so they can be tracked down and */
1290 /* fixed by hand. */
1291
1292 if ((FixedList != NULL) || (BadList != NULL))
1293 fout = fopen("antenna.out", "w");
1294
1295 /* Clear any existing list of instance connections (annotations) */
1296
1297 if (AnnotateList) {
1298 ANNOTATEINFO nextannotate;
1299 while (AnnotateList != NULL) {
1300 nextannotate = AnnotateList->next;
1301 free(AnnotateList);
1302 AnnotateList = nextannotate;
1303 }
1304 }
1305
1306 if (FixedList != NULL) {
1307 ROUTE rt;
1308 ANNOTATEINFO newannotate;
1309 fprintf(fout, "Revised netlist: New antenna anchor connections\n");
1310
1311 for (nextviolation = FixedList; nextviolation;
1312 nextviolation = nextviolation->next) {
1313 // NOTE: nextviolation->route was changed from the route that
1314 // connects to the gate in violation, to the route that fixes
1315 // the antenna error.
1316 g = FindGateNode(&NodeTable, nextviolation->route->start.node, &i);
1317 fprintf(fout, "Net=%s Instance=%s Cell=%s Pin=%s\n",
1318 nextviolation->net->netname, g->gatename,
1319 g->gatetype->gatename, g->gatetype->node[i]);
1320
1321 // Create an annotation entry for this fixed violation
1322
1323 newannotate = (ANNOTATEINFO)malloc(sizeof(struct annotateinfo_));
1324 newannotate->net = nextviolation->net;
1325 newannotate->instance = g->gatename;
1326 newannotate->pin = g->gatetype->node[i];
1327 newannotate->flag = ANNO_INIT;
1328 newannotate->next = AnnotateList;
1329 AnnotateList = newannotate;
1330 }
1331 fprintf(fout, "\n");
1332 }
1333
1334 if (BadList != NULL) {
1335 fprintf(fout, "Unfixed antenna errors:\n");
1336
1337 for (nextviolation = BadList; nextviolation;
1338 nextviolation = nextviolation->next) {
1339 g = FindGateNode(&NodeTable, nextviolation->node, &i);
1340 fprintf(fout, "Net=%s Instance=%s Cell=%s Pin=%s error on Metal%d\n",
1341 nextviolation->net->netname,
1342 g->gatename, g->gatetype->gatename,
1343 g->gatetype->node[i], nextviolation->layer + 1);
1344 }
1345 }
1346
1347 if ((FixedList != NULL) || (BadList != NULL)) fclose(fout);
1348
1349 /* Free up the node hash table */
1350
1351 FreeNodeTable(&NodeTable);
1352 Tcl_DeleteHashTable(&NodeTable);
1353
1354 /* Free up the violation lists */
1355
1356 if (FixedList != NULL) {
1357 while (FixedList != NULL) {
1358 nextviolation = FixedList->next;
1359 free(FixedList);
1360 FixedList = nextviolation;
1361 }
1362 }
1363 while (BadList != NULL) {
1364 nextviolation = BadList->next;
1365 free(BadList);
1366 BadList = nextviolation;
1367 }
1368 }
1369
1370 #endif /* TCL_QROUTER */
1371
1372 /* end of antenna.c */
1373