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 --