From 71dffb2fd239d1ceeae595a40e1fe36a7427b3bb Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Mon, 21 Nov 2022 17:13:33 -0500 Subject: [PATCH] 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). --- VERSION | 2 +- database/database.h.in | 3 ++ extract/ExtCell.c | 2 + extract/ExtHier.c | 3 ++ extract/ExtMain.c | 106 +++++++++++++++++++++++++++++++++++++---- 5 files changed, 105 insertions(+), 11 deletions(-) diff --git a/VERSION b/VERSION index f6e30960..5eb3bdf8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.344 +8.3.345 diff --git a/database/database.h.in b/database/database.h.in index 1e677fed..d0f7e230 100644 --- a/database/database.h.in +++ b/database/database.h.in @@ -418,6 +418,8 @@ typedef struct celldef * 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. + * CDDONTUSE is used during extraction to flag cells that have no + * contents and should be ignored. */ #define CDAVAILABLE 0x00001 @@ -438,6 +440,7 @@ typedef struct celldef #define CDDEREFERENCE 0x08000 #define CDFIXEDSTAMP 0x10000 #define CDNOEXTRACT 0x20000 +#define CDDONTUSE 0x40000 /* * Description of an array. diff --git a/extract/ExtCell.c b/extract/ExtCell.c index 1f0ba250..89257185 100644 --- a/extract/ExtCell.c +++ b/extract/ExtCell.c @@ -543,6 +543,8 @@ extOutputUsesFunc(cu, outf) { 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); if (cu->cu_xlo != cu->cu_xhi || cu->cu_ylo != cu->cu_yhi) { diff --git a/extract/ExtHier.c b/extract/ExtHier.c index 4b36a648..509cc5c5 100644 --- a/extract/ExtHier.c +++ b/extract/ExtHier.c @@ -115,6 +115,9 @@ extHierSubstrate(ha, use, x, y) /* then there is no need to do it again. */ 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; /* Register the name of the parent's substrate */ diff --git a/extract/ExtMain.c b/extract/ExtMain.c index 46b36847..a87fcd82 100644 --- a/extract/ExtMain.c +++ b/extract/ExtMain.c @@ -171,6 +171,48 @@ ExtInit() 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; LinkedDef *newLD; - /* Ignore all internal cells and cells that have been visited */ - if (def->cd_flags & CDINTERNAL) return 0; + /* Ignore all internal cells and cells that are marked "don't use" */ + if (def->cd_flags & (CDINTERNAL | CDDONTUSE)) return 0; /* Recurse to the bottom first */ (void) DBCellEnum(def, extDefListFunc, (ClientData)defList); @@ -194,6 +236,31 @@ extDefListFunc(use, defList) /* Don't add cells that have already been visited */ 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 */ newLD = (LinkedDef *)mallocMagic(sizeof(LinkedDef)); @@ -201,9 +268,6 @@ extDefListFunc(use, defList) newLD->ld_next = *defList; *defList = newLD; - /* Mark self as visited */ - def->cd_client = (ClientData) 1; - return 0; } @@ -221,8 +285,8 @@ extDefListFuncIncremental(use, defList) CellDef *def = use->cu_def; LinkedDef *newLD; - /* Ignore all internal cells */ - if (def->cd_flags & CDINTERNAL) return 0; + /* Ignore all internal cells and cells marked "don't use" */ + if (def->cd_flags & (CDINTERNAL | CDDONTUSE)) return 0; /* Mark cells that don't need updating */ if (!extTimestampMisMatch(def)) @@ -234,6 +298,31 @@ extDefListFuncIncremental(use, defList) /* Don't add cells that have already been visited */ 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 */ newLD = (LinkedDef *)mallocMagic(sizeof(LinkedDef)); @@ -241,9 +330,6 @@ extDefListFuncIncremental(use, defList) newLD->ld_next = *defList; *defList = newLD; - /* Mark self as visited */ - def->cd_client = (ClientData) 1; - return 0; }