From f11a718368198a2cf345125275339ce38e3e93eb Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sat, 13 Feb 2021 20:40:52 -0500 Subject: [PATCH 01/89] Added return values to DBPaintPlaneVert(), which was missing them and causing compiling under clang-10 to fail. --- VERSION | 2 +- database/DBpaint.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index f21117ae..f5b26962 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.125 +8.3.126 diff --git a/database/DBpaint.c b/database/DBpaint.c index bf91457d..5364827e 100644 --- a/database/DBpaint.c +++ b/database/DBpaint.c @@ -2573,7 +2573,7 @@ DBPaintPlaneVert(plane, area, resultTbl, undo) Tile *newtile, *tp; /* Used for paint */ if (area->r_xtop <= area->r_xbot || area->r_ytop <= area->r_ybot) - return; + return 0; /* * The following is a modified version of the area enumeration @@ -2798,6 +2798,7 @@ paintdone: done: plane->pl_hint = tile; + return 0; } /* From 48b04385c3dd5ce463ac8a7ac3b16c4fd6e2352e Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 16 Feb 2021 10:05:59 -0500 Subject: [PATCH 02/89] Corrected an error with the new off-grid DRC check that can cause a crash condition during GDS read-in. --- VERSION | 2 +- drc/DRCsubcell.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index f5b26962..b2c7c07b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.126 +8.3.127 diff --git a/drc/DRCsubcell.c b/drc/DRCsubcell.c index 053d77e6..d7b9d3af 100644 --- a/drc/DRCsubcell.c +++ b/drc/DRCsubcell.c @@ -647,6 +647,7 @@ void DRCOffGridError(rect) Rect *rect; /* Area of error */ { + if (drcSubFunc == NULL) return; (*drcSubFunc)(DRCErrorDef, rect, &drcOffGridCookie, drcSubClientData); } From bdeb4bab506946f8b13a3a0cbd0f01324bafc4bf Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Thu, 18 Feb 2021 11:26:02 +1100 Subject: [PATCH 03/89] Restore terminal if exit is called inside a TCL script at startup If exit is called in a TCL script that is executed at startup, the libc exit() function is called directly and we don't get a chance to reset the terminal. We return to the shell with echo off, and have to run "reset". A simple example: echo exit > test.tcl magic -noconsole -dnull test.tcl There are a few ways we could solve this. We could register an exit handler using atexit(). Here I use Tcl_SetExitProc() to register a callback with the TCL interpreter. --- utils/main.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/utils/main.c b/utils/main.c index 55988732..06e06c7d 100644 --- a/utils/main.c +++ b/utils/main.c @@ -770,6 +770,12 @@ mainInitAfterArgs() return 0; } +void tcl_exit_hook(ClientData clientData) +{ + TxResetTerminal(); + exit(0); +} + /* * ---------------------------------------------------------------------------- * mainInitFinal: @@ -794,6 +800,9 @@ mainInitFinal() char *rname; int result; + /* Reset terminal if exit is called inside a TCL script */ + Tcl_SetExitProc(tcl_exit_hook); + #ifdef MAGIC_WRAPPER /* Read in system pre-startup file, if it exists. */ @@ -1187,6 +1196,8 @@ mainInitFinal() UndoFlush(); TxClearPoint(); + Tcl_SetExitProc(NULL); + return 0; } From dca33becd9fe0ce019954c82161288cb4e70f0de Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 17 Feb 2021 20:46:26 -0500 Subject: [PATCH 04/89] Updated VERSION along with pull request #68 from Anton Blanchard --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index b2c7c07b..3ce5d98b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.127 +8.3.128 From aa88c696362568f910ff487d993a0232f8885220 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 17 Feb 2021 20:53:17 -0500 Subject: [PATCH 05/89] Updated from pull request #49 (required a manual merge due to change in DRC flags type). --- drc/DRCbasic.c | 14 +++++++++++--- drc/DRCextend.c | 12 +++++++++--- drc/DRCtech.c | 2 ++ drc/drc.h | 5 +++-- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/drc/DRCbasic.c b/drc/DRCbasic.c index 9f4aaf41..de60f127 100644 --- a/drc/DRCbasic.c +++ b/drc/DRCbasic.c @@ -604,9 +604,17 @@ drcTile (tile, arg) } else if (cptr->drcc_flags & DRC_MAXWIDTH) { - /* bends_illegal option only */ - if (firsttile) - drcCheckMaxwidth(tile, arg, cptr); + if (cptr->drcc_flags & DRC_MAXWIDTH_BOTH) + { + if (firsttile) + drcCheckMaxwidth(tile, arg, cptr, TRUE); + } + else + { + /* bends_illegal option only */ + if (firsttile) + drcCheckMaxwidth(tile, arg, cptr, FALSE); + } continue; } diff --git a/drc/DRCextend.c b/drc/DRCextend.c index c05515b3..1a4ad0a1 100644 --- a/drc/DRCextend.c +++ b/drc/DRCextend.c @@ -257,11 +257,14 @@ forgetit: */ int -drcCheckMaxwidth(starttile,arg,cptr) +drcCheckMaxwidth(starttile,arg,cptr,both) Tile *starttile; struct drcClientData *arg; DRCCookie *cptr; + bool both; { + int width; + int height; int edgelimit; int retval = 0; Rect boundrect; @@ -314,8 +317,11 @@ drcCheckMaxwidth(starttile,arg,cptr) if (TTMaskHasType(oktypes, TiGetLeftType(tp))) PUSHTILE(tp); } - if (boundrect.r_xtop - boundrect.r_xbot > edgelimit && - boundrect.r_ytop - boundrect.r_ybot > edgelimit) + width = boundrect.r_xtop - boundrect.r_xbot; + height = boundrect.r_ytop - boundrect.r_ybot; + + if ( (width > edgelimit && height > edgelimit) || + ( both == TRUE && (width > edgelimit || height > edgelimit)) ) { Rect rect; TiToRect(starttile,&rect); diff --git a/drc/DRCtech.c b/drc/DRCtech.c index 9aa1792b..c61c68a8 100644 --- a/drc/DRCtech.c +++ b/drc/DRCtech.c @@ -1550,6 +1550,7 @@ drcOffGrid(argc, argv) * 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: + * both - implies bend_illegal and both directions are checked * * XXXXX XXXXXX * X X XXXXXX @@ -1608,6 +1609,7 @@ drcMaxwidth(argc, argv) { if (strcmp(bends,"bend_illegal") == 0) bend = 0; else if (strcmp(bends,"bend_ok") == 0) bend = DRC_BENDS; + else if (strcmp(bends,"both") == 0) bend = DRC_MAXWIDTH_BOTH; else { TechError("unknown bend option %s\n",bends); diff --git a/drc/drc.h b/drc/drc.h index 41547c00..abcc2b40 100644 --- a/drc/drc.h +++ b/drc/drc.h @@ -73,8 +73,9 @@ typedef struct drccookie #define DRC_AREA 0x020 #define DRC_OFFGRID 0x040 #define DRC_MAXWIDTH 0x080 -#define DRC_RECTSIZE 0x100 -#define DRC_ANGLES 0x200 +#define DRC_MAXWIDTH_BOTH 0x100 +#define DRC_RECTSIZE 0x200 +#define DRC_ANGLES 0x400 #define DRC_NONSTANDARD (DRC_AREA|DRC_MAXWIDTH|DRC_RECTSIZE\ |DRC_ANGLES|DRC_OFFGRID) From 15fe4d2d299ecc947025e4cbab221b19bcad6b5b Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 17 Feb 2021 21:08:10 -0500 Subject: [PATCH 06/89] Merged pull request #35 from Jan Belohoubek --- ext2spice/ext2hier.c | 13 +++------ ext2spice/ext2spice.c | 61 ++++++++++++++++++------------------------- 2 files changed, 29 insertions(+), 45 deletions(-) diff --git a/ext2spice/ext2hier.c b/ext2spice/ext2hier.c index e6ba9381..b8dff398 100644 --- a/ext2spice/ext2hier.c +++ b/ext2spice/ext2hier.c @@ -500,7 +500,7 @@ spcdevHierVisit(hc, dev, scale) EFNode *subnode, *snode, *dnode, *subnodeFlat = NULL; int l, w, i, parmval; Rect r; - bool subAP = FALSE, hierS, hierD, extHierSDAttr(), swapped = FALSE; + bool subAP = FALSE, hierS, hierD, extHierSDAttr(); float sdM; char devchar; bool has_model = TRUE; @@ -522,6 +522,8 @@ spcdevHierVisit(hc, dev, scale) source = drain = &dev->dev_terms[1]; if (dev->dev_nterm >= 3) { + drain = &dev->dev_terms[2]; + /* If any terminal is marked with attribute "D" or "S" */ /* (label "D$" or "S$" at poly-diffusion interface), */ /* then force order of source and drain accordingly. */ @@ -531,11 +533,8 @@ spcdevHierVisit(hc, dev, scale) (dev->dev_terms[2].dterm_attrs && !strcmp(dev->dev_terms[2].dterm_attrs, "S"))) { - swapDrainSource(dev, &source, &drain); - swapped = TRUE; + swapDrainSource(dev); } - else - drain = &dev->dev_terms[2]; } else if (dev->dev_nterm == 1) // Is a device with one terminal an error? source = drain = &dev->dev_terms[0]; @@ -1023,10 +1022,6 @@ 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 9d41656a..976ab6b8 100644 --- a/ext2spice/ext2spice.c +++ b/ext2spice/ext2spice.c @@ -2219,47 +2219,39 @@ getCurDevMult() /* + *----------------------------------------------------------------------------- * 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" + * This is typically 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. + * + * Note: + * Before calling this function, ensure that dev->dev_nterm >= 3 * + * Results: + * None + * + * Side effects: + * Soure (dev->dev_terms[1]) and drain (dev->dev_terms[2]) terminals + * are swapped. + * + *----------------------------------------------------------------------------- */ + void -swapDrainSource(dev, source, drain) +swapDrainSource(dev) Dev *dev; - DevTerm **source, **drain; { - DevParam *plist; - - /* swap drain/source ordering */ - if (drain) *drain = &dev->dev_terms[1]; - if (source) *source = &dev->dev_terms[2]; - - /* Swap drain/source-related parameters. Note that the parameter */ - /* *definitions* are swapped, so if this is done, it must be */ - /* reverted before the next device is processed. */ + DevTerm tmpTerm; - plist = efGetDeviceParams(EFDevTypes[dev->dev_type]); - while (plist != NULL) - { - // Diagnostic - // TxPrintf(" * param: %s; type: %c%c\n", plist->parm_name, plist->parm_type[0], plist->parm_type[1]); - - /* Swap drain/source parameters only */ - if (!(strcmp(plist->parm_type, "a1")) || !(strcmp(plist->parm_type, "p1"))) - plist->parm_type[1] = '0' + 2; - - else if (!(strcmp(plist->parm_type, "a2")) || !(strcmp(plist->parm_type, "p2"))) - plist->parm_type[1] = '0' + 1; - - /* move pointer */ - plist = plist->parm_next; - } + /* swap original terminals */ + memcpy(&tmpTerm, &(dev->dev_terms[1]), sizeof(DevTerm)); + memcpy(&(dev->dev_terms[1]), &(dev->dev_terms[2]), sizeof(DevTerm)); + memcpy(&(dev->dev_terms[2]), &tmpTerm, sizeof(DevTerm)); } @@ -2309,7 +2301,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(), swapped = FALSE ; + bool subAP= FALSE, hierS, hierD, extHierSDAttr(); float sdM; char name[12], devchar; bool has_model = TRUE; @@ -2331,8 +2323,11 @@ spcdevVisit(dev, hc, scale, trans) gate = &dev->dev_terms[0]; if (dev->dev_nterm >= 2) source = drain = &dev->dev_terms[1]; + if (dev->dev_nterm >= 3) { + drain = &dev->dev_terms[2]; + /* If any terminal is marked with attribute "D" or "S" */ /* (label "D$" or "S$" at poly-diffusion interface), */ /* then force order of source and drain accordingly. */ @@ -2342,11 +2337,8 @@ spcdevVisit(dev, hc, scale, trans) (dev->dev_terms[2].dterm_attrs && !strcmp(dev->dev_terms[2].dterm_attrs, "S"))) { - swapDrainSource(dev, &source, &drain); - swapped = True; + swapDrainSource(dev); } - else - drain = &dev->dev_terms[2]; } subnode = dev->dev_subsnode; @@ -2852,9 +2844,6 @@ spcdevVisit(dev, hc, scale, trans) } fprintf(esSpiceF, "\n"); - /* If S/D parameters on a subcircuit were swapped, put them back */ - if (swapped) swapDrainSource(dev, NULL, NULL); - return 0; } From 1f698aa6ee526471416408b24bf64f258175c7f4 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 17 Feb 2021 21:15:54 -0500 Subject: [PATCH 07/89] Merged pull request #53 from Dan Moore. --- extract/ExtCouple.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/extract/ExtCouple.c b/extract/ExtCouple.c index 64aa56d7..dea2d9c2 100644 --- a/extract/ExtCouple.c +++ b/extract/ExtCouple.c @@ -897,6 +897,9 @@ extSideOverlap(tp, esws) subcap = (ExtCurStyle->exts_perimCap[ta][outtype] * MIN(areaAccountedFor, length)); rbp->nreg_cap -= subcap; + /* Ignore residual error at ~zero zeptoFarads. Probably */ + /* there should be better handling of round-off here. */ + if ((rbp->nreg_cap > -0.001) && (rbp->nreg_cap < 0.001)) rbp->nreg_cap = 0; if (CAP_DEBUG) extNregAdjustCap(rbp, -subcap, "obsolete_perimcap"); } else if (CAP_DEBUG) From 59b021af73587b7426a532a051fa87e4a44ab227 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 18 Feb 2021 13:05:29 -0500 Subject: [PATCH 08/89] Corrected an error in which the "select" command returns the name of an instance with double-escaped brackets if the instance name contains brackets. This then undermines the use of the backslash escape and causes the interpreter to raise an error instead of printing the name. --- VERSION | 2 +- commands/CmdRS.c | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 3ce5d98b..423f70a6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.128 +8.3.129 diff --git a/commands/CmdRS.c b/commands/CmdRS.c index 3adea56f..1934891e 100644 --- a/commands/CmdRS.c +++ b/commands/CmdRS.c @@ -819,7 +819,7 @@ CmdSelect(w, cmd) * also used to step through multiple uses. */ static bool lessCycle = FALSE, lessCellCycle = FALSE; - char path[200], *printPath, **msg, **optionArgs, *feedtext; + char path[200], *printPath, **msg, **optionArgs, *feedtext, *pstr; TerminalPath tpath; CellUse *use; CellDef *rootBoxDef; @@ -1526,6 +1526,13 @@ Okay: DBWSetBox(scx.scx_use->cu_def, &r); #ifdef MAGIC_WRAPPER + /* Remove any backslash escapes so that Tcl_escape() doesn't + * double-escape them. + */ + for (pstr = printPath; *pstr != '\0';) + if ((*pstr == '\\') && ((*(pstr + 1) == '[') || (*(pstr + 1) == ']'))) + memmove(pstr, pstr + 1, 1 + strlen(pstr + 1)); + else pstr++; tclstr = Tcl_escape(printPath); Tcl_SetResult(magicinterp, tclstr, TCL_DYNAMIC); #else From 5b2042d078ca9a2aaec3f10251c722850754cceb Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 18 Feb 2021 15:36:29 -0500 Subject: [PATCH 09/89] Corrected the "property put" command to handle changes in the GDS_FILE property in the same way that it handles changes to the FIXED_BBOX property, by setting or clearing the associated flag bit in the cell. Otherwise, it becomes impossible to make a cell writeable, as it always has some belief that it is still attached to a specific GDS file. Corrected an error in the "gds" ("calma") command parsing that switched the callbacks for the "noduplicates" and "nodatestamp" options. --- commands/CmdCD.c | 2 +- database/DBprop.c | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/commands/CmdCD.c b/commands/CmdCD.c index cb718a41..db2049f2 100644 --- a/commands/CmdCD.c +++ b/commands/CmdCD.c @@ -145,8 +145,8 @@ CmdCalma(w, cmd) "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", - "noduplicates [yes|no] do not read cells that exist before reading GDS", "nodatestamp [yes|no] write a zero value creation date stamp", + "noduplicates [yes|no] do not read cells that exist before reading GDS", "read file read Calma GDS-II format from \"file\"\n" " into edit cell", "readonly [yes|no] set cell as read-only and generate output from GDS file", diff --git a/database/DBprop.c b/database/DBprop.c index 2c267f52..3529c628 100644 --- a/database/DBprop.c +++ b/database/DBprop.c @@ -83,6 +83,15 @@ DBPropPut(cellDef, name, value) cellDef->cd_flags |= CDFIXEDBBOX; } + /* Special handling of GDS_FILE, which uses CDVENDORGDS as a quick lookup */ + if (!strcmp(name, "GDS_FILE")) + { + if (value == (ClientData)NULL) + cellDef->cd_flags &= ~CDVENDORGDS; + else + cellDef->cd_flags |= CDVENDORGDS; + } + entry = HashFind(htab, name); oldvalue = (char *)HashGetValue(entry); if (oldvalue != NULL) freeMagic(oldvalue); From 2d79e0e0ce119817f34104bfccb7ca2f8b25d653 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 18 Feb 2021 15:47:40 -0500 Subject: [PATCH 10/89] Corrected variables that set the PaintPlane routine, which had been changed from returning void to returning int without changing the type of the variable, thus causing a compiler warning. --- commands/CmdTZ.c | 2 +- drc/DRCarray.c | 2 +- drc/DRCsubcell.c | 4 ++-- garouter/gaTest.c | 2 +- select/selCreate.c | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/commands/CmdTZ.c b/commands/CmdTZ.c index a0e93833..00478dd6 100644 --- a/commands/CmdTZ.c +++ b/commands/CmdTZ.c @@ -1926,7 +1926,7 @@ CmdXor(w, cmd) PaintResultType DBXORResultTbl[NP][NT][NT]; PaintResultType (*curPaintSave)[NT][NT]; - void (*curPlaneSave)(); + int (*curPlaneSave)(); int p, t, h; diff --git a/drc/DRCarray.c b/drc/DRCarray.c index 1f44ede6..18c4d6e1 100644 --- a/drc/DRCarray.c +++ b/drc/DRCarray.c @@ -114,7 +114,7 @@ drcArrayFunc(scx, arg) ClientData drcArrayClientData; /* Extra parameter to pass to func. */ PaintResultType (*savedPaintTable)[NT][NT]; PaintResultType (*savedEraseTable)[NT][NT]; - void (*savedPaintPlane)(); + int (*savedPaintPlane)(); if ((use->cu_xlo == use->cu_xhi) && (use->cu_ylo == use->cu_yhi)) return 2; diff --git a/drc/DRCsubcell.c b/drc/DRCsubcell.c index d7b9d3af..c976a1c0 100644 --- a/drc/DRCsubcell.c +++ b/drc/DRCsubcell.c @@ -697,7 +697,7 @@ DRCInteractionCheck(def, area, erasebox, func, cdarg) int oldTiles, count, x, y, errorSaveType; Rect intArea, square, cliparea, subArea; PaintResultType (*savedPaintTable)[NT][NT]; - void (*savedPaintPlane)(); + int (*savedPaintPlane)(); struct drcClientData arg; SearchContext scx; @@ -897,7 +897,7 @@ DRCFlatCheck(use, area) SearchContext scx; void drcIncCount(); PaintResultType (*savedPaintTable)[NT][NT]; - void (*savedPaintPlane)(); + int (*savedPaintPlane)(); int drcFlatCount = 0; UndoDisable(); diff --git a/garouter/gaTest.c b/garouter/gaTest.c index 2e9cf05d..b05cf780 100644 --- a/garouter/gaTest.c +++ b/garouter/gaTest.c @@ -61,7 +61,7 @@ int gaDebNoClean = 0; /* Used in the "*garoute split" command */ PlaneMask gaSplitPlaneMask; -void (*gaSplitPaintPlane)(); +int (*gaSplitPaintPlane)(); Rect gaSplitArea; int gaSplitType; diff --git a/select/selCreate.c b/select/selCreate.c index 62b01ebf..cac59183 100644 --- a/select/selCreate.c +++ b/select/selCreate.c @@ -1074,7 +1074,7 @@ SelectAndCopy2(newSourceDef) SearchContext scx; Rect editArea, labelArea, expanded; int plane; - void (*savedPaintPlane)(); + int (*savedPaintPlane)(); extern int selACPaintFunc(); /* Forward reference. */ extern int selACCellFunc(); From 3af205cd66e596e82091b3c264ddb0b26cd68c37 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 19 Feb 2021 08:52:56 -0500 Subject: [PATCH 11/89] Altered the way that cells in unknown GDS libraries get prefixed, to make it more compatible with SPICE by keeping it case-sensitive and avoiding a number for the first character. --- VERSION | 2 +- calma/CalmaWrite.c | 23 ++++++++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/VERSION b/VERSION index 423f70a6..a82d6cf7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.129 +8.3.130 diff --git a/calma/CalmaWrite.c b/calma/CalmaWrite.c index ff4b83e9..282e83f0 100644 --- a/calma/CalmaWrite.c +++ b/calma/CalmaWrite.c @@ -613,7 +613,7 @@ calmaFullDump(def, fi, outf, filename) FILE *outf; char *filename; { - int version, rval, i; + int version, rval; char *libname = NULL, uniqlibname[4]; char *sptr, *viewopts; bool isAbstract; @@ -657,24 +657,29 @@ calmaFullDump(def, fi, outf, filename) viewopts = (char *)DBPropGet(def, "LEFview", &isAbstract); if ((!isAbstract) || (strcasecmp(viewopts, "no_prefix"))) { - /* Generate a SHORT name for this cell (else it is easy to run into the * GDS 32-character cellname limit). Save it in the hash record. The * chance of generating the same prefix for a library that has items * with conflicting names is vanishingly small, but to be pedantic, store * the prefix in a hash table and check to make sure that uniqueness is - * ensured. + * ensured. NOTE: The first character of a SPICE name cannot be a + * number. Therefore the first character is alphabetical, and the second + * is alphanumeric. There are only 936 possible combinations, but this + * is only meant to distinguish cells in large IP blocks of unknown + * origin, of which only a limited number would be expected. Beware + * the implications for LVS, as the prefixed names from layout would + * need to be compared to un-prefixed names from another netlist. */ while (TRUE) { HashEntry *he2; - for (i = 0; i < 2; i++) { - rval = random() % 62; - rval = (rval < 26) ? ('A' + rval) : ((rval < 52) ? ('a' + rval - 26) : - ('0' + rval - 52)); - uniqlibname[i] = (char)(rval & 127); - } + rval = random() % 26; + rval = 'A' + rval; + uniqlibname[0] = (char)(rval & 127); + rval = random() % 36; + rval = (rval < 26) ? ('A' + rval) : ('0' + rval - 26); + uniqlibname[1] = (char)(rval & 127); uniqlibname[2] = '_'; uniqlibname[3] = '\0'; he2 = HashLookOnly(&calmaPrefixHash, uniqlibname); From 2e9c554f2c044cb34758139375203e2fdf3296c1 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sat, 20 Feb 2021 13:24:02 -0500 Subject: [PATCH 12/89] Revised the wrapper script to use the Tk command "font measure" to get the pixel size of the default font, and scale the window glyphs and scrollbars to match, so that the display is automatically adjusted for screen resolution and does not require manual intervention to correct for high resolution displays. --- VERSION | 2 +- tcltk/wrapper.tcl | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index a82d6cf7..c11794e5 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.130 +8.3.131 diff --git a/tcltk/wrapper.tcl b/tcltk/wrapper.tcl index 5bba211a..4b327c80 100644 --- a/tcltk/wrapper.tcl +++ b/tcltk/wrapper.tcl @@ -554,7 +554,6 @@ set Opts(crosshair) 0 set Opts(hidelocked) 0 set Opts(hidespecial) 0 set Opts(toolbar) 0 -set Opts(scale) 1.0 set Opts(toolscale) 1.0 set Opts(drc) 1 set Opts(autobuttontext) 1 @@ -1135,6 +1134,16 @@ proc magic::openwrapper {{cell ""} {framename ""}} { toplevel $framename tkwait visibility $framename + # Get scale from the TkDefaultFont size, unless Opts(scale) is already + # set. On standard displays, an "M" in the Sans font is usually 10 + # pixels wide, and 22 on high resolution displays, so this maps to + # a scale of 1 on standard displays and a scale of 2 on high resolution + # displays. + + if [catch {set Opts(scale)}] { + set Opts(scale) [expr {int([font measure TkDefaultFont M] / 10)}] + } + # Resize the window if {[catch {wm geometry ${framename} $Winopts(${framename},geometry)}]} { catch {wm geometry ${framename} $Opts(geometry)} From 9a79a1eee26d650f6ed1f433fce7f46dbfec4137 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 23 Feb 2021 09:58:52 -0500 Subject: [PATCH 13/89] Fixed a minor error in the plot command that is missing a value in the print statement on detecting an invalid plot parameter value name. --- VERSION | 2 +- plot/plotMain.c | 3 ++- tcltk/toolkit.tcl | 8 ++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index c11794e5..287d1797 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.131 +8.3.132 diff --git a/plot/plotMain.c b/plot/plotMain.c index cce614c8..9583c2d4 100644 --- a/plot/plotMain.c +++ b/plot/plotMain.c @@ -538,7 +538,8 @@ PlotSetParam(name, value) { int j; - TxError("%s is not a supported plot type. Plot types are:\n"); + TxError("%s is not a supported plot type. Plot types are:\n", + value); for (j = 0 ; plotTypeNames[j] != NULL; j++) { TxError("\t%s\n", plotTypeNames[j]); diff --git a/tcltk/toolkit.tcl b/tcltk/toolkit.tcl index b3d43019..adaaee99 100644 --- a/tcltk/toolkit.tcl +++ b/tcltk/toolkit.tcl @@ -436,6 +436,14 @@ proc magic::gencell_change {instname gencell_type library parameters} { # then keep the old instance name. if {[string first $old_gname $instname] != 0} { set newinstname $instname + } else { + # The buttons "Apply" and "Okay" need to be changed for the new + # instance name + catch {.params.buttons.apply config -command \ + "magic::gencell_change $newinstname $gencell_type $library {}"} + catch {.params.buttons.okay config -command \ + "magic::gencell_change $newinstname $gencell_type $library {} ;\ + destroy .params"} } } identify $newinstname From 46baae0ce63fa3d140762955ef975f963713d3be Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 23 Feb 2021 13:46:12 -0500 Subject: [PATCH 14/89] Modified the .ext file reading and the .spice file writing so that array delimiters and hierarchy separators (characters '/', '[', and ']') that are part of instances or labels passed to magic, are preserved from input to output, but internally marked (with a backslash escape) so that they are not misinterpreted my magic when running ext2spice. --- ext2spice/ext2spice.c | 65 +++++++++++++++---------- extflat/EFbuild.c | 108 ++++++++++++++++++++++++++++++++++++++++-- extflat/EFname.c | 4 +- 3 files changed, 147 insertions(+), 30 deletions(-) diff --git a/ext2spice/ext2spice.c b/ext2spice/ext2spice.c index 976ab6b8..8c282178 100644 --- a/ext2spice/ext2spice.c +++ b/ext2spice/ext2spice.c @@ -3359,6 +3359,7 @@ char *nodeSpiceName(hname, rnode) EFNodeName *nn; HashEntry *he; EFNode *node; + char *p, *s; if (rnode) *rnode = (EFNode *)NULL; he = EFHNLook(hname, (char *) NULL, "nodeName"); @@ -3384,8 +3385,21 @@ makeName: if ( esFormat == HSPICE ) /* more processing */ nodeHspiceName(esTempName); } - ((nodeClient *) (node->efnode_client))->spiceNodeName = - StrDup(NULL, esTempName); + + /* Strip any escaped-slash hiearchy dividers or array delimiters */ + /* out of the name, as they have been put there to prevent magic */ + /* from interpeting them as hierarchy divers or array delimiters. */ + + for (s = p = esTempName; *s; p++, s++) + { + if ((*s == '\\') && ((*(s + 1) == '/') || (*(s + 1) == '[') + || (*(s + 1) == ']'))) + s++; + if (p != s) *p = *s; + } + if (p != s) *p = *s; /* Copy trailing NULL */ + + ((nodeClient *)(node->efnode_client))->spiceNodeName = StrDup(NULL, esTempName); retName: return ((nodeClient *) (node->efnode_client))->spiceNodeName; @@ -3399,7 +3413,8 @@ retName: * Create a hierarchical node name. * The flags in EFTrimFlags control whether global (!) or local (#) * suffixes are to be trimmed. Also substitutes \. with \@ if the - * format is hspice. + * format is hspice. Backslash-escaped slashes are converted back + * to the original character. * * Results: * None. @@ -3416,36 +3431,34 @@ EFHNSprintf(str, hierName) HierName *hierName; { bool trimGlob, trimLocal, convertComma, convertEqual, convertBrackets; - char *s, *cp, c; + char *cp, c; char *efHNSprintfPrefix(HierName *, char *); - s = str; if (hierName->hn_parent) str = efHNSprintfPrefix(hierName->hn_parent, str); - if (EFTrimFlags) + + cp = hierName->hn_name; + trimGlob = (EFTrimFlags & EF_TRIMGLOB); + trimLocal = (EFTrimFlags & EF_TRIMLOCAL); + convertComma = (EFTrimFlags & EF_CONVERTCOMMA); + convertEqual = (EFTrimFlags & EF_CONVERTEQUAL); + convertBrackets = (EFTrimFlags & EF_CONVERTBRACKETS); + while (c = *cp++) { - cp = hierName->hn_name; - trimGlob = (EFTrimFlags & EF_TRIMGLOB); - trimLocal = (EFTrimFlags & EF_TRIMLOCAL); - convertComma = (EFTrimFlags & EF_CONVERTCOMMA); - convertEqual = (EFTrimFlags & EF_CONVERTEQUAL); - convertBrackets = (EFTrimFlags & EF_CONVERTBRACKETS); - while (c = *cp++) + switch (c) { - switch (c) - { - case '!': if (!trimGlob) *str++ = c; break; - case '.': *str++ = (esFormat == HSPICE)?'@':'.'; break; - case '=': if (convertEqual) *str++ = ':'; break; - case ',': if (convertComma) *str++ = '|'; break; - case '[': *str++ = (convertBrackets) ? '_' : '['; break; - case ']': *str++ = (convertBrackets) ? '_' : ']'; break; - case '#': if (trimLocal) break; // else fall through - default: *str++ = c; break; - } + case '!': if (!trimGlob) *str++ = c; break; + case '.': *str++ = (esFormat == HSPICE)?'@':'.'; break; + case '=': if (convertEqual) *str++ = ':'; break; + case ',': if (convertComma) *str++ = '|'; break; + case '[': *str++ = (convertBrackets) ? '_' : '['; break; + case ']': *str++ = (convertBrackets) ? '_' : ']'; break; + case '\\': if (*(cp + 1) == '/') str++; break; + case '#': if (trimLocal) break; // else fall through + default: *str++ = c; break; } - *str++ = '\0'; } - else strcpy(str, hierName->hn_name); + *str++ = '\0'; + return 0; } diff --git a/extflat/EFbuild.c b/extflat/EFbuild.c index 09ac3a2e..ccb38dc8 100644 --- a/extflat/EFbuild.c +++ b/extflat/EFbuild.c @@ -1142,6 +1142,98 @@ efBuildAddStr(table, pMax, size, str) return max; } +/* + * ---------------------------------------------------------------------------- + * + * efNeedsCleanName -- + * + * Determine if a name needs to be cleaned by efMakeCleanName, to avoid + * excessive and unnecessary string allocation and copying . + * + * "level" is 0 or 1, defined as it is for efMakeCleanName() (see below). + * + * ---------------------------------------------------------------------------- + */ + +bool +efNeedsCleanName(str, level) + char *str; + int level; +{ + char *s; + bool seenOne = FALSE; + bool needsCleaning = FALSE; + + for (s = str; *s; s++) + if (*s == '/') + if ((s == str) || (*(s - 1) != '\\')) + { + if ((level == 0) || seenOne) + { + needsCleaning = TRUE; + break; + } + seenOne = TRUE; + } + + return needsCleaning; +} + +/* + * ---------------------------------------------------------------------------- + * + * efMakeCleanName -- + * + * Generate a copy of a name like StrDup(), but cleanse the name of slash + * characters by backslash-escaping them. This lets ext2spice differentiate + * between slashes that are part of an instance name and the hierarchical + * name for a node, which is built up internally with slash characters. + * + * "level" is the number of slashes at the end which are part of the + * hierarchy and not part of the name. "use" lines in the .ext file should + * have a level of 0, while "merge" lines have a level of 1. No other values + * of "level" are supported. + * + * ---------------------------------------------------------------------------- + */ + +char * +efMakeCleanName(str, level) + char *str; + int level; +{ + char *rstr; + char *s, *p, *ssave; + int escapes; + + /* Count unescaped slashes in the string */ + escapes = 0; + ssave = NULL; + for (s = str; *s; s++) + if (*s == '/') + if ((s == str) || (*(s - 1) != '\\')) + { + ssave = s; + escapes++; + } + + if (escapes > 0) + escapes -= level; + + rstr = (char *)mallocMagic(strlen(str) + 1 + escapes); + + for (s = str, p = rstr; *s; s++, p++) + { + if (*s == '/') + if ((s == str) || (*(s - 1) != '\\')) + if ((level == 0) || (s != ssave)) + *p++ = '\\'; + *p = *s; + } + *p = *s; /* Copy final NULL */ + return rstr; +} + /* * ---------------------------------------------------------------------------- * @@ -1213,12 +1305,12 @@ efBuildUse(def, subDefName, subUseId, ta, tb, tc, td, te, tf) &newuse->use_ylo, &newuse->use_yhi, &newuse->use_ysep)) == 6) { *cp = '\0'; - newuse->use_id = StrDup((char **) NULL, subUseId); + newuse->use_id = efMakeCleanName(subUseId, 0); *cp = '['; } else { - newuse->use_id = StrDup((char **) NULL, subUseId); + newuse->use_id = efMakeCleanName(subUseId, 0); newuse->use_xlo = newuse->use_xhi = 0; newuse->use_ylo = newuse->use_yhi = 0; newuse->use_xsep = newuse->use_ysep = 0; @@ -1260,13 +1352,20 @@ efBuildConnect(def, nodeName1, nodeName2, deltaC, av, ac) int ac; /* Number of strings in av */ { int n; + char *locName1, *locName2; Connection *conn; unsigned size = sizeof (Connection) + (efNumResistClasses - 1) * sizeof (EFPerimArea); conn = (Connection *) mallocMagic((unsigned)(size)); - if (efConnInitSubs(conn, nodeName1, nodeName2)) + locName1 = nodeName1; + if (efNeedsCleanName(nodeName1)) locName1 = efMakeCleanName(nodeName1, 1); + + locName2 = nodeName2; + if (efNeedsCleanName(nodeName2)) locName2 = efMakeCleanName(nodeName2, 1); + + if (efConnInitSubs(conn, locName1, locName2)) { conn->conn_cap = (EFCapValue) deltaC; conn->conn_next = def->def_conns; @@ -1280,6 +1379,9 @@ efBuildConnect(def, nodeName1, nodeName2, deltaC, av, ac) conn->conn_pa[n].pa_area = conn->conn_pa[n].pa_perim = 0; def->def_conns = conn; } + + if (locName1 != nodeName1) freeMagic(locName1); + if (locName2 != nodeName2) freeMagic(locName2); } /* diff --git a/extflat/EFname.c b/extflat/EFname.c index 60365cdd..cdb931fe 100644 --- a/extflat/EFname.c +++ b/extflat/EFname.c @@ -225,7 +225,8 @@ EFStrToHN(prefix, suffixStr) /* * Convert the relative name into a HierName path, with one HierName - * created for each slash-separated segment of suffixStr. + * created for each slash-separated segment of suffixStr. Backslash- + * escaped slashes are not part of a path and are ignored. */ cp = slashPtr = suffixStr; for (;;) @@ -242,6 +243,7 @@ EFStrToHN(prefix, suffixStr) slashPtr = cp; prefix = hierName; } + else if ((*cp == '\\') && (*(cp + 1) == '/')) cp += 2; else cp++; } From a61026588c6af49d282043705010fe4885ed8d88 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 24 Feb 2021 12:35:06 -0500 Subject: [PATCH 15/89] Revert "Modified the .ext file reading and the .spice file writing so that" This reverts commit 46baae0ce63fa3d140762955ef975f963713d3be. Reverting the last commit, as it does not work completely the way it is supposed to, and will most likely have to be done in a different way. --- ext2spice/ext2spice.c | 65 ++++++++++--------------- extflat/EFbuild.c | 108 ++---------------------------------------- extflat/EFname.c | 4 +- 3 files changed, 30 insertions(+), 147 deletions(-) diff --git a/ext2spice/ext2spice.c b/ext2spice/ext2spice.c index 8c282178..976ab6b8 100644 --- a/ext2spice/ext2spice.c +++ b/ext2spice/ext2spice.c @@ -3359,7 +3359,6 @@ char *nodeSpiceName(hname, rnode) EFNodeName *nn; HashEntry *he; EFNode *node; - char *p, *s; if (rnode) *rnode = (EFNode *)NULL; he = EFHNLook(hname, (char *) NULL, "nodeName"); @@ -3385,21 +3384,8 @@ makeName: if ( esFormat == HSPICE ) /* more processing */ nodeHspiceName(esTempName); } - - /* Strip any escaped-slash hiearchy dividers or array delimiters */ - /* out of the name, as they have been put there to prevent magic */ - /* from interpeting them as hierarchy divers or array delimiters. */ - - for (s = p = esTempName; *s; p++, s++) - { - if ((*s == '\\') && ((*(s + 1) == '/') || (*(s + 1) == '[') - || (*(s + 1) == ']'))) - s++; - if (p != s) *p = *s; - } - if (p != s) *p = *s; /* Copy trailing NULL */ - - ((nodeClient *)(node->efnode_client))->spiceNodeName = StrDup(NULL, esTempName); + ((nodeClient *) (node->efnode_client))->spiceNodeName = + StrDup(NULL, esTempName); retName: return ((nodeClient *) (node->efnode_client))->spiceNodeName; @@ -3413,8 +3399,7 @@ retName: * Create a hierarchical node name. * The flags in EFTrimFlags control whether global (!) or local (#) * suffixes are to be trimmed. Also substitutes \. with \@ if the - * format is hspice. Backslash-escaped slashes are converted back - * to the original character. + * format is hspice. * * Results: * None. @@ -3431,34 +3416,36 @@ EFHNSprintf(str, hierName) HierName *hierName; { bool trimGlob, trimLocal, convertComma, convertEqual, convertBrackets; - char *cp, c; + char *s, *cp, c; char *efHNSprintfPrefix(HierName *, char *); + s = str; if (hierName->hn_parent) str = efHNSprintfPrefix(hierName->hn_parent, str); - - cp = hierName->hn_name; - trimGlob = (EFTrimFlags & EF_TRIMGLOB); - trimLocal = (EFTrimFlags & EF_TRIMLOCAL); - convertComma = (EFTrimFlags & EF_CONVERTCOMMA); - convertEqual = (EFTrimFlags & EF_CONVERTEQUAL); - convertBrackets = (EFTrimFlags & EF_CONVERTBRACKETS); - while (c = *cp++) + if (EFTrimFlags) { - switch (c) + cp = hierName->hn_name; + trimGlob = (EFTrimFlags & EF_TRIMGLOB); + trimLocal = (EFTrimFlags & EF_TRIMLOCAL); + convertComma = (EFTrimFlags & EF_CONVERTCOMMA); + convertEqual = (EFTrimFlags & EF_CONVERTEQUAL); + convertBrackets = (EFTrimFlags & EF_CONVERTBRACKETS); + while (c = *cp++) { - case '!': if (!trimGlob) *str++ = c; break; - case '.': *str++ = (esFormat == HSPICE)?'@':'.'; break; - case '=': if (convertEqual) *str++ = ':'; break; - case ',': if (convertComma) *str++ = '|'; break; - case '[': *str++ = (convertBrackets) ? '_' : '['; break; - case ']': *str++ = (convertBrackets) ? '_' : ']'; break; - case '\\': if (*(cp + 1) == '/') str++; break; - case '#': if (trimLocal) break; // else fall through - default: *str++ = c; break; + switch (c) + { + case '!': if (!trimGlob) *str++ = c; break; + case '.': *str++ = (esFormat == HSPICE)?'@':'.'; break; + case '=': if (convertEqual) *str++ = ':'; break; + case ',': if (convertComma) *str++ = '|'; break; + case '[': *str++ = (convertBrackets) ? '_' : '['; break; + case ']': *str++ = (convertBrackets) ? '_' : ']'; break; + case '#': if (trimLocal) break; // else fall through + default: *str++ = c; break; + } } + *str++ = '\0'; } - *str++ = '\0'; - + else strcpy(str, hierName->hn_name); return 0; } diff --git a/extflat/EFbuild.c b/extflat/EFbuild.c index ccb38dc8..09ac3a2e 100644 --- a/extflat/EFbuild.c +++ b/extflat/EFbuild.c @@ -1142,98 +1142,6 @@ efBuildAddStr(table, pMax, size, str) return max; } -/* - * ---------------------------------------------------------------------------- - * - * efNeedsCleanName -- - * - * Determine if a name needs to be cleaned by efMakeCleanName, to avoid - * excessive and unnecessary string allocation and copying . - * - * "level" is 0 or 1, defined as it is for efMakeCleanName() (see below). - * - * ---------------------------------------------------------------------------- - */ - -bool -efNeedsCleanName(str, level) - char *str; - int level; -{ - char *s; - bool seenOne = FALSE; - bool needsCleaning = FALSE; - - for (s = str; *s; s++) - if (*s == '/') - if ((s == str) || (*(s - 1) != '\\')) - { - if ((level == 0) || seenOne) - { - needsCleaning = TRUE; - break; - } - seenOne = TRUE; - } - - return needsCleaning; -} - -/* - * ---------------------------------------------------------------------------- - * - * efMakeCleanName -- - * - * Generate a copy of a name like StrDup(), but cleanse the name of slash - * characters by backslash-escaping them. This lets ext2spice differentiate - * between slashes that are part of an instance name and the hierarchical - * name for a node, which is built up internally with slash characters. - * - * "level" is the number of slashes at the end which are part of the - * hierarchy and not part of the name. "use" lines in the .ext file should - * have a level of 0, while "merge" lines have a level of 1. No other values - * of "level" are supported. - * - * ---------------------------------------------------------------------------- - */ - -char * -efMakeCleanName(str, level) - char *str; - int level; -{ - char *rstr; - char *s, *p, *ssave; - int escapes; - - /* Count unescaped slashes in the string */ - escapes = 0; - ssave = NULL; - for (s = str; *s; s++) - if (*s == '/') - if ((s == str) || (*(s - 1) != '\\')) - { - ssave = s; - escapes++; - } - - if (escapes > 0) - escapes -= level; - - rstr = (char *)mallocMagic(strlen(str) + 1 + escapes); - - for (s = str, p = rstr; *s; s++, p++) - { - if (*s == '/') - if ((s == str) || (*(s - 1) != '\\')) - if ((level == 0) || (s != ssave)) - *p++ = '\\'; - *p = *s; - } - *p = *s; /* Copy final NULL */ - return rstr; -} - /* * ---------------------------------------------------------------------------- * @@ -1305,12 +1213,12 @@ efBuildUse(def, subDefName, subUseId, ta, tb, tc, td, te, tf) &newuse->use_ylo, &newuse->use_yhi, &newuse->use_ysep)) == 6) { *cp = '\0'; - newuse->use_id = efMakeCleanName(subUseId, 0); + newuse->use_id = StrDup((char **) NULL, subUseId); *cp = '['; } else { - newuse->use_id = efMakeCleanName(subUseId, 0); + newuse->use_id = StrDup((char **) NULL, subUseId); newuse->use_xlo = newuse->use_xhi = 0; newuse->use_ylo = newuse->use_yhi = 0; newuse->use_xsep = newuse->use_ysep = 0; @@ -1352,20 +1260,13 @@ efBuildConnect(def, nodeName1, nodeName2, deltaC, av, ac) int ac; /* Number of strings in av */ { int n; - char *locName1, *locName2; Connection *conn; unsigned size = sizeof (Connection) + (efNumResistClasses - 1) * sizeof (EFPerimArea); conn = (Connection *) mallocMagic((unsigned)(size)); - locName1 = nodeName1; - if (efNeedsCleanName(nodeName1)) locName1 = efMakeCleanName(nodeName1, 1); - - locName2 = nodeName2; - if (efNeedsCleanName(nodeName2)) locName2 = efMakeCleanName(nodeName2, 1); - - if (efConnInitSubs(conn, locName1, locName2)) + if (efConnInitSubs(conn, nodeName1, nodeName2)) { conn->conn_cap = (EFCapValue) deltaC; conn->conn_next = def->def_conns; @@ -1379,9 +1280,6 @@ efBuildConnect(def, nodeName1, nodeName2, deltaC, av, ac) conn->conn_pa[n].pa_area = conn->conn_pa[n].pa_perim = 0; def->def_conns = conn; } - - if (locName1 != nodeName1) freeMagic(locName1); - if (locName2 != nodeName2) freeMagic(locName2); } /* diff --git a/extflat/EFname.c b/extflat/EFname.c index cdb931fe..60365cdd 100644 --- a/extflat/EFname.c +++ b/extflat/EFname.c @@ -225,8 +225,7 @@ EFStrToHN(prefix, suffixStr) /* * Convert the relative name into a HierName path, with one HierName - * created for each slash-separated segment of suffixStr. Backslash- - * escaped slashes are not part of a path and are ignored. + * created for each slash-separated segment of suffixStr. */ cp = slashPtr = suffixStr; for (;;) @@ -243,7 +242,6 @@ EFStrToHN(prefix, suffixStr) slashPtr = cp; prefix = hierName; } - else if ((*cp == '\\') && (*(cp + 1) == '/')) cp += 2; else cp++; } From f2af32636879af5a801c14fcd7fa0cdac7389b6e Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 24 Feb 2021 14:41:35 -0500 Subject: [PATCH 16/89] Gave up on attempting to separate out slashes in instance names from slashes in hierarchical names. Magic does not allow slashes in names when using "identify", so the simplest solution is just to prohibit them in names being read from GDS files, and replace them with underscores to make them magic-compatible. Changing GDS names always has repercussions on things like back-annotating delays, so it should probably be revisited in the future. --- calma/CalmaRdcl.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/calma/CalmaRdcl.c b/calma/CalmaRdcl.c index b3568a49..7d0734c6 100644 --- a/calma/CalmaRdcl.c +++ b/calma/CalmaRdcl.c @@ -48,6 +48,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ int calmaNonManhattan; int CalmaFlattenLimit = 10; +int NameConvertErrors = 0; extern HashTable calmaDefInitHash; @@ -836,8 +837,24 @@ calmaElementSref(filename) READI2(propAttrType); if (propAttrType == CALMA_PROP_USENAME) { + char *s; + if (!calmaReadStringRecord(CALMA_PROPVALUE, &useid)) return -1; + + /* Magic prohibits comma and slash from use names */ + for (s = useid; *s; s++) + if (*s == '/' || *s == ',') + { + if (NameConvertErrors < 100) + TxPrintf("\"%c\" character cannot be used in instance name; " + "converting to underscore\n", *s); + else if (NameConvertErrors == 100) + TxPrintf("More than 100 character changes; not reporting" + " further errors.\n"); + *s = '_'; + NameConvertErrors++; + } } else if (propAttrType == CALMA_PROP_ARRAY_LIMITS) { From 2bb3580f3ed024a7afec8e45ca2ed787f1326ff5 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 24 Feb 2021 14:51:46 -0500 Subject: [PATCH 17/89] Also modified DEF reads to avoid letting instance names contain either slash or comma. --- VERSION | 2 +- lef/defRead.c | 26 +++++++++++--------------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/VERSION b/VERSION index 287d1797..7f0c6553 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.132 +8.3.133 diff --git a/lef/defRead.c b/lef/defRead.c index 9156e0e7..3e1bdd71 100644 --- a/lef/defRead.c +++ b/lef/defRead.c @@ -1546,24 +1546,20 @@ DefReadComponents(f, rootDef, sname, oscale, total) break; } - /* Does use name contain brackets? If so, this can */ - /* interfere with magic's use of arrays. */ - /* NOTE: This has been commented out. I think */ - /* the only confusion is in ext2spice and can be */ - /* avoided by allowing any bracket notation in an */ - /* instance name other than that used by the .ext */ - /* file for dealing with arrays, which uses the */ - /* specific syntax [xlo:xsep:xhi][ylo:ysep:yhi] and */ - /* is easy enough to distinguish. */ + /* Magic prohibits slashes and commas in use names */ + /* when using the "identify" command. Removing these */ + /* restrictions (at least the slash) is quite complex, */ + /* but really should be taken care of, since no other */ + /* tools consider this an illegal use, that I'm aware */ + /* of. */ - /* - dptr = strchr(usename, '['); - if (dptr != NULL) { + for (dptr = usename; *dptr; dptr++) + if ((*dptr == '/') || (*dptr == ',')) + { + LefError(DEF_WARNING, "Character in instance name " + "converted to underscore.\n"); *dptr = '_'; - dptr = strchr(dptr + 1, ']'); - if (dptr != NULL) *dptr = '_'; } - */ token = LefNextToken(f, TRUE); From 114b9a59f7d1673caec662304c36bccbe76920de Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 25 Feb 2021 13:37:31 -0500 Subject: [PATCH 18/89] Implemented more automation for attempting to find a tech file based on the contents of a .mag file being read in, assuming compatibility with principles of open_pdks. The search paths are not meddled with unless a file is read for which the technology cannot be found (and a technology has not already been read, or at least no database file exists in memory using any technology that has already been read). If so, then variables PDK_PATH and PDK_ROOT are searched for in both the shell environment and the local Tcl environment. Also, if open_pdks has installed PDKs in the path /usr/share/pdk/, then that path will be searched. If a corresponding technology file is found, it will be loaded. If the path corresponds to an open_pdks-style path, then the library paths in libs.ref will also be added to the search paths for cells. --- VERSION | 2 +- database/DBio.c | 249 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 243 insertions(+), 8 deletions(-) diff --git a/VERSION b/VERSION index 7f0c6553..72b47869 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.133 +8.3.134 diff --git a/database/DBio.c b/database/DBio.c index 56874065..e9026ef8 100644 --- a/database/DBio.c +++ b/database/DBio.c @@ -135,6 +135,132 @@ file_is_not_writeable(name) return(0); } +/* + * ---------------------------------------------------------------------------- + * + * DBSearchForTech -- + * + * Helper function for automatically discovering a technology used in a + * .mag file when reading. This function will recursively search all + * directories rooted at "pathroot" looking for a file "techname" which + * must include the ".tech" extension. If found, the path name is returned. + * + * Results: + * Pointer to a string containing the path name. This is allocated so as + * not to be lost, and must be freed by the caller. + * + * Side effects: + * None. + * + * ---------------------------------------------------------------------------- + */ + +char * +DBSearchForTech(techname, pathroot, level) + char *techname; + char *pathroot; + int level; +{ + char *newpath, *found; + struct dirent *tdent; + DIR *tdir; + + /* Avoid potential infinite looping. Any tech file should not be very */ + /* far down the path. 10 levels is already excessive. */ + if (level > 10) return NULL; + + tdir = opendir(pathroot); + if (tdir) { + + /* Read the directory contents of tdir */ + while ((tdent = readdir(tdir)) != NULL) + { + if (tdent->d_type != DT_DIR) + { + if (!strcmp(tdent->d_name, techname)) + return pathroot; + } + else if (strcmp(tdent->d_name, ".") && strcmp(tdent->d_name, "..")) + { + newpath = mallocMagic(strlen(pathroot) + strlen(tdent->d_name) + 3); + sprintf(newpath, "%s/%s", pathroot, tdent->d_name); + found = DBSearchForTech(techname, newpath, level + 1); + if (found != newpath) freeMagic(newpath); + if (found) return found; + } + } + closedir(tdir); + } + else + return NULL; +} + +/* + * ---------------------------------------------------------------------------- + * + * DBAddStandardCellPaths -- + * + * Search for .mag files in any directory below "pathptr", for any + * directory found containing .mag files, add that path to the search + * path for cells. + * + * Results: + * Number of paths added to CellLibPath. + * + * Side effects: + * May add paths to the CellLibPath. + * + * ---------------------------------------------------------------------------- + */ + +int +DBAddStandardCellPaths(pathptr, level) + char *pathptr; + int level; +{ + int paths = 0; + struct dirent *tdent; + char *newpath; + DIR *tdir; + bool magfound = FALSE; + + /* Avoid potential infinite looping. Any tech file should not be very */ + /* far down the path. 10 levels is already excessive. */ + if (level > 10) return 0; + + tdir = opendir(pathptr); + if (tdir) { + + while ((tdent = readdir(tdir)) != NULL) + { + if ((tdent->d_type == DT_DIR) && + (strcmp(tdent->d_name, ".") && strcmp(tdent->d_name, ".."))) + { + /* Scan the directory contents of tdir for more subdirectories */ + newpath = mallocMagic(strlen(pathptr) + strlen(tdent->d_name) + 3); + sprintf(newpath, "%s/%s", pathptr, tdent->d_name); + paths += DBAddStandardCellPaths(newpath, level + 1); + freeMagic(newpath); + } + else if (tdent->d_type != DT_DIR) + { + /* Scan the directory contents of tdir for .mag files */ + if (!strcmp(tdent->d_name + strlen(tdent->d_name) - 4, ".mag")) + { + if (magfound == FALSE) + { + PaAppend(&CellLibPath, pathptr); + paths++; + magfound = TRUE; + } + } + } + } + closedir(tdir); + } + return paths; +} + /* * ---------------------------------------------------------------------------- * @@ -335,13 +461,122 @@ dbCellReadDef(f, cellDef, name, ignoreTech, dereference) TxPrintf("Will attempt to read cell anyway.\n"); else { - TxError("Use command \"tech load\" if you want to switch" - " technologies, or use\n"); - TxError("\"cellname delete %s\" and \"load %s -force\" to" - " force the cell to load as technology %s\n", - cellDef->cd_name, cellDef->cd_name, DBTechName); - SigEnableInterrupts(); - return (FALSE); + /* If no cells are currently in memory, then make an + * attempt to find the technology associated with the + * layout and load it. + */ + + if (!CmdCheckForPaintFunc()) + { + /* Places to check for a technology: In the PDK_ROOT + * (PDKROOT) directory, PDK_PATH (PDKPATH) from environment + * variables, and CAD_ROOT from Tcl variables; the open_pdks + * default install path /usr/share/pdk/, and magic's install + * path. For CAD_ROOT the variable is expected to point to + * a path containing the techfile. For PDK_PATH and PDK_ROOT, + * search the directory tree for any subdirectory called + * magic/ and look for a compatible techfile there. + */ + char *found = NULL; + char *string, *techfullname; + + techfullname = mallocMagic(strlen(tech) + 6); + sprintf(techfullname, "%s.tech", tech); + + string = getenv("PDK_PATH"); + if (string) + found = DBSearchForTech(techfullname, string, 0); + if (!found) + { + string = getenv("PDKPATH"); + if (string) + found = DBSearchForTech(techfullname, string, 0); + } + if (!found) + { + string = getenv("PDK_ROOT"); + if (string) + found = DBSearchForTech(techfullname, string, 0); + } + if (!found) + { + string = getenv("PDKROOT"); + if (string) + found = DBSearchForTech(techfullname, string, 0); + } + if (!found) + { + found = DBSearchForTech(techfullname, "/usr/share/pdk", 0); + } +#ifdef MAGIC_WRAPPER + /* Additional checks for PDK_PATH, etc., as Tcl variables. */ + /* This is unlikely, as they would have to be set in a */ + /* startup file, and a startup file is likely to just load */ + /* the technology itself. */ + if (!found) + { + string = (char *)Tcl_GetVar(magicinterp, "PDK_ROOT", + TCL_GLOBAL_ONLY); + if (string) + found = DBSearchForTech(techfullname, string, 0); + } + if (!found) + { + string = (char *)Tcl_GetVar(magicinterp, "PDKROOT", + TCL_GLOBAL_ONLY); + if (string) + found = DBSearchForTech(techfullname, string, 0); + } + if (!found) + { + string = (char *)Tcl_GetVar(magicinterp, "PDK_PATH", + TCL_GLOBAL_ONLY); + if (string) + found = DBSearchForTech(techfullname, string, 0); + } + if (!found) + { + string = (char *)Tcl_GetVar(magicinterp, "PDKPATH", + TCL_GLOBAL_ONLY); + if (string) + found = DBSearchForTech(techfullname, string, 0); + } + +#endif + freeMagic(techfullname); + if (found) + { + char *sptr; + PaAppend(&SysLibPath, found); + + TxError("Loading technology %s\n", tech); + if (!TechLoad(tech, 0)) + TxError("Error in loading technology file\n"); + else if ((sptr = strstr(found, "libs.tech")) != NULL) + { + int paths = 0; + /* Additional automatic handling of open_pdks- */ + /* style PDKs. Append the libs.ref libraries */ + /* to the cell search path. */ + + strcpy(sptr + 5, "ref"); + paths = DBAddStandardCellPaths(found, 0); + if (paths > 0) + TxPrintf("Cell path is now \"%s\"\n", CellLibPath); + } + freeMagic(found); + } + } + if (strcmp(DBTechName, tech)) + { + TxError("Use command \"tech load\" if you want to switch" + " technologies, or use\n"); + TxError("\"cellname delete %s\" and \"load %s -force\" to" + " force the cell to load as technology %s\n", + cellDef->cd_name, cellDef->cd_name, DBTechName); + SigEnableInterrupts(); + return (FALSE); + } } } if (dbFgets(line, sizeof line, f) == NULL) From 4cc09afeacafc4f32e9dc5d9726a23593f20d3dc Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 25 Feb 2021 17:51:12 -0500 Subject: [PATCH 19/89] Corrected some errors relating to distributed allocation of node area and perimeter across devices. The distributed allocation was missing for hierarchical output, and the function that accumulates values per resistance class was initializing by iterating over device classes, not resistance classes, leading to a segfault if the number of device classes is larger than the number of resistance classes. --- ext2spice/ext2hier.c | 2 ++ ext2spice/ext2spice.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ext2spice/ext2hier.c b/ext2spice/ext2hier.c index b8dff398..c8685430 100644 --- a/ext2spice/ext2hier.c +++ b/ext2spice/ext2hier.c @@ -1892,6 +1892,8 @@ esHierVisit(hc, cdata) freeMagic(p); devMergeList = NULL; } + else if (esDistrJunct) + EFHierVisitDevs(hcf, devDistJunctHierVisit, (ClientData)NULL); /* Output devices */ EFHierVisitDevs(hcf, spcdevHierVisit, (ClientData)NULL); diff --git a/ext2spice/ext2spice.c b/ext2spice/ext2spice.c index 976ab6b8..01442a7f 100644 --- a/ext2spice/ext2spice.c +++ b/ext2spice/ext2spice.c @@ -3973,7 +3973,7 @@ update_w(resClass, w, n) { (nc->m_w.widths) = (float *)mallocMagic((unsigned)sizeof(float) * efNumResistClasses); - for (i = 0; i < EFDevNumTypes; i++) + for (i = 0; i < efNumResistClasses; i++) nc->m_w.widths[i] = 0.0; } nc->m_w.widths[resClass] += (float)w; From 83808dcf796f7e451f5cfd438d7aceb34aeeee45 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 1 Mar 2021 11:08:25 -0500 Subject: [PATCH 20/89] Corrected an error that was causing disconnects in the hierarchical SPICE netlist output that appears to have come from flags created for writing DEF that inappropriately got set during ext2spice. A redundant call to efAddNodes() was adding confusion by appearing to handle most cases but actually missing some. With the corrected flag, the redundant call is really redundant and can be removed. It has not been tested whether DEF output is affected by the change (DEF output from magic is rarely used, anyway). --- ext2spice/ext2hier.c | 8 ++++++-- extflat/EFflat.c | 16 ++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/ext2spice/ext2hier.c b/ext2spice/ext2hier.c index b8dff398..90fc6404 100644 --- a/ext2spice/ext2hier.c +++ b/ext2spice/ext2hier.c @@ -81,6 +81,7 @@ ESGenerateHierarchy(inName, flags) hc.hc_hierName = NULL; hc.hc_trans = GeoIdentityTransform; hc.hc_x = hc.hc_y = 0; + EFHierSrDefs(&hc, esMakePorts, NULL); EFHierSrDefs(&hc, NULL, NULL); /* Clear processed */ @@ -1637,8 +1638,11 @@ esMakePorts(hc, cdata) *tptr = '/'; portname = tptr + 1; - // Find the net of portname in the subcell and - // make it a port if it is not already. + /* Find the net of portname in the subcell and make it a + * port if it is not already. It is possible that the + * preferred node name is in the merge list, so the merging + * code may need to replace it with another name. + */ if (portdef) { diff --git a/extflat/EFflat.c b/extflat/EFflat.c index 3c333dd1..516c1f50 100644 --- a/extflat/EFflat.c +++ b/extflat/EFflat.c @@ -204,7 +204,7 @@ EFFlatBuildOneLevel(def, flags) efFlatRootUse.use_def = efFlatRootDef; /* Record all nodes down the hierarchy from here */ - flatnodeflags = FLATNODE_STDCELL; /* No FLATDNODE_DOWARN flag */ + flatnodeflags = 0; /* No FLATNODE_DOWARN */ efFlatNodes(&efFlatContext, (ClientData)flatnodeflags); /* Expand all subcells that contain connectivity information but */ @@ -219,10 +219,6 @@ EFFlatBuildOneLevel(def, flags) if ((usecount == 0) && (HashGetNumEntries(&efFlatRootUse.use_def->def_devs) == 0)) efFlatRootUse.use_def->def_flags |= DEF_NODEVICES; - /* Record all local nodes */ - efAddNodes(&efFlatContext, FALSE); - efAddConns(&efFlatContext, TRUE); - efFlatKills(&efFlatContext); if (!(flags & EF_NONAMEMERGE)) efFlatGlob(); @@ -297,6 +293,9 @@ EFFlatDone() * Adds node names to the table of flattened node names efNodeHashTable. * May merge nodes from the list efNodeList as per the connection * list hc->hc_use->use_def->def_conns. + * + * Note: + * stdcell = TRUE is only used when writing DEF files. * * ---------------------------------------------------------------------------- */ @@ -499,15 +498,15 @@ efAddNodes(hc, stdcell) newnode->efnode_loc.r_ybot = (int)((float)(newnode->efnode_loc.r_ybot) * scale); newnode->efnode_loc.r_ytop = (int)((float)(newnode->efnode_loc.r_ytop) * scale); + /* Add each name for this node to the hash table */ + newnode->efnode_name = (EFNodeName *) NULL; + /* Prepend to global node list */ newnode->efnode_next = efNodeList.efnode_next; newnode->efnode_prev = (EFNodeHdr *) &efNodeList; efNodeList.efnode_next->efnhdr_prev = (EFNodeHdr *) newnode; efNodeList.efnode_next = (EFNodeHdr *) newnode; - /* Add each name for this node to the hash table */ - newnode->efnode_name = (EFNodeName *) NULL; - for (nn = node->efnode_name; nn; nn = nn->efnn_next) { /* @@ -557,6 +556,7 @@ efAddNodes(hc, stdcell) newnode->efnode_name = newname; } } + } return 0; } From e4bebffeb49fde401e8f531a01feb4c3ef6eb9db Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 1 Mar 2021 11:28:15 -0500 Subject: [PATCH 21/89] Updated VERSION with the previousl commit to fix problems with the hierarchical SPICE netlist generation. --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 72b47869..22d3bd1e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.134 +8.3.135 From c99e632744e60253b9360ab19a86a9ae429360ed Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 3 Mar 2021 11:39:35 -0500 Subject: [PATCH 22/89] Modification of readspice.tcl script to work around issue if no ports are found (i.e., "port first" returns nothing, instead of a number). --- VERSION | 2 +- tcltk/readspice.tcl | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 22d3bd1e..c42d948e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.135 +8.3.136 diff --git a/tcltk/readspice.tcl b/tcltk/readspice.tcl index 058185e0..6ddf8345 100644 --- a/tcltk/readspice.tcl +++ b/tcltk/readspice.tcl @@ -115,6 +115,10 @@ proc readspice {netfile} { if {$outport < $npins} {set outport $npins} set p [port first] while {$p != -1 && $p <= $highport} { + if {$p == ""} { + puts stderr "Error: $cellname port numbering failed." + break + } set p1 [port $p next] set testpin [port $p name] if {$testpin != ""} { From 324721b5146d7c086e5d79d73541bc65c85733f4 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 4 Mar 2021 14:00:31 -0500 Subject: [PATCH 23/89] Added some options to the net selection with respect to labels. The previous behavior was to generate hierarchical names for all labels when copying contents of subcells. This is "safe" for copying selections without accidentally shorting things through labeling, but it can make a mess of the selection. Options are now "select do labels" for the existing behavior, "select no labels" to not show any labels, and "select simple labels" to show only the root name of labels in subcells. --- VERSION | 2 +- cif/CIFgen.c | 3 ++- commands/CmdRS.c | 63 +++++++++++++++++++++++++++++++++----------- database/DBconnect.c | 24 +++++++++++------ extflat/EFantenna.c | 3 ++- extract/ExtLength.c | 3 ++- netmenu/NMshowcell.c | 5 ++-- select/selCreate.c | 4 +-- select/selOps.c | 1 + select/select.h | 9 +++++++ 10 files changed, 85 insertions(+), 32 deletions(-) diff --git a/VERSION b/VERSION index c42d948e..73e0f88e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.136 +8.3.137 diff --git a/cif/CIFgen.c b/cif/CIFgen.c index 9136ac45..db9f7609 100644 --- a/cif/CIFgen.c +++ b/cif/CIFgen.c @@ -34,6 +34,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include "calma/calma.h" /* for CalmaContactArrays */ #include "commands/commands.h" /* for CmdFindNetProc() */ #include "select/selInt.h" /* for select use and def */ +#include "select/select.h" #include "utils/stack.h" #include "utils/malloc.h" #include "utils/maxrect.h" @@ -4786,7 +4787,7 @@ CIFGenLayer(op, area, cellDef, origDef, temps, hier, clientdata) scx.scx_use = CIFDummyUse; scx.scx_trans = GeoIdentityTransform; DBTreeCopyConnect(&scx, &DBConnectTbl[ttype], 0, - DBConnectTbl, &TiPlaneRect, FALSE, Select2Use); + DBConnectTbl, &TiPlaneRect, SEL_NO_LABELS, Select2Use); cifSrTiles(op, area, Select2Def, temps, cifPaintFunc, (ClientData) CIFPaintTable); DBCellClearDef(Select2Def); diff --git a/commands/CmdRS.c b/commands/CmdRS.c index 1934891e..ac5ea67f 100644 --- a/commands/CmdRS.c +++ b/commands/CmdRS.c @@ -728,27 +728,29 @@ CmdSelect(w, cmd) #define SEL_AREA 0 #define SEL_VISIBLE 1 #define SEL_CELL 2 -#define SEL_CLEAR 3 -#define SEL_FLAT 4 -#define SEL_HELP 5 -#define SEL_KEEP 6 -#define SEL_MOVE 7 -#define SEL_PICK 8 -#define SEL_SAVE 9 -#define SEL_FEEDBACK 10 -#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 +#define SEL_LABELS 3 +#define SEL_CLEAR 4 +#define SEL_FLAT 5 +#define SEL_HELP 6 +#define SEL_KEEP 7 +#define SEL_MOVE 8 +#define SEL_PICK 9 +#define SEL_SAVE 10 +#define SEL_FEEDBACK 11 +#define SEL_BBOX 12 +#define SEL_BOX 13 +#define SEL_CHUNK 14 +#define SEL_REGION 15 +#define SEL_NET 16 +#define SEL_SHORT 17 +#define SEL_DEFAULT 18 static char *cmdSelectOption[] = { "area", "visible", "cell", + "labels", "clear", "flat", "help", @@ -774,6 +776,7 @@ CmdSelect(w, cmd) "[more | less] area [layers] [de]select all info under box in layers", "[more | less] visible [layers] [de]select all visible info under box in layers", "[more | less | top] cell [name] [de]select cell under cursor, or \"name\"", + "[do | no] labels [do not] select subcell labels", "clear clear selection", "flat flatten the contents of the selection", "help print this message", @@ -832,6 +835,7 @@ CmdSelect(w, cmd) bool layerspec; bool degenerate; bool more = FALSE, less = FALSE, samePlace = TRUE; + unsigned char labelpolicy = SEL_DO_LABELS; #ifdef MAGIC_WRAPPER char *tclstr; Tcl_Obj *lobj; @@ -851,7 +855,7 @@ CmdSelect(w, cmd) /* See if "more" was given. If so, just strip off the "more" from * the argument list and set the "more" flag. Similarly for options - * "less", "nocycle", "top", and "cell". + * "less", "do", "no", "nocycle", "top", and "cell". */ if (cmd->tx_argc >= 2) @@ -876,6 +880,7 @@ CmdSelect(w, cmd) else if (!strncmp(cmd->tx_argv[1], "nocycle", arg1len)) { samePlace = FALSE; + labelpolicy = SEL_NO_LABELS; more = FALSE; less = FALSE; type = TT_SELECTBASE - 1; /* avoid cycling between types */ @@ -890,6 +895,24 @@ CmdSelect(w, cmd) optionArgs = &cmd->tx_argv[2]; cmd->tx_argc--; } + else if (!strncmp(cmd->tx_argv[1], "do", arg1len)) + { + labelpolicy = SEL_DO_LABELS; + optionArgs = &cmd->tx_argv[2]; + cmd->tx_argc--; + } + else if (!strncmp(cmd->tx_argv[1], "no", arg1len)) + { + labelpolicy = SEL_NO_LABELS; + optionArgs = &cmd->tx_argv[2]; + cmd->tx_argc--; + } + else if (!strncmp(cmd->tx_argv[1], "simple", arg1len)) + { + labelpolicy = SEL_SIMPLE_LABELS; + optionArgs = &cmd->tx_argv[2]; + cmd->tx_argc--; + } else if (!strncmp(cmd->tx_argv[1], "top", arg1len)) { @@ -982,6 +1005,14 @@ CmdSelect(w, cmd) SelectClear(); return; + case SEL_LABELS: + SelectDoLabels = labelpolicy; + if (SelectDoLabels) + TxPrintf("Selection includes subcell labels\n"); + else + TxPrintf("Selection ignores subcell labels\n"); + return; + /*-------------------------------------------------------------------- * Print out help information. *-------------------------------------------------------------------- diff --git a/database/DBconnect.c b/database/DBconnect.c index 2001be96..1265d860 100644 --- a/database/DBconnect.c +++ b/database/DBconnect.c @@ -31,6 +31,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include "utils/hash.h" #include "database/database.h" #include "database/databaseInt.h" +#include "select/select.h" #include "utils/signals.h" #include "utils/malloc.h" @@ -691,10 +692,15 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2) { int newllen = tpath->tp_next - tpath->tp_first; newlabtext[0] = '\0'; - if (newllen > 0) - strncpy(newlabtext, tpath->tp_first, newllen); - sprintf(newlabtext + newllen, "%s", lab->lab_text); - newlabptr = newlabtext; + if (tpath->tp_first == NULL) + newlabptr = lab->lab_text; + else + { + if (newllen > 0) + strncpy(newlabtext, tpath->tp_first, newllen); + sprintf(newlabtext + newllen, "%s", lab->lab_text); + newlabptr = newlabtext; + } } else return 0; } @@ -1019,9 +1025,10 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse) * clipped to this area. Pass * TiPlaneRect to get everything. */ - bool doLabels; /* If TRUE, copy connected labels - * and paint. If FALSE, copy only - * connected paint. + unsigned char doLabels; /* If SEL_DO_LABELS, copy connected labels + * and paint. If SEL_NO_LABELS, copy only + * connected paint. If SEL_SIMPLE_LABELS, + * copy only root of labels in subcircuits. */ CellUse *destUse; /* Result use in which to place * anything connected to material of @@ -1098,7 +1105,8 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse) searchtype |= TF_LABEL_ATTACH_NOT_SE; } } - if (doLabels) + if (doLabels == SEL_SIMPLE_LABELS) tpath.tp_first = NULL; + if (doLabels != SEL_NO_LABELS) DBTreeSrLabels(scx, newmask, xMask, &tpath, searchtype, dbcConnectLabelFunc, (ClientData) &csa2); } diff --git a/extflat/EFantenna.c b/extflat/EFantenna.c index 26a33a4a..480d6f90 100644 --- a/extflat/EFantenna.c +++ b/extflat/EFantenna.c @@ -34,6 +34,7 @@ #include "extflat/EFint.h" #include "extract/extract.h" #include "extract/extractInt.h" +#include "select/select.h" #include "utils/malloc.h" /* Forward declarations */ @@ -505,7 +506,7 @@ antennacheckVisit(dev, hc, scale, trans, editUse) /* To do: Mark tiles so area count can be progressive */ DBTreeCopyConnect(&scx, &DBConnectTbl[t], 0, - DBConnectTbl, &TiPlaneRect, FALSE, extPathUse); + DBConnectTbl, &TiPlaneRect, SEL_NO_LABELS, extPathUse); /* Search planes of tie types and accumulate all tiedown areas */ gdas.accum = (dlong)0; diff --git a/extract/ExtLength.c b/extract/ExtLength.c index c212c786..bfb2ba6f 100644 --- a/extract/ExtLength.c +++ b/extract/ExtLength.c @@ -45,6 +45,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include "utils/signals.h" #include "windows/windows.h" #include "dbwind/dbwind.h" +#include "select/select.h" #include "utils/styles.h" #include "utils/stack.h" #include "utils/main.h" @@ -368,7 +369,7 @@ extLengthYank(use, labList) scx.scx_trans = GeoIdentityTransform; GEO_EXPAND(&lab->lab_rect, 1, &scx.scx_area); DBTreeCopyConnect(&scx, &DBConnectTbl[lab->lab_type], 0, - DBConnectTbl, &TiPlaneRect, TRUE, extPathUse); + DBConnectTbl, &TiPlaneRect, SEL_DO_LABELS, extPathUse); } if (DebugIsSet(extDebugID, extDebLength)) diff --git a/netmenu/NMshowcell.c b/netmenu/NMshowcell.c index 72ad7fb2..854996e2 100644 --- a/netmenu/NMshowcell.c +++ b/netmenu/NMshowcell.c @@ -35,6 +35,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include "utils/styles.h" #include "textio/textio.h" #include "utils/main.h" +#include "select/select.h" #include "netmenu/nmInt.h" /* The following owns describe the cell currently being highlighted, @@ -294,7 +295,7 @@ NMShowUnderBox() &DBAllButSpaceBits); DBCellClearDef(nmscShowUse->cu_def); DBTreeCopyConnect(&scx, &DBAllButSpaceAndDRCBits, 0, - DBConnectTbl, &TiPlaneRect, TRUE, nmscShowUse); + DBConnectTbl, &TiPlaneRect, SEL_DO_LABELS, nmscShowUse); DBWAreaChanged(nmscShowDef, &nmscShowDef->cd_bbox, DBW_ALLWINDOWS, &DBAllButSpaceBits); NMShowCell(nmscShowUse, rootDef); @@ -418,6 +419,6 @@ nmSRNFunc(rect, name, label, cdarg) scx.scx_trans = GeoIdentityTransform; DBTreeCopyConnect(&scx, &DBConnectTbl[label->lab_type], 0, - DBConnectTbl, &TiPlaneRect, TRUE, nmscShowUse); + DBConnectTbl, &TiPlaneRect, SEL_DO_LABELS, nmscShowUse); return(0); } diff --git a/select/selCreate.c b/select/selCreate.c index cac59183..22054364 100644 --- a/select/selCreate.c +++ b/select/selCreate.c @@ -749,7 +749,7 @@ SelectRegion(scx, type, xMask, pArea, less) UndoDisable(); DBCellClearDef(Select2Def); DBTreeCopyConnect(scx, &connections[type], xMask, connections, - &TiPlaneRect, TRUE, Select2Use); + &TiPlaneRect, SelectDoLabels, Select2Use); UndoEnable(); /* Now transfer what we found into the main selection cell. Pick @@ -850,7 +850,7 @@ SelectNet(scx, type, xMask, pArea, less) UndoDisable(); DBCellClearDef(Select2Def); DBTreeCopyConnect(scx, &mask, xMask, DBConnectTbl, - &TiPlaneRect, TRUE, Select2Use); + &TiPlaneRect, SelectDoLabels, Select2Use); UndoEnable(); /* Network undo method added by Nishit and Tim, July 8-10, 2004 */ diff --git a/select/selOps.c b/select/selOps.c index 1fdcf877..7eb2f9a8 100644 --- a/select/selOps.c +++ b/select/selOps.c @@ -47,6 +47,7 @@ static int selStretchX, selStretchY; /* Stretch distances. Only one should * ever be non-zero. */ static TileType selStretchType; /* Type of material being stretched. */ +unsigned char SelectDoLabels = SEL_DO_LABELS; /* Whether or not to select subcell labels */ typedef struct planeAndArea { diff --git a/select/select.h b/select/select.h index 843c1ee7..25509db0 100644 --- a/select/select.h +++ b/select/select.h @@ -56,6 +56,15 @@ extern void SelectStretch(); extern void SelectArray(); extern void SelectDump(); +/* Flag to indicate whether selection captures subcell labels */ + +extern unsigned char SelectDoLabels; + +/* Flag values for SelectDoLabels: */ +#define SEL_NO_LABELS 0 +#define SEL_DO_LABELS 1 +#define SEL_SIMPLE_LABELS 2 + /* The following is the root cell that contains the current selection. */ extern CellDef *SelectRootDef; From feddffcf455d89a73da23f65bbfc2c669a6d2fc2 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sat, 6 Mar 2021 19:39:34 -0500 Subject: [PATCH 24/89] Modified the handling of subcircuit names beginning with non-alphanumeric characters. Instead of removing the non-alphanumeric characters, magic now prepends an "x" to the name. Since this naming restriction does not necessarily impact, say, LVS, it would probably be better to let this behavior be enabled or disabled by a command. --- VERSION | 2 +- ext2spice/ext2spice.c | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/VERSION b/VERSION index 73e0f88e..6be92a0c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.137 +8.3.138 diff --git a/ext2spice/ext2spice.c b/ext2spice/ext2spice.c index 01442a7f..8e6e98c8 100644 --- a/ext2spice/ext2spice.c +++ b/ext2spice/ext2spice.c @@ -1553,10 +1553,15 @@ subcktVisit(use, hierName, is_top) } } - /* SPICE subcircuit names must begin with A-Z. This will also be */ - /* enforced when writing X subcircuit calls. */ + /* SPICE subcircuit names must begin with A-Z. */ subcktname = def->def_name; - while (!isalpha(*subcktname)) subcktname++; + if (!isalpha(*subcktname)) + { + subcktname = mallocMagic(2 + strlen(def->def_name)); + sprintf(subcktname, "x%s", def->def_name); + freeMagic(def->def_name); + def->def_name = subcktname; + } if (tchars > 80) fprintf(esSpiceF, "\n+"); fprintf(esSpiceF, " %s", subcktname); /* subcircuit model name */ @@ -1664,7 +1669,13 @@ topVisit(def, doStub) /* SPICE subcircuit names must begin with A-Z. This will also be */ /* enforced when writing X subcircuit calls. */ subcktname = def->def_name; - while (!isalpha(*subcktname)) subcktname++; + if (!isalpha(*subcktname)) + { + subcktname = mallocMagic(2 + strlen(def->def_name)); + sprintf(subcktname, "x%s", def->def_name); + freeMagic(def->def_name); + def->def_name = subcktname; + } fprintf(esSpiceF, ".subckt %s", subcktname); tchars = 8 + strlen(subcktname); From 5b8a59c4adb2475af9d6b2403db0142c6349ebc8 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 9 Mar 2021 22:07:51 -0500 Subject: [PATCH 25/89] Added extensions to the toolkit base to add netlist-to-layout conversion, largely converted from the python script in open_pdks, which itself was derived from an efabless script, and none of which have been particularly well tested. --- VERSION | 2 +- tcltk/toolkit.tcl | 278 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 279 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 6be92a0c..49bc7f3f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.138 +8.3.139 diff --git a/tcltk/toolkit.tcl b/tcltk/toolkit.tcl index adaaee99..a7e0dd8b 100644 --- a/tcltk/toolkit.tcl +++ b/tcltk/toolkit.tcl @@ -8,6 +8,8 @@ # Revision 1 # October 29, 2020 # Revision 2 (names are hashed from properties) +# March 9, 2021 +# Added spice-to-layout procedure #-------------------------------------------------------------- # Sets up the environment for a toolkit. The toolkit must # supply a namespace that is the "library name". For each @@ -105,6 +107,282 @@ magic::macro ^P "magic::gencell {} ; raise .params" magic::tag select "[magic::tag select]; magic::gencell_update %1" +#-------------------------------------------------------------- +# Supporting procedures for netlist_to_layout procedure +#-------------------------------------------------------------- + +# move_forward_by_width -- +# +# Given an instance name, find the instance and position the +# cursor box at the right side of the instance. + +proc magic::move_forward_by_width {instname} { + select cell $instname + set anum [lindex [array -list count] 1] + set xpitch [lindex [array -list pitch] 0] + set bbox [box values] + set posx [lindex $bbox 0] + set posy [lindex $bbox 1] + set width [expr [lindex $bbox 2] - $posx] + set posx [expr $posx + $width + $xpitch * $anum] + box position ${posx}i ${posy}i + return [lindex $bbox 3] +} + +# get_and_move_inst -- +# +# Given a cell name, creat an instance of the cell named "instname" +# at the current cursor box position. If option "anum" is given +# and > 1, then array the cell. + +proc magic::get_and_move_inst {cellname instname {anum 1}} { + set newinst [getcell $cellname] + select cell $newinst + if {$newinst == ""} {return} + identify $instname + if {$anum > 1} {array 1 $anum} + set bbox [box values] + set posx [lindex $bbox 2] + set posy [lindex $bbox 1] + box position ${posx}i ${posy}i + return [lindex $bbox 3] +} + +# create_new_pin -- +# +# Create a new pin of size 1um x 1um at the current cursor box +# location. If "layer" is given, then create the pin on the +# given layer. Otherwise, the pin is created on the m1 layer. + +proc magic::create_new_pin {pinname portnum {layer m1}} { + box size 1um 1um + paint $layer + label $pinname FreeSans 16 0 0 0 c $layer + port make $portnum + box move s 2um +} + +# generate_layout_add -- +# +# Add a new subcircuit to a layout and seed it with components +# as found in the list "complist", and add pins according to the +# pin names in "subpins". Each entry in "complist" is a single +# device line from a SPICE file. + +proc magic::generate_layout_add {subname subpins complist library} { + global PDKNAMESPACE + + # Create a new subcircuit + load $subname -quiet + box 0 0 0 0 + + # Generate pins + if {[llength $subpins] > 0} { + set pinlist [split $subpins] + set i 0 + foreach pin $pinlist { + # Escape [ and ] in pin name + set pin_esc [string map {\[ \\\[ \] \\\]} $pin] + magic::create_new_pin $pin_esc $i + incr i + } + } + + # Set initial position for importing cells + box size 0 0 + set posx 0 + set posy [expr {round(3 / [cif scale out])}] + box position ${posx}i ${posy}i + + # Seed layout with components + foreach comp $complist { + set pinlist {} + set paramlist {} + + # Parse SPICE line into pins, device name, and parameters. Make + # sure parameters incorporate quoted expressions as {} or ''. + + set rest $comp + while {$rest != ""} { + if {[regexp -nocase {^[ \t]*[^= \t]+=[^=]+} $rest]} { + break + } elseif {[regexp -nocase {^[ \t]*([^ \t]+)[ \t]*(.*)$} $rest \ + valid token rest]} { + lappend pinlist $token + } else { + set rest "" + } + } + + while {$rest != ""} { + if {[regexp -nocase {([^= \t]+)=\'([^\']+)\'[ \t]*(.*)} $rest \ + valid pname value rest]} { + lappend paramlist [list $pname "{$value}"] + } elseif {[regexp -nocase {([^= \t]+)=\{([^\}]+)\}[ \t]*(.*)} $rest \ + valid pname value rest]} { + lappend paramlist [list $pname "{$value}"] + } elseif {[regexp -nocase {([^= \t]+)=([^= \t]+)[ \t]*(.*)} $rest \ + valid pname value rest]} { + lappend paramlist [list $pname $value] + } else { + puts stderr "Error parsing line \"$comp\"" + puts stderr "at: \"$rest\"" + set rest "" + } + } + + if {[llength $pinlist] < 2} { + puts stderr "Error: No device type found in line \"$comp\"" + puts stderr "Tokens found are: \"$pinlist\"" + continue + } + + set instname [lindex $pinlist 0] + set devtype [lindex $pinlist end] + set pinlist [lrange $pinlist 0 end-1] + + set mult 1 + foreach param $paramlist { + set parmname [lindex $param 0] + set parmval [lindex $param 1] + if {[string toupper $parmname] == "M"} { + if {[catch {set mult [expr {int($parmval)}]}]} { + set mult [expr [string trim $parmval "'"]] + } + } + } + + # devtype is assumed to be in library. If not, it will attempt to + # use 'getcell' on devtype. Note that this code depends on the + # PDK setting varible PDKNAMESPACE. + + if {$library != ""} { + set libdev ${library}::${devtype} + } else { + set libdev ${PDKNAMESPACE}::${devtype} + } + + set outparts {} + lappend outparts "magic::gencell $libdev $instname" + + # Output all parameters. Parameters not used by the toolkit are + # ignored by the toolkit. + + lappend outparts "-spice" + foreach param $paramlist { + lappend outparts [string tolower [lindex $param 0]] + lappend outparts [lindex $param 1] + } + + if {[catch {[eval [join $outparts]]}]} { + magic::get_and_move_inst $devtype $instname $mult + } else { + magic::move_forward_by_width $instname + } + } + save $subname +} + +#-------------------------------------------------------------- +# Wrapper for generating an initial layout from a SPICE netlist +# using the defined PDK toolkit procedures +# +# "netfile" is the name of a SPICE netlist +# "library" is the name of the PDK library namespace +#-------------------------------------------------------------- + +proc magic::netlist_to_layout {netfile library} { + + if {![file exists $netfile]} { + puts stderr "No such file $netfile" + return + } + + # Read data from file. Remove comment lines and concatenate + # continuation lines. + + set topname [file rootname [file tail $netfile]] + puts stdout "Creating layout from [file tail $netfile]" + + if {[file ext $netfile] == ".cdl"} { + set is_cdl true + } else { + set is_cdl false + } + + if [catch {open $netfile r} fnet] { + puts stderr "Error: Cannot open file \"$netfile\" for reading." + return + } + + 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] != " "} { + append lastline " " + } + append lastline [string range $line 1 end] + } else { + lappend fdata $lastline + set lastline $line + } + } + } + lappend fdata $lastline + close $fnet + + set insub false + set subname "" + set subpins "" + set complist {} + set toplist {} + + # suspendall + + # Parse the file + foreach line $fdata { + if {! $insub} { + set ftokens [split $line] + set keyword [string tolower [lindex $ftokens 0]] + + if {$keyword == ".subckt"} { + set subname [lindex $ftokens 1] + set subpins [lrange $ftokens 2 end] + set insub true + } elseif {[regexp -nocase {[xmcrbdivq]([^ \t]+)[ \t](.*)$} $line \ + valid instname rest]} { + lappend toplist $line + } + } else { + if {[regexp -nocase {^[ \t]*\.ends} $line]} { + set insub false + magic::generate_layout_add $subname $subpins $complist $library + set subname "" + set subpins "" + set complist {} + } elseif {[regexp -nocase {[xmcrbdivq]([^ \t]+)[ \t](.*)$} $line \ + valid instname rest]} { + lappend complist $line + } + } + } + + # Add in any top-level components (not in subcircuits) + if {[llength $toplist] > 0} { + magic::generate_layout_add $topname "" $toplist $library + } + + # resumeall +} + #------------------------------------------------------------- # gencell # From 3bd9adbaf8ced1e8c563f9ea04e2d8d0273bfb6b Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 11 Mar 2021 11:09:37 -0500 Subject: [PATCH 26/89] Corrected a set of regexps in the schematic-to-layout script that prevented normal x=y type parameters from being parsed. --- VERSION | 2 +- tcltk/readspice.tcl | 7 +++++-- tcltk/toolkit.tcl | 6 +++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/VERSION b/VERSION index 49bc7f3f..fe52a0f1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.139 +8.3.140 diff --git a/tcltk/readspice.tcl b/tcltk/readspice.tcl index 6ddf8345..18902782 100644 --- a/tcltk/readspice.tcl +++ b/tcltk/readspice.tcl @@ -53,7 +53,8 @@ proc readspice {netfile} { # Read data from file. Remove comment lines and concatenate # continuation lines. - puts stderr "Annotating port orders from $netfile" + puts stdout "Annotating port orders from $netfile" + flush stdout set fdata {} set lastline "" while {[gets $fnet line] >= 0} { @@ -109,6 +110,8 @@ proc readspice {netfile} { # Make sure pins aren't duplicated by first moving all pin # indexes above the number of pins to check. + puts stdout "Annotating cell $cell" + flush stdout set npins [expr {[llength $ftokens] - 1}] set highport [port last] set outport $highport @@ -116,7 +119,7 @@ proc readspice {netfile} { set p [port first] while {$p != -1 && $p <= $highport} { if {$p == ""} { - puts stderr "Error: $cellname port numbering failed." + puts stderr "Error: $cell port numbering failed." break } set p1 [port $p next] diff --git a/tcltk/toolkit.tcl b/tcltk/toolkit.tcl index a7e0dd8b..89758b22 100644 --- a/tcltk/toolkit.tcl +++ b/tcltk/toolkit.tcl @@ -215,13 +215,13 @@ proc magic::generate_layout_add {subname subpins complist library} { } while {$rest != ""} { - if {[regexp -nocase {([^= \t]+)=\'([^\']+)\'[ \t]*(.*)} $rest \ + if {[regexp -nocase {^([^= \t]+)=\'([^\']+)\'[ \t]*(.*)} $rest \ valid pname value rest]} { lappend paramlist [list $pname "{$value}"] - } elseif {[regexp -nocase {([^= \t]+)=\{([^\}]+)\}[ \t]*(.*)} $rest \ + } elseif {[regexp -nocase {^([^= \t]+)=\{([^\}]+)\}[ \t]*(.*)} $rest \ valid pname value rest]} { lappend paramlist [list $pname "{$value}"] - } elseif {[regexp -nocase {([^= \t]+)=([^= \t]+)[ \t]*(.*)} $rest \ + } elseif {[regexp -nocase {^([^= \t]+)=([^= \t]+)[ \t]*(.*)} $rest \ valid pname value rest]} { lappend paramlist [list $pname $value] } else { From 56be41932f46aec6585df13d7b03f5f106183898 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 11 Mar 2021 12:27:14 -0500 Subject: [PATCH 27/89] Restored the toolkit behavior of spreading out cells that are read in from a SPICE netlist in a row instead of placing them on top of each other. --- tcltk/toolkit.tcl | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tcltk/toolkit.tcl b/tcltk/toolkit.tcl index 89758b22..47feb865 100644 --- a/tcltk/toolkit.tcl +++ b/tcltk/toolkit.tcl @@ -274,9 +274,11 @@ proc magic::generate_layout_add {subname subpins complist library} { lappend outparts [lindex $param 1] } - if {[catch {[eval [join $outparts]]}]} { + if {[catch {eval [join $outparts]}]} { + # Assume this is not a gencell, and get an instance. magic::get_and_move_inst $devtype $instname $mult } else { + # Move forward for next gencell magic::move_forward_by_width $instname } } @@ -462,6 +464,11 @@ proc magic::gencell {gencell_name {instname {}} args} { set gencell_type $gencell_name } + # Check that the device exists as a gencell, or else return an error + if {[namespace eval ::${library} info commands ${gencell_type}_convert] == ""} { + error "No import routine for ${library} library cell ${gencell_type}!" + } + if {$instname == {}} { # Case: Interactive, new device with parameters in args (if any) if {$spicemode == 1} { @@ -515,6 +522,7 @@ proc magic::gencell {gencell_name {instname {}} args} { } } } + return 0 } #------------------------------------------------------------- From f790ea75896c4c97e34b216b96c5c4858841af5b Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 11 Mar 2021 13:30:28 -0500 Subject: [PATCH 28/89] More enhancements for schematic_to_layout to parse various non-circuit content in a SPICE netlist (mainly to ignore test- bench elements and commands). --- tcltk/toolkit.tcl | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/tcltk/toolkit.tcl b/tcltk/toolkit.tcl index 47feb865..2e3a1619 100644 --- a/tcltk/toolkit.tcl +++ b/tcltk/toolkit.tcl @@ -199,6 +199,10 @@ proc magic::generate_layout_add {subname subpins complist library} { set pinlist {} set paramlist {} + # NOTE: This routine deals with subcircuit calls and devices + # with models. It needs to determine when a device is instantiated + # without a model, and ignore such devices. + # Parse SPICE line into pins, device name, and parameters. Make # sure parameters incorporate quoted expressions as {} or ''. @@ -342,6 +346,7 @@ proc magic::netlist_to_layout {netfile library} { close $fnet set insub false + set incmd false set subname "" set subpins "" set complist {} @@ -349,19 +354,33 @@ proc magic::netlist_to_layout {netfile library} { # suspendall + set ignorekeys {.global .ic .option .end} + # Parse the file foreach line $fdata { - if {! $insub} { + if {$incmd} { + if {[regexp -nocase {^[ \t]*\.endc} $line]} { + set incmd false + } + } elseif {! $insub} { set ftokens [split $line] set keyword [string tolower [lindex $ftokens 0]] - if {$keyword == ".subckt"} { + if {[lsearch $ignorekeys $keyword] != -1} { + continue + } elseif {$keyword == ".command"} { + set incmd true + } elseif {$keyword == ".subckt"} { set subname [lindex $ftokens 1] set subpins [lrange $ftokens 2 end] set insub true - } elseif {[regexp -nocase {[xmcrbdivq]([^ \t]+)[ \t](.*)$} $line \ + } elseif {[regexp -nocase {^[xmcrdq]([^ \t]+)[ \t](.*)$} $line \ valid instname rest]} { lappend toplist $line + } elseif {[regexp -nocase {^[ivbe]([^ \t]+)[ \t](.*)$} $line \ + valid instname rest]} { + # These are testbench devices and should be ignored + continue } } else { if {[regexp -nocase {^[ \t]*\.ends} $line]} { @@ -370,9 +389,13 @@ proc magic::netlist_to_layout {netfile library} { set subname "" set subpins "" set complist {} - } elseif {[regexp -nocase {[xmcrbdivq]([^ \t]+)[ \t](.*)$} $line \ + } elseif {[regexp -nocase {^[xmcrdq]([^ \t]+)[ \t](.*)$} $line \ valid instname rest]} { lappend complist $line + } elseif {[regexp -nocase {^[ivbe]([^ \t]+)[ \t](.*)$} $line \ + valid instname rest]} { + # These are testbench devices and should be ignored + continue } } } From 77573843558c2a4fdd3f1fb2755fdeac4a72cc35 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 16 Mar 2021 13:37:15 -0400 Subject: [PATCH 29/89] Modified the "label" and "setlabel" commands, giving "setlabel" an extra option "-default" that allows defaults to be set for any label property other than text or port-related properties. Subsequently, the command "label " will apply the given defaults to the label. This allows a simpler way to create rendered labels from the command line without remembering all of the arguments to the extended "label" command. --- VERSION | 2 +- commands/CmdLQ.c | 30 +++++- commands/CmdRS.c | 268 +++++++++++++++++++++++++++++++++++++---------- 3 files changed, 241 insertions(+), 59 deletions(-) diff --git a/VERSION b/VERSION index fe52a0f1..06768c81 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.140 +8.3.141 diff --git a/commands/CmdLQ.c b/commands/CmdLQ.c index e4b99d48..20045d85 100644 --- a/commands/CmdLQ.c +++ b/commands/CmdLQ.c @@ -50,6 +50,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ void CmdPaintEraseButton(); +/* See the SetLabel command */ + +extern Label *DefaultLabel; /* * ---------------------------------------------------------------------------- @@ -169,8 +172,8 @@ CmdLabel(w, cmd) MagWindow *w; TxCommand *cmd; { - TileType type; - int pos, font = -1, size = 0, rotate = 0, offx = 0, offy = 0; + TileType type = (TileType)(-1); + int pos = -1, font = -1, size = 0, rotate = 0, offx = 0, offy = 0; bool sticky = FALSE; int option; char *p; @@ -185,6 +188,22 @@ CmdLabel(w, cmd) p = cmd->tx_argv[1]; + /* + * If the "setlabel" command has been used to set defaults, pick up + * the default values from DefaultLabel. + */ + if (DefaultLabel != NULL) + { + pos = DefaultLabel->lab_just; + font = DefaultLabel->lab_font; + size = DefaultLabel->lab_size; + rotate = DefaultLabel->lab_rotate; + offx = DefaultLabel->lab_offset.p_x; + offy = DefaultLabel->lab_offset.p_y; + sticky = (DefaultLabel->lab_flags & LABEL_STICKY) ? 1 : 0; + type = DefaultLabel->lab_type; + } + /* * Find and check validity of position. */ @@ -220,13 +239,14 @@ CmdLabel(w, cmd) else pos = GeoTransPos(&RootToEditTransform, pos); } - else pos = -1; if (font >= 0) { char *yp = NULL; - size = DBLambda[1]; + if (DefaultLabel == NULL) + size = DBLambda[1]; + if (cmd->tx_argc > 3) if (StrIsNumeric(cmd->tx_argv[3])) size = cmdScaleCoord(w, cmd->tx_argv[3], TRUE, TRUE, 8); @@ -304,7 +324,7 @@ CmdLabel(w, cmd) TxError("Unknown layer: %s\n", cmd->tx_argv[cmd->tx_argc - 1]); return; } - } else type = -1; + } CmdLabelProc(p, font, size, rotate, offx, offy, pos, sticky, type); } diff --git a/commands/CmdRS.c b/commands/CmdRS.c index ac5ea67f..37f9a58c 100644 --- a/commands/CmdRS.c +++ b/commands/CmdRS.c @@ -54,6 +54,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ extern void DisplayWindow(); +/* Used by CmdSetLabel() */ +Label *DefaultLabel; + /* * ---------------------------------------------------------------------------- * @@ -1892,8 +1895,7 @@ cmdLabelFontFunc(label, cellUse, transform, font) * Query or change properties of a (selected) label in the edit cell * * Usage: - * setlabel option [name] - * + * setlabel [-default] option [name] * * Option may be one of: * text @@ -1913,6 +1915,11 @@ cmdLabelFontFunc(label, cellUse, transform, font) * "setlabel font " can be used without any select to load fonts * from a startup script. * + * Use with "-default" causes the DefaultLabel structure to be created + * (if not existing already) and set with the given value. Subsequent + * use of the "label" command will start with the given defaults, then + * apply whatever non-default values are specified in the command. + * * ---------------------------------------------------------------------------- */ @@ -1933,10 +1940,12 @@ CmdSetLabel(w, cmd) TxCommand *cmd; { int pos = -1, font = -1, size = 0, rotate = 0, flags = 0; + int locargc, argstart = 1; char **msg; Point offset; TileType ttype; int option; + bool doDefault = FALSE; #ifdef MAGIC_WRAPPER Tcl_Obj *lobj; #endif @@ -1959,10 +1968,34 @@ CmdSetLabel(w, cmd) NULL }; - if (cmd->tx_argc < 2 || cmd->tx_argc > 4) + locargc = cmd->tx_argc; + if (locargc > 2) + { + if (!strncmp(cmd->tx_argv[1], "-def", 4)) + { + if (DefaultLabel == NULL) + { + DefaultLabel = (Label *)mallocMagic(sizeof(Label)); + /* Set default defaults (lab_text is ignored) */ + DefaultLabel->lab_just = -1; + DefaultLabel->lab_size = 0; + DefaultLabel->lab_font = -1; + DefaultLabel->lab_rotate = 0; + DefaultLabel->lab_flags = 0; + DefaultLabel->lab_offset.p_x = 0; + DefaultLabel->lab_offset.p_y = 0; + DefaultLabel->lab_type = (TileType)(-1); + } + doDefault = TRUE; + locargc--; + argstart++; + } + } + + if (locargc < 2 || locargc > 4) option = SETLABEL_HELP; else - option = Lookup(cmd->tx_argv[1], cmdLabelSetOption); + option = Lookup(cmd->tx_argv[argstart], cmdLabelSetOption); switch (option) { @@ -1981,20 +2014,27 @@ CmdSetLabel(w, cmd) break; case SETLABEL_TEXT: - if (EditCellUse) + if (doDefault) + { + TxError("Cannot set a default label text.\n"); + } + else if (EditCellUse) { SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL, - cmdLabelTextFunc, (cmd->tx_argc == 3) ? - (ClientData)cmd->tx_argv[2] : (ClientData)NULL); + cmdLabelTextFunc, (locargc == 3) ? + (ClientData)cmd->tx_argv[argstart + 1] : (ClientData)NULL); } break; case SETLABEL_FONT: - if (cmd->tx_argc >= 2 && cmd->tx_argc <= 4) + if (locargc >= 2 && locargc <= 4) { - if ((cmd->tx_argc == 3) && StrIsInt(cmd->tx_argv[2])) + /* This option is used to see the font name corresponding + * to a font number. + */ + if ((locargc == 3) && StrIsInt(cmd->tx_argv[argstart + 1])) { - int font = atoi(cmd->tx_argv[2]); + int font = atoi(cmd->tx_argv[argstart + 1]); if (font < -1 || font >= DBNumFonts) { if (DBNumFonts == 0) @@ -2008,67 +2048,118 @@ CmdSetLabel(w, cmd) else TxPrintf("%s\n", DBFontList[font]->mf_name); } - else if ((cmd->tx_argc == 3 || cmd->tx_argc == 4) && - !StrIsInt(cmd->tx_argv[2])) + else if ((locargc == 3 || locargc == 4) && + !StrIsInt(cmd->tx_argv[argstart + 1])) { - font = DBNameToFont(cmd->tx_argv[2]); + font = DBNameToFont(cmd->tx_argv[argstart + 1]); if (font < -1) { float scale = 1.0; - if ((cmd->tx_argc == 4) && StrIsNumeric(cmd->tx_argv[3])) - scale = (float)atof(cmd->tx_argv[3]); - if (DBLoadFont(cmd->tx_argv[2], scale) != 0) - TxError("Error loading font \"%s\"\n", cmd->tx_argv[2]); - font = DBNameToFont(cmd->tx_argv[2]); + if ((locargc == 4) && StrIsNumeric(cmd->tx_argv[argstart + 2])) + scale = (float)atof(cmd->tx_argv[argstart + 2]); + if (DBLoadFont(cmd->tx_argv[argstart + 1], scale) != 0) + TxError("Error loading font \"%s\"\n", cmd->tx_argv[argstart + 1]); + font = DBNameToFont(cmd->tx_argv[argstart + 1]); if (font < -1) break; } } - if (EditCellUse) + if (doDefault) + { + if (locargc == 2) + { + font = DefaultLabel->lab_font; + if (font == -1) +#ifdef MAGIC_WRAPPER + Tcl_SetResult(magicinterp, "default", TCL_VOLATILE); +#else + TxPrintf("default\n"); +#endif + else +#ifdef MAGIC_WRAPPER + Tcl_SetObjResult(magicinterp, + Tcl_NewStringObj(DBFontList[font]->mf_name, -1)); +#else + TxPrintf("%s\n", DBFontList[font]->mf_name); +#endif + } + else + DefaultLabel->lab_font = font; + } + else if (EditCellUse) { SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL, - cmdLabelFontFunc, (cmd->tx_argc == 3) ? + cmdLabelFontFunc, (locargc == 3) ? (ClientData)&font : (ClientData)NULL); } } break; case SETLABEL_JUSTIFY: - if (cmd->tx_argc == 3) + if (locargc == 3) { - pos = GeoNameToPos(cmd->tx_argv[2], FALSE, TRUE); + pos = GeoNameToPos(cmd->tx_argv[argstart + 1], FALSE, TRUE); if (pos < 0) break; } - if (EditCellUse) + if (doDefault) + { + if (locargc == 2) + { +#ifdef MAGIC_WRAPPER + Tcl_SetObjResult(magicinterp, + Tcl_NewStringObj(GeoPosToName(DefaultLabel->lab_just), + -1)); +#else + TxPrintf("%s\n", GeoPosToName(DefaultLabel->lab_just)); +#endif + } + else + DefaultLabel->lab_just = pos; + } + else if (EditCellUse) { SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL, - cmdLabelJustFunc, (cmd->tx_argc == 3) ? + cmdLabelJustFunc, (locargc == 3) ? (ClientData)&pos : (ClientData)NULL); } break; case SETLABEL_SIZE: - if (cmd->tx_argc == 3) + if (locargc == 3) { - if (StrIsNumeric(cmd->tx_argv[2])) - size = cmdScaleCoord(w, cmd->tx_argv[2], TRUE, TRUE, 8); + if (StrIsNumeric(cmd->tx_argv[argstart + 1])) + size = cmdScaleCoord(w, cmd->tx_argv[argstart + 1], TRUE, TRUE, 8); if (size <= 0) break; } - if (EditCellUse) + if (doDefault) + { + if (locargc == 2) + { +#ifdef MAGIC_WRAPPER + Tcl_SetObjResult(magicinterp, + Tcl_NewIntObj(DefaultLabel->lab_size)); +#else + TxPrintf("%d\n", DefaultLabel->lab_size); +#endif + } + else + DefaultLabel->lab_size = size; + } + else if (EditCellUse) { SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL, - cmdLabelSizeFunc, (cmd->tx_argc == 3) ? + cmdLabelSizeFunc, (locargc == 3) ? (ClientData)&size : (ClientData)NULL); } break; case SETLABEL_OFFSET: - if (cmd->tx_argc == 3) + if (locargc == 3) { char *yp; - if ((yp = strchr(cmd->tx_argv[2], ' ')) != NULL) + if ((yp = strchr(cmd->tx_argv[argstart + 1], ' ')) != NULL) { - offset.p_x = cmdScaleCoord(w, cmd->tx_argv[2], TRUE, TRUE, 8); + offset.p_x = cmdScaleCoord(w, cmd->tx_argv[argstart + 1], TRUE, TRUE, 8); offset.p_y = cmdScaleCoord(w, yp, TRUE, FALSE, 8); } else @@ -2077,67 +2168,138 @@ CmdSetLabel(w, cmd) return; } } - else if (cmd->tx_argc == 4) + else if (locargc == 4) { - offset.p_x = cmdScaleCoord(w, cmd->tx_argv[2], TRUE, TRUE, 8); - offset.p_y = cmdScaleCoord(w, cmd->tx_argv[3], TRUE, FALSE, 8); + offset.p_x = cmdScaleCoord(w, cmd->tx_argv[argstart + 1], TRUE, TRUE, 8); + offset.p_y = cmdScaleCoord(w, cmd->tx_argv[argstart + 2], TRUE, FALSE, 8); } - if (EditCellUse) + if (doDefault) + { + if (locargc == 2) + { +#ifdef MAGIC_WRAPPER + Tcl_Obj *lobj; + Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(magicinterp, lobj, + Tcl_NewIntObj(DefaultLabel->lab_offset.p_x)); + Tcl_ListObjAppendElement(magicinterp, lobj, + Tcl_NewIntObj(DefaultLabel->lab_offset.p_y)); + Tcl_SetObjResult(magicinterp, lobj); +#else + TxPrintf("%d %d\n", DefaultLabel->lab_offset.p_x, + DefaultLabel->lab_offset.p_y); +#endif + } + else + DefaultLabel->lab_offset = offset; + } + else if (EditCellUse) { SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL, - cmdLabelOffsetFunc, (cmd->tx_argc != 2) ? + cmdLabelOffsetFunc, (locargc != 2) ? (ClientData)&offset : (ClientData)NULL); } break; case SETLABEL_ROTATE: - if (cmd->tx_argc == 3) + if (locargc == 3) { - if (StrIsInt(cmd->tx_argv[2])) - rotate = atoi(cmd->tx_argv[2]); + if (StrIsInt(cmd->tx_argv[argstart + 1])) + rotate = atoi(cmd->tx_argv[argstart + 1]); } - if (EditCellUse) + if (doDefault) + { + if (locargc == 2) + { +#ifdef MAGIC_WRAPPER + Tcl_SetObjResult(magicinterp, + Tcl_NewIntObj(DefaultLabel->lab_rotate)); +#else + TxPrintf("%d\n", DefaultLabel->lab_rotate); +#endif + } + else + DefaultLabel->lab_rotate = rotate; + } + else if (EditCellUse) { SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL, - cmdLabelRotateFunc, (cmd->tx_argc == 3) ? + cmdLabelRotateFunc, (locargc == 3) ? (ClientData)&rotate : (ClientData)NULL); } break; case SETLABEL_STICKY: - if (cmd->tx_argc == 3) + if (locargc == 3) { - option = Lookup(cmd->tx_argv[2], cmdLabelYesNo); + option = Lookup(cmd->tx_argv[argstart + 1], cmdLabelYesNo); if (option < 0) { - TxError("Unknown sticky option \"%s\"\n", cmd->tx_argv[2]); + TxError("Unknown sticky option \"%s\"\n", cmd->tx_argv[argstart + 1]); break; } flags = (option <= 3) ? 0 : LABEL_STICKY; } - if (EditCellUse) + if (doDefault) + { + if (locargc == 2) + { +#ifdef MAGIC_WRAPPER + Tcl_SetObjResult(magicinterp, + Tcl_NewBooleanObj((DefaultLabel->lab_flags & + LABEL_STICKY) ? TRUE : FALSE)); +#else + TxPrintf("%d\n", (DefaultLabel->lab_flags & LABEL_STICKY) ? 1 : 0); +#endif + } + else + DefaultLabel->lab_flags = flags; + } + else if (EditCellUse) { SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL, - cmdLabelStickyFunc, (cmd->tx_argc == 3) ? + cmdLabelStickyFunc, (locargc == 3) ? (ClientData)&flags : (ClientData)NULL); } break; case SETLABEL_LAYER: - if (cmd->tx_argc == 3) + if (locargc == 3) { - if (!strcasecmp(cmd->tx_argv[2], "default")) + if (!strcasecmp(cmd->tx_argv[argstart + 1], "default")) ttype = -1; else { - ttype = DBTechNoisyNameType(cmd->tx_argv[2]); + ttype = DBTechNoisyNameType(cmd->tx_argv[argstart + 1]); if (ttype < 0) break; } } - if (EditCellUse) + if (doDefault) + { + if (locargc == 2) + { + if (DefaultLabel->lab_type == (TileType)(-1)) +#ifdef MAGIC_WRAPPER + Tcl_SetResult(magicinterp, "default", TCL_VOLATILE); +#else + TxPrintf("default\n"); +#endif + else +#ifdef MAGIC_WRAPPER + Tcl_SetResult(magicinterp, + DBTypeLongNameTbl[DefaultLabel->lab_type], + TCL_VOLATILE); +#else + TxPrintf("%s\n", DBTypeLongNameTbl[DefaultLabel->lab_type]); +#endif + } + else + DefaultLabel->lab_type = ttype; + } + else if (EditCellUse) { SelEnumLabels(&DBAllTypeBits, TRUE, (bool *)NULL, - cmdLabelLayerFunc, (cmd->tx_argc == 3) ? + cmdLabelLayerFunc, (locargc == 3) ? (ClientData)&ttype : (ClientData)NULL); } break; @@ -2151,7 +2313,7 @@ CmdSetLabel(w, cmd) break; default: - TxError("Unknown setlabel option \"%s\"\n", cmd->tx_argv[1]); + TxError("Unknown setlabel option \"%s\"\n", cmd->tx_argv[argstart]); break; } } From 010c0599bd44a63c7f1e7e328b29d7be800cb7fa Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 16 Mar 2021 20:31:29 -0400 Subject: [PATCH 30/89] Encountered a crash condition caused by the "equiv" statement, for circuits with nets having multiple conflicting labels, depending on where the "equiv" statement occurs in the .ext file output. Corrected the error but am still puzzled as to why this has never shown up before, as it does not appear to be the result of any recent development work. --- extflat/EFbuild.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/extflat/EFbuild.c b/extflat/EFbuild.c index 09ac3a2e..a804a9de 100644 --- a/extflat/EFbuild.c +++ b/extflat/EFbuild.c @@ -486,6 +486,14 @@ efBuildEquiv(def, nodeName1, nodeName2) efNodeMerge(&nn1->efnn_node, &nn2->efnn_node); if (nn1->efnn_port > 0) nn2->efnn_port = nn1->efnn_port; else if (nn2->efnn_port > 0) nn1->efnn_port = nn2->efnn_port; + + /* If a node has been merged away, make sure that its name */ + /* points to the merged name's hash. */ + + if (nn1->efnn_node == NULL) + HashSetValue(he1, (char *)nn2); + else if (nn2->efnn_node == NULL) + HashSetValue(he2, (char *)nn1); } return; } From 59bfa6ce86f403ad1fa3adcd63fb0c738e379a5e Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 16 Mar 2021 22:46:46 -0400 Subject: [PATCH 31/89] Found no fewer than three separate places that cause a pop-up prompt for saving on a cell which is completely unmodified. One of these was due to the BPlane implementation, which forces an instance to be deleted and re-placed on a bounding box recomputation, which should not, in that case, be considered a modification. Another always runs DRC on a subcell upon reading rather than relying on any checkplane entries in the file itself; and the last one marking the timestamp as modified stemming from an attempt to correct an O(N^2) check to O(N). All three cases have now been corrected. --- database/DBcell.c | 73 ++++++++++++++++++++++++++++++++++++++++++ database/DBcellbox.c | 4 +-- database/DBio.c | 9 ++++-- database/database.h.in | 2 ++ 4 files changed, 83 insertions(+), 5 deletions(-) diff --git a/database/DBcell.c b/database/DBcell.c index 2ff4777c..e5c5bcbb 100644 --- a/database/DBcell.c +++ b/database/DBcell.c @@ -118,6 +118,7 @@ DBCellFindDup(use, parent) * ---------------------------------------------------------------------------- * * DBPlaceCell -- + * DBPlaceCellNoModify -- * * Add a CellUse to the subcell tile plane of a CellDef. * Assumes prior check that the new CellUse is not an exact duplicate @@ -162,11 +163,47 @@ DBPlaceCell (use, def) SigEnableInterrupts(); } +/* Like DBPlaceCell(), but don't change the flags of the parent cell. */ +/* This is needed by the bounding box recalculation routine, which may */ +/* cause the cell to be deleted and replaced for the purpose of */ +/* capturing the bounding box information in the BPlane structure, but */ +/* this does not mean that anything in the parent cell has changed. */ + +void +DBPlaceCellNoModify (use, def) + CellUse * use; /* new celluse to add to subcell tile plane */ + CellDef * def; /* parent cell's definition */ +{ + Rect rect; /* argument to DBSrCellPlaneArea(), placeCellFunc() */ + BPlane *bplane; /* argument to DBSrCellPlaneArea(), placeCellFunc() */ + struct searchArg arg; /* argument to placeCellFunc() */ + + ASSERT(use != (CellUse *) NULL, "DBPlaceCell"); + ASSERT(def, "DBPlaceCell"); + + /* To do: Check non-duplicate placement, check non-duplicate ID */ + + use->cu_parent = def; + + /* Be careful not to permit interrupts during this, or the + * database could be left in a trashed state. + */ + + SigDisableInterrupts(); + BPAdd(def->cd_cellPlane, use); + if (UndoIsEnabled()) + DBUndoCellUse(use, UNDO_CELL_PLACE); + SigEnableInterrupts(); +} + /* * ---------------------------------------------------------------------------- * DBDeleteCell -- * * Remove a CellUse from the subcell tile plane of a CellDef. + * If "nomodify" is TRUE, then don't set the parent cell's CDMODIFIED flag. + * This is needed when recomputing the bounding box, which should not by + * itself change the modified state. * * Results: * None. @@ -197,3 +234,39 @@ DBDeleteCell (use) SigEnableInterrupts(); } +/* + * ---------------------------------------------------------------------------- + * DBDeleteCellNoModify -- + * + * Remove a CellUse from the subcell tile plane of a CellDef, as above, + * but don't set the parent cell's CDMODIFIED flag. This is needed when + * recomputing the bounding box, which should not by itself change the + * modified state. + * + * Results: + * None. + * + * Side effects: + * Modifies the subcell tile plane of the CellDef, sets the + * parent pointer of the deleted CellUse to NULL. + * ---------------------------------------------------------------------------- + */ + +void +DBDeleteCellNoModify (use) + CellUse * use; +{ + ASSERT(use != (CellUse *) NULL, "DBDeleteCell"); + + /* It's important that this code run with interrupts disabled, + * or else we could leave the subcell tile plane in a weird + * state. + */ + + SigDisableInterrupts(); + dbInstanceUnplace(use); + if (UndoIsEnabled()) + DBUndoCellUse(use, UNDO_CELL_DELETE); + use->cu_parent = (CellDef *) NULL; + SigEnableInterrupts(); +} diff --git a/database/DBcellbox.c b/database/DBcellbox.c index e3d17408..55b8f327 100644 --- a/database/DBcellbox.c +++ b/database/DBcellbox.c @@ -723,7 +723,7 @@ dbReComputeBboxFunc(cellDef, boundProc, recurseProc) */ parent = use->cu_parent; - DBDeleteCell(use); + DBDeleteCellNoModify(use); use->cu_parent = parent; } @@ -751,7 +751,7 @@ dbReComputeBboxFunc(cellDef, boundProc, recurseProc) if ((parent = use->cu_parent) != (CellDef *) NULL) { parent->cd_flags |= CDBOXESCHANGED; - DBPlaceCell(use, parent); + DBPlaceCellNoModify(use, parent); if (last != parent) { if (last != NULL) (*recurseProc)(last); diff --git a/database/DBio.c b/database/DBio.c index e9026ef8..2b4747bd 100644 --- a/database/DBio.c +++ b/database/DBio.c @@ -411,7 +411,7 @@ dbCellReadDef(f, cellDef, name, ignoreTech, dereference) int cellStamp = 0, rectCount = 0, rectReport = 10000; char line[2048], tech[50], layername[50]; PaintResultType *ptable; - bool result = TRUE, scaleLimit = FALSE; + bool result = TRUE, scaleLimit = FALSE, has_mismatch; Rect *rp; int c; TileType type, rtype, loctype; @@ -844,6 +844,7 @@ done: * timestamp, then force the cell to be written out with a * correct timestamp. */ + has_mismatch = FALSE; if ((cellDef->cd_timestamp != cellStamp) || (cellStamp == 0)) { CellUse *cu; @@ -852,12 +853,13 @@ done: if (cu->cu_parent != NULL) { DBStampMismatch(cellDef, &cellDef->cd_bbox); + has_mismatch = TRUE; break; } } } /* Update timestamp flags */ - DBFlagMismatches(cellDef); + if (has_mismatch) DBFlagMismatches(cellDef); cellDef->cd_timestamp = cellStamp; if (cellStamp == 0) @@ -869,7 +871,8 @@ done: } UndoEnable(); - DRCCheckThis(cellDef, TT_CHECKPAINT, (Rect *) NULL); + /* Disabled 3/16/2021. Let <> in file force a DRC check */ + /* DRCCheckThis(cellDef, TT_CHECKPAINT, (Rect *) NULL); */ SigEnableInterrupts(); return (result); diff --git a/database/database.h.in b/database/database.h.in index 18ed836d..a8c88e57 100644 --- a/database/database.h.in +++ b/database/database.h.in @@ -790,7 +790,9 @@ extern CellUse *DBFindUse(); /* Insertion/deletion of cell uses into the cell tile plane of a parent */ extern void DBPlaceCell(); +extern void DBPlaceCellNoModify(); extern void DBDeleteCell(); +extern void DBDeleteCellNoModify(); extern void DBClearCellPlane(); /* Insertion/deletion of cell uses into the name space of a parent */ From 8a0b180cde86c652cb862e1ea77555c991baf16e Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 17 Mar 2021 12:45:35 -0400 Subject: [PATCH 32/89] Modified the crash backup script to add options "disable" and "resume". However, this has not been implemented as it has been observed that the use of itimer() has a restriction of one timer per process, which interferes with the three or more uses of the timer within magic. The timer method will have to be changed to use the POSIX timer_create() routine, before this will work properly. --- VERSION | 2 +- tcltk/tools.tcl | 39 ++++++++++++++++++++++++++++++++++++--- utils/signals.c | 20 +++++++++----------- 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/VERSION b/VERSION index 06768c81..5d5b8a8f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.141 +8.3.142 diff --git a/tcltk/tools.tcl b/tcltk/tools.tcl index 6addd626..538cfc01 100644 --- a/tcltk/tools.tcl +++ b/tcltk/tools.tcl @@ -58,11 +58,31 @@ proc magic::makecrashbackup {} { global Opts *bypass crash save - if {$Opts(backupinterval) > 0} { - after $Opts(backupinterval) magic::makecrashbackup + if {![catch set Opts(backupinterval)]} { + if {$Opts(backupinterval) > 0} { + after $Opts(backupinterval) magic::makecrashbackup + } } } +#---------------------------------------------------------------- +# magic::crashbackups --- +# +# Create periodic backups. Options are: +# +# start: Begin periodic backups. If interval is not +# specified, then set interval to 10 minutes. +# +# resume: Resume periodic backups if started and stopped, +# but not if disabled or never started. +# +# stop: Stop periodic backups. +# +# disable: Disable periodic backups; set to state of +# never having been started. +# +#---------------------------------------------------------------- + proc magic::crashbackups {{option start}} { global Opts @@ -71,12 +91,25 @@ proc magic::crashbackups {{option start}} { if {[catch set Opts(backupinterval)]} { set Opts(backupinterval) 600000 } - after $Opts(backupinterval) magic::makecrashbackup + if {$Opts(backupinterval) > 0} { + after $Opts(backupinterval) magic::makecrashbackup + } + } + resume { + if {![catch set Opts(backupinterval)]} { + if {$Opts(backupinterval) > 0} { + after $Opts(backupinterval) magic::makecrashbackup + } + } } stop - cancel { after cancel magic::makecrashbackup } + disable { + after cancel magic::makecrashbackup + unset Opts(backupinterval) + } } } diff --git a/utils/signals.c b/utils/signals.c index 974447ce..e6de92f3 100644 --- a/utils/signals.c +++ b/utils/signals.c @@ -26,8 +26,17 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include #include /* for getpid() */ #include +#include +#include "tcltk/tclmagic.h" #include "utils/main.h" +#include "utils/magic.h" +#include "utils/magsgtty.h" +#include "textio/textio.h" +#include "utils/geometry.h" +#include "utils/signals.h" +#include "windows/windows.h" +#include "graphics/graphics.h" #ifndef SIGEMT #define SIGEMT 7 /* EMT instruction (SIGUNUSED) */ @@ -57,17 +66,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #endif #endif -#include - -#include "utils/magic.h" -#include "utils/magsgtty.h" -#include "textio/textio.h" -#include "utils/geometry.h" -#include "utils/signals.h" -#include "windows/windows.h" -#include "graphics/graphics.h" - - #ifndef FASYNC # define FASYNC 00100 /* kludge for SUN2s */ #endif From fd4569081e6ce85b841768c44757c94c15a74075 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 17 Mar 2021 14:54:36 -0400 Subject: [PATCH 33/89] Added a reference count to the node structure in extflat to account for the "equiv" statement---equivalent nodes names have to be registered in the def->def_nodes hash table, and if they point to the same node, then that node can't be free'd until the last referenced node is seen when iterating through the hash table to free the node records during EFDone(). This is handled by the reference count. --- extflat/EFbuild.c | 18 +++++++++++++++++- extflat/EFflat.c | 1 + extflat/extflat.h | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/extflat/EFbuild.c b/extflat/EFbuild.c index a804a9de..97c71124 100644 --- a/extflat/EFbuild.c +++ b/extflat/EFbuild.c @@ -183,6 +183,7 @@ efBuildNode(def, isSubsnode, nodeName, nodeCap, x, y, layerName, av, ac) newname = (EFNodeName *) mallocMagic((unsigned)(sizeof (EFNodeName))); newname->efnn_hier = EFStrToHN((HierName *) NULL, nodeName); newname->efnn_port = -1; /* No port assignment */ + newname->efnn_refc = 0; /* Only reference is self */ newname->efnn_next = NULL; HashSetValue(he, (char *) newname); } @@ -491,9 +492,15 @@ efBuildEquiv(def, nodeName1, nodeName2) /* points to the merged name's hash. */ if (nn1->efnn_node == NULL) + { HashSetValue(he1, (char *)nn2); + nn2->efnn_refc += nn1->efnn_refc + 1; + } else if (nn2->efnn_node == NULL) + { HashSetValue(he2, (char *)nn1); + nn1->efnn_refc += nn2->efnn_refc + 1; + } } return; } @@ -1561,6 +1568,7 @@ efNodeAddName(node, he, hn) newnn->efnn_node = node; newnn->efnn_hier = hn; newnn->efnn_port = -1; + newnn->efnn_refc = 0; HashSetValue(he, (char *) newnn); /* If the node is a port of the top level cell, denoted by flag */ @@ -1869,7 +1877,15 @@ efFreeNodeTable(table) { for (hn = nn->efnn_hier; hn; hn = hn->hn_parent) (void) HashFind(&efFreeHashTable, (char *) hn); - freeMagic((char *) nn); + + /* Node equivalences made by "equiv" statements are handled */ + /* by reference count. Don't free the node structure until */ + /* all references have been seen. */ + + if (nn->efnn_refc > 0) + nn->efnn_refc--; + else + freeMagic((char *) nn); } } diff --git a/extflat/EFflat.c b/extflat/EFflat.c index 516c1f50..463b196e 100644 --- a/extflat/EFflat.c +++ b/extflat/EFflat.c @@ -545,6 +545,7 @@ efAddNodes(hc, stdcell) newname->efnn_node = newnode; newname->efnn_hier = hierName; newname->efnn_port = -1; + newname->efnn_refc = 0; if (newnode->efnode_name) { newname->efnn_next = newnode->efnode_name->efnn_next; diff --git a/extflat/extflat.h b/extflat/extflat.h index 0e2b361a..a512e7d8 100644 --- a/extflat/extflat.h +++ b/extflat/extflat.h @@ -119,6 +119,7 @@ typedef struct efnn struct efnn *efnn_next; /* Next name for this node */ HierName *efnn_hier; /* HierName for this node */ int efnn_port; /* Port number for this node */ + unsigned char efnn_refc; /* #times referenced in hash */ } EFNodeName; /* From 2532a696e445496c0bf2fcc67392ae66009dd0ba Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 18 Mar 2021 11:37:44 -0400 Subject: [PATCH 34/89] Correction from a recent commit; complicated sets of "equiv" statement in a .ext file require that all aliases of a node name be rehashed after a node merge, or else node loops can occur. Also prevented statements of the form "equiv A A" from being output in the .ext file, as they are useless. --- VERSION | 2 +- extflat/EFbuild.c | 18 +++++++++++++++--- extract/ExtBasic.c | 8 ++++++-- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/VERSION b/VERSION index 5d5b8a8f..8d330699 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.142 +8.3.143 diff --git a/extflat/EFbuild.c b/extflat/EFbuild.c index 97c71124..ef0cbb06 100644 --- a/extflat/EFbuild.c +++ b/extflat/EFbuild.c @@ -454,6 +454,8 @@ efBuildEquiv(def, nodeName1, nodeName2) nn1 = (EFNodeName *) HashGetValue(he1); nn2 = (EFNodeName *) HashGetValue(he2); + if (nn1 == nn2) return; /* These nodes already merged */ + if (nn2 == (EFNodeName *) NULL) { /* Create nodeName1 if it doesn't exist */ @@ -482,6 +484,10 @@ efBuildEquiv(def, nodeName1, nodeName2) return; /* Repeated "equiv" statement */ if (nn1->efnn_node != nn2->efnn_node) { + struct efnode *node1 = nn1->efnn_node; + struct efnode *node2 = nn2->efnn_node; + HashSearch hs; + if (efWarn) efReadError("Merged nodes %s and %s\n", nodeName1, nodeName2); efNodeMerge(&nn1->efnn_node, &nn2->efnn_node); @@ -489,17 +495,23 @@ efBuildEquiv(def, nodeName1, nodeName2) else if (nn2->efnn_port > 0) nn1->efnn_port = nn2->efnn_port; /* If a node has been merged away, make sure that its name */ - /* points to the merged name's hash. */ + /* and all aliases point to the merged name's hash. */ if (nn1->efnn_node == NULL) { - HashSetValue(he1, (char *)nn2); nn2->efnn_refc += nn1->efnn_refc + 1; + HashStartSearch(&hs); + while (he1 = HashNext(&def->def_nodes, &hs)) + if ((EFNodeName *)HashGetValue(he1) == nn1) + HashSetValue(he1, (char *)nn2); } else if (nn2->efnn_node == NULL) { - HashSetValue(he2, (char *)nn1); nn1->efnn_refc += nn2->efnn_refc + 1; + HashStartSearch(&hs); + while (he2 = HashNext(&def->def_nodes, &hs)) + if ((EFNodeName *)HashGetValue(he2) == nn2) + HashSetValue(he2, (char *)nn1); } } return; diff --git a/extract/ExtBasic.c b/extract/ExtBasic.c index 184d1be5..c5e0b1c3 100644 --- a/extract/ExtBasic.c +++ b/extract/ExtBasic.c @@ -727,13 +727,17 @@ extOutputNodes(nodeList, outFile) fprintf(outFile, "\"\n"); } - /* Output the alternate names for the node */ + /* Output the alternate names for the node. Avoid generating */ + /* unnecessary "equiv A A" entries for labels on disconnected */ + /* nets. */ + for (ll = reg->nreg_labels; ll; ll = ll->ll_next) if (ll->ll_label->lab_text == text) { for (ll = ll->ll_next; ll; ll = ll->ll_next) if (extLabType(ll->ll_label->lab_text, LABTYPE_NAME)) - fprintf(outFile, "equiv \"%s\" \"%s\"\n", + if (strcmp(text, ll->ll_label->lab_text)) + fprintf(outFile, "equiv \"%s\" \"%s\"\n", text, ll->ll_label->lab_text); break; } From cde90bb4a74b399a1cd90fef49334a45a8903bcf Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 18 Mar 2021 11:52:56 -0400 Subject: [PATCH 35/89] Corrected a bad typo, "==" instead of "="; can cause a crash condition when doing ext2spice. --- ext2spice/ext2spice.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext2spice/ext2spice.c b/ext2spice/ext2spice.c index 8e6e98c8..1cba8f8d 100644 --- a/ext2spice/ext2spice.c +++ b/ext2spice/ext2spice.c @@ -1935,7 +1935,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM) hierD = extHierSDAttr(&dev->dev_terms[pn]); - resclass == (pn > 1) ? esFetInfo[dev->dev_type].resClassDrain : + resclass = (pn > 1) ? esFetInfo[dev->dev_type].resClassDrain : esFetInfo[dev->dev_type].resClassSource; // For parameter a followed by parameter p, @@ -1998,7 +1998,7 @@ spcWriteParams(dev, hierName, scale, l, w, sdM) pn = plist->parm_type[1] - '0'; if (pn >= dev->dev_nterm) pn = dev->dev_nterm - 1; - resclass == (pn > 1) ? esFetInfo[dev->dev_type].resClassDrain : + resclass = (pn > 1) ? esFetInfo[dev->dev_type].resClassDrain : esFetInfo[dev->dev_type].resClassSource; hierD = extHierSDAttr(&dev->dev_terms[pn]); From 08cb75a9b47fd8f7c920b99e835512f184f3ff65 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 18 Mar 2021 15:16:37 -0400 Subject: [PATCH 36/89] Modified the GDS read routine behavior so that if a cell is being flattened per "gds flatten" or "gds flatglob", and the "gds readonly" option is not set, then the instances of the flattened cells are removed from the layout. They are retained for the "readonly" option because when writing GDS of such a cell, the full hierarchy needs to be walked. --- calma/CalmaRdcl.c | 52 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/calma/CalmaRdcl.c b/calma/CalmaRdcl.c index 7d0734c6..88bdc486 100644 --- a/calma/CalmaRdcl.c +++ b/calma/CalmaRdcl.c @@ -592,6 +592,25 @@ calmaParseElement(filename, pnsrefs, pnpaths) return (calmaSkipTo(CALMA_ENDEL)); } +/* + * ---------------------------------------------------------------------------- + * + * Callback procedure for enumerating any paint in a cell. Used to find if + * a cell needs to be retained after being flattened into the parent cell. + * + * Returns 1 always. Only called if a non-space tile was encountered. + * + * ---------------------------------------------------------------------------- + */ + +int +calmaEnumFunc(tile, plane) + Tile *tile; + int *plane; +{ + return 1; +} + /* * ---------------------------------------------------------------------------- * @@ -998,9 +1017,38 @@ calmaElementSref(filename) } } - /* If cell has children in addition to paint to be flattened, */ - /* then also generate an instance of the cell. */ + /* When not reading with VENDORGDS, if a cell has contents */ + /* other than the paint to be flattened, then also generate an */ + /* instance of the cell. Otherwise (with VENDORGDS), always */ + /* generate cell instances. Note that only paint and cells */ + /* are counted, not labels (see below). */ + else if (!(def->cd_flags & CDVENDORGDS)) + { + int plane; + for (plane = PL_TECHDEPBASE; plane < DBNumPlanes; plane++) + if (DBSrPaintArea((Tile *)NULL, def->cd_planes[plane], &TiPlaneRect, + &DBAllButSpaceAndDRCBits, calmaEnumFunc, (ClientData)NULL)) + break; + + if ((plane < DBNumPlanes) || DBCellEnum(def, gdsHasUses, (ClientData)NULL)) + { + use = DBCellNewUse(def, (useid) ? useid : (char *) NULL); + if (isArray) + DBMakeArray(use, &GeoIdentityTransform, xlo, ylo, xhi, yhi, xsep, ysep); + DBSetTrans(use, &trans); + DBPlaceCell(use, cifReadCellDef); + madeinst = TRUE; + } + else + { + /* (To do: Copy labels from flattened cells, with hierarchical */ + /* names. Whether to do this or not should be an option.) */ + TxPrintf("Removing instances of flattened cell %s in %s\n", + def->cd_name, cifReadCellDef->cd_name); + madeinst = TRUE; + } + } else { use = DBCellNewUse(def, (useid) ? useid : (char *) NULL); From 8384891f3d9ab1aedccdf99aea1b78444f26a0a9 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 18 Mar 2021 20:47:59 -0400 Subject: [PATCH 37/89] Removed one diagnostic message after flattening a cell in GDS input because depending on the GDS file it could be printed millions of times. --- calma/CalmaRdcl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/calma/CalmaRdcl.c b/calma/CalmaRdcl.c index 88bdc486..a775d821 100644 --- a/calma/CalmaRdcl.c +++ b/calma/CalmaRdcl.c @@ -1044,8 +1044,8 @@ calmaElementSref(filename) { /* (To do: Copy labels from flattened cells, with hierarchical */ /* names. Whether to do this or not should be an option.) */ - TxPrintf("Removing instances of flattened cell %s in %s\n", - def->cd_name, cifReadCellDef->cd_name); + /* TxPrintf("Removing instances of flattened cell %s in %s\n", + def->cd_name, cifReadCellDef->cd_name); */ madeinst = TRUE; } } From b77352849d9ae1951e4c08380191a1f62c8c25e6 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sat, 20 Mar 2021 17:04:31 -0400 Subject: [PATCH 38/89] Corrected the "what" command so that the correct cells are listed that contain the selected paint. Previously, all cells inside the area of the selection box would be printed, which is completely wrong, and can lead unexpectedly to thousands of cell instance names being printed out. --- VERSION | 2 +- commands/CmdTZ.c | 76 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 63 insertions(+), 15 deletions(-) diff --git a/VERSION b/VERSION index 8d330699..8db3b356 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.143 +8.3.144 diff --git a/commands/CmdTZ.c b/commands/CmdTZ.c index 00478dd6..7bc0530e 100644 --- a/commands/CmdTZ.c +++ b/commands/CmdTZ.c @@ -844,6 +844,41 @@ typedef struct labelstore static int moreLabelEntries, labelEntryCount; static LabelStore *labelBlockTop, *labelEntry; +/* + * ---------------------------------------------------------------------------- + * + * cmdFindWhatTileFunc --- + * + * Callback function for CmdWhat(). Given a tile found in the current + * selection, searches the database to find what cell or cells that type + * belongs to. + * + * ---------------------------------------------------------------------------- + */ + +int +cmdFindWhatTileFunc(Tile *tile, ClientData clientData) +{ + struct linked_id **lid = (struct linked_id **)clientData; + SearchContext scx; + TileTypeBitMask tmask; + TileType type; + + TiToRect(tile, &scx.scx_area); + scx.scx_use = EditCellUse; + scx.scx_trans = GeoIdentityTransform; + + if (SplitSide(tile)) + type = SplitRightType(tile); + else + type = SplitLeftType(tile); + TTMaskSetOnlyType(&tmask, type); + + DBTreeSrTiles(&scx, &tmask, 0, cmdWhatPrintCell, (ClientData)lid); + + return 0; +} + /* * ---------------------------------------------------------------------------- * @@ -875,9 +910,7 @@ CmdWhat(w, cmd) bool foundAny; bool doList = FALSE; TileTypeBitMask layers, maskBits, *rMask; - SearchContext scx; CellUse *CheckUse; - struct linked_id *lid; #ifdef MAGIC_WRAPPER Tcl_Obj *lobj, *paintobj, *labelobj, *cellobj; @@ -959,29 +992,44 @@ CmdWhat(w, cmd) } if ((CheckUse != NULL) && (CheckUse->cu_def == SelectRootDef)) { - scx.scx_use = CheckUse; - scx.scx_area = SelectUse->cu_bbox; // BSI - scx.scx_trans = GeoIdentityTransform; // BSI + CellUse *saveUse = EditCellUse; + struct linked_id *lid; + int pNum; + + EditCellUse = CheckUse; TxPrintf("Selected mask layers:\n"); for (i = TT_SELECTBASE; i < DBNumUserLayers; i++) { if (TTMaskHasType(&layers, i)) { - lid = NULL; - TxPrintf(" %-8s (", DBTypeLongName(i)); TTMaskSetOnlyType(&maskBits, i); if (DBIsContact(i)) DBMaskAddStacking(&maskBits); - DBTreeSrTiles(&scx, &maskBits, 0, cmdWhatPrintCell, - (ClientData)&lid); - TxPrintf(")\n"); - while (lid != NULL) - { - freeMagic(lid); - lid = lid->lid_next; + + /* Search selection for tiles of this type, then */ + /* call cmdFindWhatTileFunc() to search the cell */ + /* def in the area of that tile to determine what */ + /* cell or subcell that tile belongs to. */ + + lid = NULL; + TxPrintf(" %-8s (", DBTypeLongName(i)); + for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) + if (TTMaskHasType(&DBPlaneTypes[pNum], i)) + { + DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pNum], + &SelectUse->cu_bbox, &maskBits, + cmdFindWhatTileFunc, (ClientData)&lid); + } + + TxPrintf(")\n"); + while (lid != NULL) + { + freeMagic(lid); + lid = lid->lid_next; } } } + EditCellUse = saveUse; } else { From 58cdbc53566978d5af44b8a920c193919911ada9 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sun, 21 Mar 2021 12:02:43 -0400 Subject: [PATCH 39/89] Made the "select short" command a bit easier to use (and more in line with the existing documentation) by not requiring the net containing the two labels to be selected before running the "select short" command. The command now first checks if the labels exist in the selection, and if not, the command effectively executes "goto label1 ; select net" and then continues as previously implemented. --- VERSION | 2 +- select/selOps.c | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 8db3b356..c8e7cc7e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.144 +8.3.145 diff --git a/select/selOps.c b/select/selOps.c index 7eb2f9a8..e71ed7ce 100644 --- a/select/selOps.c +++ b/select/selOps.c @@ -22,6 +22,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #endif /* not lint */ #include +#include #include "utils/magic.h" #include "utils/geometry.h" @@ -717,6 +718,43 @@ SelectShort(char *lab1, char *lab2) destlab = selLabel; } + /* Was nothing selected? Then run the equivalent of "goto lab1 ; select net */ + if (srclab == NULL && destlab == NULL) + { + CellUse *use; + TileType ttype; + Rect rect; + SearchContext scx; + MagWindow *window; + DBWclientRec *crec; + int windowMask; + + window = ToolGetBoxWindow(&rect, &windowMask); + if (!window) return NULL; + + use = (CellUse *)window->w_surfaceID; + ttype = CmdFindNetProc(lab1, use, &rect, FALSE); + if (ttype == TT_SPACE) return NULL; + + bzero(&scx, sizeof(SearchContext)); + scx.scx_use = use; + scx.scx_trans = GeoIdentityTransform; + scx.scx_area = rect; + crec = (DBWclientRec *)window->w_clientData; + + SelectNet(&scx, ttype, crec->dbw_bitmask, (Rect *)NULL, FALSE); + + for (selLabel = SelectDef->cd_labels; selLabel != NULL; selLabel = + selLabel->lab_next) + { + if ((srclab == NULL) && Match(lab1, selLabel->lab_text)) + srclab = selLabel; + + if ((destlab == NULL) && Match(lab2, selLabel->lab_text)) + destlab = selLabel; + } + } + /* Must be able to find both labels */ if (srclab == NULL || destlab == NULL) return NULL; From 633f6f558d4e3ff26db71c37f9fe2869c532cd6e Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sun, 21 Mar 2021 15:54:07 -0400 Subject: [PATCH 40/89] Modified the connectivity finding search routine so that it does not crash if too many unprocessed areas get queued up. Also modified it to prune entries that match one of the last five entries created before searching the current tile. However, it is not clear that that makes any significant difference to the run time, and it needs to be analyzed vs. the number of entries to check against. --- database/DBconnect.c | 79 +++++++++++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 19 deletions(-) diff --git a/database/DBconnect.c b/database/DBconnect.c index 1265d860..eb03fdcb 100644 --- a/database/DBconnect.c +++ b/database/DBconnect.c @@ -88,6 +88,7 @@ struct conSrArg2 conSrArea *csa2_list; /* List of areas to process */ int csa2_top; /* Index of next area to process */ + int csa2_lasttop; /* Previous top index */ int csa2_size; /* Max. number bins in area list */ }; @@ -654,7 +655,7 @@ dbcUnconnectFunc(tile, clientData) * connectivity between them. * * Results: - * Always 0. + * Return 0 normally, 1 if list size exceeds integer bounds. * * Side effects: * Adds a label to the destination definition "def". @@ -740,7 +741,7 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2) if ((slab->lab_flags & PORT_NUM_MASK) == lidx) { Rect newarea; - int pNum; + int i, pNum; // Do NOT go searching on labels connected to space! if (slab->lab_type == TT_SPACE) continue; @@ -763,24 +764,34 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2) newarea.r_ybot--; newarea.r_ytop++; + /* Check if any of the last 5 entries has the same type and */ + /* area. If so, don't duplicate the existing entry. */ + + for (i = csa2->csa2_lasttop; i > csa2->csa2_lasttop - 5; i--) + if (connectMask == csa2->csa2_list[i].connectMask) + if (GEO_SURROUND(&csa2->csa2_list[i].area, &newarea)) + return 0; + /* Register the area and connection mask as needing to be processed */ if (++csa2->csa2_top == csa2->csa2_size) { + conSrArea *newlist; + int newSize, newTotal; + /* Reached list size limit---need to enlarge the list */ /* Double the size of the list every time we hit the limit */ - conSrArea *newlist; - int i, lastsize = csa2->csa2_size; + newSize = csa2->csa2_size * 2; + newTotal = newSize * sizeof(conSrArea); + if (newTotal <= 0) return 1; - csa2->csa2_size *= 2; - - newlist = (conSrArea *)mallocMagic(csa2->csa2_size - * sizeof(conSrArea)); + newlist = (conSrArea *)mallocMagic((size_t)newTotal); memcpy((void *)newlist, (void *)csa2->csa2_list, - (size_t)lastsize * sizeof(conSrArea)); + (size_t)csa2->csa2_size * sizeof(conSrArea)); freeMagic((char *)csa2->csa2_list); csa2->csa2_list = newlist; + csa2->csa2_size = newSize; } csa2->csa2_list[csa2->csa2_top].area = newarea; @@ -811,7 +822,8 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2) * catecorner tiles from being considered as connected. * * Results: - * Always returns 0 to keep the search from aborting. + * Returns 0 normally to keep the search from aborting; returns 1 + * if allocation of list failed due to exceeding integer bounds. * * Side effects: * Adds paint to the destination definition. @@ -835,7 +847,7 @@ dbcConnectFunc(tile, cx) SearchContext scx2; TileType loctype = TiGetTypeExact(tile); TileType dinfo = 0; - int pNum = cx->tc_plane; + int i, pNum = cx->tc_plane; CellDef *def; TiToRect(tile, &tileArea); @@ -948,6 +960,16 @@ dbcConnectFunc(tile, cx) newarea.r_xtop += 1; } + /* Check if any of the last 5 entries has the same type and */ + /* area. If so, don't duplicate the existing entry. */ + /* (NOTE: Connect masks are all from the same table, so */ + /* they can be compared by address, no need for TTMaskEqual)*/ + + for (i = csa2->csa2_lasttop; i > csa2->csa2_lasttop - 5; i--) + if (connectMask == csa2->csa2_list[i].connectMask) + if (GEO_SURROUND(&csa2->csa2_list[i].area, &newarea)) + return 0; + /* Register the area and connection mask as needing to be processed */ if (++csa2->csa2_top == csa2->csa2_size) @@ -956,15 +978,19 @@ dbcConnectFunc(tile, cx) /* Double the size of the list every time we hit the limit */ conSrArea *newlist; - int i, lastsize = csa2->csa2_size; + int newSize, newTotal; - csa2->csa2_size *= 2; + newSize = csa2->csa2_size * 2; + newTotal = newSize * sizeof(conSrArea); - newlist = (conSrArea *)mallocMagic((size_t)(csa2->csa2_size) * sizeof(conSrArea)); + if (newTotal <= 0) return 1; /* Exceeded integer bounds */ + + newlist = (conSrArea *)mallocMagic((size_t)newTotal); memcpy((void *)newlist, (void *)csa2->csa2_list, - (size_t)lastsize * sizeof(conSrArea)); + (size_t)csa2->csa2_size * sizeof(conSrArea)); freeMagic((char *)csa2->csa2_list); csa2->csa2_list = newlist; + csa2->csa2_size = newSize; } csa2->csa2_list[csa2->csa2_top].area = newarea; @@ -1054,10 +1080,12 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse) csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_START_SIZE * sizeof(conSrArea)); csa2.csa2_top = -1; + csa2.csa2_lasttop = -1; DBTreeSrTiles(scx, mask, xMask, dbcConnectFunc, (ClientData) &csa2); while (csa2.csa2_top >= 0) { + int result; char pathstring[FLATTERMSIZE]; TerminalPath tpath; @@ -1069,12 +1097,21 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse) scx->scx_area = csa2.csa2_list[csa2.csa2_top].area; newtype = csa2.csa2_list[csa2.csa2_top].dinfo; csa2.csa2_top--; + csa2.csa2_lasttop = csa2.csa2_top; if (newtype & TT_DIAGONAL) - DBTreeSrNMTiles(scx, newtype, newmask, xMask, dbcConnectFunc, + result = DBTreeSrNMTiles(scx, newtype, newmask, xMask, dbcConnectFunc, (ClientData) &csa2); else - DBTreeSrTiles(scx, newmask, xMask, dbcConnectFunc, (ClientData) &csa2); + result = DBTreeSrTiles(scx, newmask, xMask, dbcConnectFunc, + (ClientData) &csa2); + + if (result != 0) + { + TxError("Connectivity search exceeded memory limit and stopped;" + " incomplete result.\n"); + break; + } /* Check the source def for any labels belonging to this */ /* tile area and plane, and add them to the destination. */ @@ -1107,8 +1144,12 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse) } if (doLabels == SEL_SIMPLE_LABELS) tpath.tp_first = NULL; if (doLabels != SEL_NO_LABELS) - DBTreeSrLabels(scx, newmask, xMask, &tpath, searchtype, - dbcConnectLabelFunc, (ClientData) &csa2); + if (DBTreeSrLabels(scx, newmask, xMask, &tpath, searchtype, + dbcConnectLabelFunc, (ClientData) &csa2) != 0) + { + TxError("Connection search hit memory limit and stopped.\n"); + break; + } } freeMagic((char *)csa2.csa2_list); From fbd1acd60ed24f07876c6dae6e2f1c992193e436 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sun, 21 Mar 2021 17:21:25 -0400 Subject: [PATCH 41/89] A few corrections to the network connection selection. The pruning method does not work and needs debugging, but is otherwise harmless. --- database/DBconnect.c | 129 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 124 insertions(+), 5 deletions(-) diff --git a/database/DBconnect.c b/database/DBconnect.c index eb03fdcb..cdab8d1c 100644 --- a/database/DBconnect.c +++ b/database/DBconnect.c @@ -767,7 +767,8 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2) /* Check if any of the last 5 entries has the same type and */ /* area. If so, don't duplicate the existing entry. */ - for (i = csa2->csa2_lasttop; i > csa2->csa2_lasttop - 5; i--) + for (i = csa2->csa2_lasttop; (i >= 0) && + (i > csa2->csa2_lasttop - 5); i--) if (connectMask == csa2->csa2_list[i].connectMask) if (GEO_SURROUND(&csa2->csa2_list[i].area, &newarea)) return 0; @@ -965,7 +966,7 @@ dbcConnectFunc(tile, cx) /* (NOTE: Connect masks are all from the same table, so */ /* they can be compared by address, no need for TTMaskEqual)*/ - for (i = csa2->csa2_lasttop; i > csa2->csa2_lasttop - 5; i--) + for (i = csa2->csa2_lasttop; (i >= 0) && (i > csa2->csa2_lasttop - 5); i--) if (connectMask == csa2->csa2_list[i].connectMask) if (GEO_SURROUND(&csa2->csa2_list[i].area, &newarea)) return 0; @@ -1000,6 +1001,118 @@ dbcConnectFunc(tile, cx) return 0; } +/* + * ---------------------------------------------------------------------------- + * ---------------------------------------------------------------------------- + */ + +int +dbcCheckConnectFunc(tile, cx) + Tile *tile; /* Tile found. */ + TreeContext *cx; /* Describes context of search. The client + * data is a pointer to a conSrArg2 record + * containing various required information. + */ +{ + struct conSrArg2 *csa2; + Rect tileArea, newarea; + TileTypeBitMask *connectMask, notConnectMask; + Rect *srArea; + SearchContext *scx = cx->tc_scx; + SearchContext scx2; + TileType loctype = TiGetTypeExact(tile); + TileType dinfo = 0; + int i, pNum = cx->tc_plane; + CellDef *def; + + TiToRect(tile, &tileArea); + srArea = &scx->scx_area; + + GeoTransRect(&scx->scx_trans, &tileArea, &newarea); + + /* Clip the current area down to something that overlaps the + * area of interest. + */ + + csa2 = (struct conSrArg2 *)cx->tc_filter->tf_arg; + GeoClip(&newarea, csa2->csa2_bounds); + if (GEO_RECTNULL(&newarea)) return 1; + + if (IsSplit(tile)) + { + dinfo = DBTransformDiagonal(loctype, &scx->scx_trans); + loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile); + } + + connectMask = &csa2->csa2_connect[loctype]; + + if (DBIsContact(loctype)) + { + /* The mask of contact types must include all stacked contacts */ + + TTMaskZero(¬ConnectMask); + TTMaskSetMask(¬ConnectMask, &DBNotConnectTbl[loctype]); + } + else + TTMaskCom2(¬ConnectMask, connectMask); + + /* Only check those tiles in the destination (select) */ + /* which have not already been painted. */ + + def = csa2->csa2_use->cu_def; + if (DBSrPaintNMArea((Tile *) NULL, def->cd_planes[pNum], + dinfo, &newarea, ¬ConnectMask, dbcUnconnectFunc, + (ClientData) NULL) == 0) + return 1; + + return 0; +} + +/* + * ---------------------------------------------------------------------------- + * ---------------------------------------------------------------------------- + */ + +int +dbPruneEntries(scx, xMask, csa2) + SearchContext *scx; + int xMask; + struct conSrArg2 *csa2; +{ + int i, j, result; + TileTypeBitMask *newmask; + TileType newtype; + + for (i = 0, j = 0; i < csa2->csa2_top; i++) + { + newmask = csa2->csa2_list[i].connectMask; + scx->scx_area = csa2->csa2_list[i].area; + newtype = csa2->csa2_list[i].dinfo; + + if (newtype & TT_DIAGONAL) + result = DBTreeSrNMTiles(scx, newtype, newmask, xMask, dbcCheckConnectFunc, + (ClientData) csa2); + else + result = DBTreeSrTiles(scx, newmask, xMask, dbcCheckConnectFunc, + (ClientData) csa2); + + if (result == 0) + { + if (i > j) + { + csa2->csa2_list[j].connectMask = newmask; + csa2->csa2_list[j].area = scx->scx_area; + csa2->csa2_list[j].dinfo = newtype; + } + j++; + } + } + if (j == i) + return 1; + + csa2->csa2_top = j; + return 0; +} /* * ---------------------------------------------------------------------------- @@ -1108,9 +1221,15 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse) if (result != 0) { - TxError("Connectivity search exceeded memory limit and stopped;" - " incomplete result.\n"); - break; + result = dbPruneEntries(scx, xMask, &csa2); + if (result == 1) + { + TxError("Connectivity search exceeded memory limit and stopped;" + " incomplete result.\n"); + break; + } + else + continue; } /* Check the source def for any labels belonging to this */ From 4ff8d0681069712cfb58938cdd8614b6d42fa7e0 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sun, 21 Mar 2021 20:53:20 -0400 Subject: [PATCH 42/89] Changed to a hybrid list and stack; the list keeps 65536 entries at a time, and when it runs out of space, it pushes the stack. This should speed up the connectivity routine somewhat, as it no longer has to copy memory when expanding the list size, and it no longer has limit at the integer boundary for memory allocation. --- database/DBconnect.c | 199 ++++++++----------------------------------- 1 file changed, 36 insertions(+), 163 deletions(-) diff --git a/database/DBconnect.c b/database/DBconnect.c index cdab8d1c..3ea3bee9 100644 --- a/database/DBconnect.c +++ b/database/DBconnect.c @@ -29,6 +29,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include "utils/geometry.h" #include "tiles/tile.h" #include "utils/hash.h" +#include "utils/stack.h" #include "database/database.h" #include "database/databaseInt.h" #include "select/select.h" @@ -86,13 +87,13 @@ struct conSrArg2 int csa2_xMask; /* Cell window mask for search */ Rect *csa2_bounds; /* Area that limits the search */ + Stack *csa2_stack; /* Stack of full csa2_list entries */ conSrArea *csa2_list; /* List of areas to process */ int csa2_top; /* Index of next area to process */ int csa2_lasttop; /* Previous top index */ - int csa2_size; /* Max. number bins in area list */ }; -#define CSA2_LIST_START_SIZE 256 +#define CSA2_LIST_SIZE 65536 /* Number of entries per list */ /* *----------------------------------------------------------------- @@ -775,24 +776,17 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2) /* Register the area and connection mask as needing to be processed */ - if (++csa2->csa2_top == csa2->csa2_size) + if (++csa2->csa2_top == CSA2_LIST_SIZE) { + /* Reached list size limit---need to push the list and */ + /* start a new one. */ + conSrArea *newlist; - int newSize, newTotal; - /* Reached list size limit---need to enlarge the list */ - /* Double the size of the list every time we hit the limit */ - - newSize = csa2->csa2_size * 2; - newTotal = newSize * sizeof(conSrArea); - if (newTotal <= 0) return 1; - - newlist = (conSrArea *)mallocMagic((size_t)newTotal); - memcpy((void *)newlist, (void *)csa2->csa2_list, - (size_t)csa2->csa2_size * sizeof(conSrArea)); - freeMagic((char *)csa2->csa2_list); + newlist = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * + sizeof(conSrArea)); + StackPush((ClientData)csa2->csa2_list, csa2->csa2_stack); csa2->csa2_list = newlist; - csa2->csa2_size = newSize; } csa2->csa2_list[csa2->csa2_top].area = newarea; @@ -973,25 +967,17 @@ dbcConnectFunc(tile, cx) /* Register the area and connection mask as needing to be processed */ - if (++csa2->csa2_top == csa2->csa2_size) + if (++csa2->csa2_top == CSA2_LIST_SIZE) { - /* Reached list size limit---need to enlarge the list */ - /* Double the size of the list every time we hit the limit */ + /* Reached list size limit---need to push the list and */ + /* start a new one. */ conSrArea *newlist; - int newSize, newTotal; - newSize = csa2->csa2_size * 2; - newTotal = newSize * sizeof(conSrArea); - - if (newTotal <= 0) return 1; /* Exceeded integer bounds */ - - newlist = (conSrArea *)mallocMagic((size_t)newTotal); - memcpy((void *)newlist, (void *)csa2->csa2_list, - (size_t)csa2->csa2_size * sizeof(conSrArea)); - freeMagic((char *)csa2->csa2_list); + newlist = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea)); + StackPush((ClientData)csa2->csa2_list, csa2->csa2_stack); csa2->csa2_list = newlist; - csa2->csa2_size = newSize; + csa2->csa2_top = 0; } csa2->csa2_list[csa2->csa2_top].area = newarea; @@ -1001,119 +987,6 @@ dbcConnectFunc(tile, cx) return 0; } -/* - * ---------------------------------------------------------------------------- - * ---------------------------------------------------------------------------- - */ - -int -dbcCheckConnectFunc(tile, cx) - Tile *tile; /* Tile found. */ - TreeContext *cx; /* Describes context of search. The client - * data is a pointer to a conSrArg2 record - * containing various required information. - */ -{ - struct conSrArg2 *csa2; - Rect tileArea, newarea; - TileTypeBitMask *connectMask, notConnectMask; - Rect *srArea; - SearchContext *scx = cx->tc_scx; - SearchContext scx2; - TileType loctype = TiGetTypeExact(tile); - TileType dinfo = 0; - int i, pNum = cx->tc_plane; - CellDef *def; - - TiToRect(tile, &tileArea); - srArea = &scx->scx_area; - - GeoTransRect(&scx->scx_trans, &tileArea, &newarea); - - /* Clip the current area down to something that overlaps the - * area of interest. - */ - - csa2 = (struct conSrArg2 *)cx->tc_filter->tf_arg; - GeoClip(&newarea, csa2->csa2_bounds); - if (GEO_RECTNULL(&newarea)) return 1; - - if (IsSplit(tile)) - { - dinfo = DBTransformDiagonal(loctype, &scx->scx_trans); - loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile); - } - - connectMask = &csa2->csa2_connect[loctype]; - - if (DBIsContact(loctype)) - { - /* The mask of contact types must include all stacked contacts */ - - TTMaskZero(¬ConnectMask); - TTMaskSetMask(¬ConnectMask, &DBNotConnectTbl[loctype]); - } - else - TTMaskCom2(¬ConnectMask, connectMask); - - /* Only check those tiles in the destination (select) */ - /* which have not already been painted. */ - - def = csa2->csa2_use->cu_def; - if (DBSrPaintNMArea((Tile *) NULL, def->cd_planes[pNum], - dinfo, &newarea, ¬ConnectMask, dbcUnconnectFunc, - (ClientData) NULL) == 0) - return 1; - - return 0; -} - -/* - * ---------------------------------------------------------------------------- - * ---------------------------------------------------------------------------- - */ - -int -dbPruneEntries(scx, xMask, csa2) - SearchContext *scx; - int xMask; - struct conSrArg2 *csa2; -{ - int i, j, result; - TileTypeBitMask *newmask; - TileType newtype; - - for (i = 0, j = 0; i < csa2->csa2_top; i++) - { - newmask = csa2->csa2_list[i].connectMask; - scx->scx_area = csa2->csa2_list[i].area; - newtype = csa2->csa2_list[i].dinfo; - - if (newtype & TT_DIAGONAL) - result = DBTreeSrNMTiles(scx, newtype, newmask, xMask, dbcCheckConnectFunc, - (ClientData) csa2); - else - result = DBTreeSrTiles(scx, newmask, xMask, dbcCheckConnectFunc, - (ClientData) csa2); - - if (result == 0) - { - if (i > j) - { - csa2->csa2_list[j].connectMask = newmask; - csa2->csa2_list[j].area = scx->scx_area; - csa2->csa2_list[j].dinfo = newtype; - } - j++; - } - } - if (j == i) - return 1; - - csa2->csa2_top = j; - return 0; -} - /* * ---------------------------------------------------------------------------- * @@ -1189,16 +1062,15 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse) /* malloc calls by maintaining a small list and expanding it only */ /* when necessary. */ - csa2.csa2_size = CSA2_LIST_START_SIZE; - csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_START_SIZE - * sizeof(conSrArea)); + csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea)); csa2.csa2_top = -1; csa2.csa2_lasttop = -1; + csa2.csa2_stack = StackNew(100); + DBTreeSrTiles(scx, mask, xMask, dbcConnectFunc, (ClientData) &csa2); while (csa2.csa2_top >= 0) { - int result; char pathstring[FLATTERMSIZE]; TerminalPath tpath; @@ -1209,29 +1081,29 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse) newmask = csa2.csa2_list[csa2.csa2_top].connectMask; scx->scx_area = csa2.csa2_list[csa2.csa2_top].area; newtype = csa2.csa2_list[csa2.csa2_top].dinfo; - csa2.csa2_top--; + if (csa2.csa2_top == 0) + { + if (StackLook(csa2.csa2_stack) != (ClientData)NULL) + { + freeMagic(csa2.csa2_list); + csa2.csa2_list = (conSrArea *)StackPop(csa2.csa2_stack); + csa2.csa2_top = CSA2_LIST_SIZE - 1; + } + else + csa2.csa2_top--; + } + else + csa2.csa2_top--; + csa2.csa2_lasttop = csa2.csa2_top; if (newtype & TT_DIAGONAL) - result = DBTreeSrNMTiles(scx, newtype, newmask, xMask, dbcConnectFunc, + DBTreeSrNMTiles(scx, newtype, newmask, xMask, dbcConnectFunc, (ClientData) &csa2); else - result = DBTreeSrTiles(scx, newmask, xMask, dbcConnectFunc, + DBTreeSrTiles(scx, newmask, xMask, dbcConnectFunc, (ClientData) &csa2); - if (result != 0) - { - result = dbPruneEntries(scx, xMask, &csa2); - if (result == 1) - { - TxError("Connectivity search exceeded memory limit and stopped;" - " incomplete result.\n"); - break; - } - else - continue; - } - /* Check the source def for any labels belonging to this */ /* tile area and plane, and add them to the destination. */ @@ -1271,6 +1143,7 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse) } } freeMagic((char *)csa2.csa2_list); + StackFree(csa2.csa2_stack); /* Recompute the bounding box of the destination and record its area * for redisplay. From f7820ed960a0d8a891ba4040d3b37086cd0879f8 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sun, 21 Mar 2021 22:26:50 -0400 Subject: [PATCH 43/89] Corrected an error in the connectivity tables that for contact types failed to add in any layers from other planes that are marked as connected in the "connect" section of the techfile but otherwise unrelated to the contact type and its residues. --- database/DBtech.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/database/DBtech.c b/database/DBtech.c index 19ccded6..2ea3676f 100644 --- a/database/DBtech.c +++ b/database/DBtech.c @@ -425,7 +425,8 @@ DBTechFinalConnect() for (n = 0; n < dbNumContacts; n++) { lp = dbContactInfo[n]; - TTMaskSetOnlyType(&DBNotConnectTbl[lp->l_type], lp->l_type); + TTMaskZero(&DBNotConnectTbl[lp->l_type]); + TTMaskSetMask(&DBNotConnectTbl[lp->l_type], &DBConnectTbl[lp->l_type]); rMask = DBResidueMask(lp->l_type); /* Different contact types may share residues. */ From c2aedcebabf46f6764f8dc9e6fbcfdf6ed418175 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 22 Mar 2021 09:49:56 -0400 Subject: [PATCH 44/89] Applied the same change made yesterday to DBconnect.c to ResConDCS.c and SimDBstuff.c, which have nearly the same connectivity search functions. All three now use the hybrid list + stack method. --- VERSION | 2 +- database/DBconnect.c | 2 -- resis/ResConDCS.c | 61 +++++++++++++++++++++++++++++--------------- sim/SimDBstuff.c | 56 +++++++++++++++++++++++++++------------- 4 files changed, 79 insertions(+), 42 deletions(-) diff --git a/VERSION b/VERSION index c8e7cc7e..6a0e5078 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.145 +8.3.146 diff --git a/database/DBconnect.c b/database/DBconnect.c index 3ea3bee9..950c8d45 100644 --- a/database/DBconnect.c +++ b/database/DBconnect.c @@ -84,7 +84,6 @@ struct conSrArg2 * to what. */ SearchContext *csa2_topscx; /* Original top-level search context */ - int csa2_xMask; /* Cell window mask for search */ Rect *csa2_bounds; /* Area that limits the search */ Stack *csa2_stack; /* Stack of full csa2_list entries */ @@ -1053,7 +1052,6 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse) unsigned char searchtype; csa2.csa2_use = destUse; - csa2.csa2_xMask = xMask; csa2.csa2_bounds = area; csa2.csa2_connect = connect; csa2.csa2_topscx = scx; diff --git a/resis/ResConDCS.c b/resis/ResConDCS.c index a150cfb8..c8591f97 100644 --- a/resis/ResConDCS.c +++ b/resis/ResConDCS.c @@ -17,6 +17,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include "utils/geofast.h" #include "tiles/tile.h" #include "utils/hash.h" +#include "utils/stack.h" #include "database/database.h" #include "utils/malloc.h" #include "textio/textio.h" @@ -46,12 +47,13 @@ struct conSrArg2 int csa2_xMask; /* Cell window mask for search */ Rect *csa2_bounds; /* Area that limits the search */ + Stack *csa2_stack; /* Stack of full csa2_list entries */ conSrArea *csa2_list; /* List of areas to process */ int csa2_top; /* Index of next area to process */ - int csa2_size; /* Max. number bins in area list */ + int csa2_lasttop; /* Previous top index */ }; -#define CSA2_LIST_START_SIZE 256 +#define CSA2_LIST_SIZE 65536 /* Number of entries per list */ extern int dbcUnconnectFunc(); extern int dbcConnectLabelFunc(); @@ -100,7 +102,7 @@ dbcConnectFuncDCS(tile, cx) TileType dinfo = 0; SearchContext *scx = cx->tc_scx; SearchContext scx2; - int pNum; + int i, pNum; CellDef *def; ExtDevice *devptr; TerminalPath tpath; @@ -296,29 +298,29 @@ dbcConnectFuncDCS(tile, cx) newarea.r_ytop += 1; } + /* Check if any of the last 5 entries has the same type and */ + /* area. If so, don't duplicate the existing entry. */ + /* (NOTE: Connect masks are all from the same table, so */ + /* they can be compared by address, no need for TTMaskEqual)*/ + + for (i = csa2->csa2_lasttop; (i >= 0) && (i > csa2->csa2_lasttop - 5); i--) + if (connectMask == csa2->csa2_list[i].connectMask) + if (GEO_SURROUND(&csa2->csa2_list[i].area, &newarea)) + return 0; + /* Register the area and connection mask as needing to be processed */ - if (++csa2->csa2_top == csa2->csa2_size) + if (++csa2->csa2_top == CSA2_LIST_SIZE) { /* Reached list size limit---need to enlarge the list */ /* Double the size of the list every time we hit the limit */ conSrArea *newlist; - int i, lastsize = csa2->csa2_size; - csa2->csa2_size *= 2; - - newlist = (conSrArea *)mallocMagic(csa2->csa2_size * sizeof(conSrArea)); - memcpy((void *)newlist, (void *)csa2->csa2_list, - (size_t)lastsize * sizeof(conSrArea)); - // for (i = 0; i < lastsize; i++) - // { - // newlist[i].area = csa2->csa2_list[i].area; - // newlist[i].connectMask = csa2->csa2_list[i].connectMask; - // newlist[i].dinfo = csa2->csa2_list[i].dinfo; - // } - freeMagic((char *)csa2->csa2_list); + newlist = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea)); + StackPush((ClientData)csa2->csa2_list, csa2->csa2_stack); csa2->csa2_list = newlist; + csa2->csa2_top = 0; } csa2->csa2_list[csa2->csa2_top].area = newarea; @@ -443,10 +445,11 @@ DBTreeCopyConnectDCS(scx, mask, xMask, connect, area, destUse) csa2.csa2_connect = connect; csa2.csa2_topscx = scx; - csa2.csa2_size = CSA2_LIST_START_SIZE; - csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_START_SIZE - * sizeof(conSrArea)); + csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea)); csa2.csa2_top = -1; + csa2.csa2_lasttop = -1; + + csa2.csa2_stack = StackNew(100); if (first) { @@ -474,7 +477,22 @@ DBTreeCopyConnectDCS(scx, mask, xMask, connect, area, destUse) newmask = csa2.csa2_list[csa2.csa2_top].connectMask; scx->scx_area = csa2.csa2_list[csa2.csa2_top].area; newtype = csa2.csa2_list[csa2.csa2_top].dinfo; - csa2.csa2_top--; + if (csa2.csa2_top == 0) + { + if (StackLook(csa2.csa2_stack) != (ClientData)NULL) + { + freeMagic(csa2.csa2_list); + csa2.csa2_list = (conSrArea *)StackPop(csa2.csa2_stack); + csa2.csa2_top = CSA2_LIST_SIZE - 1; + } + else + csa2.csa2_top--; + } + else + csa2.csa2_top--; + + csa2.csa2_lasttop = csa2.csa2_top; + if (newtype & TT_DIAGONAL) DBTreeSrNMTiles(scx, newtype, newmask, xMask, dbcConnectFuncDCS, (ClientData) &csa2); @@ -482,6 +500,7 @@ DBTreeCopyConnectDCS(scx, mask, xMask, connect, area, destUse) DBTreeSrTiles(scx, newmask, xMask, dbcConnectFuncDCS, (ClientData) &csa2); } freeMagic((char *)csa2.csa2_list); + StackFree(csa2.csa2_stack); for (CurrentT = DevList; CurrentT != NULL; CurrentT=CurrentT->nextDev) { diff --git a/sim/SimDBstuff.c b/sim/SimDBstuff.c index 840d749f..b303d4e6 100644 --- a/sim/SimDBstuff.c +++ b/sim/SimDBstuff.c @@ -31,6 +31,7 @@ #include "utils/geofast.h" #include "tiles/tile.h" #include "utils/hash.h" +#include "utils/stack.h" #include "database/database.h" #include "database/databaseInt.h" #include "textio/textio.h" @@ -86,12 +87,13 @@ struct conSrArg2 */ Rect *csa2_bounds; /* Area that limits the search */ + Stack *csa2_stack; /* Stack of full csa2_list entries */ conSrArea *csa2_list; /* List of areas to process */ int csa2_top; /* Index of next area to process */ - int csa2_size; /* Max. number bins in area list */ + int csa2_lasttop; /* Previous top index */ }; -#define CSA2_LIST_START_SIZE 256 +#define CSA2_LIST_SIZE 65536 /* Number of entries per list */ /* Forward declarations */ @@ -303,27 +305,29 @@ SimConnectFunc(tile, cx) return 1; } + /* Check if any of the last 5 entries has the same type and */ + /* area. If so, don't duplicate the existing entry. */ + /* (NOTE: Connect masks are all from the same table, so */ + /* they can be compared by address, no need for TTMaskEqual)*/ + + for (i = csa2->csa2_lasttop; (i >= 0) && (i > csa2->csa2_lasttop - 5); i--) + if (connectMask == csa2->csa2_list[i].connectMask) + if (GEO_SURROUND(&csa2->csa2_list[i].area, &newarea)) + return 0; + /* Register the area and connection mask as needing to be processed */ - if (++csa2->csa2_top == csa2->csa2_size) + if (++csa2->csa2_top == CSA2_LIST_SIZE) { /* Reached list size limit---need to enlarge the list */ /* Double the size of the list every time we hit the limit */ conSrArea *newlist; - int i, lastsize = csa2->csa2_size; - csa2->csa2_size *= 2; - - newlist = (conSrArea *)mallocMagic(csa2->csa2_size * sizeof(conSrArea)); - for (i = 0; i < lastsize; i++) - { - newlist[i].area = csa2->csa2_list[i].area; - newlist[i].connectMask = csa2->csa2_list[i].connectMask; - newlist[i].dinfo = csa2->csa2_list[i].dinfo; - } - freeMagic((char *)csa2->csa2_list); + newlist = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea)); + StackPush((ClientData)csa2->csa2_list, csa2->csa2_stack); csa2->csa2_list = newlist; + csa2->csa2_top = 0; } csa2->csa2_list[csa2->csa2_top].area = newarea; @@ -407,10 +411,11 @@ SimTreeCopyConnect(scx, mask, xMask, connect, area, destUse, Node_Name) csa2.csa2_bounds = area; csa2.csa2_connect = connect; - csa2.csa2_size = CSA2_LIST_START_SIZE; - csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_START_SIZE - * sizeof(conSrArea)); + csa2.csa2_list = (conSrArea *)mallocMagic(CSA2_LIST_SIZE * sizeof(conSrArea)); csa2.csa2_top = -1; + csa2.csa2_lasttop = -1; + + csa2.csa2_stack = StackNew(100); tpath.tp_first = tpath.tp_next = pathName; tpath.tp_last = pathName + MAXPATHNAME; @@ -425,7 +430,21 @@ SimTreeCopyConnect(scx, mask, xMask, connect, area, destUse, Node_Name) newmask = csa2.csa2_list[csa2.csa2_top].connectMask; scx->scx_area = csa2.csa2_list[csa2.csa2_top].area; newtype = csa2.csa2_list[csa2.csa2_top].dinfo; - csa2.csa2_top--; + if (csa2.csa2_top == 0) + { + if (StckLook(csa2.csa2_stack) != (ClientData)NULL) + { + freeMagic(csa2.csa2_list); + csa2.csa2_list = (conSrArea *)StackPop(csa2.csa2_stack); + csa2.csa2_top = CSA2_LIST_SIZE - 1; + } + else + csa2.csa2_top--; + } + else + csa2.csa2_top--; + + csa2.csa2_lasttop = csa2.csa2_top; if (newtype & TT_DIAGONAL) SimTreeSrNMTiles(scx, newtype, newmask, xMask, &tpath, @@ -435,6 +454,7 @@ SimTreeCopyConnect(scx, mask, xMask, connect, area, destUse, Node_Name) (ClientData) &csa2); } freeMagic((char *)csa2.csa2_list); + StackFree(csa2.csa2_stack); /* Recompute the bounding box of the destination and record * its area for redisplay. From e152deb97bb963684dee5fd053724e976971d861 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 23 Mar 2021 11:14:44 -0400 Subject: [PATCH 45/89] Corrected typo from the last commit that will cause a crash. . . --- VERSION | 2 +- sim/SimDBstuff.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 6a0e5078..d1ab7407 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.146 +8.3.147 diff --git a/sim/SimDBstuff.c b/sim/SimDBstuff.c index b303d4e6..9fafac20 100644 --- a/sim/SimDBstuff.c +++ b/sim/SimDBstuff.c @@ -432,7 +432,7 @@ SimTreeCopyConnect(scx, mask, xMask, connect, area, destUse, Node_Name) newtype = csa2.csa2_list[csa2.csa2_top].dinfo; if (csa2.csa2_top == 0) { - if (StckLook(csa2.csa2_stack) != (ClientData)NULL) + if (StackLook(csa2.csa2_stack) != (ClientData)NULL) { freeMagic(csa2.csa2_list); csa2.csa2_list = (conSrArea *)StackPop(csa2.csa2_stack); From 7cb88ffceb56c31acd11426d2c42da9b88ed5506 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 24 Mar 2021 14:52:17 -0400 Subject: [PATCH 46/89] Added a new selection command option "select intersect" that selects the area of intersection between any number of types. --- commands/CmdRS.c | 147 ++++++++++----------------------- select/selCreate.c | 199 +++++++++++++++++++++++++++++++++++++++++++++ select/select.h | 1 + 3 files changed, 245 insertions(+), 102 deletions(-) diff --git a/commands/CmdRS.c b/commands/CmdRS.c index 37f9a58c..7bdb5b0f 100644 --- a/commands/CmdRS.c +++ b/commands/CmdRS.c @@ -528,6 +528,26 @@ CmdSee(w, cmd) return; } +#define SEL_AREA 0 +#define SEL_VISIBLE 1 +#define SEL_CELL 2 +#define SEL_LABELS 3 +#define SEL_INTERSECT 4 +#define SEL_CLEAR 5 +#define SEL_FLAT 6 +#define SEL_HELP 7 +#define SEL_KEEP 8 +#define SEL_MOVE 9 +#define SEL_PICK 10 +#define SEL_SAVE 11 +#define SEL_FEEDBACK 12 +#define SEL_BBOX 13 +#define SEL_BOX 14 +#define SEL_CHUNK 15 +#define SEL_REGION 16 +#define SEL_NET 17 +#define SEL_SHORT 18 +#define SEL_DEFAULT 19 /* * ---------------------------------------------------------------------------- @@ -550,86 +570,10 @@ CmdSee(w, cmd) /* ARGSUSED */ void -cmdSelectArea(layers, less) - char *layers; /* Which layers are to be selected. */ - bool less; -{ - SearchContext scx; - TileTypeBitMask mask; - int windowMask, xMask; - DBWclientRec *crec; - MagWindow *window; - - bzero(&scx, sizeof(SearchContext)); - window = ToolGetBoxWindow(&scx.scx_area, &windowMask); - if (window == NULL) - { - TxPrintf("The box isn't in a window.\n"); - return; - } - - /* Since the box may actually be in multiple windows, we have to - * be a bit careful. If the box is only in one window, then there's - * no problem. If it's in more than window, the cursor must - * disambiguate the windows. - */ - - xMask = ((DBWclientRec *) window->w_clientData)->dbw_bitmask; - if ((windowMask & ~xMask) != 0) - { - window = CmdGetRootPoint((Point *) NULL, (Rect *) NULL); - xMask = ((DBWclientRec *) window->w_clientData)->dbw_bitmask; - if ((windowMask & xMask) == 0) - { - TxPrintf("The box is in more than one window; use the cursor\n"); - TxPrintf("to select the one you want to select from.\n"); - return; - } - } - if (CmdParseLayers(layers, &mask)) - { - if (TTMaskEqual(&mask, &DBSpaceBits)) - (void) CmdParseLayers("*,label", &mask); - TTMaskClearType(&mask, TT_SPACE); - } - else return; - - if (less) - { - (void) SelRemoveArea(&scx.scx_area, &mask); - return; - } - - scx.scx_use = (CellUse *) window->w_surfaceID; - scx.scx_trans = GeoIdentityTransform; - crec = (DBWclientRec *) window->w_clientData; - SelectArea(&scx, &mask, crec->dbw_bitmask); -} - -/* - * ---------------------------------------------------------------------------- - * - * cmdSelectVisible -- - * - * This is a utility procedure used by CmdSelect to do area - * selection of visible paint. - * - * Results: - * None. - * - * Side effects: - * The selection is augmented to contain all the information on - * layers that is visible under the box, including paint, labels, - * and expanded subcells. - * - * ---------------------------------------------------------------------------- - */ - - /* ARGSUSED */ -void -cmdSelectVisible(layers, less) +cmdSelectArea(layers, less, option) char *layers; /* Which layers are to be selected. */ bool less; + int option; /* Option from defined list above */ { SearchContext scx; TileTypeBitMask mask; @@ -680,6 +624,7 @@ cmdSelectVisible(layers, less) scx.scx_use = (CellUse *) window->w_surfaceID; scx.scx_trans = GeoIdentityTransform; crec = (DBWclientRec *) window->w_clientData; + if (option == SEL_VISIBLE) { int i; for (i = 0; i < DBNumUserLayers; i++) @@ -688,7 +633,10 @@ cmdSelectVisible(layers, less) TTMaskClearType(&mask, i); } } - SelectArea(&scx, &mask, crec->dbw_bitmask); + if (option == SEL_INTERSECT) + SelectIntersect(&scx, &mask, crec->dbw_bitmask); + else + SelectArea(&scx, &mask, crec->dbw_bitmask); } /* @@ -728,32 +676,13 @@ CmdSelect(w, cmd) * second table, due to a help message for ":select" with no arguments. */ -#define SEL_AREA 0 -#define SEL_VISIBLE 1 -#define SEL_CELL 2 -#define SEL_LABELS 3 -#define SEL_CLEAR 4 -#define SEL_FLAT 5 -#define SEL_HELP 6 -#define SEL_KEEP 7 -#define SEL_MOVE 8 -#define SEL_PICK 9 -#define SEL_SAVE 10 -#define SEL_FEEDBACK 11 -#define SEL_BBOX 12 -#define SEL_BOX 13 -#define SEL_CHUNK 14 -#define SEL_REGION 15 -#define SEL_NET 16 -#define SEL_SHORT 17 -#define SEL_DEFAULT 18 - static char *cmdSelectOption[] = { "area", "visible", "cell", "labels", + "intersection", "clear", "flat", "help", @@ -780,6 +709,7 @@ CmdSelect(w, cmd) "[more | less] visible [layers] [de]select all visible info under box in layers", "[more | less | top] cell [name] [de]select cell under cursor, or \"name\"", "[do | no] labels [do not] select subcell labels", + "[more | less] intersection [layers] [de]select intersection of layers", "clear clear selection", "flat flatten the contents of the selection", "help print this message", @@ -980,7 +910,7 @@ CmdSelect(w, cmd) } if (!(more || less)) SelectClear(); if (cmd->tx_argc == 3) - cmdSelectArea(optionArgs[1], less); + cmdSelectArea(optionArgs[1], less, option); else cmdSelectArea("*,label,subcell", less); return; @@ -994,8 +924,21 @@ CmdSelect(w, cmd) if (cmd->tx_argc > 3) goto usageError; if (!(more || less)) SelectClear(); if (cmd->tx_argc == 3) - cmdSelectVisible(optionArgs[1], less); - else cmdSelectVisible("*,label,subcell", less); + cmdSelectArea(optionArgs[1], less, option); + else cmdSelectArea("*,label,subcell", less, option); + return; + + /*-------------------------------------------------------------------- + * Select area that is the intersection of all the specified layers + *-------------------------------------------------------------------- + */ + + case SEL_INTERSECT: + if (cmd->tx_argc > 3) goto usageError; + if (!(more || less)) SelectClear(); + if (cmd->tx_argc == 3) + cmdSelectArea(optionArgs[1], less, option); + else cmdSelectArea("*,label,subcell", less, option); return; /*-------------------------------------------------------------------- diff --git a/select/selCreate.c b/select/selCreate.c index 22054364..7968dc61 100644 --- a/select/selCreate.c +++ b/select/selCreate.c @@ -253,6 +253,205 @@ selClearFunc(scx) else return 2; } +/* Structure used by selIntersectPaintFunc() */ + +struct selIntersectData { + Rect *sid_rect; + TileType sid_type; +}; + +/* + * ---------------------------------------------------------------------------- + * + * selDupPaintFunc -- + * + * Copy paint from tile area in Select2Def into SelectDef as all types + * in rMask. + * + * ---------------------------------------------------------------------------- + */ + +int +selDupPaintFunc(tile, rMask) + Tile *tile; /* The tile to get the area to copy paint. */ + TileTypeBitMask *rMask; /* Paint types to copy to. */ +{ + Rect r; + + TiToRect(tile, &r); + DBPaintMask(SelectDef, &r, rMask); + + return 0; /* Keep the search going. */ +} + +/* + * ---------------------------------------------------------------------------- + * + * selIntersectPaintFunc2 --- + * + * ---------------------------------------------------------------------------- + */ + +int +selIntersectPaintFunc2(tile, sid) + Tile *tile; /* The tile to copy paint from. */ + struct selIntersectData *sid; +{ + Rect r; + int p; + + TiToRect(tile, &r); + GEOCLIP(&r, sid->sid_rect); /* Clip out the intersection area */ + + DBPaint(Select2Def, &r, sid->sid_type); /* Paint back into Select2Def */ + + return 0; /* Keep the search going. */ +} + +/* + * ---------------------------------------------------------------------------- + * + * selIntersectPaintFunc -- + * + * Erase paint of types in rMask from the area of the tile. + * + * ---------------------------------------------------------------------------- + */ + +int +selIntersectPaintFunc(tile, type) + Tile *tile; /* The tile to copy paint from. */ + TileType type; /* The type of tile to keep */ +{ + TileTypeBitMask tMask; + Rect r; + int plane; + struct selIntersectData sid; + + TiToRect(tile, &r); + + TTMaskSetOnlyType(&tMask, type); + plane = DBPlane(type); + + sid.sid_type = TiGetTypeExact(tile); + sid.sid_rect = &r; + + DBSrPaintArea((Tile *)NULL, Select2Def->cd_planes[plane], &r, + &tMask, selIntersectPaintFunc2, (ClientData)&sid); + + return 0; /* Keep the search going. */ +} + +/* + * ---------------------------------------------------------------------------- + * + * SelectIntersect -- + * + * This procedure selects all information that falls in a given area + * and contains the intersection of all the supplied types. + * + * Results: + * None. + * + * Side effects: + * The indicated information is added to the select cell, and + * outlined on the screen. Only information of particular + * types, and in expanded cells (according to xMask) is + * selected. + * + * ---------------------------------------------------------------------------- + */ + +void +SelectIntersect(scx, types, xMask) + SearchContext *scx; /* Describes the area in which material + * is to be selected. The resulting + * coordinates should map to the coordinates + * of EditRootDef. The cell use should be + * the root of a window. + */ + TileTypeBitMask *types; /* Indicates which intersecting layers to + * select. May not include labels or cells. + */ + int xMask; /* Indicates window (or windows) where cells + * must be expanded for their contents to be + * considered. 0 means treat everything as + * expanded. + */ +{ + TileTypeBitMask tMask, rMask; + TileType s, t; + int plane; + + /* If the source definition is changing, clear the old selection. */ + + if (SelectRootDef != scx->scx_use->cu_def) + { + if (SelectRootDef != NULL) + SelectClear(); + SelectRootDef = scx->scx_use->cu_def; + SelSetDisplay(SelectUse, SelectRootDef); + } + + SelRememberForUndo(TRUE, (CellDef *) NULL, (Rect *) NULL); + + /* Select all paint of types in "types" mask and copy into Select2Def */ + + DBCellClearDef(Select2Def); + (void) DBCellCopyAllPaint(scx, types, xMask, Select2Use); + + /* Find the first type in the list. This will be used as the reference */ + + for (t = 0; t < DBNumUserLayers; t++) + if (TTMaskHasType(types, t)) + break; + + if (t == DBNumUserLayers) return; + + /* Compute the type mask of the reference type */ + TTMaskSetOnlyType(&tMask, t); + plane = DBPlane(t); + + /* For each other type in "types", do the following */ + + for (s = t + 1; s < DBNumUserLayers; s++) + { + if (TTMaskHasType(types, s)) + { + /* Copy the reference paint type from Select2Def into SelectDef */ + DBSrPaintArea((Tile *)NULL, Select2Def->cd_planes[plane], &scx->scx_area, + &tMask, selDupPaintFunc, (ClientData)&tMask); + + /* Erase the reference paint type from Select2Def */ + DBEraseMask(Select2Def, &TiPlaneRect, &tMask); + + /* Scan Select2Def for all geometry of type s inside the areas of */ + /* the reference type, and copy back to Select2Def as the reference */ + /* type */ + DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[plane], + &scx->scx_area, &tMask, selIntersectPaintFunc, (ClientData)s); + + /* Erase the reference paint type from SelectDef */ + DBEraseMask(SelectDef, &TiPlaneRect, &tMask); + } + } + + /* Copy any remaining paint in the reference layer in Select2Def to */ + /* SelectDef as all the intersection types. */ + + DBSrPaintArea((Tile *)NULL, Select2Def->cd_planes[plane], &scx->scx_area, + &tMask, selDupPaintFunc, (ClientData)types); + + SelectDef->cd_types = *types; /* Remember what types were requested */ + + /* Display the new selection. */ + + SelRememberForUndo(FALSE, SelectRootDef, &scx->scx_area); + DBReComputeBbox(SelectDef); + DBWHLRedraw(SelectRootDef, &scx->scx_area, TRUE); + DBWAreaChanged(SelectDef, &SelectDef->cd_extended, DBW_ALLWINDOWS, + &DBAllButSpaceBits); +} /* * ---------------------------------------------------------------------------- diff --git a/select/select.h b/select/select.h index 25509db0..3f53f648 100644 --- a/select/select.h +++ b/select/select.h @@ -35,6 +35,7 @@ extern void SelectRegion(); extern void SelectInit(); extern void SelectClear(); extern void SelectCell(); +extern void SelectIntersect(); extern void SelRemoveArea(); extern int SelRemoveSel2(); extern int SelectRemoveCellUse(); From b0f89ea4afe4b609991166dc91ef3fb7577f0400 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 24 Mar 2021 14:57:13 -0400 Subject: [PATCH 47/89] Updated VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index d1ab7407..3ac1f0f1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.147 +8.3.148 From dd86ecc454a36dc1fb88bbc8d782d4d43dd0e7d8 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 24 Mar 2021 15:30:30 -0400 Subject: [PATCH 48/89] Extended the "what" command to take the option "-listall" in addition to "-list", where the list of layers returned is more like the (recently extended) non-listing method where each type is followed by a list of cell names in which that type is found (within the selection area). --- commands/CmdTZ.c | 62 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/commands/CmdTZ.c b/commands/CmdTZ.c index 7bc0530e..aa0b378e 100644 --- a/commands/CmdTZ.c +++ b/commands/CmdTZ.c @@ -825,7 +825,6 @@ int cmdWhatPrintCell(tile, cxp) } if (curlid == NULL) { - TxPrintf(" %s ", CurrCellName); curlid = (struct linked_id *)mallocMagic(sizeof(struct linked_id)); curlid->lid_name = CurrCellName; curlid->lid_next = *lid; @@ -887,7 +886,7 @@ cmdFindWhatTileFunc(Tile *tile, ClientData clientData) * Print out information about what's selected. * * Usage: - * what [-list] + * what [-list[all]] * * Results: * None. @@ -896,7 +895,8 @@ cmdFindWhatTileFunc(Tile *tile, ClientData clientData) * Information gets printed to identify the kinds of paint, plus * labels and subcells, that are selected. * In the TCL version, the "-list" option puts the result in a - * nested TCL list. + * nested TCL list. The "-listall" variant gives more information + * about what cell(s) each type exists in, in the type list. * * ---------------------------------------------------------------------------- */ @@ -908,12 +908,12 @@ CmdWhat(w, cmd) { int i, locargc; bool foundAny; - bool doList = FALSE; + bool doList = FALSE, doListAll = FALSE; TileTypeBitMask layers, maskBits, *rMask; CellUse *CheckUse; #ifdef MAGIC_WRAPPER - Tcl_Obj *lobj, *paintobj, *labelobj, *cellobj; + Tcl_Obj *lobj, *paintobj, *paintcellobj, *labelobj, *cellobj; extern int cmdWhatCellListFunc(); #endif @@ -923,14 +923,23 @@ CmdWhat(w, cmd) locargc = cmd->tx_argc; #ifdef MAGIC_WRAPPER - if ((locargc == 2) && !strncmp(cmd->tx_argv[locargc - 1], "-list", 5)) + if (locargc == 2) { - doList = TRUE; - locargc--; - lobj = Tcl_NewListObj(0, NULL); - paintobj = Tcl_NewListObj(0, NULL); - labelobj = Tcl_NewListObj(0, NULL); - cellobj = Tcl_NewListObj(0, NULL); + if (!strncmp(cmd->tx_argv[locargc - 1], "-list", 5)) + { + if (!strncmp(cmd->tx_argv[locargc - 1], "-listall", 8)) + { + doListAll = TRUE; + paintcellobj = Tcl_NewListObj(0, NULL); + } + else + doList = TRUE; + locargc--; + lobj = Tcl_NewListObj(0, NULL); + paintobj = Tcl_NewListObj(0, NULL); + labelobj = Tcl_NewListObj(0, NULL); + cellobj = Tcl_NewListObj(0, NULL); + } } if (locargc > 1) { @@ -993,7 +1002,7 @@ CmdWhat(w, cmd) if ((CheckUse != NULL) && (CheckUse->cu_def == SelectRootDef)) { CellUse *saveUse = EditCellUse; - struct linked_id *lid; + struct linked_id *lid, *lidp; int pNum; EditCellUse = CheckUse; @@ -1012,7 +1021,6 @@ CmdWhat(w, cmd) /* cell or subcell that tile belongs to. */ lid = NULL; - TxPrintf(" %-8s (", DBTypeLongName(i)); for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) if (TTMaskHasType(&DBPlaneTypes[pNum], i)) { @@ -1021,7 +1029,25 @@ CmdWhat(w, cmd) cmdFindWhatTileFunc, (ClientData)&lid); } - TxPrintf(")\n"); + if (!doListAll) + { + TxPrintf(" %-8s (", DBTypeLongName(i)); + for (lidp = lid; lidp; lidp = lidp->lid_next) + TxPrintf(" %s ", lidp->lid_name); + TxPrintf(")\n"); + } + else + { + Tcl_ListObjAppendElement(magicinterp, paintobj, + Tcl_NewStringObj(DBTypeLongName(i), -1)); + Tcl_ListObjAppendElement(magicinterp, paintobj, + paintcellobj); + + for (lidp = lid; lidp; lidp = lidp->lid_next) + Tcl_ListObjAppendElement(magicinterp, paintcellobj, + Tcl_NewStringObj(lidp->lid_name, -1)); + } + while (lid != NULL) { freeMagic(lid); @@ -1056,7 +1082,7 @@ CmdWhat(w, cmd) qsort(labelBlockTop, labelEntryCount, sizeof(LabelStore), orderLabelFunc); #ifdef MAGIC_WRAPPER - if (doList) + if (doList || doListAll) { Tcl_Obj *newtriple; for (labelEntry = labelBlockTop; labelEntryCount-- > 0; labelEntry++) @@ -1100,7 +1126,7 @@ CmdWhat(w, cmd) foundAny = FALSE; #ifdef MAGIC_WRAPPER - if (doList) + if (doList || doListAll) SelEnumCells(FALSE, (bool *) NULL, (SearchContext *) NULL, cmdWhatCellListFunc, (ClientData) cellobj); else @@ -1109,7 +1135,7 @@ CmdWhat(w, cmd) cmdWhatCellFunc, (ClientData) &foundAny); #ifdef MAGIC_WRAPPER - if (doList) + if (doList || doListAll) { Tcl_ListObjAppendElement(magicinterp, lobj, paintobj); Tcl_ListObjAppendElement(magicinterp, lobj, labelobj); From e884b5b256b3a4c0b1dfb0d33907a55038111ea6 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 24 Mar 2021 16:57:22 -0400 Subject: [PATCH 49/89] Revised the "select intersect" command from the previous commit so that the behavior is to pare down any existing selection by removing any parts of it that do not intersect the layer specified on the command line. This is generally more useful than the previous method, as the intended purpose is to intersect a number of layers against one (e.g., all transistors intersecting deep nwell). --- commands/CmdRS.c | 69 +++++++++++++++++++++-- commands/CmdTZ.c | 5 +- select/selCreate.c | 138 +++++++++++---------------------------------- 3 files changed, 100 insertions(+), 112 deletions(-) diff --git a/commands/CmdRS.c b/commands/CmdRS.c index 7bdb5b0f..370380d9 100644 --- a/commands/CmdRS.c +++ b/commands/CmdRS.c @@ -633,12 +633,72 @@ cmdSelectArea(layers, less, option) TTMaskClearType(&mask, i); } } - if (option == SEL_INTERSECT) - SelectIntersect(&scx, &mask, crec->dbw_bitmask); else SelectArea(&scx, &mask, crec->dbw_bitmask); } +/* + * ---------------------------------------------------------------------------- + * + * cmdIntersectArea -- + * + * This is a utility procedure used by CmdSelect to do area + * selection itersect. + * + * Results: + * None. + * + * Side effects: + * The selection is pared down to contain only the part of the + * original selection that intersects with the type "layer". + * + * ---------------------------------------------------------------------------- + */ + +void +cmdIntersectArea(layer) + char *layer; /* The layer to intersect with */ +{ + TileType ttype; + SearchContext scx; + int windowMask, xMask; + DBWclientRec *crec; + MagWindow *window; + + bzero(&scx, sizeof(SearchContext)); + window = ToolGetBoxWindow(&scx.scx_area, &windowMask); + if (window == NULL) + { + TxPrintf("The box isn't in a window.\n"); + return; + } + + /* Since the box may actually be in multiple windows, we have to + * be a bit careful. If the box is only in one window, then there's + * no problem. If it's in more than window, the cursor must + * disambiguate the windows. + */ + + xMask = ((DBWclientRec *) window->w_clientData)->dbw_bitmask; + if ((windowMask & ~xMask) != 0) + { + window = CmdGetRootPoint((Point *) NULL, (Rect *) NULL); + xMask = ((DBWclientRec *) window->w_clientData)->dbw_bitmask; + if ((windowMask & xMask) == 0) + { + TxPrintf("The box is in more than one window; use the cursor\n"); + TxPrintf("to select the one you want to select from.\n"); + return; + } + } + + scx.scx_use = (CellUse *) window->w_surfaceID; + scx.scx_trans = GeoIdentityTransform; + crec = (DBWclientRec *) window->w_clientData; + ttype = DBTechNoisyNameType(layer); + SelectIntersect(&scx, ttype, crec->dbw_bitmask); +} + /* * ---------------------------------------------------------------------------- * @@ -935,10 +995,7 @@ CmdSelect(w, cmd) case SEL_INTERSECT: if (cmd->tx_argc > 3) goto usageError; - if (!(more || less)) SelectClear(); - if (cmd->tx_argc == 3) - cmdSelectArea(optionArgs[1], less, option); - else cmdSelectArea("*,label,subcell", less, option); + cmdIntersectArea(optionArgs[1]); return; /*-------------------------------------------------------------------- diff --git a/commands/CmdTZ.c b/commands/CmdTZ.c index aa0b378e..26b8fb50 100644 --- a/commands/CmdTZ.c +++ b/commands/CmdTZ.c @@ -1040,12 +1040,13 @@ CmdWhat(w, cmd) { Tcl_ListObjAppendElement(magicinterp, paintobj, Tcl_NewStringObj(DBTypeLongName(i), -1)); - Tcl_ListObjAppendElement(magicinterp, paintobj, - paintcellobj); for (lidp = lid; lidp; lidp = lidp->lid_next) Tcl_ListObjAppendElement(magicinterp, paintcellobj, Tcl_NewStringObj(lidp->lid_name, -1)); + + Tcl_ListObjAppendElement(magicinterp, paintobj, + paintcellobj); } while (lid != NULL) diff --git a/select/selCreate.c b/select/selCreate.c index 7968dc61..ebb92793 100644 --- a/select/selCreate.c +++ b/select/selCreate.c @@ -253,37 +253,6 @@ selClearFunc(scx) else return 2; } -/* Structure used by selIntersectPaintFunc() */ - -struct selIntersectData { - Rect *sid_rect; - TileType sid_type; -}; - -/* - * ---------------------------------------------------------------------------- - * - * selDupPaintFunc -- - * - * Copy paint from tile area in Select2Def into SelectDef as all types - * in rMask. - * - * ---------------------------------------------------------------------------- - */ - -int -selDupPaintFunc(tile, rMask) - Tile *tile; /* The tile to get the area to copy paint. */ - TileTypeBitMask *rMask; /* Paint types to copy to. */ -{ - Rect r; - - TiToRect(tile, &r); - DBPaintMask(SelectDef, &r, rMask); - - return 0; /* Keep the search going. */ -} - /* * ---------------------------------------------------------------------------- * @@ -293,18 +262,15 @@ selDupPaintFunc(tile, rMask) */ int -selIntersectPaintFunc2(tile, sid) +selIntersectPaintFunc2(tile, rect) Tile *tile; /* The tile to copy paint from. */ - struct selIntersectData *sid; + Rect *rect; /* Area to clip to */ { Rect r; - int p; TiToRect(tile, &r); - GEOCLIP(&r, sid->sid_rect); /* Clip out the intersection area */ - - DBPaint(Select2Def, &r, sid->sid_type); /* Paint back into Select2Def */ - + GEOCLIP(&r, rect); /* Clip out the intersection area */ + DBPaint(SelectDef, &r, TiGetTypeExact(tile)); /* Paint back into SelectDef */ return 0; /* Keep the search going. */ } @@ -319,26 +285,21 @@ selIntersectPaintFunc2(tile, sid) */ int -selIntersectPaintFunc(tile, type) +selIntersectPaintFunc(tile) Tile *tile; /* The tile to copy paint from. */ - TileType type; /* The type of tile to keep */ { TileTypeBitMask tMask; Rect r; - int plane; - struct selIntersectData sid; + int pNum; TiToRect(tile, &r); - TTMaskSetOnlyType(&tMask, type); - plane = DBPlane(type); - - sid.sid_type = TiGetTypeExact(tile); - sid.sid_rect = &r; - - DBSrPaintArea((Tile *)NULL, Select2Def->cd_planes[plane], &r, - &tMask, selIntersectPaintFunc2, (ClientData)&sid); - + for (pNum = 0; pNum < DBNumPlanes; pNum++) + { + DBSrPaintArea((Tile *)NULL, Select2Def->cd_planes[pNum], &r, + &DBAllButSpaceAndDRCBits, selIntersectPaintFunc2, + (ClientData)&r); + } return 0; /* Keep the search going. */ } @@ -363,15 +324,15 @@ selIntersectPaintFunc(tile, type) */ void -SelectIntersect(scx, types, xMask) +SelectIntersect(scx, type, xMask) SearchContext *scx; /* Describes the area in which material * is to be selected. The resulting * coordinates should map to the coordinates * of EditRootDef. The cell use should be * the root of a window. */ - TileTypeBitMask *types; /* Indicates which intersecting layers to - * select. May not include labels or cells. + TileType type; /* Indicates which layer to intersect with + * the current selection. */ int xMask; /* Indicates window (or windows) where cells * must be expanded for their contents to be @@ -382,67 +343,36 @@ SelectIntersect(scx, types, xMask) TileTypeBitMask tMask, rMask; TileType s, t; int plane; + SearchContext scx2; - /* If the source definition is changing, clear the old selection. */ - - if (SelectRootDef != scx->scx_use->cu_def) - { - if (SelectRootDef != NULL) - SelectClear(); - SelectRootDef = scx->scx_use->cu_def; - SelSetDisplay(SelectUse, SelectRootDef); - } + /* The source definition may not change */ + if (SelectRootDef != scx->scx_use->cu_def) return; SelRememberForUndo(TRUE, (CellDef *) NULL, (Rect *) NULL); - /* Select all paint of types in "types" mask and copy into Select2Def */ - + /* Copy SelectDef contents (paint only) into Select2Def */ DBCellClearDef(Select2Def); - (void) DBCellCopyAllPaint(scx, types, xMask, Select2Use); + scx2.scx_use = SelectUse; + scx2.scx_area = SelectUse->cu_bbox; + GeoTransTrans(&GeoIdentityTransform, &SelectUse->cu_transform, &scx2.scx_trans); + DBCellCopyAllPaint(&scx2, &DBAllButSpaceAndDRCBits, CU_DESCEND_NO_LOCK, + Select2Use); - /* Find the first type in the list. This will be used as the reference */ + /* Clear the original selection */ + DBCellClearDef(SelectDef); - for (t = 0; t < DBNumUserLayers; t++) - if (TTMaskHasType(types, t)) - break; - - if (t == DBNumUserLayers) return; - - /* Compute the type mask of the reference type */ - TTMaskSetOnlyType(&tMask, t); + /* Select all paint of type "type" and copy into SelectDef */ + TTMaskSetOnlyType(&tMask, type); plane = DBPlane(t); + (void) DBCellCopyAllPaint(scx, &tMask, xMask, SelectUse); - /* For each other type in "types", do the following */ + /* Scan Select2Def for all geometry inside the area of "type", and */ + /* copy back to SelectDef as "type" */ - for (s = t + 1; s < DBNumUserLayers; s++) - { - if (TTMaskHasType(types, s)) - { - /* Copy the reference paint type from Select2Def into SelectDef */ - DBSrPaintArea((Tile *)NULL, Select2Def->cd_planes[plane], &scx->scx_area, - &tMask, selDupPaintFunc, (ClientData)&tMask); + DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[plane], + &scx->scx_area, &tMask, selIntersectPaintFunc, (ClientData)NULL); - /* Erase the reference paint type from Select2Def */ - DBEraseMask(Select2Def, &TiPlaneRect, &tMask); - - /* Scan Select2Def for all geometry of type s inside the areas of */ - /* the reference type, and copy back to Select2Def as the reference */ - /* type */ - DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[plane], - &scx->scx_area, &tMask, selIntersectPaintFunc, (ClientData)s); - - /* Erase the reference paint type from SelectDef */ - DBEraseMask(SelectDef, &TiPlaneRect, &tMask); - } - } - - /* Copy any remaining paint in the reference layer in Select2Def to */ - /* SelectDef as all the intersection types. */ - - DBSrPaintArea((Tile *)NULL, Select2Def->cd_planes[plane], &scx->scx_area, - &tMask, selDupPaintFunc, (ClientData)types); - - SelectDef->cd_types = *types; /* Remember what types were requested */ + DBEraseMask(SelectDef, &TiPlaneRect, &tMask); /* Display the new selection. */ From f5d8dbc3e5832be59db43237e0e01f32a9da7529 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 24 Mar 2021 19:43:30 -0400 Subject: [PATCH 50/89] Corrected an error in the last commit's implementation of the "what" command. --- commands/CmdTZ.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/commands/CmdTZ.c b/commands/CmdTZ.c index 26b8fb50..489a0652 100644 --- a/commands/CmdTZ.c +++ b/commands/CmdTZ.c @@ -1007,7 +1007,7 @@ CmdWhat(w, cmd) EditCellUse = CheckUse; - TxPrintf("Selected mask layers:\n"); + if (!doListAll) TxPrintf("Selected mask layers:\n"); for (i = TT_SELECTBASE; i < DBNumUserLayers; i++) { if (TTMaskHasType(&layers, i)) @@ -1044,9 +1044,6 @@ CmdWhat(w, cmd) for (lidp = lid; lidp; lidp = lidp->lid_next) Tcl_ListObjAppendElement(magicinterp, paintcellobj, Tcl_NewStringObj(lidp->lid_name, -1)); - - Tcl_ListObjAppendElement(magicinterp, paintobj, - paintcellobj); } while (lid != NULL) @@ -1057,6 +1054,9 @@ CmdWhat(w, cmd) } } EditCellUse = saveUse; + if (doListAll) + Tcl_ListObjAppendElement(magicinterp, paintobj, paintcellobj); + } else { From 2d1cf8435a6e72c18031064911f5ef789752d6fd Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 24 Mar 2021 20:20:55 -0400 Subject: [PATCH 51/89] Corrected the list produced by "what -listall" to have the intended nesting. Corrected the "select visible" command, which got broken during the modifications. --- commands/CmdRS.c | 3 +-- commands/CmdTZ.c | 20 ++++++++++++-------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/commands/CmdRS.c b/commands/CmdRS.c index 370380d9..992987c0 100644 --- a/commands/CmdRS.c +++ b/commands/CmdRS.c @@ -633,8 +633,7 @@ cmdSelectArea(layers, less, option) TTMaskClearType(&mask, i); } } - else - SelectArea(&scx, &mask, crec->dbw_bitmask); + SelectArea(&scx, &mask, crec->dbw_bitmask); } /* diff --git a/commands/CmdTZ.c b/commands/CmdTZ.c index 489a0652..7c0395b3 100644 --- a/commands/CmdTZ.c +++ b/commands/CmdTZ.c @@ -913,7 +913,7 @@ CmdWhat(w, cmd) CellUse *CheckUse; #ifdef MAGIC_WRAPPER - Tcl_Obj *lobj, *paintobj, *paintcellobj, *labelobj, *cellobj; + Tcl_Obj *lobj, *paintobj, *paintcellobj, *celllistobj, *labelobj, *cellobj; extern int cmdWhatCellListFunc(); #endif @@ -928,10 +928,7 @@ CmdWhat(w, cmd) if (!strncmp(cmd->tx_argv[locargc - 1], "-list", 5)) { if (!strncmp(cmd->tx_argv[locargc - 1], "-listall", 8)) - { doListAll = TRUE; - paintcellobj = Tcl_NewListObj(0, NULL); - } else doList = TRUE; locargc--; @@ -1015,6 +1012,8 @@ CmdWhat(w, cmd) TTMaskSetOnlyType(&maskBits, i); if (DBIsContact(i)) DBMaskAddStacking(&maskBits); + if (doListAll) paintcellobj = Tcl_NewListObj(0, NULL); + /* Search selection for tiles of this type, then */ /* call cmdFindWhatTileFunc() to search the cell */ /* def in the area of that tile to determine what */ @@ -1038,12 +1037,16 @@ CmdWhat(w, cmd) } else { - Tcl_ListObjAppendElement(magicinterp, paintobj, + Tcl_ListObjAppendElement(magicinterp, paintcellobj, Tcl_NewStringObj(DBTypeLongName(i), -1)); + celllistobj = Tcl_NewListObj(0, NULL); for (lidp = lid; lidp; lidp = lidp->lid_next) - Tcl_ListObjAppendElement(magicinterp, paintcellobj, + Tcl_ListObjAppendElement(magicinterp, celllistobj, Tcl_NewStringObj(lidp->lid_name, -1)); + + Tcl_ListObjAppendElement(magicinterp, paintcellobj, + celllistobj); } while (lid != NULL) @@ -1051,11 +1054,12 @@ CmdWhat(w, cmd) freeMagic(lid); lid = lid->lid_next; } + if (doListAll) + Tcl_ListObjAppendElement(magicinterp, paintobj, + paintcellobj); } } EditCellUse = saveUse; - if (doListAll) - Tcl_ListObjAppendElement(magicinterp, paintobj, paintcellobj); } else From 4964b1f7894405a1cc4f88ce0fdecc103df04a62 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 25 Mar 2021 11:12:41 -0400 Subject: [PATCH 52/89] Created a new command "drop" which can be used to drop a layer into subcells in a hierarchy. The intent is to use this in conjunction with the "select intersect" command option added yesterday to add deep nwell into the cells containing the devices that need it. --- commands/CmdCD.c | 202 +++++++++++++++++++++++++++++++++++++++++++ dbwind/DBWcommands.c | 6 +- 2 files changed, 207 insertions(+), 1 deletion(-) diff --git a/commands/CmdCD.c b/commands/CmdCD.c index db2049f2..5d71580d 100644 --- a/commands/CmdCD.c +++ b/commands/CmdCD.c @@ -3921,6 +3921,208 @@ CmdDrc(w, cmd) return; } +/* + * ---------------------------------------------------------------------------- + * + * cmdDropPaintCell --- + * + * Callback function used by cmdDropFunc. Called for each tile found in + * the edit cell hierarchy that matches paint that was in the selection. + * Paints layers from lMask (clientData) into the subcell containing the + * tile, within the area of the tile. + * + * Returns: + * Always returns zero to keep the search going. + * + * ---------------------------------------------------------------------------- + */ + +int cmdDropPaintCell(tile, cxp) + Tile *tile; + TreeContext *cxp; +{ + CellDef *cellDef = cxp->tc_scx->scx_use->cu_def; + TileTypeBitMask *lMask = (TileTypeBitMask *)cxp->tc_filter->tf_arg; + int pNum; + TileType type; + Rect area; + + if (SplitSide(tile)) + type = SplitRightType(tile); + else + type = SplitLeftType(tile); + pNum = DBPlane(type); + + TiToRect(tile, &area); + + DBPaintMask(cellDef, &area, lMask); + + return 0; +} + +/* + * ---------------------------------------------------------------------------- + * + * cmdDropFunc --- + * + * Callback function used by CmdDrop. Called for each tile found in the + * selection. + * + * Returns: + * Always returns zero to keep the search going. + * + * ---------------------------------------------------------------------------- + */ + +int +cmdDropFunc(Tile *tile, ClientData clientData) +{ + TileTypeBitMask tMask, *lMask = (TileTypeBitMask *)clientData; + SearchContext scx; + TileType type; + + TiToRect(tile, &scx.scx_area); + scx.scx_use = EditCellUse; + scx.scx_trans = GeoIdentityTransform; + + if (SplitSide(tile)) + type = SplitRightType(tile); + else + type = SplitLeftType(tile); + TTMaskSetOnlyType(&tMask, type); + + DBTreeSrTiles(&scx, &tMask, 0, cmdDropPaintCell, (ClientData)lMask); + + return 0; +} + +/* + * ---------------------------------------------------------------------------- + * + * cmdDropPaintFunc -- + * + * Callback function to SelEnumPaint() from CmdDrop(). Sets a bit in + * the type mask passed as clientData for the type of the tile found + * in the selection. + * + * ---------------------------------------------------------------------------- + */ + +int +cmdDropPaintFunc(rect, type, mask) + Rect *rect; /* Not used. */ + TileType type; /* Type of this piece of paint. */ + TileTypeBitMask *mask; /* Place to OR in type's bit. */ +{ + if (type & TT_DIAGONAL) + type = (type & TT_SIDE) ? (type & TT_RIGHTMASK) >> 14 : + (type & TT_LEFTMASK); + TTMaskSetType(mask, type); + return 0; +} + +/* + * ---------------------------------------------------------------------------- + * + * CmdDrop -- + * + * Implement the ":drop" command. + * + * Usage: + * drop + * + * where is a list of paint layers. The command requires an + * existing selection, with the expectation that the selection contains + * paint material that exists in subcells of the current edit cell. The + * "drop" command will copy the types in into every subcell in + * the hierarchy of the current edit cell that contains selected material. + * + * The purpose of this command is to deal with issues arising from layers + * in a vendor GDS file that must be in the same cell as a device layer + * in order for the device to be extracted properly, but instead is placed + * in a cell further up in the hierarchy. A typical example is the deep + * nwell layer, which isolates the transistor bulk terminal from the + * substrate. Without the deep nwell layer in the same cell as the + * transistor, the transistor will be extracted with the bulk terminal + * connected to the substrate. + * + * Note that the act of copying material down into a subcell means that + * material is then present in all instances of the subcell. There is + * no implementation as yet to handle the case where some instances of the + * same subcell require and some don't, which would necessitate + * splitting the subcell into (at least) two different subcells, one + * containing and one not. This needs to be implemented. A + * possible implementation would be: 1st pass: Find all subcells that + * will be modified. Make a list of the instances that will be modified. + * After the first pass, check if the list of instances contains all + * instances of the cell def. If so, then just modify the cell def. If + * not, then make a copy the cell def and split off the instances that + * get the modification to point to that cell def, then modify that cell + * def. 2nd pass: Run the "drop" command as before. + * + * Results: + * None. + * + * Side effects: + * Subcells are modified by adding paint. + * + * ---------------------------------------------------------------------------- + */ + +void +CmdDrop(w, cmd) + MagWindow *w; + TxCommand *cmd; +{ + TileType i; + TileTypeBitMask lMask, tMask; + CellUse *checkUse; + int pNum; + + if (cmd->tx_argc != 2) + { + TxError("Usage: %s layers\n", cmd->tx_argv[0]); + return; + } + + if (!ToolGetEditBox((Rect *)NULL)) return; + if (!CmdParseLayers(cmd->tx_argv[1], &lMask)) + return; + + checkUse = NULL; + if (EditRootDef == SelectRootDef) + checkUse = EditCellUse; + if (checkUse == NULL) + { + if (w == (MagWindow *)NULL) + windCheckOnlyWindow(&w, DBWclientID); + if (w) checkUse = (CellUse *)w->w_surfaceID; + } + if ((checkUse == NULL) || (checkUse->cu_def != SelectRootDef)) + { + TxError("The selection does not match the edit cell.\n"); + return; + } + + TTMaskZero(&tMask); + SelEnumPaint(&DBAllButSpaceAndDRCBits, FALSE, (bool *)NULL, + cmdDropPaintFunc, (ClientData)&tMask); + + if (TTMaskIsZero(&tMask)) return; /* Nothing selected */ + + for (i = TT_SELECTBASE; i < DBNumUserLayers; i++) + { + if (TTMaskHasType(&tMask, i)) + { + for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) + if (TTMaskHasType(&DBPlaneTypes[pNum], i)) + DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[pNum], + &SelectUse->cu_bbox, &tMask, + cmdDropFunc, (ClientData)&lMask); + } + } +} + /* * ---------------------------------------------------------------------------- * diff --git a/dbwind/DBWcommands.c b/dbwind/DBWcommands.c index 1392f5e4..0515c402 100644 --- a/dbwind/DBWcommands.c +++ b/dbwind/DBWcommands.c @@ -42,7 +42,7 @@ extern void CmdAddPath(), CmdAntennaCheck(), CmdArray(); extern void CmdBox(), CmdCellname(), CmdClockwise(); extern void CmdContact(), CmdCopy(), CmdCorner(); extern void CmdCrash(), CmdCrosshair(); -extern void CmdDelete(), CmdDown(), CmdDrc(), CmdDump(); +extern void CmdDelete(), CmdDown(), CmdDrc(), CmdDrop(), CmdDump(); extern void CmdEdit(), CmdElement(), CmdErase(), CmdExpand(), CmdExtract(); extern void CmdFeedback(), CmdFill(), CmdFindBox(), CmdFindLabel(), CmdFlush(); extern void CmdGetcell(), CmdGrid(), CmdIdentify(); @@ -278,6 +278,10 @@ DBWInitCommands() "drc option design rule checker; type \"drc help\"\n" " for information on options", CmdDrc, FALSE); + WindAddCommand(DBWclientID, + "drop layers copy layers from edit cell into\n" + " subcells containing selected paint", + CmdDrop, FALSE); WindAddCommand(DBWclientID, "dump cell [child refPointC] [parent refPointP]\n\ copy contents of cell into edit cell, so that\n\ From f3febfae73c22654142a554a05b18daf4dc42a1d Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 25 Mar 2021 11:17:27 -0400 Subject: [PATCH 53/89] Updated VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 3ac1f0f1..415897e6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.148 +8.3.149 From 2cc557532dfd6aae1a1384c160f270b22eff9a41 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 25 Mar 2021 14:39:29 -0400 Subject: [PATCH 54/89] Modified the "flatten" command so that ports of the topmost cell are preserved, which seems like reasonable behavior. --- commands/CmdFI.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/commands/CmdFI.c b/commands/CmdFI.c index 17f30ff9..80bdd153 100644 --- a/commands/CmdFI.c +++ b/commands/CmdFI.c @@ -1865,6 +1865,7 @@ flatCopyAllLabels(scx, lab, tpath, targetUse) { Rect labTargetRect; int targetPos; + int flags = 0; CellDef *def; char labelname[1024]; char *n, *f, c; @@ -1894,6 +1895,8 @@ flatCopyAllLabels(scx, lab, tpath, targetUse) * not a port; possibly we should retain ports taken from the * top level cell, but certainly not any others. */ + if (tpath && (*tpath->tp_first) == '\0') + flags = lab->lab_flags; /* To-do Feb. 2008: Translate target rotation and offset */ @@ -1903,7 +1906,7 @@ flatCopyAllLabels(scx, lab, tpath, targetUse) strcpy(n, lab->lab_text); DBPutFontLabel(def, &labTargetRect, lab->lab_font, lab->lab_size, lab->lab_rotate, &lab->lab_offset, targetPos, - f, lab->lab_type, 0); + f, lab->lab_type, flags); *n = c; return 0; @@ -1932,7 +1935,7 @@ CmdFlatten(w, cmd) TxCommand *cmd; { int rval, xMask; - bool dolabels, dobox, toplabels, invert; + bool dolabels, dobox, toplabels, invert, doports; char *destname; CellDef *newdef; CellUse *newuse; @@ -1944,6 +1947,7 @@ CmdFlatten(w, cmd) dolabels = TRUE; toplabels = FALSE; dobox = FALSE; + doports = TRUE; rval = 0; if (cmd->tx_argc > 2) @@ -1978,6 +1982,9 @@ CmdFlatten(w, cmd) case 't': toplabels = (invert) ? FALSE : TRUE; break; + case 'p': + doports = (invert) ? FALSE : TRUE; + break; case 's': xMask = (invert) ? CU_DESCEND_NO_SUBCKT : CU_DESCEND_ALL; break; @@ -1985,7 +1992,7 @@ CmdFlatten(w, cmd) xMask = (invert) ? CU_DESCEND_NO_VENDOR : CU_DESCEND_ALL; break; default: - TxError("options are: -nolabels, -nosubcircuits " + TxError("options are: -nolabels, -nosubcircuits, -noports, " "-novendor, -dotoplabels, -dobox\n"); break; } From 9656c86b967029085b8db8704a07f3ea493402cf Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 25 Mar 2021 15:35:37 -0400 Subject: [PATCH 55/89] Added a negation capability to the "select intersect" command, so that the intersection of (A and-not B) can be found. This and the (A and B) version give a large amount of capability like the cifoutput operators available as command-line commands. Also: Fixed the new "drop" command so that it properly redisplays and runs DRC after executing, and modified the behavior so that the dropped material is clipped to the area of the selection. --- commands/CmdCD.c | 10 +++++++++- commands/CmdRS.c | 21 +++++++++++++++++++-- select/selCreate.c | 13 +++++++++++-- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/commands/CmdCD.c b/commands/CmdCD.c index 5d71580d..2eec220e 100644 --- a/commands/CmdCD.c +++ b/commands/CmdCD.c @@ -3955,6 +3955,9 @@ int cmdDropPaintCell(tile, cxp) TiToRect(tile, &area); + /* Clip to search area */ + GEOCLIP(&area, &cxp->tc_scx->scx_area); + DBPaintMask(cellDef, &area, lMask); return 0; @@ -4078,6 +4081,7 @@ CmdDrop(w, cmd) TileTypeBitMask lMask, tMask; CellUse *checkUse; int pNum; + Rect editBox; if (cmd->tx_argc != 2) { @@ -4085,7 +4089,7 @@ CmdDrop(w, cmd) return; } - if (!ToolGetEditBox((Rect *)NULL)) return; + if (!ToolGetEditBox(&editBox)) return; if (!CmdParseLayers(cmd->tx_argv[1], &lMask)) return; @@ -4121,6 +4125,10 @@ CmdDrop(w, cmd) cmdDropFunc, (ClientData)&lMask); } } + + DRCCheckThis(EditCellUse->cu_def, TT_CHECKPAINT, &editBox); + DBWAreaChanged(EditCellUse->cu_def, &editBox, DBW_ALLWINDOWS, &tMask); + DBReComputeBbox(EditCellUse->cu_def); } /* diff --git a/commands/CmdRS.c b/commands/CmdRS.c index 992987c0..86fc0760 100644 --- a/commands/CmdRS.c +++ b/commands/CmdRS.c @@ -663,6 +663,8 @@ cmdIntersectArea(layer) int windowMask, xMask; DBWclientRec *crec; MagWindow *window; + char *lptr; + bool negate = FALSE; bzero(&scx, sizeof(SearchContext)); window = ToolGetBoxWindow(&scx.scx_area, &windowMask); @@ -694,8 +696,23 @@ cmdIntersectArea(layer) scx.scx_use = (CellUse *) window->w_surfaceID; scx.scx_trans = GeoIdentityTransform; crec = (DBWclientRec *) window->w_clientData; - ttype = DBTechNoisyNameType(layer); - SelectIntersect(&scx, ttype, crec->dbw_bitmask); + + /* Special behavior: "!" or "~" in front of layer name intersects */ + /* with NOT(layer). */ + + lptr = layer; + if ((*lptr == '~') || (*lptr == '!')) + { + negate = TRUE; + lptr++; + } + + ttype = DBTechNameType(lptr); + if (ttype < 0) { + TxError("Cannot parse layer type \"%s\".\n", layer); + return; + } + SelectIntersect(&scx, ttype, crec->dbw_bitmask, negate); } /* diff --git a/select/selCreate.c b/select/selCreate.c index ebb92793..4a7124a2 100644 --- a/select/selCreate.c +++ b/select/selCreate.c @@ -324,7 +324,7 @@ selIntersectPaintFunc(tile) */ void -SelectIntersect(scx, type, xMask) +SelectIntersect(scx, type, xMask, negate) SearchContext *scx; /* Describes the area in which material * is to be selected. The resulting * coordinates should map to the coordinates @@ -339,6 +339,7 @@ SelectIntersect(scx, type, xMask) * considered. 0 means treat everything as * expanded. */ + bool negate; /* If true, search on NOT(type) */ { TileTypeBitMask tMask, rMask; TileType s, t; @@ -363,15 +364,23 @@ SelectIntersect(scx, type, xMask) /* Select all paint of type "type" and copy into SelectDef */ TTMaskSetOnlyType(&tMask, type); - plane = DBPlane(t); + + plane = DBPlane(type); (void) DBCellCopyAllPaint(scx, &tMask, xMask, SelectUse); /* Scan Select2Def for all geometry inside the area of "type", and */ /* copy back to SelectDef as "type" */ + if (negate) + { + TTMaskCom(&tMask); + TTMaskAndMask(&tMask, &DBPlaneTypes[plane]); + } DBSrPaintArea((Tile *)NULL, SelectDef->cd_planes[plane], &scx->scx_area, &tMask, selIntersectPaintFunc, (ClientData)NULL); + if (negate) TTMaskSetOnlyType(&tMask, type); /* Restore original mask */ + DBEraseMask(SelectDef, &TiPlaneRect, &tMask); /* Display the new selection. */ From 187c9285e2dc3cf6b2a5c8c3553574f73977d251 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 29 Mar 2021 11:44:39 -0400 Subject: [PATCH 56/89] Extended the "port" command with option "-quiet" to suppress error output when using the "port ... index" or "port ... name" to query values from a specific port by name or index. The "readspice" script has been modified to use this option to prevent unnecessary error output from the script as it searches a layout for possible name matches to a SPICE netlist subcircuit pin list. --- commands/CmdLQ.c | 28 ++++++++++++++++++++++------ tcltk/readspice.tcl | 12 ++++++------ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/commands/CmdLQ.c b/commands/CmdLQ.c index 20045d85..c16eac0d 100644 --- a/commands/CmdLQ.c +++ b/commands/CmdLQ.c @@ -1312,7 +1312,7 @@ complabel(const void *one, const void *two) * or * port makeall|renumber [connect_direction(s)] * or - * port [name|num] class|use|shape|index [value] + * port [name|num] class|use|shape|index|name [value] [-quiet] * * num is the index of the port, usually beginning with 1. This indicates * the order in which ports should be written to a subcircuit record @@ -1330,6 +1330,9 @@ complabel(const void *one, const void *two) * "value" is a value string representing one of the valid port classes * or uses. * + * The "-quiet" option causes magic to fail quietly and return (in Tcl) + * an empty string if the value requested does not exist. + * * Results: * None. * @@ -1366,7 +1369,7 @@ CmdPort(w, cmd) int i, refidx, idx, pos, type, option, argc; unsigned int dirmask; bool found; - bool nonEdit = FALSE; + bool nonEdit = FALSE, doQuiet = FALSE; Label *lab, *sl; Rect editBox, tmpArea; CellDef *editDef = EditCellUse->cu_def; @@ -1461,6 +1464,16 @@ CmdPort(w, cmd) argstart = 1; argc = cmd->tx_argc; + + if (argc > 1) + { + if (!strcmp(cmd->tx_argv[argc - 1], "-quiet")) + { + doQuiet = TRUE; + argc--; + } + } + if (argc > 6 || argc == 1) goto portWrongNumArgs; else @@ -1501,7 +1514,7 @@ CmdPort(w, cmd) break; } } - if (lab == NULL) + if ((lab == NULL) & (!doQuiet)) { if (StrIsInt(cmd->tx_argv[1])) TxError("No label found with index %s.\n", cmd->tx_argv[1]); @@ -1574,7 +1587,7 @@ CmdPort(w, cmd) /* label "lab" must already be a port */ if (!(lab->lab_flags & PORT_DIR_MASK)) { - if (option != PORT_REMOVE) + if ((option != PORT_REMOVE) && (!doQuiet)) TxError("The selected label is not a port.\n"); return; } @@ -1966,8 +1979,11 @@ parseindex: if ((option != PORT_MAKEALL) && (lab->lab_flags & PORT_DIR_MASK)) { /* For this syntax, the label must not already be a port */ - TxError("The selected label is already a port.\n"); - TxError("Do \"port help\" to get a list of options.\n"); + if (!doQuiet) + { + TxError("The selected label is already a port.\n"); + TxError("Do \"port help\" to get a list of options.\n"); + } return; } diff --git a/tcltk/readspice.tcl b/tcltk/readspice.tcl index 18902782..b2390dc2 100644 --- a/tcltk/readspice.tcl +++ b/tcltk/readspice.tcl @@ -123,7 +123,7 @@ proc readspice {netfile} { break } set p1 [port $p next] - set testpin [port $p name] + set testpin [port $p name -quiet] if {$testpin != ""} { port $p index $outport incr outport @@ -157,15 +157,15 @@ proc readspice {netfile} { # a port. set testpin $pin - set pinidx [port $testpin index] + set pinidx [port $testpin index -quiet] if {$pinidx == ""} { set testpin [string map {\[ < \] >]} $pin] - set pinidx [port $testpin index] + set pinidx [port $testpin index -quiet] } if {$pinidx == ""} { set testpin [string map {< \[ > \]} $pin] - set pinidx [port $testpin index] + set pinidx [port $testpin index -quiet] } # Handle issues with case insensitivity by getting @@ -174,9 +174,9 @@ proc readspice {netfile} { if {$pinidx == ""} { set highport [port last] for {set p 0} {$p <= $highport} {incr p} { - set testpin [port $p name] + set testpin [port $p name -quiet] if {[string tolower $testpin] == [string tolower $pin]} { - set pinidx [port $testpin index] + set pinidx [port $testpin index -quiet] break } } From fcdce0553d14fc8d2502033c474812d8e25a90ce Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 29 Mar 2021 11:54:47 -0400 Subject: [PATCH 57/89] Corrected an error in the previous commit, and updated the version number. --- VERSION | 2 +- commands/CmdLQ.c | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/VERSION b/VERSION index 415897e6..6bd04953 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.149 +8.3.150 diff --git a/commands/CmdLQ.c b/commands/CmdLQ.c index c16eac0d..26e1f225 100644 --- a/commands/CmdLQ.c +++ b/commands/CmdLQ.c @@ -1514,12 +1514,15 @@ CmdPort(w, cmd) break; } } - if ((lab == NULL) & (!doQuiet)) + if (lab == NULL) { - if (StrIsInt(cmd->tx_argv[1])) - TxError("No label found with index %s.\n", cmd->tx_argv[1]); - else - TxError("No port found with name %s.\n", cmd->tx_argv[1]); + if (!doQuiet) + { + if (StrIsInt(cmd->tx_argv[1])) + TxError("No label found with index %s.\n", cmd->tx_argv[1]); + else + TxError("No port found with name %s.\n", cmd->tx_argv[1]); + } return; } argstart = 2; From 8f8c3f77f2d364a74f7649b541ca5297f29bffa8 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 1 Apr 2021 12:31:46 -0400 Subject: [PATCH 58/89] Got rid of the annoying behavior of "popstack" to not return to the original view position; this was due to not setting units to internal before re-applying the previous view position. Also wrapped most of the "popstack" routine into a suspendall...resumeall block so that the view is refreshed only once; this is especially important when popping back into a full chip view. --- VERSION | 2 +- tcltk/tools.tcl | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index 6bd04953..dd2f76b4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.150 +8.3.151 diff --git a/tcltk/tools.tcl b/tcltk/tools.tcl index 538cfc01..878f7d37 100644 --- a/tcltk/tools.tcl +++ b/tcltk/tools.tcl @@ -156,12 +156,17 @@ proc magic::popstack {} { } else { set ltag [tag load] tag load {} + suspendall load [lindex $editstack end] + set snaptype [snap] + snap internal view [lindex $editstack end-1] - tag load $ltag - set editstack [lrange $editstack 0 end-2] + snap $snaptype catch {magic::cellmanager} catch {magic::captions} + resumeall + tag load $ltag + set editstack [lrange $editstack 0 end-2] } return } From 8b9c47c3efe9e507c9f32bccd393bf2efd1fa8ed Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 1 Apr 2021 13:09:08 -0400 Subject: [PATCH 59/89] Removed the stupid restriction that "cellname readwrite" won't work on a non-writeable cell. While technically valid, that just means that nobody can make temporary edits on the cell in memory, which is useful in many applications. A slight quirk of the "cellname" command is that if applied to the cell currently in the layout window, it is not possible to make the cell show as edited and editable until leaving and re-entering the cell. --- commands/CmdCD.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/commands/CmdCD.c b/commands/CmdCD.c index 2eec220e..bb779d87 100644 --- a/commands/CmdCD.c +++ b/commands/CmdCD.c @@ -1084,13 +1084,11 @@ CmdCellname(w, cmd) if (cellDef->cd_fd == -1) dbReadOpen(cellDef, NULL, TRUE, NULL); - if (cellDef->cd_fd != -1) - cellDef->cd_flags &= ~CDNOEDIT; - else - TxError("Advisory lock held on cell %s\n", cellDef->cd_name); -#else - cellDef->cd_flags &= ~CDNOEDIT; + if (cellDef->cd_fd == -1) + TxError("Warning: Cell %s is not writeable\n", cellDef->cd_name); #endif + + cellDef->cd_flags &= ~CDNOEDIT; WindAreaChanged(w, &w->w_screenArea); CmdSetWindCaption(EditCellUse, EditRootDef); } From a2f7831b17752f518a806d316e1622e71177699d Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 1 Apr 2021 17:38:00 -0400 Subject: [PATCH 60/89] First pass at properly handling deep nwell in a parent cell under subcells that do not have deep nwell. This commit handles the case where the pwell region is explicitly marked with a layer type. To do: Handle the case where the pwell region is implicit. --- extract/ExtHier.c | 76 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/extract/ExtHier.c b/extract/ExtHier.c index 73fa39e6..1426abec 100644 --- a/extract/ExtHier.c +++ b/extract/ExtHier.c @@ -60,16 +60,34 @@ int extHierConnectFunc2(); int extHierConnectFunc3(); Node *extHierNewNode(); +/*----------------------------------------------------------------------*/ +/* extHierSubShieldFunc -- */ +/* */ +/* Simple callback function for extHierSubstrate() that halts the */ +/* search if any substrate shield type is found in the search area */ +/* */ +/*----------------------------------------------------------------------*/ -/*----------------------------------------------*/ -/* extHierSubstrate */ -/* */ -/* Find the substrate node of a child cell and */ -/* make a connection between parent and child */ -/* substrates. If either of the substrate */ -/* nodes is already in the hash table, then the */ -/* table will be updated as necessary. */ -/*----------------------------------------------*/ +int +extHierSubShieldFunc(tile) + Tile *tile; +{ + return 1; +} + +/*----------------------------------------------------------------------*/ +/* extHierSubstrate -- */ +/* */ +/* Find the substrate node of a child cell and make a connection */ +/* between parent and child substrates. If either of the */ +/* substrate nodes is already in the hash table, then the table */ +/* will be updated as necessary. */ +/* */ +/* This function also determines if a child cell's substrate is */ +/* isolated by a substrate shield type, in which case no merge is */ +/* done. */ +/* */ +/*----------------------------------------------------------------------*/ void extHierSubstrate(ha, use, x, y) @@ -84,6 +102,8 @@ extHierSubstrate(ha, use, x, y) Node *node1, *node2; char *name1, *name2, *childname; CellDef *def; + Rect subArea; + int pNum; NodeRegion *extFindNodes(); @@ -107,6 +127,44 @@ extHierSubstrate(ha, use, x, y) /* Find the child's substrate node */ nodeList = extFindNodes(use->cu_def, (Rect *) NULL, TRUE); + if (nodeList == NULL) return; + + /* Check if the child's substrate node is covered by any substrate */ + /* shield type (e.g., deep nwell). This is a stupid-simple check */ + /* on the node's lower left point. This will fail if (1) only */ + /* space exists on the substrate plane in the child cell, or (2) if */ + /* some but not all devices in the child are covered by a shield */ + /* type. Item (1) is handled by checking if the region point is */ + /* outside the cell bound and using the cell bound as the search */ + /* area if so. However, it really should look for a device in the */ + /* subcell that connects to the substrate. Item (2) is up to the */ + /* designer to avoid (but should be flagged as an extraction */ + /* error). */ + + if (GEO_ENCLOSE(&nodeList->nreg_ll, &use->cu_def->cd_bbox)) + { + GeoTransPoint(&use->cu_transform, &nodeList->nreg_ll, &subArea.r_ll); + subArea.r_ur.p_x = subArea.r_ll.p_x + 1; + subArea.r_ur.p_y = subArea.r_ll.p_y + 1; + } + else + subArea = ha->ha_subArea; + + for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++) + { + if (TTMaskIntersect(&DBPlaneTypes[pNum], + &ExtCurStyle->exts_globSubstrateShieldTypes)) + { + if (DBSrPaintArea((Tile *) NULL, + def->cd_planes[pNum], &subArea, + &ExtCurStyle->exts_globSubstrateShieldTypes, + extHierSubShieldFunc, (ClientData)NULL) != 0) + { + freeMagic(nodeList); + return; + } + } + } /* Make sure substrate labels are represented */ ExtLabelRegions(use->cu_def, ExtCurStyle->exts_nodeConn, &nodeList, From 75e4fbe5ad479eafc1ab946851696bb42c5bfc1a Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sun, 4 Apr 2021 20:43:43 -0400 Subject: [PATCH 61/89] Tests of substrate extraction --- database/DBcellcopy.c | 242 +++++++++++++++++++++++++++++++++++++++++ database/database.h.in | 2 + extract/ExtHard.c | 3 + extract/ExtRegion.c | 63 +++++++++++ extract/ExtSubtree.c | 116 +++++++++++++++++--- extract/extractInt.h | 1 + 6 files changed, 414 insertions(+), 13 deletions(-) diff --git a/database/DBcellcopy.c b/database/DBcellcopy.c index 8362240b..722a7b3b 100644 --- a/database/DBcellcopy.c +++ b/database/DBcellcopy.c @@ -342,6 +342,248 @@ DBCellCheckCopyAllPaint(scx, mask, xMask, targetUse, func) DBTreeSrTiles(scx, &locMask, xMask, dbCopyAllPaint, (ClientData) &arg); } +/* Client data structure used by DBCellCopySubstrate() */ + +struct dbCopySubData { + Plane *csd_plane; + TileType csd_subtype; + int csd_pNum; + bool csd_modified; +}; + +/* + *----------------------------------------------------------------------------- + * + * DBCellCopySubstrate -- + * + * This function is used by the extraction code in ExtSubtree.c. + * Paint substrate into the target use. Similar to DBCellCopyAllPaint(), + * but it finds space tiles on the substrate plane and converts them to + * a substrate type in the target, clipped to the cell boundary. This + * allows the extraction to find and record all substrate regions, both + * common (global substrate) and local (isolated substrate), without + * requiring a physical substrate type to be drawn into all cells. + * + * Unlike normal paint copying, this can only be done by painting the + * substrate type over the entire cell area and then erasing all areas + * belonging to not-substrate types in the source. + * + * Returns: + * Nothing. + * + * Side Effects: + * Paints into the targetUse's CellDef. This only happens if two + * conditions are met: + * (1) The techfile has defined "substrate" + * (2) The techfile defines a type corresponding to the substrate + * + * ---------------------------------------------------------------------------- + */ + +void +DBCellCopySubstrate(scx, subType, notSubMask, targetUse) + SearchContext *scx; + TileType subType; /* Substrate paint type */ + TileTypeBitMask *notSubMask; /* Mask of types that are not substrate */ + CellUse *targetUse; +{ + struct dbCopySubData csd; + Plane *tempPlane; + int plane; + Rect rect; + int dbEraseNonSub(); + int dbCopySubFunc(); + + GEOTRANSRECT(&scx->scx_trans, &scx->scx_area, &rect); + + /* Clip to bounding box of the top level cell */ + GEOCLIP(&rect, &scx->scx_use->cu_def->cd_bbox); + + plane = DBPlane(subType); + + tempPlane = DBNewPlane((ClientData) TT_SPACE); + DBClearPaintPlane(tempPlane); + + /* First paint the substrate type in the temporary plane over the whole cell area */ + DBPaintPlane(tempPlane, &rect, DBStdPaintTbl(subType, plane), + (PaintUndoInfo *)NULL); + + csd.csd_subtype = subType; + csd.csd_plane = tempPlane; + csd.csd_pNum = plane; + + /* Now erase all areas that are non-substrate types in the source */ + /* Note: xMask is always zero, as this is only called from extract routines */ + DBTreeSrTiles(scx, notSubMask, 0, dbEraseNonSub, (ClientData)&csd); + + /* Finally, copy the temp plane contents into the destination */ + csd.csd_plane = targetUse->cu_def->cd_planes[plane]; + DBSrPaintArea((Tile *)NULL, tempPlane, &TiPlaneRect, + &DBAllButSpaceBits, dbCopySubFunc, (ClientData)&csd); + + /* Clean up by removing the temp plane */ + DBFreePaintPlane(tempPlane); + TiFreePlane(tempPlane); +} + +/* Create a canonical substrate. Return the modified plane */ + +Plane * +DBCellCanonicalSubstrate(scx, subType, notSubMask, subShieldMask, targetUse) + SearchContext *scx; + TileType subType; /* Substrate paint type */ + TileTypeBitMask *notSubMask; /* Mask of types that are not substrate */ + TileTypeBitMask *subShieldMask; /* Mask of types that shield substrate */ + CellUse *targetUse; +{ + struct dbCopySubData csd; + Plane *tempPlane; + int plane; + Rect rect; + int dbPaintSubFunc(); + int dbEraseNonSub(); + int dbCopySubFunc(); + + GEOTRANSRECT(&scx->scx_trans, &scx->scx_area, &rect); + + /* Clip to bounding box of the top level cell */ + GEOCLIP(&rect, &scx->scx_use->cu_def->cd_bbox); + + plane = DBPlane(subType); + + tempPlane = DBNewPlane((ClientData) TT_SPACE); + DBClearPaintPlane(tempPlane); + + csd.csd_subtype = subType; + csd.csd_plane = tempPlane; + csd.csd_pNum = plane; + csd.csd_modified = FALSE; + + /* First paint the substrate type in the temporary plane over the */ + /* area of all substrate shield types. */ + /* Note: xMask is always zero, as this is only called from extract routines */ + DBTreeSrTiles(scx, subShieldMask, 0, dbPaintSubFunc, (ClientData)&csd); + if (csd.csd_modified == FALSE) return NULL; + + /* Now erase all areas that are non-substrate types in the source */ + DBTreeSrTiles(scx, notSubMask, 0, dbEraseNonSub, (ClientData)&csd); + + /* Finally, copy the destination plane contents onto tempPlane */ + DBSrPaintArea((Tile *)NULL, targetUse->cu_def->cd_planes[plane], &TiPlaneRect, + &DBAllButSpaceBits, dbCopySubFunc, (ClientData)&csd); + + return tempPlane; +} + +/* + * Callback function for DBCellCopySubstrate() + * Finds tiles on the substrate plane in the source def that are not the + * substrate type, and erases those areas from the target. + */ + +int +dbEraseNonSub(tile, cxp) + Tile *tile; /* Pointer to tile to erase from target */ + TreeContext *cxp; /* Context from DBTreeSrTiles */ +{ + SearchContext *scx; + Rect sourceRect, targetRect; + Plane *plane; /* Plane of target data */ + TileType type, loctype, subType; + struct dbCopySubData *csd; + int pNum; + + csd = (struct dbCopySubData *)cxp->tc_filter->tf_arg; + plane = csd->csd_plane; + subType = csd->csd_subtype; + pNum = csd->csd_pNum; + + scx = cxp->tc_scx; + + type = TiGetTypeExact(tile); + if (IsSplit(tile)) + { + loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile); + if (loctype == TT_SPACE) return 0; + } + else + loctype = type; + + /* Construct the rect for the tile */ + TITORECT(tile, &sourceRect); + + /* Transform to target coordinates */ + GEOTRANSRECT(&scx->scx_trans, &sourceRect, &targetRect); + + /* Erase the substrate type from the area of this tile in the target plane. */ + return DBNMPaintPlane(plane, loctype, &targetRect, DBStdEraseTbl(subType, pNum), + (PaintUndoInfo *)NULL); +} + +/* + * Callback function for DBCellCopySubstrate() + * Simple paint function to copy substrate paint from a temporary plane into + * a target plane. + */ + +int +dbCopySubFunc(tile, csd) + Tile *tile; /* Pointer to tile to erase from target */ + struct dbCopySubData *csd; /* Client data */ +{ + Rect rect; + int pNum; + TileType type, loctype; + Plane *plane; + + plane = csd->csd_plane; + pNum = csd->csd_pNum; + type = TiGetTypeExact(tile); + if (IsSplit(tile)) + { + loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile); + if (loctype == TT_SPACE) return 0; + } + else + loctype = type; + + /* Construct the rect for the tile */ + TITORECT(tile, &rect); + + return DBNMPaintPlane(plane, type, &rect, DBStdPaintTbl(loctype, pNum), + (PaintUndoInfo *)NULL); +} + +int +dbPaintSubFunc(tile, cxp) + Tile *tile; /* Pointer to source tile with shield type */ + TreeContext *cxp; /* Context from DBTreeSrTiles */ +{ + Rect rect; + int pNum; + TileType type, loctype, subType; + Plane *plane; + struct dbCopySubData *csd; /* Client data */ + + csd = (struct dbCopySubData *)cxp->tc_filter->tf_arg; + plane = csd->csd_plane; + pNum = csd->csd_pNum; + subType = csd->csd_subtype; + type = TiGetTypeExact(tile); + if (IsSplit(tile)) + { + loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile); + if (loctype == TT_SPACE) return 0; + } + + /* Construct the rect for the tile */ + TITORECT(tile, &rect); + csd->csd_modified = TRUE; + + return DBNMPaintPlane(plane, type, &rect, DBStdPaintTbl(subType, pNum), + (PaintUndoInfo *)NULL); +} + /* *----------------------------------------------------------------------------- * diff --git a/database/database.h.in b/database/database.h.in index a8c88e57..b544cbae 100644 --- a/database/database.h.in +++ b/database/database.h.in @@ -819,6 +819,8 @@ extern char *DBPrintUseId(); extern void DBCellCopyPaint(); extern void DBCellCopyAllPaint(); extern void DBCellCheckCopyAllPaint(); +extern void DBCellCopySubstrate(); +extern Plane *DBCellCanonicalSubstrate(); extern void DBCellCopyLabels(); extern void DBCellCopyAllLabels(); extern void DBCellCopyCells(); diff --git a/extract/ExtHard.c b/extract/ExtHard.c index 1cd48c57..f938dedf 100644 --- a/extract/ExtHard.c +++ b/extract/ExtHard.c @@ -484,7 +484,10 @@ extHardFreeAll(def, tReg) /* Free all LabelLists and then the region */ for (ll = reg->treg_labels; ll; ll = ll->ll_next) + { + if (ll->ll_label->lab_flags & LABEL_GENERATE) freeMagic(ll->ll_label); freeMagic((char *) ll); + } freeMagic((char *) reg); } } diff --git a/extract/ExtRegion.c b/extract/ExtRegion.c index 658d272c..17c5c43c 100644 --- a/extract/ExtRegion.c +++ b/extract/ExtRegion.c @@ -127,6 +127,69 @@ ExtFindRegions(def, area, mask, connectsTo, uninit, first, each) return (arg.fra_region); } +/* + * ---------------------------------------------------------------------------- + * ExtFindSubstrateRegions -- + * + * This is a subset of ExtFindRegions that looks only at the substrate + * plane. It is called on the first pass, when only the parent paint + * has been added to the cumulative def. + * + * ---------------------------------------------------------------------------- + */ + +Region * +ExtFindSubstrateRegions(def, area, mask, connectsTo, uninit, first, each) + CellDef *def; /* Cell definition being searched */ + Rect *area; /* Area to search initially for tiles */ + TileTypeBitMask *mask; /* In the initial area search, only visit + * tiles whose types are in this mask. + */ + TileTypeBitMask *connectsTo;/* Connectivity table for determining regions. + * If t1 and t2 are the types of adjacent + * tiles, then t1 and t2 belong to the same + * region iff: + * TTMaskHasType(&connectsTo[t1], t2) + * + * We assume that connectsTo[] is symmetric, + * so this is the same as: + * TTMaskHasType(&connectsTo[t2], t1) + */ + ClientData uninit; /* Contents of a ti_client field indicating + * that the tile has not yet been visited. + */ + Region * (*first)(); /* Applied to first tile in region */ + int (*each)(); /* Applied to each tile in region */ +{ + FindRegion arg; + TileTypeBitMask subMask; + int extRegionAreaFunc(); + + ASSERT(first != NULL, "ExtFindRegions"); + + arg.fra_pNum = ExtCurStyle->exts_globSubstratePlane; + if (arg.fra_pNum < 0) return NULL; + + arg.fra_connectsTo = connectsTo; + arg.fra_def = def; + arg.fra_uninit = uninit; + arg.fra_first = first; + arg.fra_each = each; + arg.fra_region = (Region *) NULL; + + SigDisableInterrupts(); + + TTMaskZero(&subMask); + TTMaskSetMask(&subMask, mask); + TTMaskAndMask(&subMask, &ExtCurStyle->exts_globSubstrateTypes); + + DBSrPaintClient((Tile *) NULL, def->cd_planes[arg.fra_pNum], + area, &subMask, uninit, extRegionAreaFunc, (ClientData) &arg); + SigEnableInterrupts(); + + return (arg.fra_region); +} + /* * ---------------------------------------------------------------------------- * diff --git a/extract/ExtSubtree.c b/extract/ExtSubtree.c index 89b054a8..10aa007b 100644 --- a/extract/ExtSubtree.c +++ b/extract/ExtSubtree.c @@ -170,6 +170,11 @@ extSubtree(parentUse, reg, f) float pdone, plast; SearchContext scx; + TileType subType; + TileTypeBitMask subMask, notSubMask; + Plane *subPlane, *savePlane; + bool hasSubDef = FALSE; + /* Use the display timer to force a 5-second progress check */ GrDisplayStatus = DISPLAY_IN_PROGRESS; SigSetTimer(5); /* Print at 5-second intervals */ @@ -195,6 +200,54 @@ extSubtree(parentUse, reg, f) ha.ha_cumFlat.et_use = extYuseCum; HashInit(&ha.ha_connHash, 32, 0); + /* Determine if substrate copying is required. */ + + hasSubDef = (ExtCurStyle->exts_globSubstratePlane != -1) ? TRUE : FALSE; + if (hasSubDef) + { + /* Find a type to use for the substrate, and the mask of all types */ + /* in the same plane as the substrate that are not connected to the */ + /* substrate. If there is not a simple type representing the substrate */ + /* then do not attempt to resolve substrate regions. */ + + TTMaskZero(&subMask); + TTMaskSetMask(&subMask, &ExtCurStyle->exts_globSubstrateTypes); + + for (subType = TT_TECHDEPBASE; subType < DBNumUserLayers; subType++) + if (TTMaskHasType(&subMask, subType)) + if (DBPlane(subType) == ExtCurStyle->exts_globSubstratePlane) + break; + + TTMaskCom2(¬SubMask, &subMask); + TTMaskAndMask(¬SubMask, &DBPlaneTypes[ExtCurStyle->exts_globSubstratePlane]); + + if (subType == DBNumUserLayers) hasSubDef = FALSE; + } + + /* Generate the full flattened substrate into ha->ha_cumFlat (which */ + /* was empty initially). This adds layer geometry for the */ + /* substrate in the typical case where the substrate may be space */ + /* (implicitly defined substrate). */ + if (hasSubDef) + { + int pNum; + + scx.scx_trans = GeoIdentityTransform; + scx.scx_area = def->cd_bbox; + scx.scx_use = parentUse; + + subPlane = DBCellCanonicalSubstrate(&scx, subType, ¬SubMask, + &ExtCurStyle->exts_globSubstrateShieldTypes, parentUse); + if (subPlane != NULL) + { + pNum = ExtCurStyle->exts_globSubstratePlane; + savePlane = parentUse->cu_def->cd_planes[pNum]; + parentUse->cu_def->cd_planes[pNum] = subPlane; + } + else + hasSubDef = FALSE; /* CellDef has no isolated substrate regions */ + } + #ifndef exactinteractions /* * Cookie-cutter up def into pieces ExtCurStyle->exts_stepSize by @@ -331,6 +384,17 @@ done: /* Clear the CU_SUB_EXTRACTED flag from all children instances */ DBCellEnum(def, extClearUseFlags, (ClientData)NULL); + + /* Replace the modified substrate plane with the original */ + if (hasSubDef) + { + int pNum; + + pNum = ExtCurStyle->exts_globSubstratePlane; + parentUse->cu_def->cd_planes[pNum] = savePlane; + DBFreePaintPlane(subPlane); + TiFreePlane(subPlane); + } } #ifdef exactinteractions @@ -429,26 +493,30 @@ extSubtreeInteraction(ha) NodeRegion *reg; SearchContext scx; - /* Copy parent paint into ha->ha_cumFlat (which was initially empty) */ scx.scx_trans = GeoIdentityTransform; scx.scx_area = ha->ha_interArea; scx.scx_use = ha->ha_parentUse; + +/* + if (hasSubDef) + DBCellCopySubstrate(&scx, subType, ¬SubMask, ha->ha_cumFlat.et_use); +*/ + /* Copy parent paint into ha->ha_cumFlat */ DBCellCopyPaint(&scx, &DBAllButSpaceBits, 0, ha->ha_cumFlat.et_use); -#ifdef notdef - extCopyPaint(ha->ha_parentUse->cu_def, &ha->ha_interArea, cumDef); -#endif /* notdef */ /* - * First element on the subtree list will be parent mask info. + * First element on the subtree list will be parent mask info, + * including the full flattened substrate. * Extract nodes and capacitors. Node names come from parent. */ oneFlat = extHierNewOne(); oneDef = oneFlat->et_use->cu_def; +/* + if (hasSubDef) + DBCellCopySubstrate(&scx, subType, ¬SubMask, oneFlat->et_use); +*/ DBCellCopyPaint(&scx, &DBAllButSpaceBits, 0, oneFlat->et_use); -#ifdef notdef - extCopyPaint(ha->ha_parentUse->cu_def, &ha->ha_interArea, oneDef); -#endif /* notdef */ oneFlat->et_nodes = extFindNodes(oneDef, &ha->ha_clipArea, FALSE); if ((ExtOptions & (EXT_DOCOUPLING|EXT_DOADJUST)) == (EXT_DOCOUPLING|EXT_DOADJUST)) @@ -569,6 +637,7 @@ extSubtreeInteraction(ha) ha->ha_cumFlat.et_nodes = (NodeRegion *) NULL; extHierFreeLabels(cumDef); DBCellClearDef(cumDef); + } /* @@ -732,6 +801,18 @@ extSubtreeFunc(scx, ha) /* Record information for finding node names the hard way later */ ha->ha_subUse = use; + /* Copy the substrate into the oneFlat target */ +/* + if (ha->ha_subType != -1) + { + newscx.scx_use = ha->ha_cumFlat.et_use; + newscx.scx_area = use->cu_bbox; + GEOCLIP(&newscx.scx_area, &ha->ha_interArea); + newscx.scx_trans = GeoIdentityTransform; + DBCellCopySubstrate(&newscx, ha->ha_subType, ha->ha_notSubMask, oneFlat->et_use); + } +*/ + /* * Yank all array elements of this subcell that lie in the interaction * area. Transform to parent coordinates. Prefix is true, meaning that @@ -743,6 +824,7 @@ extSubtreeFunc(scx, ha) hy.hy_area = &ha->ha_subArea; hy.hy_target = oneFlat->et_use; hy.hy_prefix = TRUE; + (void) DBArraySr(use, &ha->ha_subArea, extHierYankFunc, (ClientData) &hy); /* @@ -767,6 +849,8 @@ extSubtreeFunc(scx, ha) */ if (extFirstPass) { + extFirstPass = FALSE; + // On the first pass, run through et_lookName's label list. // Copy any sticky labels to cumUse->cu_def, so that the labels // can be found even when there is no geometry underneath in @@ -796,7 +880,17 @@ extSubtreeFunc(scx, ha) cumUse->cu_def->cd_labels = newlab; } } - extFirstPass = FALSE; + +/* + ha->ha_cumFlat.et_nodes = + (NodeRegion *) ExtFindSubstrateRegions(cumUse->cu_def, + &TiPlaneRect, + &ExtCurStyle->exts_activeTypes, + ExtCurStyle->exts_nodeConn, + extUnInit, extHierLabFirst, (int (*)()) NULL); + ExtLabelRegions(cumUse->cu_def, ExtCurStyle->exts_nodeConn, + &(ha->ha_cumFlat.et_nodes), &TiPlaneRect); +*/ } else { @@ -861,9 +955,6 @@ extSubtreeFunc(scx, ha) newscx.scx_area = ha->ha_subArea; newscx.scx_trans = GeoIdentityTransform; DBCellCopyPaint(&newscx, &DBAllButSpaceBits, 0, cumUse); -#ifdef notdef - extCopyPaint(oneFlat->et_use->cu_def, &ha->ha_subArea, cumUse->cu_def); -#endif /* notdef */ extHierCopyLabels(oneFlat->et_use->cu_def, cumUse->cu_def); /* Prepend this tree to the list of trees we've processed so far */ @@ -1216,7 +1307,6 @@ extSubtreeHardSearch(et, arg) HierExtractArg *ha = arg->hw_ha; ExtTree *oneFlat; - arg->hw_proc = extHardProc; if (et == &ha->ha_cumFlat) { diff --git a/extract/extractInt.h b/extract/extractInt.h index 82d18d51..961aab37 100644 --- a/extract/extractInt.h +++ b/extract/extractInt.h @@ -1016,6 +1016,7 @@ extern ClientData extUnInit; /* ------------------------- Region finding --------------------------- */ extern Region *ExtFindRegions(); +extern Region *ExtFindSubstrateRegions(); /* Filter functions for ExtFindRegions() */ extern Region *extTransFirst(); extern int extTransEach(); From 7be338b44f9389a17cec80f9a6fea2f7aaf8d800 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 5 Apr 2021 10:20:41 -0400 Subject: [PATCH 62/89] Committing final verified method for handling isolated substrate. --- database/DBcellcopy.c | 138 +++++++++++++++-------------------------- database/database.h.in | 3 +- extract/ExtCell.c | 138 +++++++++++++++++++++++++++++++++++++++++ extract/ExtSubtree.c | 96 ---------------------------- select/selUnselect.c | 1 - 5 files changed, 189 insertions(+), 187 deletions(-) diff --git a/database/DBcellcopy.c b/database/DBcellcopy.c index 722a7b3b..4d100439 100644 --- a/database/DBcellcopy.c +++ b/database/DBcellcopy.c @@ -342,7 +342,7 @@ DBCellCheckCopyAllPaint(scx, mask, xMask, targetUse, func) DBTreeSrTiles(scx, &locMask, xMask, dbCopyAllPaint, (ClientData) &arg); } -/* Client data structure used by DBCellCopySubstrate() */ +/* Client data structure used by DBCellGenerateSubstrate() */ struct dbCopySubData { Plane *csd_plane; @@ -354,7 +354,7 @@ struct dbCopySubData { /* *----------------------------------------------------------------------------- * - * DBCellCopySubstrate -- + * DBCellGenerateSubstrate -- * * This function is used by the extraction code in ExtSubtree.c. * Paint substrate into the target use. Similar to DBCellCopyAllPaint(), @@ -380,61 +380,13 @@ struct dbCopySubData { * ---------------------------------------------------------------------------- */ -void -DBCellCopySubstrate(scx, subType, notSubMask, targetUse) - SearchContext *scx; - TileType subType; /* Substrate paint type */ - TileTypeBitMask *notSubMask; /* Mask of types that are not substrate */ - CellUse *targetUse; -{ - struct dbCopySubData csd; - Plane *tempPlane; - int plane; - Rect rect; - int dbEraseNonSub(); - int dbCopySubFunc(); - - GEOTRANSRECT(&scx->scx_trans, &scx->scx_area, &rect); - - /* Clip to bounding box of the top level cell */ - GEOCLIP(&rect, &scx->scx_use->cu_def->cd_bbox); - - plane = DBPlane(subType); - - tempPlane = DBNewPlane((ClientData) TT_SPACE); - DBClearPaintPlane(tempPlane); - - /* First paint the substrate type in the temporary plane over the whole cell area */ - DBPaintPlane(tempPlane, &rect, DBStdPaintTbl(subType, plane), - (PaintUndoInfo *)NULL); - - csd.csd_subtype = subType; - csd.csd_plane = tempPlane; - csd.csd_pNum = plane; - - /* Now erase all areas that are non-substrate types in the source */ - /* Note: xMask is always zero, as this is only called from extract routines */ - DBTreeSrTiles(scx, notSubMask, 0, dbEraseNonSub, (ClientData)&csd); - - /* Finally, copy the temp plane contents into the destination */ - csd.csd_plane = targetUse->cu_def->cd_planes[plane]; - DBSrPaintArea((Tile *)NULL, tempPlane, &TiPlaneRect, - &DBAllButSpaceBits, dbCopySubFunc, (ClientData)&csd); - - /* Clean up by removing the temp plane */ - DBFreePaintPlane(tempPlane); - TiFreePlane(tempPlane); -} - -/* Create a canonical substrate. Return the modified plane */ - Plane * -DBCellCanonicalSubstrate(scx, subType, notSubMask, subShieldMask, targetUse) +DBCellGenerateSubstrate(scx, subType, notSubMask, subShieldMask, targetDef) SearchContext *scx; TileType subType; /* Substrate paint type */ TileTypeBitMask *notSubMask; /* Mask of types that are not substrate */ TileTypeBitMask *subShieldMask; /* Mask of types that shield substrate */ - CellUse *targetUse; + CellDef *targetDef; { struct dbCopySubData csd; Plane *tempPlane; @@ -469,16 +421,55 @@ DBCellCanonicalSubstrate(scx, subType, notSubMask, subShieldMask, targetUse) DBTreeSrTiles(scx, notSubMask, 0, dbEraseNonSub, (ClientData)&csd); /* Finally, copy the destination plane contents onto tempPlane */ - DBSrPaintArea((Tile *)NULL, targetUse->cu_def->cd_planes[plane], &TiPlaneRect, + DBSrPaintArea((Tile *)NULL, targetDef->cd_planes[plane], &TiPlaneRect, &DBAllButSpaceBits, dbCopySubFunc, (ClientData)&csd); return tempPlane; } /* - * Callback function for DBCellCopySubstrate() + * Callback function for DBCellGenerateSubstrate() + * Finds tiles in the source def that belong to the list of types that + * shield the substrate (e.g., deep nwell), and paint the substrate type + * into the target plane over the same area. + */ + +int +dbPaintSubFunc(tile, cxp) + Tile *tile; /* Pointer to source tile with shield type */ + TreeContext *cxp; /* Context from DBTreeSrTiles */ +{ + Rect rect; + int pNum; + TileType type, loctype, subType; + Plane *plane; + struct dbCopySubData *csd; /* Client data */ + + csd = (struct dbCopySubData *)cxp->tc_filter->tf_arg; + plane = csd->csd_plane; + pNum = csd->csd_pNum; + subType = csd->csd_subtype; + type = TiGetTypeExact(tile); + if (IsSplit(tile)) + { + loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile); + if (loctype == TT_SPACE) return 0; + } + + /* Construct the rect for the tile */ + TITORECT(tile, &rect); + csd->csd_modified = TRUE; + + return DBNMPaintPlane(plane, type, &rect, DBStdPaintTbl(subType, pNum), + (PaintUndoInfo *)NULL); +} + +/* + * Callback function for DBCellGenerateSubstrate() * Finds tiles on the substrate plane in the source def that are not the - * substrate type, and erases those areas from the target. + * substrate type, and erases those areas from the target. This reduces + * the geometry in the target plane to areas that form isolated substrate + * regions. Regions belonging to the common global substrate are ignored. */ int @@ -521,9 +512,10 @@ dbEraseNonSub(tile, cxp) } /* - * Callback function for DBCellCopySubstrate() - * Simple paint function to copy substrate paint from a temporary plane into - * a target plane. + * Callback function for DBCellGenerateSubstrate() + * Simple paint function to copy all paint from the substrate plane of the + * source def into the target plane containing the isolated substrate + * regions. */ int @@ -554,36 +546,6 @@ dbCopySubFunc(tile, csd) (PaintUndoInfo *)NULL); } -int -dbPaintSubFunc(tile, cxp) - Tile *tile; /* Pointer to source tile with shield type */ - TreeContext *cxp; /* Context from DBTreeSrTiles */ -{ - Rect rect; - int pNum; - TileType type, loctype, subType; - Plane *plane; - struct dbCopySubData *csd; /* Client data */ - - csd = (struct dbCopySubData *)cxp->tc_filter->tf_arg; - plane = csd->csd_plane; - pNum = csd->csd_pNum; - subType = csd->csd_subtype; - type = TiGetTypeExact(tile); - if (IsSplit(tile)) - { - loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile); - if (loctype == TT_SPACE) return 0; - } - - /* Construct the rect for the tile */ - TITORECT(tile, &rect); - csd->csd_modified = TRUE; - - return DBNMPaintPlane(plane, type, &rect, DBStdPaintTbl(subType, pNum), - (PaintUndoInfo *)NULL); -} - /* *----------------------------------------------------------------------------- * diff --git a/database/database.h.in b/database/database.h.in index b544cbae..6a2f25d3 100644 --- a/database/database.h.in +++ b/database/database.h.in @@ -819,12 +819,11 @@ extern char *DBPrintUseId(); extern void DBCellCopyPaint(); extern void DBCellCopyAllPaint(); extern void DBCellCheckCopyAllPaint(); -extern void DBCellCopySubstrate(); -extern Plane *DBCellCanonicalSubstrate(); extern void DBCellCopyLabels(); extern void DBCellCopyAllLabels(); extern void DBCellCopyCells(); extern void DBCellCopyAllCells(); +extern Plane *DBCellGenerateSubstrate(); /* Contact image handling */ extern TileType DBPlaneToResidue(); diff --git a/extract/ExtCell.c b/extract/ExtCell.c index 50c80ceb..887cecf5 100644 --- a/extract/ExtCell.c +++ b/extract/ExtCell.c @@ -219,6 +219,137 @@ extFileOpen(def, file, mode, doLocal, prealfile) return (PaOpen(name, mode, ".ext", ".", ".", prealfile)); } +/* + * ---------------------------------------------------------------------------- + * + * extPrepSubstrate --- + * + * Prepare a replacement plane for the plane representing the substrate, as + * defined in ExtCurStyle->exts_globSubstratePlane. The target CellDef is + * searched for types that shield (i.e., isolate) a section of the layout + * from the global substrate. The tile type that represents the substrate + * is painted into the isolated regions. + * + * The purpose of this method is to deal with the common methodology in + * which the substrate is not represented by any tile type, because no mask + * is defined for the substrate. Typically, an entire cell such as a digital + * standard cell may be placed on the default substrate or in a deep nwell + * region. It is therefore necessary to be able to detect what is underneath + * a cell on the plane representing the substrate to determine if the area is + * the default substrate or an isolated region. If an isolated region, it + * must be painted with a tile type so that the extraction code can tag the + * tiles with a Region and assign it a node. This code creates the substrate + * paint in the isolated regions for the duration of the extration, then + * reverts back to the original plane afterward. + * + * Results: + * Returns a Plane structure that is the original substrate plane from + * CellDef "def", with isolated substrate regions filled with the + * substrate tile type. If there are no isolated substrate regions, + * or if a substrate plane or substrate type is not defined by the + * technology, then the routine returns NULL. + * + * Side effects: + * All modifications are limited to the returned plane structure. + * + * ---------------------------------------------------------------------------- + */ + +Plane * +extPrepSubstrate(def) + CellDef *def; +{ + SearchContext scx; + CellUse dummy; + TileType subType; + TileTypeBitMask subMask, notSubMask; + Plane *subPlane, *savePlane; + int pNum; + + /* Determine if substrate copying is required. */ + + if (ExtCurStyle->exts_globSubstratePlane == -1) return NULL; + + /* Find a type to use for the substrate, and the mask of all types */ + /* in the same plane as the substrate that are not connected to the */ + /* substrate. If there is not a simple type representing the substrate */ + /* then do not attempt to resolve substrate regions. */ + + TTMaskZero(&subMask); + TTMaskSetMask(&subMask, &ExtCurStyle->exts_globSubstrateTypes); + + for (subType = TT_TECHDEPBASE; subType < DBNumUserLayers; subType++) + if (TTMaskHasType(&subMask, subType)) + if (DBPlane(subType) == ExtCurStyle->exts_globSubstratePlane) + break; + + TTMaskCom2(¬SubMask, &subMask); + TTMaskAndMask(¬SubMask, &DBPlaneTypes[ExtCurStyle->exts_globSubstratePlane]); + + if (subType == DBNumUserLayers) return NULL; + + /* Generate the full flattened substrate into ha->ha_cumFlat (which */ + /* was empty initially). This adds layer geometry for the */ + /* substrate in the typical case where the substrate may be space */ + /* (implicitly defined substrate). */ + + scx.scx_trans = GeoIdentityTransform; + scx.scx_area = def->cd_bbox; + scx.scx_use = &dummy; + dummy.cu_def = def; + dummy.cu_id = NULL; + + subPlane = DBCellGenerateSubstrate(&scx, subType, ¬SubMask, + &ExtCurStyle->exts_globSubstrateShieldTypes, def); + if (subPlane != NULL) + { + pNum = ExtCurStyle->exts_globSubstratePlane; + savePlane = def->cd_planes[pNum]; + def->cd_planes[pNum] = subPlane; + return savePlane; + } + else + return NULL; +} + +/* + * ---------------------------------------------------------------------------- + * + * extRevertSubstrate --- + * + * This routine swaps the substrate plane of CellDef "def" with the plane + * structure provided in the argument "savePlane". It should be called at + * the end of extraction. "savePlane" should be the pointer to the substrate + * plane of "def" before it was swapped out for the modified plane created by + * the routine "extPrepSubstrate", above. The calling routine is responsible + * for knowing if extPrepSubstrate returned NULL in which case there is + * nothing to revert. + * + * Returns: + * Nothing. + * + * Side effects: + * The CellDef "def" has its substrate plane swapped out for "savePlane", + * and the original substrate plane and its contents are freed. + * ---------------------------------------------------------------------------- + */ + + +void +extRevertSubstrate(def, savePlane) + CellDef *def; + Plane *savePlane; +{ + int pNum; + Plane *subPlane; + + pNum = ExtCurStyle->exts_globSubstratePlane; + subPlane = def->cd_planes[pNum]; + def->cd_planes[pNum] = savePlane; + DBFreePaintPlane(subPlane); + TiFreePlane(subPlane); +} + /* * ---------------------------------------------------------------------------- * @@ -250,9 +381,13 @@ extCellFile(def, f, doLength) */ { NodeRegion *reg; + Plane *saveSub; UndoDisable(); + /* Prep any isolated substrate areas */ + saveSub = extPrepSubstrate(def); + /* Output the header: timestamp, technology, calls on cell uses */ if (!SigInterruptPending) extHeader(def, f); @@ -273,6 +408,9 @@ extCellFile(def, f, doLength) if (!SigInterruptPending && doLength && (ExtOptions & EXT_DOLENGTH)) extLength(extParentUse, f); + /* Revert the substrate plane, if it was altered */ + if (saveSub) extRevertSubstrate(def, saveSub); + UndoEnable(); } diff --git a/extract/ExtSubtree.c b/extract/ExtSubtree.c index 10aa007b..2e05d1e8 100644 --- a/extract/ExtSubtree.c +++ b/extract/ExtSubtree.c @@ -170,11 +170,6 @@ extSubtree(parentUse, reg, f) float pdone, plast; SearchContext scx; - TileType subType; - TileTypeBitMask subMask, notSubMask; - Plane *subPlane, *savePlane; - bool hasSubDef = FALSE; - /* Use the display timer to force a 5-second progress check */ GrDisplayStatus = DISPLAY_IN_PROGRESS; SigSetTimer(5); /* Print at 5-second intervals */ @@ -200,54 +195,6 @@ extSubtree(parentUse, reg, f) ha.ha_cumFlat.et_use = extYuseCum; HashInit(&ha.ha_connHash, 32, 0); - /* Determine if substrate copying is required. */ - - hasSubDef = (ExtCurStyle->exts_globSubstratePlane != -1) ? TRUE : FALSE; - if (hasSubDef) - { - /* Find a type to use for the substrate, and the mask of all types */ - /* in the same plane as the substrate that are not connected to the */ - /* substrate. If there is not a simple type representing the substrate */ - /* then do not attempt to resolve substrate regions. */ - - TTMaskZero(&subMask); - TTMaskSetMask(&subMask, &ExtCurStyle->exts_globSubstrateTypes); - - for (subType = TT_TECHDEPBASE; subType < DBNumUserLayers; subType++) - if (TTMaskHasType(&subMask, subType)) - if (DBPlane(subType) == ExtCurStyle->exts_globSubstratePlane) - break; - - TTMaskCom2(¬SubMask, &subMask); - TTMaskAndMask(¬SubMask, &DBPlaneTypes[ExtCurStyle->exts_globSubstratePlane]); - - if (subType == DBNumUserLayers) hasSubDef = FALSE; - } - - /* Generate the full flattened substrate into ha->ha_cumFlat (which */ - /* was empty initially). This adds layer geometry for the */ - /* substrate in the typical case where the substrate may be space */ - /* (implicitly defined substrate). */ - if (hasSubDef) - { - int pNum; - - scx.scx_trans = GeoIdentityTransform; - scx.scx_area = def->cd_bbox; - scx.scx_use = parentUse; - - subPlane = DBCellCanonicalSubstrate(&scx, subType, ¬SubMask, - &ExtCurStyle->exts_globSubstrateShieldTypes, parentUse); - if (subPlane != NULL) - { - pNum = ExtCurStyle->exts_globSubstratePlane; - savePlane = parentUse->cu_def->cd_planes[pNum]; - parentUse->cu_def->cd_planes[pNum] = subPlane; - } - else - hasSubDef = FALSE; /* CellDef has no isolated substrate regions */ - } - #ifndef exactinteractions /* * Cookie-cutter up def into pieces ExtCurStyle->exts_stepSize by @@ -384,17 +331,6 @@ done: /* Clear the CU_SUB_EXTRACTED flag from all children instances */ DBCellEnum(def, extClearUseFlags, (ClientData)NULL); - - /* Replace the modified substrate plane with the original */ - if (hasSubDef) - { - int pNum; - - pNum = ExtCurStyle->exts_globSubstratePlane; - parentUse->cu_def->cd_planes[pNum] = savePlane; - DBFreePaintPlane(subPlane); - TiFreePlane(subPlane); - } } #ifdef exactinteractions @@ -497,10 +433,6 @@ extSubtreeInteraction(ha) scx.scx_area = ha->ha_interArea; scx.scx_use = ha->ha_parentUse; -/* - if (hasSubDef) - DBCellCopySubstrate(&scx, subType, ¬SubMask, ha->ha_cumFlat.et_use); -*/ /* Copy parent paint into ha->ha_cumFlat */ DBCellCopyPaint(&scx, &DBAllButSpaceBits, 0, ha->ha_cumFlat.et_use); @@ -511,10 +443,6 @@ extSubtreeInteraction(ha) */ oneFlat = extHierNewOne(); oneDef = oneFlat->et_use->cu_def; -/* - if (hasSubDef) - DBCellCopySubstrate(&scx, subType, ¬SubMask, oneFlat->et_use); -*/ DBCellCopyPaint(&scx, &DBAllButSpaceBits, 0, oneFlat->et_use); oneFlat->et_nodes = extFindNodes(oneDef, &ha->ha_clipArea, FALSE); @@ -637,7 +565,6 @@ extSubtreeInteraction(ha) ha->ha_cumFlat.et_nodes = (NodeRegion *) NULL; extHierFreeLabels(cumDef); DBCellClearDef(cumDef); - } /* @@ -801,18 +728,6 @@ extSubtreeFunc(scx, ha) /* Record information for finding node names the hard way later */ ha->ha_subUse = use; - /* Copy the substrate into the oneFlat target */ -/* - if (ha->ha_subType != -1) - { - newscx.scx_use = ha->ha_cumFlat.et_use; - newscx.scx_area = use->cu_bbox; - GEOCLIP(&newscx.scx_area, &ha->ha_interArea); - newscx.scx_trans = GeoIdentityTransform; - DBCellCopySubstrate(&newscx, ha->ha_subType, ha->ha_notSubMask, oneFlat->et_use); - } -*/ - /* * Yank all array elements of this subcell that lie in the interaction * area. Transform to parent coordinates. Prefix is true, meaning that @@ -880,17 +795,6 @@ extSubtreeFunc(scx, ha) cumUse->cu_def->cd_labels = newlab; } } - -/* - ha->ha_cumFlat.et_nodes = - (NodeRegion *) ExtFindSubstrateRegions(cumUse->cu_def, - &TiPlaneRect, - &ExtCurStyle->exts_activeTypes, - ExtCurStyle->exts_nodeConn, - extUnInit, extHierLabFirst, (int (*)()) NULL); - ExtLabelRegions(cumUse->cu_def, ExtCurStyle->exts_nodeConn, - &(ha->ha_cumFlat.et_nodes), &TiPlaneRect); -*/ } else { diff --git a/select/selUnselect.c b/select/selUnselect.c index 466a326e..40564d91 100644 --- a/select/selUnselect.c +++ b/select/selUnselect.c @@ -372,7 +372,6 @@ SelectRemoveCellUse(use, trans) { SearchContext scx; - CellUse selectedUse; SelRemoveCellArgs args; /* The search context is the area covered by the cell's bounding box in From 865a4040dd2a55dd9bbfe0fb3dc7d7e626dbd77b Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 5 Apr 2021 10:23:05 -0400 Subject: [PATCH 63/89] Updated version along with isolated substrate handling in extraction. --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index dd2f76b4..5ff02fa2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.151 +8.3.152 From 9aa9fb53c4c56570f1614729b1f1007217551146 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 5 Apr 2021 10:29:14 -0400 Subject: [PATCH 64/89] Cleaned up some unused code left over from extraction tests. --- extract/ExtRegion.c | 63 -------------------------------------------- extract/ExtSubtree.c | 3 +-- extract/extractInt.h | 1 - 3 files changed, 1 insertion(+), 66 deletions(-) diff --git a/extract/ExtRegion.c b/extract/ExtRegion.c index 17c5c43c..658d272c 100644 --- a/extract/ExtRegion.c +++ b/extract/ExtRegion.c @@ -127,69 +127,6 @@ ExtFindRegions(def, area, mask, connectsTo, uninit, first, each) return (arg.fra_region); } -/* - * ---------------------------------------------------------------------------- - * ExtFindSubstrateRegions -- - * - * This is a subset of ExtFindRegions that looks only at the substrate - * plane. It is called on the first pass, when only the parent paint - * has been added to the cumulative def. - * - * ---------------------------------------------------------------------------- - */ - -Region * -ExtFindSubstrateRegions(def, area, mask, connectsTo, uninit, first, each) - CellDef *def; /* Cell definition being searched */ - Rect *area; /* Area to search initially for tiles */ - TileTypeBitMask *mask; /* In the initial area search, only visit - * tiles whose types are in this mask. - */ - TileTypeBitMask *connectsTo;/* Connectivity table for determining regions. - * If t1 and t2 are the types of adjacent - * tiles, then t1 and t2 belong to the same - * region iff: - * TTMaskHasType(&connectsTo[t1], t2) - * - * We assume that connectsTo[] is symmetric, - * so this is the same as: - * TTMaskHasType(&connectsTo[t2], t1) - */ - ClientData uninit; /* Contents of a ti_client field indicating - * that the tile has not yet been visited. - */ - Region * (*first)(); /* Applied to first tile in region */ - int (*each)(); /* Applied to each tile in region */ -{ - FindRegion arg; - TileTypeBitMask subMask; - int extRegionAreaFunc(); - - ASSERT(first != NULL, "ExtFindRegions"); - - arg.fra_pNum = ExtCurStyle->exts_globSubstratePlane; - if (arg.fra_pNum < 0) return NULL; - - arg.fra_connectsTo = connectsTo; - arg.fra_def = def; - arg.fra_uninit = uninit; - arg.fra_first = first; - arg.fra_each = each; - arg.fra_region = (Region *) NULL; - - SigDisableInterrupts(); - - TTMaskZero(&subMask); - TTMaskSetMask(&subMask, mask); - TTMaskAndMask(&subMask, &ExtCurStyle->exts_globSubstrateTypes); - - DBSrPaintClient((Tile *) NULL, def->cd_planes[arg.fra_pNum], - area, &subMask, uninit, extRegionAreaFunc, (ClientData) &arg); - SigEnableInterrupts(); - - return (arg.fra_region); -} - /* * ---------------------------------------------------------------------------- * diff --git a/extract/ExtSubtree.c b/extract/ExtSubtree.c index 2e05d1e8..dfde1f9e 100644 --- a/extract/ExtSubtree.c +++ b/extract/ExtSubtree.c @@ -437,8 +437,7 @@ extSubtreeInteraction(ha) DBCellCopyPaint(&scx, &DBAllButSpaceBits, 0, ha->ha_cumFlat.et_use); /* - * First element on the subtree list will be parent mask info, - * including the full flattened substrate. + * First element on the subtree list will be parent mask info. * Extract nodes and capacitors. Node names come from parent. */ oneFlat = extHierNewOne(); diff --git a/extract/extractInt.h b/extract/extractInt.h index 961aab37..82d18d51 100644 --- a/extract/extractInt.h +++ b/extract/extractInt.h @@ -1016,7 +1016,6 @@ extern ClientData extUnInit; /* ------------------------- Region finding --------------------------- */ extern Region *ExtFindRegions(); -extern Region *ExtFindSubstrateRegions(); /* Filter functions for ExtFindRegions() */ extern Region *extTransFirst(); extern int extTransEach(); From fca21c8fc0bd4da8636aad94bf052ff47bab3c58 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 5 Apr 2021 14:16:28 -0400 Subject: [PATCH 65/89] Corrected an error causing weird and undefined behavior when extracting substrate regions, due to failure to clean up the tagged tiles after exiting a search due to finding a substrate type that was not the global substrate. --- extract/ExtBasic.c | 22 ++-------------------- extract/ExtHier.c | 7 ++++++- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/extract/ExtBasic.c b/extract/ExtBasic.c index c5e0b1c3..90d33753 100644 --- a/extract/ExtBasic.c +++ b/extract/ExtBasic.c @@ -1821,26 +1821,8 @@ extOutputDevices(def, transList, outFile) extTransFindSubs(reg->treg_tile, t, tmask, def, &node, NULL); if ((node == NULL) && (TTMaskHasType(tmask, TT_SPACE))) { - /* Device node is possibly the substrate. But: Note */ - /* that TT_SPACE in the mask covers all planes, and it */ - /* is not possible to specify TT_SPACE in a single */ - /* plane. So it is necessary to check for any */ - /* shielding types that block the substrate. */ - - if (!TTMaskIsZero(&ExtCurStyle->exts_globSubstrateShieldTypes)) - { - extTransFindSubs(reg->treg_tile, t, - &ExtCurStyle->exts_globSubstrateShieldTypes, - def, &node, NULL); - } - if ((glob_subsnode == NULL) || (node != NULL)) { - /* See if there is another matching device record */ - /* with a different terminal type, and try again. */ - devptr = extDevFindMatch(devptr, t); - break; - } - else if ((node == NULL) && (glob_subsnode != NULL)) - node = glob_subsnode; + /* Device node is the global substrate. */ + node = glob_subsnode; } else if (node == NULL) { /* See if there is another matching device record */ diff --git a/extract/ExtHier.c b/extract/ExtHier.c index 1426abec..8e51d155 100644 --- a/extract/ExtHier.c +++ b/extract/ExtHier.c @@ -127,7 +127,11 @@ extHierSubstrate(ha, use, x, y) /* Find the child's substrate node */ nodeList = extFindNodes(use->cu_def, (Rect *) NULL, TRUE); - if (nodeList == NULL) return; + if (nodeList == NULL) + { + ExtResetTiles(use->cu_def, extUnInit); + return; + } /* Check if the child's substrate node is covered by any substrate */ /* shield type (e.g., deep nwell). This is a stupid-simple check */ @@ -161,6 +165,7 @@ extHierSubstrate(ha, use, x, y) extHierSubShieldFunc, (ClientData)NULL) != 0) { freeMagic(nodeList); + ExtResetTiles(use->cu_def, extUnInit); return; } } From f84de3676a94ebca6deefeb798fc5a31a9c3cf97 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 5 Apr 2021 16:03:54 -0400 Subject: [PATCH 66/89] Moved the substrate plane/restore further out so that planes are not restored until after all cells have been processed through extraction. Otherwise, top-down connections can end up with different generated names for the same node, resulting in a disconnect in the netlist. --- extflat/EFbuild.c | 1 + extflat/EFvisit.c | 1 + extract/ExtCell.c | 18 +++++++++--------- extract/ExtMain.c | 30 +++++++++++++++++++++++++++++- extract/ExtTest.c | 5 ++++- extract/extract.h | 3 ++- plow/PlowRandom.c | 7 +++++-- 7 files changed, 51 insertions(+), 14 deletions(-) diff --git a/extflat/EFbuild.c b/extflat/EFbuild.c index ef0cbb06..5d0f1530 100644 --- a/extflat/EFbuild.c +++ b/extflat/EFbuild.c @@ -32,6 +32,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header$"; #include "utils/malloc.h" #include "extflat/extflat.h" #include "extflat/EFint.h" +#include "tiles/tile.h" #include "extract/extract.h" /* for device class list */ /* diff --git a/extflat/EFvisit.c b/extflat/EFvisit.c index 6e6571a7..a556abe7 100644 --- a/extflat/EFvisit.c +++ b/extflat/EFvisit.c @@ -34,6 +34,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include "utils/utils.h" #include "extflat/extflat.h" #include "extflat/EFint.h" +#include "tiles/tile.h" #include "extract/extract.h" /* Root of the tree being flattened */ diff --git a/extract/ExtCell.c b/extract/ExtCell.c index 887cecf5..d2289dd6 100644 --- a/extract/ExtCell.c +++ b/extract/ExtCell.c @@ -58,7 +58,7 @@ ClientData extUnInit = (ClientData) CLIENTDEFAULT; int extOutputUsesFunc(); FILE *extFileOpen(); -void extCellFile(); +Plane* extCellFile(); void extHeader(); @@ -83,7 +83,7 @@ void extHeader(); * ---------------------------------------------------------------------------- */ -void +Plane * ExtCell(def, outName, doLength) CellDef *def; /* Cell being extracted */ char *outName; /* Name of output file; if NULL, derive from def name */ @@ -95,6 +95,7 @@ ExtCell(def, outName, doLength) { char *filename; FILE *f; + Plane *savePlane; bool doLocal; doLocal = (ExtOptions & EXT_DOLOCAL) ? TRUE : FALSE; @@ -115,7 +116,7 @@ ExtCell(def, outName, doLength) } extNumFatal = extNumWarnings = 0; - extCellFile(def, f, doLength); + savePlane = extCellFile(def, f, doLength); (void) fclose(f); if (extNumFatal > 0 || extNumWarnings > 0) @@ -129,6 +130,7 @@ ExtCell(def, outName, doLength) extNumWarnings, extNumWarnings != 1 ? "s" : ""); TxPrintf("\n"); } + return savePlane; } /* @@ -315,7 +317,7 @@ extPrepSubstrate(def) /* * ---------------------------------------------------------------------------- * - * extRevertSubstrate --- + * ExtRevertSubstrate --- * * This routine swaps the substrate plane of CellDef "def" with the plane * structure provided in the argument "savePlane". It should be called at @@ -336,7 +338,7 @@ extPrepSubstrate(def) void -extRevertSubstrate(def, savePlane) +ExtRevertSubstrate(def, savePlane) CellDef *def; Plane *savePlane; { @@ -371,7 +373,7 @@ extRevertSubstrate(def, savePlane) * ---------------------------------------------------------------------------- */ -void +Plane * extCellFile(def, f, doLength) CellDef *def; /* Def to be extracted */ FILE *f; /* Output to this file */ @@ -408,10 +410,8 @@ extCellFile(def, f, doLength) if (!SigInterruptPending && doLength && (ExtOptions & EXT_DOLENGTH)) extLength(extParentUse, f); - /* Revert the substrate plane, if it was altered */ - if (saveSub) extRevertSubstrate(def, saveSub); - UndoEnable(); + return saveSub; } /* diff --git a/extract/ExtMain.c b/extract/ExtMain.c index d3b0c4f5..fbc0bf5a 100644 --- a/extract/ExtMain.c +++ b/extract/ExtMain.c @@ -616,6 +616,16 @@ closeit: return (ret); } +/* Linked list structure to use to store the substrate plane from each */ +/* extracted CellDef so that they can be returned to the original after */ +/* extraction. */ + +struct saveList { + Plane *sl_plane; + CellDef *sl_def; + struct saveList *sl_next; +}; + /* * ---------------------------------------------------------------------------- * @@ -645,7 +655,9 @@ extExtractStack(stack, doExtract, rootDef) { int fatal = 0, warnings = 0; bool first = TRUE; + Plane *savePlane; CellDef *def; + struct saveList *newsl, *sl = (struct saveList *)NULL; while (def = (CellDef *) StackPop(stack)) { @@ -654,7 +666,16 @@ extExtractStack(stack, doExtract, rootDef) { if (doExtract) { - ExtCell(def, (char *) NULL, (def == rootDef)); + savePlane = ExtCell(def, (char *) NULL, (def == rootDef)); + if (savePlane != NULL) + { + newsl = (struct saveList *)mallocMagic(sizeof(struct saveList)); + newsl->sl_plane = savePlane; + newsl->sl_def = def; + newsl->sl_next = sl; + sl = newsl; + } + fatal += extNumFatal; warnings += extNumWarnings; } @@ -668,6 +689,13 @@ extExtractStack(stack, doExtract, rootDef) } } + /* Replace any modified substrate planes */ + for (; sl; sl = sl->sl_next) + { + ExtRevertSubstrate(sl->sl_def, sl->sl_plane); + freeMagic(sl); + } + if (!doExtract) { TxPrintf("\n"); diff --git a/extract/ExtTest.c b/extract/ExtTest.c index 1c4474af..8b23b407 100644 --- a/extract/ExtTest.c +++ b/extract/ExtTest.c @@ -148,6 +148,8 @@ ExtractTest(w, cmd) if (cmd->tx_argc == 1) { + Plane *savePlane; + selectedCell = CmdGetSelectedCell((Transform *) NULL); if (selectedCell == NULL) { @@ -156,7 +158,8 @@ ExtractTest(w, cmd) } extDispInit(selectedCell->cu_def, w); - ExtCell(selectedCell->cu_def, selectedCell->cu_def->cd_name, FALSE); + savePlane = ExtCell(selectedCell->cu_def, selectedCell->cu_def->cd_name, FALSE); + ExtRevertSubstrate(selectedCell->cu_def, savePlane); return; } diff --git a/extract/extract.h b/extract/extract.h index 7bb74dda..d01c9393 100644 --- a/extract/extract.h +++ b/extract/extract.h @@ -75,7 +75,8 @@ extern void ExtTechInit(); extern void ExtTechFinal(); extern void ExtSetStyle(); extern void ExtPrintStyle(); -extern void ExtCell(); +extern void ExtRevertSubstrate(); +extern Plane *ExtCell(); extern int ExtGetGateTypesMask(); extern int ExtGetDiffTypesMask(); diff --git a/plow/PlowRandom.c b/plow/PlowRandom.c index b0e2db20..680fcd4d 100644 --- a/plow/PlowRandom.c +++ b/plow/PlowRandom.c @@ -91,6 +91,7 @@ PlowRandomTest(def) static char *dirnames[] = { "up", "down", "right", "left" }; Rect plowRect; int dir, plowDir; + Plane *savePlane; #ifdef notdef strcpy(goodName, tempgood); @@ -101,7 +102,8 @@ PlowRandomTest(def) sprintf(tempExt, "%s.ext", tempName); /* Generate "good" extracted file */ - ExtCell(def, goodName, FALSE); + savePlane = ExtCell(def, goodName, FALSE); + ExtRevertSubstrate(def, savePlane); (void) sprintf(command, "sedplow %s", goodExt); system(command); #endif /* notdef */ @@ -136,7 +138,8 @@ PlowRandomTest(def) #ifdef notdef /* Extract to the temp file */ - ExtCell(def, tempName, FALSE); + savePlane = ExtCell(def, tempName, FALSE); + ExtRevertSubstrate(def, savePlane); (void) sprintf(command, "sedplow %s", tempExt); system(command); From 84f4bf82eacb989046959425fe1512f8c68ecf52 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 6 Apr 2021 10:13:36 -0400 Subject: [PATCH 67/89] Corrected a few errors in the code from yesterday's commit. --- VERSION | 2 +- database/DBcellcopy.c | 16 ++++++++++------ extract/ExtMain.c | 5 ++++- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/VERSION b/VERSION index 5ff02fa2..cb339f4e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.152 +8.3.153 diff --git a/database/DBcellcopy.c b/database/DBcellcopy.c index 4d100439..cda6e83d 100644 --- a/database/DBcellcopy.c +++ b/database/DBcellcopy.c @@ -439,12 +439,14 @@ dbPaintSubFunc(tile, cxp) Tile *tile; /* Pointer to source tile with shield type */ TreeContext *cxp; /* Context from DBTreeSrTiles */ { - Rect rect; + SearchContext *scx; + Rect sourceRect, targetRect; int pNum; TileType type, loctype, subType; Plane *plane; struct dbCopySubData *csd; /* Client data */ + scx = cxp->tc_scx; csd = (struct dbCopySubData *)cxp->tc_filter->tf_arg; plane = csd->csd_plane; pNum = csd->csd_pNum; @@ -457,10 +459,14 @@ dbPaintSubFunc(tile, cxp) } /* Construct the rect for the tile */ - TITORECT(tile, &rect); + TITORECT(tile, &sourceRect); + + /* Transform to target coordinates */ + GEOTRANSRECT(&scx->scx_trans, &sourceRect, &targetRect); + csd->csd_modified = TRUE; - return DBNMPaintPlane(plane, type, &rect, DBStdPaintTbl(subType, pNum), + return DBNMPaintPlane(plane, type, &targetRect, DBStdPaintTbl(subType, pNum), (PaintUndoInfo *)NULL); } @@ -497,8 +503,6 @@ dbEraseNonSub(tile, cxp) loctype = (SplitSide(tile)) ? SplitRightType(tile) : SplitLeftType(tile); if (loctype == TT_SPACE) return 0; } - else - loctype = type; /* Construct the rect for the tile */ TITORECT(tile, &sourceRect); @@ -507,7 +511,7 @@ dbEraseNonSub(tile, cxp) GEOTRANSRECT(&scx->scx_trans, &sourceRect, &targetRect); /* Erase the substrate type from the area of this tile in the target plane. */ - return DBNMPaintPlane(plane, loctype, &targetRect, DBStdEraseTbl(subType, pNum), + return DBNMPaintPlane(plane, type, &targetRect, DBStdEraseTbl(subType, pNum), (PaintUndoInfo *)NULL); } diff --git a/extract/ExtMain.c b/extract/ExtMain.c index fbc0bf5a..e81e331e 100644 --- a/extract/ExtMain.c +++ b/extract/ExtMain.c @@ -692,7 +692,10 @@ extExtractStack(stack, doExtract, rootDef) /* Replace any modified substrate planes */ for (; sl; sl = sl->sl_next) { - ExtRevertSubstrate(sl->sl_def, sl->sl_plane); + // ExtRevertSubstrate(sl->sl_def, sl->sl_plane); + DBFreePaintPlane(sl->sl_plane); + TiFreePlane(sl->sl_plane); + freeMagic(sl); } From 3703560305e92e29be40b01454a0b47615d5d12b Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 6 Apr 2021 10:15:15 -0400 Subject: [PATCH 68/89] Removed some testing code that was not supposed to be in the last commit. --- extract/ExtMain.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extract/ExtMain.c b/extract/ExtMain.c index e81e331e..d9d499f9 100644 --- a/extract/ExtMain.c +++ b/extract/ExtMain.c @@ -692,9 +692,9 @@ extExtractStack(stack, doExtract, rootDef) /* Replace any modified substrate planes */ for (; sl; sl = sl->sl_next) { - // ExtRevertSubstrate(sl->sl_def, sl->sl_plane); - DBFreePaintPlane(sl->sl_plane); - TiFreePlane(sl->sl_plane); + ExtRevertSubstrate(sl->sl_def, sl->sl_plane); + // DBFreePaintPlane(sl->sl_plane); + // TiFreePlane(sl->sl_plane); freeMagic(sl); } From a5e0de031cc425dd4f6015d30bdf5b183fa69392 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 6 Apr 2021 22:04:53 -0400 Subject: [PATCH 69/89] Corrected the "font measure" line in the wrapper Tcl code from revision 131, as a Tk default font size less than 10 will round the scaling factor down to zero and result in bad things happening. --- tcltk/wrapper.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tcltk/wrapper.tcl b/tcltk/wrapper.tcl index 4b327c80..f8c3056f 100644 --- a/tcltk/wrapper.tcl +++ b/tcltk/wrapper.tcl @@ -1138,10 +1138,10 @@ proc magic::openwrapper {{cell ""} {framename ""}} { # set. On standard displays, an "M" in the Sans font is usually 10 # pixels wide, and 22 on high resolution displays, so this maps to # a scale of 1 on standard displays and a scale of 2 on high resolution - # displays. + # displays. Make sure scale doesn't go to zero or bad things happen. if [catch {set Opts(scale)}] { - set Opts(scale) [expr {int([font measure TkDefaultFont M] / 10)}] + set Opts(scale) [expr {max(1, int([font measure TkDefaultFont M] / 10))}] } # Resize the window From a9fc99174a32760b5c52193e7292f3416d58a944 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 12 Apr 2021 13:32:16 -0400 Subject: [PATCH 70/89] Revert "Removed the stupid restriction that "cellname readwrite" won't work" This reverts commit 8b9c47c3efe9e507c9f32bccd393bf2efd1fa8ed. Reverting back to the state before messing with the substrate extraction code. All of the substrate extraction code is now in a separate branch. --- commands/CmdCD.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/commands/CmdCD.c b/commands/CmdCD.c index bb779d87..2eec220e 100644 --- a/commands/CmdCD.c +++ b/commands/CmdCD.c @@ -1084,11 +1084,13 @@ CmdCellname(w, cmd) if (cellDef->cd_fd == -1) dbReadOpen(cellDef, NULL, TRUE, NULL); - if (cellDef->cd_fd == -1) - TxError("Warning: Cell %s is not writeable\n", cellDef->cd_name); -#endif - + if (cellDef->cd_fd != -1) + cellDef->cd_flags &= ~CDNOEDIT; + else + TxError("Advisory lock held on cell %s\n", cellDef->cd_name); +#else cellDef->cd_flags &= ~CDNOEDIT; +#endif WindAreaChanged(w, &w->w_screenArea); CmdSetWindCaption(EditCellUse, EditRootDef); } From 04fca92bf02d6d085f7f3679e791a4eb79f6b5fd Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 19 Apr 2021 10:08:58 -0400 Subject: [PATCH 71/89] Finally got around to modifying the "cellname [list] top" command so that it returns cellnames in "natural sort" alphabetical order instead of the random order produced by scanning the hash table of cell names. Since this command is used by the "cell manager" window code, which was also not doing any sorting, then this fixes the same issue in the "cell manager". --- VERSION | 2 +- database/DBcellname.c | 134 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 111 insertions(+), 25 deletions(-) diff --git a/VERSION b/VERSION index cb339f4e..f9ae0443 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.153 +8.3.154 diff --git a/database/DBcellname.c b/database/DBcellname.c index dbfc32f0..b19ad2fc 100644 --- a/database/DBcellname.c +++ b/database/DBcellname.c @@ -21,7 +21,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #endif /* not lint */ #include +#include /* for qsort() */ #include +#include #include "tcltk/tclmagic.h" #include "utils/magic.h" @@ -598,6 +600,67 @@ DBTopPrint(mw, dolist) } } +/* + * ---------------------------------------------------------------------------- + * Simple natural sort routine + * https://stackoverflow.com/questions/34518/natural-sorting-algorithm + * By Norman Ramsey, edited for style. + * ---------------------------------------------------------------------------- + */ + +int strcmpbynum(const char *s1, const char *s2) +{ + /* Like strcmp() but compare sequences of digits numerically */ + for (;;) + { + if (*s2 == '\0') + return *s1 != '\0'; + else if (*s1 == '\0') + return 1; + else if (!(isdigit(*s1) && isdigit(*s2))) + { + if (*s1 != *s2) + return (int)*s1 - (int)*s2; + else + { + ++s1; + ++s2; + } + } + else + { + char *lim1, *lim2; + unsigned long n1 = strtoul(s1, &lim1, 10); + unsigned long n2 = strtoul(s2, &lim2, 10); + if (n1 > n2) + return 1; + else if (n1 < n2) + return -1; + s1 = lim1; + s2 = lim2; + } + } +} + +/* + * ---------------------------------------------------------------------------- + * Sort routine for qsort() to be used by DBCellPrint(). Sorts in alphabetical + * order using the natural sort routine above. List is reverse sorted since + * the code below prints from the end to the beginning of the list. + * ---------------------------------------------------------------------------- + */ + +int +qcompare(const void *one, const void *two) +{ + int cval; + + char *s1 = *((char **)one); + char *s2 = *((char **)two); + cval = strcmpbynum(s1, s2); + return -cval; +} + /* * ---------------------------------------------------------------------------- * @@ -625,11 +688,12 @@ DBCellPrint(CellName, who, dolist) int who; bool dolist; { - int found; + int found, numcells; HashSearch hs; HashEntry *entry; CellDef *celldef; CellUse *celluse; + char **celllist; if (!dolist) { @@ -657,6 +721,11 @@ DBCellPrint(CellName, who, dolist) * CDMODIFIED flag set. */ + numcells = dbCellDefTable.ht_nEntries; + if (numcells == 0) numcells = 1; + celllist = (char **)mallocMagic(numcells * sizeof(char *)); + numcells = 0; + HashStartSearch(&hs); while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL) { @@ -666,28 +735,39 @@ DBCellPrint(CellName, who, dolist) if (((celldef->cd_flags & CDINTERNAL) != CDINTERNAL) && ((who != MODIFIED) || (celldef->cd_flags & CDMODIFIED))) - { if (celldef->cd_name != NULL) - { - if (dolist) -#ifdef MAGIC_WRAPPER - Tcl_AppendElement(magicinterp, celldef->cd_name); -#else - TxPrintf("%s ", celldef->cd_name); -#endif - else - TxPrintf(" %s\n", celldef->cd_name); - } - } + celllist[numcells++] = celldef->cd_name; + } } + + qsort(celllist, numcells, sizeof(char *), qcompare); + + while (--numcells >= 0) + { + if (dolist) +#ifdef MAGIC_WRAPPER + Tcl_AppendElement(magicinterp, celllist[numcells]); +#else + TxPrintf("%s ", celllist[numcells]); +#endif + else + TxPrintf(" %s\n", celllist[numcells]); + } + + freeMagic(celllist); break; case TOPCELLS: /* - * Print the name of all the 'top' cells. + * Print the name of all the 'top' cells. Sort alphabetically. */ + numcells = dbCellDefTable.ht_nEntries; + if (numcells == 0) numcells = 1; + celllist = (char **)mallocMagic(numcells * sizeof(char *)); + numcells = 0; + HashStartSearch(&hs); while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL) { @@ -712,19 +792,25 @@ DBCellPrint(CellName, who, dolist) } } if ( (found == 0) && (celldef->cd_name != NULL) ) - { - if (dolist) -#ifdef MAGIC_WRAPPER - Tcl_AppendElement(magicinterp, celldef->cd_name); -#else - TxPrintf("%s ", celldef->cd_name); -#endif - else - TxPrintf(" %s\n", celldef->cd_name); - } + celllist[numcells++] = celldef->cd_name; } } } + + qsort(celllist, numcells, sizeof(char *), qcompare); + + while (--numcells >= 0) + { + if (dolist) +#ifdef MAGIC_WRAPPER + Tcl_AppendElement(magicinterp, celllist[numcells]); +#else + TxPrintf("%s ", celllist[numcells]); +#endif + else + TxPrintf(" %s\n", celllist[numcells]); + } + freeMagic(celllist); break; default: From 521baa91d93c9502c4a6eda783b3382c3f01cbf2 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 19 Apr 2021 12:53:32 -0400 Subject: [PATCH 72/89] Modified the "gds write" command so that it issues a strongly- worded warning if an abstract cell view is written to GDS. Corrected the "cellname ... writeable" command to allow an overrride of the read-only status of a cell. That change had been made before but apparently got reverted by the recent rollback. --- calma/CalmaWrite.c | 7 +++++++ commands/CmdCD.c | 10 ++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/calma/CalmaWrite.c b/calma/CalmaWrite.c index 282e83f0..cb1857cd 100644 --- a/calma/CalmaWrite.c +++ b/calma/CalmaWrite.c @@ -814,6 +814,13 @@ calmaProcessDef(def, outf, do_library) if (isReadOnly && hasContent && CalmaAddendum) return (0); + /* Give a strongly-worded statement about writing abstract views */ + + if (isAbstract && !isReadOnly) + TxError("Warning: Writing abstract view of \"%s\" to GDS. This is" + " probably not what you want to do.\n", + def->cd_name); + /* * Output the definitions for any of our descendants that have * not already been output. Numbers are assigned to the subcells diff --git a/commands/CmdCD.c b/commands/CmdCD.c index 2eec220e..0288f8e0 100644 --- a/commands/CmdCD.c +++ b/commands/CmdCD.c @@ -1084,13 +1084,11 @@ CmdCellname(w, cmd) if (cellDef->cd_fd == -1) dbReadOpen(cellDef, NULL, TRUE, NULL); - if (cellDef->cd_fd != -1) - cellDef->cd_flags &= ~CDNOEDIT; - else - TxError("Advisory lock held on cell %s\n", cellDef->cd_name); -#else - cellDef->cd_flags &= ~CDNOEDIT; + if (cellDef->cd_fd == -1) + TxError("Overriding advisory lock held on cell %s\n", + cellDef->cd_name); #endif + cellDef->cd_flags &= ~CDNOEDIT; WindAreaChanged(w, &w->w_screenArea); CmdSetWindCaption(EditCellUse, EditRootDef); } From 5b00ee7b832f4ba0609c3541d9d21e095f279876 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 20 Apr 2021 10:19:12 -0400 Subject: [PATCH 73/89] Added a "-pinonly" option to "lef write" to restrict the pin area to what is defined by the label, and no additional surrounding geometry. --- VERSION | 2 +- lef/lefCmd.c | 19 ++++++++++++++++--- lef/lefWrite.c | 36 ++++++++++++++++++++++++++---------- 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/VERSION b/VERSION index f9ae0443..a7015476 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.154 +8.3.155 diff --git a/lef/lefCmd.c b/lef/lefCmd.c index 6646d402..81cf3c80 100644 --- a/lef/lefCmd.c +++ b/lef/lefCmd.c @@ -92,6 +92,9 @@ CmdLef(w, cmd) * other than pin area surrounding labels, * with the indicated setback distance. */ + bool lefPinOnly = FALSE; /* If TRUE, make pins only where labels + * are defined, not the whole net. + */ bool lefTopLayer = FALSE; /* If TRUE, only output the topmost * layer used by a pin, and make * all layers below it obstructions. @@ -234,6 +237,8 @@ CmdLef(w, cmd) i++; } } + else if (!strncmp(cmd->tx_argv[i], "-pinonly", 8)) + lefPinOnly = TRUE; else if (!strncmp(cmd->tx_argv[i], "-toplayer", 9)) lefTopLayer = TRUE; else if (!strncmp(cmd->tx_argv[i], "-nomaster", 9)) @@ -244,8 +249,8 @@ CmdLef(w, cmd) } else goto wrongNumArgs; } - LefWriteAll(selectedUse, lefTopCell, lefTech, lefHide, lefTopLayer, - lefDoMaster, recurse); + LefWriteAll(selectedUse, lefTopCell, lefTech, lefHide, lefPinOnly, + lefTopLayer, lefDoMaster, recurse); } break; case LEF_WRITE: @@ -286,6 +291,13 @@ CmdLef(w, cmd) else TxPrintf("The \"-hide\" option is only for lef write\n"); } + else if (!strncmp(cmd->tx_argv[i], "-pinonly", 8)) + { + if (is_lef) + lefPinOnly = TRUE; + else + TxPrintf("The \"-pinonly\" option is only for lef write\n"); + } else if (!strncmp(cmd->tx_argv[i], "-toplayer", 9)) { if (is_lef) @@ -339,7 +351,8 @@ CmdLef(w, cmd) DefWriteCell(selectedUse->cu_def, namep, allSpecial, units); else LefWriteCell(selectedUse->cu_def, namep, selectedUse->cu_def - == EditRootDef, lefTech, lefHide, lefTopLayer, lefDoMaster); + == EditRootDef, lefTech, lefHide, lefPinOnly, + lefTopLayer, lefDoMaster); break; case LEF_HELP: wrongNumArgs: diff --git a/lef/lefWrite.c b/lef/lefWrite.c index 17a3ac17..357482ef 100644 --- a/lef/lefWrite.c +++ b/lef/lefWrite.c @@ -1095,11 +1095,12 @@ LefWritePinHeader(f, lab) */ void -lefWriteMacro(def, f, scale, setback, toplayer, domaster) +lefWriteMacro(def, f, scale, setback, pinonly, 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 pinonly; /* If TRUE, only place pins where labels are defined */ bool toplayer; /* If TRUE, only output topmost layer of pins */ bool domaster; /* If TRUE, write masterslice layers */ { @@ -1416,13 +1417,18 @@ lefWriteMacro(def, f, scale, setback, toplayer, domaster) scx.scx_area = labr; SelectClear(); - if (setback == 0) + if ((pinonly == TRUE) || (setback == 0)) { Rect carea; labelLinkedList *newlll; - SelectChunk(&scx, lab->lab_type, 0, &carea, FALSE); - if (GEO_RECTNULL(&carea)) carea = labr; + if (pinonly == TRUE) + carea = labr; + else + { + SelectChunk(&scx, lab->lab_type, 0, &carea, FALSE); + if (GEO_RECTNULL(&carea)) carea = labr; + } /* Note that a sticky label could be placed over multiple */ /* tile types, which would cause SelectChunk to fail. So */ @@ -1445,12 +1451,18 @@ lefWriteMacro(def, f, scale, setback, toplayer, domaster) 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. */ + /* remove the part inside the setback area. */ SelectNet(&scx, lab->lab_type, 0, NULL, FALSE); GEO_EXPAND(&boundary, -setback, &carea); SelRemoveArea(&carea, &DBAllButSpaceAndDRCBits); + + /* Paint over the label area so that labels do not simply */ + /* disappear by being inside the setback area. */ + + pNum = DBPlane(lab->lab_type); + DBPaintPlane(SelectDef->cd_planes[pNum], &labr, + DBStdPaintTbl(lab->lab_type, pNum), (PaintUndoInfo *) NULL); } else SelectNet(&scx, lab->lab_type, 0, NULL, FALSE); @@ -1964,11 +1976,13 @@ lefGetProperties(stackItem, i, clientData) */ void -LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, lefTopLayer, lefDoMaster, recurse) +LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, lefPinOnly, lefTopLayer, + lefDoMaster, recurse) CellUse *rootUse; bool writeTopCell; bool lefTech; int lefHide; + bool lefPinOnly; bool lefTopLayer; bool lefDoMaster; bool recurse; @@ -2040,7 +2054,7 @@ LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, lefTopLayer, lefDoMaster, r { def->cd_client = (ClientData) 0; if (!SigInterruptPending) - lefWriteMacro(def, f, scale, lefHide, lefTopLayer, lefDoMaster); + lefWriteMacro(def, f, scale, lefHide, lefPinOnly, lefTopLayer, lefDoMaster); } /* End the LEF file */ @@ -2104,12 +2118,14 @@ lefDefPushFunc(use, recurse) */ void -LefWriteCell(def, outName, isRoot, lefTech, lefHide, lefTopLayer, lefDoMaster) +LefWriteCell(def, outName, isRoot, lefTech, lefHide, lefPinOnly, 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 lefPinOnly; /* Only generate pins on label areas */ bool lefTopLayer; /* Use only topmost layer of pin if TRUE */ bool lefDoMaster; /* Write masterslice layers if TRUE */ { @@ -2145,7 +2161,7 @@ LefWriteCell(def, outName, isRoot, lefTech, lefHide, lefTopLayer, lefDoMaster) HashKill(&propHashTbl); HashKill(&siteHashTbl); } - lefWriteMacro(def, f, scale, lefHide, lefTopLayer, lefDoMaster); + lefWriteMacro(def, f, scale, lefHide, lefPinOnly, lefTopLayer, lefDoMaster); /* End the LEF file */ fprintf(f, "END LIBRARY\n\n"); From 1e08e90b2fb72908e803ae39a59fa13fe1d62542 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 20 Apr 2021 13:33:25 -0400 Subject: [PATCH 74/89] Additional modification to the previous commit to make the "-pinonly" argument to "lef write" take an optional value which is a setback distance, similar to "-hide", but specifically for limiting the distance that pins can extend into the center of a macro. --- lef/lefCmd.c | 29 +++++++++++++++++++++++++---- lef/lefWrite.c | 45 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 63 insertions(+), 11 deletions(-) diff --git a/lef/lefCmd.c b/lef/lefCmd.c index 81cf3c80..faa5d31e 100644 --- a/lef/lefCmd.c +++ b/lef/lefCmd.c @@ -92,8 +92,10 @@ CmdLef(w, cmd) * other than pin area surrounding labels, * with the indicated setback distance. */ - bool lefPinOnly = FALSE; /* If TRUE, make pins only where labels - * are defined, not the whole net. + int lefPinOnly = -1; /* If >= 0, make pins only where labels + * are defined, not the whole net. Values + * > 0 limit how far pins can extend into + * the interior of the cell. */ bool lefTopLayer = FALSE; /* If TRUE, only output the topmost * layer used by a pin, and make @@ -238,7 +240,16 @@ CmdLef(w, cmd) } } else if (!strncmp(cmd->tx_argv[i], "-pinonly", 8)) - lefPinOnly = TRUE; + { + lefPinOnly = 0; + if ((i < (cmd->tx_argc - 1)) && + StrIsNumeric(cmd->tx_argv[i + 1])) + { + lefPinOnly = cmdParseCoord(w, cmd->tx_argv[i + 1], + FALSE, TRUE); + i++; + } + } else if (!strncmp(cmd->tx_argv[i], "-toplayer", 9)) lefTopLayer = TRUE; else if (!strncmp(cmd->tx_argv[i], "-nomaster", 9)) @@ -294,7 +305,17 @@ CmdLef(w, cmd) else if (!strncmp(cmd->tx_argv[i], "-pinonly", 8)) { if (is_lef) - lefPinOnly = TRUE; + { + lefPinOnly = 0; + if ((i < (cmd->tx_argc - 1)) && + StrIsNumeric(cmd->tx_argv[i + 1])) + { + lefPinOnly = cmdParseCoord(w, cmd->tx_argv[i + 1], + FALSE, TRUE); + cargs--; + i++; + } + } else TxPrintf("The \"-pinonly\" option is only for lef write\n"); } diff --git a/lef/lefWrite.c b/lef/lefWrite.c index 357482ef..aa12f0e6 100644 --- a/lef/lefWrite.c +++ b/lef/lefWrite.c @@ -1100,7 +1100,7 @@ lefWriteMacro(def, f, scale, setback, pinonly, toplayer, domaster) 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 pinonly; /* If TRUE, only place pins where labels are defined */ + int pinonly; /* If >= 0, only place pins where labels are defined */ bool toplayer; /* If TRUE, only output topmost layer of pins */ bool domaster; /* If TRUE, write masterslice layers */ { @@ -1417,17 +1417,23 @@ lefWriteMacro(def, f, scale, setback, pinonly, toplayer, domaster) scx.scx_area = labr; SelectClear(); - if ((pinonly == TRUE) || (setback == 0)) + if (setback == 0) { Rect carea; labelLinkedList *newlll; - if (pinonly == TRUE) + if (pinonly == 0) carea = labr; else { - SelectChunk(&scx, lab->lab_type, 0, &carea, FALSE); - if (GEO_RECTNULL(&carea)) carea = labr; + SelectChunk(&scx, lab->lab_type, 0, &carea, FALSE); + if (GEO_RECTNULL(&carea)) carea = labr; + else if (pinonly > 0) + { + Rect psetback; + GEO_EXPAND(&boundary, -pinonly, &psetback); + SelRemoveArea(&psetback, &DBAllButSpaceAndDRCBits); + } } /* Note that a sticky label could be placed over multiple */ @@ -1457,6 +1463,14 @@ lefWriteMacro(def, f, scale, setback, pinonly, toplayer, domaster) GEO_EXPAND(&boundary, -setback, &carea); SelRemoveArea(&carea, &DBAllButSpaceAndDRCBits); + /* Apply any additional setback from the "-pinonly" option */ + if (pinonly > setback) + { + Rect psetback; + GEO_EXPAND(&boundary, -pinonly, &psetback); + SelRemoveArea(&psetback, &DBAllButSpaceAndDRCBits); + } + /* Paint over the label area so that labels do not simply */ /* disappear by being inside the setback area. */ @@ -1465,8 +1479,25 @@ lefWriteMacro(def, f, scale, setback, pinonly, toplayer, domaster) DBStdPaintTbl(lab->lab_type, pNum), (PaintUndoInfo *) NULL); } else + { SelectNet(&scx, lab->lab_type, 0, NULL, FALSE); + /* Apply any pin setback */ + if (pinonly >= 0) + { + Rect psetback; + GEO_EXPAND(&boundary, -pinonly, &psetback); + SelRemoveArea(&psetback, &DBAllButSpaceAndDRCBits); + + /* Paint over the label area so that labels do not simply */ + /* disappear by being inside the setback area. */ + + pNum = DBPlane(lab->lab_type); + DBPaintPlane(SelectDef->cd_planes[pNum], &labr, + DBStdPaintTbl(lab->lab_type, pNum), (PaintUndoInfo *) NULL); + } + } + // Search for gate and diff types and accumulate antenna // areas. For gates, check for all gate types tied to // devices with MOSFET types (including "msubcircuit", etc.). @@ -1982,7 +2013,7 @@ LefWriteAll(rootUse, writeTopCell, lefTech, lefHide, lefPinOnly, lefTopLayer, bool writeTopCell; bool lefTech; int lefHide; - bool lefPinOnly; + int lefPinOnly; bool lefTopLayer; bool lefDoMaster; bool recurse; @@ -2125,7 +2156,7 @@ LefWriteCell(def, outName, isRoot, lefTech, lefHide, lefPinOnly, lefTopLayer, bool isRoot; /* Is this the root cell? */ bool lefTech; /* Output layer information if TRUE */ int lefHide; /* Hide detail other than pins if >= 0 */ - bool lefPinOnly; /* Only generate pins on label areas */ + int lefPinOnly; /* Only generate pins on label areas */ bool lefTopLayer; /* Use only topmost layer of pin if TRUE */ bool lefDoMaster; /* Write masterslice layers if TRUE */ { From abb3c3b98b9adb6ed27598e8072a91e5711d86bb Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 20 Apr 2021 20:45:49 -0400 Subject: [PATCH 75/89] Some changes to ext2sim and extresist to support arbitrary device types and substrate connections. This is an intermediate step to switching from a sim file format to an ext file format for input, but resolves the worst issues of having the sim file not recognize the devices or the substrate nodes. Implemented by using the sim subcircuit format introduced in IRSIM with the "user subcircuit" package. Implementation unfinished (work in progress). --- ext2sim/ext2sim.c | 58 +++++++++++++++++- resis/ResReadSim.c | 147 ++++++++++++++++++++++++++++++++++++++++++--- resis/ResRex.c | 4 +- resis/resis.h | 3 + 4 files changed, 200 insertions(+), 12 deletions(-) diff --git a/ext2sim/ext2sim.c b/ext2sim/ext2sim.c index 35b28c05..e40148b7 100644 --- a/ext2sim/ext2sim.c +++ b/ext2sim/ext2sim.c @@ -999,11 +999,12 @@ simdevVisit(dev, hc, scale, trans) float scale; /* Scale transform for output */ Transform *trans; /* Coordinate transform */ { - DevTerm *gate, *source, *drain; + DevTerm *gate, *source, *drain, *term; EFNode *subnode, *snode, *dnode; int l, w; Rect r; char name[12]; + bool is_subckt = FALSE; HierName *hierName = hc->hc_hierName; sprintf(name, "output"); @@ -1057,7 +1058,6 @@ simdevVisit(dev, hc, scale, trans) case DEV_FET: case DEV_MOSFET: case DEV_ASYMMETRIC: - case DEV_MSUBCKT: /* The sim file format only understands "n" and "p" for FETs. */ /* The extraction method says nothing about which is which. */ /* The EFDevTypes[] should ideally start with "n" or "p". If */ @@ -1089,6 +1089,19 @@ simdevVisit(dev, hc, scale, trans) } } break; + case DEV_MSUBCKT: + case DEV_CSUBCKT: + case DEV_RSUBCKT: + case DEV_SUBCKT: + /* Use the 'x' type in .sim format. This is implemented in the */ + /* IRSIM "user subcircuit" package, so it has a valid syntax. */ + /* It is used by the extresist code in magic as a way to work */ + /* around the lack of substrate and lack of device names in the */ + /* .sim format. */ + is_subckt = TRUE; + fprintf(esSimF, "x"); + break; + default: fprintf(esSimF, "%c", EFDevTypes[dev->dev_type][0]); break; @@ -1121,8 +1134,31 @@ simdevVisit(dev, hc, scale, trans) else if (dev->dev_nterm > 2) simdevOutNode(hierName, drain->dterm_node->efnode_name->efnn_hier, name, esSimF); + if (dev->dev_nterm > 3) /* For subcircuit support ('x' device) */ + { + int i; + + sprintf(name, "subckt"); + for (i = 3; i < dev->dev_nterm; i++) + { + term = &dev->dev_terms[i]; + simdevOutNode(hierName, term->dterm_node->efnode_name->efnn_hier, + name, esSimF); + } + } + + if (is_subckt && subnode) + { + /* As a general policy on subcircuits supporting extresist, */ + /* output the subcircuit node as the last port of the */ + /* subcircuit definition. */ + putc(' ', esSimF); + simdevSubstrate(hierName, subnode->efnode_name->efnn_hier, + dev->dev_type, 0.0, FALSE, esSimF); + } + /* Support gemini's substrate comparison */ - if (esFormat == LBL && subnode) + else if (esFormat == LBL && subnode) { putc(' ', esSimF); simdevSubstrate(hierName, subnode->efnode_name->efnn_hier, @@ -1165,6 +1201,15 @@ simdevVisit(dev, hc, scale, trans) else if (dev->dev_class == DEV_CAPREV) { /* generate a capacitor */ fprintf(esSimF, " %f", (double)(dev->dev_cap)); } + else if (is_subckt) + { + /* Output length, width, and position as attributes */ + fprintf(esSimF, " l=%g w=%g x=%g y=%g", + l * scale, w * scale, r.r_xbot * scale, r.r_ybot * scale); + + /* Output tile type as an attribute for quick lookup by ResReadSim */ + fprintf(esSimF, " t=%d", fetInfo[dev->dev_type].devType); + } else if ((dev->dev_class != DEV_DIODE) && (dev->dev_class != DEV_PDIODE) && (dev->dev_class != DEV_NDIODE)) { @@ -1235,6 +1280,13 @@ simdevVisit(dev, hc, scale, trans) } } } + + if (is_subckt) + { + /* Last token on a subcircuit 'x' line is the subcircuit name */ + fprintf(esSimF, " %s", EFDevTypes[dev->dev_type]); + } + fprintf(esSimF, "\n"); return 0; diff --git a/resis/ResReadSim.c b/resis/ResReadSim.c index 8c040e48..e2bfc2b5 100644 --- a/resis/ResReadSim.c +++ b/resis/ResReadSim.c @@ -27,12 +27,13 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include "textio/textio.h" #include "extract/extract.h" #include "extract/extractInt.h" +#include "extflat/extflat.h" #include "windows/windows.h" #include "dbwind/dbwind.h" #include "utils/utils.h" #include "utils/tech.h" #include "textio/txcommands.h" -#include "resis/resis.h" +#include "resis/resis.h" /* constants defining where various fields can be found in .sim files. */ @@ -119,10 +120,10 @@ extern void ResSimProcessDrivePoints(); */ int -ResReadSim(simfile,fetproc,capproc,resproc,attrproc,mergeproc) +ResReadSim(simfile, fetproc, capproc, resproc, attrproc, mergeproc, subproc) char *simfile; - int (*fetproc)(),(*capproc)(),(*resproc)(); - int (*attrproc)(),(*mergeproc)(); + int (*fetproc)(), (*capproc)(), (*resproc)(); + int (*attrproc)(), (*mergeproc)(), (*subproc)(); { char line[MAXLINE][MAXTOKEN]; @@ -172,6 +173,8 @@ ResReadSim(simfile,fetproc,capproc,resproc,attrproc,mergeproc) line[ATTRIBUTEVALUE], simfile, &extfile); break; + case 'x': fettype = DBNumTypes; + break; case 'D': case 'c': case 'r': break; @@ -184,6 +187,10 @@ ResReadSim(simfile,fetproc,capproc,resproc,attrproc,mergeproc) TxError("Error in Reading device line of sim file.\n"); result = 1; } + else if (fettype == DBNumTypes) + { + result = (*subproc)(line); + } else if (fettype != MINFINITY) { float sheetr; @@ -317,6 +324,130 @@ gettokens(line,fp) } +/* + *------------------------------------------------------------------------- + * + * ResSimSubckt-- Processes a subcircuit line from a sim file. + * This uses the "user subcircuit" extension defined in + * IRSIM, although it is mostly intended as a way to work + * around the device type limitations of the .sim format + * when using extresist. + * + * Results: returns 0 if line was added correctly. + * + * Side Effects: Allocates devices and adds nodes to the node hash table. + * + *------------------------------------------------------------------------- + */ + +int +ResSimSubckt(line) + char line[][MAXTOKEN]; +{ + RDev *device; + int rvalue, i, j, k; + static int nowarning = TRUE; + float lambda; + TileType ttype = TT_SPACE; + char *lptr = NULL, *wptr = NULL; + + device = (RDev *) mallocMagic((unsigned) (sizeof(RDev))); + + device->status = FALSE; + device->nextDev = ResRDevList; + + lambda = (float)ExtCurStyle->exts_unitsPerLambda / resscale; + device->location.p_x = 0; + device->location.p_y = 0; + + device->rs_gattr=RDEV_NOATTR; + device->rs_sattr=RDEV_NOATTR; + device->rs_dattr=RDEV_NOATTR; + + ResRDevList = device; + device->layout = NULL; + + /* The last argument is the name of the device */ + for (i = 1; line[i][0] != '\0'; i++); + i--; + + for (j = 0; j < EFDevNumTypes; j++) + if (!strcmp(EFDevTypes[j], line[i])) + break; + + /* Read attributes, especially to pick up values for L, W, X, and Y, + * that are critical for use by extresist. + */ + for (k = 1; line[k][0] != '\0'; k++) + { + char *eqptr; + eqptr = strchr(line[k], '='); + if (eqptr != NULL) + { + if (k < i) i = k; + eqptr++; + switch (line[k][0]) { + case 'l': + lptr = eqptr; + break; + case 'w': + wptr = eqptr; + break; + case 'x': + device->location.p_x = (int)((float)atof(eqptr) / lambda); + break; + case 'y': + device->location.p_y = (int)((float)atof(eqptr) / lambda); + break; + case 't': + ttype = (int)(atoi(eqptr)); + break; + } + } + } + + /* This should not be needed, as ext2sim should encode device type */ + /* in the attributes list. */ + if (ttype == TT_SPACE) + { + if (j == EFDevNumTypes) + { + TxError("Failure to find device type %s\n", line[i]); + return 1; + } + ttype = extGetDevType(EFDevTypes[j]); + } + + device->rs_ttype = ttype; + + if (lptr != NULL && wptr != NULL) + { + float rpersquare; + ExtDevice *devptr; + + devptr = ExtCurStyle->exts_device[ttype]; + rpersquare =(float)devptr->exts_linearResist; + device->resistance = MagAtof(lptr) * rpersquare/MagAtof(wptr); + } + else + device->resistance = 0; + + rvalue = 0; + for (k = 1; k < i; k++) + { + if (k > SUBS) + { + TxError("Device %s has more than 4 ports (not handled).\n", line[i]); + break; /* No method to handle more ports than this */ + } + rvalue += ResSimNewNode(line[k], k, device); + } + + return rvalue; +} + + + /* *------------------------------------------------------------------------- * @@ -330,7 +461,7 @@ gettokens(line,fp) */ int -ResSimDevice(line,rpersquare,ttype) +ResSimDevice(line, rpersquare, ttype) char line[][MAXTOKEN]; float rpersquare; TileType ttype; @@ -428,7 +559,7 @@ ResSimDevice(line,rpersquare,ttype) */ int -ResSimNewNode(line,type,device) +ResSimNewNode(line, type, device) char line[]; int type; RDev *device; @@ -443,7 +574,7 @@ ResSimNewNode(line,type,device) TxError("Missing device connection\n"); return(1); } - entry = HashFind(&ResNodeTable,line); + entry = HashFind(&ResNodeTable, line); node = ResInitializeNode(entry); tptr = (devPtr *) mallocMagic((unsigned) (sizeof(devPtr))); tptr->thisDev = device; @@ -458,6 +589,8 @@ ResSimNewNode(line,type,device) break; case DRAIN: device->drain = node; break; + case SUBS: device->subs = node; + break; default: TxError("Bad Terminal Specifier\n"); break; } diff --git a/resis/ResRex.c b/resis/ResRex.c index 1fb8f4a8..bde291e2 100644 --- a/resis/ResRex.c +++ b/resis/ResRex.c @@ -105,8 +105,8 @@ ExtResisForDef(celldef, resisdata) HashInit(&ResNodeTable, INITFLATSIZE, HT_STRINGKEYS); /* read in .sim file */ result = (ResReadSim(celldef->cd_name, - ResSimDevice,ResSimCapacitor,ResSimResistor, - ResSimAttribute,ResSimMerge) == 0); + ResSimDevice, ResSimCapacitor, ResSimResistor, + ResSimAttribute, ResSimMerge, ResSimSubckt) == 0); if (result) /* read in .nodes file */ diff --git a/resis/resis.h b/resis/resis.h index cadf28cc..9507df0f 100644 --- a/resis/resis.h +++ b/resis/resis.h @@ -293,6 +293,7 @@ typedef struct rdev struct ressimnode *gate; /* Terminals of transistor. */ struct ressimnode *source; struct ressimnode *drain; + struct ressimnode *subs; /* Used with subcircuit type only */ Point location; /* Location of lower left point of */ /* device. */ float resistance; /* "Resistance" of device. */ @@ -519,6 +520,7 @@ typedef struct capval #define GATE 1 #define SOURCE 2 #define DRAIN 3 +#define SUBS 4 #define DRIVEONLY 0x00001000 #define ORIGIN 0x00000008 @@ -610,6 +612,7 @@ extern int ResSimCapacitor(); extern int ResSimResistor(); extern int ResSimAttribute(); extern int ResSimMerge(); +extern int ResSimSubckt(); extern int dbSrConnectStartFunc(); extern int ResEach(),ResAddPlumbing(),ResRemovePlumbing(); extern float ResCalculateChildCapacitance(); From 59fc24729c64033fedec7d73453bb8d9f5556d67 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 21 Apr 2021 13:03:26 -0400 Subject: [PATCH 76/89] Corrected issues in the extresist function found after the previous commit, mostly relating to the scale of values in the ".nodes" file produced by ext2sim. Making this file CIF syntax seemed unnecessary, so I removed the CIF syntax and scaling. "extresist" can now produce an apparently valid output on a standard cell layout. Even with the change, the extresist output is still only pseudo-hierarchical, so this does not preclude the need for eliminating the .sim format file in favor of the .ext file, but it provides a working intermediate form. --- VERSION | 2 +- database/DBconnect.c | 61 +++------------------ database/database.h.in | 52 ++++++++++++++++++ ext2sim/ext2sim.c | 3 +- extflat/EFflat.c | 14 ----- resis/ResConDCS.c | 26 --------- resis/ResMain.c | 44 +++++++-------- resis/ResReadSim.c | 34 +++++------- resis/ResRex.c | 119 +++++++++++++++++------------------------ router/rtrTravers.c | 20 ------- sim/SimDBstuff.c | 51 +----------------- 11 files changed, 142 insertions(+), 284 deletions(-) diff --git a/VERSION b/VERSION index a7015476..0b32410c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.155 +8.3.156 diff --git a/database/DBconnect.c b/database/DBconnect.c index 950c8d45..1b665473 100644 --- a/database/DBconnect.c +++ b/database/DBconnect.c @@ -45,55 +45,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ * is used to clear the markings again. */ -/* The following structure is used to hold several pieces - * of information that must be passed through multiple - * levels of search function (used by dbSrConnectFunc). - */ - -struct conSrArg -{ - CellDef *csa_def; /* Definition being searched. */ - int csa_plane; /* Index of current plane being searched. */ - TileTypeBitMask *csa_connect; /* Table indicating what connects - * to what. - */ - int (*csa_clientFunc)(); /* Client function to call. */ - ClientData csa_clientData; /* Argument for clientFunc. */ - bool csa_clear; /* FALSE means pass 1, TRUE - * means pass 2. - */ - Rect csa_bounds; /* Area that limits search. */ -}; - -/* The following structure is used to hold several pieces - * of information that must be passed through multiple - * levels of search function (used by dbcConnectFunc). - */ - -typedef struct -{ - Rect area; /* Area to process */ - TileTypeBitMask *connectMask; /* Connection mask for search */ - TileType dinfo; /* Info about triangular search areas */ -} conSrArea; - -struct conSrArg2 -{ - CellUse *csa2_use; /* Destination use */ - TileTypeBitMask *csa2_connect; /* Table indicating what connects - * to what. - */ - SearchContext *csa2_topscx; /* Original top-level search context */ - Rect *csa2_bounds; /* Area that limits the search */ - - Stack *csa2_stack; /* Stack of full csa2_list entries */ - conSrArea *csa2_list; /* List of areas to process */ - int csa2_top; /* Index of next area to process */ - int csa2_lasttop; /* Previous top index */ -}; - -#define CSA2_LIST_SIZE 65536 /* Number of entries per list */ - /* *----------------------------------------------------------------- * DBTransformDiagonal -- @@ -257,6 +208,7 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData) startTile = NULL; for (startPlane = PL_TECHDEPBASE; startPlane < DBNumPlanes; startPlane++) { + csa.csa_pNum = startPlane; if (DBSrPaintArea((Tile *) NULL, def->cd_planes[startPlane], startArea, mask, dbSrConnectStartFunc, (ClientData) &startTile) != 0) break; @@ -272,7 +224,6 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData) csa.csa_clientData = clientData; csa.csa_clear = FALSE; csa.csa_connect = connect; - csa.csa_plane = startPlane; if (dbSrConnectFunc(startTile, &csa) != 0) result = 1; /* Pass 2. Don't call any client function, just clear the marks. @@ -282,7 +233,6 @@ DBSrConnect(def, startArea, mask, connect, bounds, func, clientData) SigDisableInterrupts(); csa.csa_clientFunc = NULL; csa.csa_clear = TRUE; - csa.csa_plane = startPlane; (void) dbSrConnectFunc(startTile, &csa); SigEnableInterrupts(); @@ -348,6 +298,7 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData) startTile = NULL; for (startPlane = PL_TECHDEPBASE; startPlane < DBNumPlanes; startPlane++) { + csa.csa_pNum = startPlane; if (DBSrPaintArea((Tile *) NULL, def->cd_planes[startPlane], startArea, mask, dbSrConnectStartFunc, (ClientData) &startTile) != 0) break; @@ -363,7 +314,6 @@ DBSrConnectOnePass(def, startArea, mask, connect, bounds, func, clientData) csa.csa_clientData = clientData; csa.csa_clear = FALSE; csa.csa_connect = connect; - csa.csa_plane = startPlane; if (dbSrConnectFunc(startTile, &csa) != 0) result = 1; return result; @@ -436,7 +386,7 @@ dbSrConnectFunc(tile, csa) if (csa->csa_clientFunc != NULL) { - if ((*csa->csa_clientFunc)(tile, csa->csa_plane, csa->csa_clientData) != 0) + if ((*csa->csa_clientFunc)(tile, csa->csa_pNum, csa->csa_clientData) != 0) return 1; } @@ -579,7 +529,7 @@ donesides: */ planes = DBConnPlanes[loctype]; - planes &= ~(PlaneNumToMaskBit(csa->csa_plane)); + planes &= ~(PlaneNumToMaskBit(csa->csa_pNum)); if (planes != 0) { struct conSrArg newcsa; @@ -591,7 +541,7 @@ donesides: for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++) { if (!PlaneMaskHasPlane(planes, i)) continue; - newcsa.csa_plane = i; + newcsa.csa_pNum = i; if (IsSplit(tile)) { if (DBSrPaintNMArea((Tile *) NULL, csa->csa_def->cd_planes[i], @@ -786,6 +736,7 @@ dbcConnectLabelFunc(scx, lab, tpath, csa2) sizeof(conSrArea)); StackPush((ClientData)csa2->csa2_list, csa2->csa2_stack); csa2->csa2_list = newlist; + csa2->csa2_top = 0; } csa2->csa2_list[csa2->csa2_top].area = newarea; diff --git a/database/database.h.in b/database/database.h.in index 6a2f25d3..646882f6 100644 --- a/database/database.h.in +++ b/database/database.h.in @@ -33,6 +33,10 @@ #include "utils/hash.h" #endif /* _HASH_H */ +#ifndef _STACK_H +#include "utils/stack.h" +#endif /* _STACK_H */ + #ifndef _BPLANE_H #include "bplane/bplane.h" #endif /* _BPLANE_H */ @@ -658,6 +662,54 @@ typedef struct treeFilter /* To do: Make the tpath entries dynamically allocated */ #define FLATTERMSIZE 4096 /* Used for generating flattened labels */ +/* ------------ Information used in connectivity searches --------------*/ + +/* The following structure is used to hold several pieces of information + * that must be passed through multiple levels of search function. This + * structure is used by DBSrConnect, DBTreeCopyConnect, SimTreeCopyConnect, + * and DBTreeCopyConnectDCS. + */ + +struct conSrArg +{ + CellDef *csa_def; /* Definition being searched. */ + int csa_pNum; /* Index of plane being searched */ + TileTypeBitMask *csa_connect; /* Table indicating what connects + * to what. + */ + int (*csa_clientFunc)(); /* Client function to call. */ + ClientData csa_clientData; /* Argument for clientFunc. */ + bool csa_clear; /* FALSE means pass 1, TRUE + * means pass 2. + */ + Rect csa_bounds; /* Area that limits search. */ +}; + +typedef struct +{ + Rect area; /* Area to process */ + TileTypeBitMask *connectMask; /* Connection mask for search */ + TileType dinfo; /* Info about triangular search areas */ +} conSrArea; + +struct conSrArg2 +{ + CellUse *csa2_use; /* Destination use */ + TileTypeBitMask *csa2_connect; /* Table indicating what connects + * to what. + */ + SearchContext *csa2_topscx; /* Original top-level search context */ + int csa2_xMask; /* Cell window mask for search */ + Rect *csa2_bounds; /* Area that limits the search */ + + Stack *csa2_stack; /* Stack of full csa2_list entries */ + conSrArea *csa2_list; /* List of areas to process */ + int csa2_top; /* Index of next area to process */ + int csa2_lasttop; /* Previous top index */ +}; + +#define CSA2_LIST_SIZE 65536 /* Number of entries per list */ + /* -------------- Undo information passed to DBPaintPlane ------------- */ typedef struct diff --git a/ext2sim/ext2sim.c b/ext2sim/ext2sim.c index e40148b7..ce0ad59b 100644 --- a/ext2sim/ext2sim.c +++ b/ext2sim/ext2sim.c @@ -1624,9 +1624,8 @@ int simnodeVisit(node, res, cap) if (esLabF) { - fprintf(esLabF, "94 "); EFHNOut(hierName, esLabF); - fprintf(esLabF, " %d %d %s;\n", + fprintf(esLabF, " %d %d %s\n", node->efnode_loc.r_xbot, node->efnode_loc.r_ybot, EFLayerNames[node->efnode_type]); } diff --git a/extflat/EFflat.c b/extflat/EFflat.c index 463b196e..95c80bb0 100644 --- a/extflat/EFflat.c +++ b/extflat/EFflat.c @@ -440,12 +440,10 @@ efAddNodes(hc, stdcell) EFNode *node, *newnode; EFAttr *ap, *newap; HierName *hierName; - float scale; int size, asize; HashEntry *he; bool is_subcircuit = (def->def_flags & DEF_SUBCIRCUIT) ? TRUE : FALSE; - scale = def->def_scale; size = sizeof (EFNode) + (efNumResistClasses-1) * sizeof (EFPerimArea); for (node = (EFNode *) def->def_firstn.efnode_next; @@ -464,10 +462,6 @@ efAddNodes(hc, stdcell) newap = (EFAttr *) mallocMagic((unsigned)(asize)); (void) strcpy(newap->efa_text, ap->efa_text); GeoTransRect(&hc->hc_trans, &ap->efa_loc, &newap->efa_loc); - newap->efa_loc.r_xbot = (int)((float)(newap->efa_loc.r_xbot) * scale); - newap->efa_loc.r_xtop = (int)((float)(newap->efa_loc.r_xtop) * scale); - newap->efa_loc.r_ybot = (int)((float)(newap->efa_loc.r_ybot) * scale); - newap->efa_loc.r_ytop = (int)((float)(newap->efa_loc.r_ytop) * scale); newap->efa_type = ap->efa_type; newap->efa_next = newnode->efnode_attrs; @@ -490,14 +484,6 @@ efAddNodes(hc, stdcell) efNumResistClasses * sizeof (EFPerimArea)); GeoTransRect(&hc->hc_trans, &node->efnode_loc, &newnode->efnode_loc); - /* Scale the result by "scale" --- hopefully we end up with an integer */ - /* We don't scale the transform because the scale may be non-integer */ - /* and the Transform type has integers only. */ - newnode->efnode_loc.r_xbot = (int)((float)(newnode->efnode_loc.r_xbot) * scale); - newnode->efnode_loc.r_xtop = (int)((float)(newnode->efnode_loc.r_xtop) * scale); - newnode->efnode_loc.r_ybot = (int)((float)(newnode->efnode_loc.r_ybot) * scale); - newnode->efnode_loc.r_ytop = (int)((float)(newnode->efnode_loc.r_ytop) * scale); - /* Add each name for this node to the hash table */ newnode->efnode_name = (EFNodeName *) NULL; diff --git a/resis/ResConDCS.c b/resis/ResConDCS.c index c8591f97..c1cca55b 100644 --- a/resis/ResConDCS.c +++ b/resis/ResConDCS.c @@ -30,31 +30,6 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include "textio/txcommands.h" #include "resis/resis.h" -typedef struct -{ - Rect area; /* Area to process */ - TileTypeBitMask *connectMask; /* Connection mask for search */ - TileType dinfo; /* Info about triangular search areas */ -} conSrArea; - -struct conSrArg2 -{ - CellUse *csa2_use; /* Destination use */ - TileTypeBitMask *csa2_connect; /* Table indicating what connects - * to what. - */ - SearchContext *csa2_topscx; /* Original top-level search context */ - int csa2_xMask; /* Cell window mask for search */ - Rect *csa2_bounds; /* Area that limits the search */ - - Stack *csa2_stack; /* Stack of full csa2_list entries */ - conSrArea *csa2_list; /* List of areas to process */ - int csa2_top; /* Index of next area to process */ - int csa2_lasttop; /* Previous top index */ -}; - -#define CSA2_LIST_SIZE 65536 /* Number of entries per list */ - extern int dbcUnconnectFunc(); extern int dbcConnectLabelFunc(); extern int dbcConnectFuncDCS(); @@ -69,7 +44,6 @@ TileTypeBitMask ResSubsTypeBitMask; /* Forward declarations */ extern void ResCalcPerimOverlap(); - /* * ---------------------------------------------------------------------------- * diff --git a/resis/ResMain.c b/resis/ResMain.c index f1e65a47..e89816da 100644 --- a/resis/ResMain.c +++ b/resis/ResMain.c @@ -37,10 +37,10 @@ resNode *ResNodeQueue=NULL; /* Pending nodes */ resNode *ResOriginNode=NULL; /* node where R=0 */ resNode *resCurrentNode; int ResTileCount=0; /* Number of tiles rn_status */ -extern Region *ResFirst(); +extern Region *ResFirst(); extern Tile *FindStartTile(); -extern int ResEachTile(); -extern int ResLaplaceTile(); +extern int ResEachTile(); +extern int ResLaplaceTile(); extern ResSimNode *ResInitializeNode(); extern HashTable ResNodeTable; @@ -561,19 +561,18 @@ ResProcessTiles(goodies, origin) * * Side effects: Produces a resistance network for the node. * - * *------------------------------------------------------------------------- */ bool -ResExtractNet(startlist,goodies,cellname) +ResExtractNet(startlist, goodies, cellname) ResFixPoint *startlist; ResGlobalParams *goodies; char *cellname; { SearchContext scx; int pNum; - ResDevTile *DevTiles,*lasttile; + ResDevTile *DevTiles, *lasttile; TileTypeBitMask FirstTileMask; Point startpoint; ResFixPoint *fix; @@ -581,10 +580,10 @@ ResExtractNet(startlist,goodies,cellname) /* Make sure all global network variables are reset */ - ResResList=NULL; - ResNodeList=NULL; - ResDevList=NULL; - ResNodeQueue=NULL; + ResResList = NULL; + ResNodeList = NULL; + ResDevList = NULL; + ResNodeQueue = NULL; ResContactList = NULL; ResOriginNode = NULL; @@ -630,17 +629,16 @@ ResExtractNet(startlist,goodies,cellname) DBCellClearDef(ResUse->cu_def); - - /* Copy Paint */ + /* Copy Paint */ DevTiles = NULL; lasttile = NULL; - for (fix = startlist; fix != NULL;fix=fix->fp_next) + for (fix = startlist; fix != NULL; fix = fix->fp_next) { - ResDevTile *newdevtiles,*tmp; + ResDevTile *newdevtiles, *tmp; #ifdef ARIEL if ((ResOptionsFlags & ResOpt_Power) && - strcmp(fix->fp_name,goodies->rg_name) != 0) continue; + strcmp(fix->fp_name, goodies->rg_name) != 0) continue; #endif scx.scx_area.r_ll.p_x = fix->fp_loc.p_x-2; @@ -649,10 +647,10 @@ ResExtractNet(startlist,goodies,cellname) scx.scx_area.r_ur.p_y = fix->fp_loc.p_y+2; startpoint = fix->fp_loc; - // Because fix->fp_ttype might come from a label with a sticky type - // that does not correspond exactly to the layer underneath, include - // all connecting types. - /* TTMaskSetOnlyType(&FirstTileMask,fix->fp_ttype); */ + /* Because fix->fp_ttype might come from a label with a sticky type + * that does not correspond exactly to the layer underneath, include + * all connecting types. + */ TTMaskSetMask(&FirstTileMask, &DBConnectTbl[fix->fp_ttype]); newdevtiles = DBTreeCopyConnectDCS(&scx, &FirstTileMask, 0, @@ -662,13 +660,9 @@ ResExtractNet(startlist,goodies,cellname) if (newdevtiles) { if (DevTiles) - { lasttile->nextDev = newdevtiles; - } else - { DevTiles = newdevtiles; - } lasttile = tmp; } } @@ -682,7 +676,7 @@ ResExtractNet(startlist,goodies,cellname) &DBAllButSpaceAndDRCBits, ResConnectWithSD, extUnInit, ResFirst, ResEach); - ExtResetTiles(ResUse->cu_def,extUnInit); + ExtResetTiles(ResUse->cu_def, extUnInit); /* * dissolve the contacts and find which tiles now cover the point @@ -697,7 +691,7 @@ ResExtractNet(startlist,goodies,cellname) { Plane *plane = ResUse->cu_def->cd_planes[pNum]; Rect *rect = &ResUse->cu_def->cd_bbox; - ResFracture(plane,rect); + ResFracture(plane, rect); (void) DBSrPaintClient((Tile *) NULL,plane,rect, &DBAllButSpaceAndDRCBits, (ClientData) CLIENTDEFAULT, ResAddPlumbing, diff --git a/resis/ResReadSim.c b/resis/ResReadSim.c index e2bfc2b5..cb663a0b 100644 --- a/resis/ResReadSim.c +++ b/resis/ResReadSim.c @@ -50,11 +50,10 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #define COUPLEVALUE 3 #define REALNAME 1 #define ALIASNAME 2 -#define NODECIFCOMMAND 0 -#define NODENODENAME 1 -#define NODENODEX 2 -#define NODENODEY 3 -#define NODETYPE 4 +#define NODES_NODENAME 0 +#define NODES_NODEX 1 +#define NODES_NODEY 2 +#define NODES_NODETYPE 3 #define NODE_BBOX_LL_X 5 #define NODE_BBOX_LL_Y 6 #define NODE_BBOX_UR_X 7 @@ -236,13 +235,6 @@ ResReadNode(nodefile) char *cp; float lambda; - /* NOTE: Units from the .nodes file are in centimicrons. - * Divide by the extract scale (exts_unitsPerLambda) to get back - * to database units. This assumes that exts_unitsPerLambda doesn't - * change between output and readback. - */ - lambda = (float)ExtCurStyle->exts_unitsPerLambda; - fp = PaOpen(nodefile,"r",".nodes",".", (char *) NULL, (char **) NULL); if (fp == NULL) { @@ -251,19 +243,19 @@ ResReadNode(nodefile) } while (gettokens(line,fp) != 0) { - entry = HashFind(&ResNodeTable,line[NODENODENAME]); + entry = HashFind(&ResNodeTable,line[NODES_NODENAME]); node = ResInitializeNode(entry); - node->location.p_x = (int)((float)atof(line[NODENODEX]) / lambda); - node->location.p_y = (int)((float)atof(line[NODENODEY]) / lambda); + node->location.p_x = atoi(line[NODES_NODEX]); + node->location.p_y = atoi(line[NODES_NODEY]); #ifdef ARIEL - node->rs_bbox.r_xbot = (int)((float)atof(line[NODE_BBOX_LL_X]) / lambda); - node->rs_bbox.r_ybot = (int)((float)atof(line[NODE_BBOX_LL_Y]) / lambda); - node->rs_bbox.r_xtop = (int)((float)atof(line[NODE_BBOX_UR_X]) / lambda); - node->rs_bbox.r_ytop = (int)((float)atof(line[NODE_BBOX_UR_Y]) / lambda); + node->rs_bbox.r_xbot = atoi(line[NODE_BBOX_LL_X]); + node->rs_bbox.r_ybot = atoi(line[NODE_BBOX_LL_Y]); + node->rs_bbox.r_xtop = atoi(line[NODE_BBOX_UR_X]); + node->rs_bbox.r_ytop = atoi(line[NODE_BBOX_UR_Y]); #endif - if (cp = strchr(line[NODETYPE], ';')) *cp = '\0'; - node->type = DBTechNameType(line[NODETYPE]); + if (cp = strchr(line[NODES_NODETYPE], ';')) *cp = '\0'; + node->type = DBTechNameType(line[NODES_NODETYPE]); if (node->type == -1) { diff --git a/resis/ResRex.c b/resis/ResRex.c index bde291e2..ea4d7bb5 100644 --- a/resis/ResRex.c +++ b/resis/ResRex.c @@ -37,9 +37,9 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ /* Time constants are produced by multiplying attofarads by milliohms, */ /* giving zeptoseconds (yes, really. Look it up). This constant */ -/* converts zeptoseconds to nanoseconds. */ +/* converts zeptoseconds to picoseconds. */ -#define Z_TO_N 1e12 +#define Z_TO_P 1e9 /* ResSimNode is a node read in from a sim file */ @@ -766,12 +766,12 @@ ResCheckPorts(cellDef) result = 0; if ((node = (ResSimNode *) HashGetValue(entry)) != NULL) { - TxError("Port: name = %s exists, forcing drivepoint\n", + TxPrintf("Port: name = %s exists, forcing drivepoint\n", lab->lab_text); - TxError("Location is (%d, %d); drivepoint (%d, %d)\n", + TxPrintf("Location is (%d, %d); drivepoint (%d, %d)\n", node->location.p_x, node->location.p_y, portloc.p_x, portloc.p_y); - TxFlushErr(); + TxFlush(); node->drivepoint = portloc; node->status |= FORCE; } @@ -782,9 +782,9 @@ ResCheckPorts(cellDef) /* and a drivepoint. */ node = ResInitializeNode(entry); - TxError("Port: name = %s is new node 0x%x\n", + TxPrintf("Port: name = %s is new node 0x%x\n", lab->lab_text, node); - TxError("Location is (%d, %d); drivepoint (%d, %d)\n", + TxPrintf("Location is (%d, %d); drivepoint (%d, %d)\n", portloc.p_x, portloc.p_y, portloc.p_x, portloc.p_y); node->location = portloc; @@ -1111,37 +1111,33 @@ ResCheckSimNodes(celldef, resisdata) if (total) { - TxError("Total Nets: %d\nNets extracted: " + TxPrintf("Total Nets: %d\nNets extracted: " "%d (%f)\nNets output: %d (%f)\n", total, failed1, (float)failed1 / (float)total, failed3, (float)failed3 / (float)total); } else { - TxError("Total Nodes: %d\n",total); + TxPrintf("Total Nodes: %d\n",total); } /* close output files */ if (ResExtFile != NULL) - { (void) fclose(ResExtFile); - } + if (ResLumpFile != NULL) - { (void) fclose(ResLumpFile); - } + if (ResFHFile != NULL) - { (void) fclose(ResFHFile); - } } /* *------------------------------------------------------------------------- * - * ResFixUpConnections-- Changes the connection to a terminal of the sim + * ResFixUpConnections-- Changes the connection to a terminal of the sim * device. The new name is formed by appending .t# to the old name. * The new name is added to the hash table of node names. * @@ -1182,14 +1178,14 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename) { strcpy(oldnodename,nodename); } - (void)sprintf(newname,"%s%s%d",nodename,".t",resNodeNum++); + sprintf(newname, "%s%s%d", nodename, ".t", resNodeNum++); notdecremented = TRUE; if (simDev->gate == simNode) { if ((gate=layoutDev->rd_fet_gate) != NULL) { - /* cosmetic addition: If the layout device already has a */ + /* Cosmetic addition: If the layout device already has a */ /* name, the new one won't be used, so we decrement resNodeNum */ if (gate->rn_name != NULL) { @@ -1197,45 +1193,41 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename) notdecremented = FALSE; } - ResFixDevName(newname,GATE,simDev,gate); + ResFixDevName(newname, GATE, simDev, gate); gate->rn_name = simDev->gate->name; - (void)sprintf(newname,"%s%s%d",nodename,".t",resNodeNum++); + sprintf(newname, "%s%s%d", nodename, ".t", resNodeNum++); } else - { TxError("Missing gate connection\n"); - } } if (simDev->source == simNode) { if (simDev->drain == simNode) { - if ((source=layoutDev->rd_fet_source) && - (drain=layoutDev->rd_fet_drain)) + if ((source = layoutDev->rd_fet_source) && + (drain = layoutDev->rd_fet_drain)) { if (source->rn_name != NULL && notdecremented) { resNodeNum--; notdecremented = FALSE; } - ResFixDevName(newname,SOURCE,simDev,source); + ResFixDevName(newname, SOURCE, simDev, source); source->rn_name = simDev->source->name; - (void)sprintf(newname,"%s%s%d",nodename,".t",resNodeNum++); + (void)sprintf(newname, "%s%s%d", nodename, ".t", resNodeNum++); if (drain->rn_name != NULL) resNodeNum--; - ResFixDevName(newname,DRAIN,simDev,drain); + ResFixDevName(newname, DRAIN, simDev, drain); drain->rn_name = simDev->drain->name; /* one to each */ } else - { TxError("Missing SD connection\n"); - } } else { - if (source=layoutDev->rd_fet_source) + if ((source = layoutDev->rd_fet_source) != NULL) { - if (drain=layoutDev->rd_fet_drain) + if ((drain = layoutDev->rd_fet_drain) != NULL) { if (source != drain) { @@ -1256,7 +1248,7 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename) } layoutDev->rd_fet_drain = (resNode *)NULL; if (source->rn_name != NULL) resNodeNum--; - ResFixDevName(newname,SOURCE,simDev,source); + ResFixDevName(newname, SOURCE, simDev, source); source->rn_name = simDev->source->name; } else @@ -1266,22 +1258,20 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename) resNodeNum--; notdecremented = FALSE; } - ResFixDevName(newname,SOURCE,simDev,source); + ResFixDevName(newname, SOURCE, simDev, source); source->rn_name = simDev->source->name; } } else - { TxError("missing SD connection\n"); - } } } else if (simDev->drain == simNode) { - if (source=layoutDev->rd_fet_source) + if ((source = layoutDev->rd_fet_source) != NULL) { - if (drain=layoutDev->rd_fet_drain) + if ((drain = layoutDev->rd_fet_drain) != NULL) { if (drain != source) { @@ -1321,14 +1311,10 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename) } } else - { TxError("missing SD connection\n"); - } } else - { resNodeNum--; - } } @@ -1346,7 +1332,7 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename) */ void -ResFixDevName(line,type,device,layoutnode) +ResFixDevName(line, type, device, layoutnode) char line[]; int type; RDev *device; @@ -1359,13 +1345,13 @@ ResFixDevName(line,type,device,layoutnode) if (layoutnode->rn_name != NULL) { - entry = HashFind(&ResNodeTable,layoutnode->rn_name); + entry = HashFind(&ResNodeTable, layoutnode->rn_name); node = ResInitializeNode(entry); } else { - entry = HashFind(&ResNodeTable,line); + entry = HashFind(&ResNodeTable, line); node = ResInitializeNode(entry); } tptr = (devPtr *) mallocMagic((unsigned) (sizeof(devPtr))); @@ -1397,7 +1383,7 @@ ResFixDevName(line,type,device,layoutnode) /* *------------------------------------------------------------------------- * - * ResSortByGate--sorts device pointers whose terminal field is either + * ResSortByGate -- sorts device pointers whose terminal field is either * drain or source by gate node number, then by drain (source) number. * This places devices with identical connections next to one * another. @@ -1448,8 +1434,8 @@ ResSortByGate(DevpointerList) last = NULL; while (working != NULL && (current = working->nextDev) != NULL) { - RDev *w = working->thisDev; - RDev *c = current->thisDev; + RDev *w = working->thisDev; + RDev *c = current->thisDev; if (w->gate > c->gate) { @@ -1503,17 +1489,12 @@ ResSortByGate(DevpointerList) else { if (working->nextDev != NULL) - { TxError("Bad Device pointer in sort\n"); - } else - { working->nextDev = gatelist; - } } } - /* *------------------------------------------------------------------------- * @@ -1536,13 +1517,11 @@ ResWriteLumpFile(node) { if (gparams.rg_nodecap != 0) { - lumpedres = (int)((gparams.rg_Tdi/gparams.rg_nodecap - -(float)(gparams.rg_bigdevres))/OHMSTOMILLIOHMS); + lumpedres = (int)((gparams.rg_Tdi / gparams.rg_nodecap + - (float)(gparams.rg_bigdevres)) / OHMSTOMILLIOHMS); } else - { lumpedres = 0; - } } else { @@ -1636,35 +1615,35 @@ ResWriteExtFile(celldef, node, tol, rctol, nidx, eidx) RCdev = gparams.rg_bigdevres * gparams.rg_nodecap; - if (tol == 0.0 ||(node->status & FORCE) || - (ResOptionsFlags & ResOpt_ExtractAll)|| - (ResOptionsFlags & ResOpt_Simplify)==0|| - (rctol+1)*RCdev < rctol*gparams.rg_Tdi) + if (tol == 0.0 || (node->status & FORCE) || + (ResOptionsFlags & ResOpt_ExtractAll) || + (ResOptionsFlags & ResOpt_Simplify) == 0 || + (rctol + 1) * RCdev < rctol * gparams.rg_Tdi) { - ASSERT(gparams.rg_Tdi != -1,"ResWriteExtFile"); - (void)sprintf(newname,"%s",node->name); - cp = newname+strlen(newname)-1; + ASSERT(gparams.rg_Tdi != -1, "ResWriteExtFile"); + (void)sprintf(newname,"%s", node->name); + cp = newname + strlen(newname)-1; if (*cp == '!' || *cp == '#') *cp = '\0'; - if ((rctol+1)*RCdev < rctol*gparams.rg_Tdi || + if ((rctol + 1) * RCdev < rctol * gparams.rg_Tdi || (ResOptionsFlags & ResOpt_Tdi) == 0) { - if ((ResOptionsFlags & (ResOpt_RunSilent|ResOpt_Tdi)) == ResOpt_Tdi) + if ((ResOptionsFlags & (ResOpt_RunSilent | ResOpt_Tdi)) == ResOpt_Tdi) { - TxError("Adding %s; Tnew = %.2fns,Told = %.2fns\n", - node->name,gparams.rg_Tdi/Z_TO_N, RCdev/Z_TO_N); + TxPrintf("Adding %s; Tnew = %.2fns, Told = %.2fns\n", + node->name, gparams.rg_Tdi / Z_TO_P, RCdev / Z_TO_P); } } for (ptr = node->firstDev; ptr != NULL; ptr=ptr->nextDev) { if (layoutDev = ResGetDevice(&ptr->thisDev->location)) { - ResFixUpConnections(ptr->thisDev,layoutDev,node,newname); + ResFixUpConnections(ptr->thisDev, layoutDev, node, newname); } } if (ResOptionsFlags & ResOpt_DoExtFile) { - ResPrintExtNode(ResExtFile,ResNodeList,node->name); - ResPrintExtRes(ResExtFile,ResResList,newname); + ResPrintExtNode(ResExtFile, ResNodeList, node->name); + ResPrintExtRes(ResExtFile, ResResList, newname); } if (ResOptionsFlags & ResOpt_FastHenry) { diff --git a/router/rtrTravers.c b/router/rtrTravers.c index 73d00868..4aea9cc0 100644 --- a/router/rtrTravers.c +++ b/router/rtrTravers.c @@ -52,26 +52,6 @@ int rtrDelta; /* Change in layer width */ * is used to clear the markings again. */ -/* The following structure is used to hold several pieces - * of information that must be passed through multiple - * levels of search function. - */ - -struct conSrArg -{ - CellDef *csa_def; /* Definition being searched. */ - int csa_pNum; /* Index of plane being searched. */ - TileTypeBitMask *csa_connect; /* Table indicating what connects - * to what. - */ - int (*csa_clientFunc)(); /* Client function to call. */ - ClientData csa_clientData; /* Argument for clientFunc. */ - bool csa_clear; /* FALSE means pass 1, TRUE - * means pass 2. - */ - Rect csa_bounds; /* Area that limits search. */ -}; - /* * The search path is maintained on the C runtime stack * with rtrTileStack sructures. Each entry on the stack diff --git a/sim/SimDBstuff.c b/sim/SimDBstuff.c index 9fafac20..640519ef 100644 --- a/sim/SimDBstuff.c +++ b/sim/SimDBstuff.c @@ -46,55 +46,6 @@ #include "utils/styles.h" #include "graphics/graphics.h" -/* The following structure is used to hold several pieces - * of information that must be passed through multiple - * levels of search function. - */ - -struct conSrArg -{ - CellDef *csa_def; /* Definition being searched. */ - Plane *csa_plane; /* Current plane being searched. */ - TileTypeBitMask *csa_connect; /* Table indicating what connects - * to what. - */ - int (*csa_clientFunc)(); /* Client function to call. */ - ClientData csa_clientData; /* Argument for clientFunc. */ - bool csa_clear; /* FALSE means pass 1, TRUE - * means pass 2. - */ - Rect csa_bounds; /* Area that limits search. */ -}; - -/* For SimTreeSrConnect, the extraction proceeds in one pass, copying - * all connected stuff from a hierarchy into a single cell. A list - * is kept to record areas that still have to be searched for - * hierarchical stuff. - */ - -typedef struct -{ - Rect area; /* Area to process */ - TileTypeBitMask *connectMask; /* Connection mask for search */ - TileType dinfo; /* Info about triangular search areas */ -} conSrArea; - -struct conSrArg2 -{ - CellUse *csa2_use; /* Destination use */ - TileTypeBitMask *csa2_connect; /* Table indicating what connects - * to what. - */ - Rect *csa2_bounds; /* Area that limits the search */ - - Stack *csa2_stack; /* Stack of full csa2_list entries */ - conSrArea *csa2_list; /* List of areas to process */ - int csa2_top; /* Index of next area to process */ - int csa2_lasttop; /* Previous top index */ -}; - -#define CSA2_LIST_SIZE 65536 /* Number of entries per list */ - /* Forward declarations */ extern char *DBPrintUseId(); @@ -656,7 +607,7 @@ SimSrConnect(def, startArea, mask, connect, bounds, func, clientData) csa.csa_clientData = clientData; csa.csa_clear = FALSE; csa.csa_connect = connect; - csa.csa_plane = def->cd_planes[startPlane]; + csa.csa_pNum = startPlane; if (dbSrConnectFunc(startTile, &csa) != 0) result = 1; return result; From a5248a95d3b4887365faa93ace2772dc6f6e8a7b Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 21 Apr 2021 21:04:17 -0400 Subject: [PATCH 77/89] Additional correction for properly handling the substrate node when generating the device outputs in the .res.ext file, which was one of the main points of this exercise. --- resis/ResPrint.c | 5 ++++- resis/ResRex.c | 11 +++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/resis/ResPrint.c b/resis/ResPrint.c index ac385a06..17de1333 100644 --- a/resis/ResPrint.c +++ b/resis/ResPrint.c @@ -166,7 +166,10 @@ ResPrintExtDev(outextfile, devices) break; } - fprintf(outextfile, " \"%s\"", subsName); + if (devices->subs != NULL) + fprintf(outextfile, " \"%s\"", devices->subs->name); + else + fprintf(outextfile, " \"%s\"", subsName); fprintf(outextfile, " \"%s\" %d %s \"%s\" %d %s \"%s\" %d %s\n", devices->gate->name, diff --git a/resis/ResRex.c b/resis/ResRex.c index ea4d7bb5..bc67e95d 100644 --- a/resis/ResRex.c +++ b/resis/ResRex.c @@ -1165,18 +1165,17 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename) /* don't patch up networks. This cuts down on memory use. */ if ((ResOptionsFlags & (ResOpt_DoRsmFile | ResOpt_DoExtFile)) == 0) - { return; - } + if (simDev->layout == NULL) { layoutDev->rd_status |= RES_DEV_SAVE; simDev->layout = layoutDev; } simDev->status |= TRUE; - if (strcmp(nodename,oldnodename) != 0) + if (strcmp(nodename, oldnodename) != 0) { - strcpy(oldnodename,nodename); + strcpy(oldnodename, nodename); } sprintf(newname, "%s%s%d", nodename, ".t", resNodeNum++); notdecremented = TRUE; @@ -1204,8 +1203,8 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename) { if (simDev->drain == simNode) { - if ((source = layoutDev->rd_fet_source) && - (drain = layoutDev->rd_fet_drain)) + if (((source = layoutDev->rd_fet_source) != NULL) && + ((drain = layoutDev->rd_fet_drain) != NULL)) { if (source->rn_name != NULL && notdecremented) { From 6bd96a68dcacea52a3933eef70f8e336097eb875 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 22 Apr 2021 14:39:34 -0400 Subject: [PATCH 78/89] Created a method for annotating abstract views with GDS pointers. This can be done now by reading a LEF file, followed by reading a GDS file with the "noduplicates" option set. In addition, annotation of either the LEF view or a read-only view follows the same protocol as cell paths in the .mag file, which is to replace leading path components matching Tcl variables for PDKPATH or PDKROOT, and replace the home directory path with a tilde. --- VERSION | 2 +- calma/CalmaRdcl.c | 98 +++++++++++++-------- database/DBio.c | 191 ++++++++++++++++++++++------------------- database/database.h.in | 1 + 4 files changed, 168 insertions(+), 124 deletions(-) diff --git a/VERSION b/VERSION index 0b32410c..8be00eea 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.156 +8.3.157 diff --git a/calma/CalmaRdcl.c b/calma/CalmaRdcl.c index a775d821..9a379599 100644 --- a/calma/CalmaRdcl.c +++ b/calma/CalmaRdcl.c @@ -307,8 +307,8 @@ calmaParseStructure(filename) if (!calmaReadStringRecord(CALMA_STRNAME, &strname)) goto syntaxerror; TxPrintf("Reading \"%s\".\n", strname); - if (CalmaReadOnly) - filepos = ftello(calmaInputFile); + /* Used for read-only and annotated LEF views */ + filepos = ftello(calmaInputFile); /* Set up the cell definition */ he = HashFind(&calmaDefInitHash, strname); @@ -350,50 +350,74 @@ calmaParseStructure(filename) } } cifReadCellDef = calmaFindCell(strname, &was_called, &predefined); + if (predefined == TRUE) { - calmaNextCell(); - return TRUE; + bool isAbstract; + + /* If the cell was predefined, the "noduplicates" option was + * invoked, and the existing cell is an abstract view, then + * annotate the cell with the GDS file pointers to the cell + * data, and the GDS filename. + */ + DBPropGet(cifReadCellDef, "LEFview", &isAbstract); + if (!isAbstract) + { + calmaNextCell(); + return TRUE; + } + calmaSkipTo(CALMA_ENDSTR); } - DBCellClearDef(cifReadCellDef); - DBCellSetAvail(cifReadCellDef); - HashSetValue(he, cifReadCellDef); - cifCurReadPlanes = cifSubcellPlanes; - cifReadCellDef->cd_flags &= ~CDDEREFERENCE; - - /* For read-only cells, set flag in def */ - if (CalmaReadOnly) - cifReadCellDef->cd_flags |= CDVENDORGDS; - - /* Skip CALMA_STRCLASS or CALMA_STRTYPE */ - calmaSkipSet(structs); - - /* Initialize the hash table for layer errors */ - HashInit(&calmaLayerHash, 32, sizeof (CalmaLayerType) / sizeof (unsigned)); - was_initialized = TRUE; - - /* Body of structure: a sequence of elements */ - osrefs = nsrefs = 0; - npaths = 0; - calmaNonManhattan = 0; - while (calmaParseElement(filename, &nsrefs, &npaths)) + else { - if (SigInterruptPending) - goto done; - if (nsrefs > osrefs && (nsrefs % 100) == 0) - TxPrintf(" %d uses\n", nsrefs); - osrefs = nsrefs; + DBCellClearDef(cifReadCellDef); + DBCellSetAvail(cifReadCellDef); + HashSetValue(he, cifReadCellDef); + cifCurReadPlanes = cifSubcellPlanes; + cifReadCellDef->cd_flags &= ~CDDEREFERENCE; + + /* For read-only cells, set flag in def */ + if (CalmaReadOnly) + cifReadCellDef->cd_flags |= CDVENDORGDS; + + /* Skip CALMA_STRCLASS or CALMA_STRTYPE */ + calmaSkipSet(structs); + + /* Initialize the hash table for layer errors */ + HashInit(&calmaLayerHash, 32, sizeof (CalmaLayerType) / sizeof (unsigned)); + was_initialized = TRUE; + + /* Body of structure: a sequence of elements */ + osrefs = nsrefs = 0; + npaths = 0; calmaNonManhattan = 0; + + while (calmaParseElement(filename, &nsrefs, &npaths)) + { + if (SigInterruptPending) + goto done; + if (nsrefs > osrefs && (nsrefs % 100) == 0) + TxPrintf(" %d uses\n", nsrefs); + osrefs = nsrefs; + calmaNonManhattan = 0; + } } - if (CalmaReadOnly) + if (CalmaReadOnly || predefined) { + char cstring[1024]; + /* Writing the file position into a string is slow, but */ /* it prevents requiring special handling when printing */ /* out the properties. */ char *fpcopy = (char *)mallocMagic(20); - char *fncopy = StrDup(NULL, filename); + char *fncopy; + + /* Substitute variable for PDK path or ~ for home directory */ + /* the same way that cell references are handled in .mag files. */ + DBPathSubstitute(filename, cstring, cifReadCellDef); + fncopy = StrDup(NULL, cstring); sprintf(fpcopy, "%"DLONG_PREFIX"d", (dlong) filepos); DBPropPut(cifReadCellDef, "GDS_START", (ClientData)fpcopy); @@ -404,9 +428,11 @@ calmaParseStructure(filename) DBPropPut(cifReadCellDef, "GDS_FILE", (ClientData)fncopy); - /* Do not lock the cell, or else we can't save the */ - /* magic cell with its GDS pointers to disk. . . */ - /* cifReadCellDef->cd_flags |= CDNOEDIT; */ + if (predefined) + { + if (strname != NULL) freeMagic(strname); + return TRUE; + } } /* Check if the cell name matches the pattern list of cells to flatten */ diff --git a/database/DBio.c b/database/DBio.c index 2b4747bd..3bbfbec1 100644 --- a/database/DBio.c +++ b/database/DBio.c @@ -3405,6 +3405,103 @@ dbClearCellFunc(cellUse, cdarg) return 0; } +/* + * ---------------------------------------------------------------------------- + * + * DBPathSubstitute -- + * + * Replace the leading part of a file path string according to the following + * criteria: + * + * 1) If the filename starts with a string equal to the contents of + * Tcl variables PDK_PATH, PDKPATH, PDK_ROOT, or PDKROOT, then + * replace the string with the variable name. The "PATH" names are + * more specific than "ROOT" and so are checked first. + * 2) If the filename starts with a string equal to the contents of + * environment variable HOME, then replace the string with "~". + * + * Results: + * None. + * + * Side Effects: + * Writes into the string "cstring". + * + * ---------------------------------------------------------------------------- + */ + +void +DBPathSubstitute(pathstart, cstring, cellDef) + char *pathstart; + char *cstring; + CellDef *cellDef; +{ + bool subbed = FALSE; +#ifdef MAGIC_WRAPPER + char *tvar; + + /* Check for the leading component of the file path being equal to */ + /* one of several common variable names for the PDK location, and */ + /* if there is a match, then substitute the variable name for the */ + /* matching leading path component. */ + + if (subbed == FALSE) + { + tvar = (char *)Tcl_GetVar(magicinterp, "PDK_PATH", TCL_GLOBAL_ONLY); + if (tvar) + if (!strncmp(pathstart, tvar, strlen(tvar))) + { + sprintf(cstring, "$PDK_PATH%s", pathstart + strlen(tvar)); + subbed = TRUE; + } + } + if (subbed == FALSE) + { + tvar = (char *)Tcl_GetVar(magicinterp, "PDKPATH", TCL_GLOBAL_ONLY); + if (tvar) + if (!strncmp(pathstart, tvar, strlen(tvar))) + { + sprintf(cstring, "$PDKPATH%s", pathstart + strlen(tvar)); + subbed = TRUE; + } + } + if (subbed == FALSE) + { + tvar = (char *)Tcl_GetVar(magicinterp, "PDK_ROOT", TCL_GLOBAL_ONLY); + if (tvar) + if (!strncmp(pathstart, tvar, strlen(tvar))) + { + sprintf(cstring, "$PDK_ROOT%s", pathstart + strlen(tvar)); + subbed = TRUE; + } + } + if (subbed == FALSE) + { + tvar = (char *)Tcl_GetVar(magicinterp, "PDKROOT", TCL_GLOBAL_ONLY); + if (tvar) + if (!strncmp(pathstart, tvar, strlen(tvar))) + { + sprintf(cstring, "$PDKROOT%s", pathstart + strlen(tvar)); + subbed = TRUE; + } + } +#endif + + if (subbed == FALSE) + { + /* If path starts with home path, then replace with "~" */ + /* to make IP semi-portable between home directories */ + /* with the same file structure. */ + + char *homedir = getenv("HOME"); + + if (!strncmp(cellDef->cd_file, homedir, strlen(homedir)) + && (*(cellDef->cd_file + strlen(homedir)) == '/')) + sprintf(cstring, "~%s", cellDef->cd_file + strlen(homedir)); + else + sprintf(cstring, "%s", pathstart); + } +} + /* * ---------------------------------------------------------------------------- * @@ -3430,8 +3527,7 @@ dbWriteCellFunc(cellUse, cdarg) struct writeArg *arg = (struct writeArg *) cdarg; Transform *t; Rect *b; - bool subbed = FALSE; - char cstring[256], *pathend, *pathstart, *parent; + char cstring[1024], *pathend, *pathstart, *parent; t = &(cellUse->cu_transform); b = &(cellUse->cu_def->cd_bbox); @@ -3482,92 +3578,13 @@ dbWriteCellFunc(cellUse, cdarg) } else { -#ifdef MAGIC_WRAPPER - char *tvar; - - /* Check for the leading component of the file path being equal to */ - /* one of several common variable names for the PDK location, and */ - /* if there is a match, then substitute the variable name for the */ - /* matching leading path component. */ - - if (subbed == FALSE) - { - tvar = (char *)Tcl_GetVar(magicinterp, "PDK_PATH", TCL_GLOBAL_ONLY); - if (tvar) - if (!strncmp(pathstart, tvar, strlen(tvar))) - { - sprintf(cstring, "use %s %c%s $PDK_PATH%s\n", - cellUse->cu_def->cd_name, - (cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ', - cellUse->cu_id, pathstart + strlen(tvar)); - subbed = TRUE; - } - } - if (subbed == FALSE) - { - tvar = (char *)Tcl_GetVar(magicinterp, "PDKPATH", TCL_GLOBAL_ONLY); - if (tvar) - if (!strncmp(pathstart, tvar, strlen(tvar))) - { - sprintf(cstring, "use %s %c%s $PDKPATH%s\n", - cellUse->cu_def->cd_name, - (cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ', - cellUse->cu_id, pathstart + strlen(tvar)); - subbed = TRUE; - } - } - if (subbed == FALSE) - { - tvar = (char *)Tcl_GetVar(magicinterp, "PDK_ROOT", TCL_GLOBAL_ONLY); - if (tvar) - if (!strncmp(pathstart, tvar, strlen(tvar))) - { - sprintf(cstring, "use %s %c%s $PDK_ROOT%s\n", - cellUse->cu_def->cd_name, - (cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ', - cellUse->cu_id, pathstart + strlen(tvar)); - subbed = TRUE; - } - } - if (subbed == FALSE) - { - tvar = (char *)Tcl_GetVar(magicinterp, "PDKROOT", TCL_GLOBAL_ONLY); - if (tvar) - if (!strncmp(pathstart, tvar, strlen(tvar))) - { - sprintf(cstring, "use %s %c%s $PDKROOT%s\n", - cellUse->cu_def->cd_name, - (cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ', - cellUse->cu_id, pathstart + strlen(tvar)); - subbed = TRUE; - } - } -#endif - - if (subbed == FALSE) - { - /* If path starts with home path, then replace with "~" */ - /* to make IP semi-portable between home directories */ - /* with the same file structure. */ - - char *homedir = getenv("HOME"); - - if (!strncmp(cellUse->cu_def->cd_file, homedir, strlen(homedir)) - && (*(cellUse->cu_def->cd_file + strlen(homedir)) == '/')) - { - sprintf(cstring, "use %s %c%s ~%s\n", cellUse->cu_def->cd_name, - (cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ', - cellUse->cu_id, cellUse->cu_def->cd_file + - strlen(homedir)); - } - else - { - sprintf(cstring, "use %s %c%s %s\n", cellUse->cu_def->cd_name, - (cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ', - cellUse->cu_id, pathstart); - } - } + sprintf(cstring, "use %s %c%s ", cellUse->cu_def->cd_name, + (cellUse->cu_flags & CU_LOCKED) ? CULOCKCHAR : ' ', + cellUse->cu_id); + DBPathSubstitute(pathstart, cstring + strlen(cstring), cellUse->cu_def); + strcat(cstring, "\n"); } + FPRINTR(arg->wa_file, cstring); cellUse->cu_def->cd_flags |= CDVISITED; diff --git a/database/database.h.in b/database/database.h.in index 646882f6..1ef2d9fd 100644 --- a/database/database.h.in +++ b/database/database.h.in @@ -777,6 +777,7 @@ extern void DBFileRecovery(); extern bool DBWriteBackup(); extern bool DBReadBackup(); extern void DBRemoveBackup(); +extern void DBPathSubstitute(); /* Labels */ extern Label *DBPutLabel(); From 56c0620417eb555a420304fa008b5afc5dfa80fd Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 22 Apr 2021 15:39:32 -0400 Subject: [PATCH 79/89] Properly handled the yes/no argument to "cellname writeable" so that like other commands, it accepts the usual assortment of true/false, yes/no, 1/0. --- commands/CmdCD.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/commands/CmdCD.c b/commands/CmdCD.c index 0288f8e0..f4034a54 100644 --- a/commands/CmdCD.c +++ b/commands/CmdCD.c @@ -857,6 +857,9 @@ CmdCellname(w, cmd) IDX_ORIENTATION, IDX_RENAME, IDX_READWRITE, IDX_MODIFIED } optionType; + static char *cmdCellnameYesNo[] = { + "no", "false", "off", "0", "yes", "true", "on", "1", 0 }; + if (strstr(cmd->tx_argv[0], "in")) is_cellname = FALSE; else @@ -1072,7 +1075,10 @@ CmdCellname(w, cmd) } else if (locargc == 4) { - if (tolower(*cmd->tx_argv[3 + ((dolist) ? 1 : 0)]) == 't') + int subopt = Lookup(cmd->tx_argv[3 + ((dolist) ? 1 : 0)], + cmdCellnameYesNo); + if (subopt < 0) goto badusage; + else if (subopt >= 4) { /* Check if file is already read-write */ if (!(cellDef->cd_flags & CDNOEDIT)) From 0dcc9c6ca76403901e7e5b9df45d2d1f4ef69bc6 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sat, 24 Apr 2021 22:13:30 -0400 Subject: [PATCH 80/89] Corrected two potentially fatal errors: (1) Code doing the PDK_PATH and HOME substitution in filenames needs to watch for a NULL cd_file, and (2) The routine that removes the (UNNAMED) cell when another cell is loaded needs to NULL the boxRootDef pointer or else it ends up pointing to deallocated memory. --- VERSION | 2 +- database/DBcellname.c | 3 +-- database/DBio.c | 4 +++- dbwind/DBWtools.c | 25 +++++++++++++++++++++++++ dbwind/dbwind.h | 1 + 5 files changed, 31 insertions(+), 4 deletions(-) diff --git a/VERSION b/VERSION index 8be00eea..4c5af339 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.157 +8.3.158 diff --git a/database/DBcellname.c b/database/DBcellname.c index b19ad2fc..e6ee0b14 100644 --- a/database/DBcellname.c +++ b/database/DBcellname.c @@ -273,6 +273,7 @@ DBCellDelete(cellname, force) } celldef->cd_parents = (CellUse *)NULL; + DBWResetBox(celldef); result = DBCellDeleteDef(celldef); if (result == FALSE) @@ -282,8 +283,6 @@ DBCellDelete(cellname, force) return result; } - - /* * ---------------------------------------------------------------------------- * diff --git a/database/DBio.c b/database/DBio.c index 3bbfbec1..2b0e2a2f 100644 --- a/database/DBio.c +++ b/database/DBio.c @@ -3494,7 +3494,9 @@ DBPathSubstitute(pathstart, cstring, cellDef) char *homedir = getenv("HOME"); - if (!strncmp(cellDef->cd_file, homedir, strlen(homedir)) + if (cellDef->cd_file == NULL) + sprintf(cstring, "%s", pathstart); + else if (!strncmp(cellDef->cd_file, homedir, strlen(homedir)) && (*(cellDef->cd_file + strlen(homedir)) == '/')) sprintf(cstring, "~%s", cellDef->cd_file + strlen(homedir)); else diff --git a/dbwind/DBWtools.c b/dbwind/DBWtools.c index 12c5270b..31df5c9a 100644 --- a/dbwind/DBWtools.c +++ b/dbwind/DBWtools.c @@ -790,6 +790,31 @@ DBWSetBox(rootDef, rect) dbwRecordBoxArea(FALSE); } +/* + * ---------------------------------------------------------------------------- + * DBWResetBox() --- + * + * Make sure that boxRootDef is set to NULL if it is equal to the + * specified CellDef. This is used by the cell delete function to + * make sure that if an edit cell is deleted, the boxRootDef is not + * pointing to an invalid area of memory. + * + * Results: + * None. + * + * Side effects: + * Global variable boxRootDef may be set to NULL. + * + * ---------------------------------------------------------------------------- + */ + +void +DBWResetBox(CellDef *def) +{ + if (def == boxRootDef) + boxRootDef = NULL; +} + /* * ---------------------------------------------------------------------------- * ToolMoveBox -- diff --git a/dbwind/dbwind.h b/dbwind/dbwind.h index d9cabed8..f77f469f 100644 --- a/dbwind/dbwind.h +++ b/dbwind/dbwind.h @@ -189,6 +189,7 @@ extern void ToolMoveBox(), ToolMoveCorner(); extern int ToolGetCorner(); extern void DBWloadWindow(), DBWxloadWindow(); extern void DBWSetBox(); +extern void DBWResetBox(); extern void DBWUndoOldEdit(); extern void DBWUndoNewEdit(); From 538d7201e10c9a171dad7e477b6b66df733e20b2 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 26 Apr 2021 12:19:33 -0400 Subject: [PATCH 81/89] Modified the behavior of "extract" so that it does not try to check for sticky labels making connections through the hierarchy. This is only needed for some annoying layouts that put point-size labels with no connecting geometry in cells, and causes magic to spent excessive amounts of time searching through labels for any layout that has lots of labels. --- VERSION | 2 +- commands/CmdE.c | 4 ++++ extract/ExtHier.c | 26 ++------------------------ extract/extract.h | 1 + 4 files changed, 8 insertions(+), 25 deletions(-) diff --git a/VERSION b/VERSION index 4c5af339..70b3b850 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.158 +8.3.159 diff --git a/commands/CmdE.c b/commands/CmdE.c index cd6265c1..7d0c8f0e 100644 --- a/commands/CmdE.c +++ b/commands/CmdE.c @@ -880,6 +880,7 @@ cmdExpandFunc(use, windowMask) #define DOLENGTH 4 #define DOLOCAL 5 #define DORESISTANCE 6 +#define DOLABELCHECK 7 #define LENCLEAR 0 #define LENDRIVER 1 @@ -922,6 +923,7 @@ CmdExtract(w, cmd) "length compute driver-receiver pathlengths", "local put all generated files in the current directory", "resistance estimate resistance", + "labelcheck check for connections through sticky labels", NULL }; static char *cmdExtLength[] = @@ -1141,6 +1143,7 @@ CmdExtract(w, cmd) TxPrintf("%s length\n", OPTSET(EXT_DOLENGTH)); TxPrintf("%s local\n", OPTSET(EXT_DOLOCAL)); TxPrintf("%s resistance\n", OPTSET(EXT_DORESISTANCE)); + TxPrintf("%s label check\n", OPTSET(EXT_DOLABELCHECK)); return; #undef OPTSET } @@ -1169,6 +1172,7 @@ CmdExtract(w, cmd) case DOLENGTH: option = EXT_DOLENGTH; break; case DOLOCAL: option = EXT_DOLOCAL; break; case DORESISTANCE: option = EXT_DORESISTANCE; break; + case DOLABELCHECK: option = EXT_DOLABELCHECK; break; } if (no) ExtOptions &= ~option; else ExtOptions |= option; diff --git a/extract/ExtHier.c b/extract/ExtHier.c index 8e51d155..022afa67 100644 --- a/extract/ExtHier.c +++ b/extract/ExtHier.c @@ -346,6 +346,8 @@ extHierConnectFunc1(oneTile, ha) /* This allows the extractor to catch "sticky" labels that are not */ /* attached to a physical layer in the parent cell. */ + if (!(ExtOptions & EXT_DOLABELCHECK)) return 0; + // NOTE by Tim, 9/10/2014: This generates phantom nodes when the // labels are created by the "hard" node search; I think this code // should be restricted to sticky labels only. But not certain. @@ -393,31 +395,7 @@ extHierConnectFunc1(oneTile, ha) node1->node_names = node2->node_names; freeMagic((char *) node2); } - -#if 0 - /* Copy this label to the parent def with a */ - /* special flag, so we can output it as a node */ - /* and then delete it. Don't duplicate labels */ - /* that are already in the parent. */ - - for (newlab = ha->ha_parentUse->cu_def->cd_labels; - newlab; newlab = newlab->lab_next) - if (!strcmp(newlab->lab_text, lab->lab_text)) - break; - - if (newlab == NULL) - { - n = sizeof(Label) + strlen(lab->lab_text) - - sizeof lab->lab_text + 1; - newlab = (Label *)mallocMagic((unsigned)n); - bcopy((char *)lab, (char *)newlab, (int)n); - - newlab->lab_next = ha->ha_parentUse->cu_def->cd_labels; - ha->ha_parentUse->cu_def->cd_labels = newlab; - } -#endif } - } return (0); } diff --git a/extract/extract.h b/extract/extract.h index d01c9393..29988449 100644 --- a/extract/extract.h +++ b/extract/extract.h @@ -67,6 +67,7 @@ extern char *extDevTable[]; #define EXT_DOLENGTH 0x10 /* Extract pathlengths */ #define EXT_DOALL 0x1f /* ALL OF THE ABOVE */ #define EXT_DOLOCAL 0x20 /* Write to local directory only */ +#define EXT_DOLABELCHECK 0x40 /* Check for connections by label */ extern int ExtOptions; /* Bitmask of above */ From 36f9bfb16285ce7b6972b4d10bf897035a09f2a9 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 26 Apr 2021 17:00:37 -0400 Subject: [PATCH 82/89] Added exceptions to avoid processing sticky labels in two other places; this cuts extraction time by half for the example being used to test. --- extract/ExtHier.c | 2 ++ extract/ExtRegion.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/extract/ExtHier.c b/extract/ExtHier.c index 022afa67..8056a8e9 100644 --- a/extract/ExtHier.c +++ b/extract/ExtHier.c @@ -259,6 +259,8 @@ extHierConnections(ha, cumFlat, oneFlat) /* Look for sticky labels in the child cell that are not */ /* connected to any geometry. */ + if (!(ExtOptions & EXT_DOLABELCHECK)) return; + for (lab = sourceDef->cd_labels; lab; lab = lab->lab_next) { CellDef *cumDef = cumFlat->et_use->cu_def; diff --git a/extract/ExtRegion.c b/extract/ExtRegion.c index 658d272c..143407d3 100644 --- a/extract/ExtRegion.c +++ b/extract/ExtRegion.c @@ -245,7 +245,7 @@ ExtLabelRegions(def, connTo, nodeList, clipArea) break; } } - if ((found == FALSE) && (nodeList != NULL)) + if ((found == FALSE) && (nodeList != NULL) && (ExtOptions & EXT_DOLABELCHECK)) { // Unconnected node label. This may be a "sticky label". // If it is not connected to TT_SPACE, then create a new From be19fda504c694af8bcb63e49cedc4d887f1afeb Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 27 Apr 2021 13:07:27 -0400 Subject: [PATCH 83/89] Added a "gds unique" option that behaves like the default CIF behavior, in which if a cell is read from GDS that has the same name as a cell in memory, then the cell in memory is renamed to keep all cell names unique in the database. --- VERSION | 2 +- calma/CalmaRdcl.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++ calma/CalmaRead.c | 6 +++++ calma/calma.h | 1 + commands/CmdCD.c | 22 ++++++++++++++++++ 5 files changed, 88 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 70b3b850..7df9552c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.159 +8.3.160 diff --git a/calma/CalmaRdcl.c b/calma/CalmaRdcl.c index 9a379599..5f9dbae8 100644 --- a/calma/CalmaRdcl.c +++ b/calma/CalmaRdcl.c @@ -55,6 +55,7 @@ extern HashTable calmaDefInitHash; /* forward declarations */ int calmaElementSref(); bool calmaParseElement(); +void calmaUniqueCell(); /* Structure used when flattening the GDS hierarchy on read-in */ @@ -349,6 +350,7 @@ calmaParseStructure(filename) freeMagic(newname); } } + if (CalmaUnique) calmaUniqueCell(strname); /* Ensure uniqueness */ cifReadCellDef = calmaFindCell(strname, &was_called, &predefined); if (predefined == TRUE) @@ -1136,6 +1138,62 @@ gdsCopyPaintFunc(tile, gdsCopyRec) return 0; } +/* + * ---------------------------------------------------------------------------- + * + * calmaUniqueCell -- + * + * Attempt to find a cell in the GDS subcell name hash table. + * If one exists, rename its definition so that it will not + * be overwritten when the cell is redefined. + * + * Results: + * None. + * + * Side effects: + * None. + * + * ---------------------------------------------------------------------------- + */ + +void +calmaUniqueCell(sname) + char *sname; +{ + HashEntry *h; + CellDef *def, *testdef; + char *newname; + int snum = 0; + + h = HashLookOnly(&CifCellTable, sname); + if ((h == NULL) || HashGetValue(h) == 0) return; + + def = DBCellLookDef(sname); + if (def == (CellDef *)NULL) + return; + + /* Cell may have been called but not yet defined---this is okay. */ + else if ((def->cd_flags & CDAVAILABLE) == 0) + return; + + testdef = def; + newname = (char *)mallocMagic(10 + strlen(sname)); + + while (testdef != NULL) + { + /* Keep appending suffix indexes until we find one not used */ + sprintf(newname, "%s_%d", sname, ++snum); + testdef = DBCellLookDef(newname); + } + DBCellRenameDef(def, newname); + + h = HashFind(&CifCellTable, (char *)sname); + HashSetValue(h, 0); + + CalmaReadError("Warning: cell definition \"%s\" reused.\n", sname); + freeMagic(newname); +} + /* * ---------------------------------------------------------------------------- * diff --git a/calma/CalmaRead.c b/calma/CalmaRead.c index 7daed818..9857f8d0 100644 --- a/calma/CalmaRead.c +++ b/calma/CalmaRead.c @@ -87,6 +87,12 @@ bool CalmaNoDuplicates = FALSE; /* If TRUE, then if a cell exists in * in the GDS file, then the cell in * the GDS file is skipped. */ +bool CalmaUnique = FALSE; /* If TRUE, then if a cell exists in + * memory with the same name as a cell + * in the GDS file, then the cell in + * memory is renamed to a unique + * identifier with a _N suffix. + */ extern void calmaUnexpected(); extern int calmaWriteInitFunc(); diff --git a/calma/calma.h b/calma/calma.h index d37d50f3..de0314f1 100644 --- a/calma/calma.h +++ b/calma/calma.h @@ -33,6 +33,7 @@ extern bool CalmaDoLower; extern bool CalmaAddendum; extern bool CalmaNoDuplicates; extern bool CalmaNoDateStamp; +extern bool CalmaUnique; extern bool CalmaMergeTiles; extern bool CalmaFlattenArrays; extern bool CalmaNoDRCCheck; diff --git a/commands/CmdCD.c b/commands/CmdCD.c index f4034a54..1ba9e472 100644 --- a/commands/CmdCD.c +++ b/commands/CmdCD.c @@ -110,6 +110,7 @@ bool cmdDumpParseArgs(); #define CALMA_POLYS 19 #define CALMA_PATHS 20 #define CALMA_UNDEFINED 21 +#define CALMA_UNIQUE 22 #define CALMA_WARN_HELP CIF_WARN_END /* undefined by CIF module */ @@ -160,6 +161,7 @@ CmdCalma(w, cmd) " put wire paths into individual subcells", "undefined [allow|disallow]\n" " [dis]allow writing of GDS with calls to undefined cells", + "unique [yes|no] rename any cells with names duplicated in the GDS", NULL }; @@ -599,6 +601,26 @@ CmdCalma(w, cmd) CalmaNoDuplicates = (option < 4) ? FALSE : TRUE; return; + case CALMA_UNIQUE: + if (cmd->tx_argc == 2) + { +#ifdef MAGIC_WRAPPER + Tcl_SetObjResult(magicinterp, Tcl_NewBooleanObj(CalmaUnique)); +#else + TxPrintf("Cell defs that exist before reading GDS will be renamed.\n", + (CalmaUnique) ? "not " : ""); +#endif + return; + } + else if (cmd->tx_argc != 3) + goto wrongNumArgs; + + option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo); + if (option < 0) + goto wrongNumArgs; + CalmaUnique = (option < 4) ? FALSE : TRUE; + return; + case CALMA_NO_STAMP: if (cmd->tx_argc == 2) { From e403e9201778179e70a7e7a7067bc96aa781bb2d Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Tue, 27 Apr 2021 14:53:34 -0400 Subject: [PATCH 84/89] Correction to the previous commit (didn't work as advertised). --- calma/CalmaRdcl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/calma/CalmaRdcl.c b/calma/CalmaRdcl.c index 5f9dbae8..1581c8c3 100644 --- a/calma/CalmaRdcl.c +++ b/calma/CalmaRdcl.c @@ -1166,7 +1166,10 @@ calmaUniqueCell(sname) int snum = 0; h = HashLookOnly(&CifCellTable, sname); - if ((h == NULL) || HashGetValue(h) == 0) return; + + /* Existing entry with zero value indicates that the existing */ + /* cell came from the same GDS file, so don't change anything. */ + if ((h != NULL) && HashGetValue(h) == 0) return; def = DBCellLookDef(sname); if (def == (CellDef *)NULL) From 94a6daa9b0e18784791af9fff20eea30fb917f4b Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 7 May 2021 10:42:44 -0400 Subject: [PATCH 85/89] Corrected the array DRC checking, which was clipping to the error area + halo but then failing to limit overlap checks to that clip area, resulting in bizarre errors whenever an array is made. Not sure why the error didn't show up more often. --- VERSION | 2 +- drc/DRCarray.c | 13 ++++++++++++- drc/DRCsubcell.c | 20 +++++++++++++++----- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/VERSION b/VERSION index 7df9552c..c0947289 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.160 +8.3.161 diff --git a/drc/DRCarray.c b/drc/DRCarray.c index 18c4d6e1..662f3f29 100644 --- a/drc/DRCarray.c +++ b/drc/DRCarray.c @@ -105,7 +105,7 @@ drcArrayFunc(scx, arg) int xsep, ysep; int xsize, ysize; int rval, oldTiles; - Rect errorArea, yankArea, tmp, tmp2; + Rect errorArea, yankArea, tmp, tmp2, saveClip; DRCCookie *save_cptr; CellUse *use = scx->scx_use; Rect *area; @@ -183,6 +183,8 @@ drcArrayFunc(scx, arg) (ClientData) &yankArea); drcArrayCount += DRCBasicCheck(DRCdef, &yankArea, &errorArea, drcArrayErrorFunc, drcArrayClientData); + *arg->dCD_clip = *area; + GeoClip(arg->dCD_clip, &yankArea); (void) DBArraySr(use, &errorArea, drcArrayOverlapFunc, (ClientData) arg); } @@ -200,6 +202,8 @@ drcArrayFunc(scx, arg) (ClientData) &yankArea); drcArrayCount += DRCBasicCheck(DRCdef, &yankArea, &errorArea, drcArrayErrorFunc, drcArrayClientData); + *arg->dCD_clip = *area; + GeoClip(arg->dCD_clip, &yankArea); (void) DBArraySr(use, &errorArea, drcArrayOverlapFunc, (ClientData) arg); } @@ -222,6 +226,8 @@ drcArrayFunc(scx, arg) (ClientData) &yankArea); drcArrayCount += DRCBasicCheck(DRCdef, &yankArea, &errorArea, drcArrayErrorFunc, drcArrayClientData); + *arg->dCD_clip = *area; + GeoClip(arg->dCD_clip, &yankArea); (void) DBArraySr(use, &errorArea, drcArrayOverlapFunc, (ClientData) arg); } @@ -239,11 +245,16 @@ drcArrayFunc(scx, arg) (ClientData) &yankArea); drcArrayCount += DRCBasicCheck(DRCdef, &yankArea, &errorArea, drcArrayErrorFunc, drcArrayClientData); + *arg->dCD_clip = *area; + GeoClip(arg->dCD_clip, &yankArea); (void) DBArraySr(use, &errorArea, drcArrayOverlapFunc, (ClientData) arg); } } + /* Restore original clip rect */ + *arg->dCD_clip = *area; + (void) DBNewPaintTable(savedPaintTable); (void) DBNewPaintPlane(savedPaintPlane); diff --git a/drc/DRCsubcell.c b/drc/DRCsubcell.c index c976a1c0..ac41952a 100644 --- a/drc/DRCsubcell.c +++ b/drc/DRCsubcell.c @@ -539,13 +539,23 @@ drcExactOverlapTile(tile, cxp) type = TiGetType(tile); TTMaskSetOnlyType(&typeMask, type); - for (t = DBNumUserLayers; t < DBNumTypes; t++) + if (type < DBNumUserLayers) { - rmask = DBResidueMask(t); - if (TTMaskHasType(rmask, type)) - TTMaskSetType(&typeMask, t); + for (t = DBNumUserLayers; t < DBNumTypes; t++) + { + rmask = DBResidueMask(t); + if (TTMaskHasType(rmask, type)) + TTMaskSetType(&typeMask, t); + } + TTMaskCom2(&invMask, &typeMask); + } + else + { + rmask = DBResidueMask(type); + TTMaskSetMask(&typeMask, rmask); // Add residue types for inverse only + TTMaskCom2(&invMask, &typeMask); + TTMaskSetOnlyType(&typeMask, type); // Restore original type mask } - TTMaskCom2(&invMask, &typeMask); for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++) { From 693256c373cf3216fe0756e1d36eef608d66a0f4 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Sun, 9 May 2021 16:58:49 -0400 Subject: [PATCH 86/89] Corrected an error in extresist that caused it to lose track of any port that has zero area for the label rectangle. --- VERSION | 2 +- resis/ResMain.c | 12 +++ resis/ResPrint.c | 211 +++++++++++++++++++++++------------------------ 3 files changed, 118 insertions(+), 107 deletions(-) diff --git a/VERSION b/VERSION index c0947289..e536aa0f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.161 +8.3.162 diff --git a/resis/ResMain.c b/resis/ResMain.c index e89816da..d5c6469e 100644 --- a/resis/ResMain.c +++ b/resis/ResMain.c @@ -217,6 +217,18 @@ ResMakePortBreakpoints(def) plane = def->cd_planes[DBPlane(node->rs_ttype)]; rect = &(node->rs_bbox); + /* Beware of zero-area ports */ + if (rect->r_xbot == rect->r_xtop) + { + rect->r_xbot--; + rect->r_xtop++; + } + if (rect->r_ybot == rect->r_ytop) + { + rect->r_ybot--; + rect->r_ytop++; + } + TTMaskSetOnlyType(&mask, node->rs_ttype); (void) DBSrPaintArea((Tile *) NULL, plane, rect, &mask, ResAddBreakpointFunc, (ClientData)node); diff --git a/resis/ResPrint.c b/resis/ResPrint.c index 17de1333..a2dc6b8e 100644 --- a/resis/ResPrint.c +++ b/resis/ResPrint.c @@ -48,52 +48,52 @@ extern ResSimNode *ResInitializeNode(); */ void -ResPrintExtRes(outextfile,resistors,nodename) - FILE *outextfile; - resResistor *resistors; - char *nodename; +ResPrintExtRes(outextfile, resistors, nodename) + FILE *outextfile; + resResistor *resistors; + char *nodename; { - int nodenum=0; - char newname[MAXNAME]; - HashEntry *entry; - ResSimNode *node,*ResInitializeNode(); + int nodenum=0; + char newname[MAXNAME]; + HashEntry *entry; + ResSimNode *node, *ResInitializeNode(); - for (; resistors != NULL; resistors=resistors->rr_nextResistor) - { - /* - These names shouldn't be null; they should either be set by - the device name or by the node printing routine. This - code is included in case the resistor network is printed - before the nodes. - */ - if (resistors->rr_connection1->rn_name == NULL) - { - (void)sprintf(newname,"%s%s%d",nodename,".r",nodenum++); - entry = HashFind(&ResNodeTable,newname); - node = ResInitializeNode(entry); - resistors->rr_connection1->rn_name = node->name; - node->oldname = nodename; - } - if (resistors->rr_connection2->rn_name == NULL) - { - (void)sprintf(newname,"%s%s%d",nodename,".r",nodenum++); - entry = HashFind(&ResNodeTable,newname); - node = ResInitializeNode(entry); - resistors->rr_connection2->rn_name = node->name; - node->oldname = nodename; - } - if (ResOptionsFlags & ResOpt_DoExtFile) - { - fprintf(outextfile, "resist \"%s\" \"%s\" %g\n", + for (; resistors != NULL; resistors = resistors->rr_nextResistor) + { + /* + * These names shouldn't be null; they should either be set by + * the device name or by the node printing routine. This + * code is included in case the resistor network is printed + * before the nodes. + */ + + if (resistors->rr_connection1->rn_name == NULL) + { + (void)sprintf(newname, "%s%s%d", nodename, ".r", nodenum++); + entry = HashFind(&ResNodeTable, newname); + node = ResInitializeNode(entry); + resistors->rr_connection1->rn_name = node->name; + node->oldname = nodename; + } + if (resistors->rr_connection2->rn_name == NULL) + { + (void)sprintf(newname, "%s%s%d", nodename, ".r", nodenum++); + entry = HashFind(&ResNodeTable, newname); + node = ResInitializeNode(entry); + resistors->rr_connection2->rn_name = node->name; + node->oldname = nodename; + } + if (ResOptionsFlags & ResOpt_DoExtFile) + { + fprintf(outextfile, "resist \"%s\" \"%s\" %g\n", resistors->rr_connection1->rn_name, resistors->rr_connection2->rn_name, resistors->rr_value / (float)ExtCurStyle->exts_resistScale); - } - } + } + } } - /* *------------------------------------------------------------------------- * @@ -205,65 +205,64 @@ ResPrintExtNode(outextfile, nodelist, nodename) FILE *outextfile; resNode *nodelist; char *nodename; - { - int nodenum=0; - char newname[MAXNAME],tmpname[MAXNAME],*cp; - HashEntry *entry; - ResSimNode *node,*ResInitializeNode(); - bool DoKillNode = TRUE; - resNode *snode = nodelist; + int nodenum = 0; + char newname[MAXNAME], tmpname[MAXNAME], *cp; + HashEntry *entry; + ResSimNode *node, *ResInitializeNode(); + bool DoKillNode = TRUE; + resNode *snode = nodelist; - /* If any of the subnode names match the original node name, then */ - /* we don't want to rip out that node with a "killnode" statement. */ + /* If any of the subnode names match the original node name, then */ + /* we don't want to rip out that node with a "killnode" statement. */ - for (; nodelist != NULL; nodelist = nodelist->rn_more) + for (; nodelist != NULL; nodelist = nodelist->rn_more) + { if (nodelist->rn_name != NULL) if (!strcmp(nodelist->rn_name, nodename)) { DoKillNode = FALSE; break; } + } - if ((ResOptionsFlags & ResOpt_DoExtFile) && DoKillNode) - { - fprintf(outextfile,"killnode \"%s\"\n",nodename); - } + if ((ResOptionsFlags & ResOpt_DoExtFile) && DoKillNode) + { + fprintf(outextfile, "killnode \"%s\"\n", nodename); + } - /* Create "rnode" entries for each subnode */ + /* Create "rnode" entries for each subnode */ - for (; snode != NULL; snode = snode->rn_more) - { - if (snode->rn_name == NULL) - { - (void)sprintf(tmpname,"%s",nodename); + for (; snode != NULL; snode = snode->rn_more) + { + if (snode->rn_name == NULL) + { + (void)sprintf(tmpname,"%s",nodename); - cp = tmpname + strlen(tmpname) - 1; - if (*cp == '!' || *cp == '#') *cp = '\0'; + cp = tmpname + strlen(tmpname) - 1; + if (*cp == '!' || *cp == '#') *cp = '\0'; - (void)sprintf(newname,"%s%s%d",tmpname,".n",nodenum++); - entry = HashFind(&ResNodeTable,newname); - node = ResInitializeNode(entry); - snode->rn_name = node->name; - node->oldname = nodename; - } + (void)sprintf(newname, "%s%s%d", tmpname, ".n", nodenum++); + entry = HashFind(&ResNodeTable, newname); + node = ResInitializeNode(entry); + snode->rn_name = node->name; + node->oldname = nodename; + } - if (ResOptionsFlags & ResOpt_DoExtFile) - { - /* rnode name R C x y type (R is always 0) */ - fprintf(outextfile, "rnode \"%s\" 0 %g %d %d %d\n", + if (ResOptionsFlags & ResOpt_DoExtFile) + { + /* rnode name R C x y type (R is always 0) */ + fprintf(outextfile, "rnode \"%s\" 0 %g %d %d %d\n", snode->rn_name, - (snode->rn_float.rn_area/ - ExtCurStyle->exts_capScale), + (snode->rn_float.rn_area / ExtCurStyle->exts_capScale), snode->rn_loc.p_x, snode->rn_loc.p_y, /* the following is TEMPORARILY set to 0 */ 0); - } - } + } + } } - /* *------------------------------------------------------------------------- * @@ -279,39 +278,39 @@ ResPrintExtNode(outextfile, nodelist, nodename) */ void -ResPrintStats(goodies,name) - ResGlobalParams *goodies; - char *name; +ResPrintStats(goodies, name) + ResGlobalParams *goodies; + char *name; { - static int totalnets=0,totalnodes=0,totalresistors=0; - int nodes,resistors; - resNode *node; - resResistor *res; + static int totalnets = 0, totalnodes = 0, totalresistors = 0; + int nodes, resistors; + resNode *node; + resResistor *res; - if (goodies == NULL) - { + if (goodies == NULL) + { TxError("nets:%d nodes:%d resistors:%d\n", - totalnets,totalnodes,totalresistors); - totalnets=0; - totalnodes=0; - totalresistors=0; - return; - } - nodes=0; - resistors=0; - totalnets++; - for (node = ResNodeList; node != NULL; node=node->rn_more) + totalnets, totalnodes, totalresistors); + totalnets = 0; + totalnodes = 0; + totalresistors = 0; + return; + } + nodes = 0; + resistors = 0; + totalnets++; + for (node = ResNodeList; node != NULL; node=node->rn_more) - { - nodes++; - totalnodes++; - } - for (res = ResResList; res != NULL; res=res->rr_nextResistor) - { - resistors++; - totalresistors++; - } - TxError("%s %d %d\n",name,nodes,resistors); + { + nodes++; + totalnodes++; + } + for (res = ResResList; res != NULL; res=res->rr_nextResistor) + { + resistors++; + totalresistors++; + } + TxError("%s %d %d\n", name, nodes, resistors); } /* @@ -326,8 +325,8 @@ ResPrintStats(goodies,name) void resWriteNodeName(fp, nodeptr) - FILE *fp; - resNode *nodeptr; + FILE *fp; + resNode *nodeptr; { if (nodeptr->rn_name == NULL) fprintf(fp, "N%d", nodeptr->rn_id); From d8450cf1d46b2b66b1d751ac614534ab559bc02b Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 12 May 2021 22:49:25 -0400 Subject: [PATCH 87/89] Corrected an issue with a conflict between the "gds ordering" and "gds noduplicates" options (essentially, they were canceling each other out). --- VERSION | 2 +- calma/CalmaRdcl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index c0947289..e536aa0f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.161 +8.3.162 diff --git a/calma/CalmaRdcl.c b/calma/CalmaRdcl.c index 1581c8c3..71be0d79 100644 --- a/calma/CalmaRdcl.c +++ b/calma/CalmaRdcl.c @@ -352,6 +352,7 @@ calmaParseStructure(filename) } if (CalmaUnique) calmaUniqueCell(strname); /* Ensure uniqueness */ cifReadCellDef = calmaFindCell(strname, &was_called, &predefined); + HashSetValue(he, cifReadCellDef); if (predefined == TRUE) { @@ -374,7 +375,6 @@ calmaParseStructure(filename) { DBCellClearDef(cifReadCellDef); DBCellSetAvail(cifReadCellDef); - HashSetValue(he, cifReadCellDef); cifCurReadPlanes = cifSubcellPlanes; cifReadCellDef->cd_flags &= ~CDDEREFERENCE; From f8b6bd15257116413a7bcfedb08031f51dd554d3 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 12 May 2021 22:50:53 -0400 Subject: [PATCH 88/89] Updated version for the last commit. --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index e536aa0f..7d3253ea 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.162 +8.3.163 From 8d647287e2268f0fa8d98cb217af91768bb10735 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 14 May 2021 18:02:34 -0400 Subject: [PATCH 89/89] Implemented a basic DRC check on non-Manhattan edges. Previously checks on non-Manhattan tiles were made only on the straight edges; this was sufficient for most checks. However, it can miss the case of facing non-Manhattan edges. This check does not do triggered rules because there is no non-Manhattan maxwidth algorithm implemented, and because the triggering clipping area is a triangle and needs an extension to support it. --- VERSION | 2 +- database/DBcellcopy.c | 1 + drc/DRCbasic.c | 171 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 152 insertions(+), 22 deletions(-) diff --git a/VERSION b/VERSION index 7d3253ea..8b702771 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.163 +8.3.164 diff --git a/database/DBcellcopy.c b/database/DBcellcopy.c index cda6e83d..4b6793d7 100644 --- a/database/DBcellcopy.c +++ b/database/DBcellcopy.c @@ -688,6 +688,7 @@ DBCellCopyPaint(scx, mask, xMask, targetUse) arg.caa_mask = mask; arg.caa_targetUse = targetUse; + arg.caa_func = NULL; GeoTransRect(&scx->scx_trans, &scx->scx_area, &arg.caa_rect); /* Build dummy TreeContext */ diff --git a/drc/DRCbasic.c b/drc/DRCbasic.c index de60f127..9b29ed9e 100644 --- a/drc/DRCbasic.c +++ b/drc/DRCbasic.c @@ -26,6 +26,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include #include #include // for memcpy() +#include // for sqrt() for diagonal check #include "utils/magic.h" #include "utils/geometry.h" #include "tiles/tile.h" @@ -268,6 +269,47 @@ areaCheck(tile, arg) return 0; } +/* + * ---------------------------------------------------------------------------- + * + * areaNMCheck --- + * + * Check for errors in triangular area of a tile + * + * ---------------------------------------------------------------------------- + */ + +int +areaNMCheck(tile, arg) + Tile *tile; + struct drcClientData *arg; +{ + Rect rect; /* Area where error is to be recorded. */ + + /* Ignore the tile that initiates the check, because the error area */ + /* of a non-Manhattan check may fall inside of it. */ + if (tile == arg->dCD_initial) return 0; + + TiToRect(tile, &rect); + + /* Only consider the portion of the suspicious tile that overlaps + * the clip area for errors, unless this is a trigger rule. + */ + + if (!(arg->dCD_cptr->drcc_flags & DRC_TRIGGER)) + GeoClip(&rect, arg->dCD_clip); + + GeoClip(&rect, arg->dCD_constraint); + if ((rect.r_xbot >= rect.r_xtop) || (rect.r_ybot >= rect.r_ytop)) + return 0; + + (*(arg->dCD_function))(arg->dCD_celldef, &rect, arg->dCD_cptr, + arg->dCD_clientData); + (*(arg->dCD_errors))++; + + return 0; +} + /* * ---------------------------------------------------------------------------- * @@ -412,8 +454,11 @@ drcTile (tile, arg) if (IsSplit(tile)) { + int deltax, deltay; + TileType tt, to; + /* Check rules for DRC_ANGLES rule and process */ - TileType tt = TiGetLeftType(tile); + tt = TiGetLeftType(tile); if (tt != TT_SPACE) { for (cptr = DRCCurStyle->DRCRulesTbl[TT_SPACE][tt]; @@ -436,8 +481,98 @@ drcTile (tile, arg) } } - /* This drc is only for the left edge of the tile */ - if (SplitSide(tile)) goto checkbottom; + /* Full check of edge rules along the diagonal. */ + if (SplitSide(tile)) + { + tt = TiGetRightType(tile); /* inside type */ + to = TiGetLeftType(tile); /* outside type */ + } + else + { + tt = TiGetLeftType(tile); /* inside type */ + to = TiGetRightType(tile); /* outside type */ + } + + for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL; + cptr = cptr->drcc_next) + { + int deltax, deltay, w, h; + double r; + TileType dinfo, dsplit; + + /* Work to be done: Handle triggering rules for non-Manhattan */ + /* edges; especially important for the wide-spacing rule. */ + + if (cptr->drcc_flags & DRC_TRIGGER) + { + cptr = cptr->drcc_next; // Skip both triggering and triggered rules + continue; + } + + /* Note: Triggered wide-spacing rule will require handling */ + /* the DRC_MAXWIDTH rule on non-Manhattan edges. */ + + if (cptr->drcc_flags & (DRC_ANGLES | DRC_AREA | DRC_MAXWIDTH + | DRC_RECTSIZE | DRC_OFFGRID)) + continue; + + TiToRect(tile, &errRect); + + /* Find the rule distances according to the scale factor */ + dist = cptr->drcc_dist; + + /* drcc_edgeplane is used to avoid checks on edges */ + /* in more than one plane */ + + if (arg->dCD_plane != cptr->drcc_edgeplane) continue; + + DRCstatRules++; + + DRCstatSlow++; + arg->dCD_cptr = cptr; + arg->dCD_entries = 0; + TTMaskCom2(&tmpMask, &cptr->drcc_mask); + TTMaskClearType(&tmpMask, TT_ERROR_S); + arg->dCD_initial = tile; + + /* Compute position that is the rule distance away from */ + /* the tile's diagonal edge, by Euclidean measure */ + /* (rounded down if fractional). Use the forward */ + /* position, and negate if reversed. */ + + w = RIGHT(tile) - LEFT(tile); + h = TOP(tile) - BOTTOM(tile); + r = 1.0 / (1.0 + ((double)(w * w) / (double)(h * h))); + deltax = (int)((double)cptr->drcc_dist * sqrt(r)); + deltay = (deltax * w) / h; + + if (SplitSide(tile) == 1) deltax = -deltax; + if (SplitDirection(tile) == SplitSide(tile)) deltay = -deltay; + + dinfo = TiGetTypeExact(tile) & (TT_DIAGONAL | TT_DIRECTION | TT_SIDE); + if (!(cptr->drcc_flags & DRC_REVERSE)) + { + /* Forward case is behind the triangle */ + deltax = -deltax; + deltay = -deltay; + /* Split side changes in the reverse case */ + if (SplitSide(tile)) + dinfo &= (~TT_SIDE); + else + dinfo |= TT_SIDE; + } + + /* errRect is the tile area offset by (deltax, deltay) */ + errRect.r_xbot += deltax; + errRect.r_ybot += deltay; + errRect.r_xtop += deltax; + errRect.r_ytop += deltay; + + DBSrPaintNMArea((Tile *) NULL, + arg->dCD_celldef->cd_planes[cptr->drcc_plane], dinfo, + &errRect, &tmpMask, areaNMCheck, (ClientData) arg); + } + DRCstatEdges++; } /* @@ -679,8 +814,8 @@ drcTile (tile, arg) else tpl = tpleft; /* Make sure the edge stops at edgeBot */ - if ((TiGetTopType(tpl) != TiGetBottomType(tpleft)) || - (TiGetTopType(tpr) != TiGetBottomType(tile))) + if ((TiGetRightType(tpl) != TiGetRightType(tpleft)) || + (TiGetLeftType(tpr) != TiGetLeftType(tile))) { if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tpr))) { @@ -706,8 +841,8 @@ drcTile (tile, arg) else tpl = tpleft; /* Make sure the edge stops at edgeTop */ - if ((TiGetBottomType(tpl) != TiGetTopType(tpleft)) || - (TiGetBottomType(tpr) != TiGetTopType(tile))) + if ((TiGetRightType(tpl) != TiGetRightType(tpleft)) || + (TiGetLeftType(tpr) != TiGetLeftType(tile))) { if (TTMaskHasType(&cptr->drcc_corner, TiGetBottomType(tpr))) @@ -753,8 +888,8 @@ drcTile (tile, arg) else tpr = tile; /* Make sure the edge stops at edgeTop */ - if ((TiGetBottomType(tpl) != TiGetTopType(tpleft)) || - (TiGetBottomType(tpr) != TiGetTopType(tile))) + if ((TiGetRightType(tpl) != TiGetRightType(tpleft)) || + (TiGetLeftType(tpr) != TiGetLeftType(tile))) { if (TTMaskHasType(&cptr->drcc_corner, TiGetBottomType(tpl))) { @@ -780,8 +915,8 @@ drcTile (tile, arg) else tpr = tile; /* Make sure the edge stops at edgeBot */ - if ((TiGetTopType(tpl) != TiGetBottomType(tpleft)) || - (TiGetTopType(tpr) != TiGetBottomType(tile))) + if ((TiGetRightType(tpl) != TiGetRightType(tpleft)) || + (TiGetLeftType(tpr) != TiGetLeftType(tile))) { if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tpl))) { @@ -842,12 +977,6 @@ drcTile (tile, arg) } } - /* This drc is only for the bottom edge of the tile */ - -checkbottom: - if (IsSplit(tile)) - if (SplitSide(tile) == SplitDirection(tile)) return 0; - /* * Check design rules along a horizontal boundary between two tiles. * @@ -1052,7 +1181,7 @@ checkbottom: for (tpx = TR(tile); BOTTOM(tpx) > edgeY; tpx = LB(tpx)); else tpx = tile; - if (TTMaskHasType(&cptr->drcc_corner, TiGetLeftType(tpx))) + if (TTMaskHasType(&cptr->drcc_corner, TiGetBottomType(tpx))) { errRect.r_xtop += cdist; if (DRCEuclidean) @@ -1069,7 +1198,7 @@ checkbottom: if (LEFT(tile) >= errRect.r_xbot) tpx = BL(tile); else tpx = tile; - if (TTMaskHasType(&cptr->drcc_corner, TiGetRightType(tpx))) + if (TTMaskHasType(&cptr->drcc_corner, TiGetBottomType(tpx))) { errRect.r_xbot -= cdist; if (DRCEuclidean) @@ -1106,7 +1235,7 @@ checkbottom: for (tpx = BL(tpbot); TOP(tpx) < edgeY; tpx = RT(tpx)); else tpx = tpbot; - if (TTMaskHasType(&cptr->drcc_corner, TiGetRightType(tpx))) + if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tpx))) { errRect.r_xbot -= cdist; if (DRCEuclidean) @@ -1122,7 +1251,7 @@ checkbottom: if (RIGHT(tpbot) <= errRect.r_xtop) tpx = TR(tpbot); else tpx = tpbot; - if (TTMaskHasType(&cptr->drcc_corner, TiGetLeftType(tpx))) + if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tpx))) { errRect.r_xtop += cdist; if (DRCEuclidean)