1 /*
2 * DRCmain.c --
3 *
4 * This file provides global routines that are invoked at
5 * command-level. They do things like give information about
6 * errors and print statistics.
7 *
8 * *********************************************************************
9 * * Copyright (C) 1985, 1990 Regents of the University of California. *
10 * * Permission to use, copy, modify, and distribute this *
11 * * software and its documentation for any purpose and without *
12 * * fee is hereby granted, provided that the above copyright *
13 * * notice appear in all copies. The University of California *
14 * * makes no representations about the suitability of this *
15 * * software for any purpose. It is provided "as is" without *
16 * * express or implied warranty. Export of this software outside *
17 * * of the United States of America may require an export license. *
18 * *********************************************************************
19 */
20
21 #ifndef lint
22 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/drc/DRCmain.c,v 1.4 2010/06/24 12:37:16 tim Exp $";
23 #endif /* not lint */
24
25 #include <sys/types.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 #include "tcltk/tclmagic.h"
30 #include "utils/magic.h"
31 #include "utils/malloc.h"
32 #include "textio/textio.h"
33 #include "utils/geometry.h"
34 #include "tiles/tile.h"
35 #include "utils/hash.h"
36 #include "database/database.h"
37 #include "windows/windows.h"
38 #include "dbwind/dbwind.h"
39 #include "drc/drc.h"
40 #include "cif/cif.h"
41 #include "utils/undo.h"
42
43 /* The global variables defined below are parameters between
44 * the DRC error routines (drcPaintError and drcPrintError)
45 * and the higher-level routines that start up DRC error checks.
46 * It seemed simpler to do the communication this way rather
47 * than creating a special new record that is passed down as
48 * ClientData. Any routine invoking DRCBasicCheck with drcPaintError
49 * or drcPrintError as action routine should fill in the relevant
50 * variables.
51 */
52
53 /* The following points to a list of all the DRC styles currently
54 * understood:
55 */
56
57 DRCKeep *DRCStyleList = NULL;
58
59 DRCStyle *DRCCurStyle = NULL;
60
61 /* Used by both routines: */
62
63 int DRCErrorCount; /* Incremented by each call to either routine.
64 */
65
66 /* Used by drcPaintError: */
67
68 CellDef *DRCErrorDef; /* Place to paint error tiles. */
69 TileType DRCErrorType; /* Type of error tile to paint. */
70
71 /* Used by drcPrintError: */
72
73 int *DRCErrorList; /* List of DRC error type counts */
74 HashTable DRCErrorTable; /* Table of DRC errors and geometry */
75
76 /* Global variables used by all DRC modules to record statistics.
77 * For each statistic we keep two values, the count since stats
78 * were last printed (in DRCstatXXX), and the total count (in
79 * drcTotalXXX).
80 */
81
82 int DRCstatSquares = 0; /* Number of DRCStepSize-by-DRCStepSize
83 * squares processed by continuous checker.
84 */
85 int DRCstatTiles = 0; /* Number of tiles processed by basic
86 * checker.
87 */
88 int DRCstatEdges = 0; /* Number of "atomic" edges processed
89 * by basic checker.
90 */
91 int DRCstatRules = 0; /* Number of rules processed by basic checker
92 * (rule = one constraint for one edge).
93 */
94 int DRCstatSlow = 0; /* Number of places where constraint doesn't
95 * all fall in a single tile.
96 */
97 int DRCstatInteractions = 0; /* Number of times drcInt is called to check
98 * an interaction area.
99 */
100 int DRCstatIntTiles = 0; /* Number of tiles processed as part of
101 * subcell interaction checks.
102 */
103 int DRCstatCifTiles = 0; /* Number of tiles processed as part of
104 * cif checks.
105 */
106 int DRCstatArrayTiles = 0; /* Number of tiles processed as part of
107 * array interaction checks.
108 */
109
110 #ifdef DRCRULESHISTO
111 int DRCstatVRulesHisto[DRC_MAXRULESHISTO];
112 int DRCstatHRulesHisto[DRC_MAXRULESHISTO];
113 #endif /* DRCRULESHISTO */
114
115 static int drcTotalSquares = 0;
116 static int drcTotalTiles = 0;
117 static int drcTotalEdges = 0;
118 static int drcTotalRules = 0;
119 static int drcTotalSlow = 0;
120 static int drcTotalInteractions = 0;
121 static int drcTotalIntTiles = 0;
122 static int drcTotalArrayTiles = 0;
123
124 #ifdef DRCRULESHISTO
125 static int drcTotalVRulesHisto[DRC_MAXRULESHISTO];
126 static int drcTotalHRulesHisto[DRC_MAXRULESHISTO];
127 #endif /* DRCRULESHISTO */
128
129
130 /*
131 * ----------------------------------------------------------------------------
132 * drcPaintError --
133 *
134 * Action function that paints error tiles for each violation found.
135 *
136 * Results:
137 * None.
138 *
139 * Side effects:
140 * A tile of type DRCErrorType is painted over the area of
141 * the error, in the plane given by "plane". Also, DRCErrorCount
142 * is incremented.
143 * ----------------------------------------------------------------------------
144 */
145
146 void
drcPaintError(celldef,rect,cptr,plane)147 drcPaintError(celldef, rect, cptr, plane)
148 CellDef * celldef; /* CellDef being checked */
149 Rect * rect; /* Area of error */
150 DRCCookie * cptr; /* Design rule violated -- not used */
151 Plane * plane; /* Where to paint error tiles. */
152 {
153 PaintUndoInfo ui;
154
155 ui.pu_def = celldef;
156 ui.pu_pNum = PL_DRC_ERROR;
157 DBPaintPlane(plane, rect, DBStdPaintTbl(DRCErrorType,
158 PL_DRC_ERROR), &ui);
159 DRCErrorCount += 1;
160 }
161
162 /*
163 * ----------------------------------------------------------------------------
164 * drcSubstitute ---
165 *
166 * Check for substitution sequences in the DRC "why" string in the DRCCookie
167 * record passed in cptr, and make the appropriate substitutions. Return
168 * the modified string.
169 *
170 * Currently supported:
171 * %d encodes the rule distance. Output is given in microns
172 * %c encodes the rule corner distance. Output is given in microns.
173 * %a encodes the rule distance as area. Output is given in microns squared.
174 *
175 * To do: Add flag bits to the drcc_flags field to indicate what type of
176 * rule this is (easier than decoding it from context), and add a substitution
177 * sequence "%s" to build the entire "why" string from the relevant rule data.
178 * ----------------------------------------------------------------------------
179 */
180
181 char *
drcSubstitute(cptr)182 drcSubstitute (cptr)
183 DRCCookie * cptr; /* Design rule violated */
184 {
185 static char *why_out = NULL;
186 char *whyptr, *sptr, *wptr;
187 int subscnt = 0, whylen;
188 float oscale, value;
189 extern float CIFGetOutputScale();
190
191 whyptr = DRCCurStyle->DRCWhyList[cptr->drcc_tag];
192 while ((sptr = strchr(whyptr, '%')) != NULL)
193 {
194 subscnt++;
195 whyptr = sptr + 1;
196 }
197 if (subscnt == 0) return whyptr; /* No substitutions */
198
199 whyptr = DRCCurStyle->DRCWhyList[cptr->drcc_tag];
200 whylen = strlen(whyptr) + 20 * subscnt;
201 if (why_out != NULL) freeMagic(why_out);
202 why_out = (char *)mallocMagic(whylen * sizeof(char));
203 strcpy(why_out, whyptr);
204
205 if (cptr->drcc_flags & DRC_CIFRULE)
206 oscale = CIFGetScale(100); /* 100 = microns to centimicrons */
207 else
208 oscale = CIFGetOutputScale(1000); /* 1000 for conversion to um */
209 wptr = why_out;
210
211 while ((sptr = strchr(whyptr, '%')) != NULL)
212 {
213 /* copy up to sptr */
214 strncpy(wptr, whyptr, (int)(sptr - whyptr));
215 wptr += (sptr - whyptr);
216
217 switch (*(sptr + 1))
218 {
219 case 'd':
220 /* Replace with "dist" value in microns */
221 value = (float)cptr->drcc_dist * oscale;
222 snprintf(wptr, 20, "%01.3gum", value);
223 wptr += strlen(wptr);
224 break;
225 case 'c':
226 /* Replace with "cdist" value in microns */
227 value = (float)cptr->drcc_cdist * oscale;
228 snprintf(wptr, 20, "%01.3gum", value);
229 wptr += strlen(wptr);
230 break;
231 case 'a':
232 /* Replace with "cdist" value in microns squared */
233 value = (float)cptr->drcc_cdist * oscale * oscale;
234 snprintf(wptr, 20, "%01.4gum^2", value);
235 wptr += strlen(wptr);
236 break;
237 default:
238 /* Any other character after '%', treat as literal */
239 wptr += 2;
240 break;
241 }
242 whyptr = sptr + 2;
243 }
244 /* copy remainder of string (including trailing null) */
245 strncpy(wptr, whyptr, strlen(whyptr) + 1);
246
247 return why_out;
248 }
249
250
251 /*
252 * ----------------------------------------------------------------------------
253 * drcPrintError --
254 *
255 * Action function that prints the error message associated with each
256 * violation found.
257 *
258 * Results:
259 * None.
260 *
261 * Side effects:
262 * DRCErrorCount is incremented. The text associated with
263 * the error is entered into DRCErrorList, and, if this is
264 * the first time that entry has been seen, then the error
265 * text is printed. If the area parameter is non-NULL, then
266 * only errors intersecting that area are considered.
267 * ----------------------------------------------------------------------------
268 */
269
270 void
drcPrintError(celldef,rect,cptr,scx)271 drcPrintError (celldef, rect, cptr, scx)
272 CellDef * celldef; /* CellDef being checked -- not used here */
273 Rect * rect; /* Area of error */
274 DRCCookie * cptr; /* Design rule violated */
275 SearchContext * scx; /* Only errors in scx->scx_area get reported. */
276 {
277 HashEntry *h;
278 int i;
279 Rect *area, r;
280
281 ASSERT (cptr != (DRCCookie *) NULL, "drcPrintError");
282
283 area = &scx->scx_area;
284 if ((area != NULL) && (!GEO_OVERLAP(area, rect))) return;
285 DRCErrorCount += 1;
286
287 i = DRCErrorList[cptr->drcc_tag];
288 if (i == 0)
289 TxPrintf("%s\n", drcSubstitute(cptr));
290 DRCErrorList[cptr->drcc_tag] = i + 1;
291 }
292
293 /* Same routine as above, but output goes to a Tcl list and is appended */
294 /* to the interpreter result. */
295
296 #ifdef MAGIC_WRAPPER
297
298 void
drcListError(celldef,rect,cptr,scx)299 drcListError (celldef, rect, cptr, scx)
300 CellDef * celldef; /* CellDef being checked -- not used here */
301 Rect * rect; /* Area of error */
302 DRCCookie * cptr; /* Design rule violated */
303 SearchContext * scx; /* Only errors in scx->scx_area get reported */
304 {
305 HashEntry *h;
306 int i;
307 Rect *area;
308
309 ASSERT (cptr != (DRCCookie *) NULL, "drcListError");
310
311 area = &scx->scx_area;
312 if ((area != NULL) && (!GEO_OVERLAP(area, rect))) return;
313 DRCErrorCount += 1;
314 i = DRCErrorList[cptr->drcc_tag];
315 if (i == 0)
316 {
317 Tcl_Obj *lobj;
318 lobj = Tcl_GetObjResult(magicinterp);
319 Tcl_ListObjAppendElement(magicinterp, lobj,
320 Tcl_NewStringObj(drcSubstitute(cptr), -1));
321 Tcl_SetObjResult(magicinterp, lobj);
322 }
323 DRCErrorList[cptr->drcc_tag] = i + 1;
324 }
325
326 /* Same routine as above, but output for every single error is recorded */
327 /* along with position information. */
328
329 void
drcListallError(celldef,rect,cptr,scx)330 drcListallError (celldef, rect, cptr, scx)
331 CellDef * celldef; /* CellDef being checked -- not used here */
332 Rect * rect; /* Area of error */
333 DRCCookie * cptr; /* Design rule violated */
334 SearchContext * scx; /* Only errors in scx->scx_area get reported. */
335 {
336 Tcl_Obj *lobj, *pobj;
337 HashEntry *h;
338 Rect *area, r;
339
340 ASSERT (cptr != (DRCCookie *) NULL, "drcListallError");
341
342 // Report in top-level coordinates
343 GeoTransRect(&scx->scx_trans, rect, &r);
344 area = &scx->scx_area;
345 if ((area != NULL) && (!GEO_OVERLAP(area, rect))) return;
346 DRCErrorCount += 1;
347 h = HashFind(&DRCErrorTable, drcSubstitute(cptr));
348 lobj = (Tcl_Obj *) HashGetValue(h);
349 if (lobj == NULL)
350 lobj = Tcl_NewListObj(0, NULL);
351
352 pobj = Tcl_NewListObj(0, NULL);
353
354 Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_xbot));
355 Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_ybot));
356 Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_xtop));
357 Tcl_ListObjAppendElement(magicinterp, pobj, Tcl_NewIntObj(r.r_ytop));
358 Tcl_ListObjAppendElement(magicinterp, lobj, pobj);
359
360 HashSetValue(h, lobj);
361 }
362
363 #else
364
365 #define drcListError drcPrintError
366
367 #endif
368
369 /*
370 * ----------------------------------------------------------------------------
371 *
372 * DRCPrintStats --
373 *
374 * Prints out statistics gathered by the DRC checking routines.
375 *
376 * Results:
377 * None.
378 *
379 * Side effects:
380 * Statistics are printed. Two values are printed for each
381 * statistic: the number since statistics were last printed,
382 * and the total to date. The own variables used to keep
383 * track of statistics are updated.
384 *
385 * ----------------------------------------------------------------------------
386 */
387
388 void
DRCPrintStats()389 DRCPrintStats()
390 {
391 #ifdef DRCRULESHISTO
392 int n;
393 #endif /* DRCRULESHISTO */
394
395 TxPrintf("Design-rule checker statistics (recent/total):\n");
396 drcTotalSquares += DRCstatSquares;
397 TxPrintf(" Squares processed: %d/%d\n", DRCstatSquares,
398 drcTotalSquares);
399 DRCstatSquares = 0;
400 drcTotalTiles += DRCstatTiles;
401 TxPrintf(" Tiles processed: %d/%d\n", DRCstatTiles, drcTotalTiles);
402 DRCstatTiles = 0;
403 drcTotalEdges += DRCstatEdges;
404 TxPrintf(" Edges pieces processed: %d/%d\n", DRCstatEdges,
405 drcTotalEdges);
406 DRCstatEdges = 0;
407 drcTotalRules += DRCstatRules;
408 TxPrintf(" Constraint areas checked: %d/%d\n", DRCstatRules,
409 drcTotalRules);
410 DRCstatRules = 0;
411 drcTotalSlow += DRCstatSlow;
412 TxPrintf(" Multi-tile constraints: %d/%d\n", DRCstatSlow,
413 drcTotalSlow);
414 DRCstatSlow = 0;
415 drcTotalInteractions += DRCstatInteractions;
416 TxPrintf(" Interaction areas processed: %d/%d\n",
417 DRCstatInteractions, drcTotalInteractions);
418 DRCstatInteractions = 0;
419 drcTotalIntTiles += DRCstatIntTiles;
420 TxPrintf(" Tiles processed for interactions: %d/%d\n",
421 DRCstatIntTiles, drcTotalIntTiles);
422 DRCstatIntTiles = 0;
423 drcTotalArrayTiles += DRCstatArrayTiles;
424 TxPrintf(" Tiles processed for arrays: %d/%d\n",
425 DRCstatArrayTiles, drcTotalArrayTiles);
426 DRCstatArrayTiles = 0;
427
428 #ifdef DRCRULESHISTO
429 TxPrintf(" Number of rules applied per edge:\n");
430 TxPrintf(" # rules Horiz freq Vert freq\n");
431 for (n = 0; n < DRC_MAXRULESHISTO; n++)
432 {
433 drcTotalHRulesHisto[n] += DRCstatHRulesHisto[n];
434 drcTotalVRulesHisto[n] += DRCstatVRulesHisto[n];
435 if (drcTotalHRulesHisto[n] == 0 && drcTotalVRulesHisto[n] == 0)
436 continue;
437 TxPrintf(" %3d %10d/%10d %10d/%10d\n",
438 n,
439 DRCstatHRulesHisto[n], drcTotalHRulesHisto[n],
440 DRCstatVRulesHisto[n], drcTotalVRulesHisto[n]);
441 DRCstatHRulesHisto[n] = DRCstatVRulesHisto[n] = 0;
442 }
443 #endif /* DRCRULESHISTO */
444 }
445
446 /*
447 * ----------------------------------------------------------------------------
448 *
449 * DRCWhy --
450 *
451 * This procedure finds all errors within an area and prints messages
452 * about each distinct kind of violation found.
453 *
454 * Results:
455 * None.
456 *
457 * Side effects:
458 * None, except that error messages are printed. The given
459 * area is DRC'ed for both paint and subcell violations in every
460 * cell of def's tree that it intersects.
461 *
462 * ----------------------------------------------------------------------------
463 */
464
465 void
DRCWhy(dolist,use,area)466 DRCWhy(dolist, use, area)
467 bool dolist; /*
468 * Generate Tcl list for value
469 */
470 CellUse *use; /* Use in whose definition to start
471 * the hierarchical check.
472 */
473 Rect *area; /* Area, in def's coordinates, that
474 * is to be checked.
475 */
476 {
477 SearchContext scx;
478 Rect box;
479 int i;
480 extern int drcWhyFunc(); /* Forward reference. */
481
482 /* Create a hash table to eliminate duplicate messages. */
483
484 DRCErrorList = (int *)mallocMagic((DRCCurStyle->DRCWhySize + 1) * sizeof(int));
485 for (i = 0; i <= DRCCurStyle->DRCWhySize; i++)
486 DRCErrorList[i] = 0;
487
488 DRCErrorCount = 0;
489 box = DRCdef->cd_bbox;
490
491 /* Undo will only slow things down in here, so turn it off. */
492
493 UndoDisable();
494 scx.scx_use = use;
495 scx.scx_x = use->cu_xlo;
496 scx.scx_y = use->cu_ylo;
497 scx.scx_area = *area;
498 scx.scx_trans = GeoIdentityTransform;
499 drcWhyFunc(&scx, (pointertype)dolist);
500 UndoEnable();
501
502 /* Delete the error list */
503 freeMagic(DRCErrorList);
504
505 /* Redisplay the DRC yank definition in case anyone is looking
506 * at it.
507 */
508
509 DBReComputeBbox(DRCdef);
510 (void) GeoInclude(&DRCdef->cd_bbox, &box);
511 DBWAreaChanged(DRCdef, &box, DBW_ALLWINDOWS, &DBAllButSpaceBits);
512
513 if (DRCErrorCount == 0) TxPrintf("No errors found.\n");
514 }
515
516 #ifdef MAGIC_WRAPPER
517
518 void
DRCWhyAll(use,area,fout)519 DRCWhyAll(use, area, fout)
520 CellUse *use; /* Use in whose definition to start
521 * the hierarchical check.
522 */
523 Rect *area; /* Area, in def's coordinates, that
524 * is to be checked.
525 */
526 FILE *fout; /*
527 * Write formatted output to fout
528 */
529 {
530 SearchContext scx;
531 Rect box;
532 extern int drcWhyAllFunc(); /* Forward reference. */
533 HashSearch hs;
534 HashEntry *he;
535 Tcl_Obj *lobj, *robj;
536
537 /* Create a hash table for storing all of the results */
538
539 HashInit(&DRCErrorTable, 16, HT_STRINGKEYS);
540 DRCErrorCount = 0;
541 box = DRCdef->cd_bbox;
542
543 /* Undo will only slow things down in here, so turn it off. */
544
545 UndoDisable();
546 scx.scx_use = use;
547 scx.scx_x = use->cu_xlo;
548 scx.scx_y = use->cu_ylo;
549 scx.scx_area = *area;
550 scx.scx_trans = GeoIdentityTransform;
551 drcWhyAllFunc(&scx, NULL);
552 UndoEnable();
553
554 /* Generate results */
555
556 robj = Tcl_NewListObj(0, NULL);
557
558 HashStartSearch(&hs);
559 while ((he = HashNext(&DRCErrorTable, &hs)) != (HashEntry *)NULL)
560 {
561 lobj = (Tcl_Obj *)HashGetValue(he);
562 if (lobj != NULL)
563 {
564 Tcl_ListObjAppendElement(magicinterp, robj,
565 Tcl_NewStringObj((char *)he->h_key.h_name, -1));
566 Tcl_ListObjAppendElement(magicinterp, robj, lobj);
567 }
568 }
569 Tcl_SetObjResult(magicinterp, robj);
570
571 /* Delete the error table now that we're finished */
572 HashKill(&DRCErrorTable);
573
574 /* Redisplay the DRC yank definition in case anyone is looking
575 * at it.
576 */
577
578 DBReComputeBbox(DRCdef);
579 (void) GeoInclude(&DRCdef->cd_bbox, &box);
580 DBWAreaChanged(DRCdef, &box, DBW_ALLWINDOWS, &DBAllButSpaceBits);
581
582 if (DRCErrorCount == 0) TxPrintf("No errors found.\n");
583 }
584
585 #endif /* MAGIC_WRAPPER */
586
587 /*
588 * ----------------------------------------------------------------------------
589 *
590 * drcWhyFunc --
591 *
592 * This function is invoked underneath DrcWhy. It's called once
593 * for each subcell instance of the current cell. If the subcell
594 * is expanded, then it computes errors in that subcell and
595 * searches the subcell recursively.
596 *
597 * Results:
598 * Always returns 0 to keep the search alive.
599 *
600 * Side effects:
601 * None.
602 *
603 * ----------------------------------------------------------------------------
604 */
605
606 /* ARGSUSED */
607 int
drcWhyFunc(scx,cdarg)608 drcWhyFunc(scx, cdarg)
609 SearchContext *scx; /* Describes current state of search. */
610 ClientData cdarg; /* Used to hold boolean value "dolist" */
611 {
612 CellDef *def = scx->scx_use->cu_def;
613 bool dolist = (bool)((pointertype)cdarg);
614
615 /* Check paint and interactions in this subcell. */
616
617 (void) DRCInteractionCheck(def, &scx->scx_area, &scx->scx_area,
618 (dolist) ? drcListError : drcPrintError, (ClientData) scx);
619 return 0;
620 }
621
622 #ifdef MAGIC_WRAPPER
623
624 int
drcWhyAllFunc(scx,cdarg)625 drcWhyAllFunc(scx, cdarg)
626 SearchContext *scx; /* Describes current state of search. */
627 ClientData cdarg; /* Unused */
628 {
629 CellDef *def = scx->scx_use->cu_def;
630
631 /* Check paint and interactions in this subcell. */
632
633 (void) DRCInteractionCheck(def, &scx->scx_area, &scx->scx_area,
634 drcListallError, (ClientData)scx);
635 return 0;
636 }
637
638 #endif /* MAGIC_WRAPPER */
639
640 /*
641 * ----------------------------------------------------------------------------
642 *
643 * DRCCheck --
644 *
645 * Marks all areas underneath the cursor, forcing them to be
646 * rechecked by the DRC.
647 *
648 * Results:
649 * None.
650 *
651 * Side effects:
652 * Check tiles are painted.
653 *
654 * ----------------------------------------------------------------------------
655 */
656
657 void
DRCCheck(use,area)658 DRCCheck(use, area)
659 CellUse *use; /* Top-level use of hierarchy. */
660 Rect *area; /* This area is rechecked everywhere in the
661 * hierarchy underneath use.
662 */
663 {
664 SearchContext scx;
665 extern int drcCheckFunc(); /* Forward reference. */
666
667 if (DBCellReadArea(use, area, TRUE))
668 {
669 TxError("Failure to read in entire subtree of cell.\n");
670 return;
671 }
672
673 scx.scx_use = use;
674 scx.scx_x = use->cu_xlo;
675 scx.scx_y = use->cu_ylo;
676 scx.scx_area = *area;
677 scx.scx_trans = GeoIdentityTransform;
678 (void) drcCheckFunc(&scx, (ClientData) NULL);
679 }
680
681 /* ARGSUSED */
682 int
drcCheckFunc(scx,cdarg)683 drcCheckFunc(scx, cdarg)
684 SearchContext *scx;
685 ClientData cdarg; /* Not used. */
686 {
687 Rect cellArea;
688 CellDef *def;
689
690 /* Clip the area to the size of the cell, then recheck that area.
691 * The recheck is handled by painting the check info directly
692 * and then calling DRCCheckThis only to add the cell to the
693 * list of those to be checked. This avoids the hierarchical
694 * upwards search that would normally be made by DRCCheckThis,
695 * but which is unwelcome (and slow) here.
696 */
697
698 cellArea = scx->scx_area;
699 def = scx->scx_use->cu_def;
700 GeoClip(&cellArea, &def->cd_bbox);
701 GEO_EXPAND(&cellArea, DRCTechHalo, &cellArea);
702
703 DBPaintPlane(def->cd_planes[PL_DRC_CHECK], &cellArea,
704 DBStdPaintTbl(TT_CHECKPAINT, PL_DRC_CHECK),
705 (PaintUndoInfo *) NULL);
706
707 DRCCheckThis(def, TT_CHECKPAINT, (Rect *) NULL);
708
709 /* Search children */
710 (void) DBCellSrArea(scx, drcCheckFunc, (ClientData) NULL);
711
712 /* As a special performance hack, if the complete cell area is
713 * handled here, don't bother to look at any more array elements.
714 */
715
716 if (GEO_SURROUND(&cellArea, &def->cd_bbox))
717 return 2;
718 else return 0;
719 }
720
721 /*
722 * ----------------------------------------------------------------------------
723 *
724 * DRCCount --
725 *
726 * Searches the entire hierarchy underneath the given area.
727 * For each cell found, counts design-rule violations in
728 * that cell and outputs the counts.
729 *
730 * Results:
731 * Return linked list of cell definitions and their error counts.
732 *
733 * Side effects:
734 * None.
735 *
736 * ----------------------------------------------------------------------------
737 */
738
739 DRCCountList *
DRCCount(use,area,recurse)740 DRCCount(use, area, recurse)
741 CellUse *use; /* Top-level use of hierarchy. */
742 Rect *area; /* Area in which violations are counted. */
743 bool recurse; /* If TRUE, count errors in all subcells */
744 {
745 DRCCountList *dcl, *newdcl;
746 HashTable dupTable;
747 HashEntry *he;
748 HashSearch hs;
749 int count;
750 SearchContext scx;
751 CellDef *def;
752 extern int drcCountFunc();
753
754 /* Shouldn't happen? */
755 if (!(use->cu_def->cd_flags & CDAVAILABLE)) return NULL;
756
757 /* Use a hash table to make sure that we don't output information
758 * for any cell more than once.
759 */
760
761 HashInit(&dupTable, 16, HT_WORDKEYS);
762
763 /* Clearing CDAVAILABLE from cd_flags keeps the count from recursing */
764 if (recurse == FALSE)
765 use->cu_def->cd_flags &= ~CDAVAILABLE;
766
767 scx.scx_use = use;
768 scx.scx_x = use->cu_xlo;
769 scx.scx_y = use->cu_ylo;
770 scx.scx_area = *area;
771 scx.scx_trans = GeoIdentityTransform;
772 (void) drcCountFunc(&scx, &dupTable);
773
774 /* Create the list from the hash table */
775
776 dcl = NULL;
777 if (dupTable.ht_table != (HashEntry **) NULL)
778 {
779 HashStartSearch(&hs);
780 while ((he = HashNext(&dupTable, &hs)) != (HashEntry *)NULL)
781 {
782 count = (spointertype)HashGetValue(he);
783 if (count > 1)
784 {
785 newdcl = (DRCCountList *)mallocMagic(sizeof(DRCCountList));
786 newdcl->dcl_count = count - 1;
787 newdcl->dcl_def = (CellDef *)he->h_key.h_ptr;
788 newdcl->dcl_next = dcl;
789 dcl = newdcl;
790 }
791 }
792 }
793 HashKill(&dupTable);
794
795 /* Restore the CDAVAILABLE flag */
796 if (recurse == FALSE)
797 use->cu_def->cd_flags |= CDAVAILABLE;
798
799 return dcl;
800 }
801
802 int
drcCountFunc(scx,dupTable)803 drcCountFunc(scx, dupTable)
804 SearchContext *scx;
805 HashTable *dupTable; /* Passed as client data, used to
806 * avoid searching any cell twice.
807 */
808 {
809 int count;
810 HashEntry *h;
811 CellDef *def;
812 extern int drcCountFunc2();
813
814 /* If we've already seen this cell definition before, then skip it
815 * now.
816 */
817
818 def = scx->scx_use->cu_def;
819 h = HashFind(dupTable, (char *)def);
820 if (HashGetValue(h) != 0) goto done;
821 HashSetValue(h, 1);
822
823 /* Count errors in this cell definition by scanning the error plane. */
824
825 count = 0;
826 (void) DBSrPaintArea((Tile *) NULL, def->cd_planes[PL_DRC_ERROR],
827 &def->cd_bbox, &DBAllButSpaceBits, drcCountFunc2, (ClientData)(&count));
828 HashSetValue(h, (spointertype)count + 1);
829
830 /* Ignore children that have not been loaded---we will only report */
831 /* errors that can be seen. This avoids immediately loading and */
832 /* drc processing large layouts simply because we asked for an */
833 /* error count. When the cell is loaded, drc will be checked */
834 /* anyway, and the count can be updated in response to that check. */
835
836 if ((scx->scx_use->cu_def->cd_flags & CDAVAILABLE) == 0) return 0;
837
838 /* Scan children recursively. */
839
840 DBCellSrArea(scx, drcCountFunc, (ClientData)dupTable);
841
842 /* As a special performance hack, if the complete cell area is
843 * handled here, don't bother to look at any more array elements.
844 */
845 done: if (GEO_SURROUND(&scx->scx_area, &def->cd_bbox)) return 2;
846 else return 0;
847 }
848
849 int
drcCountFunc2(tile,countptr)850 drcCountFunc2(tile, countptr)
851 Tile *tile; /* Tile found in error plane. */
852 int *countptr; /* Address of count word. */
853 {
854 if (TiGetType(tile) != (TileType) TT_SPACE) (*countptr)++;
855 return 0;
856 }
857
858 /*
859 * ----------------------------------------------------------------------------
860 *
861 * DRCCatchUp--
862 *
863 * This procedure just runs the background checker, regardless
864 * of whether it's enabled or not, and waits for it to complete.
865 *
866 * Results:
867 * None.
868 *
869 * Side effects:
870 * Error and check tiles get painted and erased by the checker.
871 *
872 * ----------------------------------------------------------------------------
873 */
874
875 void
DRCCatchUp()876 DRCCatchUp()
877 {
878 int background;
879
880 background = DRCBackGround;
881 DRCBackGround = DRC_SET_ON;
882 DRCContinuous();
883 DRCBackGround = background;
884 }
885
886 /*
887 * ----------------------------------------------------------------------------
888 *
889 * DRCFind --
890 *
891 * Locates the next violation tile in the cell pointed to by
892 * "use" and its children.
893 * Successive calls will located successive violations, in
894 * circular order.
895 *
896 * Results:
897 * If an error tile was found in def, returns the indx of
898 * the error tile (> 0). Returns 0 if there were no error
899 * tiles in def. Returns -1 if indx was out-of-range
900 * (not that many errors in def).
901 *
902 * Side effects:
903 * Rect is filled with the location of the tile, if one is found.
904 *
905 * ----------------------------------------------------------------------------
906 */
907
908 typedef struct {
909 int current; /* count of current error */
910 int target; /* count of target error */
911 Rect *rect; /* Return rectangle */
912 Transform trans; /* Return transform */
913 HashTable *deft; /* Table of cell definitions to avoid duplicates */
914 } Sindx;
915
916 int
DRCFind(use,area,rect,indx)917 DRCFind(use, area, rect, indx)
918 CellUse *use; /* Cell use to check. */
919 Rect *area; /* Area of search */
920 Rect *rect; /* Rectangle to fill in with tile location. */
921 int indx; /* Go to this error. */
922 {
923 SearchContext scx;
924 Sindx finddata;
925 Rect trect;
926 int result;
927 int drcFindFunc();
928 HashTable defTable;
929
930 scx.scx_use = use;
931 scx.scx_x = use->cu_xlo;
932 scx.scx_y = use->cu_ylo;
933 scx.scx_area = *area;
934 scx.scx_trans = GeoIdentityTransform;
935
936 HashInit(&defTable, 16, HT_WORDKEYS);
937
938 finddata.current = 0;
939 finddata.target = indx;
940 finddata.rect = &trect;
941 finddata.trans = scx.scx_trans;
942 finddata.deft = &defTable;
943
944 result = drcFindFunc(&scx, &finddata);
945
946 HashKill(&defTable);
947
948 if (result == 0)
949 {
950 if (finddata.current == 0)
951 return 0;
952 else
953 return -1;
954 }
955
956 /* Translate rectangle back into coordinate system of "use" */
957 GeoTransRect(&finddata.trans, &trect, rect);
958 return indx;
959 }
960
961 int
drcFindFunc(scx,finddata)962 drcFindFunc(scx, finddata)
963 SearchContext *scx;
964 Sindx *finddata;
965 {
966 CellDef *def;
967 HashEntry *h;
968 int drcFindFunc2();
969 bool dereference;
970
971 def = scx->scx_use->cu_def;
972 h = HashFind(finddata->deft, (char *)def);
973 if (HashGetValue(h) != 0) return 0;
974 HashSetValue(h, 1);
975
976 dereference = (def->cd_flags & CDDEREFERENCE) ? TRUE : FALSE;
977 (void) DBCellRead(def, (char *) NULL, TRUE, dereference, NULL);
978
979 if (DBSrPaintArea((Tile *) NULL, def->cd_planes[PL_DRC_ERROR],
980 &def->cd_bbox, &DBAllButSpaceBits, drcFindFunc2,
981 (ClientData)finddata) != 0)
982 {
983 finddata->trans = scx->scx_trans;
984 return 1;
985 }
986
987 /* New behavior: Don't search children, instead propagate errors up. */
988 /* return DBCellSrArea(scx, drcFindFunc, (ClientData)finddata); */
989 return 0;
990 }
991
992 int
drcFindFunc2(tile,finddata)993 drcFindFunc2(tile, finddata)
994 Tile *tile; /* Tile in error plane. */
995 Sindx *finddata; /* Information about error to find */
996
997 {
998 if (TiGetType(tile) == (TileType) TT_SPACE) return 0;
999 if (++finddata->current == finddata->target)
1000 {
1001 TiToRect(tile, finddata->rect);
1002 return 1;
1003 }
1004 return 0;
1005 }
1006