Implemented a method to handle empty subcells that exist because a

library has been read in with the "gds readonly true" option set
because the cell contains information on where in the GDS the
cell is located, but the cell is empty because it was flattened
into the magic view and all of its contents were erased.  This can
cause issues with LVS if magic generates an empty cell into the
netlist and the LVS tool tries to compare the cells by name.  Also,
this prevents unnecessary .ext files and unnecessary merges to the
substrate of such cells (since all cells have an implied substrate).
This commit is contained in:
Tim Edwards 2022-11-21 17:13:33 -05:00
parent 0f05bb1356
commit 71dffb2fd2
5 changed files with 105 additions and 11 deletions

View File

@ -1 +1 @@
8.3.344 8.3.345

View File

@ -418,6 +418,8 @@ typedef struct celldef
* the same timestamp value. * the same timestamp value.
* CDNOEXTRACT is used by incremental extraction to flag cells that * CDNOEXTRACT is used by incremental extraction to flag cells that
* are up-to-date and do not need to be re-extracted. * are up-to-date and do not need to be re-extracted.
* CDDONTUSE is used during extraction to flag cells that have no
* contents and should be ignored.
*/ */
#define CDAVAILABLE 0x00001 #define CDAVAILABLE 0x00001
@ -438,6 +440,7 @@ typedef struct celldef
#define CDDEREFERENCE 0x08000 #define CDDEREFERENCE 0x08000
#define CDFIXEDSTAMP 0x10000 #define CDFIXEDSTAMP 0x10000
#define CDNOEXTRACT 0x20000 #define CDNOEXTRACT 0x20000
#define CDDONTUSE 0x40000
/* /*
* Description of an array. * Description of an array.

View File

@ -543,6 +543,8 @@ extOutputUsesFunc(cu, outf)
{ {
Transform *t = &cu->cu_transform; Transform *t = &cu->cu_transform;
if (cu->cu_def->cd_flags & CDDONTUSE) return 0;
fprintf(outf, "use %s %s", cu->cu_def->cd_name, cu->cu_id); fprintf(outf, "use %s %s", cu->cu_def->cd_name, cu->cu_id);
if (cu->cu_xlo != cu->cu_xhi || cu->cu_ylo != cu->cu_yhi) if (cu->cu_xlo != cu->cu_xhi || cu->cu_ylo != cu->cu_yhi)
{ {

View File

@ -115,6 +115,9 @@ extHierSubstrate(ha, use, x, y)
/* then there is no need to do it again. */ /* then there is no need to do it again. */
if (use->cu_flags & CU_SUB_EXTRACTED) return; if (use->cu_flags & CU_SUB_EXTRACTED) return;
/* Don't extract anything from cells marked "don't use". */
if (use->cu_def->cd_flags & CDDONTUSE) return;
def = (CellDef *)ha->ha_parentUse->cu_def; def = (CellDef *)ha->ha_parentUse->cu_def;
/* Register the name of the parent's substrate */ /* Register the name of the parent's substrate */

View File

