1 /*
2 * DRCsubcell.c --
3 *
4 * This file provides the facilities for finding design-rule
5 * violations that occur as a result of interactions between
6 * subcells and either paint or other subcells.
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/DRCsubcell.c,v 1.4 2009/05/01 18:59:44 tim Exp $";
23 #endif /* not lint */
24
25 #include <stdio.h>
26 #include <sys/types.h>
27
28 #include "utils/magic.h"
29 #include "textio/textio.h"
30 #include "utils/geometry.h"
31 #include "tiles/tile.h"
32 #include "utils/hash.h"
33 #include "database/database.h"
34 #include "drc/drc.h"
35 #include "windows/windows.h"
36 #include "commands/commands.h"
37 #include "utils/undo.h"
38
39 /* The variables below are made owns so that they can be used to
40 * pass information to the various search functions.
41 */
42
43 static Rect drcSubIntArea; /* Accumulates area of interactions. */
44 static CellDef *drcSubDef; /* Cell definition we're checking. */
45 static int drcSubRadius; /* Interaction radius. */
46 static CellUse *drcCurSub; /* Holds current use while searching for interactions */
47 static Rect drcSubLookArea; /* Area where we're looking for interactions */
48 static void (*drcSubFunc)(); /* Error function. */
49 static ClientData drcSubClientData;
50 /* To be passed to error function. */
51
52 /* The cookie below is dummied up to provide an error message for
53 * errors that occur because of inexact overlaps between subcells.
54 */
55
56 static DRCCookie drcSubcellCookie = {
57 0, 0, 0, 0,
58 { 0 }, { 0 },
59 0, 0, 0,
60 DRC_SUBCELL_OVERLAP_TAG,
61 (DRCCookie *) NULL
62 };
63
64 /* The cookie below is dummied up to provide an error message for
65 * errors that are in a subcell non-interaction area and have been
66 * copied up into the parent without flattening
67 */
68
69 static DRCCookie drcInSubCookie = {
70 0, 0, 0, 0,
71 { 0 }, { 0 },
72 0, 0, 0,
73 DRC_IN_SUBCELL_TAG,
74 (DRCCookie *) NULL
75 };
76
77 /* The following DRC cookie is used when flattening non-Manhattan
78 * shapes results in a non-integer coordinate. Because the non-
79 * integer coordinate cannot be represented in magic, the position
80 * is flagged as a DRC error.
81 */
82
83 static DRCCookie drcOffGridCookie = {
84 0, 0, 0, 0,
85 { 0 }, { 0 },
86 0, 0, 0,
87 DRC_OFFGRID_TAG,
88 (DRCCookie *) NULL
89 };
90
91 extern int DRCErrorType;
92 extern CellDef *DRCErrorDef;
93
94 /*
95 * ----------------------------------------------------------------------------
96 *
97 * drcFindOtherCells --
98 *
99 * This is a search function invoked when looking around a given
100 * cell for interactions. If a cell use is found other than drcCurSub,
101 * then it constitutes an interaction, and its area is included into
102 * the area parameter.
103 *
104 * Results:
105 * Always returns 0 to keep the search alive.
106 *
107 * Side effects:
108 * The area parameter may be modified by including the area
109 * of the current use.
110 *
111 * ----------------------------------------------------------------------------
112 */
113
114 int
drcFindOtherCells(use,area)115 drcFindOtherCells(use, area)
116 CellUse *use;
117 Rect *area;
118 {
119 if (use != drcCurSub)
120 GeoInclude(&use->cu_bbox, area);
121
122 return 0;
123 }
124
125 /*
126 * ----------------------------------------------------------------------------
127 *
128 * drcSubCopyErrors ---
129 *
130 * For each tile found in drcCopyErrorsFunc(), translate the tile position
131 * into the coordinate system of the parent cell (represented by the drcTemp
132 * plane in ClientData) and apply the function passed in the filter, which is
133 * whatever function handles DRC errors inside an error tile (which is
134 * different for "drc why" commands than for "drc check".
135 *
136 * Returns:
137 * 0 to keep the search going.
138 *
139 * ----------------------------------------------------------------------------
140 */
141
142 int
drcSubCopyErrors(tile,cxp)143 drcSubCopyErrors(tile, cxp)
144 Tile *tile;
145 TreeContext *cxp;
146 {
147 Rect area;
148 Rect destArea;
149 struct drcClientData *arg = (struct drcClientData *)cxp->tc_filter->tf_arg;
150
151 TiToRect(tile, &area);
152 GeoClip(&area, &cxp->tc_scx->scx_area);
153 GeoTransRect(&cxp->tc_scx->scx_trans, &area, &destArea);
154
155 (*(arg->dCD_function))(arg->dCD_celldef, &destArea, arg->dCD_cptr,
156 arg->dCD_clientData);
157 (*(arg->dCD_errors))++;
158
159 return 0;
160 }
161
162 /*
163 * ----------------------------------------------------------------------------
164 *
165 * drcSubCopyFunc ---
166 *
167 * This routine is applied for each subcell of a parent def. It calls
168 * DBNoTreeSrTiles() with the above routine drcSubCopyErrors(), which
169 * copies all error tiles from the child cell up into the parent.
170 * This is used only within areas found to be non-interacting with the
171 * parent, such that any error found in the child cell is guaranteed to
172 * be a real error, and not one that might be resolved by additional
173 * material found in the parent or a sibling cell.
174 *
175 * Added 11/10/2020: Moved drcArrayFunc() here; this limits the array
176 * checks to non-interaction areas in the parent cell.
177 * 8/20/2021: Realized that TT_ERROR_S and (maybe?) TT_ERROR_PS tiles
178 * are also error types that must be copied up.
179 *
180 * Returns:
181 * Whatever DBNoTreeSrTiles() returns.
182 *
183 * ----------------------------------------------------------------------------
184 */
185
186 int
drcSubCopyFunc(scx,cdarg)187 drcSubCopyFunc(scx, cdarg)
188 SearchContext *scx;
189 ClientData cdarg;
190 {
191 TileTypeBitMask drcMask;
192
193 /* Create a mask with all of the DRC error types in it */
194 TTMaskZero(&drcMask);
195 TTMaskSetType(&drcMask, TT_ERROR_P);
196 TTMaskSetType(&drcMask, TT_ERROR_S);
197 TTMaskSetType(&drcMask, TT_ERROR_PS);
198
199 /* Use DBNoTreeSrTiles() because we want to search only one level down */
200 return DBNoTreeSrTiles(scx, &drcMask, 0, drcSubCopyErrors, cdarg);
201 }
202
203 /*
204 * ----------------------------------------------------------------------------
205 *
206 * drcSubcellFunc --
207 *
208 * Called by DBSrCellPlaneArea when looking for interactions in
209 * a given area. It sees if this subcell participates
210 * in any interactions in the area we're rechecking.
211 *
212 * Results:
213 * Always returns 0 to keep the search alive.
214 *
215 * Side effects:
216 * The area drcSubIntArea is modified to include interactions
217 * stemming from this subcell.
218 *
219 * ----------------------------------------------------------------------------
220 */
221
222 int
drcSubcellFunc(subUse,propagate)223 drcSubcellFunc(subUse, propagate)
224 CellUse *subUse; /* Subcell instance. */
225 bool *propagate; /* Errors to propagate up */
226 {
227 Rect area, haloArea, intArea, subIntArea, locIntArea;
228 int i;
229
230 /* To determine interactions, find the bounding box of
231 * all paint and other subcells within one halo of this
232 * subcell (and also within the original area where
233 * we're recomputing errors).
234 */
235
236 area = subUse->cu_bbox;
237
238 GEO_EXPAND(&area, drcSubRadius, &haloArea);
239 GeoClip(&haloArea, &drcSubLookArea);
240
241 intArea = GeoNullRect;
242 for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
243 {
244 (void) DBSrPaintArea((Tile *) NULL, drcSubDef->cd_planes[i],
245 &haloArea, &DBAllButSpaceBits, drcIncludeArea,
246 (ClientData) &intArea);
247 }
248
249 /* DRC error tiles in a subcell are automatically pulled into the */
250 /* interaction area of the parent. Ultimately this is recursive as */
251 /* all cells are checked and errors propagate to the top level. */
252
253 subIntArea = GeoNullRect;
254
255 #if (0)
256 /* NOTE: DRC errors inside a subcell should be ignored for */
257 /* the purpose of finding interactions. Errors should only */
258 /* be copied up into the parent when in a non-interaction */
259 /* area. This is done below in DRCFindInteractions(). */
260 /* (Method added by Tim, 10/15/2020) */
261
262 /* Maybe S and PS errors should be pulled here? */
263
264 DBSrPaintArea((Tile *) NULL, subUse->cu_def->cd_planes[PL_DRC_ERROR],
265 &TiPlaneRect, &DBAllButSpaceBits, drcIncludeArea,
266 (ClientData) &subIntArea);
267
268 GeoTransRect(&(subUse->cu_transform), &subIntArea, &locIntArea);
269 GeoInclude(&locIntArea, &intArea);
270 #endif
271
272 if (!GEO_RECTNULL(&subIntArea)) *propagate = TRUE;
273
274 drcCurSub = subUse;
275 (void) DBSrCellPlaneArea(drcSubDef->cd_cellPlane, &haloArea,
276 drcFindOtherCells, (ClientData)(&intArea));
277 if (GEO_RECTNULL(&intArea)) return 0;
278
279 GEO_EXPAND(&intArea, drcSubRadius, &intArea);
280 GeoClip(&intArea, &haloArea);
281 (void) GeoInclude(&intArea, &drcSubIntArea);
282 return 0;
283 }
284
285 /*
286 * ----------------------------------------------------------------------------
287 *
288 * drcAlwaysOne --
289 *
290 * This is a utility procedure that always returns 1 when it
291 * is called. It aborts searches and notifies the invoker that
292 * an item was found during the search.
293 *
294 * Results:
295 * Always returns 1 to abort searches.
296 *
297 * Side effects:
298 * None.
299 *
300 * ----------------------------------------------------------------------------
301 */
302
303 int
drcAlwaysOne()304 drcAlwaysOne()
305 {
306 return 1;
307 }
308
309 /*
310 * ----------------------------------------------------------------------------
311 *
312 * drcSubCheckPaint --
313 *
314 * This procedure is invoked once for each subcell in a
315 * particular interaction area. It checks to see whether the
316 * subcell's subtree actually contains some paint in the potential
317 * interaction area. As soon as the second such subcell is found,
318 * it aborts the search.
319 *
320 * Results:
321 * Returns 0 to keep the search alive, unless we've found the
322 * second subcell containing paint in the interaction area.
323 * When this occurs, the search is aborted by returning 1.
324 *
325 * Side effects:
326 * When the first use with paint is found, curUse is modified
327 * to contain its address.
328 *
329 * ----------------------------------------------------------------------------
330 */
331
332 int
drcSubCheckPaint(scx,curUse)333 drcSubCheckPaint(scx, curUse)
334 SearchContext *scx; /* Contains information about the celluse
335 * that was found.
336 */
337 CellUse **curUse; /* Points to a celluse, or NULL, or -1. -1
338 * means paint was found in the root cell,
339 * and non-NULL means some other celluse had
340 * paint in it. If we find another celluse
341 * with paint, when this is non-NULL, it
342 * means there really are two cells with
343 * interacting paint, so we abort the
344 * search to tell the caller to really check
345 * this area.
346 */
347 {
348 if (DBTreeSrTiles(scx, &DBAllButSpaceAndDRCBits, 0, drcAlwaysOne,
349 (ClientData) NULL) != 0)
350 {
351 /* This subtree has stuff under the interaction area. */
352
353 if (*curUse != NULL) return 1;
354 *curUse = scx->scx_use;
355 }
356 return 0;
357 }
358
359 /*
360 * ----------------------------------------------------------------------------
361 *
362 * DRCFindInteractions --
363 *
364 * This procedure finds the bounding box of all subcell-subcell
365 * or subcell-paint interactions in a given area of a given cell.
366 *
367 * Results:
368 * Returns TRUE if there were any interactions in the given
369 * area, FALSE if there were none.
370 *
371 * Side effects:
372 * The parameter interaction is set to contain the bounding box
373 * of all places in area where one subcell comes within radius
374 * of another subcell, or where paint in def comes within radius
375 * of a subcell. Interactions between elements of array are not
376 * considered here, but interactions between arrays and other
377 * things are considered. This routine is a bit clever, in that
378 * it not only checks for bounding boxes interacting, but also
379 * makes sure the cells really contain material in the interaction
380 * area.
381 * ----------------------------------------------------------------------------
382 */
383
384 bool
DRCFindInteractions(def,area,radius,interaction)385 DRCFindInteractions(def, area, radius, interaction)
386 CellDef *def; /* Cell to check for interactions. */
387 Rect *area; /* Area of def to check for interacting
388 * material.
389 */
390 int radius; /* How close two pieces of material must be
391 * to be considered interacting. Two pieces
392 * radius apart do NOT interact, but if they're
393 * close than this they do.
394 */
395 Rect *interaction; /* Gets filled in with the bounding box of
396 * the interaction area, if any. Doesn't
397 * have a defined value when FALSE is returned.
398 */
399 {
400 int i;
401 CellUse *use;
402 SearchContext scx;
403 bool propagate;
404
405 drcSubDef = def;
406 drcSubRadius = radius;
407 DRCDummyUse->cu_def = def;
408
409 /* Find all the interactions in the area and compute the
410 * outer bounding box of all those interactions. An interaction
411 * exists whenever material in one cell approaches within radius
412 * of material in another cell. As a first approximation, assume
413 * each cell has material everywhere within its bounding box.
414 */
415
416 drcSubIntArea = GeoNullRect;
417 GEO_EXPAND(area, radius, &drcSubLookArea);
418 propagate = FALSE;
419 (void) DBSrCellPlaneArea(def->cd_cellPlane, &drcSubLookArea,
420 drcSubcellFunc, (ClientData)(&propagate));
421
422 /* If there seems to be an interaction area, make a second pass
423 * to make sure there's more than one cell with paint in the
424 * area. This will save us a lot of work where two cells
425 * have overlapping bounding boxes without overlapping paint.
426 */
427
428 if (GEO_RECTNULL(&drcSubIntArea)) return FALSE;
429 use = NULL;
430
431 /* If errors are being propagated up from child to parent, */
432 /* then the interaction area is always valid. */
433
434 if (propagate == FALSE)
435 {
436 for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
437 {
438 if (DBSrPaintArea((Tile *) NULL, def->cd_planes[i],
439 &drcSubIntArea, &DBAllButSpaceBits, drcAlwaysOne,
440 (ClientData) NULL) != 0)
441 {
442 use = (CellUse *) -1;
443 break;
444 }
445 }
446 scx.scx_use = DRCDummyUse;
447 scx.scx_trans = GeoIdentityTransform;
448 scx.scx_area = drcSubIntArea;
449 if (DBTreeSrCells(&scx, 0, drcSubCheckPaint, (ClientData) &use) == 0)
450 return FALSE;
451 }
452
453 /* OK, no more excuses, there's really an interaction area here. */
454
455 *interaction = drcSubIntArea;
456 GeoClip(interaction, area);
457 if (GEO_RECTNULL(interaction)) return FALSE;
458 return TRUE;
459 }
460
461 /*
462 * ----------------------------------------------------------------------------
463 *
464 * drcExactOverlapCheck --
465 *
466 * This procedure is invoked to check for overlap violations.
467 * It is invoked by DBSrPaintArea from drcExactOverlapTile.
468 * Any tiles passed to this procedure must lie within
469 * arg->dCD_rect, or an error is reported.
470 *
471 * Results:
472 * Always returns 0 to keep the search alive.
473 *
474 * Side effects:
475 * If an error occurs, the client error function is called and
476 * the error count is incremented.
477 *
478 * ----------------------------------------------------------------------------
479 */
480
481 int
drcExactOverlapCheck(tile,arg)482 drcExactOverlapCheck(tile, arg)
483 Tile *tile; /* Tile to check. */
484 struct drcClientData *arg; /* How to detect and process errors. */
485 {
486 Rect rect;
487
488 TiToRect(tile, &rect);
489 GeoClip(&rect, arg->dCD_clip);
490 if (GEO_RECTNULL(&rect)) return 0;
491
492 (*(arg->dCD_function)) (arg->dCD_celldef, &rect, arg->dCD_cptr,
493 arg->dCD_clientData);
494 (*(arg->dCD_errors))++;
495 return 0;
496 }
497
498 /*
499 * ----------------------------------------------------------------------------
500 *
501 * drcExactOverlapTile --
502 *
503 * This procedure is invoked by DBTreeSrTiles for each tile
504 * in each constituent cell of a subcell interaction. It
505 * makes sure that if this tile overlaps other tiles of the
506 * same type in other cells, then the overlaps are EXACT:
507 * each cell contains exactly the same information.
508 *
509 * Results:
510 * Always returns 0 to keep the search alive.
511 *
512 * Side effects:
513 * If there are errors, the client error handling routine
514 * is invoked and the count in the drcClientData record is
515 * incremented.
516 *
517 * ----------------------------------------------------------------------------
518 */
519
520 int
drcExactOverlapTile(tile,cxp)521 drcExactOverlapTile(tile, cxp)
522 Tile *tile; /* Tile that must overlap exactly. */
523 TreeContext *cxp; /* Tells how to translate out of subcell.
524 * The client data must be a drcClientData
525 * record, and the caller must have filled
526 * in the celldef, clip, errors, function,
527 * cptr, and clientData fields.
528 */
529 {
530 struct drcClientData *arg;
531 TileTypeBitMask typeMask, invMask, *rmask;
532 TileType type, t;
533 Tile *tp;
534 Rect r1, r2, r3, rex;
535 int i;
536
537 arg = (struct drcClientData *) cxp->tc_filter->tf_arg;
538 TiToRect(tile, &r1);
539 GeoTransRect(&(cxp->tc_scx->scx_trans), &r1, &r2);
540
541 GEO_EXPAND(&r2, 1, &rex); /* Area includes abutting tiles */
542 GeoClip(&rex, arg->dCD_clip); /* Except areas outside search area */
543
544 type = TiGetType(tile);
545 TTMaskSetOnlyType(&typeMask, type);
546 if (type < DBNumUserLayers)
547 {
548 for (t = DBNumUserLayers; t < DBNumTypes; t++)
549 {
550 rmask = DBResidueMask(t);
551 if (TTMaskHasType(rmask, type))
552 TTMaskSetType(&typeMask, t);
553 }
554 TTMaskCom2(&invMask, &typeMask);
555 }
556 else
557 {
558 rmask = DBResidueMask(type);
559 TTMaskSetMask(&typeMask, rmask); // Add residue types for inverse only
560 TTMaskCom2(&invMask, &typeMask);
561 TTMaskSetOnlyType(&typeMask, type); // Restore original type mask
562 }
563
564 for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
565 {
566 if (DBSrPaintArea((Tile *) NULL, DRCdef->cd_planes[i],
567 &rex, &typeMask, drcAlwaysOne, (ClientData) NULL))
568 {
569 /* There is an overlap or abutment of ExactOverlap types. */
570 /* 1) Check if any invalid type is under this tile. */
571
572 arg->dCD_rect = &r2;
573 DBSrPaintArea((Tile *) NULL, DRCdef->cd_planes[i], &r2,
574 &invMask, drcExactOverlapCheck, (ClientData) arg);
575
576 /* 2) Search the neighboring tiles for types that do not */
577 /* match the exact overlap type, and flag abutment errors. */
578
579 /* Search bottom */
580 arg->dCD_rect = &r3;
581 for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
582 if (TTMaskHasType(&invMask, TiGetType(tp)))
583 {
584 TiToRect(tp, &r1);
585 GeoTransRect(&(cxp->tc_scx->scx_trans), &r1, &r3);
586 GeoClip(&r3, &rex);
587 if (!GEO_RECTNULL(&r3))
588 DBSrPaintArea((Tile *) NULL, DRCdef->cd_planes[i],
589 &r3, &typeMask, drcExactOverlapCheck,
590 (ClientData) arg);
591 }
592
593 /* Search right */
594 for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
595 if (TTMaskHasType(&invMask, TiGetType(tp)))
596 {
597 TiToRect(tp, &r1);
598 GeoTransRect(&(cxp->tc_scx->scx_trans), &r1, &r3);
599 GeoClip(&r3, &rex);
600 if (!GEO_RECTNULL(&r3))
601 DBSrPaintArea((Tile *) NULL, DRCdef->cd_planes[i],
602 &r3, &typeMask, drcExactOverlapCheck,
603 (ClientData) arg);
604 }
605
606 /* Search top */
607 for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
608 if (TTMaskHasType(&invMask, TiGetType(tp)))
609 {
610 TiToRect(tp, &r1);
611 GeoTransRect(&(cxp->tc_scx->scx_trans), &r1, &r3);
612 GeoClip(&r3, &rex);
613 if (!GEO_RECTNULL(&r3))
614 DBSrPaintArea((Tile *) NULL, DRCdef->cd_planes[i],
615 &r3, &typeMask, drcExactOverlapCheck,
616 (ClientData) arg);
617 }
618
619 /* Search left */
620 for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
621 if (TTMaskHasType(&invMask, TiGetType(tp)))
622 {
623 TiToRect(tp, &r1);
624 GeoTransRect(&(cxp->tc_scx->scx_trans), &r1, &r3);
625 GeoClip(&r3, &rex);
626 if (!GEO_RECTNULL(&r3))
627 DBSrPaintArea((Tile *) NULL, DRCdef->cd_planes[i],
628 &r3, &typeMask, drcExactOverlapCheck,
629 (ClientData) arg);
630 }
631 }
632 }
633 return 0;
634 }
635
636 /*
637 * ----------------------------------------------------------------------------
638 *
639 * DRCOffGridError ---
640 *
641 * Function to call when a call to DBCellCheckCopyAllPaint() flags an error
642 * indicating that a subcell overlap of non-Manhattan geometry resolves to
643 * an off-grid intersection point. Note that this is different from the
644 * DRC off-grid check, which checks for geometry that does not match the
645 * manufacturing grid pitch. This checks for the case of geometry that
646 * is finer than the underlying database grid, which can only happen for
647 * two non-Manhattan shapes interacting between two different cells, and
648 * can only be caught during the process of flattening the cell contents.
649 *
650 * Results:
651 * None.
652 *
653 * Side effects:
654 * Creates a DRC error or prints the DRC error message, depending on
655 * the value of drcSubFunc.
656 *
657 * ----------------------------------------------------------------------------
658 */
659
660 void
DRCOffGridError(rect)661 DRCOffGridError(rect)
662 Rect *rect; /* Area of error */
663 {
664 if (drcSubFunc == NULL) return;
665 (*drcSubFunc)(DRCErrorDef, rect, &drcOffGridCookie, drcSubClientData);
666 }
667
668 /*
669 * ----------------------------------------------------------------------------
670 *
671 * DRCInteractionCheck --
672 *
673 * This is the top-level procedure that performs subcell interaction
674 * checks. All interaction rule violations in area of def are
675 * found, and func is called for each one.
676 *
677 * Results:
678 * The number of errors found.
679 *
680 * Side effects:
681 * The procedure func is called for each violation found. See
682 * the header for DRCBasicCheck for information about how func
683 * is called. The violations passed to func are expressed in
684 * the coordinates of def. Only violations stemming from
685 * interactions in def, as opposed to def's children, are reported.
686 *
687 * Design Note:
688 * This procedure is trickier than you think. The problem is that
689 * DRC must be guaranteed to produce EXACTLY the same collection
690 * of errors in an area, no matter how the area is checked. Checking
691 * it all as one big area should produce the same results as
692 * checking it in several smaller pieces. Otherwise, "drc why"
693 * won't work correctly, and the error configuration will depend
694 * on how the chip was checked, which is intolerable. This problem
695 * is solved here by dividing the world up into squares along a grid
696 * of dimension DRCStepSize aligned at the origin. Interaction areas
697 * are always computed by considering everything inside one grid square
698 * at a time. We may have to consider several grid squares in order
699 * to cover the area passed in by the client.
700 * ----------------------------------------------------------------------------
701 */
702
703 int
DRCInteractionCheck(def,area,erasebox,func,cdarg)704 DRCInteractionCheck(def, area, erasebox, func, cdarg)
705 CellDef *def; /* Definition in which to do check. */
706 Rect *area; /* Area in which all errors are to be found. */
707 Rect *erasebox; /* Smaller area containing DRC check tiles */
708 void (*func)(); /* Function to call for each error. */
709 ClientData cdarg; /* Extra info to be passed to func. */
710 {
711 int oldTiles, count, x, y, errorSaveType;
712 Rect intArea, square, cliparea, subArea;
713 PaintResultType (*savedPaintTable)[NT][NT];
714 int (*savedPaintPlane)();
715 struct drcClientData arg;
716 SearchContext scx;
717
718 drcSubFunc = func;
719 drcSubClientData = cdarg;
720 oldTiles = DRCstatTiles;
721 count = 0;
722
723 /* Divide the area to be checked up into squares. Process each
724 * square separately.
725 */
726
727 x = (area->r_xbot/DRCStepSize) * DRCStepSize;
728 if (x > area->r_xbot) x -= DRCStepSize;
729 y = (area->r_ybot/DRCStepSize) * DRCStepSize;
730 if (y > area->r_ybot) y -= DRCStepSize;
731 for (square.r_xbot = x; square.r_xbot < area->r_xtop;
732 square.r_xbot += DRCStepSize)
733 for (square.r_ybot = y; square.r_ybot < area->r_ytop;
734 square.r_ybot += DRCStepSize)
735 {
736 square.r_xtop = square.r_xbot + DRCStepSize;
737 square.r_ytop = square.r_ybot + DRCStepSize;
738
739 /* Limit square to erasebox. Otherwise, a huge processing */
740 /* penalty is incurred for finding a single error (e.g., */
741 /* using "drc find" or "drc why" in a large design with a */
742 /* large step size. */
743
744 cliparea = square;
745 GeoClip(&cliparea, area);
746
747 /* Prepare for subcell search */
748 DRCDummyUse->cu_def = def;
749 scx.scx_use = DRCDummyUse;
750 scx.scx_trans = GeoIdentityTransform;
751 arg.dCD_celldef = def;
752 arg.dCD_errors = &count;
753 arg.dCD_cptr = &drcInSubCookie;
754 arg.dCD_function = func;
755 arg.dCD_clientData = cdarg;
756
757 /* Find all the interactions in the square, and clip to the error
758 * area we're interested in. */
759
760 if (!DRCFindInteractions(def, &cliparea, DRCTechHalo, &intArea))
761 {
762 /* Added May 4, 2008---if there are no subcells, run the
763 * basic check over the area of the erasebox.
764 */
765 subArea = *erasebox;
766 GeoClip(&subArea, &cliparea);
767 GEO_EXPAND(&subArea, DRCTechHalo, &intArea);
768
769 errorSaveType = DRCErrorType;
770 DRCErrorType = TT_ERROR_P; // Basic check is always ERROR_P
771 DRCBasicCheck(def, &intArea, &subArea, func, cdarg);
772
773 /* Copy errors up from all non-interacting children */
774 scx.scx_area = subArea;
775 arg.dCD_clip = &subArea;
776 DBCellSrArea(&scx, drcSubCopyFunc, &arg);
777 DBCellSrArea(&scx, drcArrayFunc, &arg);
778
779 DRCErrorType = errorSaveType;
780 continue;
781 }
782 else
783 {
784 /* Added March 6, 2012: Any area(s) outside the
785 * interaction area are processed with the basic
786 * check. This avoids unnecessary copying, so it
787 * speeds up the DRC without requiring that geometry
788 * passes DRC rules independently of subcell geometry
789 * around it.
790 *
791 * As intArea can be smaller than square, we may have
792 * to process as many as four independent rectangles.
793 * NOTE that the area of (intArea + halo) will be checked
794 * in the subcell interaction check, so we can ignore
795 * that.
796 */
797 Rect eraseClip, eraseHalo, subArea;
798
799 errorSaveType = DRCErrorType;
800 DRCErrorType = TT_ERROR_P; // Basic check is always ERROR_P
801 eraseClip = *erasebox;
802 GeoClip(&eraseClip, &cliparea);
803 subArea = eraseClip;
804 arg.dCD_clip = &subArea;
805
806 /* check above */
807 if (intArea.r_ytop < eraseClip.r_ytop)
808 {
809 subArea.r_ybot = intArea.r_ytop;
810 GEO_EXPAND(&subArea, DRCTechHalo, &eraseHalo);
811 DRCBasicCheck(def, &eraseHalo, &subArea, func, cdarg);
812 /* Copy errors up from all non-interacting children */
813 scx.scx_area = subArea;
814 DBCellSrArea(&scx, drcSubCopyFunc, &arg);
815 DBCellSrArea(&scx, drcArrayFunc, &arg);
816 }
817 /* check below */
818 if (intArea.r_ybot > eraseClip.r_ybot)
819 {
820 subArea.r_ybot = eraseClip.r_ybot;
821 subArea.r_ytop = intArea.r_ybot;
822 GEO_EXPAND(&subArea, DRCTechHalo, &eraseHalo);
823 DRCBasicCheck(def, &eraseHalo, &subArea, func, cdarg);
824 /* Copy errors up from all non-interacting children */
825 scx.scx_area = subArea;
826 DBCellSrArea(&scx, drcSubCopyFunc, &arg);
827 DBCellSrArea(&scx, drcArrayFunc, &arg);
828 }
829 subArea.r_ytop = intArea.r_ytop;
830 subArea.r_ybot = intArea.r_ybot;
831
832 /* check right */
833 if (intArea.r_xtop < eraseClip.r_xtop)
834 {
835 subArea.r_xbot = intArea.r_xtop;
836 GEO_EXPAND(&subArea, DRCTechHalo, &eraseHalo);
837 DRCBasicCheck(def, &eraseHalo, &subArea, func, cdarg);
838 /* Copy errors up from all non-interacting children */
839 scx.scx_area = subArea;
840 DBCellSrArea(&scx, drcSubCopyFunc, &arg);
841 DBCellSrArea(&scx, drcArrayFunc, &arg);
842 }
843 /* check left */
844 if (intArea.r_xbot > eraseClip.r_xbot)
845 {
846 subArea.r_xtop = intArea.r_xbot;
847 subArea.r_xbot = eraseClip.r_xbot;
848 GEO_EXPAND(&subArea, DRCTechHalo, &eraseHalo);
849 DRCBasicCheck(def, &eraseHalo, &subArea, func, cdarg);
850 /* Copy errors up from all non-interacting children */
851 scx.scx_area = subArea;
852 DBCellSrArea(&scx, drcSubCopyFunc, &arg);
853 DBCellSrArea(&scx, drcArrayFunc, &arg);
854 }
855 DRCErrorType = errorSaveType;
856 }
857
858 /* Clip interaction area against subArea-expanded-by-halo */
859
860 subArea = *erasebox;
861 GEO_EXPAND(&subArea, DRCTechHalo, &cliparea);
862 GeoClip(&intArea, &cliparea);
863
864 /* Flatten the interaction area. */
865
866 DRCstatInteractions += 1;
867 GEO_EXPAND(&intArea, DRCTechHalo, &scx.scx_area);
868 DBCellClearDef(DRCdef);
869
870 savedPaintTable = DBNewPaintTable(DRCCurStyle->DRCPaintTable);
871 savedPaintPlane = DBNewPaintPlane(DBPaintPlaneMark);
872
873 (void) DBCellCheckCopyAllPaint(&scx, &DBAllButSpaceBits, 0,
874 DRCuse, func);
875
876 (void) DBNewPaintTable(savedPaintTable);
877 (void) DBNewPaintPlane(savedPaintPlane);
878
879 /* Run the basic checker over the interaction area. */
880
881 count += DRCBasicCheck(DRCdef, &scx.scx_area, &intArea,
882 func, cdarg);
883 /* TxPrintf("Interaction area: (%d, %d) (%d %d)\n",
884 intArea.r_xbot, intArea.r_ybot,
885 intArea.r_xtop, intArea.r_ytop);
886 */
887
888 /* Check for illegal partial overlaps. */
889
890 scx.scx_area = intArea;
891 arg.dCD_clip = &intArea;
892 arg.dCD_celldef = DRCdef;
893 arg.dCD_cptr = &drcSubcellCookie;
894 (void) DBTreeSrUniqueTiles(&scx, &DRCCurStyle->DRCExactOverlapTypes,
895 0, drcExactOverlapTile, (ClientData) &arg);
896 }
897
898 /* Update count of interaction tiles processed. */
899
900 DRCstatIntTiles += DRCstatTiles - oldTiles;
901 return count;
902 }
903
904 void
DRCFlatCheck(use,area)905 DRCFlatCheck(use, area)
906 CellUse *use;
907 Rect *area;
908 {
909 int x, y;
910 Rect chunk;
911 SearchContext scx;
912 void drcIncCount();
913 PaintResultType (*savedPaintTable)[NT][NT];
914 int (*savedPaintPlane)();
915 int drcFlatCount = 0;
916
917 UndoDisable();
918 for (y = area->r_ybot; y < area->r_ytop; y += 300)
919 {
920 for (x = area->r_xbot; x < area->r_xtop; x += 300)
921 {
922 chunk.r_xbot = x;
923 chunk.r_ybot = y;
924 chunk.r_xtop = x+300;
925 chunk.r_ytop = y+300;
926 if (chunk.r_xtop > area->r_xtop) chunk.r_xtop = area->r_xtop;
927 if (chunk.r_ytop > area->r_ytop) chunk.r_ytop = area->r_ytop;
928 GEO_EXPAND(&chunk, DRCTechHalo, &scx.scx_area);
929 scx.scx_use = use;
930 scx.scx_trans = GeoIdentityTransform;
931 DBCellClearDef(DRCdef);
932
933 savedPaintTable = DBNewPaintTable(DRCCurStyle->DRCPaintTable);
934 savedPaintPlane = DBNewPaintPlane(DBPaintPlaneMark);
935
936 (void) DBCellCopyAllPaint(&scx, &DBAllButSpaceBits, 0, DRCuse);
937
938 (void) DBNewPaintTable(savedPaintTable);
939 (void) DBNewPaintPlane(savedPaintPlane);
940
941 (void) DRCBasicCheck(DRCdef, &scx.scx_area, &chunk,
942 drcIncCount, (ClientData) &drcFlatCount);
943 }
944 }
945 TxPrintf("%d total errors found.\n", drcFlatCount);
946 UndoEnable();
947 }
948
949 void
drcIncCount(def,area,rule,count)950 drcIncCount(def, area, rule, count)
951 CellDef *def;
952 Rect *area;
953 DRCCookie *rule;
954 int *count;
955 {
956 *count++;
957 }
958