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