/* * DRCcif.c -- * ****************************************************************************** * Copyright (C) 1989 Digital Equipment Corporation * Permission to use, copy, modify, and distribute this * software and its documentation for any purpose and without * fee is hereby granted, provided that the above copyright * notice appear in all copies. Digital Equipment Corporation * makes no representations about the suitability of this * software for any purpose. It is provided "as is" without * express or implied warranty. * * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. **************************************************************************** * */ #ifndef lint static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/drc/DRCcif.c,v 1.5 2010/10/20 20:34:20 tim Exp $"; #endif /* not lint */ #include #include #include #include #include "utils/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 "cif/cif.h" #include "cif/CIFint.h" #include "utils/signals.h" #include "utils/stack.h" #include "utils/malloc.h" /* C99 compat */ #include "utils/tech.h" #include "textio/textio.h" extern int drcCifTile(); extern int areaCifCheck(); extern void drcCheckCifMaxwidth(); extern void drcCheckCifArea(); extern Stack *DRCstack; #define PUSHTILE(tp) \ if ((tp)->ti_client == (ClientData) DRC_UNPROCESSED) { \ (tp)->ti_client = (ClientData) DRC_PENDING; \ STACKPUSH((ClientData) (tp), DRCstack); \ } extern CIFStyle *drcCifStyle; extern bool DRCForceReload; TileTypeBitMask drcCifGenLayers; DRCCookie *drcCifRules[MAXCIFLAYERS][2]; DRCCookie *drcCifCur = NULL; int drcCifValid = FALSE; bool beenWarned = FALSE; char *drcNeedStyle = NULL; #define DRC_CIF_SPACE 0 #define DRC_CIF_SOLID 1 /* Define Euclidean distance checks */ #define RADIAL_NW 0x1000 #define RADIAL_NE 0x8000 #define RADIAL_SW 0x2000 #define RADIAL_SE 0x4000 /* * ---------------------------------------------------------------------------- * * drcCifSetStyle -- * * Process a declaration of the cif style. * This is of the form: * * cifstyle cif_style * * e.g, * * cifstyle pg * * Results: * Returns 0. * * Side effects: * Updates drcCifStyle. Do NOT attempt to update the CIF style * in the middle of reading the DRC section. Instead, if the * reported CIF style is not current, flag a warning. The DRC * will be re-read with the CIF extensions when the CIF output * style is changed. * * ---------------------------------------------------------------------------- */ int drcCifSetStyle(argc, argv) int argc; char *argv[]; { CIFKeep *new; for (new = CIFStyleList; new != NULL; new = new->cs_next) { if (!strcmp(new->cs_name, argv[1])) { drcNeedStyle = new->cs_name; DRCForceReload = TRUE; if (!strcmp(new->cs_name, CIFCurStyle->cs_name)) drcCifStyle = CIFCurStyle; else { drcCifStyle = NULL; beenWarned = TRUE; /* post no more error messages */ } return 0; } } TechError("Unknown DRC cifstyle %s\n",argv[1]); return (0); } /* * ---------------------------------------------------------------------------- * ---------------------------------------------------------------------------- */ int drcCifWarning() { if (!beenWarned) { TechError("Missing cif style for drc\n\t" "This message will not be repeated.\n"); beenWarned = TRUE; } return 0; } /* * ---------------------------------------------------------------------------- * * drcCifWidth -- same this as drcCifWidth, except that it works on * cif layers * * Results: * Returns distance. * * Side effects: * Updates the DRC technology variables. * * Notes: "centidistance" is by default in centimicrons, but it is really in * whatever units are declared in the cifoutput section; so if cifoutput * declares nanometers, then units are in nanometers. This may be in * different units from the non-CIF part of the DRC section. The escape * sequence substitution in the "Why" text will make sure that the correct * physical dimensions are presented to the end user. * * ---------------------------------------------------------------------------- */ int drcCifWidth(argc, argv) int argc; char *argv[]; { char *layername = argv[1]; int scalefactor; int centidistance = atoi(argv[2]); int why = drcWhyCreate(argv[3]); TileTypeBitMask set, setC, tmp1; int thislayer = -1; DRCCookie *dpnew,*dpnext; TileType i; if (drcCifStyle == NULL) return drcCifWarning(); for (i = 0; i < drcCifStyle->cs_nLayers;i++) { CIFLayer *layer = drcCifStyle->cs_layers[i]; if (strcmp(layer->cl_name,layername) == 0) { thislayer = i; break; } } if (thislayer == -1) { TechError("Unknown cif layer: %s\n",layername); return (0); } scalefactor = drcCifStyle->cs_scaleFactor; // centidistance *= drcCifStyle->cs_expander; // BSI dpnext = drcCifRules[thislayer][DRC_CIF_SPACE]; dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie))); drcCifAssign(dpnew, centidistance, dpnext, &CIFSolidBits, &CIFSolidBits, why, centidistance, DRC_FORWARD | DRC_CIFRULE, thislayer, 0); drcCifRules[thislayer][DRC_CIF_SPACE] = dpnew; return ((centidistance+scalefactor-1)/scalefactor); } /* * ---------------------------------------------------------------------------- * * drcCifSpacing -- same this as drcSpacing, except that it works on cif * layers. * * Results: * Returns distance. * * Side effects: * Updates the DRC technology variables. * * ---------------------------------------------------------------------------- */ int drcCifSpacing(argc, argv) int argc; char *argv[]; { char *adjacency = argv[4]; int why = drcWhyCreate(argv[5]); DRCCookie *dpnext, *dpnew; int needReverse = FALSE; TileType i, j; int scalefactor; int centidistance = atoi(argv[3]); char *layers[2]; TileType layer[2]; TileTypeBitMask cmask; int k; layers[0] = argv[1]; layers[1] = argv[2]; if (drcCifStyle == NULL) return drcCifWarning(); for (k=0; k!= 2;k++) { for (i = 0; i < drcCifStyle->cs_nLayers;i++) { CIFLayer *l = drcCifStyle->cs_layers[i]; if (strcmp(l->cl_name,layers[k]) == 0) { layer[k]=i; break; } } if (i == drcCifStyle->cs_nLayers || layer[k] == -1) { TechError("Unknown cif layer: %s",layers[k]); return (0); } } if (strcmp (adjacency, "touching_ok") == 0) { /* If touching is OK, everything must fall in the same plane. */ if (layer[0] != layer[1]) { TechError( "Spacing check with touching ok must all be in one plane.\n"); return (0); } cmask = DBSpaceBits; } else if (strcmp (adjacency, "touching_illegal") == 0) { cmask = DBAllTypeBits; needReverse = TRUE; /* nothing for now */ } else { TechError("Badly formed drc spacing line\n"); return (0); } scalefactor = drcCifStyle->cs_scaleFactor; // centidistance *= drcCifStyle->cs_expander; // BSI dpnext = drcCifRules[layer[0]][DRC_CIF_SOLID]; dpnew = (DRCCookie *) mallocMagic((unsigned) sizeof (DRCCookie)); drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits, &cmask, why, centidistance, DRC_FORWARD | DRC_CIFRULE, layer[1], 0); drcCifRules[layer[0]][DRC_CIF_SOLID] = dpnew; if (needReverse) dpnew->drcc_flags |= DRC_BOTHCORNERS; // Add rule in reverse direction dpnext = drcCifRules[layer[0]][DRC_CIF_SPACE]; dpnew = (DRCCookie *) mallocMagic((unsigned) sizeof (DRCCookie)); drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits, &cmask, why, centidistance, DRC_REVERSE | DRC_CIFRULE, layer[1], 0); drcCifRules[layer[0]][DRC_CIF_SPACE] = dpnew; if (needReverse) { // This is not so much "reverse" as it is just the // rule for b->a spacing that matches the a->b spacing. dpnew->drcc_flags |= DRC_BOTHCORNERS; dpnext = drcCifRules[layer[1]][DRC_CIF_SOLID]; dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie))); drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits, &cmask, why, centidistance, DRC_FORWARD|DRC_BOTHCORNERS | DRC_CIFRULE, layer[0], 0); drcCifRules[layer[1]][DRC_CIF_SOLID] = dpnew; // Add rule in reverse direction dpnext = drcCifRules[layer[1]][DRC_CIF_SPACE]; dpnew = (DRCCookie *) mallocMagic((unsigned) sizeof (DRCCookie)); drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits, &cmask, why, centidistance, DRC_REVERSE|DRC_BOTHCORNERS | DRC_CIFRULE, layer[0], 0); drcCifRules[layer[1]][DRC_CIF_SPACE] = dpnew; if (layer[0] == layer[1]) { dpnext = drcCifRules[layer[1]][DRC_CIF_SPACE]; dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie))); drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits, &cmask, why, centidistance, DRC_REVERSE | DRC_BOTHCORNERS | DRC_CIFRULE, layer[0], 0); drcCifRules[layer[1]][DRC_CIF_SPACE] = dpnew; dpnext = drcCifRules[layer[0]][DRC_CIF_SPACE]; dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie))); drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits, &cmask, why, centidistance, DRC_REVERSE | DRC_BOTHCORNERS | DRC_CIFRULE, layer[1], 0); drcCifRules[layer[0]][DRC_CIF_SPACE] = dpnew; } } if (layer[0] != layer[1]) /* make sure they don't overlap exactly */ { dpnext = drcCifRules[layer[1]][DRC_CIF_SPACE]; dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie))); drcCifAssign(dpnew, scalefactor, dpnext, &DBSpaceBits, &DBZeroTypeBits, why, scalefactor, DRC_FORWARD | DRC_CIFRULE, layer[0], 0); drcCifRules[layer[1]][DRC_CIF_SPACE] = dpnew; dpnext = drcCifRules[layer[0]][DRC_CIF_SPACE]; dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie))); drcCifAssign(dpnew, scalefactor, dpnext, &DBSpaceBits, &DBZeroTypeBits, why, scalefactor, DRC_FORWARD | DRC_CIFRULE, layer[1], 0); drcCifRules[layer[0]][DRC_CIF_SPACE] = dpnew; } return ((centidistance+scalefactor-1)/scalefactor); } /* * ---------------------------------------------------------------------------- * Scale CIF/DRC rules to match grid scaling. Scale by factor (n / d) * ---------------------------------------------------------------------------- */ void drcCifScale(int n, int d) { DRCCookie *dp; int i, j; if (DRCCurStyle != NULL) { for (i = 0; i != MAXCIFLAYERS; i++) for (j = 0; j < 2; j++) for (dp = drcCifRules[i][j]; dp != NULL; dp = dp->drcc_next) { if (dp->drcc_dist != 0) { dp->drcc_dist *= n; dp->drcc_dist /= d; } if (dp->drcc_cdist != 0) { dp->drcc_cdist *= n; dp->drcc_cdist /= d; } } } } /* * ---------------------------------------------------------------------------- * ---------------------------------------------------------------------------- */ void drcCifFreeStyle() { DRCCookie *dp; int i; char *old; if (DRCCurStyle != NULL) { for (i = 0; i != MAXCIFLAYERS; i++) { dp = drcCifRules[i][DRC_CIF_SPACE]; while (dp != NULL) { old = (char *)dp; dp = dp->drcc_next; freeMagic(old); } dp = drcCifRules[i][DRC_CIF_SOLID]; while (dp != NULL) { old = (char *)dp; dp = dp->drcc_next; freeMagic(old); } } } } /* * ---------------------------------------------------------------------------- * ---------------------------------------------------------------------------- */ void drcCifInit() { int i; if (drcCifValid == TRUE) drcCifFreeStyle(); for (i = 0; i != MAXCIFLAYERS; i++) { drcCifRules[i][DRC_CIF_SPACE] = NULL; drcCifRules[i][DRC_CIF_SOLID] = NULL; } drcCifValid = FALSE; TTMaskZero(&drcCifGenLayers); beenWarned = FALSE; } /* * ---------------------------------------------------------------------------- * ---------------------------------------------------------------------------- */ void drcCifFinal() { int i; for (i = 0; i != MAXCIFLAYERS; i++) { DRCCookie *dp; for (dp = drcCifRules[i][DRC_CIF_SPACE]; dp; dp = dp->drcc_next) { drcCifValid = TRUE; TTMaskSetType(&drcCifGenLayers, i); TTMaskSetType(&drcCifGenLayers, dp->drcc_plane); } for (dp = drcCifRules[i][DRC_CIF_SOLID]; dp; dp = dp->drcc_next) { drcCifValid = TRUE; TTMaskSetType(&drcCifGenLayers, i); TTMaskSetType(&drcCifGenLayers, dp->drcc_plane); } } } /* * ---------------------------------------------------------------------------- * drcCifCheck--- * * This is the primary routine for design-rule checking on CIF layers. * * Results: * None. * * Side effects: * Error paint, CIF layer generation, lots of stuff going on. * * ---------------------------------------------------------------------------- */ void drcCifCheck(arg) struct drcClientData *arg; { Rect *checkRect = arg->dCD_rect; Rect cifrect; int scale; int i,j; int oldTiles; CIFStyle *CIFSaveStyle = NULL; if (CIFCurStyle != drcCifStyle) { if (drcNeedStyle == NULL) return; CIFSaveStyle = CIFCurStyle; if (drcCifStyle == NULL) { TxPrintf("Loading DRC CIF style.\n"); CIFCurStyle = NULL; CIFLoadStyle(drcNeedStyle); if (drcCifValid != FALSE) CIFCurStyle = CIFSaveStyle; else drcCifStyle = CIFCurStyle; } if (drcCifStyle == NULL) { TxError("Error: Failed to load CIF DRC style.\n"); return; } CIFCurStyle = drcCifStyle; } if (drcCifValid == FALSE) { if (CIFSaveStyle != NULL) CIFCurStyle = CIFSaveStyle; return; } scale = drcCifStyle->cs_scaleFactor; cifrect = *checkRect; cifrect.r_xbot *= scale; cifrect.r_xtop *= scale; cifrect.r_ybot *= scale; cifrect.r_ytop *= scale; arg->dCD_rect = &cifrect; oldTiles = DRCstatTiles; CIFGen(arg->dCD_celldef, arg->dCD_celldef, checkRect, CIFPlanes, &DBAllTypeBits, TRUE, TRUE, FALSE, (ClientData)NULL); for (i = 0; i < drcCifStyle->cs_nLayers; i++) { for (j = 0; j != 2; j++) { for (drcCifCur = drcCifRules[i][j]; drcCifCur; drcCifCur = drcCifCur->drcc_next) { TileTypeBitMask *mask; arg->dCD_plane = i; DBSrPaintArea((Tile *) NULL, CIFPlanes[i], &cifrect, (j == DRC_CIF_SOLID) ? &DBSpaceBits : &CIFSolidBits, drcCifTile, arg); } } } arg->dCD_rect = checkRect; DRCstatCifTiles += DRCstatTiles - oldTiles; /* Put it back the way you found it */ if (CIFSaveStyle != NULL) CIFCurStyle = CIFSaveStyle; } /* * ---------------------------------------------------------------------------- * * drcCifTile -- * * Results: * Zero (so that the search will continue), unless an interrupt * occurs, in which case 1 is returned to stop the check. * * Side effects: * Calls the client's error function if errors are found. * * ---------------------------------------------------------------------------- */ int drcCifTile (tile, arg) Tile *tile; /* Tile being examined */ struct drcClientData *arg; { DRCCookie *cptr; /* Current design rule on list */ Tile *tp; /* Used for corner checks */ Rect *rect = arg->dCD_rect; /* Area being checked */ Rect errRect; /* Area checked for an individual rule */ TileTypeBitMask tmpMask; arg->dCD_constraint = &errRect; arg->dCD_radial = 0; /* * If we were interrupted, we want to * abort the check as quickly as possible. */ if (SigInterruptPending) return 1; DRCstatTiles++; /* For non-Manhattan tiles, if the left side of tile is not the */ /* type that is declared by the rule, then skip the left-right */ /* check. */ if (IsSplit(tile)) if (SplitSide(tile)) goto tbcheck; /* * Check design rules along a vertical boundary between two tiles. * * 1 | 4 * T * | * tpleft | tile * | * B * 2 | 3 * * The labels "T" and "B" indicate pointT and pointB respectively. * * If a rule's direction is FORWARD, then check from left to right. * * * Check the top right corner if the 1x1 lambda square * on the top left corner (1) of pointT matches the design * rule's "corner" mask. * * * Check the bottom right corner if the rule says check * BOTHCORNERS and the 1x1 lambda square on the bottom left * corner (2) of pointB matches the design rule's "corner" mask. * * If a rule's direction is REVERSE, then check from right to left. * * * Check the bottom left corner if the 1x1 lambda square * on the bottom right corner (3) of pointB matches the design * rule's "corner" mask. * * * Check the top left corner if the rule says check BOTHCORNERS * and the 1x1 lambda square on the top right corner (4) of * pointT matches the design rule's "corner" mask. */ if (drcCifCur->drcc_flags & DRC_AREA) { drcCheckCifArea(tile, arg, drcCifCur); return 0; } if (drcCifCur->drcc_flags & DRC_MAXWIDTH) { drcCheckCifMaxwidth(tile, arg, drcCifCur); return 0; } if (LEFT(tile) >= rect->r_xbot) /* check tile against rect */ { Tile *tpleft; int edgeTop, edgeBot; int top = MIN(TOP(tile), rect->r_ytop); int bottom = MAX(BOTTOM(tile), rect->r_ybot); int edgeX = LEFT(tile); for (tpleft = BL(tile); BOTTOM(tpleft) < top; tpleft = RT(tpleft)) { /* Don't check synthetic edges, i.e. edges with same type on * both sides. Such "edges" have no physical significance, and * depend on internal-details of how paint is spit into tiles. * Thus checking them just leads to confusion. (When edge rules * involving such edges are encountered during technology readin * the user is warned that such edges are not checked). */ if (TiGetRightType(tpleft) == TiGetLeftType(tile)) continue; /* * Go through list of design rules triggered by the * left-to-right edge. */ edgeTop = MIN(TOP (tpleft), top); edgeBot = MAX(BOTTOM(tpleft), bottom); if (edgeTop <= edgeBot) continue; /* do this more intelligently later XXX */ cptr = drcCifCur; { errRect.r_ytop = edgeTop; errRect.r_ybot = edgeBot; if (cptr->drcc_flags & DRC_REVERSE) { /* * Determine corner extensions. * Find the point (3) to the bottom right of pointB */ for (tp = tile; BOTTOM(tp) >= errRect.r_ybot; tp = LB(tp)) /* Nothing */; if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tp))) { errRect.r_ybot -= cptr->drcc_cdist; if (DRCEuclidean) arg->dCD_radial |= RADIAL_SW; } if (cptr->drcc_flags & DRC_BOTHCORNERS) { /* * Check the other corner by finding the * point (4) to the top right of pointT. */ if (TOP(tp = tile) <= errRect.r_ytop) for (tp = RT(tp); LEFT(tp) > edgeX; tp = BL(tp)) /* Nothing */; if (TTMaskHasType(&cptr->drcc_corner, TiGetBottomType(tp))) { errRect.r_ytop += cptr->drcc_cdist; if (DRCEuclidean) arg->dCD_radial |= RADIAL_NW; } } /* * Just for grins, see if we could avoid a messy search * by looking only at tpleft. */ errRect.r_xbot = edgeX - cptr->drcc_dist; if (LEFT(tpleft) <= errRect.r_xbot && BOTTOM(tpleft) <= errRect.r_ybot && TOP(tpleft) >= errRect.r_ytop && arg->dCD_plane == cptr->drcc_plane && TTMaskHasType(&cptr->drcc_mask, TiGetType(tpleft))) continue; errRect.r_xtop = edgeX; arg->dCD_initial = tile; } else /* FORWARD */ { /* * Determine corner extensions. * Find the point (1) to the top left of pointT */ for (tp = tpleft; TOP(tp) <= errRect.r_ytop; tp = RT(tp)) /* Nothing */; if (TTMaskHasType(&cptr->drcc_corner, TiGetBottomType(tp))) { errRect.r_ytop += cptr->drcc_cdist; if (DRCEuclidean) arg->dCD_radial |= RADIAL_NE; } if (cptr->drcc_flags & DRC_BOTHCORNERS) { /* * Check the other corner by finding the * point (2) to the bottom left of pointB. */ if (BOTTOM(tp = tpleft) >= errRect.r_ybot) for (tp = LB(tp); RIGHT(tp) < edgeX; tp = TR(tp)) /* Nothing */; if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tp))) { errRect.r_ybot -= cptr->drcc_cdist; if (DRCEuclidean) arg->dCD_radial |= RADIAL_SE; } } /* * Just for grins, see if we could avoid a messy search * by looking only at tile. */ errRect.r_xtop = edgeX + cptr->drcc_dist; if (RIGHT(tile) >= errRect.r_xtop && BOTTOM(tile) <= errRect.r_ybot && TOP(tile) >= errRect.r_ytop && arg->dCD_plane == cptr->drcc_plane && TTMaskHasType(&cptr->drcc_mask, TiGetLeftType(tile))) continue; errRect.r_xbot = edgeX; arg->dCD_initial= tpleft; } if (arg->dCD_radial) { arg->dCD_radial &= 0xf000; arg->dCD_radial |= (0xfff & cptr->drcc_cdist); } DRCstatSlow++; arg->dCD_cptr = (DRCCookie *)cptr; TTMaskCom2(&tmpMask, &cptr->drcc_mask); (void) DBSrPaintArea((Tile *) NULL, CIFPlanes[cptr->drcc_plane], &errRect, &tmpMask, areaCifCheck, (ClientData) arg); } DRCstatEdges++; } } tbcheck: /* For non-Manhattan tiles, if the bottom side of tile is not */ /* the type that is declared by the rule, then skip the top- */ /* bottom check. */ if (IsSplit(tile)) if (SplitSide(tile) == SplitDirection(tile)) return 0; /* * Check design rules along a horizontal boundary between two tiles. * * 4 tile 3 * --L----------------R-- * 1 tpbot 2 * * The labels "L" and "R" indicate pointL and pointR respectively. * If a rule's direction is FORWARD, then check from bottom to top. * * * Check the top left corner if the 1x1 lambda square on the bottom * left corner (1) of pointL matches the design rule's "corner" mask. * * * Check the top right corner if the rule says check BOTHCORNERS and * the 1x1 lambda square on the bottom right (2) corner of pointR * matches the design rule's "corner" mask. * * If a rule's direction is REVERSE, then check from top to bottom. * * * Check the bottom right corner if the 1x1 lambda square on the top * right corner (3) of pointR matches the design rule's "corner" * mask. * * * Check the bottom left corner if the rule says check BOTHCORNERS * and the 1x1 lambda square on the top left corner (4) of pointL * matches the design rule's "corner" mask. */ if (BOTTOM(tile) >= rect->r_ybot) { Tile *tpbot; int edgeLeft, edgeRight; int left = MAX(LEFT(tile), rect->r_xbot); int right = MIN(RIGHT(tile), rect->r_xtop); int edgeY = BOTTOM(tile); /* Go right across bottom of tile */ for (tpbot = LB(tile); LEFT(tpbot) < right; tpbot = TR(tpbot)) { /* Don't check synthetic edges, i.e. edges with same type on * both sides. Such "edges" have no physical significance, and * depend on internal-details of how paint is spit into tiles. * Thus checking them just leads to confusion. (When edge rules * involving such edges are encountered during technology readin * the user is warned that such edges are not checked). */ if(TiGetTopType(tpbot) == TiGetBottomType(tile)) continue; /* * Check to insure that we are inside the clip area. * Go through list of design rules triggered by the * bottom-to-top edge. */ edgeLeft = MAX(LEFT(tpbot), left); edgeRight = MIN(RIGHT(tpbot), right); if (edgeLeft >= edgeRight) continue; cptr = drcCifCur; { DRCstatRules++; errRect.r_xbot = edgeLeft; errRect.r_xtop = edgeRight; /* top to bottom */ if (cptr->drcc_flags & DRC_REVERSE) { /* * Determine corner extensions. * Find the point (3) to the top right of pointR */ if (RIGHT(tp = tile) <= errRect.r_xtop) for (tp = TR(tp); BOTTOM(tp) > edgeY; tp = LB(tp)) /* Nothing */; if (TTMaskHasType(&cptr->drcc_corner, TiGetLeftType(tp))) { errRect.r_xtop += cptr->drcc_cdist; if (DRCEuclidean) arg->dCD_radial |= RADIAL_SE; } if (cptr->drcc_flags & DRC_BOTHCORNERS) { /* * Check the other corner by finding the * point (4) to the top left of pointL. */ for (tp = tile; LEFT(tp) >= errRect.r_xbot; tp = BL(tp)) /* Nothing */; if (TTMaskHasType(&cptr->drcc_corner, TiGetRightType(tp))) { errRect.r_xbot -= cptr->drcc_cdist; if (DRCEuclidean) arg->dCD_radial |= RADIAL_SW; } } /* * Just for grins, see if we could avoid * a messy search by looking only at tpbot. */ errRect.r_ybot = edgeY - cptr->drcc_dist; if (BOTTOM(tpbot) <= errRect.r_ybot && LEFT(tpbot) <= errRect.r_xbot && RIGHT(tpbot) >= errRect.r_xtop && arg->dCD_plane == cptr->drcc_plane && TTMaskHasType(&cptr->drcc_mask, TiGetTopType(tpbot))) continue; errRect.r_ytop = edgeY; arg->dCD_initial = tile; } else /* FORWARD */ { /* * Determine corner extensions. * Find the point (1) to the bottom left of pointL */ if (LEFT(tp = tpbot) >= errRect.r_xbot) for (tp = BL(tp); TOP(tp) < edgeY; tp = RT(tp)) /* Nothing */; if (TTMaskHasType(&cptr->drcc_corner, TiGetRightType(tp))) { errRect.r_xbot -= cptr->drcc_cdist; if (DRCEuclidean) arg->dCD_radial |= RADIAL_NW; } if (cptr->drcc_flags & DRC_BOTHCORNERS) { /* * Check the other corner by finding the * point (2) to the bottom right of pointR. */ for (tp=tpbot; RIGHT(tp) <= errRect.r_xtop; tp=TR(tp)) /* Nothing */; if (TTMaskHasType(&cptr->drcc_corner, TiGetLeftType(tp))) { errRect.r_xtop += cptr->drcc_cdist; if (DRCEuclidean) arg->dCD_radial |= RADIAL_NE; } } /* * Just for grins, see if we could avoid * a messy search by looking only at tile. */ errRect.r_ytop = edgeY + cptr->drcc_dist; if (TOP(tile) >= errRect.r_ytop && LEFT(tile) <= errRect.r_xbot && RIGHT(tile) >= errRect.r_xtop && arg->dCD_plane == cptr->drcc_plane && TTMaskHasType(&cptr->drcc_mask, TiGetType(tile))) continue; errRect.r_ybot = edgeY; arg->dCD_initial = tpbot; } if (arg->dCD_radial) { arg->dCD_radial &= 0xf000; arg->dCD_radial |= (0xfff & cptr->drcc_cdist); } DRCstatSlow++; arg->dCD_cptr = (DRCCookie *)cptr; TTMaskCom2(&tmpMask, &cptr->drcc_mask); (void) DBSrPaintArea((Tile *) NULL, CIFPlanes[cptr->drcc_plane], &errRect, &tmpMask, areaCifCheck, (ClientData) arg); } DRCstatEdges++; } } return (0); } /* * ---------------------------------------------------------------------------- * * areaCifCheck -- * * Call the function passed down from DRCBasicCheck() if the current tile * violates the rule in the given DRCCookie. If the rule's connectivity * flag is set, then make sure the violating material isn't connected * to what's on the initial side of the edge before calling the client * error function. * * This function is called from DBSrPaintArea(). * * Results: * Zero (so that the search will continue). * * Side effects: * Applies the function passed as an argument. * * ---------------------------------------------------------------------------- */ int areaCifCheck(tile, arg) Tile *tile; struct drcClientData *arg; { Rect rect; /* Area where error is to be recorded. */ Rect cifrect; /* rect, in CIF coordinates */ int scale = drcCifStyle->cs_scaleFactor; /* If the tile has a legal type, then return. */ if (TTMaskHasType(&arg->dCD_cptr->drcc_mask, TiGetType(tile))) return 0; /* Only consider the portion of the suspicious tile that overlaps * the clip area for errors. */ TiToRect(tile, &cifrect); GeoClip(&cifrect, arg->dCD_constraint); if ((cifrect.r_xbot >= cifrect.r_xtop) || (cifrect.r_ybot >= cifrect.r_ytop)) return 0; rect = cifrect; rect.r_xbot /= scale; rect.r_xtop /= scale; if (rect.r_xbot == rect.r_xtop) { if (rect.r_xbot < 0) rect.r_xbot--; else rect.r_xtop++; } rect.r_ybot /= scale; rect.r_ytop /= scale; if (rect.r_ybot == rect.r_ytop) { if (rect.r_ybot < 0) rect.r_ybot--; else rect.r_ytop++; } GeoClip(&rect, arg->dCD_clip); if ((rect.r_xbot >= rect.r_xtop) || (rect.r_ybot >= rect.r_ytop)) return 0; /* * Euclidean distance checks */ if (arg->dCD_radial != 0) { unsigned int i; int sqx, sqy; int sdist = arg->dCD_radial & 0xfff; long sstest, ssdist = (long) sdist * sdist; if ((arg->dCD_radial & RADIAL_NW) != 0) { if (((sqx = arg->dCD_constraint->r_xbot + sdist - cifrect.r_xtop) >= 0) && ((sqy = cifrect.r_ybot - arg->dCD_constraint->r_ytop + sdist) >= 0) && ((sqx * sqx + sqy * sqy) >= ssdist)) return 0; else if (IsSplit(tile) && !SplitDirection(tile) && !SplitSide(tile)) { sstest = drcCifPointToSegment(arg->dCD_constraint->r_xbot + sdist, arg->dCD_constraint->r_ytop - sdist, LEFT(tile), BOTTOM(tile), RIGHT(tile), TOP(tile)); if (sstest > ssdist) return 0; } } if ((arg->dCD_radial & RADIAL_NE) != 0) { if (((sqx = cifrect.r_xbot - arg->dCD_constraint->r_xtop + sdist) >= 0) && ((sqy = cifrect.r_ybot - arg->dCD_constraint->r_ytop + sdist) >= 0) && ((sqx * sqx + sqy * sqy) >= ssdist)) return 0; else if (IsSplit(tile) && SplitDirection(tile) && SplitSide(tile)) { sstest = drcCifPointToSegment(arg->dCD_constraint->r_xtop - sdist, arg->dCD_constraint->r_ytop - sdist, LEFT(tile), TOP(tile), RIGHT(tile), BOTTOM(tile)); if (sstest > ssdist) return 0; } } if ((arg->dCD_radial & RADIAL_SW) != 0) { if (((sqx = arg->dCD_constraint->r_xbot + sdist - cifrect.r_xtop) >= 0) && ((sqy = arg->dCD_constraint->r_ybot + sdist - cifrect.r_ytop) >= 0) && ((sqx * sqx + sqy * sqy) >= ssdist)) return 0; else if (IsSplit(tile) && SplitDirection(tile) && !SplitSide(tile)) { sstest = drcCifPointToSegment(arg->dCD_constraint->r_xbot + sdist, arg->dCD_constraint->r_ybot + sdist, LEFT(tile), TOP(tile), RIGHT(tile), BOTTOM(tile)); if (sstest > ssdist) return 0; } } if ((arg->dCD_radial & RADIAL_SE) != 0) { if (((sqx = cifrect.r_xbot - arg->dCD_constraint->r_xtop + sdist) >= 0) && ((sqy = arg->dCD_constraint->r_ybot + sdist - cifrect.r_ytop) >= 0) && ((sqx * sqx + sqy * sqy) >= ssdist)) return 0; else if (IsSplit(tile) && !SplitDirection(tile) && SplitSide(tile)) { sstest = drcCifPointToSegment(arg->dCD_constraint->r_xtop - sdist, arg->dCD_constraint->r_ybot + sdist, LEFT(tile), BOTTOM(tile), RIGHT(tile), TOP(tile)); if (sstest > ssdist) return 0; } } } (*(arg->dCD_function)) (arg->dCD_celldef, &rect, arg->dCD_cptr, arg->dCD_clientData); (*(arg->dCD_errors))++; return (0); } /* * ---------------------------------------------------------------------------- * * drcCifArea -- * * Process an area rule. * This is of the form: * * cifarea layers distance why * * e.g, * * cifarea VIA 4 "via area must be at least 4" * * Results: * Returns distance. * * Side effects: * Updates the DRC technology variables. * * ---------------------------------------------------------------------------- */ int drcCifArea(argc, argv) int argc; char *argv[]; { char *layers = argv[1]; int centiarea = atoi(argv[2]); int centihorizon = atoi(argv[3]); int why = drcWhyCreate(argv[4]); TileTypeBitMask set, setC, tmp1; DRCCookie *dpnext, *dpnew; TileType i, j; int plane; int thislayer; int scalefactor; if (drcCifStyle == NULL) return drcCifWarning(); for (i = 0; i < drcCifStyle->cs_nLayers;i++) { CIFLayer *layer = drcCifStyle->cs_layers[i]; if (strcmp(layer->cl_name,layers) == 0) { thislayer = i; break; } } if (thislayer == -1) { TechError("Unknown cif layer: %s\n",layers); return (0); } scalefactor = drcCifStyle->cs_scaleFactor; // centiarea *= (drcCifStyle->cs_expander * drcCifStyle->cs_expander); dpnext = drcCifRules[thislayer][DRC_CIF_SPACE]; dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie))); drcCifAssign(dpnew, centihorizon, dpnext, &CIFSolidBits, &CIFSolidBits, why, centiarea, DRC_AREA | DRC_FORWARD | DRC_CIFRULE, thislayer, 0); drcCifRules[thislayer][DRC_CIF_SPACE] = dpnew; return ((centihorizon+scalefactor-1)/scalefactor); } /* * ---------------------------------------------------------------------------- * * drcCifMaxwidth -- cif version of drc list. * * Results: * Returns distance. * * Side effects: * Updates the DRC technology variables. * * ---------------------------------------------------------------------------- */ int drcCifMaxwidth(argc, argv) int argc; char *argv[]; { char *layers = argv[1]; int centidistance = atoi(argv[2]); char *bends = argv[3]; int why = drcWhyCreate(argv[4]); TileTypeBitMask set, setC, tmp1; DRCCookie *dpnext, *dpnew; TileType i, j; int plane; int bend; int thislayer; int scalefactor; if (drcCifStyle == NULL) return drcCifWarning(); for (i = 0; i < drcCifStyle->cs_nLayers;i++) { CIFLayer *layer = drcCifStyle->cs_layers[i]; if (strcmp(layer->cl_name,layers) == 0) { thislayer = i; break; } } if (thislayer == -1) { TechError("Unknown cif layer: %s\n",layers); return (0); } if (strcmp(bends,"bend_illegal") == 0) bend =0; else if (strcmp(bends,"bend_ok") == 0) bend =DRC_BENDS; else { TechError("unknown bend option %s\n",bends); return (0); } scalefactor = drcCifStyle->cs_scaleFactor; // centidistance *= drcCifStyle->cs_expander; // BSI dpnext = drcCifRules[thislayer][DRC_CIF_SPACE]; dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie))); drcCifAssign(dpnew, centidistance, dpnext, &CIFSolidBits, &CIFSolidBits, why, centidistance, DRC_MAXWIDTH | DRC_CIFRULE | bend, thislayer, 0); drcCifRules[thislayer][DRC_CIF_SPACE] = dpnew; return ((centidistance+scalefactor-1)/scalefactor); } /* *------------------------------------------------------------------------- * * drcCifCheckArea-- * * checks to see that a collection of cif tiles * have more than a minimum area. * * Results: * None * * Side Effects: * May cause errors to be painted. * *------------------------------------------------------------------------- */ void drcCheckCifArea(starttile, arg, cptr) Tile *starttile; struct drcClientData *arg; DRCCookie *cptr; { int arealimit = cptr->drcc_cdist; long area = 0L; TileTypeBitMask *oktypes = &cptr->drcc_mask; Tile *tile,*tp; Rect *cliprect = arg->dCD_rect; int scale = drcCifStyle->cs_scaleFactor; arg->dCD_cptr = (DRCCookie *)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 += (long)(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 >= (long)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 < (long)arealimit) { Rect rect; TiToRect(starttile,&rect); rect.r_xbot /= scale; rect.r_xtop /= scale; rect.r_ybot /= scale; rect.r_ytop /= scale; 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: /* 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); } } } /* *------------------------------------------------------------------------- * * drcCheckCifMaxwidth -- * * Checks to see that at least one dimension of a region * does not exceed some amount. * * Results: * None. * * Side Effects: * May cause errors to be painted. * *------------------------------------------------------------------------- */ void drcCheckCifMaxwidth(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; int scale = drcCifStyle->cs_scaleFactor; arg->dCD_cptr = (DRCCookie *)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) { rect.r_xbot /= scale; rect.r_xtop /= scale; rect.r_ybot /= scale; rect.r_ytop /= scale; 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; } /* 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); { rect.r_xbot /= scale; rect.r_xtop /= scale; rect.r_ybot /= scale; rect.r_ytop /= scale; 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))++; } } } /* 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); } } }