@ -171,6 +171,48 @@ ExtInit()
extLengthInit(); extLengthInit();
} }
/*
* ----------------------------------------------------------------------------
*
* Simple callback returns 1 if any cell is not marked with the CDDONTUSE
* flag. If DBCellEnum() returns 0 then all children of the CellDef are
* marked CDDONTUSE.
*
* ----------------------------------------------------------------------------
*/
int
extIsUsedFunc(use, clientData)
CellUse *use;
ClientData clientData; /* unused */
{
CellDef *def = use->cu_def;
/* If any cell is not marked CDDONTUSE then return 1 and stop the search. */
if (!(def->cd_flags & CDDONTUSE)) return 1;
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* Simple callback returns 1 if any non-space tile is found in a cell.
* Used to determine if a cell does not need extracting because it is
* an empty placeholder cell created when flattening part of a vendor
* GDS, and exists only to reference the GDS file location for writing
* GDS.
*
* ----------------------------------------------------------------------------
*/
int
extEnumFunc(tile, plane)
Tile *tile;
int *plane;
{
return 1;
}
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
@ -185,8 +227,8 @@ extDefListFunc(use, defList)
CellDef *def = use->cu_def; CellDef *def = use->cu_def;
LinkedDef *newLD; LinkedDef *newLD;
/* Ignore all internal cells and cells that have been visited */ /* Ignore all internal cells and cells that are marked "don't use" */
if (def->cd_flags & CDINTERNAL) return 0; if (def->cd_flags & (CDINTERNAL | CDDONTUSE)) return 0;
/* Recurse to the bottom first */ /* Recurse to the bottom first */
(void) DBCellEnum(def, extDefListFunc, (ClientData)defList); (void) DBCellEnum(def, extDefListFunc, (ClientData)defList);
@ -194,6 +236,31 @@ extDefListFunc(use, defList)
/* Don't add cells that have already been visited */ /* Don't add cells that have already been visited */
if (def->cd_client) return 0; if (def->cd_client) return 0;
/* Mark self as visited */
def->cd_client = (ClientData) 1;
/* Check if all descendents are marked as "don't use" */
if (DBCellEnum(def, extIsUsedFunc, (ClientData)NULL) == 0)
{
int plane;
/* Nothing below this cell had anything to extract. */
/* Check this cell for paint. If it has none, then */
/* ignore it. */
for (plane = PL_TECHDEPBASE; plane < DBNumPlanes; plane++)
if (DBSrPaintArea((Tile *)NULL, def->cd_planes[plane], &TiPlaneRect,
&DBAllButSpaceAndDRCBits, extEnumFunc, (ClientData)NULL))
break;
if (plane == DBNumPlanes)
{
/* Cell has no material. Mark it and return. */
def->cd_flags |= CDDONTUSE;
return 0;
}
}
/* When done with descendents, add self to the linked list */ /* When done with descendents, add self to the linked list */
newLD = (LinkedDef *)mallocMagic(sizeof(LinkedDef)); newLD = (LinkedDef *)mallocMagic(sizeof(LinkedDef));
@ -201,9 +268,6 @@ extDefListFunc(use, defList)
newLD->ld_next = *defList; newLD->ld_next = *defList;
*defList = newLD; *defList = newLD;
/* Mark self as visited */
def->cd_client = (ClientData) 1;
return 0; return 0;
} }
@ -221,8 +285,8 @@ extDefListFuncIncremental(use, defList)
CellDef *def = use->cu_def; CellDef *def = use->cu_def;
LinkedDef *newLD; LinkedDef *newLD;
/* Ignore all internal cells */ /* Ignore all internal cells and cells marked "don't use" */
if (def->cd_flags & CDINTERNAL) return 0; if (def->cd_flags & (CDINTERNAL | CDDONTUSE)) return 0;
/* Mark cells that don't need updating */ /* Mark cells that don't need updating */
if (!extTimestampMisMatch(def)) if (!extTimestampMisMatch(def))
@ -234,6 +298,31 @@ extDefListFuncIncremental(use, defList)
/* Don't add cells that have already been visited */ /* Don't add cells that have already been visited */
if (def->cd_client) return 0; if (def->cd_client) return 0;
/* Mark self as visited */
def->cd_client = (ClientData) 1;
/* Check if all descendents are marked as "don't use" */
if (DBCellEnum(def, extIsUsedFunc, (ClientData)NULL) == 0)
{
int plane;
/* Nothing below this cell had anything to extract. */
/* Check this cell for paint. If it has none, then */
/* ignore it. */
for (plane = PL_TECHDEPBASE; plane < DBNumPlanes; plane++)
if (DBSrPaintArea((Tile *)NULL, def->cd_planes[plane], &TiPlaneRect,
&DBAllButSpaceAndDRCBits, extEnumFunc, (ClientData)NULL))
break;
if (plane == DBNumPlanes)
{
/* Cell has no material. Mark it and return. */
def->cd_flags |= CDDONTUSE;
return 0;
}
}
/* When done with descendents, add self to the linked list */ /* When done with descendents, add self to the linked list */
newLD = (LinkedDef *)mallocMagic(sizeof(LinkedDef)); newLD = (LinkedDef *)mallocMagic(sizeof(LinkedDef));
@ -241,9 +330,6 @@ extDefListFuncIncremental(use, defList)
newLD->ld_next = *defList; newLD->ld_next = *defList;
*defList = newLD; *defList = newLD;
/* Mark self as visited */
def->cd_client = (ClientData) 1;
return 0; return 0;
} }