From bbf600836313f3816466b78097929c314eb4213a Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 5 Jun 2019 15:03:51 -0400 Subject: [PATCH 1/3] Enhancements to cifinput and cifoutput in the tech file: Added option "labels ... cellid" to handle some vendor files where apparently to get around the 30-character cell name limit, the actual cellname is encoded on a text layer. Added new cifop "boundary" (no arguments) for cases where a cell abutment box is encoded on a GDS layer; this now translates the bounding box to the FIXED_BBOX property, as is done with the LEF bounding box. Also corrected the property set function to free existing property value allocated memory when overwriting a property with a new value. --- calma/CalmaRdpt.c | 15 ++++++++----- calma/calmaInt.h | 3 +++ cif/CIFgen.c | 24 ++++++++++++++++++++ cif/CIFint.h | 9 +++++--- cif/CIFrdcl.c | 56 ++++++++++++++++++++++++++++++++++++++++++----- cif/CIFrdpt.c | 5 +++-- cif/CIFrdtech.c | 8 +++---- cif/CIFread.h | 4 ++-- cif/CIFtech.c | 14 ++++++++++-- database/DBprop.c | 3 +++ wiring/wireTech.c | 1 + 11 files changed, 117 insertions(+), 25 deletions(-) diff --git a/calma/CalmaRdpt.c b/calma/CalmaRdpt.c index cd5109c2..aee5c4b2 100644 --- a/calma/CalmaRdpt.c +++ b/calma/CalmaRdpt.c @@ -57,8 +57,6 @@ extern HashTable calmaDefInitHash; extern void calmaLayerError(); bool calmaReadPath(); -typedef enum { LABEL_TYPE_NONE, LABEL_TYPE_TEXT, LABEL_TYPE_PORT } labelType; - /* * ---------------------------------------------------------------------------- * @@ -274,7 +272,6 @@ calmaElementBoundary() } } - CIFPropRecordPath(cifReadCellDef, pathheadp, FALSE); rp = CIFPolyToRects(pathheadp, plane, CIFPaintTable, (PaintUndoInfo *)NULL); CIFFreePath(pathheadp); @@ -300,7 +297,7 @@ calmaElementBoundary() rpc.r_ytop /= calmaReadScale1; if ((ciftype >= 0) && - ((cifCurReadStyle->crs_labelSticky[ciftype] != LABEL_TYPE_NONE))) + (cifCurReadStyle->crs_labelSticky[ciftype] != LABEL_TYPE_NONE)) { Label *lab; TileType type; @@ -652,7 +649,7 @@ calmaElementPath() } } - CIFPropRecordPath(cifReadCellDef, pathheadp, TRUE); + CIFPropRecordPath(cifReadCellDef, pathheadp, TRUE, "path"); CIFPaintWirePath(pathheadp, width, (pathtype == CALMAPATH_SQUAREFLUSH || pathtype == CALMAPATH_CUSTOM) ? FALSE : TRUE, plane, CIFPaintTable, (PaintUndoInfo *)NULL); @@ -715,7 +712,7 @@ calmaElementText() cifnum = CIFCalmaLayerToCifLayer(layer, textt, cifCurReadStyle); if (cifnum < 0) { - if(cifCurReadStyle->crs_flags & CRF_IGNORE_UNKNOWNLAYER_LABELS) + if (cifCurReadStyle->crs_flags & CRF_IGNORE_UNKNOWNLAYER_LABELS) type = -1; else { calmaLayerError("Label on unknown layer/datatype", layer, textt); @@ -889,6 +886,12 @@ calmaElementText() r.r_ll.p_x * cifCurReadStyle->crs_scaleFactor, r.r_ll.p_y * cifCurReadStyle->crs_scaleFactor); } + else if (cifCurReadStyle->crs_labelSticky[cifnum] == LABEL_TYPE_CELLID) + { + /* Special handling of label layers marked "cellid" in the techfile. */ + /* The actual cellname is the ID string, not the GDS structure name. */ + DBCellRenameDef(cifReadCellDef, textbody); + } else if (type < 0) { calmaReadError("Warning: label \"%s\" at (%d, %d) is on unhandled" diff --git a/calma/calmaInt.h b/calma/calmaInt.h index 978da3a6..407d5c40 100644 --- a/calma/calmaInt.h +++ b/calma/calmaInt.h @@ -130,6 +130,9 @@ typedef struct /* Length of record header */ #define CALMAHEADERLENGTH 4 +/* Label types */ +typedef enum { LABEL_TYPE_NONE, LABEL_TYPE_TEXT, LABEL_TYPE_PORT, LABEL_TYPE_CELLID } labelType; + /* ------------------------- Input macros ----------------------------- */ /* Globals for Calma reading */ diff --git a/cif/CIFgen.c b/cif/CIFgen.c index 86eb3fb7..d063a087 100644 --- a/cif/CIFgen.c +++ b/cif/CIFgen.c @@ -3036,6 +3036,29 @@ CIFGenLayer(op, area, cellDef, temps, clientdata) } break; + case CIFOP_BOUNDARY: + cifPlane = curPlane; + /* This function for cifoutput only. cifinput handled separately. */ + if (cellDef && (cellDef->cd_flags & CDFIXEDBBOX)) + { + char *propvalue; + bool found; + + propvalue = (char *)DBPropGet(cellDef, "FIXED_BBOX", &found); + if (!found) break; + if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot, + &bbox.r_xtop, &bbox.r_ytop) != 4) break; + + cifScale = (CIFCurStyle) ? CIFCurStyle->cs_scaleFactor : 1; + bbox.r_xbot *= cifScale; + bbox.r_xtop *= cifScale; + bbox.r_ybot *= cifScale; + bbox.r_ytop *= cifScale; + DBNMPaintPlane(cifPlane, CIF_SOLIDTYPE, &bbox, + CIFPaintTable, (PaintUndoInfo *)NULL); + } + break; + case CIFOP_BBOX: if (CIFErrorDef == NULL) break; @@ -3149,6 +3172,7 @@ CIFGen(cellDef, area, planes, layers, replace, genAllPlanes, clientdata) CIFErrorLayer = i; new[i] = CIFGenLayer(CIFCurStyle->cs_layers[i]->cl_ops, &expanded, cellDef, new, clientdata); + /* Clean up the non-manhattan geometry in the plane */ if (CIFUnfracture) DBMergeNMTiles(new[i], &expanded, (PaintUndoInfo *)NULL); diff --git a/cif/CIFint.h b/cif/CIFint.h index f7f82105..6d3ef7ba 100644 --- a/cif/CIFint.h +++ b/cif/CIFint.h @@ -121,6 +121,8 @@ typedef struct cifop * the cell bounding box. This involves no magic type * layers but may itself be acted upon with grow/shrink * rules. + * CIFOP_BOUNDARY - Added 6/5/19---map the FIXED_BBOX property bounding + * box coordinates into CIF layer geometry. * CIFOP_NET - Added 11/3/08---pull an entire electrical net into * the CIF layer, selectively picking layers. * CIFOP_MAXRECT - Reduce all areas to the largest internal fitting @@ -144,9 +146,10 @@ typedef struct cifop #define CIFOP_ANDNOT 12 #define CIFOP_SQUARES_G 13 #define CIFOP_BBOX 14 -#define CIFOP_NET 15 -#define CIFOP_MAXRECT 16 -#define CIFOP_COPYUP 17 +#define CIFOP_BOUNDARY 15 +#define CIFOP_NET 16 +#define CIFOP_MAXRECT 17 +#define CIFOP_COPYUP 18 /* Added by Tim 10/21/2004 */ /* The following structure is used to pass information on how to draw diff --git a/cif/CIFrdcl.c b/cif/CIFrdcl.c index 9654af0a..1ddbfb8e 100644 --- a/cif/CIFrdcl.c +++ b/cif/CIFrdcl.c @@ -559,13 +559,15 @@ cifCopyPaintFunc(tile, cifCopyRec) int CIFPaintCurrent() { + extern int cifMakeBoundaryFunc(); /* Forward declaration. */ + extern int cifPaintCurrentFunc(); /* Forward declaration. */ + Plane *plane, *swapplane; int i; for (i = 0; i < cifCurReadStyle->crs_nLayers; i++) { TileType type; - extern int cifPaintCurrentFunc(); /* Forward declaration. */ CIFOp *op; plane = CIFGenLayer(cifCurReadStyle->crs_layers[i]->crl_ops, @@ -641,6 +643,23 @@ CIFPaintCurrent() } } } + else if (op == NULL) + { + /* Handle boundary layer */ + + op = cifCurReadStyle->crs_layers[i]->crl_ops; + while (op) + { + if (op->co_opcode == CIFOP_BOUNDARY) break; + op = op->co_next; + } + + if (op && (DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect, + &DBAllButSpaceBits, cifCheckPaintFunc, + (ClientData)NULL) == 1)) + DBSrPaintArea((Tile *) NULL, plane, &TiPlaneRect, + &CIFSolidBits, cifMakeBoundaryFunc, (ClientData)NULL); + } /* Swap planes */ swapplane = cifCurReadPlanes[type]; @@ -652,8 +671,8 @@ CIFPaintCurrent() DBSrPaintArea((Tile *) NULL, plane, &TiPlaneRect, &CIFSolidBits, cifPaintCurrentFunc, (ClientData)type); - } - + } + /* Recycle the plane, which was dynamically allocated. */ DBFreePaintPlane(plane); @@ -668,9 +687,34 @@ CIFPaintCurrent() return 0; } -/* Below is the search function invoked for each CIF tile type - * found for the current layer. - */ +/* Use CIF layer geometry to define a fixed bounding box for the current cell */ + +int +cifMakeBoundaryFunc(tile, clientdata) + Tile *tile; /* Tile of CIF information. */ + ClientData clientdata; /* Not used */ +{ + /* It is assumed that there is one rectangle for the boundary. */ + /* If there are multiple rectangles defined with the boundary */ + /* layer, then the last one defines the FIXED_BBOX property. */ + + Rect area; + char propertyvalue[128], *storedvalue; + + TiToRect(tile, &area); + + if (cifReadCellDef->cd_flags & CDFIXEDBBOX) + CIFReadError("Warning: Cell %s boundary was redefined.\n", + cifReadCellDef->cd_name); + + sprintf(propertyvalue, "%d %d %d %d", + area.r_xbot, area.r_ybot, area.r_xtop, area.r_ytop); + storedvalue = StrDup((char **)NULL, propertyvalue); + DBPropPut(cifReadCellDef, "FIXED_BBOX", storedvalue); + cifReadCellDef->cd_flags |= CDFIXEDBBOX; +} + +/* Paint CIF layer geometry into the current cell def as magic layer "type" */ int cifPaintCurrentFunc(tile, type) diff --git a/cif/CIFrdpt.c b/cif/CIFrdpt.c index d0cf25cf..ec3846af 100644 --- a/cif/CIFrdpt.c +++ b/cif/CIFrdpt.c @@ -234,9 +234,10 @@ CIFParseFlash() */ void -CIFPropRecordPath(def, pathheadp, iswire) +CIFPropRecordPath(def, pathheadp, iswire, propname) CellDef *def; CIFPath *pathheadp; + char *propname; { extern float CIFGetOutputScale(); CIFPath *pathp; @@ -273,7 +274,7 @@ CIFPropRecordPath(def, pathheadp, iswire) /* Reallocate pathstr to be no larger than needed to hold the path contents */ StrDup(&pathstr, pathstr); - DBPropPut(def, "path", (ClientData)pathstr); + DBPropPut(def, propname, (ClientData)pathstr); } /* diff --git a/cif/CIFrdtech.c b/cif/CIFrdtech.c index 0ec99571..297ad7b6 100644 --- a/cif/CIFrdtech.c +++ b/cif/CIFrdtech.c @@ -62,9 +62,6 @@ CIFOp *cifCurReadOp; /* Last geometric operation seen. */ void cifReadStyleInit(); void CIFReadLoadStyle(); -/* Label types used by the "labels" statement option */ -typedef enum { LABEL_TYPE_NONE, LABEL_TYPE_TEXT, LABEL_TYPE_PORT } labelType; - /* * ---------------------------------------------------------------------------- * @@ -858,6 +855,8 @@ CIFReadTechLine(sectionName, argc, argv) calmaLabelType = LABEL_TYPE_TEXT; else if (!strcmp(argv[2], "port")) calmaLabelType = LABEL_TYPE_PORT; + else if (!strncmp(argv[2], "cell", 4)) + calmaLabelType = LABEL_TYPE_CELLID; else goto wrongNumArgs; } @@ -952,6 +951,8 @@ CIFReadTechLine(sectionName, argc, argv) newOp->co_opcode = CIFOP_SHRINK; else if (strcmp(argv[0], "copyup") == 0) newOp->co_opcode = CIFOP_COPYUP; + else if (strcmp(argv[0], "boundary") == 0) + newOp->co_opcode = CIFOP_BOUNDARY; else { TechError("Unknown statement \"%s\".\n", argv[0]); @@ -967,7 +968,6 @@ CIFReadTechLine(sectionName, argc, argv) if (argc != 2) goto wrongNumArgs; CIFParseReadLayers(argv[1], &newOp->co_cifMask); break; - case CIFOP_GROW: case CIFOP_GROW_G: case CIFOP_SHRINK: diff --git a/cif/CIFread.h b/cif/CIFread.h index bd225e04..5656600f 100644 --- a/cif/CIFread.h +++ b/cif/CIFread.h @@ -54,8 +54,8 @@ typedef struct * the "crl_magicType" should be interpreted as a CIF layer. */ -#define CIFR_SIMPLE 1 -#define CIFR_TEMPLAYER 2 +#define CIFR_SIMPLE 1 +#define CIFR_TEMPLAYER 2 /* The following structure defines a complete CIF read-in style. * The constant MAXCIFRLAYERS must be less than TT_MAXTYPES, and diff --git a/cif/CIFtech.c b/cif/CIFtech.c index ff9e2b03..54bb05c6 100644 --- a/cif/CIFtech.c +++ b/cif/CIFtech.c @@ -104,6 +104,7 @@ cifTechFreeStyle() case CIFOP_OR: case CIFOP_BBOX: case CIFOP_MAXRECT: + case CIFOP_BOUNDARY: /* These options use co_client to hold a single */ /* integer value, so it is not allocated. */ break; @@ -802,8 +803,7 @@ CIFTechLine(sectionName, argc, argv) if (CIFCurStyle->cs_status != TECH_PENDING) return TRUE; newLayer = NULL; - if ((strcmp(argv[0], "templayer") == 0) - || (strcmp(argv[0], "layer") == 0)) + if ((strcmp(argv[0], "templayer") == 0) || (strcmp(argv[0], "layer") == 0)) { if (CIFCurStyle->cs_nLayers == MAXCIFLAYERS) { @@ -1047,6 +1047,8 @@ CIFTechLine(sectionName, argc, argv) newOp->co_opcode = CIFOP_NET; else if (strcmp(argv[0], "maxrect") == 0) newOp->co_opcode = CIFOP_MAXRECT; + else if (strcmp(argv[0], "boundary") == 0) + newOp->co_opcode = CIFOP_BOUNDARY; else { TechError("Unknown statement \"%s\".\n", argv[0]); @@ -1196,6 +1198,12 @@ bloatCheck: goto wrongNumArgs; break; + case CIFOP_BOUNDARY: + /* CIFOP_BOUNDARY has no arguments */ + if (argc != 1) + goto wrongNumArgs; + break; + case CIFOP_SQUARES_G: case CIFOP_SQUARES: @@ -1752,6 +1760,7 @@ CIFTechFinal() { case CIFOP_OR: case CIFOP_BBOX: + case CIFOP_BOUNDARY: case CIFOP_MAXRECT: case CIFOP_NET: break; @@ -2232,6 +2241,7 @@ CIFTechOutputScale(n, d) { case CIFOP_OR: case CIFOP_BBOX: + case CIFOP_BOUNDARY: case CIFOP_MAXRECT: case CIFOP_NET: break; diff --git a/database/DBprop.c b/database/DBprop.c index 2ea9b652..c2ded840 100644 --- a/database/DBprop.c +++ b/database/DBprop.c @@ -55,6 +55,7 @@ DBPropPut(cellDef, name, value) { HashTable *htab; HashEntry *entry; + char *oldvalue; /* Honor the NOEDIT flag */ if (cellDef->cd_flags & CDNOEDIT) return; @@ -67,6 +68,8 @@ DBPropPut(cellDef, name, value) htab = (HashTable *) cellDef->cd_props; entry = HashFind(htab, name); + oldvalue = (char *)HashGetValue(entry); + if (oldvalue != NULL) freeMagic(oldvalue); HashSetValue(entry, value); } diff --git a/wiring/wireTech.c b/wiring/wireTech.c index 7f49e9a9..a8e4aa75 100644 --- a/wiring/wireTech.c +++ b/wiring/wireTech.c @@ -108,6 +108,7 @@ WireTechLine(sectionName, argc, argv) return TRUE; } WireUnits = atoi(argv[1]); + return TRUE; } if (strcmp(argv[0], "contact") != 0) From 0cd45ae6f746839d0e72c4ba63ed65b14830122d Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 5 Jun 2019 16:48:45 -0400 Subject: [PATCH 2/3] Modified the cell clear routine so that it removes properties in addition to subcells, paint, and labels. Otherwise problems arise if a cell is read from LEF followed by GDS; the GDS view overwrites the LEF but the property "LEFview" remains and causes problems when writing GDS output subsequently. --- database/DBcellsubr.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/database/DBcellsubr.c b/database/DBcellsubr.c index a430d671..4b9f96a8 100644 --- a/database/DBcellsubr.c +++ b/database/DBcellsubr.c @@ -157,7 +157,8 @@ dbCopyDefFunc(tile, def) * DBCellClearDef -- * * Empties out all tile planes of the indicated CellDef, making it - * as though the def had been newly allocated. + * as though the def had been newly allocated. This also removes all + * labels and all properties from the cell. * * Results: * None. @@ -221,6 +222,10 @@ DBCellClearDef(cellDef) freeMagic((char *) lab); cellDef->cd_labels = (Label *) NULL; cellDef->cd_lastLabel = (Label *) NULL; + + /* Remove all defined properties */ + DBPropClearAll(cellDef); + SigEnableInterrupts(); } From 87c07451d1867f302d456e864632a3c2af7b7b09 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 5 Jun 2019 17:02:20 -0400 Subject: [PATCH 3/3] Corrected the LEF read routine so that when LEF is read to annotate an existing GDS file, the "LEFview" property is not set (i.e., it should not be marked as an abstract view because it is still a GDS view). --- lef/lefRead.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lef/lefRead.c b/lef/lefRead.c index 3904ade4..a15a4202 100644 --- a/lef/lefRead.c +++ b/lef/lefRead.c @@ -1604,10 +1604,18 @@ origin_error: } } + /* Note: When the LEF view is used to annotate an */ + /* existing GDS view, then the view is not considered */ + /* "abstract"; otherwise, writing GDS output gets very */ + /* complicated and inefficient. */ + /* Note: The value here is ignored, setting to "TRUE". */ /* The "extract" command only cares that the key exists. */ + /* i.e., setting it to "FALSE" would be ineffective. */ + + if (!is_imported) + DBPropPut(lefMacro, "LEFview", StrDup((char **)NULL, "TRUE")); - DBPropPut(lefMacro, "LEFview", StrDup((char **)NULL, "TRUE")); DBWAreaChanged(lefMacro, &lefMacro->cd_bbox, DBW_ALLWINDOWS, &DBAllButSpaceBits); }