From 15f1c82bc9d5003bd15da7f2868e5812ec5c62bc Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 1 Jun 2020 16:49:59 -0400 Subject: [PATCH] Added two new features: (1) Default substrate name: Added an optional name field to the "substrate" line in the extract section of the techfile. This is the default name of the substrate if not connected to anything labeled. It may use a Tcl variable (preferred). (2) Added command option "instance orientation [-def]" that returns the orientation of the named or selected instance. The -def option returns the orientation using DEF naming convention; otherwise, the naming used with "getcell" is generated. --- VERSION | 2 +- commands/CmdCD.c | 45 +++++++++-- database/DBcellname.c | 165 ++++++++++++++++++++++++++++++++++++++++- database/database.h.in | 3 + extract/ExtBasic.c | 24 +++++- extract/ExtTech.c | 10 ++- utils/geometry.c | 58 +++++++++++++++ 7 files changed, 294 insertions(+), 13 deletions(-) diff --git a/VERSION b/VERSION index 3dbda18d..2933de05 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.19 +8.3.20 diff --git a/commands/CmdCD.c b/commands/CmdCD.c index 396ebb66..aebc0b4e 100644 --- a/commands/CmdCD.c +++ b/commands/CmdCD.c @@ -579,6 +579,8 @@ outputCalma: * cellname [list] filepath [path|"default"] * or * cellname property [name] [property_key [property_value]] + * or + * instance orientation [name] [-def] * * Results: * None. @@ -597,7 +599,9 @@ CmdCellname(w, cmd) MagWindow *w; TxCommand *cmd; { + bool is_cellname; bool dolist = FALSE; + bool dodef = FALSE; int option; int locargc = cmd->tx_argc; char *cellname = NULL; @@ -623,6 +627,7 @@ CmdCellname(w, cmd) "lock lock the named cell (prevent changes to cell use)", "unlock unlock the named cell (allow changes to cell use)", "property list or set cell definition properties", + "orientation list or set instance orientation", "rename rename the indicated cell", "writeable make the cell definition read-only or read-write", "modified true if modified, false if not", @@ -632,13 +637,15 @@ CmdCellname(w, cmd) IDX_INSTANCE, IDX_CHILDINST, IDX_CELLDEF, IDX_ALLCELLS, IDX_TOPCELLS, IDX_IN_WINDOW, IDX_CREATE, IDX_DELETE, IDX_FILEPATH, IDX_FLAGS, IDX_LOCK, IDX_UNLOCK, - IDX_PROPERTY, IDX_RENAME, IDX_READWRITE, - IDX_MODIFIED } optionType; + IDX_PROPERTY, IDX_ORIENTATION, IDX_RENAME, + IDX_READWRITE, IDX_MODIFIED } optionType; if (strstr(cmd->tx_argv[0], "in")) - func = DBUsePrint; + is_cellname = FALSE; else - func = DBCellPrint; + is_cellname = TRUE; + + func = (is_cellname) ? DBCellPrint : DBUsePrint; if (locargc > 1) { @@ -647,6 +654,21 @@ CmdCellname(w, cmd) locargc--; } } + + /* Check for option at end of option list */ + + if (*cmd->tx_argv[cmd->tx_argc - 1] == '-') { + char *option = cmd->tx_argv[cmd->tx_argc - 1] + 1; + if (!strcmp(option, "list")) { + dolist = TRUE; + locargc--; + } + else if (!strcmp(option, "def")) { + dodef = TRUE; + locargc--; + } + } + if (locargc > 5 || locargc < 2) goto badusage; option = Lookup(cmd->tx_argv[1 + ((dolist) ? 1 : 0)], cmdCellOption); @@ -672,7 +694,7 @@ CmdCellname(w, cmd) } } - if (func != DBUsePrint) + if (is_cellname) { /* These functions only work with cell uses (instances) */ switch (option) { @@ -681,6 +703,10 @@ CmdCellname(w, cmd) TxError("Cell definitions cannot be locked. Use \"instance\"?\n"); TxError(" or do you mean \"cellname writeable\"?\n"); return; + case IDX_ORIENTATION: + TxError("Cell definitions do not have orientations." + " Use \"instance\"?\n"); + return; } } else @@ -721,16 +747,16 @@ CmdCellname(w, cmd) (*func)(cellname, SELF, dolist); break; case IDX_CELLDEF: - (*func)(cellname, ((func == DBUsePrint) ? OTHER : SELF), dolist); + (*func)(cellname, ((is_cellname == FALSE) ? OTHER : SELF), dolist); break; case IDX_INSTANCE: - (*func)(cellname, ((func == DBUsePrint) ? SELF : OTHER), dolist); + (*func)(cellname, ((is_cellname == FALSE) ? SELF : OTHER), dolist); break; case IDX_CHILDREN: (*func)(cellname, CHILDREN, dolist); break; case IDX_CHILDINST: - (*func)(cellname, ((func == DBUsePrint) ? CHILDREN : CHILDINST), dolist); + (*func)(cellname, ((is_cellname == FALSE) ? CHILDREN : CHILDINST), dolist); break; case IDX_PARENTS: (*func)(cellname, PARENTS, dolist); @@ -958,6 +984,9 @@ CmdCellname(w, cmd) DBCellSetAvail(newDef); } break; + case IDX_ORIENTATION: + DBOrientUse(cellname, dodef); + break; case IDX_LOCK: DBLockUse(cellname, TRUE); break; diff --git a/database/DBcellname.c b/database/DBcellname.c index 2672d6ba..ec10d1ee 100644 --- a/database/DBcellname.c +++ b/database/DBcellname.c @@ -1154,7 +1154,7 @@ DBLockUse(UseName, bval) CellDef *celldef; CellUse *celluse; - int dbUseLockFunc(); + int dbLockUseFunc(); /* * @@ -1199,6 +1199,169 @@ DBLockUse(UseName, bval) } } +/* + * ---------------------------------------------------------------------------- + * + * DBOrientUse -- + * + * This routine sets or reports a cell instance's orientation + * UseName is the name of a specific CellUse. If NULL, then the + * operation applies to all selected cell uses. "orient" is a + * string in the form used by "getcell" (e.g., "180", "270v", + * etc.), unless "dodef" is true, in which case the output is + * given in the form used by DEF ("N", "FN", etc.). + * reported. + * + * Results: + * None. + * + * Side effects: + * cu_transform changed for indicated cell use. + * + * ---------------------------------------------------------------------------- + */ + +void +DBOrientUse(UseName, dodef) + char *UseName; + bool dodef; +{ + int found; + HashSearch hs; + HashEntry *entry; + CellDef *celldef; + CellUse *celluse; + + int dbOrientUseFunc(); + + /* + * + * Check to see if a cell name was specified. If not, then search + * for selected cells. + * + */ + + if (UseName == NULL) + { + if (EditCellUse == NULL) + TxError("Cannot set orientation of a non-edit cell!\n"); + else + SelEnumCells(TRUE, (int *)NULL, (SearchContext *)NULL, + dbOrientUseFunc, (ClientData)&dodef); + } + else + { + SearchContext scx; + + bzero(&scx, sizeof(SearchContext)); + found = 0; + + HashStartSearch(&hs); + while( (entry = HashNext(&dbCellDefTable, &hs)) != NULL) + { + celldef = (CellDef *) HashGetValue(entry); + if (celldef != (CellDef *) NULL) + { + celluse = celldef->cd_parents; /* only need one */ + if (celluse != (CellUse *)NULL) { + DBTreeFindUse(UseName, celluse, &scx); + if (scx.scx_use != NULL) break; + } + } + } + + if (scx.scx_use == NULL) + TxError("Cell %s is not currently loaded.\n", UseName); + else + dbOrientUseFunc(NULL, scx.scx_use, NULL, (ClientData)&dodef); + } +} + +/* + * dbOrientUseFunc() + */ + +/* For corresponding enumerations, see GeoTransOrient() */ +enum def_orient {ORIENT_NORTH, ORIENT_SOUTH, ORIENT_EAST, ORIENT_WEST, + ORIENT_FLIPPED_NORTH, ORIENT_FLIPPED_SOUTH, ORIENT_FLIPPED_EAST, + ORIENT_FLIPPED_WEST}; + +int +dbOrientUseFunc(selUse, use, transform, data) + CellUse *selUse; /* Use from selection cell */ + CellUse *use; /* Use from layout corresponding to selection */ + Transform *transform; + ClientData data; +{ + bool *dodef = (bool *)data; + + if (EditCellUse && !DBIsChild(use, EditCellUse)) + { + TxError("Cell %s (%s) isn't a child of the edit cell.\n", + use->cu_id, use->cu_def->cd_name); + return 0; + } + + if (selUse != NULL) + { + switch (GeoTransOrient(&selUse->cu_transform)) { +#ifdef MAGIC_WRAPPER + case ORIENT_NORTH: + Tcl_AppendElement(magicinterp, (*dodef) ? "N" : "0"); + break; + case ORIENT_EAST: + Tcl_AppendElement(magicinterp, (*dodef) ? "E" : "90"); + break; + case ORIENT_SOUTH: + Tcl_AppendElement(magicinterp, (*dodef) ? "S" : "180"); + break; + case ORIENT_WEST: + Tcl_AppendElement(magicinterp, (*dodef) ? "W" : "270"); + break; + case ORIENT_FLIPPED_NORTH: + Tcl_AppendElement(magicinterp, (*dodef) ? "FN" : "0h"); + break; + case ORIENT_FLIPPED_EAST: + Tcl_AppendElement(magicinterp, (*dodef) ? "FE" : "90h"); + break; + case ORIENT_FLIPPED_SOUTH: + Tcl_AppendElement(magicinterp, (*dodef) ? "FS" : "180h"); + break; + case ORIENT_FLIPPED_WEST: + Tcl_AppendElement(magicinterp, (*dodef) ? "FW" : "270h"); + break; +#else + case ORIENT_NORTH: + TxPrintf((*dodef) ? "N" : "0"); + break; + case ORIENT_EAST: + TxPrintf((*dodef) ? "E" : "90"); + break; + case ORIENT_SOUTH: + TxPrintf((*dodef) ? "S" : "180"); + break; + case ORIENT_WEST: + TxPrintf((*dodef) ? "W" : "270"); + break; + case ORIENT_FLIPPED_NORTH: + TxPrintf((*dodef) ? "FN" : "0h"); + break; + case ORIENT_FLIPPED_EAST: + TxPrintf((*dodef) ? "FE" : "90h"); + break; + case ORIENT_FLIPPED_SOUTH: + TxPrintf((*dodef) ? "FS" : "180h"); + break; + case ORIENT_FLIPPED_WEST: + TxPrintf((*dodef) ? "FW" : "270h"); + break; +#endif + } + + } + return 0; +} + /* * ---------------------------------------------------------------------------- * diff --git a/database/database.h.in b/database/database.h.in index d88cf249..9ee227b2 100644 --- a/database/database.h.in +++ b/database/database.h.in @@ -772,6 +772,9 @@ extern int DBCellSrDefs(); extern CellUse *DBCellNewUse(); extern bool DBCellDeleteUse(); extern CellUse *DBCellFindDup(); +extern void DBLockUse(); +extern void DBUnlockUse(); +extern void DBOrientUse(); /* Cell selection */ extern CellUse *DBSelectCell(); diff --git a/extract/ExtBasic.c b/extract/ExtBasic.c index 03e018bf..23c20fcb 100644 --- a/extract/ExtBasic.c +++ b/extract/ExtBasic.c @@ -321,7 +321,7 @@ extBasic(def, outFile) /* Output each node, along with its resistance and capacitance to substrate */ if (!SigInterruptPending) - extOutputNodes(nodeList, outFile); + extOutputNodes(nodeList, outFile, glob_subsnode); /* Output coupling capacitances */ if (!SigInterruptPending && (ExtOptions&EXT_DOCOUPLING) && (!propfound)) @@ -862,6 +862,28 @@ extNodeName(node) if (extLabType(ll->ll_label->lab_text, LABTYPE_NAME)) return (ll->ll_label->lab_text); + /* If the techfile specifies a global name for the substrate, use */ + /* that in preference to the default "p_x_y#" name. */ + + if ((NodeRegion *)node == glob_subsnode) + { + if (ExtCurStyle->exts_globSubstrateName != NULL) + { + if (ExtCurStyle->exts_globSubstrateName[0] == '$' && + ExtCurStyle->exts_globSubstrateName[1] != '$') + { + // If subsName is a Tcl variable (begins with "$"), make the + // variable substitution, if one exists. Ignore double-$. + + char *varsub = (char *)Tcl_GetVar(magicinterp, + &ExtCurStyle->exts_globSubstrateName[1], + TCL_GLOBAL_ONLY); + return (varsub != NULL) ? varsub : ExtCurStyle->exts_globSubstrateName; + } + else + return ExtCurStyle->exts_globSubstrateName; + } + } extMakeNodeNumPrint(namebuf, node->lreg_pnum, node->lreg_ll); return (namebuf); } diff --git a/extract/ExtTech.c b/extract/ExtTech.c index 55212d59..06e04b54 100644 --- a/extract/ExtTech.c +++ b/extract/ExtTech.c @@ -166,8 +166,8 @@ static keydesc keyTable[] = { "style", STYLE, 2, 4, "stylename", - "substrate", SUBSTRATE, 3, 4, -"types plane", + "substrate", SUBSTRATE, 3, 5, +"types plane [subs-node]", "units", UNITS, 2, 2, "lambda|microns", @@ -786,6 +786,7 @@ extTechStyleInit(style) style->exts_globSubstratePlane = -1; TTMaskZero(&style->exts_globSubstrateTypes); TTMaskZero(&style->exts_globSubstrateShieldTypes); + style->exts_globSubstrateName = (char *)NULL; } @@ -2834,6 +2835,11 @@ ExtTechLine(sectionName, argc, argv) TTMaskSetMask(&ExtCurStyle->exts_globSubstrateTypes, &types1); ExtCurStyle->exts_globSubstrateShieldTypes = idTypes; ExtCurStyle->exts_globSubstratePlane = DBTechNoisyNamePlane(argv[2]); + + /* Handle optional substrate node name */ + if (argc == 4) + ExtCurStyle->exts_globSubstrateName = StrDup((char **)NULL, argv[3]); + break; case NOPLANEORDER: { if ( ExtCurStyle->exts_planeOrderStatus == seenPlaneOrder ) diff --git a/utils/geometry.c b/utils/geometry.c index faabe9d3..791f390b 100644 --- a/utils/geometry.c +++ b/utils/geometry.c @@ -530,6 +530,64 @@ GeoTransPos(t, pos) return pos; } +/*------------------------------------------------------------------- + * GeoTransOrient -- + * This routine returns the orientation corresponding to a transform. + * + * Results: + * The return value is an orientation as defined by the enumeration + * below (which is also used by the LEF read routine). It has to + * agree with the enumeration used by dbOrientUseFunc. + * + * Side Effects: None. + *------------------------------------------------------------------- + */ + +enum def_orient {ORIENT_NORTH, ORIENT_SOUTH, ORIENT_EAST, ORIENT_WEST, + ORIENT_FLIPPED_NORTH, ORIENT_FLIPPED_SOUTH, ORIENT_FLIPPED_EAST, + ORIENT_FLIPPED_WEST}; + +int +GeoTransOrient(t) + Transform *t; /* Transform to be applied. */ + +{ + int pidx; + + if ((t->t_b == 0) && (t->t_d == 0)) + { + pidx = ((t->t_a) > 0) ? 1 : 0; + pidx += ((t->t_e) > 0) ? 2 : 0; + + switch (pidx) { + case 0: + return ORIENT_SOUTH; + case 1: + return ORIENT_FLIPPED_SOUTH; + case 2: + return ORIENT_FLIPPED_NORTH; + case 3: + return ORIENT_NORTH; + } + } + else if ((t->t_a == 0) && (t->t_e == 0)) + { + pidx = ((t->t_b) > 0) ? 1 : 0; + pidx += ((t->t_d) > 0) ? 2 : 0; + + switch (pidx) { + case 0: + return ORIENT_FLIPPED_EAST; + case 1: + return ORIENT_EAST; + case 2: + return ORIENT_WEST; + case 3: + return ORIENT_FLIPPED_WEST; + } + } +} + /*------------------------------------------------------------------- * GeoInvertTrans --