Found another issue with the substrate extraction, caused by the
fact that "extract all" does not enumerate cells from bottom up as I had assumed---The order is roughly bottom-to-top, but cells re-used in different places in the hierarchy could end up called before one or more of their own subcells is extracted. Since this conflicted with the preparation of the substrate in each extracted subcircuit, I changed the method to enumerate cells so that it is properly bottom-to-top. Also, methods were added to "extract" (incremental), "extract cell", and "extract parents" to ensure that the substrate is prepared on all subcells before extraction.
This commit is contained in:
parent
ff10aedf69
commit
a09fa78d2c
|
|
@ -1062,7 +1062,7 @@ CmdExtract(w, cmd)
|
|||
TxError("No cell selected\n");
|
||||
return;
|
||||
}
|
||||
ExtCell(selectedUse->cu_def, namep, FALSE);
|
||||
ExtractOneCell(selectedUse->cu_def, namep, FALSE);
|
||||
return;
|
||||
|
||||
case EXTPARENTS:
|
||||
|
|
|
|||
|
|
@ -416,6 +416,8 @@ typedef struct celldef
|
|||
* with caution as it messes with the usual timestamp tracking,
|
||||
* but is useful for preparing libraries all cells of which have
|
||||
* the same timestamp value.
|
||||
* CDNOEXTRACT is used by incremental extraction to flag cells that
|
||||
* are up-to-date and do not need to be re-extracted.
|
||||
*/
|
||||
|
||||
#define CDAVAILABLE 0x00001
|
||||
|
|
@ -435,6 +437,7 @@ typedef struct celldef
|
|||
#define CDVISITED 0x04000
|
||||
#define CDDEREFERENCE 0x08000
|
||||
#define CDFIXEDSTAMP 0x10000
|
||||
#define CDNOEXTRACT 0x20000
|
||||
|
||||
/*
|
||||
* Description of an array.
|
||||
|
|
|
|||
|
|
@ -94,12 +94,18 @@ ExtCell(def, outName, doLength)
|
|||
*/
|
||||
{
|
||||
char *filename;
|
||||
FILE *f;
|
||||
FILE *f = NULL;
|
||||
Plane *savePlane;
|
||||
bool doLocal;
|
||||
|
||||
doLocal = (ExtOptions & EXT_DOLOCAL) ? TRUE : FALSE;
|
||||
|
||||
/* Incremental extraction: If the cell is marked for no extraction,
|
||||
* then just prepare the substrate plane and return it to the caller.
|
||||
*/
|
||||
if (def->cd_flags & CDNOEXTRACT)
|
||||
return extPrepSubstrate(def);
|
||||
|
||||
f = extFileOpen(def, outName, "w", doLocal, &filename);
|
||||
|
||||
TxPrintf("Extracting %s into %s:\n", def->cd_name, filename);
|
||||
|
|
@ -117,7 +123,7 @@ ExtCell(def, outName, doLength)
|
|||
|
||||
extNumErrors = extNumWarnings = 0;
|
||||
savePlane = extCellFile(def, f, doLength);
|
||||
(void) fclose(f);
|
||||
if (f != NULL) fclose(f);
|
||||
|
||||
if (extNumErrors > 0 || extNumWarnings > 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -75,11 +75,28 @@ CellUse *extParentUse;
|
|||
|
||||
/* ------------------------ Data local to this file ------------------- */
|
||||
|
||||
typedef struct _linkedDef {
|
||||
CellDef *ld_def;
|
||||
struct _linkedDef *ld_next;
|
||||
} LinkedDef;
|
||||
|
||||
/* 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;
|
||||
};
|
||||
|
||||
/* Stack of defs pending extraction */
|
||||
Stack *extDefStack;
|
||||
|
||||
/* Forward declarations */
|
||||
int extDefInitFunc(), extDefPushFunc();
|
||||
int extDefInitFunc();
|
||||
void extDefPush();
|
||||
void extDefIncremental();
|
||||
void extParents();
|
||||
void extDefParentFunc();
|
||||
void extDefParentAreaFunc();
|
||||
|
|
@ -154,6 +171,82 @@ ExtInit()
|
|||
extLengthInit();
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
extDefListFunc(use, defList)
|
||||
CellUse *use;
|
||||
LinkedDef **defList;
|
||||
{
|
||||
CellDef *def = use->cu_def;
|
||||
LinkedDef *newLD;
|
||||
|
||||
/* Ignore all internal cells and cells that have been visited */
|
||||
if (def->cd_flags & CDINTERNAL) return 0;
|
||||
|
||||
/* Recurse to the bottom first */
|
||||
(void) DBCellEnum(def, extDefListFunc, (ClientData)defList);
|
||||
|
||||
/* Don't add cells that have already been visited */
|
||||
if (def->cd_client) return 0;
|
||||
|
||||
/* When done with descendents, add self to the linked list */
|
||||
|
||||
newLD = (LinkedDef *)mallocMagic(sizeof(LinkedDef));
|
||||
newLD->ld_def = def;
|
||||
newLD->ld_next = *defList;
|
||||
*defList = newLD;
|
||||
|
||||
/* Mark self as visited */
|
||||
def->cd_client = (ClientData) 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
extDefListFuncIncremental(use, defList)
|
||||
CellUse *use;
|
||||
LinkedDef **defList;
|
||||
{
|
||||
CellDef *def = use->cu_def;
|
||||
LinkedDef *newLD;
|
||||
|
||||
/* Ignore all internal cells */
|
||||
if (def->cd_flags & CDINTERNAL) return 0;
|
||||
|
||||
/* Mark cells that don't need updating */
|
||||
if (!extTimestampMisMatch(def))
|
||||
def->cd_flags |= CDNOEXTRACT;
|
||||
|
||||
/* Recurse to the bottom first */
|
||||
(void) DBCellEnum(def, extDefListFuncIncremental, (ClientData)defList);
|
||||
|
||||
/* Don't add cells that have already been visited */
|
||||
if (def->cd_client) return 0;
|
||||
|
||||
/* When done with descendents, add self to the linked list */
|
||||
|
||||
newLD = (LinkedDef *)mallocMagic(sizeof(LinkedDef));
|
||||
newLD->ld_def = def;
|
||||
newLD->ld_next = *defList;
|
||||
*defList = newLD;
|
||||
|
||||
/* Mark self as visited */
|
||||
def->cd_client = (ClientData) 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -178,6 +271,8 @@ void
|
|||
ExtAll(rootUse)
|
||||
CellUse *rootUse;
|
||||
{
|
||||
LinkedDef *defList = NULL;
|
||||
|
||||
/* Make sure the entire subtree is read in */
|
||||
if (DBCellReadArea(rootUse, &rootUse->cu_def->cd_bbox, TRUE))
|
||||
{
|
||||
|
|
@ -191,9 +286,16 @@ ExtAll(rootUse)
|
|||
/* Mark all defs as being unvisited */
|
||||
(void) DBCellSrDefs(0, extDefInitFunc, (ClientData) 0);
|
||||
|
||||
/* Recursively visit all defs in the tree and push on stack */
|
||||
/* Recursively visit all defs in the tree and create a linked list */
|
||||
/* from bottommost back up to the top. */
|
||||
|
||||
extDefListFunc(rootUse, &defList);
|
||||
|
||||
/* Now reverse the list onto a stack such that the bottommost cell */
|
||||
/* is the first to be extracted, and so forth back up to the top. */
|
||||
|
||||
extDefStack = StackNew(100);
|
||||
(void) extDefPushFunc(rootUse);
|
||||
extDefPush(defList);
|
||||
|
||||
/* Now extract all the cells we just found */
|
||||
extExtractStack(extDefStack, TRUE, rootUse->cu_def);
|
||||
|
|
@ -214,22 +316,20 @@ extDefInitFunc(def)
|
|||
}
|
||||
|
||||
/*
|
||||
* Function to push each cell def on extDefStack
|
||||
* if it hasn't already been pushed, and then recurse
|
||||
* on all that def's children.
|
||||
* Function to reverse the linked list of CellDefs to extract by
|
||||
* pushing each cell def from the list onto extDefStack.
|
||||
*/
|
||||
int
|
||||
extDefPushFunc(use)
|
||||
CellUse *use;
|
||||
|
||||
void
|
||||
extDefPush(defList)
|
||||
LinkedDef *defList;
|
||||
{
|
||||
CellDef *def = use->cu_def;
|
||||
|
||||
if (def->cd_client || (def->cd_flags&CDINTERNAL))
|
||||
return (0);
|
||||
|
||||
def->cd_client = (ClientData) 1;
|
||||
StackPush((ClientData) def, extDefStack);
|
||||
(void) DBCellEnum(def, extDefPushFunc, (ClientData) 0);
|
||||
while (defList != NULL)
|
||||
{
|
||||
StackPush((ClientData)defList->ld_def, extDefStack);
|
||||
freeMagic(defList);
|
||||
defList = defList->ld_next;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
@ -266,6 +366,7 @@ ExtUnique(rootUse, option)
|
|||
int option;
|
||||
{
|
||||
CellDef *def;
|
||||
LinkedDef *defList = NULL;
|
||||
int nwarn;
|
||||
int locoption;
|
||||
|
||||
|
|
@ -282,9 +383,16 @@ ExtUnique(rootUse, option)
|
|||
/* Mark all defs as being unvisited */
|
||||
(void) DBCellSrDefs(0, extDefInitFunc, (ClientData) 0);
|
||||
|
||||
/* Recursively visit all defs in the tree and push on stack */
|
||||
/* Recursively visit all defs in the tree and create a linked list */
|
||||
/* from bottommost back up to the top. */
|
||||
|
||||
extDefListFunc(rootUse, &defList);
|
||||
|
||||
/* Now reverse the list onto a stack such that the bottommost cell */
|
||||
/* is the first to be extracted, and so forth back up to the top. */
|
||||
|
||||
extDefStack = StackNew(100);
|
||||
(void) extDefPushFunc(rootUse);
|
||||
extDefPush(defList);
|
||||
|
||||
/* Now process all the cells we just found */
|
||||
nwarn = 0;
|
||||
|
|
@ -349,6 +457,38 @@ extParents(use, doExtract)
|
|||
CellUse *use;
|
||||
bool doExtract; /* If TRUE, we extract; if FALSE, we print */
|
||||
{
|
||||
LinkedDef *defList = NULL;
|
||||
CellDef *def;
|
||||
Plane *saveSub;
|
||||
struct saveList *newsl, *sl = (struct saveList *)NULL;
|
||||
|
||||
/* Mark all defs as being unvisited */
|
||||
(void) DBCellSrDefs(0, extDefInitFunc, (ClientData) 0);
|
||||
|
||||
/* All children of use->cu_def need substrate preparation */
|
||||
extDefListFunc(use, &defList);
|
||||
|
||||
/* use->cu_def is on the top of the list, so remove it */
|
||||
freeMagic(defList);
|
||||
defList = defList->ld_next;
|
||||
|
||||
while (defList != NULL)
|
||||
{
|
||||
def = defList->ld_def;
|
||||
saveSub = extPrepSubstrate(def);
|
||||
if (saveSub != NULL)
|
||||
{
|
||||
newsl = (struct saveList *)mallocMagic(sizeof(struct saveList));
|
||||
newsl->sl_plane = saveSub;
|
||||
newsl->sl_def = def;
|
||||
newsl->sl_next = sl;
|
||||
sl = newsl;
|
||||
}
|
||||
|
||||
freeMagic(defList);
|
||||
defList = defList->ld_next;
|
||||
}
|
||||
|
||||
/* Mark all defs as being unvisited */
|
||||
(void) DBCellSrDefs(0, extDefInitFunc, (ClientData) 0);
|
||||
|
||||
|
|
@ -359,6 +499,13 @@ extParents(use, doExtract)
|
|||
/* Now extract all the cells we just found */
|
||||
extExtractStack(extDefStack, doExtract, (CellDef *) NULL);
|
||||
StackFree(extDefStack);
|
||||
|
||||
/* Replace any modified substrate planes in use->cu_def's children */
|
||||
for (; sl; sl = sl->sl_next)
|
||||
{
|
||||
ExtRevertSubstrate(sl->sl_def, sl->sl_plane);
|
||||
freeMagic(sl);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -482,6 +629,76 @@ extDefParentAreaFunc(def, baseDef, allButUse, area)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* ExtractOneCell ---
|
||||
*
|
||||
* Extract a single cell by preparing the substrate plane of all of its
|
||||
* children, calling ExtCell(), then restoring the substrate planes of
|
||||
* all the cells.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
ExtractOneCell(def, outName, doLength)
|
||||
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.
|
||||
*/
|
||||
{
|
||||
LinkedDef *defList = NULL;
|
||||
CellUse dummyUse;
|
||||
CellDef *subDef;
|
||||
Plane *savePlane;
|
||||
struct saveList *newsl, *sl = (struct saveList *)NULL;
|
||||
|
||||
dummyUse.cu_def = def;
|
||||
|
||||
/* Mark all defs as being unvisited */
|
||||
(void) DBCellSrDefs(0, extDefInitFunc, (ClientData) 0);
|
||||
|
||||
extDefListFunc(&dummyUse, &defList);
|
||||
|
||||
/* def is on top of the list, so remove it */
|
||||
freeMagic(defList);
|
||||
defList = defList->ld_next;
|
||||
|
||||
/* Prepare substrates of all children of def */
|
||||
while (defList != NULL)
|
||||
{
|
||||
subDef = defList->ld_def;
|
||||
savePlane = extPrepSubstrate(subDef);
|
||||
if (savePlane != NULL)
|
||||
{
|
||||
newsl = (struct saveList *)mallocMagic(sizeof(struct saveList));
|
||||
newsl->sl_plane = savePlane;
|
||||
newsl->sl_def = subDef;
|
||||
newsl->sl_next = sl;
|
||||
sl = newsl;
|
||||
}
|
||||
freeMagic(defList);
|
||||
defList = defList->ld_next;
|
||||
}
|
||||
|
||||
savePlane = ExtCell(def, outName, doLength);
|
||||
|
||||
/* Restore all modified substrate planes */
|
||||
|
||||
if (savePlane != NULL) ExtRevertSubstrate(def, savePlane);
|
||||
for (; sl; sl = sl->sl_next)
|
||||
{
|
||||
ExtRevertSubstrate(sl->sl_def, sl->sl_plane);
|
||||
freeMagic(sl);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
bool
|
||||
extContainsGeometry(def, allButUse, area)
|
||||
CellDef *def;
|
||||
|
|
@ -505,6 +722,8 @@ extContainsGeometry(def, allButUse, area)
|
|||
return (FALSE);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
bool
|
||||
extContainsCellFunc(use, allButUse)
|
||||
CellUse *use;
|
||||
|
|
@ -542,6 +761,8 @@ void
|
|||
ExtIncremental(rootUse)
|
||||
CellUse *rootUse;
|
||||
{
|
||||
LinkedDef *defList = NULL;
|
||||
|
||||
/* Make sure the entire subtree is read in */
|
||||
if (DBCellReadArea(rootUse, &rootUse->cu_def->cd_bbox, TRUE))
|
||||
{
|
||||
|
|
@ -558,12 +779,16 @@ ExtIncremental(rootUse)
|
|||
/* Mark all defs as being unvisited */
|
||||
(void) DBCellSrDefs(0, extDefInitFunc, (ClientData) 0);
|
||||
|
||||
/*
|
||||
* Recursively visit all defs in the tree
|
||||
* and push on stack if they need extraction.
|
||||
*/
|
||||
/* Recursively visit all defs in the tree and create a linked list */
|
||||
/* from bottommost back up to the top. */
|
||||
|
||||
extDefListFuncIncremental(rootUse, &defList);
|
||||
|
||||
/* Now reverse the list onto a stack such that the bottommost cell */
|
||||
/* is the first to be extracted, and so forth back up to the top. */
|
||||
|
||||
extDefStack = StackNew(100);
|
||||
(void) extDefIncrementalFunc(rootUse);
|
||||
extDefPush(defList);
|
||||
|
||||
/* Now extract all the cells we just found */
|
||||
extExtractStack(extDefStack, TRUE, rootUse->cu_def);
|
||||
|
|
@ -571,32 +796,12 @@ ExtIncremental(rootUse)
|
|||
}
|
||||
|
||||
/*
|
||||
* Function to push each cell def on extDefStack if it hasn't
|
||||
* already been pushed and if it needs re-extraction, and then
|
||||
* recurse on all that def's children.
|
||||
*/
|
||||
|
||||
int
|
||||
extDefIncrementalFunc(use)
|
||||
CellUse *use;
|
||||
{
|
||||
CellDef *def = use->cu_def;
|
||||
|
||||
if (def->cd_client || (def->cd_flags&CDINTERNAL))
|
||||
return (0);
|
||||
|
||||
def->cd_client = (ClientData) 1;
|
||||
if (extTimestampMisMatch(def))
|
||||
StackPush((ClientData) def, extDefStack);
|
||||
(void) DBCellEnum(def, extDefIncrementalFunc, (ClientData) 0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* Function returning TRUE if 'def' needs re-extraction.
|
||||
* This will be the case if either the .ext file for 'def'
|
||||
* does not exist, or if its timestamp fails to match that
|
||||
* recorded in 'def'.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
bool
|
||||
|
|
@ -625,16 +830,6 @@ 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;
|
||||
};
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -689,7 +884,7 @@ extExtractStack(stack, doExtract, rootDef)
|
|||
errorcnt += extNumErrors;
|
||||
warnings += extNumWarnings;
|
||||
}
|
||||
else
|
||||
else if (!(def->cd_flags & CDNOEXTRACT))
|
||||
{
|
||||
if (!first) TxPrintf(", ");
|
||||
TxPrintf("%s", def->cd_name);
|
||||
|
|
@ -703,6 +898,7 @@ extExtractStack(stack, doExtract, rootDef)
|
|||
for (; sl; sl = sl->sl_next)
|
||||
{
|
||||
ExtRevertSubstrate(sl->sl_def, sl->sl_plane);
|
||||
sl->sl_def->cd_flags &= ~CDNOEXTRACT;
|
||||
freeMagic(sl);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ extern void ExtSetStyle();
|
|||
extern void ExtPrintStyle();
|
||||
extern void ExtRevertSubstrate();
|
||||
extern Plane *ExtCell();
|
||||
extern void ExtractOneCell();
|
||||
|
||||
extern int ExtGetGateTypesMask();
|
||||
extern int ExtGetDiffTypesMask();
|
||||
|
|
@ -103,5 +104,7 @@ extern void ExtGetZAxis();
|
|||
extern void ExtDumpCaps();
|
||||
|
||||
extern int extEnumTilePerim();
|
||||
extern Plane *extPrepSubstrate();
|
||||
|
||||
|
||||
#endif /* _EXTRACT_H */
|
||||
|
|
|
|||
Loading…
Reference in New Issue