#ifndef lint static char rcsid[] = "$Header: /ufs/repository/magic/drc/DRCextend.c,v 1.2 2001/01/12 22:12:29 jsolomon Exp $"; #endif #include #include #include "misc/magic.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 "signals/signals.h" #include "utils/stack.h" #ifdef DRC_EXTENSIONS Stack *DRCstack = NULL; #define PUSHTILE(tp) \ if ((tp)->ti_client == (ClientData) DRC_UNPROCESSED) { \ (tp)->ti_client = (ClientData) DRC_PENDING; \ STACKPUSH((ClientData) (tp), DRCstack); \ } /* *------------------------------------------------------------------------- * * 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. * *------------------------------------------------------------------------- */ drcCheckArea(starttile,arg,cptr) Tile *starttile; struct drcClientData *arg; DRCCookie *cptr; { int arealimit = cptr->drcc_cdist; int area=0; TileTypeBitMask *oktypes = &cptr->drcc_mask; Tile *tile,*tp; Rect *cliprect = arg->dCD_rect; static Stack *DRCstack= NULL; 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 (tile->ti_client != (ClientData)DRC_PENDING) continue; area += (RIGHT(tile)-LEFT(tile))*(TOP(tile)-BOTTOM(tile)); tile->ti_client = (ClientData)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 >= arealimit) goto forgetit; /* Top */ for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp)) if (TTMaskHasType(oktypes, TiGetType(tp))) PUSHTILE(tp); /* Left */ for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp)) if (TTMaskHasType(oktypes, TiGetType(tp))) PUSHTILE(tp); /* Bottom */ for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp)) if (TTMaskHasType(oktypes, TiGetType(tp))) PUSHTILE(tp); /* Right */ for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp)) if (TTMaskHasType(oktypes, TiGetType(tp))) PUSHTILE(tp); } if (area dCD_clip); if (!GEO_RECTNULL(&rect)) { (*(arg->dCD_function)) (arg->dCD_celldef, &rect, arg->dCD_cptr, arg->dCD_clientData); /*** DBWAreaChanged(arg->dCD_celldef,&rect, DBW_ALLWINDOWS, &DBAllButSpaceBits); ***/ (*(arg->dCD_errors))++; } } forgetit: /* reset the tiles */ starttile->ti_client = (ClientData)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 (tp->ti_client != (ClientData)DRC_UNPROCESSED) { tp->ti_client = (ClientData)DRC_UNPROCESSED; STACKPUSH(tp,DRCstack); } /* Left */ for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp)) if (tp->ti_client != (ClientData)DRC_UNPROCESSED) { tp->ti_client = (ClientData)DRC_UNPROCESSED; STACKPUSH(tp,DRCstack); } /* Bottom */ for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp)) if (tp->ti_client != (ClientData)DRC_UNPROCESSED) { tp->ti_client = (ClientData)DRC_UNPROCESSED; STACKPUSH(tp,DRCstack); } /* Right */ for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp)) if (tp->ti_client != (ClientData)DRC_UNPROCESSED) { tp->ti_client = (ClientData)DRC_UNPROCESSED; STACKPUSH(tp,DRCstack); } } return 0; } /* *------------------------------------------------------------------------- * * drcCheckMaxwidth - checks to see that at least one dimension of a region * does not exceed some amount. * * 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: none * * Side Effects: may cause errors to be painted. * *------------------------------------------------------------------------- */ drcCheckMaxwidth(starttile,arg,cptr) Tile *starttile; struct drcClientData *arg; DRCCookie *cptr; { int edgelimit = cptr->drcc_dist; Rect boundrect; TileTypeBitMask *oktypes = &cptr->drcc_mask; Tile *tile,*tp; arg->dCD_cptr = cptr; if (DRCstack == (Stack *) NULL) DRCstack = StackNew(64); /* if bends are allowed, just check on a tile-by-tile basis that one dimension is the max. This is pretty stupid, but it correctly calculates the trench width rule. dcs 12.06.89 */ if (cptr->drcc_flags & DRC_BENDS) { Rect rect; TiToRect(starttile,&rect); if (rect.r_xtop-rect.r_xbot > edgelimit && rect.r_ytop-rect.r_ybot > edgelimit) { GeoClip(&rect, arg->dCD_clip); if (!GEO_RECTNULL(&rect)) { (*(arg->dCD_function)) (arg->dCD_celldef, &rect, arg->dCD_cptr, arg->dCD_clientData); /*** DBWAreaChanged(arg->dCD_celldef,&rect, DBW_ALLWINDOWS, &DBAllButSpaceBits); ***/ (*(arg->dCD_errors))++; } } return 0; } /* Mark this tile as pending and push it */ PUSHTILE(starttile); TiToRect(starttile,&boundrect); while (!StackEmpty(DRCstack)) { tile = (Tile *) STACKPOP(DRCstack); if (tile->ti_client != (ClientData)DRC_PENDING) continue; 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); tile->ti_client = (ClientData)DRC_PROCESSED; if (boundrect.r_xtop - boundrect.r_xbot > edgelimit && boundrect.r_ytop - boundrect.r_ybot > edgelimit) break; /* Top */ for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp)) if (TTMaskHasType(oktypes, TiGetType(tp))) PUSHTILE(tp); /* Left */ for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp)) if (TTMaskHasType(oktypes, TiGetType(tp))) PUSHTILE(tp); /* Bottom */ for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp)) if (TTMaskHasType(oktypes, TiGetType(tp))) PUSHTILE(tp); /* Right */ for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp)) if (TTMaskHasType(oktypes, TiGetType(tp))) PUSHTILE(tp); } if (boundrect.r_xtop - boundrect.r_xbot > edgelimit && boundrect.r_ytop - boundrect.r_ybot > 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); /*** DBWAreaChanged(arg->dCD_celldef,&rect, DBW_ALLWINDOWS, &DBAllButSpaceBits); ***/ (*(arg->dCD_errors))++; } } /* reset the tiles */ starttile->ti_client = (ClientData)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 (tp->ti_client != (ClientData)DRC_UNPROCESSED) { tp->ti_client = (ClientData)DRC_UNPROCESSED; STACKPUSH(tp,DRCstack); } /* Left */ for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp)) if (tp->ti_client != (ClientData)DRC_UNPROCESSED) { tp->ti_client = (ClientData)DRC_UNPROCESSED; STACKPUSH(tp,DRCstack); } /* Bottom */ for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp)) if (tp->ti_client != (ClientData)DRC_UNPROCESSED) { tp->ti_client = (ClientData)DRC_UNPROCESSED; STACKPUSH(tp,DRCstack); } /* Right */ for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp)) if (tp->ti_client != (ClientData)DRC_UNPROCESSED) { tp->ti_client = (ClientData)DRC_UNPROCESSED; STACKPUSH(tp,DRCstack); } } return 0; } /* *------------------------------------------------------------------------- * * 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. * *------------------------------------------------------------------------- */ drcCheckRectSize(starttile, arg, cptr) Tile *starttile; struct drcClientData *arg; DRCCookie *cptr; { int maxsize = cptr->drcc_dist; int even = cptr->drcc_cdist; TileTypeBitMask *oktypes = &cptr->drcc_mask; int width; int height; int errwidth; int errheight; Tile *t; bool error = FALSE; /* 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))++; } } return 0; } #endif