From 8519d2f13c07c1244a19bc63711b059e07887f6a Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 25 Jun 2020 20:59:44 -0400 Subject: [PATCH 01/72] Corrected the "macro" command so that if no help text has been given for the key bindings, then the key bindings themselves will be printed when "macro help" is run, and not just empty strings. --- VERSION | 2 +- windows/windCmdAM.c | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/VERSION b/VERSION index 3bebc709..9dc2a91e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.27 +8.3.28 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; From 99a0575501abc14bd143ece2d03208bd1229b0ea Mon Sep 17 00:00:00 2001 From: Dan Moore Date: Wed, 24 Jun 2020 12:22:04 -0700 Subject: [PATCH 02/72] Changed the end-of-line comment character from ';' to '$' when formatting a SPICE netlist for NGSPICE. This is the documented character as described in the NGSPICE User Manual, section 2.2.4 End-of-line comments --- ext2spice/ext2hier.c | 10 +++++----- ext2spice/ext2spice.c | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ext2spice/ext2hier.c b/ext2spice/ext2hier.c index cec86c72..91526c73 100644 --- a/ext2spice/ext2hier.c +++ b/ext2spice/ext2hier.c @@ -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; @@ -1254,7 +1254,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 +1262,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) { diff --git a/ext2spice/ext2spice.c b/ext2spice/ext2spice.c index 6fcc89ac..310b668e 100644 --- a/ext2spice/ext2spice.c +++ b/ext2spice/ext2spice.c @@ -2328,7 +2328,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 +2336,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; @@ -3203,7 +3203,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 +3211,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) { From b36d5cce3c67cb84231104947a1312a76578b081 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sat, 27 Jun 2020 19:50:43 -0400 Subject: [PATCH 03/72] Updated VERSION along with the pull request merge for changing the in-line comment character recognized by ngspice (which has changed since the version of the documentation I had, which supported the use of the character ';', which was what magic was using). --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 9dc2a91e..5f5e2f70 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.28 +8.3.29 From eab0fe770d23de62ab8d5019b4a87d4d41f2b0ff Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sat, 27 Jun 2020 21:46:53 -0400 Subject: [PATCH 04/72] Corrected the readspice script to treat the input line as a string and not a character list when checking the first character of a SPICE netlist for a comment or continuation character. --- tcltk/readspice.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tcltk/readspice.tcl b/tcltk/readspice.tcl index 66e116ed..6357eab3 100644 --- a/tcltk/readspice.tcl +++ b/tcltk/readspice.tcl @@ -57,8 +57,8 @@ proc readspice {netfile} { set fdata {} set lastline "" while {[gets $fnet line] >= 0} { - if {[lindex $line 0] != "*"} { - if {[lindex $line 0] == "+"} { + if {[string index $line 0] != "*"} { + if {[string index $line 0] == "+"} { if {[string range $line end end] != " "} { append lastline " " } From 0b17c4d168718ca58e0845e65ea821426c03e8f7 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 29 Jun 2020 08:25:55 -0400 Subject: [PATCH 05/72] Not sure why the temporary copy of DRCtech.c was not removed in previous commits, but am now doing 'git rm' on it to make sure it stays banished. --- DRCtech.c | 4094 ----------------------------------------------------- 1 file changed, 4094 deletions(-) delete mode 100644 DRCtech.c 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; -} - From f6de28c760252914fb5fe1822cfdeadba746ad6b Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 29 Jun 2020 11:07:43 -0400 Subject: [PATCH 06/72] Corrected defs.mak.in to use @LD@ passed from the configure script instead of hard-coding "ld" for the LINK variable. --- VERSION | 2 +- scripts/defs.mak.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 5f5e2f70..593d990c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.29 +8.3.30 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@ From 6812e7cd10b56ac17d069bcbab967167709cc3e4 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 29 Jun 2020 21:13:57 -0400 Subject: [PATCH 07/72] Modified readspice to support the CDL "*.PININFO" line for annotating layouts with pin class (direction) from CDL files. --- tcltk/readspice.tcl | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tcltk/readspice.tcl b/tcltk/readspice.tcl index 6357eab3..3773aac3 100644 --- a/tcltk/readspice.tcl +++ b/tcltk/readspice.tcl @@ -57,6 +57,12 @@ proc readspice {netfile} { set fdata {} set lastline "" while {[gets $fnet 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] != " "} { @@ -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,6 +99,7 @@ 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 @@ -142,6 +152,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 +161,8 @@ proc readspice {netfile} { incr n set changed true } + # Record the pin name as unmodified + dict set pindict $pin $pin } } if {$changed} { @@ -157,6 +171,23 @@ 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] + set pin [dict get $pindict $pinname] + case $pindir { + B {port $pin class inout} + I {port $pin class input} + O {port $pin class output} + } + } + } + } elseif {$keyword == ".ends"} { + set cell "" + set status 0 } } resumeall From 52dadcff08bb05406e7c26df3b2b4b699a8504a1 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 30 Jun 2020 16:07:31 -0400 Subject: [PATCH 08/72] Modified the "plot svg" command to remove the window trimmings (scrollbar, title bar, etc.) from the output if the command is called from the non-GUI-wrapper environment (where the border area is part of the rendered output). This was required due to an unsolved bug in which calling magic to write SVG output from the wrapper in some pathological case exposed a Tk bug that caused the Tk grid manager to infinite loop, filling memory without limit. --- VERSION | 2 +- plot/plotCmd.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 593d990c..2e217430 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.30 +8.3.31 diff --git a/plot/plotCmd.c b/plot/plotCmd.c index aa710ad0..e77f2480 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 @@ -271,7 +272,13 @@ 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); GrTCairoPlotSVG(cmd->tx_argv[2], window); + window->w_flags = flags; return; #endif From 14251b797fa45f4ff9706bedeb488fd642b796b7 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 30 Jun 2020 18:05:12 -0400 Subject: [PATCH 09/72] Corrected readspice.tcl script to ignore CDL parameters in the subcircuit I/O list, and to not fail with an error if something in the PININFO line cannot be found in the layout (just prints an error message instead). --- tcltk/readspice.tcl | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/tcltk/readspice.tcl b/tcltk/readspice.tcl index 3773aac3..aee24037 100644 --- a/tcltk/readspice.tcl +++ b/tcltk/readspice.tcl @@ -106,6 +106,10 @@ proc readspice {netfile} { set n 1 set changed false 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} @@ -177,11 +181,14 @@ proc readspice {netfile} { set infopair [split $pininfo :] set pinname [lindex $infopair 0] set pindir [lindex $infopair 1] - set pin [dict get $pindict $pinname] - case $pindir { - B {port $pin class inout} - I {port $pin class input} - O {port $pin class output} + 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." } } } From 2be23d886d0e69e108d695339f154cc40dea6578 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sun, 5 Jul 2020 17:39:00 -0400 Subject: [PATCH 10/72] Test. --- test | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test diff --git a/test b/test new file mode 100644 index 00000000..e69de29b From d577439be94fc25003bd8d9254192d3dda68bad4 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sun, 5 Jul 2020 17:39:24 -0400 Subject: [PATCH 11/72] Test again. --- test | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 test diff --git a/test b/test deleted file mode 100644 index e69de29b..00000000 From 72b4053774c4534503e4642bd53426b2c3ab97ba Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sun, 5 Jul 2020 21:38:28 -0400 Subject: [PATCH 12/72] Updated VERSION to force an update on the system; no changes were made. --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 2e217430..e3f7510e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.31 +8.3.32 From 7a8e6352a31942eef3ea9eef2a90dafb44155fd7 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 15 Jul 2020 17:29:56 -0400 Subject: [PATCH 13/72] Two changes to "lef write": (1) Added support for generating output for geometry on MASTERSLICE layers (which was inadvertantly broken), and (2) Added option "lef write -toplayer", which outputs pin geometry only for the topmost layer belonging to a pin, with connected layers underneath being designated as obstructions. --- VERSION | 2 +- lef/defWrite.c | 10 ++++---- lef/lefCmd.c | 18 +++++++++++++-- lef/lefWrite.c | 63 ++++++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 77 insertions(+), 16 deletions(-) diff --git a/VERSION b/VERSION index e3f7510e..2c358a89 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.32 +8.3.33 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..f4c9bd83 100644 --- a/lef/lefCmd.c +++ b/lef/lefCmd.c @@ -87,6 +87,10 @@ CmdLef(w, cmd) * the macro other than pin area * immediately surrounding labels. */ + bool lefTopLayer = False; /* If TRUE, only output the topmost + * layer used by a pin, and make + * all layers below it obstructions. + */ bool recurse = FALSE; /* If TRUE, recurse on all subcells * during "writeall". By default, * only the immediate children of the @@ -208,13 +212,16 @@ CmdLef(w, cmd) lefTech = TRUE; else if (!strncmp(cmd->tx_argv[i], "-hide", 5)) lefHide = TRUE; + else if (!strncmp(cmd->tx_argv[i], "-toplayer", 9)) + lefTopLayer = TRUE; 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, + recurse); } break; case LEF_WRITE: @@ -245,6 +252,13 @@ CmdLef(w, cmd) 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], "-units", 5)) { if (is_lef) @@ -284,7 +298,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); break; case LEF_HELP: wrongNumArgs: diff --git a/lef/lefWrite.c b/lef/lefWrite.c index 63124498..848f7ab6 100644 --- a/lef/lefWrite.c +++ b/lef/lefWrite.c @@ -503,7 +503,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 +568,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 +654,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 +817,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,11 +1088,12 @@ LefWritePinHeader(f, lab) */ void -lefWriteMacro(def, f, scale, hide) +lefWriteMacro(def, f, scale, hide, toplayer) 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 */ + bool toplayer; /* If TRUE, only output topmost layer of pins */ { bool propfound, ispwrrail; char *propvalue, *class = NULL; @@ -1080,7 +1105,7 @@ lefWriteMacro(def, f, scale, hide) 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; @@ -1410,6 +1435,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 +1454,11 @@ 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. */ + if (toplayer) pNum = pTop; + lc.pNum = pNum; DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pNum], &TiPlaneRect, &DBAllButSpaceAndDRCBits, @@ -1458,6 +1499,8 @@ lefWriteMacro(def, f, scale, hide) &TiPlaneRect, &lc.rmask, lefWriteGeometry, (ClientData) &lc); lc.lefMode = LEF_MODE_PORT; + + if (toplayer) break; /* Stop after processing topmost layer */ } DBCellClearDef(lc.lefYank); lab->lab_flags |= PORT_VISITED; @@ -1777,11 +1820,12 @@ lefGetProperties(stackItem, i, clientData) */ void -LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, recurse) +LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, lefTopLayer, recurse) CellUse *rootUse; bool writeTopCell; bool lefTech; bool lefHide; + bool lefTopLayer; bool recurse; { HashTable propHashTbl, siteHashTbl; @@ -1847,7 +1891,7 @@ LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, recurse) { def->cd_client = (ClientData) 0; if (!SigInterruptPending) - lefWriteMacro(def, f, scale, lefHide); + lefWriteMacro(def, f, scale, lefHide, lefTopLayer); } /* End the LEF file */ @@ -1911,12 +1955,13 @@ lefDefPushFunc(use, recurse) */ void -LefWriteCell(def, outName, isRoot, lefTech, lefHide) +LefWriteCell(def, outName, isRoot, lefTech, lefHide, lefTopLayer) 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 */ + bool lefTopLayer; /* Use only topmost layer of pin if TRUE */ { char *filename; FILE *f; @@ -1950,7 +1995,7 @@ LefWriteCell(def, outName, isRoot, lefTech, lefHide) HashKill(&propHashTbl); HashKill(&siteHashTbl); } - lefWriteMacro(def, f, scale, lefHide); + lefWriteMacro(def, f, scale, lefHide, lefTopLayer); fclose(f); } From 838c9b840d17b3832ebc5fa60845a650fc0226f9 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 16 Jul 2020 08:55:46 -0400 Subject: [PATCH 14/72] Added a "calma library" command option, to generate a GDS library from the subcircuits of a top-level layout without also writing the top level. --- VERSION | 2 +- calma/CalmaWrite.c | 11 +++++++---- calma/calma.h | 1 + commands/CmdCD.c | 40 +++++++++++++++++++++++++++++++--------- 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/VERSION b/VERSION index 2c358a89..04e6cffe 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.33 +8.3.34 diff --git a/calma/CalmaWrite.c b/calma/CalmaWrite.c index 4ef116c3..b2815e0b 100644 --- a/calma/CalmaWrite.c +++ b/calma/CalmaWrite.c @@ -53,6 +53,7 @@ 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 */ @@ -328,7 +329,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 +742,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; @@ -907,7 +909,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..a7e7ebb7 100644 --- a/calma/calma.h +++ b/calma/calma.h @@ -28,6 +28,7 @@ extern bool CalmaSubcellPolygons; extern bool CalmaSubcellPaths; extern bool CalmaDoLabels; +extern bool CalmaDoLibrary; extern bool CalmaDoLower; extern bool CalmaMergeTiles; extern bool CalmaFlattenArrays; diff --git a/commands/CmdCD.c b/commands/CmdCD.c index aebc0b4e..3eb439d5 100644 --- a/commands/CmdCD.c +++ b/commands/CmdCD.c @@ -95,15 +95,16 @@ bool cmdDumpParseArgs(); #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_LIBRARY 7 +#define CALMA_LOWER 8 +#define CALMA_MERGE 9 +#define CALMA_READ 10 +#define CALMA_READONLY 11 +#define CALMA_RESCALE 12 +#define CALMA_WARNING 13 +#define CALMA_WRITE 14 +#define CALMA_POLYS 15 +#define CALMA_PATHS 16 #define CALMA_WARN_HELP CIF_WARN_END /* undefined by CIF module */ @@ -132,6 +133,7 @@ CmdCalma(w, cmd) "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 +229,26 @@ 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_CONTACTS: if (cmd->tx_argc == 2) { From 1a774e92d1e9283d9557fcf301024e5cbd2b2c80 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 17 Jul 2020 12:38:21 -0400 Subject: [PATCH 15/72] Corrected an error pointed out by Sylvain Munaut in which the "plow" command fails for the tutorial tut3d cell due to a missing initialization of the cd_cellPlane record in DBCellCopyDefBody(). This was missed in the implementation of "bplane", and was not checked because the routine is only called from the "plow" command routines. --- VERSION | 2 +- database/DBcellsubr.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 04e6cffe..e1b0db6e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.34 +8.3.35 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. */ From d755e4400ac7fc26e7614b803a834940d650496b Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sat, 18 Jul 2020 15:49:20 -0400 Subject: [PATCH 16/72] Corrected an error in the the extSubtreeFunc() routine, that is supposed to pull "sticky labels" into the cumulative flattened layout. Because it failed to check for the "sticky" flag, it would copy all labels, causing extraction time to go exponential as the number of labels in the design increases. Based on this correction, the extHierConnectFunc1() routine should be able to be optimized by stopping the search for sticky labels on the first non-sticky label, since extSubtreeFunc() ensures that all sticky labels come first in the label list. --- VERSION | 2 +- extract/ExtHier.c | 7 ++++++- extract/ExtSubtree.c | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index e1b0db6e..96d5f4df 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.35 +8.3.36 diff --git a/extract/ExtHier.c b/extract/ExtHier.c index c1445273..7f7e58ec 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; diff --git a/extract/ExtSubtree.c b/extract/ExtSubtree.c index 42763f04..577295e4 100644 --- a/extract/ExtSubtree.c +++ b/extract/ExtSubtree.c @@ -766,6 +766,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; From f7b5f384612dc809410e5a2ad96c0d0d039a719e Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sun, 19 Jul 2020 17:08:51 -0400 Subject: [PATCH 17/72] Corrected an error in the last commit in which I expanded the body of a "for" loop in extract/ExtHier.c from one line to two but failed to then put braces around the whole loop. --- VERSION | 2 +- extract/ExtHier.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 96d5f4df..448d2739 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.36 +8.3.37 diff --git a/extract/ExtHier.c b/extract/ExtHier.c index 7f7e58ec..73fa39e6 100644 --- a/extract/ExtHier.c +++ b/extract/ExtHier.c @@ -291,7 +291,7 @@ extHierConnectFunc1(oneTile, ha) // node only describes a single point. for (lab = cumDef->cd_labels; lab; lab = lab->lab_next) - + { // 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; @@ -355,6 +355,7 @@ extHierConnectFunc1(oneTile, ha) #endif } + } return (0); } From 9c4fb65a582d86e5d8eb78496c2220464101a3d1 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sun, 19 Jul 2020 21:56:00 -0400 Subject: [PATCH 18/72] Corrected a problem with "lef read" that prevents it from working with non-standard extensions such as ".tlef". --- lef/lefWrite.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lef/lefWrite.c b/lef/lefWrite.c index 848f7ab6..71ef906d 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); From e453f130eee28f8b1d0a0e22f1eef5d4663751fd Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sun, 19 Jul 2020 22:10:19 -0400 Subject: [PATCH 19/72] Also corrected the "lef write" output to always put "END LIBRARY" at the end of a macro output, even if it is not part of a library. According to some commercial tools, this is what is expected, even though the use of "END LIBRARY" is never explained in the LEF/DEF spec. --- lef/lefWrite.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lef/lefWrite.c b/lef/lefWrite.c index 71ef906d..a0395548 100644 --- a/lef/lefWrite.c +++ b/lef/lefWrite.c @@ -1900,7 +1900,7 @@ LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, lefTopLayer, recurse) } /* End the LEF file */ - fprintf(f, "END LIBRARY ;\n"); + fprintf(f, "END LIBRARY\n\n"); fclose(f); StackFree(lefDefStack); @@ -2001,6 +2001,10 @@ LefWriteCell(def, outName, isRoot, lefTech, lefHide, lefTopLayer) HashKill(&siteHashTbl); } lefWriteMacro(def, f, scale, lefHide, lefTopLayer); + + /* End the LEF file */ + fprintf(f, "END LIBRARY\n\n"); + fclose(f); } From ae1743e5ada3007668355f475ce0b7a1383e3c45 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 21 Jul 2020 08:40:25 -0400 Subject: [PATCH 20/72] Removed handling of LEF macro "SOURCE", which is only valid pre- version 5.6, and Magic now officially writes version 5.7. --- VERSION | 2 +- lef/lefRead.c | 4 ++-- lef/lefWrite.c | 4 ---- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/VERSION b/VERSION index 448d2739..5bec06c4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.37 +8.3.38 diff --git a/lef/lefRead.c b/lef/lefRead.c index 22346bdb..2ae6c806 100644 --- a/lef/lefRead.c +++ b/lef/lefRead.c @@ -1839,8 +1839,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: diff --git a/lef/lefWrite.c b/lef/lefWrite.c index a0395548..d1e6349a 100644 --- a/lef/lefWrite.c +++ b/lef/lefWrite.c @@ -1224,10 +1224,6 @@ lefWriteMacro(def, f, scale, hide, toplayer) 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 */ From 850df529b9951ae449a5ad543ad17a6b032e93e8 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 22 Jul 2020 12:18:47 -0400 Subject: [PATCH 21/72] Removed "NAMESCASESENSITIVE" from "lef write", since this has been deprecated since LEF version 5.6. --- VERSION | 2 +- lef/lefWrite.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 5bec06c4..fe887032 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.38 +8.3.39 diff --git a/lef/lefWrite.c b/lef/lefWrite.c index d1e6349a..2762e09c 100644 --- a/lef/lefWrite.c +++ b/lef/lefWrite.c @@ -261,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"); From 19dd5638d60cb633ecf22e4bc7e740d744cbdf92 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sat, 25 Jul 2020 12:00:18 -0400 Subject: [PATCH 22/72] Removed "UNITS \n DATABASE MICRONS" entry from all LEF file output other than the technology LEF (when given the option to dump the technology LEF information). --- VERSION | 2 +- lef/lefWrite.c | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/VERSION b/VERSION index fe887032..febc9584 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.39 +8.3.40 diff --git a/lef/lefWrite.c b/lef/lefWrite.c index 2762e09c..ed3b0021 100644 --- a/lef/lefWrite.c +++ b/lef/lefWrite.c @@ -285,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; From 13ab2c3e5951f85d5459e0a13bf4e88c08564b39 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sun, 26 Jul 2020 10:58:36 -0400 Subject: [PATCH 23/72] Modified the warning in database/DBio.c that says "Cannot open file for writing!" so that it actually tells you what is the name of the file that it is trying to write. --- VERSION | 2 +- database/DBio.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index febc9584..2997be56 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.40 +8.3.41 diff --git a/database/DBio.c b/database/DBio.c index 5272b774..8508c711 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); } From 807c33139d3af20dc8daa24fd44e745a2962e19d Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sun, 26 Jul 2020 16:25:25 -0400 Subject: [PATCH 24/72] Extended the "port" command with the option "renumber", which forces all ports in a cell to be reordered in alphabetical order, which ensures that the output of "extract" is always the same (apart from coupling capacitance, which still ends up in randomized order due to the use of hashing based on memory address followed by iterating through the hash table). --- commands/CmdLQ.c | 90 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 6 deletions(-) diff --git a/commands/CmdLQ.c b/commands/CmdLQ.c index 2c6fda11..d0aecf71 100644 --- a/commands/CmdLQ.c +++ b/commands/CmdLQ.c @@ -1196,6 +1196,28 @@ 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. + * + * ---------------------------------------------------------------------------- + */ + +int +complabel(const void *one, const void *two) +{ + Label *l1 = *((Label **)one); + Label *l2 = *((Label **)two); + return strcmp(l1->lab_text, l2->lab_text); +} + /* * ---------------------------------------------------------------------------- * @@ -1207,7 +1229,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] * @@ -1248,7 +1272,8 @@ portFindLabel(editDef, port, unique, nonEdit) #define PORT_MAKEALL 9 #define PORT_NAME 10 #define PORT_REMOVE 11 -#define PORT_HELP 12 +#define PORT_RENUMBER 12 +#define PORT_HELP 13 void CmdPort(w, cmd) @@ -1279,6 +1304,7 @@ CmdPort(w, cmd) "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 }; @@ -1437,7 +1463,8 @@ CmdPort(w, cmd) } } - if ((option != PORT_LAST) && (option != PORT_MAKEALL) && (lab == NULL)) + if ((option != PORT_LAST) && (option != PORT_MAKEALL) + && (option != PORT_RENUMBER) && (lab == NULL)) { /* Let "port remove" fail without complaining. */ if (option != PORT_REMOVE) @@ -1452,7 +1479,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)) { /* label "lab" must already be a port */ if (!(lab->lab_flags & PORT_DIR_MASK)) @@ -1466,8 +1494,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; @@ -1732,6 +1761,55 @@ CmdPort(w, cmd) editDef->cd_flags |= (CDMODIFIED | CDGETNEWSTAMP); break; + case PORT_RENUMBER: + /* Renumber ports in canonical order (by alphabetical + * order of the label text). + */ + { + 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. . . From 917d7590d31670f020e86717d6f11bd8c4355992 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 27 Jul 2020 12:10:08 -0400 Subject: [PATCH 25/72] Implemented a string truncation with ellipsis for the output to the caption line in the GUI window, which was causing problems with long filenames overrunning the string array dedicated to the caption line. Thanks to Sylvain Munaut for the patch. --- VERSION | 2 +- commands/CmdSubrs.c | 54 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/VERSION b/VERSION index 2997be56..2f376d3e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.41 +8.3.42 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); From ae3c3d7bafce0943e35301a26321021d6d243571 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 29 Jul 2020 14:13:23 -0400 Subject: [PATCH 26/72] Corrected ext2spice, which was reversing source and drain for the "msubcircuit" extraction model, which would normally not make any difference except that when source and/or drain are tagged with terminal attributes, then the source and drain are swapped with respect to what is expected in the output SPICE netlist. --- ext2spice/ext2spice.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/ext2spice/ext2spice.c b/ext2spice/ext2spice.c index 310b668e..c5a6e0b0 100644 --- a/ext2spice/ext2spice.c +++ b/ext2spice/ext2spice.c @@ -2443,11 +2443,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 +2468,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. */ From 313112329cd0d6a959e5bd38e4184f49dbcaa9dc Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 29 Jul 2020 14:16:05 -0400 Subject: [PATCH 27/72] Updated version to force new tarball and github mirror. --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 2f376d3e..a8d813b2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.42 +8.3.43 From 2e0e7af3f3c2411f54ce74276d0afd2514bbf039 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 30 Jul 2020 21:01:24 -0400 Subject: [PATCH 28/72] Corrected an error with the "slots" function that prevents slots from being generated in areas of negative coordinates when a grid limit is defined for the output style. --- VERSION | 2 +- cif/CIFgen.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index a8d813b2..49d92867 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.43 +8.3.44 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; } } From 5fb41a68c8042660006d60b45f6409b15fefc58c Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 31 Jul 2020 14:11:24 -0400 Subject: [PATCH 29/72] Modified the routine that determines contact size from the CIF rules to accomodate a method used for processes that require additional spacing between contacts for large via arrays; this requires distinguishing between large and small areas to output vias, and so requires use of "and" and "and-not" before "squares". This highlights the arbitrary nature of this routine, which probably works better getting data from cifinput, or not at all (i.e., it is used when reading LEF, but it is known that the LEF read routines would be better implemented by running input through CIFGen(). If that were done, then this problem would not come up). --- VERSION | 2 +- cif/CIFtech.c | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 49d92867..aba983b0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.44 +8.3.45 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; } } From 78fbbfa0323f2cb53784c7569c2e5581e05229e6 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 31 Jul 2020 21:45:42 -0400 Subject: [PATCH 30/72] Corrected some uninitialized variables in the "lef write" function. --- lef/lefWrite.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lef/lefWrite.c b/lef/lefWrite.c index ed3b0021..84c648a9 100644 --- a/lef/lefWrite.c +++ b/lef/lefWrite.c @@ -1134,11 +1134,27 @@ lefWriteMacro(def, f, scale, hide, toplayer) 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; From e00a9a293fc568f48b07d7cd452d5238b0c63c9e Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 31 Jul 2020 21:56:01 -0400 Subject: [PATCH 31/72] Corrected one more uninitialized variable, in ExtHard.c. --- extract/ExtHard.c | 1 + 1 file changed, 1 insertion(+) 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 */ From 0598f4edf7b9da8987e7bf3b7d6c0e15772f4b0d Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sun, 2 Aug 2020 09:37:45 -0400 Subject: [PATCH 32/72] Corrected a potential segfaulting error in which (apparently) port labels that are unnattached ("attached" to space), or possibly sticky labels without any geometry underneath, end up with a NULL node during EFBuild(). --- VERSION | 2 +- extflat/EFbuild.c | 34 +++++++++++++++++++++------------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/VERSION b/VERSION index aba983b0..cb917cf0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.45 +8.3.46 diff --git a/extflat/EFbuild.c b/extflat/EFbuild.c index c5614f98..44c9c019 100644 --- a/extflat/EFbuild.c +++ b/extflat/EFbuild.c @@ -155,23 +155,31 @@ 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++); + } + 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); From 8b05346409e2dca08202a2acadd691d14a299d6a Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 3 Aug 2020 08:18:58 -0400 Subject: [PATCH 33/72] Added an assertion in ExtCell.c to force a fault if the technology is NULL when writing a .ext file; this should help with tracking down an obscure bug. --- VERSION | 2 +- extract/ExtCell.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index cb917cf0..283b9214 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.46 +8.3.47 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); From 0a532f5721c633c62ea7b2e8accd6fd6e625ee27 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sat, 8 Aug 2020 14:02:29 -0400 Subject: [PATCH 34/72] Applied a patch from Ahmed Ghazy that corrects an error reading PINS from a DEF file that have the PLACED or FIXED property declared before LAYER. --- VERSION | 2 +- lef/defRead.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 283b9214..867d7b9f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.47 +8.3.48 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. */ From 1ee9309d1549390756ffcbcd6efe0309c951bc67 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sat, 8 Aug 2020 15:27:01 -0400 Subject: [PATCH 35/72] Fixed a long-standing but unnoticed (or unreported) error in which using the "-rcfile" switch fails if running magic from a user home directory. --- utils/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/main.c b/utils/main.c index 42bd033f..1e1c28a1 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. */ From 6c508c25b9e137804eac9db991ca327d0420f5b2 Mon Sep 17 00:00:00 2001 From: Jan Belohoubek Date: Sun, 9 Aug 2020 17:34:24 +0200 Subject: [PATCH 36/72] swapDrainSource moved into a function to encapsulate swap-related tasks; area parameters swapped according to the D/S attributes; SPICE attribute comment printf moved to the end of export function as it allows to add more device types --- ext2spice/ext2hier.c | 68 ++++++++++++++++++++++++++----------------- ext2spice/ext2spice.c | 49 +++++++++++++++++++++++++++++-- 2 files changed, 88 insertions(+), 29 deletions(-) diff --git a/ext2spice/ext2hier.c b/ext2spice/ext2hier.c index 91526c73..5b17bda0 100644 --- a/ext2spice/ext2hier.c +++ b/ext2spice/ext2hier.c @@ -439,6 +439,8 @@ subcktHierVisit(use, hierName, is_top) return subcktVisit(use, hierName, is_top); } +extern void swapDrainSource(); + /* * ---------------------------------------------------------------------------- * @@ -516,8 +518,7 @@ spcdevHierVisit(hc, dev, scale) (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); } else drain = &dev->dev_terms[2]; @@ -666,12 +667,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 +694,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. */ @@ -979,20 +986,27 @@ 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"); return 0; diff --git a/ext2spice/ext2spice.c b/ext2spice/ext2spice.c index c5a6e0b0..1c8cd1e3 100644 --- a/ext2spice/ext2spice.c +++ b/ext2spice/ext2spice.c @@ -2184,6 +2184,51 @@ 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 */ + *drain = &dev->dev_terms[1]; + *source = &dev->dev_terms[2]; + + /* swap drain/source-related parameters */ + plist = efGetDeviceParams(EFDevTypes[dev->dev_type]); + while (plist != NULL) + { + 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_name, "as")) || !(strcmp(plist->parm_name, "ps"))) + { + plist->parm_type[1] = '0' + 2; + } + else if (!(strcmp(plist->parm_name, "ad")) || !(strcmp(plist->parm_name, "pd"))) + { + plist->parm_type[1] = '0' + 1; + } + + /* move pointer */ + plist = plist->parm_next; + } +} + + /* * ---------------------------------------------------------------------------- * @@ -2263,8 +2308,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]; + /* If D/S should be swapped, also parameters must be swapped */ + swapDrainSource(dev, &source, &drain); } else drain = &dev->dev_terms[2]; From 18131e26b3d3a4fb5ba4ebfa051a8319910ea581 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sun, 9 Aug 2020 13:11:38 -0400 Subject: [PATCH 37/72] Pulled merge request from Jan Belohoubek, but corrected the problem of needing to revert parameter definitions after swapping them during a device source/drain swap. --- VERSION | 2 +- ext2spice/ext2hier.c | 13 ++++++++----- ext2spice/ext2spice.c | 33 +++++++++++++++++++-------------- ext2spice/ext2spice.h | 1 + 4 files changed, 29 insertions(+), 20 deletions(-) diff --git a/VERSION b/VERSION index 867d7b9f..a7af17d8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.48 +8.3.49 diff --git a/ext2spice/ext2hier.c b/ext2spice/ext2hier.c index 5b17bda0..dc57ce5c 100644 --- a/ext2spice/ext2hier.c +++ b/ext2spice/ext2hier.c @@ -439,8 +439,6 @@ subcktHierVisit(use, hierName, is_top) return subcktVisit(use, hierName, is_top); } -extern void swapDrainSource(); - /* * ---------------------------------------------------------------------------- * @@ -487,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; @@ -517,9 +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"))) - { + { swapDrainSource(dev, &source, &drain); - } + swapped = TRUE; + } else drain = &dev->dev_terms[2]; } @@ -1009,6 +1008,10 @@ spcdevHierVisit(hc, dev, scale) break; } fprintf(esSpiceF, "\n"); + + /* If S/D parameters were swapped, then put them back */ + if (swapped) swapDrainSource(dev, NULL, NULL); + return 0; } diff --git a/ext2spice/ext2spice.c b/ext2spice/ext2spice.c index 1c8cd1e3..f8c4b891 100644 --- a/ext2spice/ext2spice.c +++ b/ext2spice/ext2spice.c @@ -2204,24 +2204,25 @@ swapDrainSource(dev, source, drain) DevParam *plist; /* swap drain/source ordering */ - *drain = &dev->dev_terms[1]; - *source = &dev->dev_terms[2]; + if (drain) *drain = &dev->dev_terms[1]; + if (source) *source = &dev->dev_terms[2]; - /* swap drain/source-related parameters */ + /* 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) { - TxPrintf(" * param: %s; type: %c%c\n", plist->parm_name, plist->parm_type[0], plist->parm_type[1]); + // 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_name, "as")) || !(strcmp(plist->parm_name, "ps"))) - { + /* 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_name, "ad")) || !(strcmp(plist->parm_name, "pd"))) - { + + else if (!(strcmp(plist->parm_type, "a2")) || !(strcmp(plist->parm_type, "p2"))) plist->parm_type[1] = '0' + 1; - } /* move pointer */ plist = plist->parm_next; @@ -2275,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; @@ -2308,8 +2309,8 @@ spcdevVisit(dev, hc, scale, trans) (dev->dev_terms[2].dterm_attrs && !strcmp(dev->dev_terms[2].dterm_attrs, "S"))) { - /* If D/S should be swapped, also parameters must be swapped */ - swapDrainSource(dev, &source, &drain); + swapDrainSource(dev, &source, &drain); + swapped = True; } else drain = &dev->dev_terms[2]; @@ -2817,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; } diff --git a/ext2spice/ext2spice.h b/ext2spice/ext2spice.h index 1aa38067..3992ca2e 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(); From 0df5f6d0731024da457eeb42cb88725d93572920 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 11 Aug 2020 16:50:26 -0400 Subject: [PATCH 38/72] Provisionally switched the memory allocation definitions away from Tcl_Alloc() and Tcl_Free() because Tcl_Alloc() uses (unsigned int) for the argument type and therefore limits memory allocations to what can fit in 32 bits. Using the system malloc(size_t) should not cause any issues. --- VERSION | 2 +- utils/malloc.c | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index a7af17d8..e6246dae 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.49 +8.3.50 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) From 9c1c365a5ebd05c0fae7d40fea3b6b0c546d30e9 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 1 Sep 2020 17:16:22 -0400 Subject: [PATCH 39/72] Added new command options "port first" and "port next" to make it easier to scan through a cell's ports. Used that capability in the "readspice" script to handle case sensitivity problems, and to find labels that are not ports and force them to be ports to match the reference netlist. --- VERSION | 2 +- commands/CmdLQ.c | 67 +++++++++++++++++++++++++++++++++++++-------- database/DBio.c | 10 +++++++ tcltk/readspice.tcl | 54 ++++++++++++++++++++++++++++++------ 4 files changed, 112 insertions(+), 21 deletions(-) diff --git a/VERSION b/VERSION index e6246dae..8f6ad577 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.50 +8.3.51 diff --git a/commands/CmdLQ.c b/commands/CmdLQ.c index d0aecf71..9af414e1 100644 --- a/commands/CmdLQ.c +++ b/commands/CmdLQ.c @@ -1267,13 +1267,15 @@ complabel(const void *one, const void *two) #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_RENUMBER 12 -#define PORT_HELP 13 +#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) @@ -1282,7 +1284,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; @@ -1299,6 +1301,8 @@ 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", @@ -1440,7 +1444,7 @@ 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); @@ -1463,8 +1467,9 @@ CmdPort(w, cmd) } } - if ((option != PORT_LAST) && (option != PORT_MAKEALL) - && (option != PORT_RENUMBER) && (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) @@ -1480,7 +1485,7 @@ CmdPort(w, cmd) if ((option != PORT_MAKE) && (option != PORT_MAKEALL) && (option != PORT_EXISTS) && (option != PORT_RENUMBER) - && (option != PORT_LAST)) + && (option != PORT_LAST) && (option != PORT_FIRST)) { /* label "lab" must already be a port */ if (!(lab->lab_flags & PORT_DIR_MASK)) @@ -1520,6 +1525,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)) { diff --git a/database/DBio.c b/database/DBio.c index 8508c711..894fc5df 100644 --- a/database/DBio.c +++ b/database/DBio.c @@ -443,6 +443,16 @@ dbCellReadDef(f, cellDef, name, ignoreTech, dereference) continue; } + struct timespec t; + + t.tv_sec = 0; + t.tv_nsec = 900000000; + TxError("x\n"); + nanosleep(&t, NULL); + TxError("y\n"); + usleep(900000); + TxError("z\n"); + TTMaskZero(&typemask); rmask = &typemask; type = DBTechNameType(layername); diff --git a/tcltk/readspice.tcl b/tcltk/readspice.tcl index aee24037..dda21d63 100644 --- a/tcltk/readspice.tcl +++ b/tcltk/readspice.tcl @@ -105,6 +105,25 @@ proc readspice {netfile} { 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. @@ -127,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] @@ -139,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 != ""} { From f4b15188253f440acf6e303d0f083eb71cbee05c Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 2 Sep 2020 09:20:09 -0400 Subject: [PATCH 40/72] Changed the "port renumber" command option to sort ports by case- insensitive alphabetical order instead of case-sensitive. --- VERSION | 2 +- commands/CmdLQ.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/VERSION b/VERSION index 8f6ad577..fb571d57 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.51 +8.3.52 diff --git a/commands/CmdLQ.c b/commands/CmdLQ.c index 9af414e1..7d370314 100644 --- a/commands/CmdLQ.c +++ b/commands/CmdLQ.c @@ -1205,7 +1205,8 @@ portFindLabel(editDef, port, unique, nonEdit) * 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. + * consistent and repeatable port order. However, note that since SPICE + * is case-insensitive, case-insensitive string comparison is used. * * ---------------------------------------------------------------------------- */ @@ -1215,7 +1216,7 @@ complabel(const void *one, const void *two) { Label *l1 = *((Label **)one); Label *l2 = *((Label **)two); - return strcmp(l1->lab_text, l2->lab_text); + return strcasecmp(l1->lab_text, l2->lab_text); } /* @@ -1806,7 +1807,9 @@ CmdPort(w, cmd) case PORT_RENUMBER: /* Renumber ports in canonical order (by alphabetical - * order of the label text). + * order of the label text). NOTE: Because SPICE is + * case-insensitive, case-insensitive alphabetical order + * is used. */ { int numlabels, n, p; From c59278475014ea15ce629908d5503c944f9c5c55 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 3 Sep 2020 19:30:39 -0400 Subject: [PATCH 41/72] Accidentally managed to add some test code into the database that was not supposed to have been committed. It has been removed. --- database/DBio.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/database/DBio.c b/database/DBio.c index 894fc5df..8508c711 100644 --- a/database/DBio.c +++ b/database/DBio.c @@ -443,16 +443,6 @@ dbCellReadDef(f, cellDef, name, ignoreTech, dereference) continue; } - struct timespec t; - - t.tv_sec = 0; - t.tv_nsec = 900000000; - TxError("x\n"); - nanosleep(&t, NULL); - TxError("y\n"); - usleep(900000); - TxError("z\n"); - TTMaskZero(&typemask); rmask = &typemask; type = DBTechNameType(layername); From 5148049ffc8ccfa6bd1482c13c6c4e534c797e64 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 3 Sep 2020 19:31:46 -0400 Subject: [PATCH 42/72] Modified version to make sure the github repo and tarball gets updated. --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index fb571d57..00c75c67 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.52 +8.3.53 From 1ef41905894fc9a719fae4b1d9c32705a0c6d63e Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 4 Sep 2020 09:57:16 -0400 Subject: [PATCH 43/72] Corrected issue with parent and child cells in completely different directories starting from root getting the root directory "/" removed from the front of the child cell path. --- VERSION | 2 +- database/DBio.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 00c75c67..c1cda334 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.53 +8.3.54 diff --git a/database/DBio.c b/database/DBio.c index 8508c711..3f662eed 100644 --- a/database/DBio.c +++ b/database/DBio.c @@ -3173,6 +3173,10 @@ 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) { From 05950b16ea4274e429f1ec449976aeae72a3e2fb Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 4 Sep 2020 11:10:44 -0400 Subject: [PATCH 44/72] Corrected a problem with the last commit, in which the check for no common directory components between parent and child should have been outside the while loop. --- database/DBio.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/database/DBio.c b/database/DBio.c index 3f662eed..76ab5a30 100644 --- a/database/DBio.c +++ b/database/DBio.c @@ -3174,10 +3174,12 @@ dbWriteCellFunc(cellUse, cdarg) else break; - /* If there are no common components, then restore the leading '/' */ - if ((*pathorigin == '/') && (pathstart == pathorigin + 1)) - pathstart = pathorigin; } + + /* If there are no common components, then restore the leading '/' */ + if ((*pathorigin == '/') && (pathstart == pathorigin + 1)) + pathstart = pathorigin; + if (pathend != NULL) { *pathend = '\0'; From 6cf5f65b516a8dde664e5c7f7760cb91fae2b311 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 9 Sep 2020 12:18:09 -0400 Subject: [PATCH 45/72] Corrected a tiny but bad error in the extract section reading of the tech file that completely undermined the ability to describe an asymmetric device (different materials for terminals). --- VERSION | 2 +- extract/ExtTech.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index c1cda334..5b22f009 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.54 +8.3.55 diff --git a/extract/ExtTech.c b/extract/ExtTech.c index 61d65a61..2b1e8933 100644 --- a/extract/ExtTech.c +++ b/extract/ExtTech.c @@ -2280,7 +2280,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++; From ebe12fecfef8466462f1f47b544e0ad98f77836e Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 10 Sep 2020 21:44:02 -0400 Subject: [PATCH 46/72] Corrected an extraction error that prevented the use of the same device layer type to describe the extraction for both a regular FET and an extended-drain device. Note that the current code still requires that the extended-drain device be declared first, and does not check for this or attempt to reorder if incorrect. --- VERSION | 2 +- extract/ExtBasic.c | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 5b22f009..a6167b75 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.55 +8.3.56 diff --git a/extract/ExtBasic.c b/extract/ExtBasic.c index 6d048629..d4c37554 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; @@ -2749,6 +2756,7 @@ extTransPerimFunc(bp) else { TxError("Error: Asymmetric device with multiple terminals!\n"); + break; } /* Add the length to this terminal's perimeter */ From 32ec9625354c6d73c551ff01449f70d9c74b3aee Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 11 Sep 2020 17:29:12 -0400 Subject: [PATCH 47/72] Separated drain and source records for the esFetInfo array, to support asymmetric FETs and other devices like bipolars that have three distinct terminals. This does not go as far as it should to make the array independent of the number of declared terminals of the device. However, it suffices to make, e.g., parameter "a2=area" work for a bipolar device, and to generate the right drain and source areas and perimeters for asymmetric (e.g., extended-drain) devices. --- ext2sim/ext2sim.c | 36 +++++++++++--------- ext2spice/ext2hier.c | 29 ++++++++-------- ext2spice/ext2spice.c | 77 ++++++++++++++++++++++--------------------- ext2spice/ext2spice.h | 3 +- extract/ExtBasic.c | 2 +- extract/ExtSubtree.c | 21 ++++++++++-- extract/ExtTech.c | 37 ++++++++++++++++++--- 7 files changed, 130 insertions(+), 75 deletions(-) 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 dc57ce5c..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); } } @@ -965,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) { @@ -1538,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 f8c4b891..0a402d7b 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); } } @@ -2771,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) @@ -3998,7 +3998,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 3992ca2e..e21e6acd 100644 --- a/ext2spice/ext2spice.h +++ b/ext2spice/ext2spice.h @@ -90,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/extract/ExtBasic.c b/extract/ExtBasic.c index d4c37554..6ef620d6 100644 --- a/extract/ExtBasic.c +++ b/extract/ExtBasic.c @@ -1743,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 */ diff --git a/extract/ExtSubtree.c b/extract/ExtSubtree.c index 577295e4..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); diff --git a/extract/ExtTech.c b/extract/ExtTech.c index 2b1e8933..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 */ From a52590a10ee52f96b28d1242cf7f9eb97806223a Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 11 Sep 2020 17:40:46 -0400 Subject: [PATCH 48/72] Updated the version number to trigger the git mirror. --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index a6167b75..0344f0fc 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.56 +8.3.57 From c3e8ed545d8b89854f0dbd85714500471bc68665 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 14 Sep 2020 15:54:38 -0400 Subject: [PATCH 49/72] Implemented an additional setback value for "lef write -hide " that produces a result that looks like "lef write -hide" in the middle but "lef write" around the edge. Can be useful for catching all the detail around the edges but obscuring/simplifying the bulk of the cell interior. --- lef/lefCmd.c | 36 ++++++++++++--- lef/lefWrite.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 143 insertions(+), 14 deletions(-) diff --git a/lef/lefCmd.c b/lef/lefCmd.c index f4c9bd83..2cb557a0 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" @@ -83,9 +84,9 @@ 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 @@ -106,11 +107,13 @@ CmdLef(w, cmd) "read [filename] read a LEF file filename[.lef]\n" " read [filename] -import read a LEF file; import cells from .mag files", "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 }; @@ -211,7 +214,16 @@ 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], "-all", 4)) @@ -248,7 +260,17 @@ 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"); } diff --git a/lef/lefWrite.c b/lef/lefWrite.c index 84c648a9..d58f400d 100644 --- a/lef/lefWrite.c +++ b/lef/lefWrite.c @@ -1095,11 +1095,11 @@ LefWritePinHeader(f, lab) */ void -lefWriteMacro(def, f, scale, hide, toplayer) +lefWriteMacro(def, f, scale, setback, toplayer) 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 propfound, ispwrrail; @@ -1275,6 +1275,14 @@ lefWriteMacro(def, f, scale, hide, toplayer) &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. */ @@ -1399,7 +1407,7 @@ lefWriteMacro(def, f, scale, hide, toplayer) scx.scx_area = labr; SelectClear(); - if (hide) + if (setback == 0) { Rect carea; labelLinkedList *newlll; @@ -1423,6 +1431,18 @@ lefWriteMacro(def, f, scale, hide, toplayer) 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); @@ -1578,7 +1598,7 @@ lefWriteMacro(def, f, scale, hide, toplayer) /* 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 */ @@ -1598,6 +1618,7 @@ lefWriteMacro(def, f, scale, hide, toplayer) 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)) @@ -1607,6 +1628,10 @@ lefWriteMacro(def, f, scale, hide, toplayer) lefGetBound, (ClientData)(&layerBound)); } + /* Clip layerBound to setback boundary */ + GEO_EXPAND(&boundary, -setback, &r); + GeoClip(&layerBound, &r); + DBPaint(lc.lefYank, &layerBound, ttype); } @@ -1630,6 +1655,43 @@ lefWriteMacro(def, f, scale, hide, toplayer) 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 { @@ -1652,7 +1714,7 @@ lefWriteMacro(def, f, scale, hide, toplayer) 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], @@ -1663,6 +1725,51 @@ lefWriteMacro(def, f, scale, hide, toplayer) 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) @@ -1843,7 +1950,7 @@ LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, lefTopLayer, recurse) CellUse *rootUse; bool writeTopCell; bool lefTech; - bool lefHide; + int lefHide; bool lefTopLayer; bool recurse; { @@ -1979,7 +2086,7 @@ LefWriteCell(def, outName, isRoot, lefTech, lefHide, lefTopLayer) 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 */ { char *filename; From 6e4046607dfd8543f59e5e55b6a01a9704cc20d9 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 15 Sep 2020 21:46:38 -0400 Subject: [PATCH 50/72] Found an apparent error in the continuous DRC that tends to erase errors in the periphery of where a change has been made. For some reason this was not apparent before, but seems to be from a change dating back to 2008---which seems unlikely. The fact that it has not been seen before may have something to do with the size of the DRC halo compared to the DRC step size in the SkyWater PDK, where it has suddenly become apparent. Jury is still out on this one. --- drc/DRCcontin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drc/DRCcontin.c b/drc/DRCcontin.c index e7674c15..efb7ec43 100644 --- a/drc/DRCcontin.c +++ b/drc/DRCcontin.c @@ -707,7 +707,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, From 813bc223ac11f09e12a18706309b3167b172fccd Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 15 Sep 2020 21:57:20 -0400 Subject: [PATCH 51/72] Updated version to force the overnight github mirror. --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 0344f0fc..2dabf87d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.57 +8.3.58 From 380b287aa9882e96a26a168d3448438edc9fae0a Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 21 Sep 2020 16:03:37 -0400 Subject: [PATCH 52/72] Modified the extraction code to properly handle length and width of devices that have a terminal underneath the device. Code not yet tested. --- VERSION | 2 +- extract/ExtBasic.c | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 2dabf87d..eb775235 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.58 +8.3.59 diff --git a/extract/ExtBasic.c b/extract/ExtBasic.c index 6ef620d6..241dc799 100644 --- a/extract/ExtBasic.c +++ b/extract/ExtBasic.c @@ -3032,7 +3032,26 @@ 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++) + { + PlaneMask pmask = DBTechTypesToPlanes(&devptr->exts_deviceSDTypes[i]); + + 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. */ From ec3ac4863fc0ca3b81e1397cd68242bb55fca36c Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 21 Sep 2020 16:52:49 -0400 Subject: [PATCH 53/72] Also corrected an error where the bounds search uses the device type in the device record, which was not updated at the end of checking terminals for matching device extraction types. so the boundary survey might see the wrong device type and generate an incorrect boundary survey as a result. --- extract/ExtBasic.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extract/ExtBasic.c b/extract/ExtBasic.c index 241dc799..7af8f295 100644 --- a/extract/ExtBasic.c +++ b/extract/ExtBasic.c @@ -1849,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) @@ -1948,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) */ From 5308c352686d1359d036ecd473250fcc4997db8e Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 21 Sep 2020 20:23:37 -0400 Subject: [PATCH 54/72] Corrected one final case of extracting an extended-drain pFET because the opposite type (pwell) is not directly underneath the gate, but touches it on the plane below. Because the pwell may be represented by space tiles on the well plane, it was also necessary to deal with the space type in the bitmask. --- extract/ExtBasic.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/extract/ExtBasic.c b/extract/ExtBasic.c index 7af8f295..17b41ae0 100644 --- a/extract/ExtBasic.c +++ b/extract/ExtBasic.c @@ -2262,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; @@ -2271,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; @@ -3041,7 +3046,12 @@ extSpecialPerimFunc(bp, sense) { for (i = 0; !TTMaskIsZero(&devptr->exts_deviceSDTypes[i]); i++) { - PlaneMask pmask = DBTechTypesToPlanes(&devptr->exts_deviceSDTypes[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))) { From b846c45056e6d0163356e06bae8bc9470eb15bac Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 22 Sep 2020 15:25:26 -0400 Subject: [PATCH 55/72] Changed the behavior of the "compose" paint and erase rules to allow multiple types to be painted; for example, to paint over both planes of a contact when a paint type causes the contact to disappear. --- VERSION | 2 +- database/DBtpaint.c | 66 +++++++++++++++++++++++---------------------- 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/VERSION b/VERSION index eb775235..8a296751 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.59 +8.3.60 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); From aac2c06dfdfb144e8be96b3e64ec287f469790c6 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 25 Sep 2020 22:39:50 -0400 Subject: [PATCH 56/72] Corrected a problem with both the "port" command and the "lef read" command when annotating an existing layout from a LEF database, if there is a port in the layout that is shadowed by a label with the same name that is not a port. --- VERSION | 2 +- commands/CmdLQ.c | 5 +++-- lef/lefRead.c | 25 +++++++++++++++++++++++-- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/VERSION b/VERSION index 8a296751..a20393fb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.60 +8.3.61 diff --git a/commands/CmdLQ.c b/commands/CmdLQ.c index 7d370314..1c008a1c 100644 --- a/commands/CmdLQ.c +++ b/commands/CmdLQ.c @@ -1407,7 +1407,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; } } @@ -1419,7 +1419,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) diff --git a/lef/lefRead.c b/lef/lefRead.c index 2ae6c806..53ad5f07 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 { From 52d9639011b54c7a6fccfd56a426d2e7862ca012 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 6 Oct 2020 15:41:35 -0400 Subject: [PATCH 57/72] Added a "-nomaster" option to "lef write", and made writing masterslice layers in the output a default option. Use "-nomaster" to prevent the output of masterslice layers. --- VERSION | 2 +- lef/lefCmd.c | 18 +++++++++++++++--- lef/lefWrite.c | 16 ++++++++++------ 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/VERSION b/VERSION index a20393fb..4eb423f5 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.61 +8.3.62 diff --git a/lef/lefCmd.c b/lef/lefCmd.c index 2cb557a0..233ed893 100644 --- a/lef/lefCmd.c +++ b/lef/lefCmd.c @@ -88,10 +88,13 @@ CmdLef(w, cmd) * other than pin area surrounding labels, * with the indicated setback distance. */ - bool lefTopLayer = False; /* If TRUE, only output the topmost + 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, * only the immediate children of the @@ -226,6 +229,8 @@ CmdLef(w, cmd) } 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; @@ -233,7 +238,7 @@ CmdLef(w, cmd) else goto wrongNumArgs; } LefWriteAll(selectedUse, lefTopCell, lefTech, lefHide, lefTopLayer, - recurse); + lefDoMaster, recurse); } break; case LEF_WRITE: @@ -281,6 +286,13 @@ CmdLef(w, cmd) 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) @@ -320,7 +332,7 @@ CmdLef(w, cmd) DefWriteCell(selectedUse->cu_def, namep, allSpecial, units); else LefWriteCell(selectedUse->cu_def, namep, selectedUse->cu_def - == EditRootDef, lefTech, lefHide, lefTopLayer); + == EditRootDef, lefTech, lefHide, lefTopLayer, lefDoMaster); break; case LEF_HELP: wrongNumArgs: diff --git a/lef/lefWrite.c b/lef/lefWrite.c index d58f400d..e84d53b4 100644 --- a/lef/lefWrite.c +++ b/lef/lefWrite.c @@ -1095,12 +1095,13 @@ LefWritePinHeader(f, lab) */ void -lefWriteMacro(def, f, scale, setback, toplayer) +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 */ 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; @@ -1193,7 +1194,8 @@ lefWriteMacro(def, f, scale, setback, toplayer) 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); @@ -1946,12 +1948,13 @@ lefGetProperties(stackItem, i, clientData) */ void -LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, lefTopLayer, recurse) +LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, lefTopLayer, lefDoMaster, recurse) CellUse *rootUse; bool writeTopCell; bool lefTech; int lefHide; bool lefTopLayer; + bool lefDoMaster; bool recurse; { HashTable propHashTbl, siteHashTbl; @@ -2017,7 +2020,7 @@ LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, lefTopLayer, recurse) { def->cd_client = (ClientData) 0; if (!SigInterruptPending) - lefWriteMacro(def, f, scale, lefHide, lefTopLayer); + lefWriteMacro(def, f, scale, lefHide, lefTopLayer, lefDoMaster); } /* End the LEF file */ @@ -2081,13 +2084,14 @@ lefDefPushFunc(use, recurse) */ void -LefWriteCell(def, outName, isRoot, lefTech, lefHide, lefTopLayer) +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 */ 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; @@ -2121,7 +2125,7 @@ LefWriteCell(def, outName, isRoot, lefTech, lefHide, lefTopLayer) HashKill(&propHashTbl); HashKill(&siteHashTbl); } - lefWriteMacro(def, f, scale, lefHide, lefTopLayer); + lefWriteMacro(def, f, scale, lefHide, lefTopLayer, lefDoMaster); /* End the LEF file */ fprintf(f, "END LIBRARY\n\n"); From 076ee09e2eeb8242a60cc68d89363d727e14bcb4 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 7 Oct 2020 15:37:31 -0400 Subject: [PATCH 58/72] Added two new command options: "select bbox", which returns the bounding box of the selection (somewhat unuseful, especially as the result gets absorbed by the tag callback), and "box select", which sets the cursor box to the bounding box of the selection (much more useful). Also corrected the "port" command so that the command "port make" will search only for non-port labels. --- VERSION | 2 +- commands/CmdAB.c | 30 +++++++++++++++++++++++------- commands/CmdLQ.c | 8 ++++++-- commands/CmdRS.c | 42 ++++++++++++++++++++++++++++++++++++------ 4 files changed, 66 insertions(+), 16 deletions(-) diff --git a/VERSION b/VERSION index 4eb423f5..4d445a44 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.62 +8.3.63 diff --git a/commands/CmdAB.c b/commands/CmdAB.c index fa919ceb..8878b8cc 100644 --- a/commands/CmdAB.c +++ b/commands/CmdAB.c @@ -545,6 +545,7 @@ selGetArrayFunc(selUse, use, trans, arg) * box size [width height] * box position [llx lly] [-edit] * box values [llx lly urx ury] [-edit] + * box select * * box | cursor * @@ -580,13 +581,14 @@ 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_SELECT 5 +#define BOX_MOVE 6 +#define BOX_GROW 7 +#define BOX_SHRINK 8 +#define BOX_CORNER 9 +#define BOX_EXISTS 10 +#define BOX_HELP 11 +#define BOX_DEFAULT 12 void CmdBox(w, cmd) @@ -599,6 +601,7 @@ 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", + "select set box to selection bounding box", "move move box position", "grow expand box size", "shrink shrink box size", @@ -907,6 +910,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/CmdLQ.c b/commands/CmdLQ.c index 1c008a1c..3f1b25ae 100644 --- a/commands/CmdLQ.c +++ b/commands/CmdLQ.c @@ -1449,7 +1449,12 @@ CmdPort(w, cmd) 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) { @@ -1467,7 +1472,6 @@ CmdPort(w, cmd) #endif return; } - } if ((option != PORT_LAST) && (option != PORT_FIRST) && (option != PORT_MAKEALL) && (option != PORT_RENUMBER) 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. From c86d3ebb602d98dcbec9d379ec06c450f1a810f7 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 7 Oct 2020 16:07:36 -0400 Subject: [PATCH 59/72] Another update that properly deals with the "port" command for limiting search to non-port labels or to port labels only, depending on the command option (which was previously not implemented properly). --- commands/CmdLQ.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/commands/CmdLQ.c b/commands/CmdLQ.c index 3f1b25ae..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) { From 4e5f7251b7118de043a6583159b1d6158349a206 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 7 Oct 2020 16:26:56 -0400 Subject: [PATCH 60/72] Modified the "lef write -toplayer" option so that masterslice layers are considered an exception to the "-toplayer" restriction; this is because masterslice well/substrate layers will affect the electrical connectivity between port and sustrate or well. --- lef/lefWrite.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/lef/lefWrite.c b/lef/lefWrite.c index e84d53b4..6239f37b 100644 --- a/lef/lefWrite.c +++ b/lef/lefWrite.c @@ -1107,6 +1107,7 @@ lefWriteMacro(def, f, scale, setback, toplayer, domaster) char *propvalue, *class = NULL; Label *lab, *tlab, *reflab; Rect boundary, labr; + PlaneMask pmask; SearchContext scx; CellDef *lefFlatDef; CellUse lefFlatUse, lefSourceUse; @@ -1181,6 +1182,7 @@ lefWriteMacro(def, f, scale, setback, toplayer, domaster) 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 */ @@ -1196,6 +1198,7 @@ lefWriteMacro(def, f, scale, setback, toplayer, domaster) lefLayer *lefl = (lefLayer *)HashGetValue(he); if (lefl && (lefl->lefClass == CLASS_ROUTE || lefl->lefClass == CLASS_VIA || (domaster && lefl->lefClass == CLASS_MASTER))) + { if (lefl->type != -1) { TTMaskSetType(&lc.rmask, lefl->type); @@ -1210,6 +1213,10 @@ lefWriteMacro(def, f, scale, setback, toplayer, domaster) 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); @@ -1497,8 +1504,19 @@ lefWriteMacro(def, f, scale, setback, toplayer, domaster) { /* Option to output only the topmost layer of a network */ /* as PIN geometry. All layers below it are considered */ - /* obstructions. */ - if (toplayer) pNum = pTop; + /* 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 (!PlaneMaskHashPlane(&pmask, pNum)) + continue; + } + else continue; + } lc.pNum = pNum; DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pNum], @@ -1540,8 +1558,6 @@ lefWriteMacro(def, f, scale, setback, toplayer, domaster) &TiPlaneRect, &lc.rmask, lefWriteGeometry, (ClientData) &lc); lc.lefMode = LEF_MODE_PORT; - - if (toplayer) break; /* Stop after processing topmost layer */ } DBCellClearDef(lc.lefYank); lab->lab_flags |= PORT_VISITED; From dc99e382dd106f7f2076b423a47f1226dea8a94d Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 7 Oct 2020 16:34:49 -0400 Subject: [PATCH 61/72] Corrected a simple error from the last commit. --- lef/lefWrite.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lef/lefWrite.c b/lef/lefWrite.c index 6239f37b..6803f087 100644 --- a/lef/lefWrite.c +++ b/lef/lefWrite.c @@ -1512,7 +1512,7 @@ lefWriteMacro(def, f, scale, setback, toplayer, domaster) { if (domaster & (pmask != 0)) { - if (!PlaneMaskHashPlane(&pmask, pNum)) + if (!PlaneMaskHasPlane(pmask, pNum)) continue; } else continue; From 581ad6041b77eb9a06a16f53ce5f8f21748e57f0 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 8 Oct 2020 13:50:14 -0400 Subject: [PATCH 62/72] Added new command option "box remove" that removes the cursor box from the layout window. The main reason for this is to keep the box out of the image when doing "plot svg". The "plot" command was also modified to always do a plot of the entire cell in the active layout window if the box is not present. --- VERSION | 2 +- commands/CmdAB.c | 25 +++++++++++++++++-------- plot/plotCmd.c | 10 +++++----- tcltk/wrapper.tcl | 4 ++++ 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/VERSION b/VERSION index 4d445a44..b941f982 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.63 +8.3.64 diff --git a/commands/CmdAB.c b/commands/CmdAB.c index 8878b8cc..4d662dc3 100644 --- a/commands/CmdAB.c +++ b/commands/CmdAB.c @@ -545,6 +545,7 @@ 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 @@ -581,14 +582,15 @@ selGetArrayFunc(selUse, use, trans, arg) #define BOX_SIZE 2 #define BOX_POSITION 3 #define BOX_VALUES 4 -#define BOX_SELECT 5 -#define BOX_MOVE 6 -#define BOX_GROW 7 -#define BOX_SHRINK 8 -#define BOX_CORNER 9 -#define BOX_EXISTS 10 -#define BOX_HELP 11 -#define BOX_DEFAULT 12 +#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) @@ -601,6 +603,7 @@ 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", @@ -661,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. */ diff --git a/plot/plotCmd.c b/plot/plotCmd.c index e77f2480..9d72f60f 100644 --- a/plot/plotCmd.c +++ b/plot/plotCmd.c @@ -176,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; 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 == {}} { From a066f01bb274f38ade68abb6f8e2682c828649b2 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 8 Oct 2020 14:04:28 -0400 Subject: [PATCH 63/72] Upon reflection, decided to just omit the cursor box when generating an SVG plot. --- plot/plotCmd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plot/plotCmd.c b/plot/plotCmd.c index 9d72f60f..f59a8821 100644 --- a/plot/plotCmd.c +++ b/plot/plotCmd.c @@ -277,7 +277,9 @@ CmdPlot(w, cmd) /* 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 From c0015efbe0a27d5d258d2238744c671492773c5b Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 13 Oct 2020 09:47:54 -0400 Subject: [PATCH 64/72] Added experimental "calma addendum" option to output only references to readonly cells but not the readonly cells themselves when writing a GDS library. --- VERSION | 2 +- calma/CalmaWrite.c | 21 ++++++++++++------ calma/calma.h | 1 + commands/CmdCD.c | 54 ++++++++++++++++++++++++++++++++-------------- 4 files changed, 54 insertions(+), 24 deletions(-) diff --git a/VERSION b/VERSION index b941f982..50db9de7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.64 +8.3.65 diff --git a/calma/CalmaWrite.c b/calma/CalmaWrite.c index b2815e0b..2118c18a 100644 --- a/calma/CalmaWrite.c +++ b/calma/CalmaWrite.c @@ -57,6 +57,7 @@ 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 */ @@ -774,13 +775,6 @@ calmaProcessDef(def, outf, do_library) 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 @@ -799,6 +793,19 @@ calmaProcessDef(def, outf, do_library) 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; diff --git a/calma/calma.h b/calma/calma.h index a7e7ebb7..bedc169b 100644 --- a/calma/calma.h +++ b/calma/calma.h @@ -30,6 +30,7 @@ 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/commands/CmdCD.c b/commands/CmdCD.c index 3eb439d5..f235f693 100644 --- a/commands/CmdCD.c +++ b/commands/CmdCD.c @@ -89,22 +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_LIBRARY 7 -#define CALMA_LOWER 8 -#define CALMA_MERGE 9 -#define CALMA_READ 10 -#define CALMA_READONLY 11 -#define CALMA_RESCALE 12 -#define CALMA_WARNING 13 -#define CALMA_WRITE 14 -#define CALMA_POLYS 15 -#define CALMA_PATHS 16 +#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 */ @@ -127,6 +128,7 @@ 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", @@ -249,6 +251,26 @@ CmdCalma(w, cmd) 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) { From e7074e572369da877bf43921e8403a36c8a9c106 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 14 Oct 2020 17:20:45 -0400 Subject: [PATCH 65/72] Added two small features: (1) Added the "-annotate" option to "lef read". While "lef read" normally annotates existing layout, this option ensures that no additional cells are created from macros in the input LEF file. (2) Added a check on the "Input off lambda grid" warning during CIF/GDS input such that it is not repeated once issued, as it tends to be output many times when it occurs. --- VERSION | 2 +- cif/CIFrdutils.c | 18 +++++++++++++----- lef/lefCmd.c | 11 +++++++++-- lef/lefRead.c | 16 +++++++++++++--- utils/main.c | 2 +- 5 files changed, 37 insertions(+), 12 deletions(-) diff --git a/VERSION b/VERSION index 50db9de7..1212715f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.65 +8.3.66 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/lef/lefCmd.c b/lef/lefCmd.c index 233ed893..e8984361 100644 --- a/lef/lefCmd.c +++ b/lef/lefCmd.c @@ -72,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. @@ -108,7 +112,8 @@ 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\n", " write [filename] -hide hide details in area set back distance ", @@ -181,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) @@ -196,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; diff --git a/lef/lefRead.c b/lef/lefRead.c index 53ad5f07..5c55c143 100644 --- a/lef/lefRead.c +++ b/lef/lefRead.c @@ -1713,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; @@ -1764,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); @@ -2508,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; @@ -2734,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/utils/main.c b/utils/main.c index 1e1c28a1..55988732 100644 --- a/utils/main.c +++ b/utils/main.c @@ -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); From 9a5cc08d41773f014ef53ddeacda38ee7ef11bd4 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 14 Oct 2020 21:41:50 -0400 Subject: [PATCH 66/72] Made a small change to add a flag to the DRC rules to denote whether the rule is a normal database rule or a CIF-DRC rule. For the latter, the flag is used when substituting for escape strings in the "why" rule explanation to produce the correct value in microns. --- cif/CIFmain.c | 22 ++++++++++++++++++++++ cif/cif.h | 1 + drc/DRCcif.c | 26 +++++++++++++++----------- drc/DRCmain.c | 5 ++++- drc/drc.h | 5 ++++- 5 files changed, 46 insertions(+), 13 deletions(-) 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/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/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/DRCmain.c b/drc/DRCmain.c index 1d9443a2..0258cd10 100644 --- a/drc/DRCmain.c +++ b/drc/DRCmain.c @@ -201,7 +201,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) diff --git a/drc/drc.h b/drc/drc.h index 40984a0e..390a3cde 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. */ @@ -74,6 +74,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 From 4c5b40bcd9560b3f9a5d27e07cf288a148e9435d Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 14 Oct 2020 22:04:47 -0400 Subject: [PATCH 67/72] Added the correct header to DRCmain.c to see the prototype for CIFGetScale(). --- drc/DRCmain.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drc/DRCmain.c b/drc/DRCmain.c index 0258cd10..b211adca 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 From 9f49ad97da399213f9b0ece85a1c3cf685950a1c Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 14 Oct 2020 22:39:48 -0400 Subject: [PATCH 68/72] Added a fix from Dan Moore to remove the Depend files on "make clean" (these are automatically removed and regenerated on "make" anyway). --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7fc163dc..cf262b42 100644 --- a/Makefile +++ b/Makefile @@ -98,7 +98,7 @@ install-tcl-real: install-tcl-dirs clean: for dir in ${MODULES} ${PROGRAMS} ${TECH} ${UNUSED_MODULES}; do \ (cd $$dir && ${MAKE} clean); done - ${RM} *.tmp */*.tmp *.sav */*.sav *.log TAGS tags + ${RM} *.tmp */*.tmp *.sav */*.sav *.log TAGS tags */Depend distclean: touch defs.mak From 4bbe4ef74e5eac98c503bf6483ee7a40dbb0547a Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 14 Oct 2020 22:53:03 -0400 Subject: [PATCH 69/72] Added another fix from a pull request by Dan Moore, which apparently fixes a problem with substrate nodes not being flagged as such when reading .ext files. --- extflat/EFbuild.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/extflat/EFbuild.c b/extflat/EFbuild.c index 44c9c019..09ac3a2e 100644 --- a/extflat/EFbuild.c +++ b/extflat/EFbuild.c @@ -167,6 +167,12 @@ efBuildNode(def, isSubsnode, nodeName, nodeCap, x, y, layerName, av, ac) 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; } } From 5cb645e2d5456f4bb209dc4e736272b17ea8ca15 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 15 Oct 2020 12:18:14 -0400 Subject: [PATCH 70/72] Fixed a missing requirement of a reverse direction check on spacing rules with "surround_ok" on different planes. --- VERSION | 2 +- drc/DRCtech.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 1212715f..f3d26a30 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.66 +8.3.67 diff --git a/drc/DRCtech.c b/drc/DRCtech.c index 2387fda0..7bd7e1ab 100644 --- a/drc/DRCtech.c +++ b/drc/DRCtech.c @@ -1762,7 +1762,7 @@ drcMaskSpacing(set1, set2, pmask1, pmask2, wwidth, distance, adjacency, { needtrigger = TRUE; touchingok = FALSE; - + needReverse = TRUE; } else { From 2a4baa82c3af46b62d241d30ccd0a392efb79ffa Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 15 Oct 2020 17:31:20 -0400 Subject: [PATCH 71/72] Substantially overhauled the way that the DRC checker finds and processes "interaction areas". This should eliminate weirdnesses where errors will fail to show up in a subcell that does not interact with paint or other subcells in the top level edit cell. These errors cannot be reported directly in the top level cell, but a new error message has been created to direct the user to check the subcell for errors. Also: Modified the toolkit procedures to force DRC to be run on newly created or modified parameterized cell layouts. There is some oddity about the process that causes DRC errors to be delayed unless a print statement is put before the DRC check; I would like to investigate this further. --- Makefile | 4 +- drc/DRCcontin.c | 11 ++++-- drc/DRCmain.c | 10 ++--- drc/DRCsubcell.c | 94 ++++++++++++++++++++++++++++++++++++++++++----- drc/DRCtech.c | 9 +++++ drc/drc.h | 2 + tcltk/toolkit.tcl | 4 ++ 7 files changed, 113 insertions(+), 21 deletions(-) diff --git a/Makefile b/Makefile index cf262b42..e1d61fbd 100644 --- a/Makefile +++ b/Makefile @@ -98,7 +98,7 @@ install-tcl-real: install-tcl-dirs clean: for dir in ${MODULES} ${PROGRAMS} ${TECH} ${UNUSED_MODULES}; do \ (cd $$dir && ${MAKE} clean); done - ${RM} *.tmp */*.tmp *.sav */*.sav *.log TAGS tags */Depend + ${RM} *.tmp */*.tmp *.sav */*.sav *.log TAGS tags distclean: touch defs.mak @@ -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/drc/DRCcontin.c b/drc/DRCcontin.c index efb7ec43..41e97133 100644 --- a/drc/DRCcontin.c +++ b/drc/DRCcontin.c @@ -197,10 +197,13 @@ 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. */ @@ -683,7 +686,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. */ diff --git a/drc/DRCmain.c b/drc/DRCmain.c index b211adca..6a2e9ade 100644 --- a/drc/DRCmain.c +++ b/drc/DRCmain.c @@ -615,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); */ @@ -639,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 7bd7e1ab..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 */ @@ -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 390a3cde..061a1ce2 100644 --- a/drc/drc.h +++ b/drc/drc.h @@ -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. */ @@ -266,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/tcltk/toolkit.tcl b/tcltk/toolkit.tcl index 75fa12cd..1ec0778e 100644 --- a/tcltk/toolkit.tcl +++ b/tcltk/toolkit.tcl @@ -363,6 +363,8 @@ proc magic::gencell_change {instname gencell_type library parameters} { eval "box values $savebox" snap $snaptype resumeall + puts stdout "Done." + drc check redraw } @@ -472,6 +474,8 @@ proc magic::gencell_create {gencell_type library parameters} { snap $snaptype resumeall redraw + puts stdout "Done." + drc check return $instname } From 4b0652ecc98e1abc4b350f7ee7f520082b82e99c Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 15 Oct 2020 20:59:08 -0400 Subject: [PATCH 72/72] Additional change: The switch to propagating DRC errors up from the bottom in non-interacting areas means that any change in DRC to a subcell must be handled before checking DRC in the parent. Previously the order of checks was reversed, moving parent cells to the beginning of the check list. This prevents the error cited in the previous commit which was showing up as a delayed DRC check when creating parameterized cells. --- drc/DRCcontin.c | 34 ++++++++++++++++++++++++++++++++++ tcltk/toolkit.tcl | 4 ---- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/drc/DRCcontin.c b/drc/DRCcontin.c index 41e97133..a8131361 100644 --- a/drc/DRCcontin.c +++ b/drc/DRCcontin.c @@ -208,6 +208,13 @@ DRCCheckThis (celldef, operation, area) /* 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; @@ -229,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. diff --git a/tcltk/toolkit.tcl b/tcltk/toolkit.tcl index 1ec0778e..75fa12cd 100644 --- a/tcltk/toolkit.tcl +++ b/tcltk/toolkit.tcl @@ -363,8 +363,6 @@ proc magic::gencell_change {instname gencell_type library parameters} { eval "box values $savebox" snap $snaptype resumeall - puts stdout "Done." - drc check redraw } @@ -474,8 +472,6 @@ proc magic::gencell_create {gencell_type library parameters} { snap $snaptype resumeall redraw - puts stdout "Done." - drc check return $instname }