#ifndef lint static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/drc/DRCextend.c,v 1.6 2010/09/20 21:13:22 tim Exp $"; #endif #include #include #include #include "utils/magic.h" #include "utils/malloc.h" #include "utils/geometry.h" #include "tiles/tile.h" #include "utils/hash.h" #include "database/database.h" #include "windows/windows.h" #include "dbwind/dbwind.h" #include "dbwind/dbwtech.h" #include "drc/drc.h" #include "utils/signals.h" #include "utils/stack.h" #include "utils/maxrect.h" Stack *DRCstack = (Stack *)NULL; #define PUSHTILE(tp) \ if (TiGetClient(tp) == DRC_UNPROCESSED) { \ TiSetClientINT(tp, DRC_PENDING); \ STACKPUSH((ClientData) (tp), DRCstack); \ } /* *------------------------------------------------------------------------- * * drcCheckAngles --- checks whether a tile conforms to orthogonal-only * geometry (90 degree angles only) or 45-degree geometry (x must * be equal to y on all non-Manhattan tiles). * * Results: none * * Side Effects: may cause errors to be painted. * * NOTES: Tile has been determined to be a split tile before this * routine is called. * *------------------------------------------------------------------------- */ void drcCheckAngles(tile, arg, cptr) Tile *tile; struct drcClientData *arg; DRCCookie *cptr; { Rect rect; bool ortho = (cptr->drcc_flags & DRC_ANGLES_45) ? FALSE : TRUE; if (ortho || ((RIGHT(tile) - LEFT(tile)) != (TOP(tile) - BOTTOM(tile)))) { TiToRect(tile, &rect); GeoClip(&rect, arg->dCD_clip); if (!GEO_RECTNULL(&rect)) { arg->dCD_cptr = cptr; (*(arg->dCD_function)) (arg->dCD_celldef, &rect, arg->dCD_cptr, arg->dCD_clientData); (*(arg->dCD_errors))++; } } } /* *------------------------------------------------------------------------- * * drcCheckOffGrid- checks to see that an edge is on the specified * grid pitch. * * Results: none * * Side Effects: may cause errors to be painted. * *------------------------------------------------------------------------- */ void drcCheckOffGrid(edgeRect, arg, cptr) Rect *edgeRect; struct drcClientData *arg; DRCCookie *cptr; { Rect rect; int gtest; if (cptr->drcc_dist <= 1) return; /* No error by definition */ rect = *edgeRect; GeoClip(&rect, arg->dCD_clip); /* Expand rect to nearest pitch */ gtest = (rect.r_xbot / cptr->drcc_dist) * cptr->drcc_dist; if (gtest < rect.r_xbot) rect.r_xbot = gtest; gtest = (rect.r_xtop / cptr->drcc_dist) * cptr->drcc_dist; if (gtest > rect.r_xtop) rect.r_xtop = gtest; gtest = (rect.r_ybot / cptr->drcc_dist) * cptr->drcc_dist; if (gtest < rect.r_ybot) rect.r_ybot = gtest; gtest = (rect.r_ytop / cptr->drcc_dist) * cptr->drcc_dist; if (gtest > rect.r_ytop) rect.r_ytop = gtest; if (!GEO_RECTNULL(&rect)) { (*(arg->dCD_function)) (arg->dCD_celldef, &rect, arg->dCD_cptr, arg->dCD_clientData); (*(arg->dCD_errors))++; } } /* *------------------------------------------------------------------------- * * drcCheckArea- checks to see that a collection of tiles of a given * type have more than a minimum area. * * Results: none * * Side Effects: may cause errors to be painted. * *------------------------------------------------------------------------- */ void drcCheckArea(starttile,arg,cptr) Tile *starttile; struct drcClientData *arg; DRCCookie *cptr; { int arealimit; long area = 0L; TileTypeBitMask *oktypes = &cptr->drcc_mask; Tile *tile,*tp; Rect *cliprect = arg->dCD_rect; arealimit = cptr->drcc_cdist; arg->dCD_cptr = cptr; if (DRCstack == (Stack *) NULL) DRCstack = StackNew(64); /* Mark this tile as pending and push it */ PUSHTILE(starttile); while (!StackEmpty(DRCstack)) { tile = (Tile *) STACKPOP(DRCstack); if (TiGetClientINT(tile) != DRC_PENDING) continue; area += (long)(RIGHT(tile)-LEFT(tile))*(TOP(tile)-BOTTOM(tile)); TiSetClientINT(tile, DRC_PROCESSED); /* are we at the clip boundary? If so, skip to the end */ if (RIGHT(tile) == cliprect->r_xtop || LEFT(tile) == cliprect->r_xbot || BOTTOM(tile) == cliprect->r_ybot || TOP(tile) == cliprect->r_ytop) goto forgetit; if (area >= (long)arealimit) goto forgetit; /* Top */ for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp)) if (TTMaskHasType(oktypes, TiGetBottomType(tp))) PUSHTILE(tp); /* Left */ for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp)) if (TTMaskHasType(oktypes, TiGetRightType(tp))) PUSHTILE(tp); /* Bottom */ for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp)) if (TTMaskHasType(oktypes, TiGetTopType(tp))) PUSHTILE(tp); /* Right */ for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp)) if (TTMaskHasType(oktypes, TiGetLeftType(tp))) PUSHTILE(tp); } if (area < (long)arealimit) { Rect rect; TiToRect(starttile,&rect); GeoClip(&rect, arg->dCD_clip); if (!GEO_RECTNULL(&rect)) { (*(arg->dCD_function)) (arg->dCD_celldef, &rect, arg->dCD_cptr, arg->dCD_clientData); (*(arg->dCD_errors))++; } } forgetit: while (!StackEmpty(DRCstack)) tile = (Tile *) STACKPOP(DRCstack); /* reset the tiles */ TiSetClient(starttile, DRC_UNPROCESSED); STACKPUSH(starttile, DRCstack); while (!StackEmpty(DRCstack)) { tile = (Tile *) STACKPOP(DRCstack); /* Top */ for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp)) if (TiGetClient(tp) != DRC_UNPROCESSED) { TiSetClient(tp, DRC_UNPROCESSED); STACKPUSH(tp,DRCstack); } /* Left */ for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp)) if (TiGetClient(tp) != DRC_UNPROCESSED) { TiSetClient(tp, DRC_UNPROCESSED); STACKPUSH(tp,DRCstack); } /* Bottom */ for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp)) if (TiGetClient(tp) != DRC_UNPROCESSED) { TiSetClient(tp, DRC_UNPROCESSED); STACKPUSH(tp,DRCstack); } /* Right */ for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp)) if (TiGetClient(tp) != DRC_UNPROCESSED) { TiSetClient(tp, DRC_UNPROCESSED); STACKPUSH(tp,DRCstack); } } } /* *------------------------------------------------------------------------- * * drcCheckMaxwidth - checks to see that at least one dimension of a region * does not exceed some amount (original version---for "bends_illegal" * option only). * * This should really be folded together with drcCheckArea, since the routines * are nearly identical, but I'm feeling lazy, so I'm just duplicating * the code for now. * * Results: 1 if within max bounds, 0 otherwise. * * Side Effects: may cause errors to be painted. * *------------------------------------------------------------------------- */ int drcCheckMaxwidth(starttile,arg,cptr,both) Tile *starttile; struct drcClientData *arg; DRCCookie *cptr; bool both; { int width; int height; int edgelimit; int retval = 0; Rect boundrect; TileTypeBitMask *oktypes; Tile *tile,*tp; oktypes = &cptr->drcc_mask; edgelimit = cptr->drcc_dist; arg->dCD_cptr = cptr; if (DRCstack == (Stack *) NULL) DRCstack = StackNew(64); /* Mark this tile as pending and push it */ PUSHTILE(starttile); TiToRect(starttile,&boundrect); while (!StackEmpty(DRCstack)) { tile = (Tile *) STACKPOP(DRCstack); if (TiGetClientINT(tile) != DRC_PENDING) continue; TiSetClientINT(tile, DRC_PROCESSED); if (boundrect.r_xbot > LEFT(tile)) boundrect.r_xbot = LEFT(tile); if (boundrect.r_xtop < RIGHT(tile)) boundrect.r_xtop = RIGHT(tile); if (boundrect.r_ybot > BOTTOM(tile)) boundrect.r_ybot = BOTTOM(tile); if (boundrect.r_ytop < TOP(tile)) boundrect.r_ytop = TOP(tile); if (boundrect.r_xtop - boundrect.r_xbot > edgelimit && boundrect.r_ytop - boundrect.r_ybot > edgelimit) { while (!StackEmpty(DRCstack)) tile = (Tile *) STACKPOP(DRCstack); break; } /* Top */ for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp)) if (TTMaskHasType(oktypes, TiGetBottomType(tp))) PUSHTILE(tp); /* Left */ for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp)) if (TTMaskHasType(oktypes, TiGetRightType(tp))) PUSHTILE(tp); /* Bottom */ for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp)) if (TTMaskHasType(oktypes, TiGetTopType(tp))) PUSHTILE(tp); /* Right */ for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp)) if (TTMaskHasType(oktypes, TiGetLeftType(tp))) PUSHTILE(tp); } width = boundrect.r_xtop - boundrect.r_xbot; height = boundrect.r_ytop - boundrect.r_ybot; if ( (width > edgelimit && height > edgelimit) || ( both == TRUE && (width > edgelimit || height > edgelimit)) ) { Rect rect; TiToRect(starttile,&rect); GeoClip(&rect, arg->dCD_clip); if (!GEO_RECTNULL(&rect)) { (*(arg->dCD_function)) (arg->dCD_celldef, &rect, arg->dCD_cptr, arg->dCD_clientData); (*(arg->dCD_errors))++; retval = 1; } } /* reset the tiles */ TiSetClient(starttile, DRC_UNPROCESSED); STACKPUSH(starttile, DRCstack); while (!StackEmpty(DRCstack)) { tile = (Tile *) STACKPOP(DRCstack); /* Top */ for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp)) if (TiGetClient(tp) != DRC_UNPROCESSED) { TiSetClient(tp, DRC_UNPROCESSED); STACKPUSH(tp,DRCstack); } /* Left */ for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp)) if (TiGetClient(tp) != DRC_UNPROCESSED) { TiSetClient(tp, DRC_UNPROCESSED); STACKPUSH(tp,DRCstack); } /* Bottom */ for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp)) if (TiGetClient(tp) != DRC_UNPROCESSED) { TiSetClient(tp, DRC_UNPROCESSED); STACKPUSH(tp,DRCstack); } /* Right */ for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp)) if (TiGetClient(tp) != DRC_UNPROCESSED) { TiSetClient(tp, DRC_UNPROCESSED); STACKPUSH(tp,DRCstack); } } return retval; } /* *------------------------------------------------------------------------- * * drcCheckRectSize- * * Checks to see that a collection of tiles of given * types have the proper size (max size and also even or odd size). * * Results: none * * Side Effects: may cause errors to be painted. * *------------------------------------------------------------------------- */ void drcCheckRectSize(starttile, arg, cptr) Tile *starttile; struct drcClientData *arg; DRCCookie *cptr; { int maxsize, even; TileTypeBitMask *oktypes = &cptr->drcc_mask; int width; int height; int errwidth; int errheight; Tile *t; bool error = FALSE; maxsize = cptr->drcc_dist; even = cptr->drcc_cdist; /* This code only has to work for rectangular regions, since we always * check for rectangular-ness using normal edge rules produced when * we read in the tech file. */ arg->dCD_cptr = cptr; ASSERT(TTMaskHasType(oktypes, TiGetType(starttile)), "drcCheckRectSize"); for (t = starttile; TTMaskHasType(oktypes, TiGetType(t)); t = TR(t)) /* loop has empty body */ ; errwidth = width = LEFT(t) - LEFT(starttile); for (t = starttile; TTMaskHasType(oktypes, TiGetType(t)); t = RT(t)) /* loop has empty body */ ; errheight = height = BOTTOM(t) - BOTTOM(starttile); ASSERT(width > 0 && height > 0, "drcCheckRectSize"); if (width > maxsize) {error = TRUE; errwidth = (width - maxsize);} else if (height > maxsize) {error = TRUE; errheight = (height - maxsize);} else if (even >= 0) { /* meaning of "even" variable: -1, any; 0, even; 1, odd */ if (ABS(width - ((width/2)*2)) != even) {error = TRUE; errwidth = 1;} else if (ABS(height - ((height/2)*2)) != even) {error = TRUE; errheight = 1;} } if (error) { Rect rect; TiToRect(starttile, &rect); rect.r_xtop = rect.r_xbot + errwidth; rect.r_ytop = rect.r_ybot + errheight; GeoClip(&rect, arg->dCD_clip); if (!GEO_RECTNULL(&rect)) { (*(arg->dCD_function)) (arg->dCD_celldef, &rect, arg->dCD_cptr, arg->dCD_clientData); (*(arg->dCD_errors))++; } } } /* *------------------------------------------------------------------------- * * MaxRectsExclude --- * * Trivial callback function which detects if a type is found * overlapping a Maxrects area. * * Results: * Always return 1 to immediately halt the search. * * Side effects: * None. * *------------------------------------------------------------------------- */ int MaxRectsExclude( Tile *tile, ClientData clientdata) { return 1; } /* *------------------------------------------------------------------------- * * drcCanonicalMaxwidth - checks to see that at least one dimension of a * rectangular region does not exceed some amount. * * This differs from "CheckMaxwidth" in being more rigorous about * determining where a region of max width might be found. There * is no "bend" rule here. We check from the edge being observed * and back, and adjust the bounds on the sides, forking as * necessary to consider alternative arrangements of the interior * rectangle. A distance "dist" is passed to the routine. We * may push the interior rectangle back by up to this amount from * the observed edge. For "widespacing" rules, we check all * interior regions that satisfy maxwidth and whose edge is * within "dist" of the original edge. For slotting requirement * rules, "dist" is zero (inability to find a rectangle touching * the original edge ensures that no such rectangle exists that * can't be found touching a different edge). Also, we only * need to check one of the four possible edge combinations * (this part of it is handled in the drcBasic code). * * Results: * LinkedRect list of areas satisfying maxwidth. There may be * more than one rectangle, and rectangles may overlap. It * may make more sense to return only one rectangle, the union * of all rectangles in the list. * * Side Effects: * None. * *------------------------------------------------------------------------- */ MaxRectsData * drcCanonicalMaxwidth(starttile, dir, arg, cptr) Tile *starttile; int dir; /* direction of rule */ struct drcClientData *arg; DRCCookie *cptr; { int s, edgelimit; Tile *tile,*tp; TileTypeBitMask wrongtypes; static MaxRectsData *mrd = (MaxRectsData *)NULL; Rect *boundrect, boundorig; /* Generate an initial array size of 8 for rlist and swap. */ if (mrd == (MaxRectsData *)NULL) { mrd = (MaxRectsData *)mallocMagic(sizeof(MaxRectsData)); mrd->rlist = (Rect *)mallocMagic(8 * sizeof(Rect)); mrd->swap = (Rect *)mallocMagic(8 * sizeof(Rect)); mrd->listdepth = 8; } if (starttile == NULL) return mrd; boundrect = &(mrd->rlist[0]); mrd->match = CLIENTDEFAULT; edgelimit = cptr->drcc_dist; arg->dCD_cptr = cptr; TiToRect(starttile, boundrect); /* Determine area to be searched */ switch (dir) { case GEO_NORTH: boundrect->r_ytop = boundrect->r_ybot; boundrect->r_xbot -= (edgelimit - 1); boundrect->r_xtop += (edgelimit - 1); boundrect->r_ytop += edgelimit; break; case GEO_SOUTH: boundrect->r_ybot = boundrect->r_ytop; boundrect->r_xbot -= (edgelimit - 1); boundrect->r_xtop += (edgelimit - 1); boundrect->r_ybot -= edgelimit; break; case GEO_EAST: boundrect->r_xtop = boundrect->r_xbot; boundrect->r_ybot -= (edgelimit - 1); boundrect->r_ytop += (edgelimit - 1); boundrect->r_xtop += edgelimit; break; case GEO_WEST: boundrect->r_xbot = boundrect->r_xtop; boundrect->r_ybot -= (edgelimit - 1); boundrect->r_ytop += (edgelimit - 1); boundrect->r_xbot -= edgelimit; break; case GEO_CENTER: boundrect->r_xbot -= edgelimit; boundrect->r_xtop += edgelimit; boundrect->r_ybot -= edgelimit; boundrect->r_ytop += edgelimit; break; } /* Do an area search on boundrect to find all materials not */ /* in oktypes. Each such tile clips or subdivides */ /* boundrect. Any rectangles remaining after the search */ /* satisfy the maxwidth rule. */ mrd->entries = 1; mrd->maxdist = edgelimit; TTMaskCom2(&wrongtypes, &cptr->drcc_mask); boundorig = *boundrect; DBSrPaintArea(starttile, arg->dCD_celldef->cd_planes[cptr->drcc_edgeplane], &boundorig, &wrongtypes, FindMaxRects, mrd); if (mrd->entries == 0) return NULL; else if (cptr->drcc_plane != cptr->drcc_edgeplane) { /* If the "exclude" option is used, then the maxrect rule will be * ignored for any metal area partially or totally covered by any * type in cptr->drcc_corner on plane cptr->drcc_plane (!= * cptr->drcc_edgeplane). */ for (s = 0; s < mrd->entries; s++) { Rect *r = &(mrd->rlist[s]); if (DBSrPaintArea((Tile *)NULL, arg->dCD_celldef->cd_planes[cptr->drcc_plane], r, &cptr->drcc_corner, MaxRectsExclude, NULL) != 0) { /* Take this area out of consideration */ r->r_xtop = r->r_xbot; r->r_ytop = r->r_ybot; } } return (MaxRectsData *)mrd; } else return (MaxRectsData *)mrd; }