Beginning to tear apart the extresist code; work in progress
and a lot of construction mess. Resolved conflicts after rebasing on master, since both were modifying the list of options to "extract".
This commit is contained in:
parent
4943da5ce4
commit
b768fcc3f9
141
README
141
README
|
|
@ -2,33 +2,126 @@ Second major code overhaul of 2026
|
|||
-----------------------------------------
|
||||
Implement the planned changes to "extresist":
|
||||
|
||||
(1) Remove the .sim format as a requirement.
|
||||
extresist will get its node list from doing
|
||||
a standard extraction (extFindNodes() or
|
||||
ExtFindRegions(), whichever is appropriate.
|
||||
This should be able to be done as a relatively
|
||||
simple change, allowing "extresist" to be used
|
||||
(1) Remove the .sim format as a requirement. extresist will get its node
|
||||
list from doing a standard extraction (extFindNodes() or
|
||||
ExtFindRegions(), whichever is appropriate. This should be able to be
|
||||
done as a relatively simple change, allowing "extresist" to be used
|
||||
without doing "ext2sim" as part of the process.
|
||||
|
||||
(2) Move extresist into the "extract" code.
|
||||
"extresist" will become a command "extract do
|
||||
extresist" and "ext2spice extresist on|off"
|
||||
will determine if split nodes and terminals
|
||||
are kept apart in the final netlist or
|
||||
aggregated---Exactly as capacitance is done
|
||||
now.
|
||||
(2) Move extresist into the "extract" code. "extresist" will become a
|
||||
command "extract do extresist" and "ext2spice extresist on|off"
|
||||
will determine if split nodes and terminals are kept apart in the
|
||||
final netlist or aggregated---Exactly as capacitance is done now.
|
||||
|
||||
Need to figure out how "tile junk" client data
|
||||
and extract client data can exist simultaneously.
|
||||
Need to figure out how "tile junk" client data and extract client
|
||||
data can exist simultaneously.
|
||||
|
||||
"extresist" will run within "extBasic", being
|
||||
called on a node after the devices and nodes are
|
||||
identified; nodes created by ExtFindRegions()
|
||||
will get sub-divided into more nodes. The
|
||||
difficult case will be where a single tile gets
|
||||
multiple nodes (such as where other wires branch
|
||||
off the tile in the up or down direction). Maybe
|
||||
this can be done like ClientData for split tiles,
|
||||
with an indicator bit in ti_body?
|
||||
"extresist" will run within "extBasic", being called on a node after
|
||||
the devices and nodes are identified; nodes created by ExtFindRegions()
|
||||
will get sub-divided into more nodes. The difficult case will be where
|
||||
a single tile gets multiple nodes (such as where other wires branch off
|
||||
the tile in the up or down direction). Maybe this can be done like
|
||||
ClientData for split tiles, with an indicator bit in ti_body?
|
||||
|
||||
-----------------------------------------------------
|
||||
For (1):
|
||||
|
||||
Reading the "nodes" file only creates "node" entries, one per net.
|
||||
With an ExtFindRegions and ExtLabelRegions (or extFindNodes?) there
|
||||
should be an equivalent list from which node names, locations, and
|
||||
types can be taken. This information will be redundant, for now.
|
||||
|
||||
Note that ExtResisForDef() runs extResPrepSubstrate() which is like
|
||||
extPrepSubstrate(), which is run from extCellFile().
|
||||
|
||||
So ExtResisForDef() could replace lines 150 to 174 with the ExtBasic
|
||||
calls to ExtFindRegions(), extFindNodes(), and ExtLabelRegions().
|
||||
This is followed by temporary code that creates the tables and lists
|
||||
that the extresist code uses. Then, run the ResCheckSimNodes() code,
|
||||
or at least the part for a single node (which is ResRex.c lines 1071
|
||||
to 1240)
|
||||
|
||||
Add a ClientData record to a NodeRegion, and extresist can run
|
||||
by adding "tileJunk" records to the NodeRegion client data, and
|
||||
leave the region records in place. (done)
|
||||
|
||||
Then need to figure out how to output the data all at once.
|
||||
|
||||
Replace the "extresist" command with "extract do extresist".
|
||||
EXT_DOEXTRESIST. Maybe later replace "resistance" and make it
|
||||
equivalent to "extresist", or maybe make "resistance" *be*
|
||||
DOEXTRESIST and use "lumped" instead of "resistance" (I like
|
||||
this better). (done)
|
||||
|
||||
"ext2spice extresist on" will then output the netlist exactly as
|
||||
it appears in the .ext file, while "ext2spice extresist off" will
|
||||
conglomerate the .tX and .nX sub-nodes and produce what is
|
||||
hopefully the equivalent of a netlist from a .ext file without
|
||||
"extract do extresist".
|
||||
|
||||
We keep (maybe)
|
||||
HashTable ResNodeTable
|
||||
RDev *ResRDevList
|
||||
|
||||
At issue: Doing it this way might be more convenient, but by
|
||||
keeping the NodeRegions in place and adding "tileJunk" records,
|
||||
it's harder to find where the subnets are connected. If the
|
||||
NodeRegions get replaced, then there are way more regions but,
|
||||
for example, a transistor terminal node is easily found by
|
||||
looking at the Region pointer connected to the terminal type.
|
||||
However, nodes are output by working through the node list and
|
||||
devices are output by working through the device list, so the
|
||||
information is readily available.
|
||||
|
||||
Currently the "to-do" work starts at ExtBasic.c line 313.
|
||||
|
||||
Pulled out the central part of ResCheckSimNodes() into "ResProcessNode()".
|
||||
This allows ExtBasic.c to loop over its own nodeList, prepare the
|
||||
ResSimNode structure, and then call ResProcessNode() to process a
|
||||
single network.
|
||||
|
||||
These are all then bypassed:
|
||||
|
||||
CmdExtResist()
|
||||
ExtResisForDef()
|
||||
extResPrepSubstrate()
|
||||
ResReadSim()
|
||||
ResCheckPorts()
|
||||
ResCheckSimNodes()
|
||||
(clean up ResNodeTable and ResRDevList)
|
||||
|
||||
The only one of the bypassed routines which may need to be handled
|
||||
is "ResCheckPorts()". Possibly the ExtSubtree/ExtHier stuff can be
|
||||
used in place? The main issue is figuring out where the ports are.
|
||||
Unlike the original "extresist" method, it should be possible to do
|
||||
this properly. Punt on it for the moment.
|
||||
|
||||
Try to compile with the separated-out ResProcessNode() routine.
|
||||
Okay, got that working.
|
||||
|
||||
Now, the hard work: Prepare an extresist node record from ExtBasic.c.
|
||||
Don't worry about how ClientData records are managed, for now.
|
||||
|
||||
Now, what does ResCleanUpEverything() do? We don't want to destroy
|
||||
the records until the end. Maybe node regions should be replaced by
|
||||
subnets here? And the resistors can be kept in a linked list or
|
||||
hash table to be output along with the devices.
|
||||
|
||||
The issue here is that some tiles can contain multiple sub-nets,
|
||||
if there are wires branching off. Note, however, that wires can
|
||||
only branch off of a single rectangle in the north or south directions,
|
||||
due to the "maximum horizontal stripes" rule. What if subnets within
|
||||
a tile were handled by splitting the tile, which would only be done
|
||||
horizontally, and keeping the tiles separate by setting a flag in
|
||||
ti_body such that a long wire with many branches would be split into
|
||||
multiple segments with the flag set to 1010101. . ., which allows the
|
||||
normal tile handling to work. The flags can be cleaned up afterward
|
||||
and the tiles merged (maybe just erase and repaint the tile)? Note
|
||||
that this would never happen with split tiles. Probably okay with
|
||||
contacts?
|
||||
|
||||
Due to the maximum horizontal stripes consideration, does
|
||||
ResCalcNorthSouth() *ever* get called??
|
||||
Okay, a long vertical contact with metal branches on either side
|
||||
would invalidate my assumption, and yes, ResCalcNorthSouth() would
|
||||
be called.
|
||||
|
|
|
|||
|
|
@ -931,6 +931,7 @@ cmdExpandFunc(
|
|||
#define DOLABELCHECK 7
|
||||
#define DOALIASES 8
|
||||
#define DOUNIQUE 9
|
||||
#define DOEXTRESIST 10
|
||||
|
||||
#define LENCLEAR 0
|
||||
#define LENDRIVER 1
|
||||
|
|
@ -975,10 +976,11 @@ CmdExtract(
|
|||
"coupling extract coupling capacitance",
|
||||
"length compute driver-receiver pathlengths",
|
||||
"local put all generated files in the current directory",
|
||||
"resistance estimate resistance",
|
||||
"lumped estimate lumped resistance",
|
||||
"labelcheck check for connections through sticky labels",
|
||||
"aliases output all net name aliases",
|
||||
"unique ensure unique node names during extraction",
|
||||
"resistance extract resistance",
|
||||
NULL
|
||||
};
|
||||
static const char * const cmdExtLength[] =
|
||||
|
|
@ -1280,10 +1282,11 @@ CmdExtract(
|
|||
TxPrintf("%s capacitance\n", OPTSET(EXT_DOCAPACITANCE));
|
||||
TxPrintf("%s coupling\n", OPTSET(EXT_DOCOUPLING));
|
||||
TxPrintf("%s length\n", OPTSET(EXT_DOLENGTH));
|
||||
TxPrintf("%s resistance\n", OPTSET(EXT_DORESISTANCE));
|
||||
TxPrintf("%s lumped R\n", OPTSET(EXT_DORESISTANCE));
|
||||
TxPrintf("%s label check\n", OPTSET(EXT_DOLABELCHECK));
|
||||
TxPrintf("%s aliases\n", OPTSET(EXT_DOALIASES));
|
||||
TxPrintf("%s unique\n", OPTSET(EXT_DOUNIQUE));
|
||||
TxPrintf("%s resistance\n", OPTSET(EXT_DOEXTRESIST));
|
||||
return;
|
||||
#undef OPTSET
|
||||
}
|
||||
|
|
@ -1314,6 +1317,7 @@ CmdExtract(
|
|||
case DOLABELCHECK: option = EXT_DOLABELCHECK; break;
|
||||
case DOALIASES: option = EXT_DOALIASES; break;
|
||||
case DOUNIQUE: option = EXT_DOUNIQUE; break;
|
||||
case DOEXTRESIST: option = EXT_DOEXTRESIST; break;
|
||||
case DOLOCAL:
|
||||
/* "extract do local" and "extract no local" are kept for
|
||||
* backwards compatibility, but now effectively implement
|
||||
|
|
|
|||
|
|
@ -301,6 +301,28 @@ extBasic(def, outFile)
|
|||
if (!SigInterruptPending && (ExtDoWarn & EXTWARN_DUP) && !isabstract)
|
||||
extFindDuplicateLabels(def, nodeList);
|
||||
|
||||
/*
|
||||
* If full R-C extraction is requested, then run it now. This
|
||||
* code was previously run as the "extresist" command, but it
|
||||
* makes more sense to be integral to the extraction process.
|
||||
* It must be run prior to extFindCoupling() so that coupling
|
||||
* capacitances are correctly assigned to subnets.
|
||||
*/
|
||||
if (!SigInterruptPending && (ExtOptions & EXT_DOEXTRESIST))
|
||||
{
|
||||
ResSimNode *rsimnode;
|
||||
ResisData resisdata;
|
||||
int n_ext = 0, n_out = 0;
|
||||
|
||||
for (reg = nodeList; reg && !SigInterruptPending; reg = reg->nreg_next)
|
||||
{
|
||||
rsimnode = ResCreateNode();
|
||||
ResProcessNode(rsimnode, def, &resisdata, &n_ext, &n_out);
|
||||
|
||||
/* To be completed */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Build up table of coupling capacitances (overlap, sidewall).
|
||||
* This comes before extOutputNodes because we may have to adjust
|
||||
|
|
|
|||
|
|
@ -68,13 +68,14 @@ extern const char * const extDevTable[];
|
|||
#define EXT_DOADJUST 0x001 /* Extract hierarchical adjustments */
|
||||
#define EXT_DOCAPACITANCE 0x002 /* Extract capacitance */
|
||||
#define EXT_DOCOUPLING 0x004 /* Extract coupling capacitance */
|
||||
#define EXT_DORESISTANCE 0x008 /* Extract resistance */
|
||||
#define EXT_DORESISTANCE 0x008 /* Extract lumped resistance */
|
||||
#define EXT_DOLENGTH 0x010 /* Extract pathlengths */
|
||||
#define EXT_DOFRINGEHALO 0x020 /* Distributed fringe capacitance */
|
||||
#define EXT_DOALL 0x03f /* ALL OF THE ABOVE */
|
||||
#define EXT_DOLABELCHECK 0x040 /* Check for connections by label */
|
||||
#define EXT_DOALIASES 0x080 /* Output all node aliases */
|
||||
#define EXT_DOUNIQUE 0x100 /* Force unique nodes during extraction */
|
||||
#define EXT_DOEXTRESIST 0x200 /* Do full R-C extraction */
|
||||
|
||||
extern int ExtOptions; /* Bitmask of above */
|
||||
extern char *ExtLocalPath; /* If non-NULL, location to write .ext files */
|
||||
|
|
|
|||
|
|
@ -209,6 +209,7 @@ typedef struct nreg
|
|||
* in X, then in Y.
|
||||
*/
|
||||
LabelList *nreg_labels; /* See LabRegion for description */
|
||||
ClientData nreg_subnet; /* Subnet record generated by extresist */
|
||||
CapValue nreg_cap; /* Capacitance to ground */
|
||||
ResValue nreg_resist; /* Resistance estimate */
|
||||
PerimArea nreg_pa[1]; /* Dummy; each node actually has
|
||||
|
|
|
|||
438
resis/ResRex.c
438
resis/ResRex.c
|
|
@ -966,6 +966,223 @@ ResCheckPorts(cellDef)
|
|||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResCreateNode ---
|
||||
*
|
||||
* Create a node structure for extresist for the method where
|
||||
* ResProcessNode() is called from extBasic() as part of the
|
||||
* "extract" command.
|
||||
*
|
||||
* Results:
|
||||
* Returns the node structure to be passed to ResProcessNode().
|
||||
*
|
||||
* Side effects:
|
||||
* Memory is allocated for the node structure.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
ResSimNode *ResCreateNode()
|
||||
{
|
||||
ResSimNode *node;
|
||||
|
||||
/* To be completed */
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* ResProcessNode ---
|
||||
*
|
||||
* Do resistance extraction for a single network.
|
||||
*
|
||||
* Results:
|
||||
* 1 if node was processed, 0 otherwise.
|
||||
*
|
||||
* Side effects:
|
||||
* Many. Update the totals for number of nets extracted and
|
||||
* number of nets output in the pointers in the argument list.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
ResProcessNode(
|
||||
ResSimNode *node, /* Node record for network */
|
||||
CellDef *celldef, /* Cell def being processed */
|
||||
ResisData *resisdata, /* Extraction parameters kept here */
|
||||
char *outfile, /* Name of output file */
|
||||
int *num_extracted, /* Number of nets extracted so far */
|
||||
int *num_output) /* Number of nets output so far */
|
||||
{
|
||||
HashEntry *he;
|
||||
devPtr *ptr;
|
||||
float ftolerance, minRes, cumRes;
|
||||
float rctol = resisdata->tdiTolerance;
|
||||
float rthresh = resisdata->rthresh;
|
||||
int nidx = 1, eidx = 1; /* node & segment counters for geom. */
|
||||
|
||||
/* Ignore or include specified nodes */
|
||||
|
||||
if (ResIncludeTable.ht_nEntries > 0)
|
||||
{
|
||||
he = HashLookOnly(&ResIncludeTable, node->name);
|
||||
if (he == NULL) return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
he = HashLookOnly(&ResIgnoreTable, node->name);
|
||||
if (he != NULL) return 0;
|
||||
}
|
||||
|
||||
/* Has this node been merged away or is it marked as skipped? */
|
||||
/* If so, skip it */
|
||||
|
||||
if ((node->status & (FORWARD | REDUNDANT)) ||
|
||||
((node->status & SKIP) &&
|
||||
(ResOptionsFlags & ResOpt_ExtractAll) == 0))
|
||||
return 0;
|
||||
|
||||
ResCurrentNode = node->name;
|
||||
ResSortByGate(&node->firstDev);
|
||||
|
||||
/* Find largest SD device connected to node. */
|
||||
|
||||
minRes = FLT_MAX;
|
||||
gparams.rg_devloc = (Point *) NULL;
|
||||
gparams.rg_status = FALSE;
|
||||
gparams.rg_nodecap = node->capacitance;
|
||||
|
||||
/* The following is only used if there is a drivepoint */
|
||||
/* to identify which tile the drivepoint is on. */
|
||||
|
||||
gparams.rg_ttype = node->rs_ttype;
|
||||
|
||||
for (ptr = node->firstDev; ptr != NULL; ptr = ptr->nextDev)
|
||||
{
|
||||
RDev *t1;
|
||||
RDev *t2;
|
||||
|
||||
if (ptr->terminal == GATE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Get cumulative resistance of all devices */
|
||||
/* with same connections. */
|
||||
|
||||
cumRes = ptr->thisDev->resistance;
|
||||
t1 = ptr->thisDev;
|
||||
for (; ptr->nextDev != NULL; ptr = ptr->nextDev)
|
||||
{
|
||||
t1 = ptr->thisDev;
|
||||
t2 = ptr->nextDev->thisDev;
|
||||
if (t1->gate != t2->gate) break;
|
||||
if ((t1->source != t2->source || t1->drain != t2->drain) &&
|
||||
(t1->source != t2->drain || t1->drain != t2->source))
|
||||
break;
|
||||
|
||||
/* Do parallel combination */
|
||||
if ((cumRes != 0.0) && (t2->resistance != 0.0))
|
||||
cumRes = (cumRes * t2->resistance) / (cumRes + t2->resistance);
|
||||
else
|
||||
cumRes = 0;
|
||||
}
|
||||
if (minRes > cumRes)
|
||||
{
|
||||
minRes = cumRes;
|
||||
gparams.rg_devloc = &t1->location;
|
||||
gparams.rg_ttype = t1->rs_ttype;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* special handling for FORCE and DRIVELOC labels: */
|
||||
/* set minRes = node->minsizeres if it exists, 0 otherwise */
|
||||
|
||||
if (node->status & (FORCE|DRIVELOC))
|
||||
{
|
||||
if (node->status & MINSIZE)
|
||||
{
|
||||
minRes = node->minsizeres;
|
||||
}
|
||||
else
|
||||
{
|
||||
minRes = 0;
|
||||
}
|
||||
if (node->status & DRIVELOC)
|
||||
{
|
||||
gparams.rg_devloc = &node->drivepoint;
|
||||
gparams.rg_status |= DRIVEONLY;
|
||||
}
|
||||
if (node->status & PORTNODE)
|
||||
{
|
||||
/* The node is a port, not a device, so make */
|
||||
/* sure rg_ttype is set accordingly. */
|
||||
gparams.rg_ttype = node->rs_ttype;
|
||||
}
|
||||
}
|
||||
if ((gparams.rg_devloc == NULL) && (node->status & FORCE))
|
||||
{
|
||||
TxError("Node %s has force label but no drive point or "
|
||||
"driving device\n", node->name);
|
||||
}
|
||||
if ((minRes == FLT_MAX) || (gparams.rg_devloc == NULL))
|
||||
return 1;
|
||||
|
||||
gparams.rg_bigdevres = (int)minRes * OHMSTOMILLIOHMS;
|
||||
if (minRes > resisdata->rthresh)
|
||||
ftolerance = minRes;
|
||||
else
|
||||
ftolerance = resisdata->rthresh;
|
||||
|
||||
/*
|
||||
* Is the device resistance greater than the lumped node
|
||||
* resistance? If so, extract net.
|
||||
*/
|
||||
|
||||
if ((node->resistance > ftolerance) || (node->status & FORCE) ||
|
||||
(ResOpt_ExtractAll & ResOptionsFlags))
|
||||
{
|
||||
ResFixPoint fp;
|
||||
|
||||
(*num_extracted)++;
|
||||
if (ResExtractNet(node, &gparams, outfile) != 0)
|
||||
{
|
||||
/* On error, don't output this net, but keep going */
|
||||
if (node->type == TT_SPACE)
|
||||
TxPrintf("Note: Substrate node %s not extracted as network.\n",
|
||||
node->name);
|
||||
else
|
||||
TxError("Error in extracting node %s\n", node->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
ResDoSimplify(ftolerance, rctol, &gparams);
|
||||
if (ResOptionsFlags & ResOpt_DoLumpFile)
|
||||
ResWriteLumpFile(node);
|
||||
|
||||
if (gparams.rg_maxres >= ftolerance ||
|
||||
(ResOptionsFlags & ResOpt_ExtractAll))
|
||||
{
|
||||
resNodeNum = 0;
|
||||
(*num_output) += ResWriteExtFile(celldef, node, rctol, &nidx, &eidx);
|
||||
}
|
||||
}
|
||||
#ifdef PARANOID
|
||||
ResSanityChecks(node->name, ResResList, ResNodeList, ResDevList);
|
||||
#endif
|
||||
ResCleanUpEverything();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -988,15 +1205,10 @@ ResCheckSimNodes(celldef, resisdata)
|
|||
ResisData *resisdata;
|
||||
{
|
||||
ResSimNode *node;
|
||||
devPtr *ptr;
|
||||
float ftolerance, minRes, cumRes;
|
||||
int failed1=0;
|
||||
int failed3=0;
|
||||
int total =0;
|
||||
int numext = 0; /* Number of nets extracted */
|
||||
int numout = 0; /* Number of nets output */
|
||||
int total = 0; /* Total number of nets processed */
|
||||
char *outfile = celldef->cd_name;
|
||||
float rctol = resisdata->tdiTolerance;
|
||||
float rthresh = resisdata->rthresh;
|
||||
int nidx = 1, eidx = 1; /* node & segment counters for geom. */
|
||||
|
||||
if (ResOptionsFlags & ResOpt_DoExtFile)
|
||||
{
|
||||
|
|
@ -1005,8 +1217,8 @@ ResCheckSimNodes(celldef, resisdata)
|
|||
if (strcmp(ExtLocalPath, "."))
|
||||
{
|
||||
char *namebuf;
|
||||
namebuf = alloc = mallocMagic(strlen(ExtLocalPath) + strlen(celldef->cd_name)
|
||||
+ 2);
|
||||
namebuf = alloc = mallocMagic(strlen(ExtLocalPath) +
|
||||
strlen(celldef->cd_name) + 2);
|
||||
sprintf(namebuf, "%s/%s", ExtLocalPath, celldef->cd_name);
|
||||
outfile = namebuf;
|
||||
}
|
||||
|
|
@ -1015,17 +1227,13 @@ ResCheckSimNodes(celldef, resisdata)
|
|||
outfile = celldef->cd_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
ResExtFile = NULL;
|
||||
}
|
||||
|
||||
if (ResOptionsFlags & ResOpt_DoLumpFile)
|
||||
{
|
||||
ResLumpFile = PaOpen(outfile, "w", ".res.lump", ".", (char *)NULL, (char **)NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
ResLumpFile = NULL;
|
||||
}
|
||||
|
||||
if (ResOptionsFlags & ResOpt_FastHenry)
|
||||
{
|
||||
char *geofilename;
|
||||
|
|
@ -1034,9 +1242,7 @@ ResCheckSimNodes(celldef, resisdata)
|
|||
ResPortIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ResFHFile = NULL;
|
||||
}
|
||||
|
||||
if ((ResExtFile == NULL && (ResOptionsFlags & ResOpt_DoExtFile))
|
||||
|| ((ResOptionsFlags & ResOpt_DoLumpFile) && ResLumpFile == NULL)
|
||||
|
|
@ -1052,191 +1258,23 @@ ResCheckSimNodes(celldef, resisdata)
|
|||
*/
|
||||
|
||||
if (ResExtFile != NULL)
|
||||
{
|
||||
fprintf(ResExtFile, "scale %d %d %g\n",
|
||||
ExtCurStyle->exts_resistScale,
|
||||
ExtCurStyle->exts_capScale,
|
||||
ExtCurStyle->exts_unitsPerLambda);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write reference plane (substrate) definition and end statement
|
||||
* to the FastHenry geometry file.
|
||||
*/
|
||||
if (ResOptionsFlags & ResOpt_FastHenry)
|
||||
{
|
||||
ResPrintReference(ResFHFile, ResRDevList, celldef);
|
||||
}
|
||||
|
||||
for (node = ResOriginalNodes; node != NULL; node=node->nextnode)
|
||||
{
|
||||
HashEntry *he;
|
||||
|
||||
if (SigInterruptPending) break;
|
||||
|
||||
/* Ignore or include specified nodes */
|
||||
|
||||
if (ResIncludeTable.ht_nEntries > 0)
|
||||
{
|
||||
he = HashLookOnly(&ResIncludeTable, node->name);
|
||||
if (he == NULL) continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
he = HashLookOnly(&ResIgnoreTable, node->name);
|
||||
if (he != NULL) continue;
|
||||
}
|
||||
|
||||
/* Has this node been merged away or is it marked as skipped? */
|
||||
/* If so, skip it */
|
||||
if ((node->status & (FORWARD | REDUNDANT)) ||
|
||||
((node->status & SKIP) &&
|
||||
(ResOptionsFlags & ResOpt_ExtractAll) == 0))
|
||||
continue;
|
||||
|
||||
ResCurrentNode = node->name;
|
||||
total++;
|
||||
|
||||
ResSortByGate(&node->firstDev);
|
||||
|
||||
/* Find largest SD device connected to node. */
|
||||
|
||||
minRes = FLT_MAX;
|
||||
gparams.rg_devloc = (Point *) NULL;
|
||||
gparams.rg_status = FALSE;
|
||||
gparams.rg_nodecap = node->capacitance;
|
||||
|
||||
/* The following is only used if there is a drivepoint */
|
||||
/* to identify which tile the drivepoint is on. */
|
||||
|
||||
gparams.rg_ttype = node->rs_ttype;
|
||||
|
||||
for (ptr = node->firstDev; ptr != NULL; ptr = ptr->nextDev)
|
||||
{
|
||||
RDev *t1;
|
||||
RDev *t2;
|
||||
|
||||
if (ptr->terminal == GATE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Get cumulative resistance of all devices */
|
||||
/* with same connections. */
|
||||
|
||||
cumRes = ptr->thisDev->resistance;
|
||||
t1 = ptr->thisDev;
|
||||
for (; ptr->nextDev != NULL; ptr = ptr->nextDev)
|
||||
{
|
||||
t1 = ptr->thisDev;
|
||||
t2 = ptr->nextDev->thisDev;
|
||||
if (t1->gate != t2->gate) break;
|
||||
if ((t1->source != t2->source ||
|
||||
t1->drain != t2->drain) &&
|
||||
(t1->source != t2->drain ||
|
||||
t1->drain != t2->source)) break;
|
||||
|
||||
/* Do parallel combination */
|
||||
if ((cumRes != 0.0) && (t2->resistance != 0.0))
|
||||
{
|
||||
cumRes = (cumRes * t2->resistance) /
|
||||
(cumRes + t2->resistance);
|
||||
}
|
||||
else
|
||||
{
|
||||
cumRes = 0;
|
||||
}
|
||||
}
|
||||
if (minRes > cumRes)
|
||||
{
|
||||
minRes = cumRes;
|
||||
gparams.rg_devloc = &t1->location;
|
||||
gparams.rg_ttype = t1->rs_ttype;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* special handling for FORCE and DRIVELOC labels: */
|
||||
/* set minRes = node->minsizeres if it exists, 0 otherwise */
|
||||
|
||||
if (node->status & (FORCE|DRIVELOC))
|
||||
{
|
||||
if (node->status & MINSIZE)
|
||||
{
|
||||
minRes = node->minsizeres;
|
||||
}
|
||||
else
|
||||
{
|
||||
minRes = 0;
|
||||
}
|
||||
if (node->status & DRIVELOC)
|
||||
{
|
||||
gparams.rg_devloc = &node->drivepoint;
|
||||
gparams.rg_status |= DRIVEONLY;
|
||||
}
|
||||
if (node->status & PORTNODE)
|
||||
{
|
||||
/* The node is a port, not a device, so make */
|
||||
/* sure rg_ttype is set accordingly. */
|
||||
gparams.rg_ttype = node->rs_ttype;
|
||||
}
|
||||
}
|
||||
if ((gparams.rg_devloc == NULL) && (node->status & FORCE))
|
||||
{
|
||||
TxError("Node %s has force label but no drive point or "
|
||||
"driving device\n", node->name);
|
||||
}
|
||||
if ((minRes == FLT_MAX) || (gparams.rg_devloc == NULL))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
gparams.rg_bigdevres = (int)minRes * OHMSTOMILLIOHMS;
|
||||
if (minRes > resisdata->rthresh)
|
||||
ftolerance = minRes;
|
||||
else
|
||||
ftolerance = resisdata->rthresh;
|
||||
|
||||
/*
|
||||
* Is the device resistance greater than the lumped node
|
||||
* resistance? If so, extract net.
|
||||
*/
|
||||
|
||||
if ((node->resistance > ftolerance) || (node->status & FORCE) ||
|
||||
(ResOpt_ExtractAll & ResOptionsFlags))
|
||||
{
|
||||
ResFixPoint fp;
|
||||
|
||||
failed1++;
|
||||
if (ResExtractNet(node, &gparams, outfile) != 0)
|
||||
{
|
||||
/* On error, don't output this net, but keep going */
|
||||
if (node->type == TT_SPACE)
|
||||
TxPrintf("Note: Substrate node %s not extracted as network.\n",
|
||||
node->name);
|
||||
else
|
||||
TxError("Error in extracting node %s\n", node->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
ResDoSimplify(ftolerance, rctol, &gparams);
|
||||
if (ResOptionsFlags & ResOpt_DoLumpFile)
|
||||
{
|
||||
ResWriteLumpFile(node);
|
||||
}
|
||||
if (gparams.rg_maxres >= ftolerance ||
|
||||
(ResOptionsFlags & ResOpt_ExtractAll))
|
||||
{
|
||||
resNodeNum = 0;
|
||||
failed3 += ResWriteExtFile(celldef, node, rctol,
|
||||
&nidx, &eidx);
|
||||
}
|
||||
}
|
||||
#ifdef PARANOID
|
||||
ResSanityChecks(node->name, ResResList, ResNodeList, ResDevList);
|
||||
#endif
|
||||
ResCleanUpEverything();
|
||||
}
|
||||
total += ResProcessNode(node, celldef, resisdata, outfile,
|
||||
&numext, &numout);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1245,9 +1283,7 @@ ResCheckSimNodes(celldef, resisdata)
|
|||
*/
|
||||
|
||||
if (ResOptionsFlags & ResOpt_DoExtFile)
|
||||
{
|
||||
ResPrintExtDev(ResExtFile, ResRDevList);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write end statement to the FastHenry geometry file.
|
||||
|
|
@ -1280,30 +1316,20 @@ ResCheckSimNodes(celldef, resisdata)
|
|||
/* Output statistics about extraction */
|
||||
|
||||
if (total)
|
||||
{
|
||||
TxPrintf("Total Nets: %d\nNets extracted: "
|
||||
"%d (%f)\nNets output: %d (%f)\n", total, failed1,
|
||||
(float)failed1 / (float)total, failed3,
|
||||
(float)failed3 / (float)total);
|
||||
}
|
||||
"%d (%f)\nNets output: %d (%f)\n", total, numext,
|
||||
(float)numext / (float)total, numout,
|
||||
(float)numout / (float)total);
|
||||
else
|
||||
{
|
||||
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);
|
||||
if (ResExtFile != NULL) (void) fclose(ResExtFile);
|
||||
if (ResLumpFile != NULL) (void) fclose(ResLumpFile);
|
||||
if (ResFHFile != NULL) (void) fclose(ResFHFile);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue