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.
This commit is contained in:
Tim Edwards 2022-01-20 21:50:13 -05:00
parent 6deb7d4f01
commit c2755a061f
6 changed files with 227 additions and 13 deletions

View File

@ -1 +1 @@
8.3.258
8.3.259

View File

@ -50,6 +50,7 @@ int calmaNonManhattan;
int CalmaFlattenLimit = 10;
int NameConvertErrors = 0;
bool CalmaRewound = FALSE;
bool CalmaMaskHints = FALSE;
extern HashTable calmaDefInitHash;

View File

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

View File

@ -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++;

View File

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

View File

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