diff --git a/VERSION b/VERSION index f21117ae..8b702771 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.125 +8.3.164 diff --git a/calma/CalmaRdcl.c b/calma/CalmaRdcl.c index b3568a49..71be0d79 100644 --- a/calma/CalmaRdcl.c +++ b/calma/CalmaRdcl.c @@ -48,12 +48,14 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ int calmaNonManhattan; int CalmaFlattenLimit = 10; +int NameConvertErrors = 0; extern HashTable calmaDefInitHash; /* forward declarations */ int calmaElementSref(); bool calmaParseElement(); +void calmaUniqueCell(); /* Structure used when flattening the GDS hierarchy on read-in */ @@ -306,8 +308,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); @@ -348,51 +350,76 @@ calmaParseStructure(filename) freeMagic(newname); } } + if (CalmaUnique) calmaUniqueCell(strname); /* Ensure uniqueness */ cifReadCellDef = calmaFindCell(strname, &was_called, &predefined); + HashSetValue(he, cifReadCellDef); + 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); + 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); @@ -403,9 +430,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 */ @@ -591,6 +620,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; +} + /* * ---------------------------------------------------------------------------- * @@ -836,8 +884,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) { @@ -981,9 +1045,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); @@ -1045,6 +1138,65 @@ 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); + + /* 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) + 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/CalmaWrite.c b/calma/CalmaWrite.c index ff4b83e9..cb1857cd 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); @@ -809,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/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/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/CmdCD.c b/commands/CmdCD.c index cb718a41..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 */ @@ -145,8 +146,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", @@ -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) { @@ -857,6 +879,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 +1097,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)) @@ -1084,13 +1112,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); } @@ -3921,6 +3947,216 @@ 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); + + /* Clip to search area */ + GEOCLIP(&area, &cxp->tc_scx->scx_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; + Rect editBox; + + if (cmd->tx_argc != 2) + { + TxError("Usage: %s layers\n", cmd->tx_argv[0]); + return; + } + + if (!ToolGetEditBox(&editBox)) 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); + } + } + + DRCCheckThis(EditCellUse->cu_def, TT_CHECKPAINT, &editBox); + DBWAreaChanged(EditCellUse->cu_def, &editBox, DBW_ALLWINDOWS, &tMask); + DBReComputeBbox(EditCellUse->cu_def); +} + /* * ---------------------------------------------------------------------------- * 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/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; } diff --git a/commands/CmdLQ.c b/commands/CmdLQ.c index e4b99d48..26e1f225 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); } @@ -1292,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 @@ -1310,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. * @@ -1346,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; @@ -1441,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 @@ -1483,10 +1516,13 @@ CmdPort(w, cmd) } 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; @@ -1554,7 +1590,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; } @@ -1946,8 +1982,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/commands/CmdRS.c b/commands/CmdRS.c index 3adea56f..86fc0760 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; + /* * ---------------------------------------------------------------------------- * @@ -525,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 /* * ---------------------------------------------------------------------------- @@ -547,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; @@ -677,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,6 +636,85 @@ cmdSelectVisible(layers, less) 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; + char *lptr; + bool negate = FALSE; + + 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; + + /* 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); +} + /* * ---------------------------------------------------------------------------- * @@ -725,30 +752,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_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 - static char *cmdSelectOption[] = { "area", "visible", "cell", + "labels", + "intersection", "clear", "flat", "help", @@ -774,6 +784,8 @@ 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", + "[more | less] intersection [layers] [de]select intersection of layers", "clear clear selection", "flat flatten the contents of the selection", "help print this message", @@ -819,7 +831,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; @@ -832,6 +844,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 +864,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 +889,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 +904,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)) { @@ -954,7 +986,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; @@ -968,8 +1000,18 @@ 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; + cmdIntersectArea(optionArgs[1]); return; /*-------------------------------------------------------------------- @@ -982,6 +1024,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. *-------------------------------------------------------------------- @@ -1526,6 +1576,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 @@ -1854,8 +1911,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 @@ -1875,6 +1931,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. + * * ---------------------------------------------------------------------------- */ @@ -1895,10 +1956,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 @@ -1921,10 +1984,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) { @@ -1943,20 +2030,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) @@ -1970,67 +2064,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 @@ -2039,67 +2184,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; @@ -2113,7 +2329,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; } } diff --git a/commands/CmdTZ.c b/commands/CmdTZ.c index a0e93833..7c0395b3 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; @@ -844,6 +843,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; +} + /* * ---------------------------------------------------------------------------- * @@ -852,7 +886,7 @@ static LabelStore *labelBlockTop, *labelEntry; * Print out information about what's selected. * * Usage: - * what [-list] + * what [-list[all]] * * Results: * None. @@ -861,7 +895,8 @@ static LabelStore *labelBlockTop, *labelEntry; * 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. * * ---------------------------------------------------------------------------- */ @@ -873,14 +908,12 @@ CmdWhat(w, cmd) { int i, locargc; bool foundAny; - bool doList = FALSE; + bool doList = FALSE, doListAll = FALSE; TileTypeBitMask layers, maskBits, *rMask; - SearchContext scx; CellUse *CheckUse; - struct linked_id *lid; #ifdef MAGIC_WRAPPER - Tcl_Obj *lobj, *paintobj, *labelobj, *cellobj; + Tcl_Obj *lobj, *paintobj, *paintcellobj, *celllistobj, *labelobj, *cellobj; extern int cmdWhatCellListFunc(); #endif @@ -890,14 +923,20 @@ 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; + 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) { @@ -959,29 +998,69 @@ 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, *lidp; + int pNum; - TxPrintf("Selected mask layers:\n"); + EditCellUse = CheckUse; + + if (!doListAll) 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) + + 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 */ + /* cell or subcell that tile belongs to. */ + + lid = NULL; + 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); + } + + if (!doListAll) { - freeMagic(lid); - lid = lid->lid_next; + TxPrintf(" %-8s (", DBTypeLongName(i)); + for (lidp = lid; lidp; lidp = lidp->lid_next) + TxPrintf(" %s ", lidp->lid_name); + TxPrintf(")\n"); } + else + { + 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, celllistobj, + Tcl_NewStringObj(lidp->lid_name, -1)); + + Tcl_ListObjAppendElement(magicinterp, paintcellobj, + celllistobj); + } + + while (lid != NULL) + { + freeMagic(lid); + lid = lid->lid_next; + } + if (doListAll) + Tcl_ListObjAppendElement(magicinterp, paintobj, + paintcellobj); } } + EditCellUse = saveUse; + } else { @@ -1008,7 +1087,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++) @@ -1052,7 +1131,7 @@ CmdWhat(w, cmd) foundAny = FALSE; #ifdef MAGIC_WRAPPER - if (doList) + if (doList || doListAll) SelEnumCells(FALSE, (bool *) NULL, (SearchContext *) NULL, cmdWhatCellListFunc, (ClientData) cellobj); else @@ -1061,7 +1140,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); @@ -1926,7 +2005,7 @@ CmdXor(w, cmd) PaintResultType DBXORResultTbl[NP][NT][NT]; PaintResultType (*curPaintSave)[NT][NT]; - void (*curPlaneSave)(); + int (*curPlaneSave)(); int p, t, h; 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/DBcellcopy.c b/database/DBcellcopy.c index 8362240b..4b6793d7 100644 --- a/database/DBcellcopy.c +++ b/database/DBcellcopy.c @@ -342,6 +342,214 @@ DBCellCheckCopyAllPaint(scx, mask, xMask, targetUse, func) DBTreeSrTiles(scx, &locMask, xMask, dbCopyAllPaint, (ClientData) &arg); } +/* Client data structure used by DBCellGenerateSubstrate() */ + +struct dbCopySubData { + Plane *csd_plane; + TileType csd_subtype; + int csd_pNum; + bool csd_modified; +}; + +/* + *----------------------------------------------------------------------------- + * + * DBCellGenerateSubstrate -- + * + * 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 + * + * ---------------------------------------------------------------------------- + */ + +Plane * +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 */ + CellDef *targetDef; +{ + 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, targetDef->cd_planes[plane], &TiPlaneRect, + &DBAllButSpaceBits, dbCopySubFunc, (ClientData)&csd); + + return tempPlane; +} + +/* + * 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 */ +{ + 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; + 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, &sourceRect); + + /* Transform to target coordinates */ + GEOTRANSRECT(&scx->scx_trans, &sourceRect, &targetRect); + + csd->csd_modified = TRUE; + + return DBNMPaintPlane(plane, type, &targetRect, 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. 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 +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; + } + + /* 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, type, &targetRect, DBStdEraseTbl(subType, pNum), + (PaintUndoInfo *)NULL); +} + +/* + * 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 +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); +} + /* *----------------------------------------------------------------------------- * @@ -480,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/database/DBcellname.c b/database/DBcellname.c index dbfc32f0..e6ee0b14 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" @@ -271,6 +273,7 @@ DBCellDelete(cellname, force) } celldef->cd_parents = (CellUse *)NULL; + DBWResetBox(celldef); result = DBCellDeleteDef(celldef); if (result == FALSE) @@ -280,8 +283,6 @@ DBCellDelete(cellname, force) return result; } - - /* * ---------------------------------------------------------------------------- * @@ -598,6 +599,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 +687,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 +720,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 +734,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 +791,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: diff --git a/database/DBconnect.c b/database/DBconnect.c index 2001be96..1b665473 100644 --- a/database/DBconnect.c +++ b/database/DBconnect.c @@ -29,8 +29,10 @@ 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" #include "utils/signals.h" #include "utils/malloc.h" @@ -43,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 */ - int csa2_xMask; /* Cell window mask for search */ - Rect *csa2_bounds; /* Area that limits the search */ - - 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 */ -}; - -#define CSA2_LIST_START_SIZE 256 - /* *----------------------------------------------------------------- * DBTransformDiagonal -- @@ -255,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; @@ -270,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. @@ -280,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(); @@ -346,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; @@ -361,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; @@ -434,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; } @@ -577,7 +529,7 @@ donesides: */ planes = DBConnPlanes[loctype]; - planes &= ~(PlaneNumToMaskBit(csa->csa_plane)); + planes &= ~(PlaneNumToMaskBit(csa->csa_pNum)); if (planes != 0) { struct conSrArg newcsa; @@ -589,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], @@ -653,7 +605,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". @@ -691,10 +643,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; } @@ -734,7 +691,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; @@ -757,24 +714,29 @@ 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 >= 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 */ + /* Reached list size limit---need to push the list and */ + /* start a new one. */ 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)); - 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; @@ -805,7 +767,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. @@ -829,7 +792,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); @@ -942,23 +905,29 @@ 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 >= 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 */ + /* Reached list size limit---need to push the list and */ + /* start a new one. */ conSrArea *newlist; - int i, lastsize = csa2->csa2_size; - csa2->csa2_size *= 2; - - newlist = (conSrArea *)mallocMagic((size_t)(csa2->csa2_size) * sizeof(conSrArea)); - memcpy((void *)newlist, (void *)csa2->csa2_list, - (size_t)lastsize * 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_top = 0; } csa2->csa2_list[csa2->csa2_top].area = newarea; @@ -968,7 +937,6 @@ dbcConnectFunc(tile, cx) return 0; } - /* * ---------------------------------------------------------------------------- * @@ -1019,9 +987,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 @@ -1034,7 +1003,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; @@ -1043,10 +1011,11 @@ 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) @@ -1061,13 +1030,28 @@ 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) DBTreeSrNMTiles(scx, newtype, newmask, xMask, dbcConnectFunc, (ClientData) &csa2); else - DBTreeSrTiles(scx, newmask, xMask, dbcConnectFunc, (ClientData) &csa2); + DBTreeSrTiles(scx, newmask, xMask, dbcConnectFunc, + (ClientData) &csa2); /* Check the source def for any labels belonging to this */ /* tile area and plane, and add them to the destination. */ @@ -1098,11 +1082,17 @@ DBTreeCopyConnect(scx, mask, xMask, connect, area, doLabels, destUse) searchtype |= TF_LABEL_ATTACH_NOT_SE; } } - if (doLabels) - DBTreeSrLabels(scx, newmask, xMask, &tpath, searchtype, - dbcConnectLabelFunc, (ClientData) &csa2); + if (doLabels == SEL_SIMPLE_LABELS) tpath.tp_first = NULL; + if (doLabels != SEL_NO_LABELS) + 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); + StackFree(csa2.csa2_stack); /* Recompute the bounding box of the destination and record its area * for redisplay. diff --git a/database/DBio.c b/database/DBio.c index 56874065..2b0e2a2f 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; +} + /* * ---------------------------------------------------------------------------- * @@ -285,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; @@ -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) @@ -609,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; @@ -617,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) @@ -634,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); @@ -3167,6 +3405,105 @@ 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 (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 + sprintf(cstring, "%s", pathstart); + } +} + /* * ---------------------------------------------------------------------------- * @@ -3192,8 +3529,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); @@ -3244,92 +3580,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/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; } /* 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); 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. */ diff --git a/database/database.h.in b/database/database.h.in index 18ed836d..1ef2d9fd 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 @@ -725,6 +777,7 @@ extern void DBFileRecovery(); extern bool DBWriteBackup(); extern bool DBReadBackup(); extern void DBRemoveBackup(); +extern void DBPathSubstitute(); /* Labels */ extern Label *DBPutLabel(); @@ -790,7 +843,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 */ @@ -821,6 +876,7 @@ extern void DBCellCopyLabels(); extern void DBCellCopyAllLabels(); extern void DBCellCopyCells(); extern void DBCellCopyAllCells(); +extern Plane *DBCellGenerateSubstrate(); /* Contact image handling */ extern TileType DBPlaneToResidue(); 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\ 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(); diff --git a/drc/DRCarray.c b/drc/DRCarray.c index 1f44ede6..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; @@ -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; @@ -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/DRCbasic.c b/drc/DRCbasic.c index 9f4aaf41..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++; } /* @@ -604,9 +739,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; } @@ -671,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))) { @@ -698,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))) @@ -745,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))) { @@ -772,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))) { @@ -834,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. * @@ -1044,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) @@ -1061,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) @@ -1098,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) @@ -1114,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) 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/DRCsubcell.c b/drc/DRCsubcell.c index 053d77e6..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++) { @@ -647,6 +657,7 @@ void DRCOffGridError(rect) Rect *rect; /* Area of error */ { + if (drcSubFunc == NULL) return; (*drcSubFunc)(DRCErrorDef, rect, &drcOffGridCookie, drcSubClientData); } @@ -696,7 +707,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; @@ -896,7 +907,7 @@ DRCFlatCheck(use, area) SearchContext scx; void drcIncCount(); PaintResultType (*savedPaintTable)[NT][NT]; - void (*savedPaintPlane)(); + int (*savedPaintPlane)(); int drcFlatCount = 0; UndoDisable(); 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) diff --git a/ext2sim/ext2sim.c b/ext2sim/ext2sim.c index 35b28c05..ce0ad59b 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; @@ -1572,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/ext2spice/ext2hier.c b/ext2spice/ext2hier.c index e6ba9381..2373bb7b 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 */ @@ -500,7 +501,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 +523,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 +534,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 +1023,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; } @@ -1642,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) { @@ -1897,6 +1896,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 5f1b81bc..b3c96123 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); @@ -1924,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, @@ -1987,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]); @@ -2219,47 +2230,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 +2312,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 +2334,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 +2348,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 +2855,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; } @@ -4083,7 +4083,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; 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/extflat/EFbuild.c b/extflat/EFbuild.c index 09ac3a2e..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 */ /* @@ -183,6 +184,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); } @@ -453,6 +455,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 */ @@ -481,11 +485,35 @@ 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); 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 */ + /* and all aliases point to the merged name's hash. */ + + if (nn1->efnn_node == NULL) + { + 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) + { + 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; } @@ -1553,6 +1581,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 */ @@ -1861,7 +1890,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 3c333dd1..95c80bb0 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. * * ---------------------------------------------------------------------------- */ @@ -441,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; @@ -465,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; @@ -491,13 +484,8 @@ 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; /* Prepend to global node list */ newnode->efnode_next = efNodeList.efnode_next; @@ -505,9 +493,6 @@ efAddNodes(hc, stdcell) 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) { /* @@ -546,6 +531,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; @@ -557,6 +543,7 @@ efAddNodes(hc, stdcell) newnode->efnode_name = newname; } } + } return 0; } 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/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; /* diff --git a/extract/ExtBasic.c b/extract/ExtBasic.c index 184d1be5..90d33753 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; } @@ -1817,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/ExtCell.c b/extract/ExtCell.c index 50c80ceb..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; } /* @@ -219,6 +221,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); +} + /* * ---------------------------------------------------------------------------- * @@ -240,7 +373,7 @@ extFileOpen(def, file, mode, doLocal, prealfile) * ---------------------------------------------------------------------------- */ -void +Plane * extCellFile(def, f, doLength) CellDef *def; /* Def to be extracted */ FILE *f; /* Output to this file */ @@ -250,9 +383,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); @@ -274,6 +411,7 @@ extCellFile(def, f, doLength) extLength(extParentUse, f); UndoEnable(); + return saveSub; } /* 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) 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/ExtHier.c b/extract/ExtHier.c index 73fa39e6..8056a8e9 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,49 @@ extHierSubstrate(ha, use, x, y) /* Find the child's substrate node */ nodeList = extFindNodes(use->cu_def, (Rect *) NULL, TRUE); + 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 */ + /* 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); + ExtResetTiles(use->cu_def, extUnInit); + return; + } + } + } /* Make sure substrate labels are represented */ ExtLabelRegions(use->cu_def, ExtCurStyle->exts_nodeConn, &nodeList, @@ -196,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; @@ -283,6 +348,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. @@ -330,31 +397,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/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/extract/ExtMain.c b/extract/ExtMain.c index d3b0c4f5..d9d499f9 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,16 @@ 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); + + freeMagic(sl); + } + if (!doExtract) { TxPrintf("\n"); 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 diff --git a/extract/ExtSubtree.c b/extract/ExtSubtree.c index 89b054a8..dfde1f9e 100644 --- a/extract/ExtSubtree.c +++ b/extract/ExtSubtree.c @@ -429,14 +429,12 @@ 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; + + /* 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. @@ -446,9 +444,6 @@ extSubtreeInteraction(ha) oneDef = oneFlat->et_use->cu_def; 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)) @@ -743,6 +738,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 +763,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 +794,6 @@ extSubtreeFunc(scx, ha) cumUse->cu_def->cd_labels = newlab; } } - extFirstPass = FALSE; } else { @@ -861,9 +858,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 +1210,6 @@ extSubtreeHardSearch(et, arg) HierExtractArg *ha = arg->hw_ha; ExtTree *oneFlat; - arg->hw_proc = extHardProc; if (et == &ha->ha_cumFlat) { 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..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 */ @@ -75,7 +76,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/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/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); diff --git a/lef/lefCmd.c b/lef/lefCmd.c index 6646d402..faa5d31e 100644 --- a/lef/lefCmd.c +++ b/lef/lefCmd.c @@ -92,6 +92,11 @@ CmdLef(w, cmd) * other than pin area surrounding labels, * with the indicated setback distance. */ + 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 * all layers below it obstructions. @@ -234,6 +239,17 @@ CmdLef(w, cmd) i++; } } + else if (!strncmp(cmd->tx_argv[i], "-pinonly", 8)) + { + 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)) @@ -244,8 +260,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 +302,23 @@ 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 = 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"); + } else if (!strncmp(cmd->tx_argv[i], "-toplayer", 9)) { if (is_lef) @@ -339,7 +372,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..aa12f0e6 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 */ + 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 */ { @@ -1421,8 +1422,19 @@ lefWriteMacro(def, f, scale, setback, toplayer, domaster) Rect carea; labelLinkedList *newlll; - SelectChunk(&scx, lab->lab_type, 0, &carea, FALSE); - if (GEO_RECTNULL(&carea)) carea = labr; + if (pinonly == 0) + carea = labr; + else + { + 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 */ /* tile types, which would cause SelectChunk to fail. So */ @@ -1445,16 +1457,47 @@ 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); + + /* 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. */ + + 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); + /* 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.). @@ -1964,11 +2007,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; + int lefPinOnly; bool lefTopLayer; bool lefDoMaster; bool recurse; @@ -2040,7 +2085,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 +2149,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 */ + 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 */ { @@ -2145,7 +2192,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"); 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/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/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); diff --git a/resis/ResConDCS.c b/resis/ResConDCS.c index a150cfb8..c1cca55b 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" @@ -29,30 +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 */ - - 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 */ -}; - -#define CSA2_LIST_START_SIZE 256 - extern int dbcUnconnectFunc(); extern int dbcConnectLabelFunc(); extern int dbcConnectFuncDCS(); @@ -67,7 +44,6 @@ TileTypeBitMask ResSubsTypeBitMask; /* Forward declarations */ extern void ResCalcPerimOverlap(); - /* * ---------------------------------------------------------------------------- * @@ -100,7 +76,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 +272,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 +419,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 +451,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 +474,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/resis/ResMain.c b/resis/ResMain.c index f1e65a47..d5c6469e 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; @@ -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); @@ -561,19 +573,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 +592,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 +641,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 +659,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 +672,9 @@ ResExtractNet(startlist,goodies,cellname) if (newdevtiles) { if (DevTiles) - { lasttile->nextDev = newdevtiles; - } else - { DevTiles = newdevtiles; - } lasttile = tmp; } } @@ -682,7 +688,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 +703,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/ResPrint.c b/resis/ResPrint.c index ac385a06..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); - } - } + } + } } - /* *------------------------------------------------------------------------- * @@ -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, @@ -202,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); - } - } + } + } } - /* *------------------------------------------------------------------------- * @@ -276,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); } /* @@ -323,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); diff --git a/resis/ResReadSim.c b/resis/ResReadSim.c index 8c040e48..cb663a0b 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. */ @@ -49,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 @@ -119,10 +119,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 +172,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 +186,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; @@ -229,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) { @@ -244,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) { @@ -317,6 +316,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 +453,7 @@ gettokens(line,fp) */ int -ResSimDevice(line,rpersquare,ttype) +ResSimDevice(line, rpersquare, ttype) char line[][MAXTOKEN]; float rpersquare; TileType ttype; @@ -428,7 +551,7 @@ ResSimDevice(line,rpersquare,ttype) */ int -ResSimNewNode(line,type,device) +ResSimNewNode(line, type, device) char line[]; int type; RDev *device; @@ -443,7 +566,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 +581,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..bc67e95d 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 */ @@ -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 */ @@ -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. * @@ -1169,27 +1165,26 @@ 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); } - (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 +1192,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) != NULL) && + ((drain = layoutDev->rd_fet_drain) != NULL)) { 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 +1247,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 +1257,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 +1310,10 @@ ResFixUpConnections(simDev, layoutDev, simNode, nodename) } } else - { TxError("missing SD connection\n"); - } } else - { resNodeNum--; - } } @@ -1346,7 +1331,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 +1344,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 +1382,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 +1433,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 +1488,12 @@ ResSortByGate(DevpointerList) else { if (working->nextDev != NULL) - { TxError("Bad Device pointer in sort\n"); - } else - { working->nextDev = gatelist; - } } } - /* *------------------------------------------------------------------------- * @@ -1536,13 +1516,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 +1614,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/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(); 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/select/selCreate.c b/select/selCreate.c index 62b01ebf..4a7124a2 100644 --- a/select/selCreate.c +++ b/select/selCreate.c @@ -253,6 +253,144 @@ selClearFunc(scx) else return 2; } +/* + * ---------------------------------------------------------------------------- + * + * selIntersectPaintFunc2 --- + * + * ---------------------------------------------------------------------------- + */ + +int +selIntersectPaintFunc2(tile, rect) + Tile *tile; /* The tile to copy paint from. */ + Rect *rect; /* Area to clip to */ +{ + Rect r; + + TiToRect(tile, &r); + GEOCLIP(&r, rect); /* Clip out the intersection area */ + DBPaint(SelectDef, &r, TiGetTypeExact(tile)); /* Paint back into SelectDef */ + return 0; /* Keep the search going. */ +} + +/* + * ---------------------------------------------------------------------------- + * + * selIntersectPaintFunc -- + * + * Erase paint of types in rMask from the area of the tile. + * + * ---------------------------------------------------------------------------- + */ + +int +selIntersectPaintFunc(tile) + Tile *tile; /* The tile to copy paint from. */ +{ + TileTypeBitMask tMask; + Rect r; + int pNum; + + TiToRect(tile, &r); + + for (pNum = 0; pNum < DBNumPlanes; pNum++) + { + DBSrPaintArea((Tile *)NULL, Select2Def->cd_planes[pNum], &r, + &DBAllButSpaceAndDRCBits, selIntersectPaintFunc2, + (ClientData)&r); + } + 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, type, xMask, negate) + 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. + */ + 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 + * considered. 0 means treat everything as + * expanded. + */ + bool negate; /* If true, search on NOT(type) */ +{ + TileTypeBitMask tMask, rMask; + TileType s, t; + int plane; + SearchContext scx2; + + /* The source definition may not change */ + if (SelectRootDef != scx->scx_use->cu_def) return; + + SelRememberForUndo(TRUE, (CellDef *) NULL, (Rect *) NULL); + + /* Copy SelectDef contents (paint only) into Select2Def */ + DBCellClearDef(Select2Def); + 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); + + /* Clear the original selection */ + DBCellClearDef(SelectDef); + + /* Select all paint of type "type" and copy into SelectDef */ + TTMaskSetOnlyType(&tMask, type); + + 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. */ + + SelRememberForUndo(FALSE, SelectRootDef, &scx->scx_area); + DBReComputeBbox(SelectDef); + DBWHLRedraw(SelectRootDef, &scx->scx_area, TRUE); + DBWAreaChanged(SelectDef, &SelectDef->cd_extended, DBW_ALLWINDOWS, + &DBAllButSpaceBits); +} /* * ---------------------------------------------------------------------------- @@ -749,7 +887,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 +988,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 */ @@ -1074,7 +1212,7 @@ SelectAndCopy2(newSourceDef) SearchContext scx; Rect editArea, labelArea, expanded; int plane; - void (*savedPaintPlane)(); + int (*savedPaintPlane)(); extern int selACPaintFunc(); /* Forward reference. */ extern int selACCellFunc(); diff --git a/select/selOps.c b/select/selOps.c index 1fdcf877..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" @@ -47,6 +48,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 { @@ -716,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; 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 diff --git a/select/select.h b/select/select.h index 843c1ee7..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(); @@ -56,6 +57,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; diff --git a/sim/SimDBstuff.c b/sim/SimDBstuff.c index 840d749f..640519ef 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" @@ -45,54 +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 */ - - 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 */ -}; - -#define CSA2_LIST_START_SIZE 256 - /* Forward declarations */ extern char *DBPrintUseId(); @@ -303,27 +256,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 +362,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 +381,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 (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) SimTreeSrNMTiles(scx, newtype, newmask, xMask, &tpath, @@ -435,6 +405,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. @@ -636,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; diff --git a/tcltk/readspice.tcl b/tcltk/readspice.tcl index 058185e0..b2390dc2 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,14 +110,20 @@ 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 if {$outport < $npins} {set outport $npins} set p [port first] while {$p != -1 && $p <= $highport} { + if {$p == ""} { + puts stderr "Error: $cell port numbering failed." + 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 @@ -150,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 @@ -167,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 } } diff --git a/tcltk/toolkit.tcl b/tcltk/toolkit.tcl index b3d43019..2e3a1619 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,307 @@ 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 {} + + # 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 ''. + + 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]}]} { + # 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 + } + } + 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 incmd false + set subname "" + set subpins "" + set complist {} + set toplist {} + + # suspendall + + set ignorekeys {.global .ic .option .end} + + # Parse the file + foreach line $fdata { + 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 {[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 {^[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]} { + set insub false + magic::generate_layout_add $subname $subpins $complist $library + set subname "" + set subpins "" + set complist {} + } 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 + } + } + } + + # Add in any top-level components (not in subcircuits) + if {[llength $toplist] > 0} { + magic::generate_layout_add $topname "" $toplist $library + } + + # resumeall +} + #------------------------------------------------------------- # gencell # @@ -184,6 +487,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} { @@ -237,6 +545,7 @@ proc magic::gencell {gencell_name {instname {}} args} { } } } + return 0 } #------------------------------------------------------------- @@ -436,6 +745,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 diff --git a/tcltk/tools.tcl b/tcltk/tools.tcl index 6addd626..878f7d37 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) + } } } @@ -123,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 } diff --git a/tcltk/wrapper.tcl b/tcltk/wrapper.tcl index 5bba211a..f8c3056f 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. Make sure scale doesn't go to zero or bad things happen. + + if [catch {set Opts(scale)}] { + set Opts(scale) [expr {max(1, int([font measure TkDefaultFont M] / 10))}] + } + # Resize the window if {[catch {wm geometry ${framename} $Winopts(${framename},geometry)}]} { catch {wm geometry ${framename} $Opts(geometry)} 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; } 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