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:
Tim Edwards 2022-04-05 21:33:15 -04:00
parent ff10aedf69
commit a09fa78d2c
5 changed files with 268 additions and 60 deletions

View File

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

View File

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

View File

@ -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)
{

View File

@ -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);
}

View File

@ -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 */