Some further refinements to the last commit, and other additions:

(1) An incorrect use of ExtResetTiles() was found in "extresist"
    which impacts performance, especially for small nets.
(2) Corrected units for resistance tolerance in extresist, and
    handled output printing in fs when delay values get below ps
    size.
(3) Added command option "extract do unique notopports" to be the
    extraction option equivalent of the standalone command
    "extract unique notopports".
(4) Changed the "extresist" default for "mindelay" to 1ps from 0,
    in response to the observation that lumped resistance from
    "extract" can be an extreme overestimate, and the extracted
    time delay from "extesist" calculations should be used as a
    better determination of whether a net should be output as a
    resistor network or not.
(5) Added documentation for both "extract do unique notopports"
    and the change to the "extresist" default values.
This commit is contained in:
R. Timothy Edwards 2026-05-29 17:16:37 -04:00
parent 349ffd091f
commit c22031724a
11 changed files with 95 additions and 41 deletions

View File

@ -1096,7 +1096,7 @@ CmdExtract(
"lumped estimate lumped resistance",
"labelcheck check for connections through sticky labels",
"aliases output all net name aliases",
"unique ensure unique node names during extraction",
"unique [notopports] ensure unique node names during extraction",
"resistance extract resistance (same as \"do extresist\")",
NULL
};
@ -1403,6 +1403,7 @@ CmdExtract(
TxPrintf("%s label check\n", OPTSET(EXT_DOLABELCHECK));
TxPrintf("%s aliases\n", OPTSET(EXT_DOALIASES));
TxPrintf("%s unique\n", OPTSET(EXT_DOUNIQUE));
TxPrintf("%s unique notopports\n", OPTSET(EXT_DOUNIQNOTOPPORTS));
TxPrintf("%s resistance (extresist)\n", OPTSET(EXT_DOEXTRESIST));
return;
#undef OPTSET
@ -1433,9 +1434,19 @@ CmdExtract(
case DORESISTANCE: option = EXT_DORESISTANCE; break;
case DOLABELCHECK: option = EXT_DOLABELCHECK; break;
case DOALIASES: option = EXT_DOALIASES; break;
case DOUNIQUE: option = EXT_DOUNIQUE; break;
case DOEXTRESIST:
case DOEXTRESIST2: option = EXT_DOEXTRESIST; break;
case DOUNIQUE:
if (argc == 4)
{
if (!strncmp(argv[3], "notop", 5))
option = EXT_DOUNIQNOTOPPORTS | EXT_DOUNIQUE;
else
TxError("Usage: extract do unique [notopports]\n");
}
else
option = EXT_DOUNIQUE;
break;
case DOLOCAL:
/* "extract do local" and "extract no local" are kept for
* backwards compatibility, but now effectively implement

View File

@ -102,16 +102,17 @@ Circuit netlist extractor
but will usually just slow down processing by commands
like "ext2spice" that use the .ext file contents, so it
is disabled by default.
<DT> <B>unique</B>
<DT> <B>unique</B> [<B>notopports</B>]
<DD> (Added in magic version 8.3.594) This setting replaces
the use of the command option "extract unique". Instead
of changing labels in the design, unique labels are
generated for the duration of the extraction, and then
reverted back to the original text. The "extract unique"
command option is maintained for backwards compatibility.
Note the difference: "extract unique" is a command that
runs immediately, and cannot be undone;
"extract do unique" is an option setting for "extract".
the use of the command option "extract unique" (and
"extract unique notopports"). Instead of changing labels
in the design, unique labels are generated for the duration
of the extraction, and then reverted back to the original
text. The "extract unique" command option is maintained
for backwards compatibility. Note the difference:
"extract unique" is a command that runs immediately, and
cannot be undone; "extract do unique" is an option setting
for "extract".
<DT> <B>resistance</B>
<DD> (Added in magic version 8.3.597) This setting replaces
the use of the standalone command "extresist". The

View File

@ -43,8 +43,7 @@ information.
<DD> With no value given, returns the current delay time threshold
used to determine if a network will or will not be analyzed for
resistance extraction, in picoseconds. The default
<B>mindelay</B> value is zero, indicating that delay time is
not used for determining extraction. If <I>value</I> is given,
<B>mindelay</B> value is 1ps. If <I>value</I> is given,
then set the delay threshold to <I>value</I> picoseconds.
<DT> <B>minres</B> [<I>value</I>]
<DD> With no value given, returns the current absolute resistance

View File

@ -629,6 +629,8 @@ extSetResist(reg)
for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++)
{
ResValue resnew, restot;
reg->nreg_pa[n].pa_area = area = extResistArea[n];
reg->nreg_pa[n].pa_perim = perim = extResistPerim[n];
if (area > 0 && perim > 0)
@ -639,8 +641,15 @@ extSetResist(reg)
if (v < 0) s = 0; else s = sqrt(v);
fperim = (float) perim;
reg->nreg_resist += (fperim + s) / (fperim - s)
* ExtCurStyle->exts_resistByResistClass[n];
resnew = (fperim + s) / (fperim - s) *
ExtCurStyle->exts_resistByResistClass[n];
restot = reg->nreg_resist + resnew;
/* Check for integer overflow. There is no point in trying
* to accommodate huge resistance values for an estimate.
* The value just saturates at the maximum integer value.
*/
if (restot > 0) reg->nreg_resist = restot;
}
/* Reset for the next pass */

View File

@ -76,14 +76,10 @@ void extHeader();
*/
Plane *
ExtCell(def, outName, doLength)
ExtCell(def, outName, isTop)
CellDef *def; /* Cell being extracted */
char *outName; /* Name of output file; if NULL, derive from def name */
bool doLength; /* If TRUE, extract pathlengths from drivers to
* receivers (the names are stored in ExtLength.c).
* Should only be TRUE for the root cell in a
* hierarchy.
*/
bool isTop; /* If TRUE, cell is the top level cell */
{
char *filename;
FILE *f = NULL;
@ -116,7 +112,7 @@ ExtCell(def, outName, doLength)
}
extNumErrors = extNumWarnings = 0;
savePlane = extCellFile(def, f, doLength);
savePlane = extCellFile(def, f, isTop);
if (f != NULL) fclose(f);
if (extNumErrors > 0 || extNumWarnings > 0)
@ -476,13 +472,10 @@ ExtRevertSubstrate(def, savePlane)
*/
Plane *
extCellFile(def, f, doLength)
extCellFile(def, f, isTop)
CellDef *def; /* Def to be extracted */
FILE *f; /* Output to this file */
bool doLength; /* TRUE if we should extract driver-receiver path
* length information for this cell (see ExtCell
* for more details).
*/
bool isTop; /* TRUE if the cell is the top level cell */
{
NodeRegion *reg;
Plane *saveSub;
@ -493,8 +486,19 @@ extCellFile(def, f, doLength)
/* If "extract do unique" was specified, then make labels in the
* cell unique.
*/
if (ExtOptions & EXT_DOUNIQUE)
extUniqueCell(def, EXT_UNIQ_TEMP);
{
if (ExtOptions & EXT_DOUNIQNOTOPPORTS)
{
if (isTop)
extUniqueCell(def, EXT_UNIQ_TEMP_NOPORTS);
else
extUniqueCell(def, EXT_UNIQ_TEMP);
}
else
extUniqueCell(def, EXT_UNIQ_TEMP);
}
/* Prep any isolated substrate areas */
if (ExtOptions & EXT_DOEXTRESIST)
@ -524,7 +528,7 @@ extCellFile(def, f, doLength)
ExtResetTiles(def, CLIENTDEFAULT);
/* Final pass: extract length information if desired */
if (!SigInterruptPending && doLength && (ExtOptions & EXT_DOLENGTH))
if (!SigInterruptPending && isTop && (ExtOptions & EXT_DOLENGTH))
extLength(extParentUse, f);
UndoEnable();

View File

@ -473,6 +473,19 @@ ExtUnique(rootUse, option)
/* Fix up bounding boxes if they've changed */
DBFixMismatch();
/* Because the "extract unique" does the same thing as "extract do unique"
* but the options may be different, disable "extract do unique" when
* "extract unique" is run, on the assumption that no user would
* intentionally use both methods. If "do unique" was set and got
* disabled, then flag a warning.
*/
if (ExtOptions & EXT_DOUNIQUE)
{
ExtOptions &= ~EXT_DOUNIQUE;
TxPrintf("Warning: Extract option \"do unique\" disabled because "
"\"extract unique\" was run.\n");
}
/* Mark all defs as being unvisited */
(void) DBCellSrDefs(0, extDefInitFunc, (ClientData) 0);

View File

@ -66,6 +66,8 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
* label. This way, the unique label form can be used by the
* extraction code but labels (and port indexes) can be reverted
* afterward, and no permanent change is made to the circuit.
* Option EXT_UNIQ_TEMP_NOPORTS is a combination of EXT_UNIQ_TEMP and
* EXT_UNIQ_NOPORTS.
*
* Results:
* Returns the number of warnings generated.
@ -226,8 +228,9 @@ extMakeUnique(def, ll, lreg, lregList, labelHash, option)
text = ll->ll_label->lab_text;
if (option == EXT_UNIQ_ALL || option == EXT_UNIQ_TEMP)
goto makeUnique;
else if ((option == EXT_UNIQ_NOPORTS || option == EXT_UNIQ_NOTOPPORTS)
&& !(ll->ll_label->lab_flags & PORT_DIR_MASK))
else if ((option == EXT_UNIQ_NOPORTS || option == EXT_UNIQ_NOTOPPORTS ||
option == EXT_UNIQ_TEMP_NOPORTS) &&
!(ll->ll_label->lab_flags & PORT_DIR_MASK))
goto makeUnique;
cpend = strchr(text, '\0');
@ -326,7 +329,8 @@ makeUnique:
saveLab = *lab;
/* Flag this label as having been modified */
if (option == EXT_UNIQ_TEMP) flags |= LABEL_UNIQUE;
if ((option == EXT_UNIQ_TEMP) || (option == EXT_UNIQ_TEMP_NOPORTS))
flags |= LABEL_UNIQUE;
DBRemoveLabel(def, lab);
DBPutFontLabel(def, &saveLab.lab_rect,

View File

@ -76,6 +76,7 @@ extern const char * const extDevTable[];
#define EXT_DOLABELCHECK 0x040 /* Check for connections by label */
#define EXT_DOALIASES 0x080 /* Output all node aliases */
#define EXT_DOEXTRESIST 0x200 /* Do full R-C extraction */
#define EXT_DOUNIQNOTOPPORTS 0x400 /* Ignore top cell ports w/EXT_DOUNIQUE */
extern int ExtOptions; /* Bitmask of above */
extern char *ExtLocalPath; /* If non-NULL, location to write .ext files */
@ -86,6 +87,7 @@ extern char *ExtLocalPath; /* If non-NULL, location to write .ext files */
#define EXT_UNIQ_NOPORTS 2
#define EXT_UNIQ_NOTOPPORTS 3
#define EXT_UNIQ_TEMP 4 /* Used only with "EXT_DOUNIQUE" */
#define EXT_UNIQ_TEMP_NOPORTS 5 /* Used only with "EXT_DOUNIQUE" */
extern bool ExtTechLine();
extern void ExtTechInit();

View File

@ -1382,8 +1382,6 @@ ResExtractNet(node, resisdata, cellname)
}
DBReComputeBbox(ResUse->cu_def);
ExtResetTiles(scx.scx_use->cu_def, CLIENTDEFAULT);
/* To avoid issues with overlapping stacked contact types and */
/* double-counting contacts on multiple planes, erase the top */
/* contact layers of all contacts. ExtFindRegions() will still */

View File

@ -519,6 +519,7 @@ ResReadNode(int argc, char *argv[])
{
HashEntry *entry;
ResExtNode *node;
int noderesist;
entry = HashFind(&ResNodeTable, argv[NODES_NODENAME]);
node = ResExtInitNode(entry);
@ -526,7 +527,10 @@ ResReadNode(int argc, char *argv[])
node->location.p_x = atoi(argv[NODES_NODEX]);
node->location.p_y = atoi(argv[NODES_NODEY]);
node->type = DBTechNameType(argv[NODES_NODETYPE]);
node->resistance = atoi(argv[NODES_NODERES]);
noderesist = atoi(argv[NODES_NODERES]);
if (noderesist < 0) noderesist = INFINITY;
/* Make sure node resistance is in units of milliohms */
node->resistance = (float)noderesist * (float)ExtCurStyle->exts_resistScale;
if (node->type == -1)
{

View File

@ -218,11 +218,11 @@ ResInit()
/* Defaults:
* (1) rthresh: Only extract networks with a lumped resistance > 10 ohms
* (2) minres: Prune resistors < 1 ohm when possible
* (3) mindelay: Do not gate extraction based on calculated delay.
* (3) mindelay: Only extract networks with a calculated delay > 1 ps
*/
resisdata->rthresh = 10000.0;
resisdata->minres = 1000.0;
resisdata->mindelay = 0.0;
resisdata->mindelay = 1.0e9; /* 1ps = 1.0e9zs
resisdata->frequency = 10e6; /* 10 MHz default */
HashInit(&ResIgnoreTable, INITFLATSIZE, HT_STRINGKEYS);
@ -407,7 +407,8 @@ typedef enum {
Tcl_SetObjResult(magicinterp,
Tcl_NewDoubleObj((double)resisdata->rthresh));
#else
TxPrintf("Minimum resistor threshold is %g.\n", resisdata->rthresh);
TxPrintf("Minimum resistor threshold is %g mohms.\n",
resisdata->rthresh);
#endif
}
return;
@ -1907,9 +1908,17 @@ ResWriteExtFile(celldef, node, resisdata, nidx, eidx)
if (!(ResOptionsFlags & ResOpt_RunSilent))
{
TxPrintf("Adding %s; (Tnew = %.2fps ; Tmin = %.2fps)\n",
node->name, resisdata->rg_Tdi * Z_TO_P,
resisdata->mindelay * Z_TO_P);
float ftdi, fdmin;
ftdi = resisdata->rg_Tdi * Z_TO_P;
fdmin = resisdata->mindelay * Z_TO_P;
if ((ftdi < 0.01) || ((fdmin < 0.01) && (resisdata->mindelay > 0)))
TxPrintf("Adding %s; (Tnew = %.2ffs ; Tmin = %.2ffs)\n",
node->name, ftdi * 1000, fdmin * 1000);
else
TxPrintf("Adding %s; (Tnew = %.2fps ; Tmin = %.2fps)\n",
node->name, ftdi, fdmin);
}
for (ptr = node->devices; ptr != NULL; ptr = ptr->nextDev)