From c2755a061f9156cbd30dbcfb5538204836c1667c Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 20 Jan 2022 21:50:13 -0500 Subject: [PATCH] First cut at a method to automatically generate mask hint properties in a cell to account for the difference between what's in an input GDS file and what magic would write out itself from the processed data. This potentially allows library cells to be read in that will generate the equivalent mask data as output without resorting to using GDS file references as properties. The method is activated with the new command option "gds maskhints on" and the default is off. --- VERSION | 2 +- calma/CalmaRdcl.c | 1 + calma/calma.h | 1 + cif/CIFhier.c | 1 + cif/CIFrdcl.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++ commands/CmdCD.c | 48 +++++++++--- 6 files changed, 227 insertions(+), 13 deletions(-) diff --git a/VERSION b/VERSION index 807bada7..aa16d4ea 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.258 +8.3.259 diff --git a/calma/CalmaRdcl.c b/calma/CalmaRdcl.c index 7a45a437..cf81d1b1 100644 --- a/calma/CalmaRdcl.c +++ b/calma/CalmaRdcl.c @@ -50,6 +50,7 @@ int calmaNonManhattan; int CalmaFlattenLimit = 10; int NameConvertErrors = 0; bool CalmaRewound = FALSE; +bool CalmaMaskHints = FALSE; extern HashTable calmaDefInitHash; diff --git a/calma/calma.h b/calma/calma.h index de0314f1..0d4aa223 100644 --- a/calma/calma.h +++ b/calma/calma.h @@ -34,6 +34,7 @@ extern bool CalmaAddendum; extern bool CalmaNoDuplicates; extern bool CalmaNoDateStamp; extern bool CalmaUnique; +extern bool CalmaMaskHints; extern bool CalmaMergeTiles; extern bool CalmaFlattenArrays; extern bool CalmaNoDRCCheck; diff --git a/cif/CIFhier.c b/cif/CIFhier.c index ed8538f8..e51d5894 100644 --- a/cif/CIFhier.c +++ b/cif/CIFhier.c @@ -310,6 +310,7 @@ cifFlatMaskHints(name, value, mhd) if (lastval) freeMagic(lastval); /* Parse through the four values and check if there's more */ + while (*vptr && isspace(*vptr)) vptr++; while (*vptr && !isspace(*vptr)) vptr++; while (*vptr && isspace(*vptr)) vptr++; while (*vptr && !isspace(*vptr)) vptr++; diff --git a/cif/CIFrdcl.c b/cif/CIFrdcl.c index 5a69f0ab..2986e1b7 100644 --- a/cif/CIFrdcl.c +++ b/cif/CIFrdcl.c @@ -540,6 +540,40 @@ cifCopyPaintFunc(tile, cifCopyRec) return 0; } +/* + * ---------------------------------------------------------------------------- + * + * cifMaskHintFunc -- + * + * For each tile in the scanned plane, convert the tile into a coordinate + * string by appending the coordinates to the list passed as clientData. + * + * Results: + * Return 0 to keep the search going. + * + * Side effects: + * Allocates memory for and seeds a linked rect entry + * + * ---------------------------------------------------------------------------- + */ + +int +cifMaskHintFunc(tile, lrecp) + Tile *tile; + LinkedRect **lrecp; +{ + Rect r; + LinkedRect *newlr; + + newlr = (LinkedRect *)mallocMagic(sizeof(LinkedRect)); + newlr->r_next = *lrecp; + (*lrecp) = newlr; + + TiToRect(tile, &newlr->r_r); + + return 0; +} + /* * ---------------------------------------------------------------------------- * @@ -683,6 +717,159 @@ CIFPaintCurrent(filetype) TiFreePlane(plane); } + /* If mask hints were requested, then for each GDS/CIF layer in the */ + /* input, if the layer has a corresponding output layer and the */ + /* output layer has a mask hints operator, then generate the output */ + /* plane for that layer, compare to the input plane, and create */ + /* mask hint properties to make the output the same as the input. */ + + if (CalmaMaskHints) + { + int j; + CIFOp *op, newop, subop; + Plane *presult; + TileTypeBitMask genMask; + int *in_out_map; + extern char *(cifReadLayers[MAXCIFRLAYERS]); + + TTMaskZero(&genMask); + in_out_map = (int *)mallocMagic(cifNReadLayers * sizeof(int)); + + for (i = 0; i < cifNReadLayers; i++) + { + /* Does the input layer have a corresponding output layer? */ + in_out_map[i] = -1; + for (j = 0; j < CIFCurStyle->cs_nLayers; j++) + { + if (!strcmp(CIFCurStyle->cs_layers[j]->cl_name, cifReadLayers[i])) + { + /* Does the layer have a mask-hints operator? */ + for (op = CIFCurStyle->cs_layers[j]->cl_ops; op; op = op->co_next) + if (op->co_opcode == CIFOP_MASKHINTS) + { + TTMaskSetType(&genMask, j); + in_out_map[i] = j; + break; + } + } + if (in_out_map[i] >= 0) break; + } + } + + /* Multiply input planes to the same scale as the generated output */ + CIFScalePlanes(CIFCurStyle->cs_scaleFactor, 1, cifCurReadPlanes); + + /* Generate the output for these layers from the cell contents */ + CIFClearPlanes(CIFPlanes); + + /* TO-DO: Replace DBAllTypeBits with genMask. Requires that genMask */ + /* be expanded to include all dependent layers. */ + CIFGen(cifReadCellDef, cifReadCellDef, &TiPlaneRect, CIFPlanes, &DBAllTypeBits, + TRUE, FALSE, FALSE, (ClientData)NULL); + + /* Set up double operator for OR and ANDNOT functions */ + newop.co_opcode = CIFOP_OR; + newop.co_distance = 0; + newop.co_next = &subop; + newop.co_client = (ClientData)NULL; + TTMaskZero(&newop.co_paintMask); + + subop.co_opcode = CIFOP_ANDNOT; + subop.co_distance = 0; + subop.co_next = NULL; + subop.co_client = (ClientData)NULL; + TTMaskZero(&subop.co_paintMask); + + for (i = 0; i < cifNReadLayers; i++) + { + LinkedRect *lrec = NULL; + char *propstr = NULL; + char locstr[512]; + Plane *tempp; + + j = in_out_map[i]; + if (j < 0) continue; + + TTMaskSetOnlyType(&subop.co_cifMask, j); + + /* Replace last layer + 1 on CIFPlanes with input layer i */ + + tempp = CIFPlanes[CIFCurStyle->cs_nLayers]; + TTMaskSetOnlyType(&newop.co_cifMask, CIFCurStyle->cs_nLayers); + CIFPlanes[CIFCurStyle->cs_nLayers] = cifCurReadPlanes[i]; + CIFCurStyle->cs_nLayers++; + + /* Compute result (i AND-NOT j), which will be all the areas of + * the input on layer i that are not generated by writing output + * layer j. + */ + presult = CIFGenLayer(&newop, &TiPlaneRect, (CellDef *)NULL, + (CellDef *)NULL, CIFPlanes, FALSE, (ClientData)NULL); + + /* Scan the resulting plane and generate linked Rect structures for + * each shape found. + */ + DBSrPaintArea((Tile *)NULL, presult, &TiPlaneRect, &CIFSolidBits, + cifMaskHintFunc, (ClientData)&lrec); + + if (lrec != NULL) + { + char *propname; + + propname = (char *)mallocMagic(11 + strlen(cifReadLayers[i])); + sprintf(propname, "MASKHINTS_%s", cifReadLayers[i]); + + propstr = (char *)NULL; + + /* Turn all linked Rects into a mask-hints property in the + * target cell. + */ + while (lrec != NULL) + { + char *newstr; + sprintf(locstr, "%d %d %d %d", + lrec->r_r.r_xbot / CIFCurStyle->cs_scaleFactor, + lrec->r_r.r_ybot / CIFCurStyle->cs_scaleFactor, + lrec->r_r.r_xtop / CIFCurStyle->cs_scaleFactor, + lrec->r_r.r_ytop / CIFCurStyle->cs_scaleFactor); + if (propstr == NULL) + { + newstr = (char *)mallocMagic(strlen(locstr) + 1); + sprintf(newstr, "%s", locstr); + } + else + { + newstr = (char *)mallocMagic(strlen(locstr) + + strlen(propstr) + 2); + sprintf(newstr, "%s %s", propstr, locstr); + freeMagic(propstr); + } + propstr = newstr; + freeMagic(lrec); + lrec = lrec->r_next; + } + /* NOTE: propstr is transferred to the CellDef and should + * not be free'd here. + */ + DBPropPut(cifReadCellDef, propname, propstr); + freeMagic(propname); + } + + /* Delete the generated plane */ + DBFreePaintPlane(presult); + TiFreePlane(presult); + + /* Replace the input plane that was shuffled out */ + CIFCurStyle->cs_nLayers--; + CIFPlanes[CIFCurStyle->cs_nLayers] = tempp; + } + + /* Free up the planes used to create the output */ + CIFClearPlanes(CIFPlanes); + + freeMagic((char *)in_out_map); + } + /* Now go through all the current planes and zero them out. */ for (i = 0; i < MAXCIFRLAYERS; i++) diff --git a/commands/CmdCD.c b/commands/CmdCD.c index f9936f49..f937f2a2 100644 --- a/commands/CmdCD.c +++ b/commands/CmdCD.c @@ -99,18 +99,19 @@ bool cmdDumpParseArgs(); #define CALMA_LABELS 8 #define CALMA_LIBRARY 9 #define CALMA_LOWER 10 -#define CALMA_MERGE 11 -#define CALMA_NO_STAMP 12 -#define CALMA_NO_DUP 13 -#define CALMA_READ 14 -#define CALMA_READONLY 15 -#define CALMA_RESCALE 16 -#define CALMA_WARNING 17 -#define CALMA_WRITE 18 -#define CALMA_POLYS 19 -#define CALMA_PATHS 20 -#define CALMA_UNDEFINED 21 -#define CALMA_UNIQUE 22 +#define CALMA_MASKHINTS 11 +#define CALMA_MERGE 12 +#define CALMA_NO_STAMP 13 +#define CALMA_NO_DUP 14 +#define CALMA_READ 15 +#define CALMA_READONLY 16 +#define CALMA_RESCALE 17 +#define CALMA_WARNING 18 +#define CALMA_WRITE 19 +#define CALMA_POLYS 20 +#define CALMA_PATHS 21 +#define CALMA_UNDEFINED 22 +#define CALMA_UNIQUE 23 #define CALMA_WARN_HELP CIF_WARN_END /* undefined by CIF module */ @@ -145,6 +146,7 @@ CmdCalma(w, cmd) "labels [yes|no] cause labels to be output when writing GDS-II", "library [yes|no] do not output the top level, only subcells", "lower [yes|no] allow both upper and lower case in labels", + "maskhints [yes|no] generate mask hint properties on input", "merge [yes|no] merge tiles into polygons in the output", "nodatestamp [yes|no] write a zero value creation date stamp", "noduplicates [yes|no] do not read cells that exist before reading GDS", @@ -537,6 +539,28 @@ CmdCalma(w, cmd) CalmaDoLower = (option < 4) ? FALSE : TRUE; return; + case CALMA_MASKHINTS: + if (cmd->tx_argc == 2) + { +#ifdef MAGIC_WRAPPER + Tcl_SetObjResult(magicinterp, Tcl_NewBooleanObj(CalmaMaskHints)); +#else + if (CalmaMaskHints) + TxPrintf("Mask hints generated from GDS input.\n"); + else + TxPrintf("No mask hints generated from GDS input.\n"); +#endif + return; + } + else if (cmd->tx_argc != 3) + goto wrongNumArgs; + + option = Lookup(cmd->tx_argv[2], cmdCalmaYesNo); + if (option < 0) + goto wrongNumArgs; + CalmaMaskHints = (option < 4) ? FALSE : TRUE; + return; + case CALMA_MERGE: if (cmd->tx_argc == 2) {