diff --git a/DRCtech.c b/DRCtech.c deleted file mode 100644 index f3d22699..00000000 --- a/DRCtech.c +++ /dev/null @@ -1,4094 +0,0 @@ -/* - * DRCtech.c -- - * - * Technology initialization for the DRC module. - * - * ********************************************************************* - * * Copyright (C) 1985, 1990 Regents of the University of California. * - * * 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. The University of California * - * * makes no representations about the suitability of this * - * * software for any purpose. It is provided "as is" without * - * * express or implied warranty. Export of this software outside * - * * of the United States of America may require an export license. * - * ********************************************************************* - */ - -#ifndef lint -static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/drc/DRCtech.c,v 1.12 2010/10/20 12:04:12 tim Exp $"; -#endif /* not lint */ - -#include -#include -#include - -#include "tcltk/tclmagic.h" -#include "utils/magic.h" -#include "utils/geometry.h" -#include "utils/utils.h" -#include "tiles/tile.h" -#include "utils/hash.h" -#include "database/database.h" -#include "drc/drc.h" -#include "utils/tech.h" -#include "textio/textio.h" -#include "utils/malloc.h" -#include "cif/cif.h" -#include "cif/CIFint.h" - -CIFStyle *drcCifStyle = NULL; -bool DRCForceReload = FALSE; -HashTable DRCWhyErrorTable; /* Table of DRC errors */ - -/* - * DRC interaction radius being used (not necessarily the same as - * what's defined in the current DRC style). - */ -global int DRCTechHalo; -global int DRCStepSize; - -/* The following variable can be set to zero to turn off - * any optimizations of design rule lists. - */ - -global int DRCRuleOptimization = TRUE; - -/* The following variables count how many rules were specified by - * the technology file and how many edge rules were optimized away. - */ - -static int drcRulesSpecified = 0; -static int drcRulesOptimized = 0; - -/* Rules with unique names are tagged with a reference number */ -/* for use in placing errors into the DRC error plane. */ - -static int DRCtag = 0; - -/* - * Forward declarations. - */ -int drcWidth(), drcSpacing(), drcEdge(), drcNoOverlap(); -int drcExactOverlap(), drcExtend(); -int drcSurround(), drcRectOnly(), drcOverhang(); -int drcStepSize(), drcOption(); -int drcMaxwidth(), drcArea(), drcRectangle(), drcAngles(); -int drcCifSetStyle(), drcCifWidth(), drcCifSpacing(); -int drcCifMaxwidth(), drcCifArea(); - -void DRCTechStyleInit(); -void drcLoadStyle(); -void DRCTechFinal(); -void drcTechFinalStyle(); - -/* - * ---------------------------------------------------------------------------- - * - * Given a TileType bit mask, return the plane mask of planes that are - * coincident with all types. This is roughly equivalent to the deprecated - * DBTechMinSetPlanes(), but does not attempt to produce a reduced set of - * tile types. Since the collective mask of all possible planes is usually - * found by a call to DBTechNoisyNameMask, we don't attempt to OR all the - * plane masks together, but assume this collective mask is available and - * passed as an argument. - * - * ---------------------------------------------------------------------------- - */ - -PlaneMask -CoincidentPlanes(typeMask, pmask) - TileTypeBitMask *typeMask; /* Mask of types to check coincidence */ - PlaneMask pmask; /* Mask of all possible planes of types */ -{ - PlaneMask planes = pmask; - TileType i; - - /* AND each plane against the collective mask */ - for (i = TT_SELECTBASE; i < DBNumTypes; i++) - if (TTMaskHasType(typeMask, i)) - planes &= DBTypePlaneMaskTbl[i]; - - return planes; -} - - -/* - * ---------------------------------------------------------------------------- - * - * Given a plane mask, return the plane number of the lowest plane in the mask. - * - * ---------------------------------------------------------------------------- - */ - -int -LowestMaskBit(PlaneMask pmask) -{ - PlaneMask pset = pmask; - int plane = 0; - - if (pmask == 0) return DBNumPlanes; - - while ((pset & 0x1) == 0) - { - plane++; - pset >>= 1; - } - return plane; -} - -/* - * ---------------------------------------------------------------------------- - * - * DRCPrintStyle -- - * - * Print the available and/or current extraction styles. - * - * Results: - * None. - * - * Side effects: - * Output. - * - * ---------------------------------------------------------------------------- - */ - -void -DRCPrintStyle(dolist, doforall, docurrent) - bool dolist, doforall, docurrent; -{ - DRCKeep *style; - - if (docurrent) - { - if (DRCCurStyle == NULL) - TxError("Error: No style is set\n"); - else - { - if (!dolist) TxPrintf("The current style is \""); -#ifdef MAGIC_WRAPPER - if (dolist) - Tcl_SetResult(magicinterp, DRCCurStyle->ds_name, NULL); - else -#endif - TxPrintf("%s", DRCCurStyle->ds_name); - if (!dolist) TxPrintf("\".\n"); - } - } - - if (doforall) - { - if (!dolist) TxPrintf("The DRC styles are: "); - - for (style = DRCStyleList; style; style = style->ds_next) - { - if (dolist) - { -#ifdef MAGIC_WRAPPER - Tcl_AppendElement(magicinterp, style->ds_name); -#else - if (style != DRCStyleList) TxPrintf(" "); - TxPrintf("%s", style->ds_name); -#endif - } - else - { - if (style != DRCStyleList) TxPrintf(", "); - TxPrintf("%s", style->ds_name); - } - } - if (!dolist) TxPrintf(".\n"); - } -} - -/* - * ---------------------------------------------------------------------------- - * - * DRCSetStyle -- - * - * Set the current DRC style to 'name'. - * - * Results: - * None. - * - * Side effects: - * Output. - * - * ---------------------------------------------------------------------------- - */ - -void -DRCSetStyle(name) - char *name; -{ - DRCKeep *style, *match; - int length; - - if (name == NULL) return; - - match = NULL; - length = strlen(name); - for (style = DRCStyleList; style; style = style->ds_next) - { - if (strncmp(name, style->ds_name, length) == 0) - { - if (match != NULL) - { - TxError("DRC style \"%s\" is ambiguous.\n", name); - DRCPrintStyle(FALSE, TRUE, TRUE); - return; - } - match = style; - } - } - - if (match != NULL) - { - drcLoadStyle(match->ds_name); - TxPrintf("DRC style is now \"%s\"\n", name); - return; - } - - TxError("\"%s\" is not one of the DRC styles Magic knows.\n", name); - DRCPrintStyle(FALSE, TRUE, TRUE); -} - -/* - * ---------------------------------------------------------------------------- - * - * drcTechFreeStyle -- - * - * This procedure frees all memory associated with a DRC style. - * - * Results: - * None. - * - * Side effects: - * Memory free'd. - * - * ---------------------------------------------------------------------------- - */ - -void -drcTechFreeStyle() -{ - int i, j; - char *old; - DRCCookie *dp; - - if (DRCCurStyle != NULL) - { - /* Remove all old rules from the DRC rules table */ - - for (i = 0; i < TT_MAXTYPES; i++) - for (j = 0; j < TT_MAXTYPES; j++) - { - dp = DRCCurStyle->DRCRulesTbl[i][j]; - while (dp != NULL) - { - char *old = (char *)dp; - dp = dp->drcc_next; - freeMagic(old); - } - } - - /* Clear the Why string list */ - freeMagic(DRCCurStyle->DRCWhyList); - - freeMagic(DRCCurStyle); - DRCCurStyle = NULL; - } -} - -/* - * ---------------------------------------------------------------------------- - * - * drcTechNewStyle -- - * - * This procedure creates a new DRC style at the end of the list - * of styles and initializes it to completely null. - * - * Results: - * None. - * - * Side effects: - * A new element is added to the end of DRCStyleList, and DRCCurStyle - * is set to point to it. - * - * ---------------------------------------------------------------------------- - */ - -void -drcTechNewStyle() -{ - drcTechFreeStyle(); - DRCTechStyleInit(); -} - -/* - * ---------------------------------------------------------------------------- - * drcWhyCreate -- - * - * Create a hash entry for the DRC "why" string, if it does not already - * exist. - * - * Returns: - * A pointer to the drcWhy structure containing the string and tag. - * - * Side effects: - * Adds to the DRCWhyList if whystring has not been used before. - * Calls StrDup() and increments DRCWhySize. DRCWhyList is allocated - * in blocks of 50 at a time and only expands when filled. - * Temporary hash table DRCWhyErrorTable is used to determine if a - * string entry is unique. It is cleared after the technology file - * has been processed. - * ---------------------------------------------------------------------------- - */ - -int -drcWhyCreate(whystring) - char *whystring; -{ - HashEntry *he; - - he = HashLookOnly(&DRCWhyErrorTable, whystring); - if (he != NULL) - return (int)((pointertype)HashGetValue(he)); - - /* Grow the list in increments of 50 */ - if ((DRCCurStyle->DRCWhySize % 50) == 0) - { - int i; - char **newList; - newList = (char **)mallocMagic((DRCCurStyle->DRCWhySize + 51) * sizeof(char *)); - newList[0] = (char *)NULL; - for (i = 1; i <= DRCCurStyle->DRCWhySize; i++) - newList[i] = DRCCurStyle->DRCWhyList[i]; - if (DRCCurStyle->DRCWhySize > 0) - freeMagic((char *)DRCCurStyle->DRCWhyList); - DRCCurStyle->DRCWhyList = newList; - } - DRCCurStyle->DRCWhySize++; - - he = HashFind(&DRCWhyErrorTable, whystring); - HashSetValue(he, (char *)((pointertype)DRCCurStyle->DRCWhySize)); - - DRCCurStyle->DRCWhyList[DRCCurStyle->DRCWhySize] = StrDup((char **)NULL, whystring); - - return DRCCurStyle->DRCWhySize; -} - -/* - * ---------------------------------------------------------------------------- - * - * drcFindBucket -- - * - * Find the bucket preceding the point where we with to insert a new DRC - * cookie. Don't insert a cookie in the middle of a pair of coupled - * (trigger + check) rules. - * - * Results: - * Returns a pointer to the location where we want to insert a rule - * - * Side effects: - * None. - * - * ---------------------------------------------------------------------------- - */ - -DRCCookie * -drcFindBucket(i, j, distance) - int i, j, distance; -{ - DRCCookie *dp; - - if (DRCCurStyle == NULL) return NULL; - - /* find bucket preceding the new one we wish to insert */ - - for (dp = DRCCurStyle->DRCRulesTbl[i][j]; - dp->drcc_next != (DRCCookie *) NULL; - dp = dp->drcc_next) - { - if (dp->drcc_next->drcc_flags & DRC_TRIGGER) - { - if (dp->drcc_next->drcc_next->drcc_dist >= distance) - break; - else - dp = dp->drcc_next; - } - else if (dp->drcc_next->drcc_dist >= distance) break; - } - - return dp; -} - -/* - * ---------------------------------------------------------------------------- - * - * drcLoadStyle -- - * - * Re-read the technology file to load the specified technology DRC style - * into structure DRCCurStyle. It incurs a complete reading of the tech - * file on startup and every time the extraction style is changed, but we - * can assume that this does not happen often. The first style in the - * technology file is assumed to be the default, so that re-reading the - * tech file is not necessary on startup unless the default DRC style is - * changed by a call do "drc style". - * - * ---------------------------------------------------------------------------- - */ - -void -drcLoadStyle(stylename) - char *stylename; -{ - SectionID invdrc; - - if (DRCCurStyle->ds_name == stylename) return; - - drcTechNewStyle(); /* Reinitialize and mark as not loaded */ - DRCCurStyle->ds_name = stylename; - - invdrc = TechSectionGetMask("drc", NULL); - TechLoad(NULL, invdrc); - - DRCTechScale(DBLambda[0], DBLambda[1]); -} - -/* - * ---------------------------------------------------------------------------- - * DRCReloadCurStyle --- - * - * This routine is used by CIFLoadStyle whenever the DRC section makes - * reference to CIF layers. - * - * Results: - * None. - * - * Side Effects: - * DRC rule database is deleted and regenerated. - * - * ---------------------------------------------------------------------------- - */ - -void -DRCReloadCurStyle() -{ - char *stylename; - DRCKeep * style; - - if (DRCCurStyle == NULL) return; - - for (style = DRCStyleList; style != NULL; style = style->ds_next) - { - if (!strcmp(style->ds_name, DRCCurStyle->ds_name)) - { - DRCCurStyle->ds_name = NULL; - drcLoadStyle(style->ds_name); - break; - } - } -} - -/* - * ---------------------------------------------------------------------------- - * DRCTechInit -- - * - * Free and re-initialize the technology-specific variables for the DRC module. - * This routine is *only* called upon a "tech load" command, when all existing - * DRC data must be cleaned up and free'd. - * - * Results: - * None. - * - * Side effects: - * Clears out all the DRC tables. - * ---------------------------------------------------------------------------- - */ - -void -DRCTechInit() -{ - DRCKeep *style; - - /* Clean up any old info */ - - drcTechFreeStyle(); - - for (style = DRCStyleList; style != NULL; style = style->ds_next) - { - freeMagic(style->ds_name); - freeMagic(style); - } - DRCStyleList = NULL; -} - -/* - * ---------------------------------------------------------------------------- - * DRCTechStyleInit -- - * - * Initialize the technology-specific variables for the DRC module. - * - * Results: - * None. - * - * Side effects: - * Clears out all the DRC tables. - * ---------------------------------------------------------------------------- - */ - -void -DRCTechStyleInit() -{ - int i, j, plane; - DRCCookie *dp; - PaintResultType result; - - drcRulesOptimized = 0; - drcRulesSpecified = 0; - - if (DRCCurStyle == NULL) - { - DRCCurStyle = (DRCStyle *) mallocMagic(sizeof(DRCStyle)); - DRCCurStyle->ds_name = NULL; - } - - DRCCurStyle->ds_status = TECH_NOT_LOADED; - - TTMaskZero(&DRCCurStyle->DRCExactOverlapTypes); - DRCCurStyle->DRCTechHalo = 0; - DRCCurStyle->DRCScaleFactorN = 1; - DRCCurStyle->DRCScaleFactorD = 1; - DRCCurStyle->DRCStepSize = 0; - DRCCurStyle->DRCFlags = (char)0; - DRCCurStyle->DRCWhySize = 0; - - HashInit(&DRCWhyErrorTable, 16, HT_STRINGKEYS); - - /* First DRC entry is associated with the statically-allocated */ - /* drcArrayCookie and has a tag of DRC_ARRAY_OVERLAP_TAG = 1 */ - /* (see DRCarray.c). */ - drcWhyCreate("This layer can't abut or partially overlap between array elements"); - - /* Second DRC entry is associated with the statically-allocated */ - /* drcOverlapCookie and has a tag of DRC_OVERLAP_TAG = 2 */ - /* (see DRCbasic.c). */ - drcWhyCreate("Can't overlap those layers"); - - /* Third DRC entry is associated with the statically-allocated */ - /* drcSubcellCookie and has a tag of DRC_SUBCELL_OVERLAP_TAG = 3 */ - /* (see DRCsubcell.c). */ - drcWhyCreate("This layer can't abut or partially overlap between subcells"); - - DRCTechHalo = 0; - - /* Put a dummy rule at the beginning of the rules table for each entry */ - - for (i = 0; i < TT_MAXTYPES; i++) - { - for (j = 0; j < TT_MAXTYPES; j++) - { - dp = DRCCurStyle->DRCRulesTbl[i][j]; - dp = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie))); - dp->drcc_dist = -1; - dp->drcc_cdist = -1; - dp->drcc_next = (DRCCookie *) NULL; - TTMaskZero(&dp->drcc_mask); - DRCCurStyle->DRCRulesTbl[i][j] = dp; - } - } - - /* Copy the default paint table into the DRC paint table. The DRC - * paint table will be modified as we read the drc section. Also - * make sure that the error layer is super-persistent (once it - * appears, it can't be gotten rid of by painting). Also, make - * some crossings automatically illegal: two layers can't cross - * unless the result of painting one on top of the other is to - * get one of the layers, and it doesn't matter which is painted - * on top of which. - */ - - for (plane = 0; plane < DBNumPlanes; plane++) - for (i = 0; i < DBNumTypes; i++) - for (j = 0; j < DBNumTypes; j++) - { - result = DBPaintResultTbl[plane][i][j]; - if ((i == TT_ERROR_S) || (j == TT_ERROR_S)) - DRCCurStyle->DRCPaintTable[plane][i][j] = TT_ERROR_S; - else if ((i == TT_SPACE) || (j == TT_SPACE) - || !DBTypeOnPlane(j, plane) - || !DBPaintOnTypePlanes(i, j)) - DRCCurStyle->DRCPaintTable[plane][i][j] = result; - - /* Modified for stackable types (Tim, 10/3/03) */ - else if ((i >= DBNumUserLayers) || - ((result >= DBNumUserLayers) - && (DBTechFindStacking(i, j) == result))) - { - DRCCurStyle->DRCPaintTable[plane][i][j] = result; - } - - else if ((!TTMaskHasType(&DBLayerTypeMaskTbl[i], result) - && !TTMaskHasType(&DBLayerTypeMaskTbl[j], result)) - || ((result != DBPaintResultTbl[plane][j][i]) - && DBTypeOnPlane(i, plane) - && DBPaintOnTypePlanes(j, i))) - { - DRCCurStyle->DRCPaintTable[plane][i][j] = TT_ERROR_S; - /* TxError("Error: %s on %s, was %s\n", - DBTypeLongNameTbl[i], DBTypeLongNameTbl[j], - DBTypeLongNameTbl[result]); */ - } - else - DRCCurStyle->DRCPaintTable[plane][i][j] = result; - } - - drcCifInit(); -} - -/* - * ---------------------------------------------------------------------------- - * - * DRCTechLine -- - * - * Parse a line in the DRC section from the technology file. Handle DRC - * styles. The rules themselves are handled by DRCTechAddRule. - * - * Results: - * TRUE if line parsed correctly; FALSE if fatal error condition - * encountered. - * - * Side effects: - * Appends information to the DRC tables. - * - * ---------------------------------------------------------------------------- - */ - -bool -DRCTechLine(sectionName, argc, argv) - char *sectionName; /* The name of this section */ - int argc; /* Number of fields on the line */ - char *argv[]; /* Values of the fields */ -{ - int j, l; - DRCKeep *newStyle, *p; - char *tptr, *cptr; - - if (argc <= 0) return TRUE; - else if (argc >= 2) l = strlen(argv[1]); - - if (strcmp(argv[0], "style") == 0) - { - if (argc != 2) - { - if ((argc != 4) || (strncmp(argv[2], "variant", 7))) - { - wrongNumArgs: - TechError("Wrong number of arguments in %s statement.\n", - argv[0]); - return TRUE; - } - } - for (newStyle = DRCStyleList; newStyle != NULL; - newStyle = newStyle->ds_next) - { - /* Here we're only establishing existence; break on - * the first variant found. - */ - if (!strncmp(newStyle->ds_name, argv[1], l)) - break; - } - if (newStyle == NULL) - { - if (argc == 2) - { - newStyle = (DRCKeep *)mallocMagic(sizeof(DRCKeep)); - newStyle->ds_next = NULL; - newStyle->ds_name = StrDup((char **) NULL, argv[1]); - - /* Append to end of style list */ - if (DRCStyleList == NULL) - DRCStyleList = newStyle; - else - { - for (p = DRCStyleList; p->ds_next; p = p->ds_next); - p->ds_next = newStyle; - } - } - else /* Handle style variants */ - { - DRCKeep *saveStyle = NULL; - - /* 4th argument is a comma-separated list of variants */ - - tptr = argv[3]; - while (*tptr != '\0') - { - cptr = strchr(tptr, ','); - if (cptr != NULL) *cptr = '\0'; - newStyle = (DRCKeep *)mallocMagic(sizeof(DRCKeep)); - newStyle->ds_next = NULL; - newStyle->ds_name = (char *)mallocMagic(l - + strlen(tptr) + 1); - sprintf(newStyle->ds_name, "%s%s", argv[1], tptr); - - /* Remember the 1st variant as the default */ - if (saveStyle == NULL) saveStyle = newStyle; - - /* Append to end of style list */ - if (DRCStyleList == NULL) - DRCStyleList = newStyle; - else - { - for (p = DRCStyleList; p->ds_next; p = p->ds_next); - p->ds_next = newStyle; - } - - if (cptr == NULL) - break; - else - tptr = cptr + 1; - } - newStyle = saveStyle; - } - } - - if (DRCCurStyle == NULL) /* Shouldn't happen, but be safe. . .*/ - { - drcTechNewStyle(); - DRCCurStyle->ds_name = newStyle->ds_name; - DRCCurStyle->ds_status = TECH_PENDING; - } - else if ((DRCCurStyle->ds_status == TECH_PENDING) || - (DRCCurStyle->ds_status == TECH_SUSPENDED)) - DRCCurStyle->ds_status = TECH_LOADED; - else if (DRCCurStyle->ds_status == TECH_NOT_LOADED) - { - if (DRCCurStyle->ds_name == NULL) { - DRCCurStyle->ds_name = newStyle->ds_name; - DRCCurStyle->ds_status = TECH_PENDING; - } - else if (argc == 2) - { - if (!strcmp(argv[1], DRCCurStyle->ds_name)) - DRCCurStyle->ds_status = TECH_PENDING; - } - else if (argc == 4) - { - /* Verify that the style matches one variant */ - - if (!strncmp(DRCCurStyle->ds_name, argv[1], l)) - { - tptr = argv[3]; - while (*tptr != '\0') - { - cptr = strchr(tptr, ','); - if (cptr != NULL) *cptr = '\0'; - if (!strcmp(DRCCurStyle->ds_name + l, tptr)) - { - DRCCurStyle->ds_status = TECH_PENDING; - return TRUE; - } - if (cptr == NULL) - return TRUE; - else - tptr = cptr + 1; - } - } - } - } - return (TRUE); - } - - if (DRCCurStyle == NULL) - return FALSE; - - /* For backwards compatibility, if we have encountered a line that */ - /* is not "style" prior to setting a style, then we create a style */ - /* called "default". */ - - if (DRCStyleList == NULL) - { - char *locargv[2][10] = {"style", "default"}; - - if (DRCTechLine(sectionName, 2, locargv) == FALSE) - return FALSE; - } - else if (DRCStyleList->ds_next == NULL) - { - /* On reload, if there is only one style, use it. This is */ - /* necessary for the DRC-CIF extensions, since even though */ - /* the one-and-only DRC section may have been loaded, the DRC- */ - /* CIF parts of it become enabled or disabled depending on what */ - /* CIFCurStyle is active. */ - - DRCCurStyle->ds_status = TECH_PENDING; - } - - /* Only continue past this point if we are loading the DRC style */ - - if ((DRCCurStyle->ds_status != TECH_PENDING) && - (DRCCurStyle->ds_status != TECH_SUSPENDED)) - return TRUE; - - /* Process "scalefactor" line next (if any) */ - - if (strcmp(argv[0], "scalefactor") == 0) - { - int scaleN, scaleD; - - if (argc != 2 && argc != 3) goto wrongNumArgs; - - scaleN = atof(argv[1]); - - if (argc == 3) - scaleD = atof(argv[2]); - else - scaleD = 1; - - if (scaleN <= 0 || scaleD <= 0) - { - TechError("Scale factor must be greater than 0.\n"); - TechError("Setting scale factor to default value 1.\n"); - DRCCurStyle->DRCScaleFactorN = 1; - DRCCurStyle->DRCScaleFactorD = 1; - return TRUE; - } - DRCCurStyle->DRCScaleFactorN = scaleN; - DRCCurStyle->DRCScaleFactorD = scaleD; - return TRUE; - } - - /* Process "variant" lines next. */ - - if (strncmp(argv[0], "variant", 7) == 0) - { - /* If our style variant is not one of the ones declared */ - /* on the line, then we ignore all input until we */ - /* either reach the end of the style, the end of the */ - /* section, or another "variant" line. */ - - if (argc != 2) goto wrongNumArgs; - tptr = argv[1]; - while (*tptr != '\0') - { - cptr = strchr(tptr, ','); - if (cptr != NULL) - { - *cptr = '\0'; - for (j = 1; isspace(*(cptr - j)); j++) - *(cptr - j) = '\0'; - } - - if (*tptr == '*') - { - DRCCurStyle->ds_status = TECH_PENDING; - return TRUE; - } - else - { - l = strlen(DRCCurStyle->ds_name) - strlen(tptr); - if (!strcmp(tptr, DRCCurStyle->ds_name + l)) - { - DRCCurStyle->ds_status = TECH_PENDING; - return TRUE; - } - } - - if (cptr == NULL) - break; - else - tptr = cptr + 1; - } - DRCCurStyle->ds_status = TECH_SUSPENDED; - } - - /* Anything below this line is not parsed if we're in TECH_SUSPENDED mode */ - if (DRCCurStyle->ds_status != TECH_PENDING) return TRUE; - - return DRCTechAddRule(sectionName, argc, argv); -} - -void -drcCifAssign(cookie, dist, next, mask, corner, tag, cdist, flags, planeto, planefrom) - DRCCookie *cookie, *next; - int dist, cdist; - TileTypeBitMask *mask, *corner; - int tag; - int flags, planeto, planefrom; -{ - (cookie)->drcc_dist = dist; - (cookie)->drcc_next = next; - (cookie)->drcc_mask = *mask; - (cookie)->drcc_corner = *corner; - (cookie)->drcc_tag = tag; - (cookie)->drcc_cdist = cdist; - (cookie)->drcc_flags = flags; - (cookie)->drcc_edgeplane = planefrom; - (cookie)->drcc_plane = planeto; - (cookie)->drcc_mod = 0; - (cookie)->drcc_cmod = 0; -} - -// This is like drcCifAssign, but checks for bad plane numbers in planeto and -// planefrom - -void -drcAssign(cookie, dist, next, mask, corner, why, cdist, flags, planeto, planefrom) - DRCCookie *cookie, *next; - int dist, cdist; - TileTypeBitMask *mask, *corner; - int why; - int flags, planeto, planefrom; -{ - /* Diagnostic */ - if (planeto >= DBNumPlanes) - TechError("Bad plane in DRC assignment.\n"); - if (planefrom >= DBNumPlanes) - TechError("Bad edge plane in DRC assignment.\n"); - - drcCifAssign(cookie, dist, next, mask, corner, why, cdist, flags, planeto, - planefrom); -} - -/* - * ---------------------------------------------------------------------------- - * - * DRCTechAddRule -- - * - * Add a new entry to the DRC table. - * - * Results: - * Always returns TRUE so that tech file read-in doesn't abort. - * - * Side effects: - * Updates the DRC technology variables. - * - * Organization: - * We select a procedure based on the first keyword (argv[0]) - * and call it to do the work of implementing the rule. Each - * such procedure is of the following form: - * - * int - * proc(argc, argv) - * int argc; - * char *argv[]; - * { - * } - * - * It returns the distance associated with the design rule, - * or -1 in the event of a fatal error that should cause - * DRCTechAddRule() to return FALSE (currently, none of them - * do, so we always return TRUE). If there is no distance - * associated with the design rule, 0 is returned. - * - * ---------------------------------------------------------------------------- - */ - - - /* ARGSUSED */ -bool -DRCTechAddRule(sectionName, argc, argv) - char *sectionName; /* Unused */ - int argc; - char *argv[]; -{ - int which, distance, mdist; - char *fmt; - static struct - { - char *rk_keyword; /* Initial keyword */ - int rk_minargs; /* Min # arguments */ - int rk_maxargs; /* Max # arguments */ - int (*rk_proc)(); /* Procedure implementing this keyword */ - char *rk_err; /* Error message */ - } ruleKeys[] = { - "angles", 4, 4, drcAngles, - "layers 45|90 why", - "edge", 8, 9, drcEdge, - "layers1 layers2 distance okTypes cornerTypes cornerDistance why [plane]", - "edge4way", 8, 9, drcEdge, - "layers1 layers2 distance okTypes cornerTypes cornerDistance why [plane]", - "exact_overlap", 2, 2, drcExactOverlap, - "layers", - "extend", 5, 6, drcExtend, - "layers1 layers2 distance why", - "no_overlap", 3, 3, drcNoOverlap, - "layers1 layers2", - "option", 2, 2, drcOption, - "option_name option_value", - "overhang", 5, 5, drcOverhang, - "layers1 layers2 distance why", - "rect_only", 3, 3, drcRectOnly, - "layers why", - "spacing", 6, 7, drcSpacing, - "layers1 layers2 separation [layers3] adjacency why", - "stepsize", 2, 2, drcStepSize, - "step_size", - "surround", 6, 6, drcSurround, - "layers1 layers2 distance presence why", - "width", 4, 4, drcWidth, - "layers width why", - "widespacing", 7, 8, drcSpacing, - "layers1 width layers2 separation adjacency why", - "area", 5, 5, drcArea, - "layers area horizon why", - "maxwidth", 4, 5, drcMaxwidth, - "layers maxwidth bends why", - "cifstyle", 2, 2, drcCifSetStyle, - "cif_style", - "cifwidth", 4, 4, drcCifWidth, - "layers width why", - "cifspacing", 6, 6, drcCifSpacing, - "layers1 layers2 separation adjacency why", - "cifarea", 5, 5, drcCifArea, - "layers area horizon why", - "cifmaxwidth", 5, 5, drcCifMaxwidth, - "layers maxwidth bends why", - "rectangle", 5, 5, drcRectangle, - "layers maxwidth [even|odd|any] why", - 0 - }, *rp; - - drcRulesSpecified += 1; - - which = LookupStruct(argv[0], (LookupTable *) ruleKeys, sizeof ruleKeys[0]); - if (which < 0) - { - TechError("Bad DRC rule type \"%s\"\n", argv[0]); - TxError("Valid rule types are:\n"); - for (fmt = "%s", rp = ruleKeys; rp->rk_keyword; rp++, fmt = ", %s") - TxError(fmt, rp->rk_keyword); - TxError(".\n"); - return (TRUE); - } - rp = &ruleKeys[which]; - if (argc < rp->rk_minargs || argc > rp->rk_maxargs) - { - TechError("Rule type \"%s\" usage: %s %s\n", - rp->rk_keyword, rp->rk_keyword, rp->rk_err); - return (TRUE); - } - - distance = (*rp->rk_proc)(argc, argv); - if (distance < 0) - return (FALSE); - - /* Update the halo to be the maximum distance (in magic units) of */ - /* any design rule */ - - mdist = distance; - - if (mdist > DRCTechHalo) - DRCTechHalo = mdist; - - return (TRUE); -} - -/* - * ---------------------------------------------------------------------------- - * - * drcExtend -- - * - * Process an extension rule. - * This is of the form: - * - * extend layers1 layers2 distance [exact_width] why - * - * indicating that if "layers1" extends from "layers2", then it must - * have a width of at least "distance". This is very much like the - * "overhang" rule, except that the extension is optional. Example: - * - * extend nfet ndiff 2 "n-transistor length must be at least 2" - * - * "extend" implements the following general-purpose edge rule: - * - * edge4way layers2 layers1 distance layers1 0 0 why - * - * Option "exact_width" implements an additional rule that checks for - * maximum extension at distance. This is intended for use with, for - * example, a fixed gate length for a specific type of device. - * - * Results: - * Returns distance. - * - * Side effects: - * Updates the DRC technology variables. - * - * ---------------------------------------------------------------------------- - */ - -int -drcExtend(argc, argv) - int argc; - char *argv[]; -{ - char *layers1 = argv[1]; - char *layers2 = argv[2]; - int distance = atoi(argv[3]); - int why; - TileTypeBitMask set1, setC; - DRCCookie *dp, *dpnew, *dptrig; - TileType i, j; - int plane, plane2; - TileTypeBitMask set2, setZ, setN, setM; - PlaneMask pMask1, pMask2, pset, ptest; - bool exact = FALSE; - - if (!strncmp(argv[4], "exact_", 6)) - { - exact = TRUE; - why = drcWhyCreate(argv[5]); - } - else - why = drcWhyCreate(argv[4]); - - ptest = DBTechNoisyNameMask(layers1, &set1); - pMask1 = CoincidentPlanes(&set1, ptest); - - if (pMask1 == 0) - { - TechError("All layers in first set for \"extend\" must be on " - "the same plane\n"); - return (0); - } - - ptest = DBTechNoisyNameMask(layers2, &set2); - pMask2 = CoincidentPlanes(&set2, ptest); - - if (pMask2 == 0) - { - TechError("All layers in second set for \"extend\" must be on " - "the same plane\n"); - return (0); - } - - /* setM is the union of set1 and set2 */ - TTMaskZero(&setM); - TTMaskSetMask3(&setM, &set1, &set2); - - /* setN is the inverse of set1, and setC is the inverse of set2 */ - TTMaskCom2(&setN, &set1); - TTMaskCom2(&setC, &set2); - - /* Zero mask */ - TTMaskZero(&setZ); - - for (i = 0; i < DBNumTypes; i++) - { - for (j = 0; j < DBNumTypes; j++) - { - if (i == j) continue; - if (pset = (DBTypesOnSamePlane(i, j) & pMask2)) - { - /* Edge depends on whether or not the extension is */ - /* on the same plane as the layer from which it is */ - /* measured. */ - - if ((pset & pMask1) != 0) - { - if (TTMaskHasType(&set2, i) && TTMaskHasType(&set1, j)) - { - plane = LowestMaskBit(pset & pMask1); - - /* find bucket preceding the new one we wish to insert */ - dp = drcFindBucket(i, j, distance); - dpnew = (DRCCookie *)mallocMagic(sizeof(DRCCookie)); - drcAssign(dpnew, distance, dp->drcc_next, &setM, &setZ, why, - 0, DRC_FORWARD, plane, plane); - - dp->drcc_next = dpnew; - - dp = drcFindBucket(j, i, distance); - dpnew = (DRCCookie *)mallocMagic(sizeof(DRCCookie)); - drcAssign(dpnew, distance, dp->drcc_next, &setM, &setZ, why, - 0, DRC_REVERSE, plane, plane); - - dp->drcc_next = dpnew; - - if (exact) - { - /* find bucket preceding the new one we wish to insert */ - dp = drcFindBucket(i, j, distance); - dpnew = (DRCCookie *)mallocMagic(sizeof(DRCCookie)); - drcAssign(dpnew, distance, dp->drcc_next, &setN, &setZ, why, - 0, DRC_FORWARD | DRC_OUTSIDE, plane, plane); - - dp->drcc_next = dpnew; - - dp = drcFindBucket(j, i, distance); - dpnew = (DRCCookie *)mallocMagic(sizeof(DRCCookie)); - drcAssign(dpnew, distance, dp->drcc_next, &setN, &setZ, why, - 0, DRC_REVERSE | DRC_OUTSIDE, plane, plane); - - dp->drcc_next = dpnew; - } - } - } - else /* Multi-plane extend rule */ - { - if (TTMaskHasType(&set2, i) && TTMaskHasType(&setC, j)) - { - plane = LowestMaskBit(pset); - plane2 = LowestMaskBit(pMask1); - - /* find bucket preceding the new one we wish to insert */ - dp = drcFindBucket(i, j, distance); - dpnew = (DRCCookie *)mallocMagic(sizeof(DRCCookie)); - drcAssign(dpnew, distance, dp->drcc_next, &setM, &setZ, why, - 0, DRC_FORWARD, plane2, plane); - dptrig = (DRCCookie *)mallocMagic(sizeof(DRCCookie)); - drcAssign(dptrig, 1, dpnew, &setN, &setZ, why, - 0, DRC_FORWARD | DRC_TRIGGER, plane2, plane); - dp->drcc_next = dptrig; - - dp = drcFindBucket(j, i, distance); - dpnew = (DRCCookie *)mallocMagic(sizeof(DRCCookie)); - drcAssign(dpnew, distance, dp->drcc_next, &setM, &setZ, why, - 0, DRC_REVERSE, plane2, plane); - dptrig = (DRCCookie *)mallocMagic(sizeof(DRCCookie)); - drcAssign(dptrig, 1, dpnew, &setN, &setZ, why, - 0, DRC_REVERSE | DRC_TRIGGER, plane2, plane); - dp->drcc_next = dptrig; - } - } - } - } - } - return (distance); -} - -/* - * ---------------------------------------------------------------------------- - * - * drcWidth -- - * - * Process a width rule. - * This is of the form: - * - * width layers distance why - * - * e.g, - * - * width poly,pmc 2 "poly width must be at least 2" - * - * Optional "from layers2" is useful when defining a device width; - * effectively, it represents an overhang rule where the presence of - * the overhanging material is optional. The equivalent rule is: - * - * edge4way layers2 layers distance layers 0 0 why - * - * - * Results: - * Returns distance. - * - * Side effects: - * Updates the DRC technology variables. - * - * ---------------------------------------------------------------------------- - */ - -int -drcWidth(argc, argv) - int argc; - char *argv[]; -{ - char *layers = argv[1]; - int distance = atoi(argv[2]); - int why = drcWhyCreate(argv[3]); - TileTypeBitMask set, setC; - PlaneMask pmask, pset, ptest; - DRCCookie *dp, *dpnew; - TileType i, j; - int plane; - - ptest = DBTechNoisyNameMask(layers, &set); - pmask = CoincidentPlanes(&set, ptest); - TTMaskCom2(&setC, &set); - - if (pmask == 0) - { - TechError("All layers for \"width\" must be on same plane\n"); - return (0); - } - - for (i = 0; i < DBNumTypes; i++) - { - for (j = 0; j < DBNumTypes; j++) - { - if (i == j) continue; - /* - * Must have types in 'set' for at least 'distance' - * to the right of any edge between a type in '~set' - * and a type in 'set'. - */ - - if (pset = (DBTypesOnSamePlane(i, j) & pmask)) - { - if (TTMaskHasType(&setC, i) && TTMaskHasType(&set, j)) - { - plane = LowestMaskBit(pset); - - /* Find bucket preceding the new one we wish to insert */ - dp = drcFindBucket(i, j, distance); - dpnew = (DRCCookie *)mallocMagic(sizeof (DRCCookie)); - drcAssign(dpnew, distance, dp->drcc_next, &set, &set, - why, distance, DRC_FORWARD, plane, plane); - dp->drcc_next = dpnew; - } - } - } - } - return (distance); -} - -/* - * ---------------------------------------------------------------------------- - * - * drcArea -- - * - * Process an area rule. - * This is of the form: - * - * area layers area horizon why - * - * e.g, - * - * area pmc 4 2 "poly contact area must be at least 4" - * - * "area" is the total area in lambda^2. - * - * "horizon" is the halo distance for the check. Normally, this would - * be the area (in lambda^2) divided by the minimum width rule (in - * lambda). Anything larger would not be a violation as long as the - * minimum width rule is satisfied. - * - * Results: - * Returns distance. - * - * Side effects: - * Updates the DRC technology variables. - * - * ---------------------------------------------------------------------------- - */ - -int -drcArea(argc, argv) - int argc; - char *argv[]; -{ - char *layers = argv[1]; - int distance = atoi(argv[2]); - int horizon = atoi(argv[3]); - int why = drcWhyCreate(argv[4]); - TileTypeBitMask set, setC; - DRCCookie *dp, *dpnew; - TileType i, j; - PlaneMask pmask, ptest, pset; - int plane; - - ptest = DBTechNoisyNameMask(layers, &set); - pmask = CoincidentPlanes(&set, ptest); - TTMaskCom2(&setC, &set); - - if (pmask == 0) - { - TechError("All layers for \"area\" must be on same plane\n"); - return (0); - } - - for (i = 0; i < DBNumTypes; i++) - { - for (j = 0; j < DBNumTypes; j++) - { - if (i == j) continue; - /* - * Must have types in 'set' for at least 'distance' - * to the right of any edge between a type in '~set' - * and a type in 'set'. - */ - if (pset = (DBTypesOnSamePlane(i, j) & pmask)) - { - if (TTMaskHasType(&setC, i) && TTMaskHasType(&set, j)) - { - plane = LowestMaskBit(pset); - - /* find bucket preceding the new one we wish to insert */ - dp = drcFindBucket(i, j, horizon); - dpnew = (DRCCookie *) mallocMagic(sizeof (DRCCookie)); - drcAssign(dpnew, horizon, dp->drcc_next, &set, &set, why, - distance, DRC_AREA|DRC_FORWARD, plane, plane); - - dp->drcc_next = dpnew; - } - } - } - } - return (horizon); -} - -/* - * ---------------------------------------------------------------------------- - * - * drcMaxwidth -- - * - * Process a maxwidth rule. - * This is of the form: - * - * maxwidth layers distance [bends] why - * - * This routine was updated 3/6/05 to match the "canonical" definition of - * a maxwidth region, which is any rectangle containing that is - * at least in both width and height. If the keyword - * "bend_illegal" is present, then the definition reverts to the original - * (see below) for backwards-compatibility. Otherwise ("bend_ok" or - * nothing), the new routine is used. - * - * maxwidth metal1 389 "metal1 width > 35um must be slotted" - * maxwidth pmc 4 bend_illegal "poly contact area must be no wider than 4" - * maxwidth trench 4 bend_ok "trench width must be exactly 4" - * - * bend_illegal - means that one_dimension must be distance for any - * point in the region. This is used for emitters and contacts - * that are rectangular (so we can't generate them with the - * squares command) and some exact width in one direction. - * bend_ok - Used mainly for wide metal rules where metal greater than - * some given width must be slotted. Also, used for things - * like trench, where the width is some fixed value: - * - * XXXXX XXXXXX - * X X XXXXXX - * X X X X - * XXXXX XXXXXX - * - * OK BAD - * - * Results: - * Returns distance. - * - * Side effects: - * Updates the DRC technology variables. - * - * ---------------------------------------------------------------------------- - */ - -int -drcMaxwidth(argc, argv) - int argc; - char *argv[]; -{ - char *layers = argv[1]; - int distance = atoi(argv[2]); - char *bends = argv[3]; - int why; - TileTypeBitMask set, setC; - DRCCookie *dp, *dpnew; - TileType i, j; - PlaneMask pmask, ptest, pset; - int plane; - int bend; - - ptest = DBTechNoisyNameMask(layers, &set); - pmask = CoincidentPlanes(&set, ptest); - TTMaskCom2(&setC, &set); - - if (pmask == 0) - { - TechError("All layers for \"maxwidth\" must be on same plane\n"); - return (0); - } - - if (argc == 4) - { - /* "bends" is irrelevent if distance is zero, so choose the */ - /* faster algorithm to process */ - - if (distance == 0) - bend = 0; - else - bend = DRC_BENDS; - why = drcWhyCreate(argv[3]); - } - else - { - 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); - } - why = drcWhyCreate(argv[4]); - } - - for (i = 0; i < DBNumTypes; i++) - { - for (j = 0; j < DBNumTypes; j++) - { - if (i == j) continue; - /* - * Must have types in 'set' for at least 'distance' - * to the right of any edge between a type in '~set' - * and a type in 'set'. - */ - if (pset = (DBTypesOnSamePlane(i, j) & pmask)) - { - if (TTMaskHasType(&setC, i) && TTMaskHasType(&set, j)) - { - plane = LowestMaskBit(pset); - - /* find bucket preceding the new one we wish to insert */ - dp = drcFindBucket(i, j, distance); - dpnew = (DRCCookie *) mallocMagic(sizeof (DRCCookie)); - drcAssign(dpnew, distance, dp->drcc_next, &set, &set, why, - distance, DRC_MAXWIDTH | bend, plane, plane); - - dp->drcc_next = dpnew; - } - } - } - } - return (distance); -} - -/* - * ---------------------------------------------------------------------------- - * drcAngles -- - * - * Process an "angles" rule specifying that geometry for a certain layer - * must be limited to 90 degrees or 45 degrees. If not specified, any - * angle is allowed, although width rules will flag errors on acute angles. - * - * ---------------------------------------------------------------------------- - */ - -int -drcAngles(argc, argv) - int argc; - char *argv[]; -{ - char *layers = argv[1]; - int angles = atoi(argv[2]); - int why = drcWhyCreate(argv[3]); - TileTypeBitMask set; - DRCCookie *dp, *dpnew; - int plane; - TileType i, j; - - DBTechNoisyNameMask(layers, &set); - - angles /= 45; - angles--; /* angles now 0 for 45s and 1 for 90s */ - - if ((angles != 0) && (angles != 1)) - { - TechError("angles must be 45 or 90\n"); - return 0; - } - - for (i = 0; i < DBNumTypes; i++) - { - if (TTMaskHasType(&set, i)) - { - plane = DBPlane(i); - - /* Insert rule at boundary of tile and TT_SPACE. This is */ - /* processed for each tile, separately from other rules, so */ - /* we don't really care what the edge is; TT_SPACE is */ - /* chosen as an arbitrary place to hold the rule. */ - - dp = drcFindBucket(TT_SPACE, i, 1); - dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie))); - drcAssign(dpnew, 1, dp->drcc_next, &set, &set, why, - 1, DRC_ANGLES | angles, plane, plane); - dp->drcc_next = dpnew; - } - } - return 1; -} - -/* - * ---------------------------------------------------------------------------- - * - * drcSpacing3 -- - * - * Process a special spacing rule of the form: - * - * spacing layers1 layers2 distance corner_ok layers3 why - * - * This spacing rule is not checked when a type from "layers3" fills the - * corner between "layers1" and "layers2". This is used, e.g., for - * diffusion-to-poly spacing, where diffusion and poly may touch at the - * corner of a FET type. It is equivalent to: - * - * edge4way layers1 ~(layers3,layers1) distance ~(layers2) 0 0 why - * - * The complementary case is redundant, so not checked. - * - * ---------------------------------------------------------------------------- - */ - -int -drcSpacing3(argc, argv) - int argc; - char *argv[]; -{ - char *layers1 = argv[1], *layers2 = argv[2]; - char *layers3 = argv[5]; - int distance = atoi(argv[3]); - char *adjacency = argv[4]; - int why = drcWhyCreate(argv[6]); - TileTypeBitMask set1, set2, set3; - int plane; - DRCCookie *dp, *dpnew; - TileType i, j; - PlaneMask pmask, pset, ptest; - - ptest = DBTechNoisyNameMask(layers1, &set1); - pmask = CoincidentPlanes(&set1, ptest); - - ptest = DBTechNoisyNameMask(layers2, &set2); - pmask &= CoincidentPlanes(&set2, ptest); - - ptest = DBTechNoisyNameMask(layers3, &set3); - pmask &= CoincidentPlanes(&set3, ptest); - - if (pmask == 0) - { - TechError("Spacing check with \"corner_ok\" must have" - " all types in one plane.\n"); - return (0); - } - - /* In this usage everything must fall in the same plane. */ - - /* We need masks for (~types2)/plane and for (~(types1,types3))/plane */ - - TTMaskCom(&set2); - TTMaskSetMask(&set3, &set1); - TTMaskCom(&set3); - - for (i = 0; i < DBNumTypes; i++) - { - for (j = 0; j < DBNumTypes; j++) - { - if (i == j) continue; - if (pset = (DBTypesOnSamePlane(i, j) & pmask)) - { - if (TTMaskHasType(&set1, i) && TTMaskHasType(&set3, j)) - { - plane = LowestMaskBit(pset); - - /* Find bucket preceding the new one we wish to insert */ - dp = drcFindBucket(i, j, distance); - dpnew = (DRCCookie *)mallocMagic(sizeof (DRCCookie)); - drcAssign(dpnew, distance, dp->drcc_next, &set2, &set3, - why, distance, DRC_FORWARD | DRC_BOTHCORNERS, - plane, plane); - dp->drcc_next = dpnew; - - /* find bucket preceding new one we wish to insert */ - dp = drcFindBucket(j, i, distance); - dpnew = (DRCCookie *)mallocMagic(sizeof (DRCCookie)); - drcAssign(dpnew, distance, dp->drcc_next, &set2, &set3, - why, distance, DRC_REVERSE | DRC_BOTHCORNERS, - plane, plane); - dp->drcc_next = dpnew; - } - } - } - } - return distance; -} - -/* - *------------------------------------------------------------------- - * - * drcMaskSpacing --- - * - * This is the core of the drcSpacing routine. When the spacing - * rule layers independently cover more than one plane, this routine - * is invoked for each independent plane. - * - * Results: - * Returns the rule's maximum distance - * - * Side effects: - * Adds rules to the DRC rule table. - * - *------------------------------------------------------------------- - */ - -int -drcMaskSpacing(set1, set2, pmask1, pmask2, wwidth, distance, adjacency, - why, widerule, runlength, multiplane) - TileTypeBitMask *set1, *set2; - PlaneMask pmask1, pmask2; - int wwidth, distance; - char *adjacency, *why; - bool widerule; - int runlength; - bool multiplane; -{ - TileTypeBitMask tmp1, tmp2, setR, setRreverse; - int plane, plane2; - PlaneMask pset, ptest; - DRCCookie *dp, *dpnew; - int needReverse = (widerule) ? TRUE : FALSE; - TileType i, j, pref; - bool needtrigger = FALSE; - bool touchingok = TRUE; - bool cornerok = FALSE; - - if (!strcmp(adjacency, "surround_ok")) - { - if (multiplane) - { - TechError("\"surround_ok\" requires surrounding types to " - "be in the same plane.\n"); - return (0); - } - else if ((pmask1 & pmask2) == 0) - { - /* New rule implementation (7/8/06): When types */ - /* are on different planes and "surround_ok" is */ - /* declared, implement as a triggered rule (but not */ - /* for widespacing, which already uses the */ - /* triggering rule mechanism). */ - - if (!widerule) - { - needtrigger = TRUE; - touchingok = FALSE; - - } - else - { - TechError("Widespacing checks cannot use \"surround_ok\".\n"); - return (0); - } - } - else - { - TechError("\"surround_ok\" used when spacing rule types are in " - "the same plane. Did you mean \"touching_ok\"?\n"); - touchingok = TRUE; /* Treat like "touching_ok" */ - } - } - else if (!strcmp(adjacency, "touching_ok")) - { - /* If touching is OK, everything must fall in the same plane. */ - if (multiplane || ((pmask1 & pmask2) == 0)) - { - TechError("Spacing check with \"touching_ok\" must have" - " all types in one plane. Possibly you want" - " \"surround_ok\"?\n"); - return (0); - } - else - touchingok = TRUE; - } - else if (!strcmp(adjacency, "touching_illegal")) - { - touchingok = FALSE; - needtrigger = FALSE; - } - else - { - TechError("Badly formed drc spacing line: need \"touching_ok\", " - "\"touching_illegal\", or \"surround_ok\".\n"); - return (0); - } - - if (touchingok) - { - /* In "touching_ok rules, spacing to set2 is be checked in FORWARD - * direction at edges between set1 and (setR = ~set1 AND ~set2). - * - * In addition, spacing to set1 is checked in FORWARD direction - * at edges between set2 and (setRreverse = ~set1 AND ~set2). - * - * If set1 and set2 are different, above are checked in REVERSE as - * well as forward direction. This is important since touching - * material frequently masks violations in one direction. - * - * setR and setRreverse are set appropriately below. - */ - - tmp1 = *set1; - tmp2 = *set2; - - /* Restrict planes to those that are coincident */ - pmask1 &= pmask2; - pmask2 = pmask1; - TTMaskCom(&tmp1); - TTMaskCom(&tmp2); - TTMaskAndMask(&tmp1, &tmp2); - setR = tmp1; - setRreverse = tmp1; - - /* If set1 != set2, set flag to check rules in both directions */ - if (!TTMaskEqual(set1, set2)) - needReverse = TRUE; - } - else - { - /* In "touching_illegal" rules, spacing to set2 will be checked - * in FORWARD direction at edges between set1 and (setR=~set1). - * - * In addition, spacing to set1 will be checked in FORWARD direction - * at edges between set2 and (setRreverse= ~set2). - * - * setR and setRreverse are set appropriately below. - */ - TTMaskCom2(&setR, set1); - TTMaskCom2(&setRreverse, set2); - } - - for (i = 0; i < DBNumTypes; i++) - { - for (j = 0; j < DBNumTypes; j++) - { - if (i == j) continue; - if (pset = (DBTypesOnSamePlane(i, j) & pmask1)) - { - plane = LowestMaskBit(pset); - - /* LHS is an element of set1, RHS is an element of setR */ - if (TTMaskHasType(set1, i) && TTMaskHasType(&setR, j)) - { - plane2 = LowestMaskBit(pmask2); - - /* - * Must not have 'set2' for 'distance' to the right of - * an edge between 'set1' and the types not in 'set1' - * (touching_illegal case) or in neither - * 'set1' nor 'set2' (touching_ok case). - */ - - /* Find bucket preceding the new one we wish to insert */ - dp = drcFindBucket(i, j, distance); - - dpnew = (DRCCookie *)mallocMagic(sizeof(DRCCookie)); - TTMaskClearMask3(&tmp1, &DBPlaneTypes[plane2], set2); - TTMaskAndMask3(&tmp2, &DBPlaneTypes[plane], &setR); - - if (widerule) - { - DRCCookie *dptrig; - - /* Create two contiguous rules, one for spacing */ - /* and one for width. These are created in */ - /* reverse order due to the stack property of */ - /* the linked list. */ - - drcAssign(dpnew, distance, dp->drcc_next, &tmp1, &tmp2, - why, distance, DRC_FORWARD, plane2, plane); - dptrig = (DRCCookie *) mallocMagic((unsigned) - (sizeof (DRCCookie))); - drcAssign(dptrig, wwidth, dpnew, set1, set1, why, - runlength, DRC_REVERSE | DRC_MAXWIDTH | - DRC_TRIGGER | DRC_BENDS, plane2, plane); - - dp->drcc_next = dptrig; - } - else if (needtrigger) - { - DRCCookie *dptrig; - - /* Create two contiguous spacing rules */ - - drcAssign(dpnew, distance, dp->drcc_next, &tmp1, &tmp2, - why, wwidth, DRC_FORWARD | DRC_BOTHCORNERS, - plane2, plane); - dptrig = (DRCCookie *) mallocMagic((unsigned) - (sizeof (DRCCookie))); - drcAssign(dptrig, 1, dpnew, set2, &tmp2, why, 1, - DRC_FORWARD | DRC_TRIGGER, - plane2, plane); - - dp->drcc_next = dptrig; - } - else - { - drcAssign(dpnew, distance, dp->drcc_next, &tmp1, - &tmp2, why, wwidth, DRC_FORWARD, plane2, plane); - dp->drcc_next = dpnew; - } - - if (needReverse) - dpnew->drcc_flags |= DRC_BOTHCORNERS; - - if (needReverse) - { - /* Add check in reverse direction, - * NOTE: am assuming single plane rule here (since reverse - * rules only used with touching_ok which must be - * single plane) - */ - - /* find bucket preceding new one we wish to insert */ - dp = drcFindBucket(j, i, distance); - dpnew = (DRCCookie *)mallocMagic(sizeof (DRCCookie)); - if (widerule) - { - DRCCookie *dptrig; - - /* Assign two coupled rules (see above) */ - - drcAssign(dpnew, distance, dp->drcc_next, &tmp1, - &tmp2, why, distance, - DRC_REVERSE | DRC_BOTHCORNERS, plane2, plane); - dptrig = (DRCCookie *) mallocMagic((unsigned) - (sizeof (DRCCookie))); - drcAssign(dptrig, wwidth, dpnew, set1, set1, why, - runlength, DRC_FORWARD | DRC_MAXWIDTH | - DRC_TRIGGER | DRC_BENDS, plane2, plane); - dp->drcc_next = dptrig; - } - else if (needtrigger) - { - DRCCookie *dptrig; - - /* Create two contiguous spacing rules */ - - drcAssign(dpnew, distance, dp->drcc_next, &tmp1, &tmp2, - why, wwidth, DRC_REVERSE | DRC_BOTHCORNERS, - plane2, plane); - dptrig = (DRCCookie *) mallocMagic((unsigned) - (sizeof (DRCCookie))); - drcAssign(dptrig, 1, dpnew, set2, &tmp2, why, 1, - DRC_REVERSE | DRC_TRIGGER, - plane2, plane); - - dp->drcc_next = dptrig; - } - else - { - drcAssign(dpnew,distance,dp->drcc_next, - &tmp1, &tmp2, why, wwidth, - DRC_REVERSE | DRC_BOTHCORNERS, plane2, plane); - dp->drcc_next = dpnew; - } - } - } - } - - if (TTMaskEqual(set1, set2)) continue; - if (widerule) continue; /* Can't determine width of set1 */ - /* when looking at the edge of set2 */ - - /* - * Now, if set1 and set2 are distinct apply the rule for LHS in set1 - * and RHS in set2. - */ - - if (pset = (DBTypesOnSamePlane(i, j) & pmask2)) - { - plane = LowestMaskBit(pset); - - /* LHS is an element of set2, RHS is an element of setRreverse */ - if (TTMaskHasType(set2, i) && TTMaskHasType(&setRreverse, j)) - { - plane2 = LowestMaskBit(pmask1); - - /* Find bucket preceding the new one we wish to insert */ - dp = drcFindBucket(i, j, distance); - dpnew = (DRCCookie *)mallocMagic(sizeof (DRCCookie)); - TTMaskClearMask3(&tmp1, &DBPlaneTypes[plane2], set1); - TTMaskAndMask3(&tmp2, &DBPlaneTypes[plane], &setRreverse); - - if (needtrigger) - { - DRCCookie *dptrig; - - /* Create two contiguous spacing rules */ - - drcAssign(dpnew, distance, dp->drcc_next, &tmp1, &tmp2, - why, distance, DRC_FORWARD | DRC_BOTHCORNERS, - plane2, plane); - dptrig = (DRCCookie *)mallocMagic(sizeof (DRCCookie)); - drcAssign(dptrig, 1, dpnew, set1, &tmp2, why, 1, - DRC_FORWARD | DRC_TRIGGER, - plane2, plane); - dp->drcc_next = dptrig; - } - else - { - drcAssign(dpnew, distance, dp->drcc_next, &tmp1, &tmp2, - why, distance, DRC_FORWARD, plane2, plane); - dp->drcc_next = dpnew; - } - - if (needReverse) - dpnew->drcc_flags |= DRC_BOTHCORNERS; - - if (needReverse) - { - /* Add check in reverse direction, - * NOTE: am assuming single plane rule here (since reverse - * rules only used with touching_ok which must be - * single plane) - */ - /* find bucket preceding new one we wish to insert */ - dp = drcFindBucket(j, i, distance); - dpnew = (DRCCookie *) mallocMagic(sizeof (DRCCookie)); - - if (needtrigger) - { - DRCCookie *dptrig; - - /* Create two contiguous spacing rules */ - - drcAssign(dpnew, distance, dp->drcc_next, &tmp1, &tmp2, - why, distance, DRC_REVERSE | DRC_BOTHCORNERS, - plane2, plane); - dptrig = (DRCCookie *)mallocMagic(sizeof (DRCCookie)); - drcAssign(dptrig, 1, dpnew, set1, &tmp2, why, 1, - DRC_REVERSE | DRC_TRIGGER, - plane2, plane); - dp->drcc_next = dptrig; - } - else - { - drcAssign(dpnew, distance, dp->drcc_next, - &tmp1, &tmp2, why, distance, - DRC_REVERSE | DRC_BOTHCORNERS, plane2, plane); - dp->drcc_next = dpnew; - } - } - } - } - - /* Finally, if multiplane rule then check that set2 types - * are not present just to right of edges with setR on LHS - * and set1 on RHS. This check is necessary to make sure - * that a set1 rectangle doesn't coincide exactly with a - * set2 rectangle. - * (This check added by Michael Arnold on 4/10/86.) - */ - - if (needtrigger) continue; - - if (pset = (DBTypesOnSamePlane(i, j) & pmask1)) - { - plane = LowestMaskBit(pset); - - /* LHS is an element of setR, RHS is an element of set1 */ - if (TTMaskHasType(&setR, i) && TTMaskHasType(set1, j)) - { - /* - * Must not have 'set2' for 'distance' to the right of - * an edge between the types not in set1 and set1. - * (is only checked for cross plane rules - these are - * all of type touching_illegal) - */ - - /* Walk list to last check. New checks ("cookies") go - * at end of list since we are checking for distance of - * 1 and the list is sorted in order of decreasing distance. - */ - for (dp = DRCCurStyle->DRCRulesTbl [i][j]; - dp->drcc_next != (DRCCookie *) NULL; - dp = dp->drcc_next); /* null body */ - - /* Insert one check for each plane involved in set2 */ - plane2 = LowestMaskBit(pmask2); - - /* filter out checks that are not cross plane */ - if (i == TT_SPACE) - { - if (DBTypeOnPlane(j, plane2)) - continue; - } - else - { - if (DBTypeOnPlane(i, plane2)) - continue; - } - - /* create new check and add it to list */ - dpnew = (DRCCookie *) mallocMagic(sizeof (DRCCookie)); - TTMaskClearMask3(&tmp1, &DBPlaneTypes[plane2], set2); - TTMaskZero(&tmp2); - - drcAssign(dpnew, 1, dp->drcc_next, &tmp1, &tmp2, why, - distance, DRC_FORWARD, plane2, plane); - dp->drcc_next = dpnew; - } - } - } - } - return (MAX(wwidth, distance)); -} - -/* - * ---------------------------------------------------------------------------- - * - * drcSpacing -- - * - * Process a spacing rule. - * This is of the form: - * - * spacing layers1 layers2 distance adjacency why - * - * e.g, - * - * spacing metal,pmc/m,dmc/m metal,pmc/m,dmc/m 4 touching_ok \ - * "metal spacing must be at least 4" - * - * Adjacency may be either "touching_ok" or "touching_illegal" - * In the first case, no violation occurs when types in layers1 are - * immediately adjacent to types in layers2. In the second case, - * such adjacency causes a violation. - * - * Results: - * Returns distance. - * - * Side effects: - * Updates the DRC technology variables. - * - * Notes: - * Extended to include the rule syntax: - * - * widespacing layers1 width [runlength] layers2 distance adjacency why - * - * This extension covers rules such as "If m1 width > 10um, then spacing to - * unconnected m1 must be at least 0.6um". This assumes that the instantiated - * edge4way rule is a standard "spacing" rule in which "dist" and "cdist" - * (corner extension) distances are always the same, so we can use the "cdist" - * record to encode the width of "layers1" which triggers the rule. We re-use - * the CheckMaxwidth() code, but with the following differences: 1) it does not - * trigger any error painting functions, 2) it returns a value stating whether - * the maxwidth rule applies or not, 3) it uses the DBLayerTypeMaskTbl[] for - * the tile type in question, not "oktypes", for its search, and 4) it uses - * the max width in the "cdist" record, not the "dist" record, for the max - * width rule. The "dist" record is copied to "cdist" before actually applying - * the spacing rule, so that the rule acts like a proper spacing rule. - * - * Added adjacency rule "surround_ok" to check spacing to a type that - * may also abut or surround the first layer---the portion of the layer - * that is abutting or surrounding is not checked. This allows checks - * of, e.g., diffusion in well to a separate well edge, or distance from - * a poly bottom plate to unconnected poly. - * - * (Added 11/6/06) Adjacency may be "corner_ok", in which case it calls - * routing drcSpacing3() (see above). - * - * (Added 9/19/18) Additional run-length distance can be used to limit the - * maxwidth rule to geometry exceeding the given run-length (often used with - * 65nm and smaller feature size processes). - * - * ---------------------------------------------------------------------------- - */ - -int -drcSpacing(argc, argv) - int argc; - char *argv[]; -{ - char *layers1 = argv[1], *layers2; - char *adjacency; - int why; - TileTypeBitMask set1, set2, tmp1, tmp2; - PlaneMask pmask1, pmask2, pmaskA, pmaskB, ptest; - int wwidth, distance, plane, plane2, runlength; - bool widerule, multiplane = FALSE; - - if ((argc == 7) && (!strcmp(argv[4], "corner_ok"))) - return drcSpacing3(argc, argv); - - widerule = (strncmp(argv[0], "wide", 4) == 0); - - if (widerule) - { - wwidth = atoi(argv[2]); - - if (argc == 8) - { - runlength = atoi(argv[3]); - layers2 = argv[4]; - distance = atoi(argv[5]); - adjacency = argv[6]; - why = drcWhyCreate(argv[7]); - } - else - { - layers2 = argv[3]; - distance = atoi(argv[4]); - runlength = distance; - adjacency = argv[5]; - why = drcWhyCreate(argv[6]); - } - /* TxPrintf("Info: DRCtech: widespacing rule for %s width %d:" - " spacing must be %d\n", layers1, wwidth, distance); */ - } - else - { - layers2 = argv[2]; - distance = atoi(argv[3]); - adjacency = argv[4]; - wwidth = distance; - why = drcWhyCreate(argv[5]); - runlength = distance; - if (argc >= 7) - { - TechError("Unknown argument in spacing line.\n"); - return(0); - } - } - - /* Either list of types may contain independent types on different */ - /* planes. However, if so, then we may not use touching_ok, and */ - /* there are other restrictions. */ - - ptest = DBTechNoisyNameMask(layers1, &set1); - pmask1 = CoincidentPlanes(&set1, ptest); - - if ((pmask1 == 0) && (ptest != 0)) - { - pmask1 = ptest; - multiplane = TRUE; - for (plane = 0; plane < DBNumPlanes; plane++) - for (plane2 = 0; plane2 < DBNumPlanes; plane2++) - { - if (plane == plane2) continue; - if (PlaneMaskHasPlane(pmask1, plane) && - PlaneMaskHasPlane(pmask1, plane2)) - { - TTMaskAndMask3(&tmp1, &DBPlaneTypes[plane], - &DBPlaneTypes[plane2]); - TTMaskAndMask(&tmp1, &set1); - if (!TTMaskIsZero(&tmp1)) - { - TechError("Types in first list must either be in" - " one plane or else types must not share" - " planes.\n"); - return (0); - } - } - } - } - - ptest = DBTechNoisyNameMask(layers2, &set2); - pmask2 = CoincidentPlanes(&set2, ptest); - - if ((pmask2 == 0) && (ptest != 0)) - { - pmask2 = ptest; - multiplane = TRUE; - for (plane = 0; plane < DBNumPlanes; plane++) - for (plane2 = 0; plane2 < DBNumPlanes; plane2++) - { - if (plane == plane2) continue; - if (PlaneMaskHasPlane(pmask2, plane) && - PlaneMaskHasPlane(pmask2, plane2)) - { - TTMaskAndMask3(&tmp1, &DBPlaneTypes[plane], - &DBPlaneTypes[plane2]); - TTMaskAndMask(&tmp1, &set2); - if (!TTMaskIsZero(&tmp1)) - { - TechError("Types in second list must either be in" - " one plane or else types must not share" - " planes.\n"); - return (0); - } - } - } - } - - if (multiplane) - { - /* Loop over independent plane/layer combinations */ - - for (plane = 0; plane < DBNumPlanes; plane++) - for (plane2 = 0; plane2 < DBNumPlanes; plane2++) - { - if (PlaneMaskHasPlane(pmask1, plane) && - PlaneMaskHasPlane(pmask2, plane2)) - { - pmaskA = PlaneNumToMaskBit(plane); - pmaskB = PlaneNumToMaskBit(plane2); - - TTMaskAndMask3(&tmp1, &set1, &DBPlaneTypes[plane]); - TTMaskAndMask3(&tmp2, &set2, &DBPlaneTypes[plane2]); - - return drcMaskSpacing(&tmp1, &tmp2, pmaskA, pmaskB, - wwidth, distance, adjacency, why, - widerule, runlength, multiplane); - } - } - } - else - return drcMaskSpacing(&set1, &set2, pmask1, pmask2, wwidth, - distance, adjacency, why, widerule, runlength, multiplane); - - return 0; -} - -/* - * ---------------------------------------------------------------------------- - * - * drcEdge -- - * - * Process a primitive edge rule. - * This is of the form: - * - * edge layers1 layers2 dist OKtypes cornerTypes cornerDist why [plane] - * or edge4way layers1 layers2 dist OKtypes cornerTypes cornerDist why [plane] - * - * e.g, - * - * edge poly,pmc s 1 diff poly,pmc "poly-diff separation must be 2" - * - * An "edge" rule is applied only down and to the left. - * An "edge4way" rule is applied in all four directions. - * - * Results: - * Returns greater of dist and cdist. - * - * Side effects: - * Updates the DRC technology variables. - * - * ---------------------------------------------------------------------------- - */ - -int -drcEdge(argc, argv) - int argc; - char *argv[]; -{ - char *layers1 = argv[1], *layers2 = argv[2]; - int distance = atoi(argv[3]); - char *okTypes = argv[4], *cornerTypes = argv[5]; - int cdist = atoi(argv[6]); - int why = drcWhyCreate(argv[7]); - bool fourway = (strcmp(argv[0], "edge4way") == 0); - TileTypeBitMask set1, set2, setC, setM; - DRCCookie *dp, *dpnew; - int plane, checkPlane, tmpPlane; - PlaneMask pMask1, pMaskM, pMaskC, pset, ptest; - TileType i, j; - - /* - * Edge4way rules produce [j][i] entries as well as [i][j] - * ones, and check both corners rather than just one corner. - */ - - ptest = DBTechNoisyNameMask(layers1, &set1); - pMask1 = CoincidentPlanes(&set1, ptest); - - ptest = DBTechNoisyNameMask(layers2, &set2); - pMask1 &= CoincidentPlanes(&set2, ptest); - - if (pMask1 == 0) - { - TechError("All edges in edge rule must lie in shared planes.\n"); - return (0); - } - - /* Give warning if types1 and types2 intersect */ - if (TTMaskIntersect(&set1, &set2)) - TechError("Warning: types1 and types2 have nonempty intersection. " - "DRC does not check edges with the same type on both " - "sides.\n"); - - ptest = DBTechNoisyNameMask(cornerTypes, &setC); - pMaskC = CoincidentPlanes(&setC, ptest); - - if ((pMaskC & pMask1) == 0) - { - TechError("Corner types aren't in same plane as edges.\n"); - return (0); - } - - if (argc == 9) - tmpPlane = DBTechNoisyNamePlane(argv[8]); - - /* - * OKtypes determine the checkPlane. If checkPlane exists, it should - * only be used to check against the plane of OKtypes. - */ - - ptest = DBTechNoisyNameMask(okTypes, &setM); - pMaskM = CoincidentPlanes(&setM, ptest); - - if (pMaskM == 0 || pMaskM == DBTypePlaneMaskTbl[TT_SPACE]) - { - /* Technically it should be illegal to specify simply "space" - * in the types list for a DRC rule, as it is ambiguous. - * However, we will assume that the plane of the edge is - * intended. The "plane" argument may be used to do the - * qualification (for backwards compatibility); any other use - * gets a warning. - */ - - if (TTMaskEqual(&DBSpaceBits, &setM)) - { - if (argc == 9) - pMaskM = PlaneNumToMaskBit(tmpPlane); - else - { - TechError("OK types \"%s\" in more than one plane.\n" - " Assuming same plane (%s) as edge.\n", - okTypes, DBPlaneLongNameTbl[LowestMaskBit(pMask1)]); - pMaskM = pMask1; - } - } - - /* The case okTypes="0" is explicitly allowed according */ - /* to the manual, so we parse it accordingly. */ - - else if (!strcmp(okTypes, "0")) - pMaskM = pMask1; - else - { - TechError("All OK types must lie in one plane.\n"); - return (0); - } - } - - /* "plane" argument deprecated; kept for backward compatibility only */ - - if ((argc == 9) && (PlaneNumToMaskBit(tmpPlane) != pMaskM)) - TechError("Ignoring bad plane argument.\n"); - - for (i = 0; i < DBNumTypes; i++) - { - for (j = 0; j < DBNumTypes; j++) - { - if (i == j) continue; - if (pset = (DBTypesOnSamePlane(i, j) & pMask1)) - { - if (TTMaskHasType(&set1, i) && TTMaskHasType(&set2, j)) - { - /* For fastest DRC, checkPlane and plane should be */ - /* the same, if possible. */ - - if (pset & pMaskM != 0) - { - plane = LowestMaskBit(pset & pMaskM); - checkPlane = plane; - } - else - { - plane = LowestMaskBit(pset); - checkPlane = LowestMaskBit(pMaskM); - } - - /* Find bucket preceding the new one we wish to insert */ - dp = drcFindBucket(i, j, distance); - dpnew = (DRCCookie *)mallocMagic(sizeof (DRCCookie)); - drcAssign(dpnew, distance, dp->drcc_next, &setM, &setC, - why, cdist, DRC_FORWARD, checkPlane, plane); - if (fourway) dpnew->drcc_flags |= DRC_BOTHCORNERS; - dp->drcc_next = dpnew; - - if (!fourway) continue; - - /* find bucket preceding new one we wish to insert */ - dp = drcFindBucket(j, i, distance); - dpnew = (DRCCookie *)mallocMagic(sizeof (DRCCookie)); - drcAssign(dpnew,distance,dp->drcc_next, &setM, &setC, - why, cdist, DRC_REVERSE, checkPlane, plane); - dpnew->drcc_flags |= DRC_BOTHCORNERS; - dp->drcc_next = dpnew; - } - } - } - } - return (MAX(distance, cdist)); -} - -/* - * ---------------------------------------------------------------------------- - * - * drcOverhang -- - * - * Process an overhang rule. - * This is of the form: - * - * overhang layers2 layers1 dist why - * - * indicating that layers2 must overhang layers1 by a distance of at least - * dist. - * - * This rule is equivalent to: - * - * edge4way layers1 space/p2|layers2 dist layers1|layers2 \ - * space/p2|layers2 dist why - * - * ---------------------------------------------------------------------------- - */ - -int -drcOverhang(argc, argv) - int argc; - char *argv[]; -{ - char *layers2 = argv[1], *layers1 = argv[2]; - int distance = atoi(argv[3]); - int why = drcWhyCreate(argv[4]); - TileTypeBitMask set1, set2, setM, setC, setN, set2inv; - DRCCookie *dp, *dpnew, *dptrig; - int plane, plane2; - TileType i, j; - PlaneMask pMask1, pMask2, pset, ptest; - - ptest = DBTechNoisyNameMask(layers1, &set1); - pMask1 = CoincidentPlanes(&set1, ptest); - if (pMask1 == 0) - { - TechError("All layers in first set for \"overhang\" must be on " - "the same plane\n"); - return (0); - } - TTMaskCom2(&setN, &set1); - - ptest = DBTechNoisyNameMask(layers2, &set2); - pMask2 = CoincidentPlanes(&set2, ptest); - if (pMask2 == 0) - { - TechError("All layers in second set for \"overhang\" must be on " - "the same plane\n"); - return (0); - } - TTMaskCom2(&set2inv, &set2); - - /* Warn if types1 and types2 intersect */ - if (TTMaskIntersect(&set1, &set2)) - TechError("Warning: inside and outside types have nonempty intersection. " - "DRC does not check edges with the same type on both sides.\n"); - - /* SetM is the union of set1 and set2 */ - TTMaskZero(&setM); - TTMaskSetMask3(&setM, &set1, &set2); - - /* Add space to set2 */ - TTMaskSetType(&set2, TT_SPACE); - - /* SetC is the empty set */ - TTMaskZero(&setC); - - for (i = 0; i < DBNumTypes; i++) - { - for (j = 0; j < DBNumTypes; j++) - { - if (i == j) continue; - if (pset = (DBTypesOnSamePlane(i, j) & pMask2)) - { - if ((pset & pMask1) != 0) - { - if (TTMaskHasType(&set1, i) && TTMaskHasType(&set2, j)) - { - plane = LowestMaskBit(pset); - - /* Find bucket preceding the new one we wish to insert */ - dp = drcFindBucket(i, j, distance); - dpnew = (DRCCookie *)mallocMagic (sizeof (DRCCookie)); - drcAssign(dpnew, distance, dp->drcc_next, &setM, - &setM, why, distance, - DRC_FORWARD | DRC_BOTHCORNERS, - plane, plane); - dp->drcc_next = dpnew; - - /* find bucket preceding new one we wish to insert */ - dp = drcFindBucket(j, i, distance); - dpnew = (DRCCookie *)mallocMagic(sizeof (DRCCookie)); - drcAssign(dpnew, distance, dp->drcc_next, - &setM, &setM, why, distance, - DRC_REVERSE | DRC_BOTHCORNERS, - plane, plane); - dp->drcc_next = dpnew; - } - } - else /* Multi-plane overhang rule */ - { - if (TTMaskHasType(&set2, i) && TTMaskHasType(&set2inv, j)) - { - plane = LowestMaskBit(pset); - plane2 = LowestMaskBit(pMask1); - - /* find bucket preceding the new one we wish to insert */ - dp = drcFindBucket(i, j, distance); - dpnew = (DRCCookie *)mallocMagic(sizeof(DRCCookie)); - drcAssign(dpnew, distance, dp->drcc_next, &set1, &set1, why, - distance, DRC_FORWARD, plane2, plane); - dptrig = (DRCCookie *)mallocMagic(sizeof(DRCCookie)); - drcAssign(dptrig, 1, dpnew, &setN, &setC, why, - 0, DRC_FORWARD | DRC_TRIGGER, plane2, plane); - dp->drcc_next = dptrig; - - dp = drcFindBucket(j, i, distance); - dpnew = (DRCCookie *)mallocMagic(sizeof(DRCCookie)); - drcAssign(dpnew, distance, dp->drcc_next, &set1, &set1, why, - distance, DRC_REVERSE, plane2, plane); - dptrig = (DRCCookie *)mallocMagic(sizeof(DRCCookie)); - drcAssign(dptrig, 1, dpnew, &setN, &setC, why, - 0, DRC_REVERSE | DRC_TRIGGER, plane2, plane); - dp->drcc_next = dptrig; - } - } - } - } - } - return distance; -} - -/* - * ---------------------------------------------------------------------------- - * - * drcRectOnly -- - * - * Process a rectangle-only rule. This rule prohibits non-rectangular - * geometry, and is used especially for contacts, as the "squares" operator - * in the CIF/GDS output generator can't handle non-rectangular areas. - * The rule is of the form: - * - * rect_only layers why - * - * and is equivalent to: - * - * edge4way layers ~(layers)/plane 1 ~(layers)/plane (all_layers)/plane 1 - * - * The rect_only rule avoids the above contrived construction, especially the - * requirement of specifying "all_layers" as something like (~(x),x)/p, a sure- - * fire obfuscation. - * - * ---------------------------------------------------------------------------- - */ - -int -drcRectOnly(argc, argv) - int argc; - char *argv[]; -{ - char *layers = argv[1]; - int why = drcWhyCreate(argv[2]); - TileTypeBitMask set1, set2, setC; - PlaneMask pmask, pset, ptest; - DRCCookie *dp, *dpnew; - int plane; - TileType i, j; - - ptest = DBTechNoisyNameMask(layers, &set1); - pmask = CoincidentPlanes(&set1, ptest); - - if (pmask == 0) - { - TechError("All types for \"rect_only\" must be on the same plane.\n"); - return (0); - } - - /* set2 is the inverse of set1 */ - TTMaskCom2(&set2, &set1); - - for (i = 0; i < DBNumTypes; i++) - { - for (j = 0; j < DBNumTypes; j++) - { - if (i == j) continue; - - if (pset = (DBTypesOnSamePlane(i, j) & pmask)) - { - if (TTMaskHasType(&set1, i) && TTMaskHasType(&set2, j)) - { - plane = LowestMaskBit(pset); - /* setC = all types in plane */ - TTMaskZero(&setC); - TTMaskSetMask(&setC, &DBPlaneTypes[plane]); - - /* Find bucket preceding the new one we wish to insert */ - dp = drcFindBucket(i, j, 1); - dpnew = (DRCCookie *)mallocMagic(sizeof (DRCCookie)); - drcAssign(dpnew, 1, dp->drcc_next, &set2, &setC, why, 1, - DRC_FORWARD | DRC_BOTHCORNERS, plane, plane); - dp->drcc_next = dpnew; - - /* find bucket preceding new one we wish to insert */ - dp = drcFindBucket(j, i, 1); - dpnew = (DRCCookie *)mallocMagic(sizeof (DRCCookie)); - drcAssign(dpnew,1,dp->drcc_next, &set2, &setC, why, 1, - DRC_REVERSE | DRC_BOTHCORNERS, plane, plane); - dp->drcc_next = dpnew; - } - } - } - } - return 1; -} - -/* - * ---------------------------------------------------------------------------- - * - * drcSurround -- - * - * Process a surround rule. - * This is of the form: - * - * surround layers1 layers2 dist presence why - * - * indicating that layers2 must surround layers1 by at least distance - * dist in all directions. - * - * This rule is equivalent to: - * - * edge4way ~(layers2)/plane2 layers2 dist ~(layers1)/plane1 \ - * layers2 dist why - * - * When presence=absence_illegal, the following additional rule is needed: - * - * edge4way layers1 ~(layers2)/plane1 dist NULL ~(layers2)/plane1 \ - * dist why - * - * Extension added July 12, 2014: For via rules where an asymmetric - * surround is allowed, with a smaller surround allowed on two sides if - * the remaining two sides have a larger surround. This can be implemented - * with a trigger rule, and is specified by the syntax above with "presence" - * being "directional". Note that the rule expresses that the overhang rule - * requires the presence of the material on one side of a corner. If the - * other side has a non-zero minimum surround requirement, then it should - * be implemented with an additional (absence_illegal) surround rule. - * Otherwise, any width of material less than "dist" on one side of a - * corner will trigger the rule requiring at least "dist" width of the same - * material on the other side of the corner. - * - * ---------------------------------------------------------------------------- - */ - -int -drcSurround(argc, argv) - int argc; - char *argv[]; -{ - char *layers1 = argv[1], *layers2 = argv[2]; - int distance = atoi(argv[3]); - char *presence = argv[4]; - int why = drcWhyCreate(argv[5]); - TileTypeBitMask set1, set2, setM, invM, setR; - DRCCookie *dp, *dpnew, *dptrig; - int plane1, plane2; - PlaneMask pmask, pmask2, pset, ptest; - TileType i, j; - bool isExact = FALSE; - bool isDirectional = FALSE; - - ptest = DBTechNoisyNameMask(layers1, &setM); - pmask = CoincidentPlanes(&setM, ptest); - if (pmask == 0) - { - TechError("Inside types in \"surround\" must be on the same plane\n"); - return (0); - } - - ptest = DBTechNoisyNameMask(layers2, &set2); - pmask2 = CoincidentPlanes(&set2, ptest); - if (pmask2 == 0) - { - TechError("Outside types in \"surround\" must be on the same plane\n"); - return (0); - } - - /* "exact_width" rule implemented 9/16/10. This enforces an exact */ - /* surround distance. "absence_illegal" is implied. */ - - if (!strncmp(presence, "exact_", 6)) isExact = TRUE; - else if (!strncmp(presence, "directional", 11)) - { - isDirectional = TRUE; - /* Combined mask */ - TTMaskZero(&setR); - TTMaskSetMask(&setR, &setM); - TTMaskSetMask(&setR, &set2); - } - - /* invert setM */ - TTMaskCom2(&invM, &setM); - - /* set1 is the inverse of set2 */ - TTMaskCom2(&set1, &set2); - - for (i = 0; i < DBNumTypes; i++) - { - for (j = 0; j < DBNumTypes; j++) - { - if (i == j) continue; /* Ignore false edges */ - if (pset = (DBTypesOnSamePlane(i, j) & pmask2)) - { - if (isDirectional) - { - /* Directional surround is done entirely differently */ - - if (TTMaskHasType(&setM, i) && TTMaskHasType(&invM, j)) - { - plane1 = LowestMaskBit(pmask); - plane2 = LowestMaskBit(pset); - - /* Find bucket preceding the new one we wish to insert */ - dp = drcFindBucket(i, j, distance); - dpnew = (DRCCookie *)mallocMagic(sizeof(DRCCookie)); - - /* Insert triggered rule */ - drcAssign(dpnew, distance, dp->drcc_next, &setR, - &DBAllTypeBits, - why, distance, - DRC_REVERSE | DRC_BOTHCORNERS, - plane1, plane2); - dptrig = (DRCCookie *)mallocMagic(sizeof(DRCCookie)); - drcAssign(dptrig, distance, dpnew, &set2, - &DBZeroTypeBits, why, 0, - DRC_FORWARD | DRC_TRIGGER, - plane1, plane2); - dp->drcc_next = dptrig; - - /* And the other direction. . . */ - dp = drcFindBucket(j, i, distance); - dpnew = (DRCCookie *)mallocMagic(sizeof(DRCCookie)); - - /* Insert triggered rule */ - drcAssign(dpnew, distance, dp->drcc_next, &setR, - &DBAllTypeBits, - why, distance, - DRC_FORWARD | DRC_BOTHCORNERS, - plane1, plane2); - dptrig = (DRCCookie *)mallocMagic(sizeof(DRCCookie)); - drcAssign(dptrig, distance, dpnew, &set2, - &DBZeroTypeBits, why, 0, - DRC_REVERSE | DRC_TRIGGER, - plane1, plane2); - dp->drcc_next = dptrig; - } - } - else - { - if (TTMaskHasType(&set1, i) && TTMaskHasType(&set2, j)) - { - plane1 = LowestMaskBit(pmask); - plane2 = LowestMaskBit(pset); - - /* Find bucket preceding the new one we wish to insert */ - dp = drcFindBucket(i, j, distance); - dpnew = (DRCCookie *)mallocMagic(sizeof(DRCCookie)); - drcAssign(dpnew, distance, dp->drcc_next, &invM, &set2, - why, distance, - DRC_FORWARD | DRC_BOTHCORNERS, - plane1, plane2); - dp->drcc_next = dpnew; - - /* find bucket preceding new one we wish to insert */ - dp = drcFindBucket(j, i, distance); - dpnew = (DRCCookie *)mallocMagic(sizeof(DRCCookie)); - drcAssign(dpnew, distance, dp->drcc_next, &invM, &set2, - why, distance, - DRC_REVERSE | DRC_BOTHCORNERS, - plane1, plane2); - dp->drcc_next = dpnew; - } - } - } - } - } - - if (isExact) - { - for (i = 0; i < DBNumTypes; i++) - { - for (j = 0; j < DBNumTypes; j++) - { - if (i == j) continue; /* Ignore false edges */ - if (pset = (DBTypesOnSamePlane(i, j) & pmask)) - { - if (TTMaskHasType(&setM, i) && TTMaskHasType(&set2, j)) - { - plane1 = LowestMaskBit(pset); - - /* Find bucket preceding the new one we wish to insert */ - dp = drcFindBucket(i, j, distance); - dpnew = (DRCCookie *)mallocMagic(sizeof(DRCCookie)); - drcAssign(dpnew, distance, dp->drcc_next, &set1, &set2, - why, distance, - DRC_FORWARD | DRC_BOTHCORNERS | DRC_OUTSIDE, - plane1, plane1); - dp->drcc_next = dpnew; - - /* find bucket preceding new one we wish to insert */ - dp = drcFindBucket(j, i, distance); - dpnew = (DRCCookie *)mallocMagic(sizeof(DRCCookie)); - drcAssign(dpnew, distance, dp->drcc_next, &set1, &set2, - why, distance, - DRC_REVERSE | DRC_BOTHCORNERS | DRC_OUTSIDE, - plane1, plane1); - dp->drcc_next = dpnew; - } - } - } - } - } - - if ((!isExact) && strcmp(presence, "absence_illegal")) return distance; - - /* Add an extra rule when presence of the surrounding */ - /* layer is required. Rule is different if planes match. */ - - if (pset = pmask & pmask2) - { - TTMaskZero(&invM); - TTMaskSetMask(&invM, &setM); - TTMaskSetMask(&invM, &set2); - TTMaskCom(&invM); - TTMaskZero(&set1); - - for (i = 0; i < DBNumTypes; i++) - for (j = 0; j < DBNumTypes; j++) - { - if (i == j) continue; - if (pset = (DBTypesOnSamePlane(i, j) & pmask & pmask2)) - { - plane1 = LowestMaskBit(pset); - if (TTMaskHasType(&setM, i) && TTMaskHasType(&invM, j)) - { - /* Find bucket preceding the new one we wish to insert */ - dp = drcFindBucket(i, j, distance); - dpnew = (DRCCookie *) mallocMagic((unsigned) - (sizeof (DRCCookie))); - drcAssign(dpnew, distance, dp->drcc_next, - &set1, &invM, why, distance, - DRC_FORWARD | DRC_BOTHCORNERS, - plane1, plane1); - dp->drcc_next = dpnew; - - /* find bucket preceding new one we wish to insert */ - dp = drcFindBucket(j, i, distance); - dpnew = (DRCCookie *) mallocMagic((unsigned) - (sizeof (DRCCookie))); - drcAssign(dpnew,distance,dp->drcc_next, - &set1, &invM, why, distance, - DRC_REVERSE | DRC_BOTHCORNERS, - plane1, plane1); - dp->drcc_next = dpnew; - } - } - } - } - else - { - for (i = 0; i < DBNumTypes; i++) - for (j = 0; j < DBNumTypes; j++) - { - if (i == j) continue; - if (pset = (DBTypesOnSamePlane(i, j) & pmask)) - { - if (TTMaskHasType(&setM, i) && TTMaskHasType(&invM, j)) - { - plane1 = LowestMaskBit(pset); - plane2 = LowestMaskBit(pmask2); - - /* Find bucket preceding the new one we wish to insert */ - dp = drcFindBucket(i, j, distance); - dpnew = (DRCCookie *) mallocMagic((unsigned) - (sizeof (DRCCookie))); - drcAssign(dpnew, distance, dp->drcc_next, - &set2, &invM, why, distance, - DRC_FORWARD | DRC_BOTHCORNERS, - plane2, plane1); - dp->drcc_next = dpnew; - - /* find bucket preceding new one we wish to insert */ - dp = drcFindBucket(j, i, distance); - dpnew = (DRCCookie *) mallocMagic((unsigned) - (sizeof (DRCCookie))); - drcAssign(dpnew,distance,dp->drcc_next, - &set2, &invM, why, distance, - DRC_REVERSE | DRC_BOTHCORNERS, - plane2, plane1); - dp->drcc_next = dpnew; - } - } - } - } - - return distance; -} - -/* - * ---------------------------------------------------------------------------- - * - * drcNoOverlap -- - * - * Process a no-overlap rule. - * This is of the form: - * - * no_overlap layers1 layers2 - * - * e.g, - * - * no_overlap poly m2contact - * - * Results: - * Returns 0. - * - * Side effects: - * Updates the DRC technology variables. - * - * ---------------------------------------------------------------------------- - */ - -int -drcNoOverlap(argc, argv) - int argc; - char *argv[]; -{ - char *layers1 = argv[1], *layers2 = argv[2]; - TileTypeBitMask set1, set2; - TileType i, j; - int plane; - - /* - * Grab up two sets of tile types, and make sure that if - * any type from one set is painted over any type from the - * other, then an error results. - */ - - DBTechNoisyNameMask(layers1, &set1); - DBTechNoisyNameMask(layers2, &set2); - - for (i = 0; i < DBNumTypes; i++) - for (j = 0; j < DBNumTypes; j++) - if (TTMaskHasType(&set1, i) && TTMaskHasType(&set2, j)) - for (plane = 0; plane < DBNumPlanes; plane++) - { - DRCCurStyle->DRCPaintTable[plane][j][i] = TT_ERROR_S; - DRCCurStyle->DRCPaintTable[plane][i][j] = TT_ERROR_S; - } - - return (0); -} - -/* - * ---------------------------------------------------------------------------- - * - * drcExactOverlap -- - * - * Process an exact overlap - * This is of the form: - * - * exact_overlap layers - * - * e.g, - * - * exact_overlap pmc,dmc - * - * Results: - * Returns 0. - * - * Side effects: - * Updates DRCExactOverlapTypes. - * - * ---------------------------------------------------------------------------- - */ - -int -drcExactOverlap(argc, argv) - int argc; - char *argv[]; -{ - char *layers = argv[1]; - TileTypeBitMask set; - - /* - * Grab up a bunch of tile types, and remember these: tiles - * of these types cannot overlap themselves in different cells - * unless they overlap exactly. - */ - - DBTechNoisyNameMask(layers, &set); - TTMaskSetMask(&DRCCurStyle->DRCExactOverlapTypes, &set); - return (0); -} - -/* - * ---------------------------------------------------------------------------- - * - * drcRectangle -- - * - * Process a rectangle rule. This is of the form: - * - * rectangle layers maxwidth [even|odd|any] why - * - * The rule checks to make sure that the region is rectangular and that the - * width and length are even or odd, as specified. These two criteria ensure - * that the squares rule of the cifout section can properly produce via - * holes without misaligning them between cells and without putting the via - * holes off grid. The maxwidth is required to make the extent of this rule - * a finite size, so that we can set the DRChalo to something finite. - * - * Results: - * maxwidth - * - * Side effects: - * Updates the DRC technology variables. - * - * ---------------------------------------------------------------------------- - */ - -int -drcRectangle(argc, argv) - int argc; - char *argv[]; -{ - char *layers = argv[1]; - int why = drcWhyCreate(argv[4]); - TileTypeBitMask types, nottypes; - int maxwidth; - static char *drcRectOpt[4] = {"any", "even", "odd", 0}; - int i, j, even, plane; - PlaneMask pMask, pset, ptest; - - /* parse arguments */ - ptest = DBTechNoisyNameMask(layers, &types); - pMask = CoincidentPlanes(&types, ptest); - - if (pMask == 0) { - TechError("Layers in rectangle rule must lie in a single plane."); - return 0; - } - TTMaskCom2(¬types, &types); - - if (sscanf(argv[2], "%d", &maxwidth) != 1) { - TechError("bad maxwidth in rectangle rule"); - return 0; - } - even = Lookup(argv[3], drcRectOpt); - if (even < 0) { - TechError("bad [even|odd|any] selection in rectangle rule"); - return 0; - } - even--; /* -1: any, 0: even, 1: odd */ - - /* Install 2 edge rules: one that checks rectangle-ness, and one that - * checks size - */ - for (i = 0; i < DBNumTypes; i++) - { - for (j = 0; j < DBNumTypes; j++) - { - if (i == j) continue; - - if (pset = (DBTypesOnSamePlane(i, j) & pMask)) - { - if (TTMaskHasType(&types, i) && TTMaskHasType(¬types, j)) - { - DRCCookie *dp, *dpnew; - - plane = LowestMaskBit(pset); - - /* - * A rule that checks rectangle-ness. - * left: oktypes, right: other types - * This rule needs to be checked in all 4 directions - */ - int distance = 1; - - /* Find bucket preceding the new one we wish to insert */ - dp = drcFindBucket(i, j, distance); - dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie))); - drcAssign(dpnew, distance, dp->drcc_next, - ¬types, &DBAllTypeBits, why, distance, - DRC_FORWARD, plane, plane); - dp->drcc_next = dpnew; - - /* Find bucket preceding the new one we wish to insert */ - dp = drcFindBucket(j, i, distance); /* note: j, i not i, j */ - dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie))); - drcAssign(dpnew, distance, dp->drcc_next, - ¬types, &DBAllTypeBits, why, distance, - DRC_REVERSE, plane, plane); - dp->drcc_next = dpnew; - - if (maxwidth > 0) { - /* - * A rule that checks size. - * left: other types, right: oktypes - */ - distance = maxwidth; - - /* note: j, i not i, j */ - for (dp = DRCCurStyle->DRCRulesTbl[j][i]; - dp->drcc_next != (DRCCookie *) NULL && - dp->drcc_next->drcc_dist < distance; - dp = dp->drcc_next); /* null body */ - - dpnew = (DRCCookie *)mallocMagic(sizeof (DRCCookie)); - drcAssign(dpnew, distance, dp->drcc_next, - &types, &DBZeroTypeBits, why, even, - DRC_RECTSIZE, plane, plane); - dp->drcc_next = dpnew; - } - } - } - } - } - return maxwidth; -} - -/* - * ---------------------------------------------------------------------------- - * - * drcOption -- - * - * Process an option declaration - * This is of the form: - * - * option option_name [...] - * - * e.g, - * - * option wide-width-inclusive - * - * Results: - * Returns 0. - * - * Side effects: - * Updates DRCFlags. - * - * ---------------------------------------------------------------------------- - */ - -int -drcOption(argc, argv) - int argc; - char *argv[]; -{ - int i; - - if (DRCCurStyle == NULL) return 0; - - /* Assume space-separated list of options. Flag an error on any */ - /* option name not recognized. */ - - for (i = 1; i < argc; i++) - { - if (!strcmp(argv[i], "wide-width-noninclusive")) - DRCCurStyle->DRCFlags |= DRC_FLAGS_WIDEWIDTH_NONINCLUSIVE; - else - { - TechError("Unrecognized DRC option \"%s\" (ignored).\n", argv[i]); - } - } - return (0); -} - -/* - * ---------------------------------------------------------------------------- - * - * drcStepSize -- - * - * Process a declaration of the step size. - * This is of the form: - * - * stepsize step_size - * - * e.g, - * - * stepsize 1000 - * - * Results: - * Returns 0. - * - * Side effects: - * Updates DRCStepSize. - * - * ---------------------------------------------------------------------------- - */ - -int -drcStepSize(argc, argv) - int argc; - char *argv[]; -{ - if (DRCCurStyle == NULL) return 0; - - DRCCurStyle->DRCStepSize = atoi(argv[1]); - if (DRCCurStyle->DRCStepSize <= 0) - { - TechError("Step size must be a positive integer.\n"); - DRCCurStyle->DRCStepSize = 0; - } - else if (DRCCurStyle->DRCStepSize < 16) - { - TechError("Warning: abnormally small DRC step size (%d)\n", - DRCCurStyle->DRCStepSize); - } - - return (0); -} - -/* - * ---------------------------------------------------------------------------- - * - * DRCTechFinal -- - * - * Called after all lines of the drc section in the technology file have been - * read. Ensures that a valid style is in effect, and then calls - * drcTechFinalStyle(). - * - * Results: - * None. - * - * Side effects: - * See drcTechFinalStyle(); - * - * ---------------------------------------------------------------------------- - */ - -void -DRCTechFinal() -{ - DRCStyle *ds; - - /* Create a "default" style if there isn't one */ - - if (DRCStyleList == NULL) - { - DRCStyleList = (DRCKeep *)mallocMagic(sizeof(DRCKeep)); - DRCStyleList->ds_next = NULL; - DRCStyleList->ds_name = StrDup((char **)NULL, "default"); - - drcTechNewStyle(); - DRCCurStyle->ds_name = DRCStyleList->ds_name; - DRCCurStyle->ds_status = TECH_LOADED; - } - drcTechFinalStyle(DRCCurStyle); -} - -/* - * ---------------------------------------------------------------------------- - * drcScaleDown --- - * - * DRC distances may be specified with a scale factor so that physically - * based rules can be recorded, but the rules used will be rounded (up) - * to the nearest lambda. The fractional part of the true distance in - * lambda is saved, so that the original value can be recovered when - * the magic grid is rescaled. - * - * Results: - * None. - * - * Side Effects: - * Scales all the DRC distances by dividing by the DRC scale factor. - * ---------------------------------------------------------------------------- - */ - -void -drcScaleDown(style, scalefactor) - DRCStyle *style; - int scalefactor; -{ - TileType i, j; - DRCCookie *dp; - int dist; - - if (scalefactor > 1) - { - for (i = 0; i < TT_MAXTYPES; i++) - for (j = 0; j < TT_MAXTYPES; j++) - for (dp = style->DRCRulesTbl[i][j]; dp != NULL; dp = dp->drcc_next) - { - if (dp->drcc_dist > 0) - { - dist = dp->drcc_dist; - dp->drcc_dist /= scalefactor; - if ((dp->drcc_mod = (unsigned char)(dist % scalefactor)) != 0) - if (!(dp->drcc_flags & DRC_MAXWIDTH)) - dp->drcc_dist++; - } - if (dp->drcc_cdist > 0) - { - int locscale = scalefactor; - if (dp->drcc_flags & DRC_AREA) - locscale *= scalefactor; - - dist = dp->drcc_cdist; - dp->drcc_cdist /= locscale; - if ((dp->drcc_cmod = (unsigned char)(dist % locscale)) != 0) - dp->drcc_cdist++; - } - } - } -} - -/* - * ---------------------------------------------------------------------------- - * drcScaleUp --- - * - * Recovers the original (pre-scaled) values for drcc_dist and - * drcc_cdist in the DRC cookies. - * - * Results: - * None. - * - * Side Effects: - * Scales all the DRC distances by multiplying by the DRC scale factor. - * ---------------------------------------------------------------------------- - */ - -void -drcScaleUp(style, scalefactor) - DRCStyle *style; - int scalefactor; -{ - TileType i, j; - DRCCookie *dp; - int dist; - - if (style == NULL) return; - - if (scalefactor > 1) - { - for (i = 0; i < TT_MAXTYPES; i++) - for (j = 0; j < TT_MAXTYPES; j++) - for (dp = style->DRCRulesTbl[i][j]; dp != NULL; dp = dp->drcc_next) - { - if (dp->drcc_dist > 0) - { - dist = dp->drcc_dist; - if (dp->drcc_mod != 0) - if (!(dp->drcc_flags & DRC_MAXWIDTH)) - dp->drcc_dist--; - dp->drcc_dist *= scalefactor; - dp->drcc_dist += (short)dp->drcc_mod; - dp->drcc_mod = 0; - } - if (dp->drcc_cdist > 0) - { - dist = dp->drcc_cdist; - if (dp->drcc_cmod != 0) - dp->drcc_cdist--; - dp->drcc_cdist *= scalefactor; - if (dp->drcc_flags & DRC_AREA) - dp->drcc_cdist *= scalefactor; - dp->drcc_cdist += (short)dp->drcc_cmod; - dp->drcc_cmod = 0; - } - } - } -} - -/* - * ---------------------------------------------------------------------------- - * - * drcTechFinalStyle -- - * - * Called after all lines of the drc section in the technology file have been - * read. The preliminary DRC Rules Table is pruned by removing rules covered - * by other (longer distance) rules, and by removing the dummy rule at the - * front of each list. Where edges are completely illegal, the rule list is - * pruned to a single rule. - * - * Results: - * None. - * - * Side effects: - * May remove DRCCookies from the linked lists of the DRCRulesTbl. - * - * ---------------------------------------------------------------------------- - */ - -void -drcTechFinalStyle(style) - DRCStyle *style; -{ - TileTypeBitMask tmpMask, nextMask; - DRCCookie *dummy, *dp, *next, *dptrig; - DRCCookie **dpp, **dp2back; - TileType i, j; - - /* Done with DRCWhyErrorTable */ - HashKill(&DRCWhyErrorTable); - - /* If the scale factor is not 1, then divide all distances by */ - /* the scale factor, take the ceiling, and save the (negative) */ - /* remainder. */ - - drcScaleUp(style, style->DRCScaleFactorD); - drcScaleDown(style, style->DRCScaleFactorN); - - /* Scale DRCTechHalo to match */ - DRCTechHalo *= style->DRCScaleFactorD; - DRCTechHalo /= style->DRCScaleFactorN; - - /* Set maximum halo */ - style->DRCTechHalo = DRCTechHalo; - - /* A reasonable chunk size for design-rule checking is about - * 16 times the maximum design-rule interaction distance. This - * results in a halo overhead of about 27%. If there's no DRC - * information at all (TechHalo is zero), just pick any size. - * (Update 1/13/09: "any size" needs a bit of modification, - * because 64 will be way too small for a layout with a small - * scalefactor. Assuming that the CIF output style is valid, - * use its scalefactor to adjust the step size). - */ - if (style->DRCStepSize == 0) - { - if (style->DRCTechHalo == 0) - { - if (CIFCurStyle != NULL) - style->DRCStepSize = 6400 / CIFCurStyle->cs_scaleFactor; - else - style->DRCStepSize = 64; - } - else - style->DRCStepSize = 16 * style->DRCTechHalo; - } - DRCStepSize = style->DRCStepSize; - - /* Remove dummy buckets */ - for (i = 0; i < TT_MAXTYPES; i++) - { - for (j = 0; j < TT_MAXTYPES; j++) - { - dpp = &(style->DRCRulesTbl [i][j]); - dummy = *dpp; - *dpp = dummy->drcc_next; - freeMagic((char *) dummy); - } - } - drcCifFinal(); - - if (!DRCRuleOptimization) return; - - /* Check for edges that are completely illegal. Where this is the - * case, eliminate all of the edge's rules except one. - */ - - for (i = 0; i < DBNumTypes; i++) - { - for (j = 0; j < DBNumTypes; j++) - { - DRCCookie *keep = NULL, *dptest, *dptemp, *dpnew; - - for (dp = style->DRCRulesTbl[i][j]; dp != NULL; dp = dp->drcc_next) - { - if (dp->drcc_flags & (DRC_NONSTANDARD || DRC_OUTSIDE)) continue; - if (dp->drcc_flags & DRC_REVERSE) - { - if ((i == TT_SPACE) || TTMaskHasType(&dp->drcc_mask, i)) continue; - } - else - { - if ((j == TT_SPACE) || TTMaskHasType(&dp->drcc_mask, j)) continue; - } - - /* Rules where okTypes are in a different plane don't count, */ - /* unless i or j also appear in the checked plane. */ - - if (dp->drcc_plane != dp->drcc_edgeplane) - { - if (dp->drcc_flags & DRC_REVERSE) - { - if ((i == TT_SPACE) || !DBTypeOnPlane(i, dp->drcc_plane)) - continue; - } - else - { - if ((j == TT_SPACE) || !DBTypeOnPlane(j, dp->drcc_plane)) - continue; - } - } - - // if (DBIsContact(i) || DBIsContact(j) || i == TT_SPACE || - // j == TT_SPACE) continue; - - dpnew = NULL; - keep = dp; - - /* This edge is illegal. Throw away all rules except the one - * needed that is always violated. - */ - - dptest = style->DRCRulesTbl[i][j]; - while (dptest != NULL) - { - dptemp = dptest->drcc_next; - if ((dptest == keep) || (dptest->drcc_edgeplane != - keep->drcc_edgeplane)) - { - dptest->drcc_next = NULL; - if (dpnew == NULL) - style->DRCRulesTbl[i][j] = dptest; - else - dpnew->drcc_next = dptest; - dpnew = dptest; - - /* "keep" can't be a trigger rule! */ - if (dptest == keep) - keep->drcc_flags &= ~DRC_TRIGGER; - } - else - { - freeMagic((char *)dptest); - drcRulesOptimized++; - } - dptest = dptemp; - } - } - - /* TxPrintf("Edge %s-%s is illegal.\n", DBTypeShortName(i), - DBTypeShortName(j)); - */ - } - } - - /* - * Remove any rule A "covered" by another rule B, i.e., - * B's distance >= A's distance, - * B's corner distance >= A's corner distance, - * B's RHS type mask is a subset of A's RHS type mask, and - * B's corner mask == A's corner mask - * B's check plane == A's check plane - * either both A and B or neither is a REVERSE direction rule - * if A is BOTHCORNERS then B must be, too - */ - - for (i = 0; i < DBNumTypes; i++) - { - for (j = 0; j < DBNumTypes; j++) - { - for (dp = style->DRCRulesTbl[i][j]; dp != NULL; dp = dp->drcc_next) - { - /* Don't optimize on trigger rules; optimize on the */ - /* rule that gets triggered. */ - if (dp->drcc_flags & DRC_TRIGGER) - { - dptrig = dp; - dp = dp->drcc_next; - } - else - dptrig = NULL; - - /* - * Check following buckets to see if any is a superset. - */ - if (dp->drcc_flags & DRC_NONSTANDARD) continue; - for (next = dp->drcc_next; next != NULL; - next = next->drcc_next) - { - if (next->drcc_flags & DRC_TRIGGER) - { - /* A triggered rule cannot be considered */ - /* a superset of a non-triggered rule or */ - /* a rule with a different trigger, so */ - /* we skip all triggered rules and their */ - /* triggering rule. */ - next = next->drcc_next; - continue; - } - tmpMask = nextMask = next->drcc_mask; - TTMaskAndMask(&tmpMask, &dp->drcc_mask); - if (!TTMaskEqual(&tmpMask, &nextMask)) continue; - if (!TTMaskEqual(&dp->drcc_corner, &next->drcc_corner)) - continue; - if (dp->drcc_dist > next->drcc_dist) continue; - if (dp->drcc_cdist > next->drcc_cdist) continue; - if (dp->drcc_plane != next->drcc_plane) continue; - if (dp->drcc_flags & DRC_REVERSE) - { - if (!(next->drcc_flags & DRC_REVERSE)) continue; - } - else if (next->drcc_flags & DRC_REVERSE) continue; - if ((next->drcc_flags & DRC_BOTHCORNERS) - && (dp->drcc_flags & DRC_BOTHCORNERS) == 0) - continue; - if (next->drcc_flags & DRC_NONSTANDARD) continue; - if (dp->drcc_dist == next->drcc_dist) - { - if ((next->drcc_flags & DRC_OUTSIDE) && - !(dp->drcc_flags & DRC_OUTSIDE)) continue; - if (!(next->drcc_flags & DRC_OUTSIDE) && - (dp->drcc_flags & DRC_OUTSIDE)) continue; - } - break; - } - - if (next == NULL) continue; - - /* "dp" is a subset of "next". Eliminate it. */ - - /* For triggered rules, eliminate both the rule */ - /* and the trigger. */ - if (dptrig != NULL) dp = dptrig; - - /* TxPrintf("For edge %s-%s, \"%s\" covers \"%s\"\n", - DBTypeShortName(i), DBTypeShortName(j), - DRCCurStyle->DRCWhyList[next->drcc_tag], - DRCCurStyle->DRCWhyList[dp->drcc_tag]); - */ - dp2back = &(style->DRCRulesTbl[i][j]); - while (*dp2back != dp) - dp2back = &(*dp2back)->drcc_next; - - /* Trigger rules */ - if (dptrig != NULL) - { - dptrig = dp->drcc_next; - freeMagic((char *)dp->drcc_next); - *dp2back = dp->drcc_next->drcc_next; - - /* Replace this entry so on the next cycle */ - /* dp will be the next rule. This works */ - /* even though dp is free'd (below), due to */ - /* the one-delayed free mechanism. */ - dp->drcc_next = *dp2back; - } - else - *dp2back = dp->drcc_next; - - freeMagic((char *) dp); - drcRulesOptimized += 1; - } - } - } -} - - -/* - * ---------------------------------------------------------------------------- - * - * DRCTechRuleStats -- - * - * Print out some statistics about the design rule database. - * - * Results: - * None. - * - * Side effects: - * A bunch of stuff gets printed on the terminal. - * - * ---------------------------------------------------------------------------- - */ - -#define MAXBIN 10 - -void -DRCTechRuleStats() -{ - int counts[MAXBIN+1]; - int edgeRules, overflow; - int i, j; - DRCCookie *dp; - - /* Count up the total number of edge rules, and histogram them - * by the number of rules per edge. - */ - - edgeRules = 0; - overflow = 0; - for (i=0; i<=MAXBIN; i++) counts[i] = 0; - - for (i=0; iDRCRulesTbl[i][j]; dp != NULL; dp = dp->drcc_next) - thisCount++; - edgeRules += thisCount; - if (!DBTypesOnSamePlane(i, j)) continue; - if (thisCount <= MAXBIN) counts[thisCount] += 1; - else overflow += 1; - } - - /* Print out the results. */ - - TxPrintf("Total number of rules specifed in tech file: %d\n", - drcRulesSpecified); - TxPrintf("Edge rules optimized away: %d\n", drcRulesOptimized); - TxPrintf("Edge rules left in database: %d\n", edgeRules); - TxPrintf("Histogram of # edges vs. rules per edge:\n"); - for (i=0; i<=MAXBIN; i++) - { - TxPrintf(" %2d rules/edge: %d.\n", i, counts[i]); - } - TxPrintf(" >%2d rules/edge: %d.\n", MAXBIN, overflow); -} - -/* - * ---------------------------------------------------------------------------- - * - * DRCTechScale -- - * - * Multiply all DRC rule widths and spacings by a factor of scaled/scalen. - * (Don't need to use DBScaleValue() because all values must be positive - * and cannot be (M)INFINITY.) - * - * ---------------------------------------------------------------------------- - */ - -void -DRCTechScale(scalen, scaled) - int scalen, scaled; -{ - DRCCookie *dp; - TileType i, j; - int scalegcf; - - if (DRCCurStyle == NULL) return; - else if (scalen == scaled == 1) return; - - /* Revert DRC rules to original (unscaled) values */ - drcScaleUp(DRCCurStyle, DRCCurStyle->DRCScaleFactorN); - drcScaleDown(DRCCurStyle, DRCCurStyle->DRCScaleFactorD); - - /* Do the same for the plow rules */ - DRCPlowScale(DRCCurStyle->DRCScaleFactorN, DRCCurStyle->DRCScaleFactorD, FALSE); - - DRCCurStyle->DRCScaleFactorD *= scaled; - DRCCurStyle->DRCScaleFactorN *= scalen; - - /* Reduce scalefactor ratio by greatest common factor */ - scalegcf = FindGCF(DRCCurStyle->DRCScaleFactorD, DRCCurStyle->DRCScaleFactorN); - DRCCurStyle->DRCScaleFactorD /= scalegcf; - DRCCurStyle->DRCScaleFactorN /= scalegcf; - - /* Rescale all rules to the new scalefactor */ - drcScaleUp(DRCCurStyle, DRCCurStyle->DRCScaleFactorD); - drcScaleDown(DRCCurStyle, DRCCurStyle->DRCScaleFactorN); - - /* Do the same for the plow rules */ - DRCPlowScale(DRCCurStyle->DRCScaleFactorD, DRCCurStyle->DRCScaleFactorN, TRUE); - - DRCTechHalo *= scaled; - DRCTechHalo /= scalen; - - DRCStepSize *= scaled; - DRCStepSize /= scalen; - - DRCCurStyle->DRCTechHalo *= scaled; - DRCCurStyle->DRCTechHalo /= scalen; - - DRCCurStyle->DRCStepSize *= scaled; - DRCCurStyle->DRCStepSize /= scalen; -} - -/* The following routines are used by the "tech" command (and in other places, - * such as the LEF file reader) to query the DRC database. - */ - -/* - *----------------------------------------------------------------------------- - * DRCGetDefaultLayerWidth --- - * - * Determine a default layer width from the DRC width rules - * of a layer. Continue processing until we have processed all - * rules, since rules are ordered from shortest to longest distance, - * and the maximum distance rule will mask any rules with a shorter - * distance. - * - * Results: - * The minimum width of the magic layer, in magic internal units - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -DRCGetDefaultLayerWidth(ttype) - TileType ttype; -{ - int routeWidth = 0; - DRCCookie *cptr; - TileTypeBitMask *set; - - for (cptr = DRCCurStyle->DRCRulesTbl[TT_SPACE][ttype]; cptr != (DRCCookie *) NULL; - cptr = cptr->drcc_next) - { - /* FORWARD rules only, and no MAXWIDTH */ - if ((cptr->drcc_flags & (DRC_REVERSE | DRC_MAXWIDTH)) == 0) - { - set = &cptr->drcc_mask; - if (TTMaskHasType(set, ttype) && TTMaskEqual(set, &cptr->drcc_corner)) - if ((cptr->drcc_plane == DBPlane(ttype)) && - (cptr->drcc_dist == cptr->drcc_cdist)) - { - routeWidth = cptr->drcc_dist; - /* Diagnostic */ - /* - TxPrintf("DRC: Layer %s has default width %d\n", - DBTypeLongNameTbl[ttype], routeWidth); - */ - } - } - } - return routeWidth; -} - -/* - *----------------------------------------------------------------------------- - * DRCGetDefaultLayerSpacing --- - * - * Determine a default layer-to-layer spacing from the DRC width - * rules of a layer. Continue processing all rules, since rules - * are ordered from shortest to longest distance, and the largest - * distance matching the criteria sets the rule. - * - * Results: - * The minimum spacing between the specified magic layer types, - * in magic internal units - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -DRCGetDefaultLayerSpacing(ttype1, ttype2) - TileType ttype1, ttype2; -{ - int routeSpacing = 0; - DRCCookie *cptr; - TileTypeBitMask *set; - - for (cptr = DRCCurStyle->DRCRulesTbl[ttype1][TT_SPACE]; cptr != (DRCCookie *) NULL; - cptr = cptr->drcc_next) - { - if (cptr->drcc_flags & DRC_TRIGGER) { /* Skip widespacing rules */ - cptr = cptr->drcc_next; - continue; - } - if ((cptr->drcc_flags & DRC_REVERSE) == 0) /* FORWARD only */ - { - set = &cptr->drcc_mask; - if (!TTMaskHasType(set, ttype2)) - if (PlaneMaskHasPlane(DBTypePlaneMaskTbl[ttype2], cptr->drcc_plane) && - (cptr->drcc_dist == cptr->drcc_cdist)) - { - routeSpacing = cptr->drcc_dist; - /* Diagnostic */ - /* - TxPrintf("DRC: Layer %s has default spacing %d to layer %s\n", - DBTypeLongNameTbl[ttype1], routeSpacing, - DBTypeLongNameTbl[ttype2]); - */ - } - } - } - return routeSpacing; -} - -/* - *----------------------------------------------------------------------------- - * DRCGetDefaultLayerSurround --- - * - * Determine the default minimum required surround amount - * of layer type 2 around layer type 1. - * Continue processing all rules, since rules are ordered from - * shortest to longest distance, and the largest value of the - * surround material sets the minimum required width. - * - * Results: - * The minimum spacing between the specified magic layer types, - * in magic internal units - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -DRCGetDefaultLayerSurround(ttype1, ttype2) - TileType ttype1, ttype2; -{ - int layerSurround = 0; - DRCCookie *cptr; - TileTypeBitMask *set; - - for (cptr = DRCCurStyle->DRCRulesTbl[ttype1][TT_SPACE]; cptr != (DRCCookie *) NULL; - cptr = cptr->drcc_next) - { - if ((cptr->drcc_flags & DRC_REVERSE) == 0) /* FORWARD only */ - { - set = &cptr->drcc_mask; - if (!TTMaskHasType(set, TT_SPACE)) - if (PlaneMaskHasPlane(DBTypePlaneMaskTbl[ttype2], cptr->drcc_plane) && - (cptr->drcc_dist == cptr->drcc_cdist)) - { - layerSurround = cptr->drcc_dist; - /* Diagnostic */ - /* - TxPrintf("DRC: Layer %s has default surround %d over layer %s\n", - DBTypeLongNameTbl[ttype2], layerSurround, - DBTypeLongNameTbl[ttype1]); - */ - } - } - } - return layerSurround; -} - -/* - *----------------------------------------------------------------------------- - * DRCGetDefaultLayerWideSpacing --- - * - * Determine a default layer-to-self wide-layer spacing rule from - * the DRC width rules of a layer. - * - * Results: - * The minimum spacing between the specified magic layer type and - * itself, where one of the shapes has width greater than "twidth". - * The result value is in magic internal units. - * - * If "twidth" is zero, then return the maximum spacing rule distance. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -DRCGetDefaultWideLayerSpacing(ttype, twidth) - TileType ttype; - int twidth; -{ - int routeSpacing = 0; - DRCCookie *cptr; - TileTypeBitMask *set; - bool widerule = FALSE; - - for (cptr = DRCCurStyle->DRCRulesTbl[ttype][TT_SPACE]; cptr != (DRCCookie *) NULL; - cptr = cptr->drcc_next) - { - if (cptr->drcc_flags & DRC_TRIGGER) /* Widespacing rule */ - { - widerule = TRUE; - if (twidth > 0 && cptr->drcc_dist > twidth) /* Check against rule width */ - return routeSpacing; - } - if (widerule && ((cptr->drcc_flags & DRC_REVERSE) == 0)) /* FORWARD only */ - { - set = &cptr->drcc_mask; - if (!TTMaskHasType(set, ttype)) - if (PlaneMaskHasPlane(DBTypePlaneMaskTbl[ttype], cptr->drcc_plane) && - (cptr->drcc_dist == cptr->drcc_cdist)) - { - routeSpacing = cptr->drcc_dist; - /* Diagnostic */ - /* - TxPrintf("DRC: Layer %s has wide spacing %d to layer %s width %d\n", - DBTypeLongNameTbl[ttype1], routeSpacing, - DBTypeLongNameTbl[ttype2], twidth); - */ - } - } - if (!(cptr->drcc_flags & DRC_TRIGGER)) widerule = FALSE; - } - return routeSpacing; -} - diff --git a/Makefile b/Makefile index 7fc163dc..e1d61fbd 100644 --- a/Makefile +++ b/Makefile @@ -107,7 +107,7 @@ distclean: ${RM} ${MAGICDIR}/scripts/default.conf ${RM} ${MAGICDIR}/scripts/config.log ${MAGICDIR}/scripts/config.status ${RM} scripts/magic.spec magic-`cat VERSION` magic-`cat VERSION`.tgz - ${RM} *.log + ${RM} *.log */Depend dist: ${RM} scripts/magic.spec magic-`cat VERSION` magic-`cat VERSION`.tgz diff --git a/VERSION b/VERSION index 3bebc709..f3d26a30 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.27 +8.3.67 diff --git a/calma/CalmaWrite.c b/calma/CalmaWrite.c index 4ef116c3..2118c18a 100644 --- a/calma/CalmaWrite.c +++ b/calma/CalmaWrite.c @@ -53,9 +53,11 @@ static char rcsid[] __attribute__ ((unused)) ="$Header: /usr/cvsroot/magic-8.0/c #include "utils/stack.h" /* Exports */ +bool CalmaDoLibrary = FALSE; /* If TRUE, do not output the top level */ bool CalmaDoLabels = TRUE; /* If FALSE, don't output labels with GDS-II */ bool CalmaDoLower = TRUE; /* If TRUE, allow lowercase labels. */ bool CalmaFlattenArrays = FALSE; /* If TRUE, output arrays as individual uses */ +bool CalmaAddendum = FALSE; /* If TRUE, do not output readonly cell defs */ /* Experimental stuff---not thoroughly tested (as of Sept. 2007)! */ bool CalmaContactArrays = FALSE; /* If TRUE, output contacts as subcell arrays */ @@ -328,7 +330,7 @@ CalmaWrite(rootDef, f) * to insure that each child cell is output before it is used. The * root cell is output last. */ - (void) calmaProcessDef(rootDef, f); + (void) calmaProcessDef(rootDef, f, CalmaDoLibrary); /* Finish up by outputting the end-of-library marker */ calmaOutRH(4, CALMA_ENDLIB, CALMA_NODATA, f); @@ -741,13 +743,14 @@ calmaProcessUse(use, outf) CellUse *use; /* Process use->cu_def */ FILE *outf; /* Stream file */ { - return (calmaProcessDef(use->cu_def, outf)); + return (calmaProcessDef(use->cu_def, outf, FALSE)); } int -calmaProcessDef(def, outf) +calmaProcessDef(def, outf, do_library) CellDef *def; /* Output this def's children, then the def itself */ FILE *outf; /* Stream file */ + bool do_library; /* If TRUE, output only children of def, but not def */ { char *filename; bool isReadOnly, oldStyle, hasContent, isAbstract, hasGDSEnd; @@ -772,13 +775,6 @@ calmaProcessDef(def, outf) return (0); } - /* - * Output the definitions for any of our descendants that have - * not already been output. Numbers are assigned to the subcells - * as they are output. - */ - (void) DBCellEnum(def, calmaProcessUse, (ClientData) outf); - /* * Check if this is a read-only file that is supposed to be copied * verbatim from input to output. If so, do the direct copy. If @@ -797,6 +793,19 @@ calmaProcessDef(def, outf) DBPropGet(def, "GDS_END", &hasGDSEnd); filename = (char *)DBPropGet(def, "GDS_FILE", &isReadOnly); + /* When used with "calma addendum true", don't output the read-only */ + /* cells. This makes the library incomplete and dependent on the */ + /* vendor libraries, so use with caution. */ + + if (isReadOnly && hasContent && CalmaAddendum) return (0); + + /* + * Output the definitions for any of our descendants that have + * not already been output. Numbers are assigned to the subcells + * as they are output. + */ + (void) DBCellEnum(def, calmaProcessUse, (ClientData) outf); + if (isReadOnly && hasContent) { char *buffer, *offptr, *retfilename; @@ -907,7 +916,8 @@ calmaProcessDef(def, outf) /* Output this cell definition from the Magic database */ if (!isReadOnly) - calmaOutFunc(def, outf, &TiPlaneRect); + if (!do_library) + calmaOutFunc(def, outf, &TiPlaneRect); return (0); } diff --git a/calma/calma.h b/calma/calma.h index f810e7a1..bedc169b 100644 --- a/calma/calma.h +++ b/calma/calma.h @@ -28,7 +28,9 @@ extern bool CalmaSubcellPolygons; extern bool CalmaSubcellPaths; extern bool CalmaDoLabels; +extern bool CalmaDoLibrary; extern bool CalmaDoLower; +extern bool CalmaAddendum; extern bool CalmaMergeTiles; extern bool CalmaFlattenArrays; extern bool CalmaNoDRCCheck; diff --git a/cif/CIFgen.c b/cif/CIFgen.c index 4e268327..1095024a 100644 --- a/cif/CIFgen.c +++ b/cif/CIFgen.c @@ -3444,7 +3444,10 @@ calcX: delta = abs(*sxbot) % CIFCurStyle->cs_gridLimit; if (delta > 0) { - *axtop -= 2 * delta; + if (*sxbot >= 0) + *axtop -= 2 * delta; + else + *axtop += 2 * delta; goto calcX; } } @@ -3471,7 +3474,10 @@ calcY: delta = abs(*sybot) % CIFCurStyle->cs_gridLimit; if (delta > 0) { - *aytop -= 2 * delta; + if (*sybot >= 0) + *aytop -= 2 * delta; + else + *aytop += 2 * delta; goto calcY; } } diff --git a/cif/CIFmain.c b/cif/CIFmain.c index ad6742d1..fb2ea1af 100644 --- a/cif/CIFmain.c +++ b/cif/CIFmain.c @@ -145,6 +145,28 @@ CIFGetOutputScale(convert) (float)(CIFCurStyle->cs_expander * convert)); } +/* + * ---------------------------------------------------------------------------- + * + * CIFGetScale -- + * + * Same as the above routine, but provides the scalefactor to get CIF + * units from centimicrons (which generally means just returning the + * expander value to show if units have been declared in nanometers or + * angstroms). + * + * ---------------------------------------------------------------------------- + */ + +float +CIFGetScale(convert) + int convert; +{ + if (CIFCurStyle == NULL) return 1.0; + + return (1.0 / (float)(CIFCurStyle->cs_expander * convert)); +} + /* * ---------------------------------------------------------------------------- * diff --git a/cif/CIFrdutils.c b/cif/CIFrdutils.c index 1e5ab408..7450a7e6 100644 --- a/cif/CIFrdutils.c +++ b/cif/CIFrdutils.c @@ -60,6 +60,7 @@ FILE *cifErrorFile; int cifLineNumber; /* Number of current line. */ int cifTotalWarnings; /* Number of warnings detected */ int cifTotalErrors; /* Number of errors detected */ +bool cifSeenSnapWarning; /* Track this to prevent excessive messaging */ /* The variables used below hold general information about what * we're currently working on. @@ -218,8 +219,10 @@ CIFScaleCoord(cifCoord, snap_type) switch (snap_type) { case COORD_EXACT: - CIFReadWarning("Input off lambda grid by %d/%d; grid redefined.\n", + if (!cifSeenSnapWarning) + CIFReadWarning("Input off lambda grid by %d/%d; grid redefined.\n", remain, denom); + cifSeenSnapWarning = TRUE; CIFTechInputScale(1, denom, FALSE); CIFTechOutputScale(1, denom); @@ -243,8 +246,10 @@ CIFScaleCoord(cifCoord, snap_type) case COORD_HALF_U: case COORD_HALF_L: if (denom > 2) { - CIFReadWarning("Input off lambda grid by %d/%d; grid redefined.\n", - remain, denom); + if (!cifSeenSnapWarning) + CIFReadWarning("Input off lambda grid by %d/%d; " + "grid redefined.\n", remain, denom); + cifSeenSnapWarning = TRUE; /* scale to nearest half-lambda */ if (!(denom & 0x1)) denom >>= 1; @@ -277,8 +282,10 @@ CIFScaleCoord(cifCoord, snap_type) break; case COORD_ANY: - CIFReadWarning("Input off lambda grid by %d/%d; snapped to grid.\n", - abs(remain), abs(denom)); + if (!cifSeenSnapWarning) + CIFReadWarning("Input off lambda grid by %d/%d; snapped to grid.\n", + abs(remain), abs(denom)); + cifSeenSnapWarning = TRUE; /* Careful: must round down a bit more for negative numbers, in * order to ensure that a point exactly halfway between Magic units @@ -1591,6 +1598,7 @@ CIFReadFile(file) cifTotalWarnings = 0; cifTotalErrors = 0; CifPolygonCount = 0; + cifSeenSnapWarning = FALSE; cifInputFile = file; cifReadScale1 = 1; diff --git a/cif/CIFtech.c b/cif/CIFtech.c index d7a310cf..0c905592 100644 --- a/cif/CIFtech.c +++ b/cif/CIFtech.c @@ -2143,7 +2143,11 @@ CIFGetContactSize(type, edge, spacing, border) /* Anything other than an OR function will break */ /* the relationship between magic layers and cuts. */ - else if (sop->co_opcode != CIFOP_OR) + /* NOTE: Making an exception for AND_NOT, which is */ + /* used to distinguish between small and large via */ + /* areas. */ + else if ((sop->co_opcode != CIFOP_OR) && + (sop->co_opcode != CIFOP_ANDNOT)) break; } } diff --git a/cif/cif.h b/cif/cif.h index b2407bf8..304f3840 100644 --- a/cif/cif.h +++ b/cif/cif.h @@ -66,6 +66,7 @@ extern void CIFReadTechFinal(); /* Externally-visible procedures: */ extern float CIFGetOutputScale(); +extern float CIFGetScale(); extern float CIFGetInputScale(); extern int CIFGetDefaultContactSize(); diff --git a/commands/CmdAB.c b/commands/CmdAB.c index fa919ceb..4d662dc3 100644 --- a/commands/CmdAB.c +++ b/commands/CmdAB.c @@ -545,6 +545,8 @@ selGetArrayFunc(selUse, use, trans, arg) * box size [width height] * box position [llx lly] [-edit] * box values [llx lly urx ury] [-edit] + * box remove + * box select * * box | cursor * @@ -580,13 +582,15 @@ selGetArrayFunc(selUse, use, trans, arg) #define BOX_SIZE 2 #define BOX_POSITION 3 #define BOX_VALUES 4 -#define BOX_MOVE 5 -#define BOX_GROW 6 -#define BOX_SHRINK 7 -#define BOX_CORNER 8 -#define BOX_EXISTS 9 -#define BOX_HELP 10 -#define BOX_DEFAULT 11 +#define BOX_REMOVE 5 +#define BOX_SELECT 6 +#define BOX_MOVE 7 +#define BOX_GROW 8 +#define BOX_SHRINK 9 +#define BOX_CORNER 10 +#define BOX_EXISTS 11 +#define BOX_HELP 12 +#define BOX_DEFAULT 13 void CmdBox(w, cmd) @@ -599,6 +603,8 @@ CmdBox(w, cmd) "size [width height] set or return box size", "position [llx lly] [-edit] set or return box position", "values [llx lly urx ury] [-edit] set or return box coordinates", + "remove remove cursor box from display", + "select set box to selection bounding box", "move move box position", "grow expand box size", "shrink shrink box size", @@ -658,6 +664,12 @@ CmdBox(w, cmd) windCheckOnlyWindow(&w, DBWclientID); + if (option == BOX_REMOVE) + { + DBWSetBox((CellDef *)NULL, &GeoNullRect); + return; + } + /*----------------------------------------------------------*/ /* Check for the command options which do not require a box */ /* to be present. */ @@ -907,6 +919,19 @@ CmdBox(w, cmd) boxptr->r_ytop = boxptr->r_ybot + height; break; + case BOX_SELECT: + if (argc == 2) + { + Rect selarea; + GeoTransRect(&SelectUse->cu_transform, &SelectDef->cd_bbox, &selarea); + boxptr->r_xbot = selarea.r_xbot; + boxptr->r_ybot = selarea.r_ybot; + boxptr->r_xtop = selarea.r_xtop; + boxptr->r_ytop = selarea.r_ytop; + } + else goto badusage; + break; + case BOX_VALUES: if (argc == 2) { diff --git a/commands/CmdCD.c b/commands/CmdCD.c index aebc0b4e..f235f693 100644 --- a/commands/CmdCD.c +++ b/commands/CmdCD.c @@ -89,21 +89,23 @@ bool cmdDumpParseArgs(); */ #define CALMA_HELP 0 -#define CALMA_ARRAYS 1 -#define CALMA_CONTACTS 2 -#define CALMA_DRCCHECK 3 -#define CALMA_FLATTEN 4 -#define CALMA_ORDERING 5 -#define CALMA_LABELS 6 -#define CALMA_LOWER 7 -#define CALMA_MERGE 8 -#define CALMA_READ 9 -#define CALMA_READONLY 10 -#define CALMA_RESCALE 11 -#define CALMA_WARNING 12 -#define CALMA_WRITE 13 -#define CALMA_POLYS 14 -#define CALMA_PATHS 15 +#define CALMA_ADDENDUM 1 +#define CALMA_ARRAYS 2 +#define CALMA_CONTACTS 3 +#define CALMA_DRCCHECK 4 +#define CALMA_FLATTEN 5 +#define CALMA_ORDERING 6 +#define CALMA_LABELS 7 +#define CALMA_LIBRARY 8 +#define CALMA_LOWER 9 +#define CALMA_MERGE 10 +#define CALMA_READ 11 +#define CALMA_READONLY 12 +#define CALMA_RESCALE 13 +#define CALMA_WARNING 14 +#define CALMA_WRITE 15 +#define CALMA_POLYS 16 +#define CALMA_PATHS 17 #define CALMA_WARN_HELP CIF_WARN_END /* undefined by CIF module */ @@ -126,12 +128,14 @@ CmdCalma(w, cmd) static char *cmdCalmaOption[] = { "help print this help information", + "addendum [yes|no] output only cells that are not type \"readonly\"", "arrays [yes|no] output arrays as individual subuses (like in CIF)", "contacts [yes|no] optimize output by arraying contacts as subcells", "drccheck [yes|no] mark all cells as needing DRC checking", "flatten [yes|no|limit] flatten simple cells (e.g., contacts) on input", "ordering [on|off] cause cells to be read in post-order", "labels [yes|no] cause labels to be output when writing GDS-II", + "library [yes|no] do not output the top level, only subcells", "lower [yes|no] allow both upper and lower case in labels", "merge [yes|no] merge tiles into polygons in the output", "read file read Calma GDS-II format from \"file\"\n" @@ -227,6 +231,46 @@ CmdCalma(w, cmd) CalmaDoLabels = (option < 3) ? FALSE : TRUE; return; + case CALMA_LIBRARY: + if (cmd->tx_argc == 2) + { +#ifdef MAGIC_WRAPPER + Tcl_SetObjResult(magicinterp, Tcl_NewBooleanObj(CalmaDoLibrary)); +#else + TxPrintf("The top-level cell will %sbe output to the GDS file.\n", + (CalmaDoLibrary) ? "not " : ""); +#endif + return; + } + else if (cmd->tx_argc != 3) + goto wrongNumArgs; + + option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo); + if (option < 0) + goto wrongNumArgs; + CalmaDoLibrary = (option < 3) ? FALSE : TRUE; + return; + + case CALMA_ADDENDUM: + if (cmd->tx_argc == 2) + { +#ifdef MAGIC_WRAPPER + Tcl_SetObjResult(magicinterp, Tcl_NewBooleanObj(CalmaAddendum)); +#else + TxPrintf("Read-only cell defs will %sbe output to the GDS file.\n", + (CalmaAddendum) ? "not " : ""); +#endif + return; + } + else if (cmd->tx_argc != 3) + goto wrongNumArgs; + + option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo); + if (option < 0) + goto wrongNumArgs; + CalmaAddendum = (option < 3) ? FALSE : TRUE; + return; + case CALMA_CONTACTS: if (cmd->tx_argc == 2) { diff --git a/commands/CmdLQ.c b/commands/CmdLQ.c index 2c6fda11..c0bf6ce9 100644 --- a/commands/CmdLQ.c +++ b/commands/CmdLQ.c @@ -1115,6 +1115,7 @@ cmdPortLabelFunc2(scx, label, tpath, cdata) /* Find a label in the cell editDef. */ /* */ /* If "port" is true, then search only for labels that are ports. */ +/* If false, then search only for labels that are not ports. */ /* If "unique" is true, then return a label only if exactly one label */ /* is found in the edit box. */ /*----------------------------------------------------------------------*/ @@ -1123,10 +1124,10 @@ Label * portFindLabel(editDef, port, unique, nonEdit) CellDef *editDef; bool unique; - bool port; + bool port; // If TRUE, only look for labels that are ports bool *nonEdit; // TRUE if label is not in the edit cell { - int found; + int found, wrongkind; Label *lab, *sl; Rect editBox; @@ -1138,10 +1139,19 @@ portFindLabel(editDef, port, unique, nonEdit) ToolGetEditBox(&editBox); found = 0; + wrongkind = FALSE; if (nonEdit) *nonEdit = FALSE; lab = NULL; for (sl = editDef->cd_labels; sl != NULL; sl = sl->lab_next) { + /* Ignore labels based on whether label is or is not a port */ + if (((port == TRUE) && !(sl->lab_flags & PORT_DIR_MASK)) || + ((port == FALSE) && (sl->lab_flags & PORT_DIR_MASK))) + { + wrongkind = TRUE; /* Found at least one label of the wrong kind */ + continue; + } + if (GEO_OVERLAP(&editBox, &sl->lab_rect) || GEO_SURROUND(&editBox, &sl->lab_rect)) { @@ -1167,11 +1177,13 @@ portFindLabel(editDef, port, unique, nonEdit) if (nonEdit) *nonEdit = FALSE; } } + if ((found == 0) && (wrongkind == TRUE)) return NULL; /* If no label was found, then search the hierarchy under the box. */ /* The calling routine may determine whether a label that is not in */ /* the edit cell may be valid for the command (e.g., if querying */ - /* but not changing values). */ + /* but not changing values). NOTE: Currently this does not apply */ + /* the "port" option. */ if (found == 0) { @@ -1196,6 +1208,29 @@ portFindLabel(editDef, port, unique, nonEdit) return lab; } + +/* + * ---------------------------------------------------------------------------- + * + * complabel() -- + * + * qsort() callback routine used by CmdPort when renumbering ports. + * Simply do a string comparison on the two labels. There is no special + * meaning to the lexigraphic ordering; it is meant only to enforce a + * consistent and repeatable port order. However, note that since SPICE + * is case-insensitive, case-insensitive string comparison is used. + * + * ---------------------------------------------------------------------------- + */ + +int +complabel(const void *one, const void *two) +{ + Label *l1 = *((Label **)one); + Label *l2 = *((Label **)two); + return strcasecmp(l1->lab_text, l2->lab_text); +} + /* * ---------------------------------------------------------------------------- * @@ -1207,7 +1242,9 @@ portFindLabel(editDef, port, unique, nonEdit) * usage, below). * * Usage: - * port make|makeall [num] [connect_direction(s)] + * port make [num] [connect_direction(s)] + * or + * port makeall|renumber [connect_direction(s)] * or * port [name|num] class|use|shape|index [value] * @@ -1243,12 +1280,15 @@ portFindLabel(editDef, port, unique, nonEdit) #define PORT_EQUIV 4 #define PORT_EXISTS 5 #define PORT_CONNECT 6 -#define PORT_LAST 7 -#define PORT_MAKE 8 -#define PORT_MAKEALL 9 -#define PORT_NAME 10 -#define PORT_REMOVE 11 -#define PORT_HELP 12 +#define PORT_FIRST 7 +#define PORT_NEXT 8 +#define PORT_LAST 9 +#define PORT_MAKE 10 +#define PORT_MAKEALL 11 +#define PORT_NAME 12 +#define PORT_REMOVE 13 +#define PORT_RENUMBER 14 +#define PORT_HELP 15 void CmdPort(w, cmd) @@ -1257,7 +1297,7 @@ CmdPort(w, cmd) { char **msg; int argstart; - int i, idx, pos, type, option, argc; + int i, refidx, idx, pos, type, option, argc; unsigned short dirmask; bool found; bool nonEdit = FALSE; @@ -1274,11 +1314,14 @@ CmdPort(w, cmd) "equivalent [number] make port equivalent to another port", "exists report if a label is a port or not", "connections [dir...] get [set] port connection directions", + "first report the lowest port number used", + "next [number] report the next port number used", "last report the highest port number used", "make [index] [dir...] turn a label into a port", "makeall [index] [dir] turn all labels into ports", "name report the port name", "remove turn a port back into a label", + "renumber renumber all ports", "help print this help information", NULL }; @@ -1376,7 +1419,7 @@ CmdPort(w, cmd) if (sl && ((sl->lab_flags & PORT_DIR_MASK) != 0)) if ((sl->lab_flags & PORT_NUM_MASK) == portidx) { - lab = sl; + lab = sl; break; } } @@ -1388,7 +1431,8 @@ CmdPort(w, cmd) if (!strcmp(portname, sl->lab_text)) { lab = sl; - break; + if (sl && ((sl->lab_flags & PORT_DIR_MASK) != 0)) + break; } } if (lab == NULL) @@ -1414,10 +1458,15 @@ CmdPort(w, cmd) { /* Check for options that require only one selected port */ - if (option != PORT_LAST) + if (option != PORT_LAST && option != PORT_FIRST) { if (lab == NULL) - lab = portFindLabel(editDef, TRUE, TRUE, &nonEdit); + { + if (option == PORT_MAKE) + lab = portFindLabel(editDef, FALSE, TRUE, &nonEdit); + else + lab = portFindLabel(editDef, TRUE, TRUE, &nonEdit); + } if (option == PORT_EXISTS) { @@ -1435,9 +1484,10 @@ CmdPort(w, cmd) #endif return; } - } - if ((option != PORT_LAST) && (option != PORT_MAKEALL) && (lab == NULL)) + if ((option != PORT_LAST) && (option != PORT_FIRST) && + (option != PORT_MAKEALL) && (option != PORT_RENUMBER) + && (lab == NULL)) { /* Let "port remove" fail without complaining. */ if (option != PORT_REMOVE) @@ -1452,7 +1502,8 @@ CmdPort(w, cmd) /* Check for options that require label to be a port */ if ((option != PORT_MAKE) && (option != PORT_MAKEALL) - && (option != PORT_EXISTS) && (option != PORT_LAST)) + && (option != PORT_EXISTS) && (option != PORT_RENUMBER) + && (option != PORT_LAST) && (option != PORT_FIRST)) { /* label "lab" must already be a port */ if (!(lab->lab_flags & PORT_DIR_MASK)) @@ -1466,8 +1517,9 @@ CmdPort(w, cmd) /* Check for options that cannot operate on a non-edit cell label */ if (nonEdit) { - if ((option == PORT_MAKE) || (option == PORT_MAKEALL) || - (option == PORT_REMOVE) || (argc == 3)) + if ((option == PORT_MAKE) || (option == PORT_MAKEALL) + || (option == PORT_REMOVE) || (option == PORT_RENUMBER) + || (argc == 3)) { TxError("Cannot modify a port in an non-edit cell.\n"); return; @@ -1491,6 +1543,44 @@ CmdPort(w, cmd) #endif break; + case PORT_FIRST: + i = PORT_NUM_MASK + 1; + for (sl = editDef->cd_labels; sl != NULL; sl = sl->lab_next) + { + if (sl->lab_flags & PORT_DIR_MASK) + { + idx = sl->lab_flags & PORT_NUM_MASK; + if (idx < i) i = idx; + } + } + if (i == PORT_NUM_MASK + 1) i = -1; +#ifdef MAGIC_WRAPPER + Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(i)); +#else + TxPrintf("%d\n", i); +#endif + break; + + case PORT_NEXT: + refidx = lab->lab_flags & PORT_NUM_MASK; + i = PORT_NUM_MASK + 1; + for (sl = editDef->cd_labels; sl != NULL; sl = sl->lab_next) + { + if (sl->lab_flags & PORT_DIR_MASK) + { + idx = sl->lab_flags & PORT_NUM_MASK; + if (idx > refidx) + if (idx < i) i = idx; + } + } + if (i == PORT_NUM_MASK + 1) i = -1; +#ifdef MAGIC_WRAPPER + Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(i)); +#else + TxPrintf("Index = %d\n", i); +#endif + break; + case PORT_EXISTS: if (!(lab->lab_flags & PORT_DIR_MASK)) { @@ -1732,6 +1822,57 @@ CmdPort(w, cmd) editDef->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP); break; + case PORT_RENUMBER: + /* Renumber ports in canonical order (by alphabetical + * order of the label text). NOTE: Because SPICE is + * case-insensitive, case-insensitive alphabetical order + * is used. + */ + { + int numlabels, n, p; + Label **slablist, *tlab, *lastlab; + extern int complabel(); + + /* Create a sortable list of labels */ + numlabels = 0; + for (lab = editDef->cd_labels; lab; lab = lab->lab_next) + numlabels++; + + slablist = (Label **)mallocMagic(numlabels * sizeof(Label *)); + numlabels = 0; + for (lab = editDef->cd_labels; lab; lab = lab->lab_next) + { + *(slablist + numlabels) = lab; + numlabels++; + } + + /* Sort the list */ + qsort(slablist, numlabels, sizeof(Label *), complabel); + + /* Number the ports by sorted order */ + p = 0; + lastlab = NULL; + for (n = 0; n < numlabels; n++) + { + tlab = *(slablist + n); + if (tlab->lab_flags & PORT_DIR_MASK) + { + if (lastlab) + if (!strcmp(lastlab->lab_text, tlab->lab_text)) + p--; + + tlab->lab_flags &= ~PORT_NUM_MASK; + tlab->lab_flags |= p; + lastlab = tlab; + p++; + } + } + + /* Clean up */ + freeMagic((char *)slablist); + } + break; + case PORT_MAKEALL: lab = editDef->cd_labels; // Fall through. . . diff --git a/commands/CmdRS.c b/commands/CmdRS.c index 5535b7be..95178efa 100644 --- a/commands/CmdRS.c +++ b/commands/CmdRS.c @@ -680,12 +680,13 @@ CmdSelect(w, cmd) #define SEL_PICK 8 #define SEL_SAVE 9 #define SEL_FEEDBACK 10 -#define SEL_BOX 11 -#define SEL_CHUNK 12 -#define SEL_REGION 13 -#define SEL_NET 14 -#define SEL_SHORT 15 -#define SEL_DEFAULT 16 +#define SEL_BBOX 11 +#define SEL_BOX 12 +#define SEL_CHUNK 13 +#define SEL_REGION 14 +#define SEL_NET 15 +#define SEL_SHORT 16 +#define SEL_DEFAULT 17 static char *cmdSelectOption[] = { @@ -700,6 +701,7 @@ CmdSelect(w, cmd) "pick", "save", "feedback", + "bbox", "box", "chunk", "region", @@ -724,6 +726,7 @@ CmdSelect(w, cmd) "pick delete selection from layout", "save file save selection on disk in file.mag", "feedback [style] copy selection to feedback", + "bbox return the bounding box of the selection", "[more | less] box | chunk | region | net [layers]\n" " [de]select chunk/region/net specified by\n" " the lower left corner of the current box", @@ -775,6 +778,7 @@ CmdSelect(w, cmd) bool more = FALSE, less = FALSE, samePlace = TRUE; #ifdef MAGIC_WRAPPER char *tclstr; + Tcl_Obj *lobj; #endif /* How close two clicks must be to be considered the same point: */ @@ -933,6 +937,32 @@ CmdSelect(w, cmd) TxPrintf(" select %s\n", *msg); return; + /*-------------------------------------------------------------------- + * Print or return the bounding box of the selection + *-------------------------------------------------------------------- + */ + + case SEL_BBOX: + GeoTransRect(&SelectUse->cu_transform, &SelectDef->cd_bbox, &selarea); + +#ifdef MAGIC_WRAPPER + lobj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(magicinterp, lobj, + Tcl_NewIntObj(selarea.r_xbot)); + Tcl_ListObjAppendElement(magicinterp, lobj, + Tcl_NewIntObj(selarea.r_ybot)); + Tcl_ListObjAppendElement(magicinterp, lobj, + Tcl_NewIntObj(selarea.r_xtop)); + Tcl_ListObjAppendElement(magicinterp, lobj, + Tcl_NewIntObj(selarea.r_ytop)); + Tcl_SetObjResult(magicinterp, lobj); +#else + TxPrintf("Select bounding box: %d %d %d %d\n", + selarea.r_xbot, selarea.r_ybot, + selarea.r_xtop, selarea.r_ytop); +#endif + return; + /*-------------------------------------------------------------------- * Make a copy of the selection at its present loction but do not * clear the selection. diff --git a/commands/CmdSubrs.c b/commands/CmdSubrs.c index 842b026a..b2f2b954 100644 --- a/commands/CmdSubrs.c +++ b/commands/CmdSubrs.c @@ -774,6 +774,37 @@ again: return (returnname); } +/* + * ---------------------------------------------------------------------------- + * + * nameEllipsis --- + * + * Truncate a string an append an ellipsis ("...") to the end if the string + * will overflow a fixed array length. + * + * ---------------------------------------------------------------------------- + */ + +static char * +nameEllipsis(name, maxlen, prefix) + char *name; + int maxlen; + char **prefix; +{ + int l = strlen(name); + + if (l < maxlen) + { + *prefix = ""; + return name; + } + else + { + *prefix = "..."; + return &name[l - maxlen + 3]; + } +} + /* * ---------------------------------------------------------------------------- * @@ -804,12 +835,14 @@ cmdSaveWindSet(window, def) { char caption[200]; CellDef *rootDef; + char *name, *name_pfx; rootDef = ((CellUse *) window->w_surfaceID)->cu_def; if (rootDef != def) return 0; - (void) sprintf(caption, "%s [NOT BEING EDITED]", def->cd_name); + name = nameEllipsis(def->cd_name, 175, &name_pfx); + (void) snprintf(caption, sizeof(caption), "%s%s [NOT BEING EDITED]", name_pfx, name); (void) StrDup(&window->w_iconname, def->cd_name); WindCaption(window, caption); return 0; @@ -896,13 +929,22 @@ cmdWindSet(window) { char caption[200]; CellDef *wDef; + char *name[2], *name_pfx[2]; wDef = ((CellUse *) window->w_surfaceID)->cu_def; - if (wDef != newRootDef) - (void) sprintf(caption, "%s [NOT BEING EDITED]", wDef->cd_name); - else { - (void) sprintf(caption, "%s EDITING %s", wDef->cd_name, - newEditDef->cd_name); + + + + if (wDef != newRootDef) { + name[0] = nameEllipsis(wDef->cd_name, 175, &name_pfx[0]); + (void) snprintf(caption, sizeof(caption), "%s%s [NOT BEING EDITED]", + name_pfx[0], name[0]); + } else { + name[0] = nameEllipsis(wDef->cd_name, 90, &name_pfx[0]); + name[1] = nameEllipsis(newEditDef->cd_name, 90, &name_pfx[1]); + (void) snprintf(caption, sizeof(caption), "%s%s EDITING %s%s", + name_pfx[0], name[0], name_pfx[1], name[1]); + #ifdef SCHEME_INTERPRETER /* Add a binding to scheme variable "edit-cell" */ LispSetEdit (newEditDef->cd_name); diff --git a/database/DBcellsubr.c b/database/DBcellsubr.c index 94d02efb..d9e6ee8c 100644 --- a/database/DBcellsubr.c +++ b/database/DBcellsubr.c @@ -104,7 +104,7 @@ DBDescendSubcell(use, xMask) * * Copies the contents of the CellDef pointed to by sourceDef into the * CellDef pointed to by destDef. Only the planes, labels, flags, - * use-id hash table, and bounding box are copied. + * cell plane, use-id hash table, and bounding box are copied. * * Results: * None. @@ -131,6 +131,8 @@ DBCellCopyDefBody(sourceDef, destDef) for (i = 0; i < MAXPLANES; i++) destDef->cd_planes[i] = sourceDef->cd_planes[i]; + destDef->cd_cellPlane = sourceDef->cd_cellPlane; + /* Be careful to update parent pointers in the children of dest. * Don't allow interrupts to wreck this. */ diff --git a/database/DBio.c b/database/DBio.c index 5272b774..76ab5a30 100644 --- a/database/DBio.c +++ b/database/DBio.c @@ -2986,7 +2986,7 @@ DBCellWrite(cellDef, fileName) if (realf == NULL) { cellDef->cd_flags |= CDMODIFIED; - TxError("Warning: Cannot open file for writing!\n"); + TxError("Warning: Cannot open file \"%s\" for writing!\n", expandname); } else { @@ -2994,7 +2994,7 @@ DBCellWrite(cellDef, fileName) if (thestat.st_size != DBFileOffset) { cellDef->cd_flags |= CDMODIFIED; - TxError("Warning: I/O error in writing file\n"); + TxError("Warning: I/O error in writing file \"%s\"\n", expandname); } fclose(realf); } @@ -3173,7 +3173,13 @@ dbWriteCellFunc(cellUse, cdarg) } else break; + } + + /* If there are no common components, then restore the leading '/' */ + if ((*pathorigin == '/') && (pathstart == pathorigin + 1)) + pathstart = pathorigin; + if (pathend != NULL) { *pathend = '\0'; diff --git a/database/DBtpaint.c b/database/DBtpaint.c index 9e8ed254..26c8d884 100644 --- a/database/DBtpaint.c +++ b/database/DBtpaint.c @@ -600,6 +600,7 @@ dbTechAddPaintErase(type, sectionName, argc, argv) int pNum; PlaneMask pMask, rMask; TileType t1, t2, tres; + TileTypeBitMask tMask; if (argc < 3) { @@ -609,7 +610,13 @@ dbTechAddPaintErase(type, sectionName, argc, argv) if ((t1 = DBTechNoisyNameType(argv[0])) < 0) return FALSE; if ((t2 = DBTechNoisyNameType(argv[1])) < 0) return FALSE; - if ((tres = DBTechNoisyNameType(argv[2])) < 0) return FALSE; + + /* Modified 9/22/2020 to allow multiple types to paint, for example */ + /* to replace a contact type with types on both residue planes. */ + + rMask = DBTechNoisyNameMask(argv[2], &tMask); + if (TTMaskIsZero(&tMask)) return FALSE; + if (argc == 3) { if (t1 == TT_SPACE) @@ -629,51 +636,46 @@ dbTechAddPaintErase(type, sectionName, argc, argv) else pMask = PlaneNumToMaskBit(pNum); } - rMask = LayerPlaneMask(tres); - - /* (The plane mask of "tres" may be a subset of t1, but NOT vice */ - /* versa. Otherwise we will end up creating rules that are not */ - /* dependent on t1 in some planes.) */ - - /* This restriction lifted 5/11/04 with code in DBPaint() that */ - /* recursively paints image types onto planes where they may be */ - /* missed by the inability to generate the correct paint table for */ - /* the operation. */ - -// if (rMask & ~pMask) -// { -// TechError("Planes of result type must be a subset of those of have-type\n"); -// return FALSE; -// } pMask &= ~rMask; + for (tres = 0; tres < DBNumTypes; tres++) + { + if (TTMaskHasType(&tMask, tres)) + { + if (type == RULE_PAINT) + { + /* Apply to all planes of rMask. */ + + for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) + if (PlaneMaskHasPlane(rMask, pNum)) + if (DBTypeOnPlane(tres, pNum)) + dbSetPaintEntry(t1, t2, pNum, tres); + } + else /* (type == RULE_ERASE) */ + { + /* Apply to all planes of rMask. */ + + for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) + if (PlaneMaskHasPlane(rMask, pNum)) + if (DBTypeOnPlane(tres, pNum)) + dbSetEraseEntry(t1, t2, pNum, tres); + } + } + } + if (type == RULE_PAINT) { - /* Apply to all planes of rMask. */ - - for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) - if (PlaneMaskHasPlane(rMask, pNum)) - dbSetPaintEntry(t1, t2, pNum, tres); - /* For all planes of pMask which are not in rMask, result is space */ - for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) if (PlaneMaskHasPlane(pMask, pNum)) - dbSetPaintEntry(t1, t2, pNum, TT_SPACE); + dbSetPaintEntry(t1, t2, pNum, TT_SPACE); } else /* (type == RULE_ERASE) */ { - /* Apply to all planes of rMask. */ - - for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) - if (PlaneMaskHasPlane(rMask, pNum)) - dbSetEraseEntry(t1, t2, pNum, tres); - /* For all planes of pMask which are not in rMask, result is space */ - for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) if (PlaneMaskHasPlane(pMask, pNum)) dbSetEraseEntry(t1, t2, pNum, TT_SPACE); diff --git a/drc/DRCcif.c b/drc/DRCcif.c index cd7659ae..942501e1 100644 --- a/drc/DRCcif.c +++ b/drc/DRCcif.c @@ -200,7 +200,7 @@ drcCifWidth(argc, argv) dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie))); drcCifAssign(dpnew, centidistance, dpnext, &CIFSolidBits, &CIFSolidBits, why, centidistance, - DRC_FORWARD, thislayer, 0); + DRC_FORWARD | DRC_CIFRULE, thislayer, 0); drcCifRules[thislayer][DRC_CIF_SPACE] = dpnew; return ((centidistance+scalefactor-1)/scalefactor); @@ -291,7 +291,7 @@ drcCifSpacing(argc, argv) dpnext = drcCifRules[layer[0]][DRC_CIF_SOLID]; dpnew = (DRCCookie *) mallocMagic((unsigned) sizeof (DRCCookie)); drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits, - &cmask, why, centidistance, DRC_FORWARD, layer[1], 0); + &cmask, why, centidistance, DRC_FORWARD | DRC_CIFRULE, layer[1], 0); drcCifRules[layer[0]][DRC_CIF_SOLID] = dpnew; if (needReverse) dpnew->drcc_flags |= DRC_BOTHCORNERS; @@ -299,7 +299,7 @@ drcCifSpacing(argc, argv) dpnext = drcCifRules[layer[0]][DRC_CIF_SPACE]; dpnew = (DRCCookie *) mallocMagic((unsigned) sizeof (DRCCookie)); drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits, - &cmask, why, centidistance, DRC_REVERSE, layer[1], 0); + &cmask, why, centidistance, DRC_REVERSE | DRC_CIFRULE, layer[1], 0); drcCifRules[layer[0]][DRC_CIF_SPACE] = dpnew; if (needReverse) @@ -311,14 +311,16 @@ drcCifSpacing(argc, argv) 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, layer[0], 0); + 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, layer[0], 0); + why, centidistance, DRC_REVERSE|DRC_BOTHCORNERS | DRC_CIFRULE, + layer[0], 0); drcCifRules[layer[1]][DRC_CIF_SPACE] = dpnew; if (layer[0] == layer[1]) @@ -326,14 +328,16 @@ drcCifSpacing(argc, argv) 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, + &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, + why, centidistance, + DRC_REVERSE | DRC_BOTHCORNERS | DRC_CIFRULE, layer[1], 0); drcCifRules[layer[0]][DRC_CIF_SPACE] = dpnew; } @@ -344,13 +348,13 @@ drcCifSpacing(argc, argv) dpnext = drcCifRules[layer[1]][DRC_CIF_SPACE]; dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie))); drcCifAssign(dpnew, scalefactor, dpnext, &DBSpaceBits, &DBZeroTypeBits, - why, scalefactor, DRC_FORWARD, layer[0], 0); + 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, layer[1], 0); + why, scalefactor, DRC_FORWARD | DRC_CIFRULE, layer[1], 0); drcCifRules[layer[0]][DRC_CIF_SPACE] = dpnew; } @@ -1097,7 +1101,7 @@ drcCifArea(argc, argv) dpnext = drcCifRules[thislayer][DRC_CIF_SPACE]; dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie))); drcCifAssign(dpnew, centihorizon, dpnext, &CIFSolidBits, &CIFSolidBits, - why, centiarea, DRC_AREA | DRC_FORWARD, thislayer, 0); + why, centiarea, DRC_AREA | DRC_FORWARD | DRC_CIFRULE, thislayer, 0); drcCifRules[thislayer][DRC_CIF_SPACE] = dpnew; @@ -1167,7 +1171,7 @@ drcCifMaxwidth(argc, argv) dpnext = drcCifRules[thislayer][DRC_CIF_SPACE]; dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie))); drcCifAssign(dpnew, centidistance, dpnext, &CIFSolidBits, &CIFSolidBits, - why, centidistance, DRC_MAXWIDTH | bend, thislayer, 0); + why, centidistance, DRC_MAXWIDTH | DRC_CIFRULE | bend, thislayer, 0); drcCifRules[thislayer][DRC_CIF_SPACE] = dpnew; return ((centidistance+scalefactor-1)/scalefactor); diff --git a/drc/DRCcontin.c b/drc/DRCcontin.c index e7674c15..a8131361 100644 --- a/drc/DRCcontin.c +++ b/drc/DRCcontin.c @@ -197,14 +197,24 @@ DRCCheckThis (celldef, operation, area) * of CellDefs waiting for DRC */ - /* Ignore read-only, internal, and vendor GDS cells. None of these */ - /* can contain DRC errors that could be fixed in magic. */ + /* Ignore internal GDS cells. */ + /* Note that this rescinds the former behavior of ignoring DRC on */ + /* vendor and read-only cells. Such cells will be flattened in */ + /* interaction areas and show errors anyway, so not showing errors */ + /* in the cell is just confusing. */ - if (celldef->cd_flags & (CDVENDORGDS | CDNOEDIT | CDINTERNAL)) return; + if (celldef->cd_flags & CDINTERNAL) return; /* Insert celldef into list of Defs waiting to be checked, unless */ /* it is already there. */ +#if (0) + + /* The switch to copying up DRC errors from non-interacting */ + /* child cells means that the child cells must be processed */ + /* first. So this routine changes from prepending the cell */ + /* to the list to appending it. */ + pback = &DRCPendingRoot; p = DRCPendingRoot; @@ -226,6 +236,33 @@ DRCCheckThis (celldef, operation, area) p->dpc_next = DRCPendingRoot; DRCPendingRoot = p; +#endif + /* Append new cell to check to the pending list */ + if (DRCPendingRoot == NULL) + { + p = (DRCPendingCookie *) mallocMagic(sizeof (DRCPendingCookie)); + p->dpc_def = celldef; + p->dpc_next = NULL; + DRCPendingRoot = p; + } + else + { + DRCPendingCookie *plast; + plast = DRCPendingRoot; + while (plast->dpc_next != NULL) + { + if (plast->dpc_def == celldef) break; + plast = plast->dpc_next; + } + if (plast->dpc_next == NULL) + { + p = (DRCPendingCookie *) mallocMagic(sizeof (DRCPendingCookie)); + p->dpc_def = celldef; + p->dpc_next = NULL; + plast->dpc_next = p; + } + } + /* Mark the area in this celldef (but don't worry about this stuff * for undo purposes). Also, it's important to disable interrupts * in here, or the paint operation could get aborted underneath us. @@ -683,7 +720,7 @@ drcCheckTile(tile, arg) DRCErrorType = TT_ERROR_S; (void) DRCInteractionCheck(celldef, &square, &erasebox, - drcPaintError, (ClientData) drcTempPlane); + drcPaintError, (ClientData)drcTempPlane); /* Check #3: check for array formation errors in the area. */ @@ -707,7 +744,7 @@ drcCheckTile(tile, arg) DBPaintPlane(celldef->cd_planes[PL_DRC_CHECK], &erasebox, DBStdEraseTbl(TiGetType(tile), PL_DRC_CHECK), (PaintUndoInfo *) NULL); - DBPaintPlane(celldef->cd_planes[PL_DRC_ERROR], &checkbox, + DBPaintPlane(celldef->cd_planes[PL_DRC_ERROR], &erasebox, DBStdEraseTbl(TT_ERROR_P, PL_DRC_ERROR), (PaintUndoInfo *) NULL); DBPaintPlane(celldef->cd_planes[PL_DRC_ERROR], &checkbox, diff --git a/drc/DRCmain.c b/drc/DRCmain.c index 1d9443a2..6a2e9ade 100644 --- a/drc/DRCmain.c +++ b/drc/DRCmain.c @@ -37,6 +37,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include "windows/windows.h" #include "dbwind/dbwind.h" #include "drc/drc.h" +#include "cif/cif.h" #include "utils/undo.h" /* The global variables defined below are parameters between @@ -201,7 +202,10 @@ drcSubstitute (cptr) why_out = (char *)mallocMagic(whylen * sizeof(char)); strcpy(why_out, whyptr); - oscale = CIFGetOutputScale(1000); /* 1000 for conversion to um */ + if (cptr->drcc_flags & DRC_CIFRULE) + oscale = CIFGetScale(100); /* 100 = microns to centimicrons */ + else + oscale = CIFGetOutputScale(1000); /* 1000 for conversion to um */ wptr = why_out; while ((sptr = strchr(whyptr, '%')) != NULL) @@ -611,11 +615,9 @@ drcWhyFunc(scx, cdarg) /* Check paint and interactions in this subcell. */ (void) DRCInteractionCheck(def, &scx->scx_area, &scx->scx_area, - (dolist) ? drcListError : drcPrintError, - (ClientData) scx); + (dolist) ? drcListError : drcPrintError, (ClientData) scx); (void) DRCArrayCheck(def, &scx->scx_area, - (dolist) ? drcListError : drcPrintError, - (ClientData) scx); + (dolist) ? drcListError : drcPrintError, (ClientData) scx); /* New behavior: Don't search children, instead propagate errors up. */ /* (void) DBCellSrArea(scx, drcWhyFunc, (ClientData)cdarg); */ @@ -635,9 +637,9 @@ drcWhyAllFunc(scx, cdarg) /* Check paint and interactions in this subcell. */ (void) DRCInteractionCheck(def, &scx->scx_area, &scx->scx_area, - drcListallError, (ClientData)scx); + drcListallError, (Plane *)NULL, (ClientData)scx); (void) DRCArrayCheck(def, &scx->scx_area, - drcListallError, (ClientData)scx); + drcListallError, (Plane *)NULL, (ClientData)scx); /* New behavior: Don't search children, instead propagate errors up. */ /* (void) DBCellSrArea(scx, drcWhyAllFunc, (ClientData)cdarg); */ diff --git a/drc/DRCsubcell.c b/drc/DRCsubcell.c index eea576c0..6fb049a9 100644 --- a/drc/DRCsubcell.c +++ b/drc/DRCsubcell.c @@ -61,6 +61,19 @@ static DRCCookie drcSubcellCookie = { (DRCCookie *) NULL }; +/* The cookie below is dummied up to provide an error message for + * errors that are in a subcell non-interaction area and have been + * copied up into the parent without flattening + */ + +static DRCCookie drcInSubCookie = { + 0, 0, 0, 0, + { 0 }, { 0 }, + 0, 0, 0, + DRC_IN_SUBCELL_TAG, + (DRCCookie *) NULL +}; + extern int DRCErrorType; /* @@ -94,6 +107,33 @@ drcFindOtherCells(use, area) return 0; } +/* For each tile found in drcCopyErrorsFunc(), translate the */ +/* tile position into the coordinate system of the parent cell */ +/* (represented by the drcTemp plane in ClientData) and */ +/* copy (paint) into it. */ + +int +drcSubCopyErrors(tile, cxp) + Tile *tile; + TreeContext *cxp; +{ + Rect area; + Rect destArea; + struct drcClientData *arg = (struct drcClientData *)cxp->tc_filter->tf_arg; + + // DBTreeSrTiles() checks its own tiles, which we want to ignore. + if (arg->dCD_celldef == cxp->tc_scx->scx_use->cu_def) return 0; + + TiToRect(tile, &area); + GeoClip(&area, &cxp->tc_scx->scx_area); + GeoTransRect(&cxp->tc_scx->scx_trans, &area, &destArea); + + (*(arg->dCD_function))(arg->dCD_celldef, &destArea, arg->dCD_cptr, + arg->dCD_clientData); + (*(arg->dCD_errors))++; + + return 0; +} /* * ---------------------------------------------------------------------------- @@ -146,12 +186,24 @@ drcSubcellFunc(subUse, propagate) /* all cells are checked and errors propagate to the top level. */ subIntArea = GeoNullRect; + +#if (0) + /* NOTE: DRC errors inside a subcell should be ignored for */ + /* the purpose of finding interactions. Errors should only */ + /* be copied up into the parent when in a non-interaction */ + /* area. This is done below in DRCFindInteractions(). */ + /* (Method added by Tim, 10/15/2020) */ + + /* Maybe S and PS errors should be pulled here? */ + DBSrPaintArea((Tile *) NULL, subUse->cu_def->cd_planes[PL_DRC_ERROR], &TiPlaneRect, &DBAllButSpaceBits, drcIncludeArea, (ClientData) &subIntArea); GeoTransRect(&(subUse->cu_transform), &subIntArea, &locIntArea); GeoInclude(&locIntArea, &intArea); +#endif + if (!GEO_RECTNULL(&subIntArea)) *propagate = TRUE; drcCurSub = subUse; @@ -555,12 +607,17 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg) void (*savedPaintPlane)(); struct drcClientData arg; SearchContext scx; + TileTypeBitMask drcMask; drcSubFunc = func; drcSubClientData = cdarg; oldTiles = DRCstatTiles; count = 0; + /* Create a mask with only TT_ERROR_P in it */ + TTMaskZero(&drcMask); + TTMaskSetType(&drcMask, TT_ERROR_P); + /* Divide the area to be checked up into squares. Process each * square separately. */ @@ -585,6 +642,16 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg) cliparea = square; GeoClip(&cliparea, area); + /* Prepare for subcell search */ + DRCDummyUse->cu_def = def; + scx.scx_use = DRCDummyUse; + scx.scx_trans = GeoIdentityTransform; + arg.dCD_celldef = def; + arg.dCD_errors = &count; + arg.dCD_cptr = &drcInSubCookie; + arg.dCD_function = func; + arg.dCD_clientData = cdarg; + /* Find all the interactions in the square, and clip to the error * area we're interested in. */ @@ -600,6 +667,11 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg) errorSaveType = DRCErrorType; DRCErrorType = TT_ERROR_P; // Basic check is always ERROR_P DRCBasicCheck(def, &intArea, &subArea, func, cdarg); + + /* Copy errors up from all non-interacting children */ + scx.scx_area = subArea; + DBTreeSrTiles(&scx, &drcMask, 0, drcSubCopyErrors, &arg); + DRCErrorType = errorSaveType; continue; } @@ -632,6 +704,9 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg) subArea.r_ybot = intArea.r_ytop; GEO_EXPAND(&subArea, DRCTechHalo, &eraseHalo); DRCBasicCheck(def, &eraseHalo, &subArea, func, cdarg); + /* Copy errors up from all non-interacting children */ + scx.scx_area = subArea; + DBTreeSrTiles(&scx, &drcMask, 0, drcSubCopyErrors, &arg); } /* check below */ if (intArea.r_ybot > eraseClip.r_ybot) @@ -640,6 +715,9 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg) subArea.r_ytop = intArea.r_ybot; GEO_EXPAND(&subArea, DRCTechHalo, &eraseHalo); DRCBasicCheck(def, &eraseHalo, &subArea, func, cdarg); + /* Copy errors up from all non-interacting children */ + scx.scx_area = subArea; + DBTreeSrTiles(&scx, &drcMask, 0, drcSubCopyErrors, &arg); } subArea.r_ytop = intArea.r_ytop; subArea.r_ybot = intArea.r_ybot; @@ -650,6 +728,9 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg) subArea.r_xbot = intArea.r_xtop; GEO_EXPAND(&subArea, DRCTechHalo, &eraseHalo); DRCBasicCheck(def, &eraseHalo, &subArea, func, cdarg); + /* Copy errors up from all non-interacting children */ + scx.scx_area = subArea; + DBTreeSrTiles(&scx, &drcMask, 0, drcSubCopyErrors, &arg); } /* check left */ if (intArea.r_xbot > eraseClip.r_xbot) @@ -658,6 +739,9 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg) subArea.r_xbot = eraseClip.r_xbot; GEO_EXPAND(&subArea, DRCTechHalo, &eraseHalo); DRCBasicCheck(def, &eraseHalo, &subArea, func, cdarg); + /* Copy errors up from all non-interacting children */ + scx.scx_area = subArea; + DBTreeSrTiles(&scx, &drcMask, 0, drcSubCopyErrors, &arg); } DRCErrorType = errorSaveType; } @@ -672,9 +756,6 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg) DRCstatInteractions += 1; GEO_EXPAND(&intArea, DRCTechHalo, &scx.scx_area); - DRCDummyUse->cu_def = def; - scx.scx_use = DRCDummyUse; - scx.scx_trans = GeoIdentityTransform; DBCellClearDef(DRCdef); savedPaintTable = DBNewPaintTable(DRCCurStyle->DRCPaintTable); @@ -696,15 +777,10 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg) /* Check for illegal partial overlaps. */ - scx.scx_use = DRCDummyUse; scx.scx_area = intArea; - scx.scx_trans = GeoIdentityTransform; - arg.dCD_celldef = DRCdef; arg.dCD_clip = &intArea; - arg.dCD_errors = &count; + arg.dCD_celldef = DRCdef; arg.dCD_cptr = &drcSubcellCookie; - arg.dCD_function = func; - arg.dCD_clientData = cdarg; (void) DBTreeSrUniqueTiles(&scx, &DRCCurStyle->DRCExactOverlapTypes, 0, drcExactOverlapTile, (ClientData) &arg); } diff --git a/drc/DRCtech.c b/drc/DRCtech.c index 2387fda0..6f477424 100644 --- a/drc/DRCtech.c +++ b/drc/DRCtech.c @@ -582,6 +582,11 @@ DRCTechStyleInit() /* (see DRCsubcell.c). */ drcWhyCreate("This layer can't abut or partially overlap between subcells"); + /* Fourth DRC entry is associated with the statically-allocated */ + /* drcSubcellCookie and has a tag of DRC_IN_SUBCELL_TAG = 4 */ + /* (see DRCsubcell.c). */ + drcWhyCreate("See error definition in the subcell"); + DRCTechHalo = 0; /* Put a dummy rule at the beginning of the rules table for each entry */ @@ -1762,7 +1767,7 @@ drcMaskSpacing(set1, set2, pmask1, pmask2, wwidth, distance, adjacency, { needtrigger = TRUE; touchingok = FALSE; - + needReverse = TRUE; } else { @@ -2000,6 +2005,9 @@ drcMaskSpacing(set1, set2, pmask1, pmask2, wwidth, distance, adjacency, TTMaskClearMask3(&tmp1, &DBPlaneTypes[plane2], set1); TTMaskAndMask3(&tmp2, &DBPlaneTypes[plane], &setRreverse); + /* NOTE: This is needed for some situation, but I */ + /* do not recall the exact nature of it. In other */ + /* cases only the simple rule check is needed. */ if (needtrigger) { DRCCookie *dptrig; @@ -2036,6 +2044,7 @@ drcMaskSpacing(set1, set2, pmask1, pmask2, wwidth, distance, adjacency, dp = drcFindBucket(j, i, distance); dpnew = (DRCCookie *) mallocMagic(sizeof (DRCCookie)); + /* See above */ if (needtrigger) { DRCCookie *dptrig; diff --git a/drc/drc.h b/drc/drc.h index 40984a0e..061a1ce2 100644 --- a/drc/drc.h +++ b/drc/drc.h @@ -35,7 +35,7 @@ typedef struct drccookie unsigned char drcc_cmod; /* Fractional part of drcc_cdist */ TileTypeBitMask drcc_mask; /* Legal types on RHS */ TileTypeBitMask drcc_corner; /* Types that trigger corner check */ - unsigned char drcc_flags; /* Miscellaneous flags, see below. */ + unsigned short drcc_flags; /* Miscellaneous flags, see below. */ int drcc_edgeplane; /* Plane of edge */ int drcc_plane; /* Index of plane on which to check * legal types. */ @@ -47,6 +47,7 @@ typedef struct drccookie #define DRC_ARRAY_OVERLAP_TAG 1 #define DRC_OVERLAP_TAG 2 #define DRC_SUBCELL_OVERLAP_TAG 3 +#define DRC_IN_SUBCELL_TAG 4 /* *This is size "int" because it holds an area for DRC_AREA rules, */ /* and therefore may have twice the bit length of a normal rule distance. */ @@ -74,6 +75,9 @@ typedef struct drccookie #define DRC_ANGLES 0x80 #define DRC_NONSTANDARD (DRC_AREA|DRC_MAXWIDTH|DRC_RECTSIZE|DRC_ANGLES) +/* More flags for indicating what the rule type represents */ +#define DRC_CIFRULE 0x100 + #define DRC_PENDING 0 #define DRC_UNPROCESSED CLIENTDEFAULT #define DRC_PROCESSED 1 @@ -263,6 +267,7 @@ extern DRCCountList *DRCCount(); extern int DRCFind(); extern void DRCCatchUp(); extern bool DRCFindInteractions(); +extern int DRCBasicCheck(); extern void DRCPrintStyle(); extern void DRCSetStyle(); diff --git a/ext2sim/ext2sim.c b/ext2sim/ext2sim.c index e5811290..7034cc71 100644 --- a/ext2sim/ext2sim.c +++ b/ext2sim/ext2sim.c @@ -92,7 +92,8 @@ FILE *esLabF = NULL; static unsigned short esFormat = MIT ; struct { - short resClassSD ; /* the resistance class of the src/drn of the dev */ + short resClassSource ; /* the resistance class of the source of the dev */ + short resClassDrain ; /* the resistance class of the drain of the dev */ short resClassSub ; /* the resistance class of the substrate of the dev */ char *defSubs ; /* the default substrate node */ } fetInfo[MAXDEVTYPES]; @@ -262,8 +263,7 @@ CmdExtToSim(w, cmd) char **msg; bool err_result; - short sd_rclass; - short sub_rclass; + short s_rclass, d_rclass, sub_rclass; char *devname; char *subname; int idx; @@ -572,7 +572,8 @@ runexttosim: for ( i = 0 ; i < MAXDEVTYPES ; i++ ) { - fetInfo[i].resClassSD = NO_RESCLASS; + fetInfo[i].resClassSource = NO_RESCLASS; + fetInfo[i].resClassDrain = NO_RESCLASS; fetInfo[i].resClassSub = NO_RESCLASS; fetInfo[i].defSubs = NULL; } @@ -582,7 +583,7 @@ runexttosim: /* command) */ idx = 0; - while (ExtGetDevInfo(idx++, &devname, &sd_rclass, &sub_rclass, &subname)) + while (ExtGetDevInfo(idx++, &devname, &s_rclass, &d_rclass, &sub_rclass, &subname)) { if (idx == MAXDEVTYPES) { @@ -593,7 +594,8 @@ runexttosim: if (EFStyle != NULL) { - fetInfo[i].resClassSD = sd_rclass; + fetInfo[i].resClassSource = s_rclass; + fetInfo[i].resClassDrain = d_rclass; fetInfo[i].resClassSub = sub_rclass; fetInfo[i].defSubs = subname; } @@ -670,24 +672,25 @@ main(argc, argv) /* create default fetinfo entries (MOSIS) which can be overriden by the command line arguments */ for ( i = 0 ; i < MAXDEVTYPES ; i++ ) { - fetInfo[i].resClassSD = NO_RESCLASS; + fetInfo[i].resClassSource = NO_RESCLASS; + fetInfo[i].resClassDrain = NO_RESCLASS; fetInfo[i].resClassSub = NO_RESCLASS; fetInfo[i].defSubs = NULL; } i = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, "nfet"); - fetInfo[i].resClassSD = 0 ; + fetInfo[i].resClassSource = fetInfo[i].resClassDrain = 0 ; fetInfo[i].resClassSub = NO_RESCLASS ; fetInfo[i].defSubs = "Gnd!"; i = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, "pfet"); - fetInfo[i].resClassSD = 1 ; + fetInfo[i].resClassSource = fetInfo[i].resClassDrain = 1 ; fetInfo[i].resClassSub = 6 ; fetInfo[i].defSubs = "Vdd!"; i = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, "nmos"); - fetInfo[i].resClassSD = 0 ; + fetInfo[i].resClassSource = fetInfo[i].resClassDrain = 0 ; fetInfo[i].resClassSub = NO_RESCLASS ; fetInfo[i].defSubs = "Gnd!"; i = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, "pmos"); - fetInfo[i].resClassSD = 1 ; + fetInfo[i].resClassSource = fetInfo[i].resClassDrain = 1 ; fetInfo[i].resClassSub = 6 ; fetInfo[i].defSubs = "Vdd!"; /* Process command line arguments */ @@ -888,7 +891,8 @@ simmainArgs(pargc, pargv) if ( sscanf(rp, "%d/%s", &rClass, subsNode) != 2 ) goto usage; } ndx = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, cp); - fetInfo[ndx].resClassSD = rClass; + fetInfo[ndx].resClassSource = rClass; + fetInfo[ndx].resClassDrain = rClass; fetInfo[ndx].resClassSub = rClassSub; fetInfo[ndx].defSubs = (char *) mallocMagic((unsigned) (strlen(subsNode)+1)); strcpy(fetInfo[ndx].defSubs,subsNode); @@ -1160,12 +1164,12 @@ simdevVisit(dev, hc, scale, trans) if ( esFormat == SU ) { fprintf(esSimF, "%s", (source->dterm_attrs) ? "," : " s=" ); if (hierS) - simnAPHier(source, hierName, fetInfo[dev->dev_type].resClassSD, + simnAPHier(source, hierName, fetInfo[dev->dev_type].resClassSource, scale, esSimF); else { snode= SimGetNode(hierName, source->dterm_node->efnode_name->efnn_hier); - simnAP(snode, fetInfo[dev->dev_type].resClassSD, scale, esSimF); + simnAP(snode, fetInfo[dev->dev_type].resClassSource, scale, esSimF); } } if (drain->dterm_attrs) { @@ -1178,12 +1182,12 @@ simdevVisit(dev, hc, scale, trans) if ( esFormat == SU ) { fprintf(esSimF, "%s", (drain->dterm_attrs) ? "," : " d=" ); if (hierD) - simnAPHier(drain, hierName, fetInfo[dev->dev_type].resClassSD, + simnAPHier(drain, hierName, fetInfo[dev->dev_type].resClassDrain, scale, esSimF); else { dnode = SimGetNode(hierName, drain->dterm_node->efnode_name->efnn_hier); - simnAP(dnode, fetInfo[dev->dev_type].resClassSD, + simnAP(dnode, fetInfo[dev->dev_type].resClassDrain, scale, esSimF); } } diff --git a/ext2spice/ext2hier.c b/ext2spice/ext2hier.c index cec86c72..3f366cec 100644 --- a/ext2spice/ext2hier.c +++ b/ext2spice/ext2hier.c @@ -172,9 +172,11 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM) } else { - int pn; + int pn, resclass; pn = plist->parm_type[1] - '0'; if (pn >= dev->dev_nterm) pn = dev->dev_nterm - 1; + resclass = (pn > 1) ? esFetInfo[dev->dev_type].resClassDrain : + esFetInfo[dev->dev_type].resClassSource; dnode = GetHierNode(hc, dev->dev_terms[pn].dterm_node->efnode_name->efnn_hier); @@ -186,16 +188,14 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM) 'p' && plist->parm_next->parm_type[1] == plist->parm_type[1]) { - spcnAP(dnode, esFetInfo[dev->dev_type].resClassSD, - scale, plist->parm_name, + spcnAP(dnode, resclass, scale, plist->parm_name, plist->parm_next->parm_name, sdM, esSpiceF, w); plist = plist->parm_next; } else { - spcnAP(dnode, esFetInfo[dev->dev_type].resClassSD, - scale, plist->parm_name, NULL, sdM, + spcnAP(dnode, resclass, scale, plist->parm_name, NULL, sdM, esSpiceF, w); } } @@ -218,9 +218,11 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM) } else { - int pn; + int pn, resclass; pn = plist->parm_type[1] - '0'; if (pn >= dev->dev_nterm) pn = dev->dev_nterm - 1; + resclass = (pn > 1) ? esFetInfo[dev->dev_type].resClassDrain : + esFetInfo[dev->dev_type].resClassSource; dnode = GetHierNode(hc, dev->dev_terms[pn].dterm_node->efnode_name->efnn_hier); @@ -232,15 +234,13 @@ spcHierWriteParams(hc, dev, scale, l, w, sdM) 'a' && plist->parm_next->parm_type[1] == plist->parm_type[1]) { - spcnAP(dnode, esFetInfo[dev->dev_type].resClassSD, - scale, plist->parm_next->parm_name, + spcnAP(dnode, resclass, scale, plist->parm_next->parm_name, plist->parm_name, sdM, esSpiceF, w); plist = plist->parm_next; } else { - spcnAP(dnode, esFetInfo[dev->dev_type].resClassSD, - scale, NULL, plist->parm_name, sdM, + spcnAP(dnode, resclass, scale, NULL, plist->parm_name, sdM, esSpiceF, w); } } @@ -485,7 +485,7 @@ spcdevHierVisit(hc, dev, scale) EFNode *subnode, *snode, *dnode, *subnodeFlat = NULL; int l, w, i, parmval; Rect r; - bool subAP= FALSE, hierS, hierD, extHierSDAttr() ; + bool subAP = FALSE, hierS, hierD, extHierSDAttr(), swapped = FALSE; float sdM; char devchar; bool has_model = TRUE; @@ -515,10 +515,10 @@ spcdevHierVisit(hc, dev, scale) !strcmp(dev->dev_terms[1].dterm_attrs, "D")) || (dev->dev_terms[2].dterm_attrs && !strcmp(dev->dev_terms[2].dterm_attrs, "S"))) - { - drain = &dev->dev_terms[1]; - source = &dev->dev_terms[2]; - } + { + swapDrainSource(dev, &source, &drain); + swapped = TRUE; + } else drain = &dev->dev_terms[2]; } @@ -553,7 +553,7 @@ spcdevHierVisit(hc, dev, scale) case DEV_FET: if (source == drain) { - if (esFormat == NGSPICE) fprintf(esSpiceF, "; "); + if (esFormat == NGSPICE) fprintf(esSpiceF, "$ "); fprintf(esSpiceF, "** SOURCE/DRAIN TIED\n"); } break; @@ -561,7 +561,7 @@ spcdevHierVisit(hc, dev, scale) default: if (gate == source) { - if (esFormat == NGSPICE) fprintf(esSpiceF, "; "); + if (esFormat == NGSPICE) fprintf(esSpiceF, "$ "); fprintf(esSpiceF, "** SHORTED DEVICE\n"); } break; @@ -666,12 +666,12 @@ spcdevHierVisit(hc, dev, scale) break; case DEV_MSUBCKT: - /* msubcircuit is "Xnnn source gate [drain [sub]]]" */ + /* msubcircuit is "Xnnn drain gate [source [sub]]]" */ /* to more conveniently handle situations where MOSFETs */ /* are modeled by subcircuits with the same pin ordering. */ spcdevOutNode(hc->hc_hierName, - source->dterm_node->efnode_name->efnn_hier, + drain->dterm_node->efnode_name->efnn_hier, "subckt", esSpiceF); /* Drop through to below (no break statement) */ @@ -693,15 +693,21 @@ spcdevHierVisit(hc, dev, scale) /* except that the "gate" node is treated as an identifier */ /* only and is not output. */ - if ((dev->dev_nterm > 1) && (dev->dev_class != DEV_MSUBCKT)) - spcdevOutNode(hc->hc_hierName, - source->dterm_node->efnode_name->efnn_hier, - "subckt", esSpiceF); - if (dev->dev_nterm > 2) - spcdevOutNode(hc->hc_hierName, - drain->dterm_node->efnode_name->efnn_hier, - "subckt", esSpiceF); - + if (dev->dev_class != DEV_MSUBCKT) + { + if (dev->dev_nterm > 1) + spcdevOutNode(hc->hc_hierName, source->dterm_node->efnode_name->efnn_hier, + "subckt", esSpiceF); + if (dev->dev_nterm > 2) + spcdevOutNode(hc->hc_hierName, drain->dterm_node->efnode_name->efnn_hier, + "subckt", esSpiceF); + } + else /* class DEV_MSUBCKT */ + { + if (dev->dev_nterm > 2) + spcdevOutNode(hc->hc_hierName, source->dterm_node->efnode_name->efnn_hier, + "subckt", esSpiceF); + } /* The following only applies to DEV_SUBCKT*, which may define as */ /* many terminal types as it wants. */ @@ -959,10 +965,10 @@ spcdevHierVisit(hc, dev, scale) fprintf(esSpiceF, "\n+ "); dnode = GetHierNode(hc, drain->dterm_node->efnode_name->efnn_hier); - spcnAP(dnode, esFetInfo[dev->dev_type].resClassSD, scale, + spcnAP(dnode, esFetInfo[dev->dev_type].resClassDrain, scale, "ad", "pd", sdM, esSpiceF, w); snode= GetHierNode(hc, source->dterm_node->efnode_name->efnn_hier); - spcnAP(snode, esFetInfo[dev->dev_type].resClassSD, scale, + spcnAP(snode, esFetInfo[dev->dev_type].resClassSource, scale, "as", "ps", sdM, esSpiceF, w); if (subAP) { @@ -979,22 +985,33 @@ spcdevHierVisit(hc, dev, scale) else fprintf(esSpiceF, "asub=0 psub=0"); } - - /* Now output attributes, if present */ - if (!esNoAttrs) - { - if (gate->dterm_attrs || source->dterm_attrs || drain->dterm_attrs) - fprintf(esSpiceF,"\n**devattr"); - if (gate->dterm_attrs) - fprintf(esSpiceF, " g=%s", gate->dterm_attrs); - if (source->dterm_attrs) - fprintf(esSpiceF, " s=%s", source->dterm_attrs); - if (drain->dterm_attrs) - fprintf(esSpiceF, " d=%s", drain->dterm_attrs); - } - break; + } + + /* Output attributes, if present - it looks more convenient here, as other device types may be added */ + switch (dev->dev_class) + { + case DEV_FET: + case DEV_MOSFET: + case DEV_ASYMMETRIC: + case DEV_MSUBCKT: + if (!esNoAttrs) + { + if (gate->dterm_attrs || source->dterm_attrs || drain->dterm_attrs) + fprintf(esSpiceF,"\n**devattr"); + if (gate->dterm_attrs) + fprintf(esSpiceF, " g=%s", gate->dterm_attrs); + if (source->dterm_attrs) + fprintf(esSpiceF, " s=%s", source->dterm_attrs); + if (drain->dterm_attrs) + fprintf(esSpiceF, " d=%s", drain->dterm_attrs); + } + break; } fprintf(esSpiceF, "\n"); + + /* If S/D parameters were swapped, then put them back */ + if (swapped) swapDrainSource(dev, NULL, NULL); + return 0; } @@ -1254,7 +1271,7 @@ spcnodeHierVisit(hc, node, res, cap) static char ntmp[MAX_STR_SIZE]; EFHNSprintf(ntmp, hierName); - if (esFormat == NGSPICE) fprintf(esSpiceF, " ; "); + if (esFormat == NGSPICE) fprintf(esSpiceF, " $ "); fprintf(esSpiceF, "** %s == %s\n", ntmp, nsn); } cap = cap / 1000; @@ -1262,12 +1279,12 @@ spcnodeHierVisit(hc, node, res, cap) { fprintf(esSpiceF, esSpiceCapFormat, esCapNum++, nsn, cap, (isConnected) ? "" : - (esFormat == NGSPICE) ? " ; **FLOATING" : + (esFormat == NGSPICE) ? " $ **FLOATING" : " **FLOATING"); } if (node->efnode_attrs && !esNoAttrs) { - if (esFormat == NGSPICE) fprintf(esSpiceF, " ; "); + if (esFormat == NGSPICE) fprintf(esSpiceF, " $ "); fprintf(esSpiceF, "**nodeattr %s :",nsn ); for (fmt = " %s", ap = node->efnode_attrs; ap; ap = ap->efa_next) { @@ -1521,7 +1538,10 @@ devDistJunctHierVisit(hc, dev, scale) for (i = 1; idev_nterm; i++) { n = GetHierNode(hc, dev->dev_terms[i].dterm_node->efnode_name->efnn_hier); - update_w(esFetInfo[dev->dev_type].resClassSD, w, n); + if (i == 1) + update_w(esFetInfo[dev->dev_type].resClassSource, w, n); + else + update_w(esFetInfo[dev->dev_type].resClassDrain, w, n); } return 0; } diff --git a/ext2spice/ext2spice.c b/ext2spice/ext2spice.c index 1066fcc6..e38b472c 100644 --- a/ext2spice/ext2spice.c +++ b/ext2spice/ext2spice.c @@ -239,8 +239,7 @@ CmdExtToSpice(w, cmd) char *substr = NULL; bool err_result, locDoSubckt; - short sd_rclass; - short sub_rclass; + short s_rclass, d_rclass, sub_rclass; char *devname; char *subname; int idx, idx2; @@ -729,7 +728,8 @@ runexttospice: the command line arguments */ for ( i = 0 ; i < MAXDEVTYPES ; i++ ) { - esFetInfo[i].resClassSD = NO_RESCLASS; + esFetInfo[i].resClassSource = NO_RESCLASS; + esFetInfo[i].resClassDrain = NO_RESCLASS; esFetInfo[i].resClassSub = NO_RESCLASS; esFetInfo[i].defSubs = NULL; } @@ -739,7 +739,7 @@ runexttospice: /* command) */ idx = 0; - while (ExtGetDevInfo(idx++, &devname, &sd_rclass, &sub_rclass, &subname)) + while (ExtGetDevInfo(idx++, &devname, &s_rclass, &d_rclass, &sub_rclass, &subname)) { if (idx == MAXDEVTYPES) { @@ -751,7 +751,8 @@ runexttospice: esNoModelType = i; if (EFStyle != NULL) { - esFetInfo[i].resClassSD = sd_rclass; + esFetInfo[i].resClassSource = s_rclass; + esFetInfo[i].resClassDrain = d_rclass; esFetInfo[i].resClassSub = sub_rclass; esFetInfo[i].defSubs = subname; } @@ -992,24 +993,25 @@ main(argc, argv) /* create default devinfo entries (MOSIS) which can be overriden by the command line arguments */ for ( i = 0 ; i < MAXDEVTYPES ; i++ ) { - esFetInfo[i].resClassSD = NO_RESCLASS; + esFetInfo[i].resClassSource = NO_RESCLASS; + esFetInfo[i].resClassDrain = NO_RESCLASS; esFetInfo[i].resClassSub = NO_RESCLASS; esFetInfo[i].defSubs = NULL; } i = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, "ndev"); - esFetInfo[i].resClassSD = 0 ; + esFetInfo[i].resClassSource = esFetInfo[i].resClassDrain = 0 ; esFetInfo[i].resClassSub = NO_RESCLASS ; esFetInfo[i].defSubs = "Gnd!"; i = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, "pdev"); - esFetInfo[i].resClassSD = 1 ; + esFetInfo[i].resClassSource = esFetInfo[i].resClassDrain = 1 ; esFetInfo[i].resClassSub = 8 ; esFetInfo[i].defSubs = "Vdd!"; i = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, "nmos"); - esFetInfo[i].resClassSD = 0 ; + esFetInfo[i].resClassSource = esFetInfo[i].resClassDrain = 0 ; esFetInfo[i].resClassSub = NO_RESCLASS ; esFetInfo[i].defSubs = "Gnd!"; i = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, "pmos"); - esFetInfo[i].resClassSD = 1 ; + esFetInfo[i].resClassSource = esFetInfo[i].resClassDrain = 1 ; esFetInfo[i].resClassSub = 8 ; esFetInfo[i].defSubs = "Vdd!"; /* Process command line arguments */ @@ -1237,7 +1239,7 @@ spcmainArgs(pargc, pargv) if ( sscanf(rp, "%d/%s", &rClass, subsNode) != 2 ) goto usage; } ndx = efBuildAddStr(EFDevTypes, &EFDevNumTypes, MAXDEVTYPES, cp); - esFetInfo[ndx].resClassSD = rClass; + esFetInfo[ndx].resClassSource = esFetInfo[ndx].resClassDrain = rClass; esFetInfo[ndx].resClassSub = rClassSub; if ( ((1<parm_type[1] - '0'; if (pn >= dev->dev_nterm) pn = dev->dev_nterm - 1; hierD = extHierSDAttr(&dev->dev_terms[pn]); + resclass == (pn > 1) ? esFetInfo[dev->dev_type].resClassDrain : + esFetInfo[dev->dev_type].resClassSource; + // For parameter a followed by parameter p, // process both at the same time. @@ -1898,16 +1903,14 @@ spcWriteParams(dev, hierName, scale, l, w, sdM) { if (hierD) spcnAPHier(&dev->dev_terms[pn], hierName, - esFetInfo[dev->dev_type].resClassSD, - scale, plist->parm_type, + resclass, scale, plist->parm_type, plist->parm_next->parm_type, sdM, esSpiceF); else { dnode = SpiceGetNode(hierName, dev->dev_terms[pn].dterm_node->efnode_name->efnn_hier); - spcnAP(dnode, esFetInfo[dev->dev_type].resClassSD, - scale, plist->parm_name, + spcnAP(dnode, resclass, scale, plist->parm_name, plist->parm_next->parm_name, sdM, esSpiceF, w); } @@ -1917,15 +1920,13 @@ spcWriteParams(dev, hierName, scale, l, w, sdM) { if (hierD) spcnAPHier(&dev->dev_terms[pn], hierName, - esFetInfo[dev->dev_type].resClassSD, - scale, plist->parm_type, NULL, + resclass, scale, plist->parm_type, NULL, sdM, esSpiceF); else { dnode = SpiceGetNode(hierName, dev->dev_terms[pn].dterm_node->efnode_name->efnn_hier); - spcnAP(dnode, esFetInfo[dev->dev_type].resClassSD, - scale, plist->parm_name, NULL, + spcnAP(dnode, resclass, scale, plist->parm_name, NULL, sdM, esSpiceF, w); } } @@ -1948,11 +1949,14 @@ spcWriteParams(dev, hierName, scale, l, w, sdM) } else { - int pn; + int pn, resclass; pn = plist->parm_type[1] - '0'; if (pn >= dev->dev_nterm) pn = dev->dev_nterm - 1; + resclass == (pn > 1) ? esFetInfo[dev->dev_type].resClassDrain : + esFetInfo[dev->dev_type].resClassSource; + hierD = extHierSDAttr(&dev->dev_terms[pn]); // For parameter p followed by parameter a, @@ -1964,15 +1968,13 @@ spcWriteParams(dev, hierName, scale, l, w, sdM) { if (hierD) spcnAPHier(&dev->dev_terms[pn], hierName, - esFetInfo[dev->dev_type].resClassSD, - scale, plist->parm_next->parm_type, + resclass, scale, plist->parm_next->parm_type, plist->parm_type, sdM, esSpiceF); else { dnode = SpiceGetNode(hierName, dev->dev_terms[pn].dterm_node->efnode_name->efnn_hier); - spcnAP(dnode, esFetInfo[dev->dev_type].resClassSD, - scale, plist->parm_next->parm_name, + spcnAP(dnode, resclass, scale, plist->parm_next->parm_name, plist->parm_name, sdM, esSpiceF, w); } plist = plist->parm_next; @@ -1981,15 +1983,13 @@ spcWriteParams(dev, hierName, scale, l, w, sdM) { if (hierD) spcnAPHier(&dev->dev_terms[pn], hierName, - esFetInfo[dev->dev_type].resClassSD, - scale, NULL, plist->parm_type, + resclass, scale, NULL, plist->parm_type, sdM, esSpiceF); else { dnode = SpiceGetNode(hierName, dev->dev_terms[pn].dterm_node->efnode_name->efnn_hier); - spcnAP(dnode, esFetInfo[dev->dev_type].resClassSD, - scale, NULL, plist->parm_name, + spcnAP(dnode, resclass, scale, NULL, plist->parm_name, sdM, esSpiceF, w); } } @@ -2184,6 +2184,52 @@ getCurDevMult() return (esFMult && (esFMIndex > 0)) ? esFMult[esFMIndex-1] : (float)1.0; } + +/* + * swapDrainSource + * + * Swap drain and source ordering and the related stuff + * including the drain/source area parameters + * + * This is typycally called if any terminal is marked with attribute "D" or "S" + * (label "D$" or "S$" at poly-diffusion interface), + * then swap order of source and drain compared to the default ordering. + * + */ +void +swapDrainSource(dev, source, drain) + Dev *dev; + DevTerm **source, **drain; +{ + DevParam *plist; + + /* swap drain/source ordering */ + if (drain) *drain = &dev->dev_terms[1]; + if (source) *source = &dev->dev_terms[2]; + + /* Swap drain/source-related parameters. Note that the parameter */ + /* *definitions* are swapped, so if this is done, it must be */ + /* reverted before the next device is processed. */ + + plist = efGetDeviceParams(EFDevTypes[dev->dev_type]); + while (plist != NULL) + { + // Diagnostic + // TxPrintf(" * param: %s; type: %c%c\n", plist->parm_name, plist->parm_type[0], plist->parm_type[1]); + + /* Swap drain/source parameters only */ + if (!(strcmp(plist->parm_type, "a1")) || !(strcmp(plist->parm_type, "p1"))) + plist->parm_type[1] = '0' + 2; + + else if (!(strcmp(plist->parm_type, "a2")) || !(strcmp(plist->parm_type, "p2"))) + plist->parm_type[1] = '0' + 1; + + /* move pointer */ + plist = plist->parm_next; + } +} + + /* * ---------------------------------------------------------------------------- * @@ -2230,7 +2276,7 @@ spcdevVisit(dev, hc, scale, trans) DevTerm *gate, *source, *drain; EFNode *subnode, *snode, *dnode, *subnodeFlat = NULL; int l, w, i, parmval; - bool subAP= FALSE, hierS, hierD, extHierSDAttr() ; + bool subAP= FALSE, hierS, hierD, extHierSDAttr(), swapped = FALSE ; float sdM; char name[12], devchar; bool has_model = TRUE; @@ -2263,8 +2309,8 @@ spcdevVisit(dev, hc, scale, trans) (dev->dev_terms[2].dterm_attrs && !strcmp(dev->dev_terms[2].dterm_attrs, "S"))) { - drain = &dev->dev_terms[1]; - source = &dev->dev_terms[2]; + swapDrainSource(dev, &source, &drain); + swapped = True; } else drain = &dev->dev_terms[2]; @@ -2328,7 +2374,7 @@ spcdevVisit(dev, hc, scale, trans) case DEV_FET: if (source == drain) { - if (esFormat == NGSPICE) fprintf(esSpiceF, "; "); + if (esFormat == NGSPICE) fprintf(esSpiceF, "$ "); fprintf(esSpiceF, "** SOURCE/DRAIN TIED\n"); } break; @@ -2336,7 +2382,7 @@ spcdevVisit(dev, hc, scale, trans) default: if (gate == source) { - if (esFormat == NGSPICE) fprintf(esSpiceF, "; "); + if (esFormat == NGSPICE) fprintf(esSpiceF, "$ "); fprintf(esSpiceF, "** SHORTED DEVICE\n"); } break; @@ -2443,11 +2489,11 @@ spcdevVisit(dev, hc, scale, trans) case DEV_MSUBCKT: - /* MOS-like subcircuit is "Xnnn source gate [drain [sub]]" */ + /* MOS-like subcircuit is "Xnnn drain gate [source [sub]]" */ /* to more conveniently handle cases where MOS devices are */ /* modeled by subcircuits with the same pin ordering. */ - spcdevOutNode(hierName, source->dterm_node->efnode_name->efnn_hier, + spcdevOutNode(hierName, drain->dterm_node->efnode_name->efnn_hier, name, esSpiceF); /* Drop through to below (no break statement) */ @@ -2468,12 +2514,21 @@ spcdevVisit(dev, hc, scale, trans) /* except that the "gate" node is treated as an identifier */ /* only and is not output. */ - if ((dev->dev_nterm > 1) && (dev->dev_class != DEV_MSUBCKT)) - spcdevOutNode(hierName, source->dterm_node->efnode_name->efnn_hier, - name, esSpiceF); - if (dev->dev_nterm > 2) - spcdevOutNode(hierName, drain->dterm_node->efnode_name->efnn_hier, - name, esSpiceF); + if (dev->dev_class != DEV_MSUBCKT) + { + if (dev->dev_nterm > 1) + spcdevOutNode(hierName, source->dterm_node->efnode_name->efnn_hier, + name, esSpiceF); + if (dev->dev_nterm > 2) + spcdevOutNode(hierName, drain->dterm_node->efnode_name->efnn_hier, + name, esSpiceF); + } + else /* class DEV_MSUBCKT */ + { + if (dev->dev_nterm > 2) + spcdevOutNode(hierName, source->dterm_node->efnode_name->efnn_hier, + name, esSpiceF); + } /* The following only applies to DEV_SUBCKT*, which may define as */ /* many terminal types as it wants. */ @@ -2716,20 +2771,20 @@ spcdevVisit(dev, hc, scale, trans) fprintf(esSpiceF, "\n+ "); if (hierD) - spcnAPHier(drain, hierName, esFetInfo[dev->dev_type].resClassSD, + spcnAPHier(drain, hierName, esFetInfo[dev->dev_type].resClassDrain, scale, "ad", "pd", sdM, esSpiceF); else { dnode = SpiceGetNode(hierName, drain->dterm_node->efnode_name->efnn_hier); - spcnAP(dnode, esFetInfo[dev->dev_type].resClassSD, scale, + spcnAP(dnode, esFetInfo[dev->dev_type].resClassDrain, scale, "ad", "pd", sdM, esSpiceF, w); } if (hierS) - spcnAPHier(source, hierName, esFetInfo[dev->dev_type].resClassSD, + spcnAPHier(source, hierName, esFetInfo[dev->dev_type].resClassSource, scale, "as", "ps", sdM, esSpiceF); else { snode= SpiceGetNode(hierName, source->dterm_node->efnode_name->efnn_hier); - spcnAP(snode, esFetInfo[dev->dev_type].resClassSD, scale, + spcnAP(snode, esFetInfo[dev->dev_type].resClassSource, scale, "as", "ps", sdM, esSpiceF, w); } if (subAP) @@ -2763,6 +2818,10 @@ spcdevVisit(dev, hc, scale, trans) break; } fprintf(esSpiceF, "\n"); + + /* If S/D parameters on a subcircuit were swapped, put them back */ + if (swapped) swapDrainSource(dev, NULL, NULL); + return 0; } @@ -3203,7 +3262,7 @@ spcnodeVisit(node, res, cap) static char ntmp[MAX_STR_SIZE]; EFHNSprintf(ntmp, hierName); - if (esFormat == NGSPICE) fprintf(esSpiceF, "; "); + if (esFormat == NGSPICE) fprintf(esSpiceF, "$ "); fprintf(esSpiceF, "** %s == %s\n", ntmp, nsn); } cap = cap / 1000; @@ -3211,12 +3270,12 @@ spcnodeVisit(node, res, cap) { fprintf(esSpiceF, esSpiceCapFormat, esCapNum++, nsn, cap, (isConnected) ? "\n" : - (esFormat == NGSPICE) ? " ; **FLOATING\n" : + (esFormat == NGSPICE) ? " $ **FLOATING\n" : " **FLOATING\n"); } if (node->efnode_attrs && !esNoAttrs) { - if (esFormat == NGSPICE) fprintf(esSpiceF, " ; "); + if (esFormat == NGSPICE) fprintf(esSpiceF, " $ "); fprintf(esSpiceF, "**nodeattr %s :",nsn ); for (fmt = " %s", ap = node->efnode_attrs; ap; ap = ap->efa_next) { @@ -4038,7 +4097,10 @@ devDistJunctVisit(dev, hc, scale, trans) { n = SpiceGetNode(hierName, dev->dev_terms[i].dterm_node->efnode_name->efnn_hier); - update_w(esFetInfo[dev->dev_type].resClassSD, w, n); + if (i == 1) + update_w(esFetInfo[dev->dev_type].resClassSource, w, n); + else + update_w(esFetInfo[dev->dev_type].resClassDrain, w, n); } return 0; } diff --git a/ext2spice/ext2spice.h b/ext2spice/ext2spice.h index 1aa38067..e21e6acd 100644 --- a/ext2spice/ext2spice.h +++ b/ext2spice/ext2spice.h @@ -29,6 +29,7 @@ extern EFNode *spcdevSubstrate(); extern char *nodeSpiceName(); extern int nodeVisitDebug(); extern void topVisit(); +extern void swapDrainSource(); extern int _ext2spice_start(); extern EFNode *spcdevHierSubstrate(); @@ -89,7 +90,8 @@ extern DQueue subcktNameQueue ; /* q used to print it sorted at the end*/ typedef struct { - short resClassSD ; /* the resistance class of the src/drn of the dev */ + short resClassSource ; /* the resistance class of the source of the dev */ + short resClassDrain ; /* the resistance class of the drain of the dev */ short resClassSub ; /* the resistance class of the substrate of the dev */ char *defSubs ; /* the default substrate node */ } fetInfoList; diff --git a/extflat/EFbuild.c b/extflat/EFbuild.c index c5614f98..09ac3a2e 100644 --- a/extflat/EFbuild.c +++ b/extflat/EFbuild.c @@ -155,23 +155,37 @@ efBuildNode(def, isSubsnode, nodeName, nodeCap, x, y, layerName, av, ac) if (efWarn) efReadError("Warning: duplicate node name %s\n", nodeName); - /* Just add to C, perim, area of existing node */ - newnode = newname->efnn_node; - newnode->efnode_cap += (EFCapValue) nodeCap; - for (n = 0; n < efNumResistClasses && ac > 1; n++, ac -= 2) + /* newnode should exist if newname does. Having a NULL node */ + /* may be caused by detached labels "connected" to space. */ + + if ((newnode = newname->efnn_node) != NULL) { - newnode->efnode_pa[n].pa_area += atoi(*av++); - newnode->efnode_pa[n].pa_perim += atoi(*av++); + /* Just add to C, perim, area of existing node */ + newnode->efnode_cap += (EFCapValue) nodeCap; + for (n = 0; n < efNumResistClasses && ac > 1; n++, ac -= 2) + { + newnode->efnode_pa[n].pa_area += atoi(*av++); + newnode->efnode_pa[n].pa_perim += atoi(*av++); + } + + /* If this node is identified as substrate, ensure that */ + /* the flag is set. */ + if (isSubsnode == TRUE) + newnode->efnode_flags |= EF_SUBS_NODE; + + return; } - return; } - /* Allocate a new node with 'nodeName' as its single name */ - newname = (EFNodeName *) mallocMagic((unsigned)(sizeof (EFNodeName))); - newname->efnn_hier = EFStrToHN((HierName *) NULL, nodeName); - newname->efnn_port = -1; /* No port assignment */ - newname->efnn_next = NULL; - HashSetValue(he, (char *) newname); + if (!newname) + { + /* Allocate a new node with 'nodeName' as its single name */ + newname = (EFNodeName *) mallocMagic((unsigned)(sizeof (EFNodeName))); + newname->efnn_hier = EFStrToHN((HierName *) NULL, nodeName); + newname->efnn_port = -1; /* No port assignment */ + newname->efnn_next = NULL; + HashSetValue(he, (char *) newname); + } /* New node itself */ size = sizeof (EFNode) + (efNumResistClasses - 1) * sizeof (EFPerimArea); diff --git a/extract/ExtBasic.c b/extract/ExtBasic.c index 6d048629..17b41ae0 100644 --- a/extract/ExtBasic.c +++ b/extract/ExtBasic.c @@ -1724,7 +1724,14 @@ extOutputDevices(def, transList, outFile) continue; /* This terminal already found by perimeter search */ tmask = &devptr->exts_deviceSDTypes[termcount]; - if (TTMaskIsZero(tmask)) break; /* End of SD terminals */ + if (TTMaskIsZero(tmask)) { + if (termcount < nsd) { + /* See if there is another matching device record with */ + /* a different number of terminals, and try again. */ + devptr = extDevFindMatch(devptr, t); + } + break; /* End of SD terminals */ + } else if (!TTMaskIntersect(tmask, &DBPlaneTypes[reg->treg_pnum])) { node = NULL; @@ -1736,7 +1743,7 @@ extOutputDevices(def, transList, outFile) break; } extTransRec.tr_devmatch |= (MATCH_TERM << termcount); - extTransRec.tr_termnode[termcount++] = node; + extTransRec.tr_termnode[termcount] = node; } else if (TTMaskHasType(tmask, TT_SPACE)) { /* Device node is specified as being the substrate */ @@ -1842,6 +1849,7 @@ extOutputDevices(def, transList, outFile) if (varsub != NULL) subsName = varsub; } #endif + extTransRec.tr_devrec = devptr; /* Original-style FET record backward compatibility */ if (devptr->exts_deviceClass != DEV_FET) @@ -1941,6 +1949,7 @@ extOutputDevices(def, transList, outFile) arg.fra_uninit = (ClientData) extTransRec.tr_gatenode; arg.fra_region = (Region *) reg; arg.fra_each = extAnnularTileFunc; + (void) ExtFindNeighbors(reg->treg_tile, arg.fra_pNum, &arg); extSeparateBounds(n - 1); /* Handle MOScaps (if necessary) */ @@ -2253,7 +2262,7 @@ extTransFindSubs(tile, t, mask, def, sn, layerptr) NodeRegion **sn; TileType *layerptr; { - Rect tileArea; + Rect tileArea, tileAreaPlus; int pNum; int extTransFindSubsFunc1(); /* Forward declaration */ NodeAndType noderec; @@ -2262,11 +2271,16 @@ extTransFindSubs(tile, t, mask, def, sn, layerptr) noderec.layer = TT_SPACE; TiToRect(tile, &tileArea); + + /* Expand tile area by 1 in all directions. This catches terminals */ + /* on certain extended drain MOSFET devices. */ + GEO_EXPAND(&tileArea, 1, &tileAreaPlus); + for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) { if (TTMaskIntersect(&DBPlaneTypes[pNum], mask)) { - if (DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum], &tileArea, + if (DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum], &tileAreaPlus, mask, extTransFindSubsFunc1, (ClientData)&noderec)) { *sn = noderec.region; @@ -2749,6 +2763,7 @@ extTransPerimFunc(bp) else { TxError("Error: Asymmetric device with multiple terminals!\n"); + break; } /* Add the length to this terminal's perimeter */ @@ -3024,7 +3039,31 @@ extSpecialPerimFunc(bp, sense) if (toutside == TT_SPACE) if (glob_subsnode != NULL) diffNode = glob_subsnode; + } + /* Check for terminal on different plane than the device */ + if (!needSurvey) + { + for (i = 0; !TTMaskIsZero(&devptr->exts_deviceSDTypes[i]); i++) + { + TileTypeBitMask mmask; + PlaneMask pmask; + + mmask = devptr->exts_deviceSDTypes[i]; + if (toutside != TT_SPACE) TTMaskClearType(&mmask, TT_SPACE); + pmask = DBTechTypesToPlanes(&mmask); + + if (!PlaneMaskHasPlane(pmask, DBPlane(tinside))) + { + diffNode = extTransRec.tr_termnode[i]; + needSurvey = TRUE; + break; + } + } + } + + if (!sense || needSurvey) + { /* * Since we're repeating the search, all terminals should be there. */ diff --git a/extract/ExtCell.c b/extract/ExtCell.c index 8d7c1751..50c80ceb 100644 --- a/extract/ExtCell.c +++ b/extract/ExtCell.c @@ -308,6 +308,8 @@ extHeader(def, f) bool propfound; char *propvalue; + ASSERT(DBTechName != NULL, "extHeader"); + /* Output a timestamp (should be first) */ fprintf(f, "timestamp %d\n", def->cd_timestamp); diff --git a/extract/ExtHard.c b/extract/ExtHard.c index 1cacf94d..a884a87e 100644 --- a/extract/ExtHard.c +++ b/extract/ExtHard.c @@ -340,6 +340,7 @@ extHardSetLabel(scx, reg, arg) } GeoTransRect(&scx->scx_trans, &r, &newlab->lab_rect); newlab->lab_type = oldlab->lab_type; + newlab->lab_flags = oldlab->lab_flags; text = oldlab->lab_text; /* Don't care, really, which orientation the label has */ diff --git a/extract/ExtHier.c b/extract/ExtHier.c index c1445273..73fa39e6 100644 --- a/extract/ExtHier.c +++ b/extract/ExtHier.c @@ -291,7 +291,12 @@ extHierConnectFunc1(oneTile, ha) // node only describes a single point. for (lab = cumDef->cd_labels; lab; lab = lab->lab_next) - if (GEO_TOUCH(&r, &lab->lab_rect) && (lab->lab_flags & LABEL_STICKY)) + { + // All sticky labels are at the front of the list in cumDef, so + // stop when we see the first non-sticky label. + if (!(lab->lab_flags & LABEL_STICKY)) break; + + if (GEO_TOUCH(&r, &lab->lab_rect)) if (TTMaskHasType(connected, lab->lab_type)) { HashTable *table = &ha->ha_connHash; @@ -350,6 +355,7 @@ extHierConnectFunc1(oneTile, ha) #endif } + } return (0); } diff --git a/extract/ExtSubtree.c b/extract/ExtSubtree.c index 42763f04..89b054a8 100644 --- a/extract/ExtSubtree.c +++ b/extract/ExtSubtree.c @@ -28,6 +28,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include #include +#include #include "tcltk/tclmagic.h" #include "utils/magic.h" @@ -42,6 +43,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include "debug/debug.h" #include "extract/extract.h" #include "extract/extractInt.h" +#include "graphics/graphics.h" #include "utils/signals.h" #include "windows/windows.h" #include "dbwind/dbwind.h" @@ -168,6 +170,10 @@ extSubtree(parentUse, reg, f) float pdone, plast; SearchContext scx; + /* Use the display timer to force a 5-second progress check */ + GrDisplayStatus = DISPLAY_IN_PROGRESS; + SigSetTimer(5); /* Print at 5-second intervals */ + if ((ExtOptions & (EXT_DOCOUPLING|EXT_DOADJUST)) != (EXT_DOCOUPLING|EXT_DOADJUST)) halo = 1; @@ -264,9 +270,16 @@ extSubtree(parentUse, reg, f) cuts++; pdone = 100.0 * ((float)cuts / (float)totcuts); if ((((pdone - plast) > 5.0) || (cuts == totcuts)) && (cuts > 1)) { - TxPrintf("Completed %d%%\n", (int)(pdone + 0.5)); - plast = pdone; - TxFlushOut(); + /* Only print something if the 5-second timer has expired */ + if (GrDisplayStatus == DISPLAY_BREAK_PENDING) + { + TxPrintf("Completed %d%%\n", (int)(pdone + 0.5)); + plast = pdone; + TxFlushOut(); + + GrDisplayStatus = DISPLAY_IN_PROGRESS; + SigSetTimer(5); + } #ifdef MAGIC_WRAPPER /* We need to let Tk paint the console display */ @@ -313,6 +326,8 @@ done: /* Output connections and node adjustments */ extOutputConns(&ha.ha_connHash, f); HashKill(&ha.ha_connHash); + GrDisplayStatus = DISPLAY_IDLE; + SigRemoveTimer(); /* Clear the CU_SUB_EXTRACTED flag from all children instances */ DBCellEnum(def, extClearUseFlags, (ClientData)NULL); @@ -766,6 +781,8 @@ extSubtreeFunc(scx, ha) for (lab = cumDef->cd_labels; lab ; lab = lab->lab_next) { + if (!(lab->lab_flags & LABEL_STICKY)) continue; + n = sizeof (Label) + strlen(lab->lab_text) - sizeof lab->lab_text + 1; diff --git a/extract/ExtTech.c b/extract/ExtTech.c index 61d65a61..c0b2da44 100644 --- a/extract/ExtTech.c +++ b/extract/ExtTech.c @@ -293,14 +293,22 @@ ExtCompareStyle(stylename) * * Side Effects: * Fills values in the argument list. + * + * Notes: + * The original sd_rclassptr has been expanded to s_rclassptr and + * d_rclassptr to capture asymmetric devices, bipolars, etc. Note + * that this is not a general-purpose method extending beyond two + * (non-gate) terminals, and should be updated. + * * ---------------------------------------------------------------------------- */ bool -ExtGetDevInfo(idx, devnameptr, sd_rclassptr, sub_rclassptr, subnameptr) +ExtGetDevInfo(idx, devnameptr, s_rclassptr, d_rclassptr, sub_rclassptr, subnameptr) int idx; char **devnameptr; - short *sd_rclassptr; /* First SD type only---needs to be updated! */ + short *s_rclassptr; /* Source (1st terminal) type only */ + short *d_rclassptr; /* Drain (2nd terminal) type only */ short *sub_rclassptr; char **subnameptr; { @@ -348,18 +356,39 @@ ExtGetDevInfo(idx, devnameptr, sd_rclassptr, sub_rclassptr, subnameptr) *subnameptr = devptr->exts_deviceSubstrateName; tmask = &devptr->exts_deviceSDTypes[0]; - *sd_rclassptr = (short)(-1); /* NO_RESCLASS */ + *s_rclassptr = (short)(-1); /* NO_RESCLASS */ for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++) { rmask = &ExtCurStyle->exts_typesByResistClass[n]; if (TTMaskIntersect(rmask, tmask)) { - *sd_rclassptr = (short)n; + *s_rclassptr = (short)n; break; } } + tmask = &devptr->exts_deviceSDTypes[1]; + if (TTMaskIsZero(tmask)) + { + /* Set source and drain resistance classes to be the same */ + *d_rclassptr = (short)n; + } + else + { + *d_rclassptr = (short)(-1); /* NO_RESCLASS */ + + for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++) + { + rmask = &ExtCurStyle->exts_typesByResistClass[n]; + if (TTMaskIntersect(rmask, tmask)) + { + *d_rclassptr = (short)n; + break; + } + } + } + tmask = &devptr->exts_deviceSubstrateTypes; *sub_rclassptr = (short)(-1); /* NO_RESCLASS */ @@ -2280,7 +2309,7 @@ ExtTechLine(sectionName, argc, argv) /* terminals */ for (i = iterm; i < iterm + nterm; i++) - DBTechNoisyNameMask(argv[iterm], &termtypes[i - iterm]); + DBTechNoisyNameMask(argv[i], &termtypes[i - iterm]); termtypes[nterm] = DBZeroTypeBits; if (nterm == 0) i++; diff --git a/lef/defRead.c b/lef/defRead.c index 18c8b274..9d41dc00 100644 --- a/lef/defRead.c +++ b/lef/defRead.c @@ -1025,6 +1025,7 @@ DefReadPins(f, rootDef, sname, oscale, total) break; } pending = FALSE; + curlayer = -1; /* Now do a search through the line for "+" entries */ /* And process each. */ diff --git a/lef/defWrite.c b/lef/defWrite.c index 4d2c9a26..a3702703 100644 --- a/lef/defWrite.c +++ b/lef/defWrite.c @@ -902,7 +902,7 @@ defNetGeometryFunc(tile, plane, defdata) /* Layer names are taken from the LEF database. */ lefName = MagicToLefTable[ttype].lefName; - ASSERT(lefName, "Valid ttype"); + if (lefName == NULL) return 0; /* Do not write types not in LEF definition */ lefType = MagicToLefTable[ttype].lefInfo; orient = GEO_EAST; @@ -1393,6 +1393,7 @@ defCountViaFunc(tile, cviadata) /* Generate a via name from the layer name and tile size */ lname = MagicToLefTable[ctype].lefName; + if (lname == NULL) return 0; /* Do not output undefined LEF layers */ TiToRect(tile, &r); /* Boundary search. WARNING: This code is quite naive. The */ @@ -1551,7 +1552,8 @@ defGetType(ttype, lefptr) while (he = HashNext(&LefInfo, &hs)) { lefl = (lefLayer *)HashGetValue(he); - if (lefl && (contact == lefl->lefClass)) + if (lefl && ((contact == lefl->lefClass) || + ((contact == CLASS_ROUTE) && (lefl->lefClass == CLASS_MASTER)))) if ((lefl->type == ttype) || (lefl->obsType == ttype)) { if (lefptr) *lefptr = lefl; @@ -1560,9 +1562,9 @@ defGetType(ttype, lefptr) } } - /* If we got here, there is no entry; use the database name */ + /* If we got here, there is no entry; return NULL. */ if (lefptr) *lefptr = (lefLayer *)NULL; - return DBTypeLongNameTbl[ttype]; + return NULL; } /* diff --git a/lef/lefCmd.c b/lef/lefCmd.c index b1336bc5..e8984361 100644 --- a/lef/lefCmd.c +++ b/lef/lefCmd.c @@ -22,6 +22,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include "windows/windows.h" #include "dbwind/dbwind.h" #include "utils/main.h" +#include "utils/utils.h" #include "textio/txcommands.h" #include "commands/commands.h" @@ -71,6 +72,10 @@ CmdLef(w, cmd) * when the FOREIGN statement * is encountered in a macro. */ + bool lefAnnotate = FALSE; /* Indicates that no celldefs should be + * created from any LEF files, which + * will be used for annotation only. + */ bool lefTopCell = TRUE; /* Indicates whether or not we * write the top-level cell to * LEF, or just the subcells. @@ -83,9 +88,16 @@ CmdLef(w, cmd) * will be output along with the * lef macro. */ - bool lefHide = FALSE; /* If TRUE, hide all details of - * the macro other than pin area - * immediately surrounding labels. + int lefHide = -1; /* If >= 0, hide all details of the macro + * other than pin area surrounding labels, + * with the indicated setback distance. + */ + bool lefTopLayer = FALSE; /* If TRUE, only output the topmost + * layer used by a pin, and make + * all layers below it obstructions. + */ + bool lefDoMaster = TRUE; /* If TRUE, output masterslice layers; + * If FALSE, ignore masterslice layers. */ bool recurse = FALSE; /* If TRUE, recurse on all subcells * during "writeall". By default, @@ -100,13 +112,16 @@ CmdLef(w, cmd) static char *cmdLefOption[] = { "read [filename] read a LEF file filename[.lef]\n" - " read [filename] -import read a LEF file; import cells from .mag files", + " read [filename] -import read a LEF file; import cells from .mag files\n", + " read [filename] -annotate read a LEF file for cell annotation only.", "write [filename] [-tech] write LEF for current cell\n" - " write [filename] -hide hide all details other than ports", + " write [filename] -hide hide all details other than ports\n", + " write [filename] -hide hide details in area set back distance ", "writeall write all cells including the top-level cell\n" " writeall -notop write all children of the top-level cell\n" " writeall -all recurse on all subcells of the top-level cell\n", - " writeall -hide hide all details other than ports", + " writeall -hide hide all details other than ports\n", + " writeall -hide [dist] hide details in area set back distance dist", "help print this help information", NULL }; @@ -171,6 +186,8 @@ CmdLef(w, cmd) { if (!strncmp(cmd->tx_argv[i], "-import", 7)) lefImport = TRUE; + else if (!strncmp(cmd->tx_argv[i], "-anno", 5)) + lefAnnotate = TRUE; else if (!strncmp(cmd->tx_argv[i], "-label", 6)) { if (is_lef) @@ -186,7 +203,7 @@ CmdLef(w, cmd) namep = cmd->tx_argv[2]; if (is_lef) - LefRead(namep, lefImport); + LefRead(namep, lefImport, lefAnnotate); else DefRead(namep, defLabelNets); break; @@ -207,14 +224,28 @@ CmdLef(w, cmd) else if (!strncmp(cmd->tx_argv[i], "-tech", 5)) lefTech = TRUE; else if (!strncmp(cmd->tx_argv[i], "-hide", 5)) - lefHide = TRUE; + { + lefHide = 0; + if ((i < (cmd->tx_argc - 1)) && + StrIsNumeric(cmd->tx_argv[i + 1])) + { + lefHide = cmdParseCoord(w, cmd->tx_argv[i + 1], + FALSE, TRUE); + i++; + } + } + else if (!strncmp(cmd->tx_argv[i], "-toplayer", 9)) + lefTopLayer = TRUE; + else if (!strncmp(cmd->tx_argv[i], "-nomaster", 9)) + lefDoMaster = FALSE; else if (!strncmp(cmd->tx_argv[i], "-all", 4)) recurse = TRUE; else goto wrongNumArgs; } else goto wrongNumArgs; } - LefWriteAll(selectedUse, lefTopCell, lefTech, lefHide, recurse); + LefWriteAll(selectedUse, lefTopCell, lefTech, lefHide, lefTopLayer, + lefDoMaster, recurse); } break; case LEF_WRITE: @@ -241,10 +272,34 @@ CmdLef(w, cmd) else if (!strncmp(cmd->tx_argv[i], "-hide", 5)) { if (is_lef) - lefHide = TRUE; + { + lefHide = 0; + if ((i < (cmd->tx_argc - 1)) && + StrIsNumeric(cmd->tx_argv[i + 1])) + { + lefHide = cmdParseCoord(w, cmd->tx_argv[i + 1], + FALSE, TRUE); + cargs--; + i++; + } + } else TxPrintf("The \"-hide\" option is only for lef write\n"); } + else if (!strncmp(cmd->tx_argv[i], "-toplayer", 9)) + { + if (is_lef) + lefTopLayer = TRUE; + else + TxPrintf("The \"-toplayer\" option is only for lef write\n"); + } + else if (!strncmp(cmd->tx_argv[i], "-nomaster", 9)) + { + if (is_lef) + lefDoMaster = FALSE; + else + TxPrintf("The \"-nomaster\" option is only for lef write\n"); + } else if (!strncmp(cmd->tx_argv[i], "-units", 5)) { if (is_lef) @@ -284,7 +339,7 @@ CmdLef(w, cmd) DefWriteCell(selectedUse->cu_def, namep, allSpecial, units); else LefWriteCell(selectedUse->cu_def, namep, selectedUse->cu_def - == EditRootDef, lefTech, lefHide); + == EditRootDef, lefTech, lefHide, lefTopLayer, lefDoMaster); break; case LEF_HELP: wrongNumArgs: diff --git a/lef/lefRead.c b/lef/lefRead.c index 22346bdb..5c55c143 100644 --- a/lef/lefRead.c +++ b/lef/lefRead.c @@ -1568,19 +1568,40 @@ LefReadPin(lefMacro, f, pinname, pinNum, oscale, is_imported) if (is_imported) { bool needRect = TRUE; + bool hasPort = FALSE; Label *lab; + /* Conflicting interests: One purpose of annotation */ + /* is to make ports where none existed. But if the */ + /* cell has both port and non-port labels with the */ + /* same string, then don't mess with the non-port */ + /* label. */ + + for (lab = firstlab; lab; lab = lab->lab_next) + if (lab->lab_flags & PORT_DIR_MASK) + if (!strcmp(lab->lab_text, testpin)) + { + hasPort = TRUE; + break; + } + /* Skip the port geometry but find the pin name and */ /* annotate with the use and direction. Note that */ /* there may be multiple instances of the label. */ /* However, if the label is a point label, then */ /* replace it with the geometry from the LEF file. */ - for (lab = firstlab; lab; lab = lab->lab_next) + if (hasPort == FALSE) lab = firstlab; + for (; lab; lab = lab->lab_next) { if (!strcmp(lab->lab_text, testpin)) { - if (GEO_RECTNULL(&lab->lab_rect)) + /* If there is at least one port label with this */ + /* name, then ignore all non-port labels with the */ + /* same name. */ + if ((hasPort) && (!(lab->lab_flags & PORT_DIR_MASK))) + break; + else if (GEO_RECTNULL(&lab->lab_rect)) break; else { @@ -1692,13 +1713,16 @@ enum lef_macro_keys {LEF_CLASS = 0, LEF_SIZE, LEF_ORIGIN, LEF_TIMING, LEF_FOREIGN, LEF_PROPERTY, LEF_MACRO_END}; void -LefReadMacro(f, mname, oscale, importForeign) +LefReadMacro(f, mname, oscale, importForeign, doAnnotate) FILE *f; /* LEF file being read */ char *mname; /* name of the macro */ float oscale; /* scale factor um->magic units */ bool importForeign; /* Whether we should try to read * in a cell. */ + bool doAnnotate; /* If true, ignore all macros that are + * not already CellDefs. + */ { CellDef *lefMacro; HashEntry *he; @@ -1743,6 +1767,12 @@ LefReadMacro(f, mname, oscale, importForeign) lefMacro = DBCellLookDef(newname); if (lefMacro == NULL) { + if (doAnnotate) + { + /* Ignore any macro that does not correspond to an existing cell */ + LefSkipSection(f, "MACRO"); + return; + } lefMacro = lefFindCell(newname); DBCellClearDef(lefMacro); DBCellSetAvail(lefMacro); @@ -1839,8 +1869,8 @@ origin_error: break; case LEF_SOURCE: token = LefNextToken(f, TRUE); - if (*token != '\n') - DBPropPut(lefMacro, "LEFsource", StrDup((char **)NULL, token)); + /* Ignore "SOURCE" as it is deprecated from LEF 5.6, and */ + /* magic will write LEF version 5.7. */ LefEndStatement(f); break; case LEF_SITE: @@ -2487,9 +2517,10 @@ enum lef_sections {LEF_VERSION = 0, LEF_END}; void -LefRead(inName, importForeign) +LefRead(inName, importForeign, doAnnotate) char *inName; bool importForeign; + bool doAnnotate; { FILE *f; char *filename; @@ -2713,7 +2744,7 @@ LefRead(inName, importForeign) TxPrintf("LEF file: Defines new cell %s\n", token); */ sprintf(tsave, "%.127s", token); - LefReadMacro(f, tsave, oscale, importForeign); + LefReadMacro(f, tsave, oscale, importForeign, doAnnotate); break; case LEF_END: if (LefParseEndStatement(f, "LIBRARY") == 0) diff --git a/lef/lefWrite.c b/lef/lefWrite.c index 63124498..6803f087 100644 --- a/lef/lefWrite.c +++ b/lef/lefWrite.c @@ -186,6 +186,11 @@ lefFileOpen(def, file, suffix, mode, prealfile) { if (strcmp(endp, suffix)) { + /* Try once as-is, with the given extension. That takes care */ + /* of some less-usual extensions like ".tlef". */ + if ((rfile = PaOpen(name, mode, NULL, Path, CellLibPath, prealfile)) != NULL) + return rfile; + len = endp - name; if (len > sizeof namebuf - 1) len = sizeof namebuf - 1; (void) strncpy(namebuf, name, len); @@ -256,7 +261,6 @@ lefWriteHeader(def, f, lefTech, propTable, siteTable) /* Reference version 5.7 (November 2009). */ fprintf(f, "VERSION 5.7 ;\n"); - fprintf(f, IN0 "NAMESCASESENSITIVE ON ;\n"); fprintf(f, IN0 "NOWIREEXTENSIONATPIN ON ;\n"); fprintf(f, IN0 "DIVIDERCHAR \"/\" ;\n"); fprintf(f, IN0 "BUSBITCHARS \"[]\" ;\n"); @@ -281,10 +285,13 @@ lefWriteHeader(def, f, lefTech, propTable, siteTable) } } - fprintf(f, "UNITS\n"); - fprintf(f, IN0 "DATABASE MICRONS %d ;\n", LEFdbUnits); - fprintf(f, "END UNITS\n"); - fprintf(f, "\n"); + if (lefTech) + { + fprintf(f, "UNITS\n"); + fprintf(f, IN0 "DATABASE MICRONS %d ;\n", LEFdbUnits); + fprintf(f, "END UNITS\n"); + fprintf(f, "\n"); + } HashStartSearch(&hs); nprops = 0; @@ -503,7 +510,12 @@ lefEraseGeometry(tile, cdata) ttype = otype; /* Erase the tile area out of lefFlat */ - DBErase(flatDef, &area, ttype); + /* Use DBNMPaintPlane, NOT DBErase(). This erases contacts one */ + /* plane at a time, which normally is bad, but since every plane */ + /* gets erased eventually during "lef write", this is okay. */ + /* DBErase(flatDef, &area, ttype); */ + DBNMPaintPlane(flatDef->cd_planes[lefdata->pNum], otype, &area, + DBStdEraseTbl(ttype, lefdata->pNum), NULL); return 0; } @@ -563,6 +575,25 @@ lefAccumulateArea(tile, cdata) return 0; } +/* + * ---------------------------------------------------------------------------- + * + * lefFindTopmost -- + * + * Function called to find the topmost layer used by a pin network + * + * Return 0 to keep the search going. + * ---------------------------------------------------------------------------- + */ + +int +lefFindTopmost(tile, cdata) + Tile *tile; + ClientData cdata; +{ + return 1; /* Stop processing on the first tile found */ +} + /* * ---------------------------------------------------------------------------- * @@ -630,7 +661,7 @@ lefYankGeometry(tile, cdata) while (ttype < DBNumUserLayers) { lefMagicToLefLayer = lefdata->lefMagicMap; - if (lefMagicToLefLayer[ttype].lefInfo != NULL) + if (lefMagicToLefLayer[ttype].lefName != NULL) { if (IsSplit(tile)) // Set only the side being yanked @@ -793,7 +824,7 @@ lefWriteGeometry(tile, cdata) lefdata->numWrites++; if (ttype != lefdata->lastType) - if (lefMagicToLefLayer[ttype].lefInfo != NULL) + if (lefMagicToLefLayer[ttype].lefName != NULL) { fprintf(f, IN2 "LAYER %s ;\n", lefMagicToLefLayer[ttype].lefName); @@ -1064,23 +1095,26 @@ LefWritePinHeader(f, lab) */ void -lefWriteMacro(def, f, scale, hide) +lefWriteMacro(def, f, scale, setback, toplayer, domaster) CellDef *def; /* Def for which to generate LEF output */ FILE *f; /* Output to this file */ float scale; /* Output distance units conversion factor */ - bool hide; /* If TRUE, hide all detail except pins */ + int setback; /* If >= 0, hide all detail except pins inside setback */ + bool toplayer; /* If TRUE, only output topmost layer of pins */ + bool domaster; /* If TRUE, write masterslice layers */ { bool propfound, ispwrrail; char *propvalue, *class = NULL; Label *lab, *tlab, *reflab; Rect boundary, labr; + PlaneMask pmask; SearchContext scx; CellDef *lefFlatDef; CellUse lefFlatUse, lefSourceUse; TileTypeBitMask lmask, boundmask, *lrmask, gatetypemask, difftypemask; TileType ttype; lefClient lc; - int idx, pNum, maxport, curport; + int idx, pNum, pTop, maxport, curport; char leffmt[2][10]; char *LEFtext; HashSearch hs; @@ -1102,11 +1136,27 @@ lefWriteMacro(def, f, scale, hide) lefFlatUse.cu_id = StrDup((char **)NULL, "Flattened cell"); lefFlatUse.cu_expandMask = CU_DESCEND_SPECIAL; lefFlatUse.cu_def = lefFlatDef; + lefFlatUse.cu_parent = (CellDef *)NULL; + lefFlatUse.cu_xlo = 0; + lefFlatUse.cu_ylo = 0; + lefFlatUse.cu_xhi = 0; + lefFlatUse.cu_yhi = 0; + lefFlatUse.cu_xsep = 0; + lefFlatUse.cu_ysep = 0; + lefFlatUse.cu_client = (ClientData)CLIENTDEFAULT; DBSetTrans(&lefFlatUse, &GeoIdentityTransform); lefSourceUse.cu_id = StrDup((char **)NULL, "Source cell"); lefSourceUse.cu_expandMask = CU_DESCEND_ALL; lefSourceUse.cu_def = def; + lefSourceUse.cu_parent = (CellDef *)NULL; + lefSourceUse.cu_xlo = 0; + lefSourceUse.cu_ylo = 0; + lefSourceUse.cu_xhi = 0; + lefSourceUse.cu_yhi = 0; + lefSourceUse.cu_xsep = 0; + lefSourceUse.cu_ysep = 0; + lefSourceUse.cu_client = (ClientData)CLIENTDEFAULT; DBSetTrans(&lefSourceUse, &GeoIdentityTransform); scx.scx_use = &lefSourceUse; @@ -1132,6 +1182,7 @@ lefWriteMacro(def, f, scale, hide) TTMaskZero(&lc.rmask); TTMaskZero(&boundmask); TTMaskZero(&lmask); + pmask = 0; /* Any layer which has a port label attached to it should by */ /* necessity be considered a routing layer. Usually this will not */ @@ -1145,7 +1196,9 @@ lefWriteMacro(def, f, scale, hide) while (he = HashNext(&LefInfo, &hs)) { lefLayer *lefl = (lefLayer *)HashGetValue(he); - if (lefl && (lefl->lefClass == CLASS_ROUTE || lefl->lefClass == CLASS_VIA)) + if (lefl && (lefl->lefClass == CLASS_ROUTE || lefl->lefClass == CLASS_VIA + || (domaster && lefl->lefClass == CLASS_MASTER))) + { if (lefl->type != -1) { TTMaskSetType(&lc.rmask, lefl->type); @@ -1160,6 +1213,10 @@ lefWriteMacro(def, f, scale, hide) if (lefl->obsType != -1) TTMaskSetType(&lc.rmask, lefl->obsType); + if (domaster && lefl->lefClass == CLASS_MASTER) + pmask |= DBTypePlaneMaskTbl[lefl->type]; + } + if (lefl && (lefl->lefClass == CLASS_BOUND)) if (lefl->type != -1) TTMaskSetType(&boundmask, lefl->type); @@ -1194,10 +1251,6 @@ lefWriteMacro(def, f, scale, hide) fprintf(f, IN0 "CLASS BLOCK ;\n"); } - propvalue = (char *)DBPropGet(def, "LEFsource", &propfound); - if (propfound) - fprintf(f, IN0 "SOURCE %s ;\n", propvalue); - fprintf(f, IN0 "FOREIGN %s ;\n", def->cd_name); /* If a boundary class was declared in the LEF section, then use */ @@ -1231,6 +1284,14 @@ lefWriteMacro(def, f, scale, hide) &boundary.r_ybot, &boundary.r_xtop, &boundary.r_ytop); } + /* Check if (boundry less setback) is degenerate. If so, then */ + /* there is no effect of the "-hide" option. */ + if (setback > 0) + { + if ((boundary.r_xtop - boundary.r_xbot) < (2 * setback)) setback = -1; + if ((boundary.r_ytop - boundary.r_ybot) < (2 * setback)) setback = -1; + } + /* Write position and size information */ /* Note: Using "0.0 - X" prevents fprintf from generating "negative */ /* zeros" in the output. */ @@ -1355,7 +1416,7 @@ lefWriteMacro(def, f, scale, hide) scx.scx_area = labr; SelectClear(); - if (hide) + if (setback == 0) { Rect carea; labelLinkedList *newlll; @@ -1379,6 +1440,18 @@ lefWriteMacro(def, f, scale, hide) newlll->lll_next = lll; lll = newlll; } + else if (setback > 0) + { + Rect carea; + + /* For -hide with setback, select the entire net and then */ + /* remove the part inside the setback area. Note that this */ + /* does not check if this causes the label to disappear. */ + + SelectNet(&scx, lab->lab_type, 0, NULL, FALSE); + GEO_EXPAND(&boundary, -setback, &carea); + SelRemoveArea(&carea, &DBAllButSpaceAndDRCBits); + } else SelectNet(&scx, lab->lab_type, 0, NULL, FALSE); @@ -1410,6 +1483,17 @@ lefWriteMacro(def, f, scale, hide) if (antdiffarea > 0) break; } + if (toplayer) + { + for (pTop = DBNumPlanes - 1; pTop >= PL_TECHDEPBASE; pTop--) + { + if (DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pTop], + &TiPlaneRect, &DBAllButSpaceAndDRCBits, + lefFindTopmost, (ClientData)NULL) == 1) + break; + } + } + // For all geometry in the selection, write LEF records, // and mark the corresponding tiles in lefFlatDef as // visited. @@ -1418,6 +1502,22 @@ lefWriteMacro(def, f, scale, hide) lc.lastType = TT_SPACE; for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) { + /* Option to output only the topmost layer of a network */ + /* as PIN geometry. All layers below it are considered */ + /* obstructions. Masterslice layers are considered an */ + /* exception, as they are often needed for ensuring */ + /* connectivity between power supply and wells. */ + + if (toplayer && (pNum != pTop)) + { + if (domaster & (pmask != 0)) + { + if (!PlaneMaskHasPlane(pmask, pNum)) + continue; + } + else continue; + } + lc.pNum = pNum; DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pNum], &TiPlaneRect, &DBAllButSpaceAndDRCBits, @@ -1516,7 +1616,7 @@ lefWriteMacro(def, f, scale, hide) /* Restrict to routing planes only */ - if (hide) + if (setback >= 0) { /* If details of the cell are to be hidden, then first paint */ /* all route layers with an obstruction rectangle the size of */ @@ -1536,6 +1636,7 @@ lefWriteMacro(def, f, scale, hide) for (ttype = TT_TECHDEPBASE; ttype < DBNumTypes; ttype++) if (TTMaskHasType(&lmask, ttype)) { + Rect r; layerBound.r_xbot = layerBound.r_xtop = 0; for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) if (TTMaskHasType(&DBPlaneTypes[pNum], ttype)) @@ -1545,6 +1646,10 @@ lefWriteMacro(def, f, scale, hide) lefGetBound, (ClientData)(&layerBound)); } + /* Clip layerBound to setback boundary */ + GEO_EXPAND(&boundary, -setback, &r); + GeoClip(&layerBound, &r); + DBPaint(lc.lefYank, &layerBound, ttype); } @@ -1568,6 +1673,43 @@ lefWriteMacro(def, f, scale, hide) DBErase(lc.lefYank, &thislll->lll_area, lab->lab_type); freeMagic(thislll); } + + if (setback > 0) + { + /* For -hide with setback, yank everything in the area outside */ + /* the setback. */ + + for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) + { + Rect r; + lc.pNum = pNum; + + r = def->cd_bbox; + r.r_ytop = boundary.r_ybot + setback; + DBSrPaintArea((Tile *)NULL, lefFlatDef->cd_planes[pNum], + &r, &DBAllButSpaceAndDRCBits, + lefYankGeometry, (ClientData) &lc); + r = def->cd_bbox; + r.r_ybot = boundary.r_ytop - setback; + DBSrPaintArea((Tile *)NULL, lefFlatDef->cd_planes[pNum], + &r, &DBAllButSpaceAndDRCBits, + lefYankGeometry, (ClientData) &lc); + r = def->cd_bbox; + r.r_ybot = boundary.r_ybot + setback; + r.r_ytop = boundary.r_ytop - setback; + r.r_xtop = boundary.r_xbot + setback; + DBSrPaintArea((Tile *)NULL, lefFlatDef->cd_planes[pNum], + &r, &DBAllButSpaceAndDRCBits, + lefYankGeometry, (ClientData) &lc); + r = def->cd_bbox; + r.r_ybot = boundary.r_ybot + setback; + r.r_ytop = boundary.r_ytop - setback; + r.r_xbot = boundary.r_xtop - setback; + DBSrPaintArea((Tile *)NULL, lefFlatDef->cd_planes[pNum], + &r, &DBAllButSpaceAndDRCBits, + lefYankGeometry, (ClientData) &lc); + } + } } else { @@ -1590,7 +1732,7 @@ lefWriteMacro(def, f, scale, hide) lefWriteGeometry, (ClientData) &lc); /* Additional yank & write for contacts (although ignore contacts for -hide) */ - if (!hide) + if (setback < 0) { lc.lefMode = LEF_MODE_OBS_CONTACT; DBSrPaintArea((Tile *)NULL, lefFlatDef->cd_planes[pNum], @@ -1601,6 +1743,51 @@ lefWriteMacro(def, f, scale, hide) lefWriteGeometry, (ClientData) &lc); lc.lefMode = LEF_MODE_OBSTRUCT; } + else if (setback > 0) + { + Rect r; + + /* Apply only to area outside setback. */ + lc.lefMode = LEF_MODE_OBS_CONTACT; + + r = def->cd_bbox; + r.r_ytop = boundary.r_ybot + setback; + DBSrPaintArea((Tile *)NULL, lefFlatDef->cd_planes[pNum], + &r, &DBAllButSpaceAndDRCBits, + lefYankContacts, (ClientData) &lc); + DBSrPaintArea((Tile *)NULL, lc.lefYank->cd_planes[pNum], + &r, &lc.rmask, lefWriteGeometry, (ClientData) &lc); + + r = def->cd_bbox; + r.r_ybot = boundary.r_ytop - setback; + DBSrPaintArea((Tile *)NULL, lefFlatDef->cd_planes[pNum], + &r, &DBAllButSpaceAndDRCBits, + lefYankContacts, (ClientData) &lc); + DBSrPaintArea((Tile *)NULL, lc.lefYank->cd_planes[pNum], + &r, &lc.rmask, lefWriteGeometry, (ClientData) &lc); + + r = def->cd_bbox; + r.r_ybot = boundary.r_ybot + setback; + r.r_ytop = boundary.r_ytop - setback; + r.r_xtop = boundary.r_xbot + setback; + DBSrPaintArea((Tile *)NULL, lefFlatDef->cd_planes[pNum], + &r, &DBAllButSpaceAndDRCBits, + lefYankContacts, (ClientData) &lc); + DBSrPaintArea((Tile *)NULL, lc.lefYank->cd_planes[pNum], + &r, &lc.rmask, lefWriteGeometry, (ClientData) &lc); + + r = def->cd_bbox; + r.r_ybot = boundary.r_ybot + setback; + r.r_ytop = boundary.r_ytop - setback; + r.r_xbot = boundary.r_xtop - setback; + DBSrPaintArea((Tile *)NULL, lefFlatDef->cd_planes[pNum], + &r, &DBAllButSpaceAndDRCBits, + lefYankContacts, (ClientData) &lc); + DBSrPaintArea((Tile *)NULL, lc.lefYank->cd_planes[pNum], + &r, &lc.rmask, lefWriteGeometry, (ClientData) &lc); + + lc.lefMode = LEF_MODE_OBSTRUCT; + } } if (lc.numWrites > 0) @@ -1777,11 +1964,13 @@ lefGetProperties(stackItem, i, clientData) */ void -LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, recurse) +LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, lefTopLayer, lefDoMaster, recurse) CellUse *rootUse; bool writeTopCell; bool lefTech; - bool lefHide; + int lefHide; + bool lefTopLayer; + bool lefDoMaster; bool recurse; { HashTable propHashTbl, siteHashTbl; @@ -1847,11 +2036,11 @@ LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, recurse) { def->cd_client = (ClientData) 0; if (!SigInterruptPending) - lefWriteMacro(def, f, scale, lefHide); + lefWriteMacro(def, f, scale, lefHide, lefTopLayer, lefDoMaster); } /* End the LEF file */ - fprintf(f, "END LIBRARY ;\n"); + fprintf(f, "END LIBRARY\n\n"); fclose(f); StackFree(lefDefStack); @@ -1911,12 +2100,14 @@ lefDefPushFunc(use, recurse) */ void -LefWriteCell(def, outName, isRoot, lefTech, lefHide) +LefWriteCell(def, outName, isRoot, lefTech, lefHide, lefTopLayer, lefDoMaster) CellDef *def; /* Cell being written */ char *outName; /* Name of output file, or NULL. */ bool isRoot; /* Is this the root cell? */ bool lefTech; /* Output layer information if TRUE */ - bool lefHide; /* Hide detail other than pins if TRUE */ + int lefHide; /* Hide detail other than pins if >= 0 */ + bool lefTopLayer; /* Use only topmost layer of pin if TRUE */ + bool lefDoMaster; /* Write masterslice layers if TRUE */ { char *filename; FILE *f; @@ -1950,7 +2141,11 @@ LefWriteCell(def, outName, isRoot, lefTech, lefHide) HashKill(&propHashTbl); HashKill(&siteHashTbl); } - lefWriteMacro(def, f, scale, lefHide); + lefWriteMacro(def, f, scale, lefHide, lefTopLayer, lefDoMaster); + + /* End the LEF file */ + fprintf(f, "END LIBRARY\n\n"); + fclose(f); } diff --git a/plot/plotCmd.c b/plot/plotCmd.c index aa710ad0..f59a8821 100644 --- a/plot/plotCmd.c +++ b/plot/plotCmd.c @@ -98,6 +98,7 @@ CmdPlot(w, cmd) int iwidth, scale; #ifdef HAVE_LIBCAIRO + int flags; extern void GrTCairoPlotSVG(); #endif @@ -175,11 +176,11 @@ CmdPlot(w, cmd) if ((!ToolGetBox(&boxRootDef, &scx.scx_area)) || (scx.scx_use->cu_def != boxRootDef)) { - TxError("The box and cursor must appear in the same window\n"); - TxError(" for plotting. The box indicates the area to\n"); - TxError(" plot, and the cursor's window tells which\n"); - TxError(" cells are expanded and unexpanded).\n"); - return; + /* If no box is specified, then use the cell in the layout */ + /* window, and plot the entire cell using the cell bounding */ + /* box as the area to plot. */ + + scx.scx_area = scx.scx_use->cu_def->cd_bbox; } scx.scx_trans = GeoIdentityTransform; mask = crec->dbw_visibleLayers; @@ -271,7 +272,15 @@ CmdPlot(w, cmd) cmdPlotOption[PLOTSVG]); return; } + flags = window->w_flags; + /* In case this is called from a non-GUI wrapper window, remove */ + /* the window border widgets from the rendered display. */ + window->w_flags &= ~(WIND_SCROLLABLE | WIND_SCROLLBARS | WIND_CAPTION + | WIND_BORDER); + DBWHLRemoveClient(DBWDrawBox); // Prevent drawing the cursor box GrTCairoPlotSVG(cmd->tx_argv[2], window); + DBWHLAddClient(DBWDrawBox); // Restore drawing the cursor box + window->w_flags = flags; return; #endif diff --git a/scripts/defs.mak.in b/scripts/defs.mak.in index 0404e2ee..45d65f53 100755 --- a/scripts/defs.mak.in +++ b/scripts/defs.mak.in @@ -56,7 +56,7 @@ RM = rm -f CP = cp AR = ar ARFLAGS = crv -LINK = ld -r +LINK = @LD@ -r LD = @LD@ MCPP = @MCPP@ MSED = @MSED@ diff --git a/tcltk/readspice.tcl b/tcltk/readspice.tcl index 66e116ed..dda21d63 100644 --- a/tcltk/readspice.tcl +++ b/tcltk/readspice.tcl @@ -57,8 +57,14 @@ proc readspice {netfile} { set fdata {} set lastline "" while {[gets $fnet line] >= 0} { - if {[lindex $line 0] != "*"} { - if {[lindex $line 0] == "+"} { + # Handle CDL format *.PININFO (convert to .PININFO ...) + if {$is_cdl && ([string range $line 0 1] == "*.")} { + if {[string tolower [string range $line 2 8]] == "pininfo"} { + set line [string range $line 1 end] + } + } + if {[string index $line 0] != "*"} { + if {[string index $line 0] == "+"} { if {[string range $line end end] != " "} { append lastline " " } @@ -74,6 +80,9 @@ proc readspice {netfile} { # Now look for all ".subckt" lines + set cell "" + set status 0 + suspendall foreach line $fdata { set ftokens [split $line] @@ -90,12 +99,36 @@ proc readspice {netfile} { if {$keyword == ".subckt"} { set cell [lindex $ftokens 1] set status [cellname list exists $cell] + set pindict [dict create] if {$status != 0} { load $cell box values 0 0 0 0 set n 1 set changed false + + # Make sure pins aren't duplicated by first moving all pin + # indexes above the number of pins to check. + + set npins [expr {[llength $ftokens] - 1}] + set highport [port last] + set outport $highport + if {$outport < $npins} {set outport $npins} + set p [port first] + while {$p != -1 && $p <= $highport} { + set p1 [port $p next] + set testpin [port $p name] + if {$testpin != ""} { + port $p index $outport + incr outport + } + set p $p1 + } + foreach pin [lrange $ftokens 2 end] { + # If "=" is in the name, then we have finished the pins + # and are looking at parameters, and so parsing is done. + if {[string first = $pin] >= 0} {break} + # Tcl "split" will not group spaces and tabs but leaves # empty strings. if {$pin == {}} {continue} @@ -113,9 +146,6 @@ proc readspice {netfile} { set testpin $pin set pinidx [port $testpin index] - # Test a few common delimiter translations. This list - # is by no means exhaustive. - if {$pinidx == ""} { set testpin [string map {\[ < \] >]} $pin] set pinidx [port $testpin index] @@ -125,15 +155,37 @@ proc readspice {netfile} { set pinidx [port $testpin index] } - # Also test some case sensitivity issues (also not exhaustive) + # Handle issues with case insensitivity by getting + # a list of ports and doing a case comparison. if {$pinidx == ""} { - set testpin [string tolower $pin] - set pinidx [port $testpin index] + set highport [port last] + for {set p 0} {$p <= $highport} {incr p} { + set testpin [port $p name] + if {[string tolower $testpin] == [string tolower $pin]} { + set pinidx [port $testpin index] + break + } + } } + + # Finally, check if there is a bare label that matches the + # port name. If so, convert it into a port + if {$pinidx == ""} { - set testpin [string toupper $pin] - set pinidx [port $testpin index] + select top cell + select area labels + set all [lindex [what -list] 1] + select clear + foreach labrec $all { + set testpin [lindex $labrec 0] + if {[string tolower $testpin] == [string tolower $pin]} { + goto $testpin + set pinidx -1 + port make $n + break + } + } } if {$pinidx != ""} { @@ -142,6 +194,8 @@ proc readspice {netfile} { set changed true } incr n + # Record the original and modified pin names + dict set pindict $pin $testpin } else { set layer [goto $pin] if {$layer != ""} { @@ -149,6 +203,8 @@ proc readspice {netfile} { incr n set changed true } + # Record the pin name as unmodified + dict set pindict $pin $pin } } if {$changed} { @@ -157,6 +213,26 @@ proc readspice {netfile} { } else { puts stdout "Cell $cell in netlist has not been loaded." } + } elseif {$keyword == ".pininfo"} { + if {($cell != "") && ($status != 0)} { + foreach pininfo [lrange $ftokens 1 end] { + set infopair [split $pininfo :] + set pinname [lindex $infopair 0] + set pindir [lindex $infopair 1] + if {![catch {set pin [dict get $pindict $pinname]}]} { + case $pindir { + B {port $pin class inout} + I {port $pin class input} + O {port $pin class output} + } + } elseif {$pinname != ""} { + puts stderr ".PININFO error: Pin $pinname not found." + } + } + } + } elseif {$keyword == ".ends"} { + set cell "" + set status 0 } } resumeall diff --git a/tcltk/wrapper.tcl b/tcltk/wrapper.tcl index cacc5b27..5bba211a 100644 --- a/tcltk/wrapper.tcl +++ b/tcltk/wrapper.tcl @@ -614,6 +614,10 @@ proc magic::repaintwrapper { win } { proc magic::boxview {win {cmdstr ""}} { if {${cmdstr} == "exists" || ${cmdstr} == "help" || ${cmdstr} == ""} { # do nothing. . . informational only, no change to the box + } elseif {${cmdstr} == "remove"} { + set framename [winfo parent $win] + if {$framename == "."} {return} + ${framename}.titlebar.pos configure -text "no box" } elseif {[info level] <= 1} { # For NULL window, find all layout windows and apply update to each. if {$win == {}} { diff --git a/utils/main.c b/utils/main.c index 42bd033f..55988732 100644 --- a/utils/main.c +++ b/utils/main.c @@ -940,7 +940,7 @@ mainInitFinal() } } - if (getcwd(cwd, 512) == NULL || strcmp(cwd, home)) + if (getcwd(cwd, 512) == NULL || strcmp(cwd, home) || (RCFileName[0] == '/')) { /* Read in the .magicrc file from the current directory, if */ /* different from HOME. */ @@ -1153,7 +1153,7 @@ mainInitFinal() break; #ifdef LEF_MODULE case FN_LEF_FILE: - LefRead(temporary->fn, FALSE); + LefRead(temporary->fn, FALSE, FALSE); break; case FN_DEF_FILE: DefRead(temporary->fn, FALSE); diff --git a/utils/malloc.c b/utils/malloc.c index 965d6893..7bc17d60 100644 --- a/utils/malloc.c +++ b/utils/malloc.c @@ -74,8 +74,16 @@ static char *freeDelayedItem = NULL; #define MallocRoutine(a) ckalloc(a) #define FreeRoutine(a) ckfree(a) #else -#define MallocRoutine(a) Tcl_Alloc(a) -#define FreeRoutine(a) Tcl_Free(a) +/* DO NOT USE: Tcl_Alloc is defined with argument (unsigned int) NOT + * (size_t) and therefore limits memory allocation to the size of a + * 32-bit integer. Just use the normal malloc() and free(). Left as-is + * with TCL_MEM_DEBUG with the caveat that one should not use this to + * debug a huge design. Valgrind works better anyway. + */ +/* #define MallocRoutine(a) Tcl_Alloc(a) */ +/* #define FreeRoutine(a) Tcl_Free(a) */ +#define MallocRoutine(a) malloc(a) +#define FreeRoutine(a) free(a) #endif #else #define MallocRoutine(a) malloc(a) diff --git a/windows/windCmdAM.c b/windows/windCmdAM.c index b8c96ca6..ecf784f1 100644 --- a/windows/windCmdAM.c +++ b/windows/windCmdAM.c @@ -1104,7 +1104,7 @@ windDoMacro(w, cmd, interactive) if (interactive && !cMacro->interactive) continue; if (do_help) - cp = cMacro->helptext; + cp = (cMacro->helptext == NULL) ? cMacro->macrotext : cMacro->helptext; else cp = cMacro->macrotext; @@ -1135,10 +1135,11 @@ windDoMacro(w, cmd, interactive) else { if (cMacro->interactive) - TxPrintf("Interactive macro '%s' contains \"%s\"\n", - cn, cp); + TxPrintf("Interactive macro '%s' %s \"%s\"\n", + cn, (do_help) ? "" : "contains", cp); else - TxPrintf("Macro '%s' contains \"%s\"\n", cn, cp); + TxPrintf("Macro '%s' %s \"%s\"\n", + cn, (do_help) ? "" : "contains", cp); } freeMagic(cn); any = TRUE;