/* CIFreadcell.c - * * This file contains more routines to parse CIF files. In * particular, it contains the routines to handle cells, * both definitions and calls, and user-defined features * like labels. * * ********************************************************************* * * Copyright (C) 1985, 1990 Regents of the University of California. * * * Permission to use, copy, modify, and distribute this * * * software and its documentation for any purpose and without * * * fee is hereby granted, provided that the above copyright * * * notice appear in all copies. The University of California * * * makes no representations about the suitability of this * * * software for any purpose. It is provided "as is" without * * * express or implied warranty. Export of this software outside * * * of the United States of America may require an export license. * * ********************************************************************* */ #ifndef lint static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cif/CIFrdcl.c,v 1.5 2010/08/25 17:33:55 tim Exp $"; #endif /* not lint */ #include #include #include #include "utils/magic.h" #include "utils/malloc.h" #include "utils/geometry.h" #include "tiles/tile.h" #include "utils/hash.h" #include "utils/undo.h" #include "database/database.h" #include "cif/CIFint.h" #include "cif/CIFread.h" #include "cif/cif.h" #include "calma/calma.h" #include "utils/utils.h" #include "windows/windows.h" #include "dbwind/dbwind.h" #include "utils/main.h" #include "drc/drc.h" /* The following variable is made available to the outside world, * and is the cell definition currently being modified. */ CellDef *cifReadCellDef; /* * The following hash table is used internally to keep track of * of all the cells we've seen definitions for or calls on. * The hash table entries contain pointers to cellDefs, and * are indexed by CIF cell number. If the CDAVAILABLE bit is * set it means we've read the cell's contents. If not set, it * means that the cell has been called but not yet defined. */ HashTable CifCellTable; /* The following variable is used to save and restore current * paint layer information so that we can resume the correct * layer after a subcell definition. */ Plane *cifOldReadPlane = NULL; /* The following boolean is TRUE if a subcell definition is being * read. FALSE means we're working on the EditCell. */ bool cifSubcellBeingRead; /* The following two collections of planes are used to hold CIF * information while cells are being read in (one set for the * outermost, unnamed cell, and one for the current subcell). * When a cell is complete, then geometrical operations are * performed on the layers and stuff is painted into Magic. */ Plane *cifEditCellPlanes[MAXCIFRLAYERS]; Plane *cifSubcellPlanes[MAXCIFRLAYERS]; Plane **cifCurReadPlanes = cifEditCellPlanes; /* Set of planes currently * in force. */ TileType cifCurLabelType = TT_SPACE; /* Magic layer on which to put '94' * labels that aren't identified by * type. */ /* Structure used when flattening the CIF hierarchy on read-in */ typedef struct { Plane *plane; Transform *trans; } CIFCopyRec; /* The following variable is used to hold a subcell id between * the 91 statement and the (immediately-following?) call statement. * The string this points to is dynamically allocated, so it must * also be freed explicitly. */ char *cifSubcellId = NULL; /* * ---------------------------------------------------------------------------- * * CIFReadCellInit -- * * This procedure initializes the data structures in this * module just prior to reading a CIF file. * * If ptrkeys is 0, the keys used in this hash table will * be strings; if it is 1, the keys will be CIF numbers. * * Results: * None. * * Side effects: * The cell hash table is initialized, and things are set up * to put information in the EditCell first. * * ---------------------------------------------------------------------------- */ void CIFReadCellInit(ptrkeys) int ptrkeys; { int i; HashInit(&CifCellTable, 32, ptrkeys); cifReadCellDef = EditCellUse->cu_def; cifSubcellBeingRead = FALSE; cifCurReadPlanes = cifEditCellPlanes; for (i = 0; i < MAXCIFRLAYERS; i += 1) { if (cifEditCellPlanes[i] == NULL) cifEditCellPlanes[i] = DBNewPlane((ClientData) TT_SPACE); if (cifSubcellPlanes[i] == NULL) cifSubcellPlanes[i] = DBNewPlane((ClientData) TT_SPACE); } } /* * ---------------------------------------------------------------------------- * * cifForgetCell -- * * This local procedure is used to find a cell in the subcell * table and remove its CellDef entry. * * Results: * FALSE if no such entry was found, otherwise TRUE. * * Side effects: * Mucks with the CIF cell name hash table. * * ---------------------------------------------------------------------------- */ bool cifForgetCell(cifNum) int cifNum; { HashEntry *h; h = HashLookOnly(&CifCellTable, (char *)(spointertype)cifNum); if (h == NULL) return FALSE; else if (HashGetValue(h) == 0) return FALSE; HashSetValue(h, 0); return TRUE; } /* * ---------------------------------------------------------------------------- * * cifUniqueCell -- * * Attempt to find a cell in the CIF subcell name hash table. * If one exists, rename its definition so that it will not * be overwritten when the cell is redefined. * * Results: * None. * * Side effects: * None. * * ---------------------------------------------------------------------------- */ void cifUniqueCell(cifNum) int cifNum; { HashEntry *h; CellDef *def, *testdef; char name[17]; int reused = 0; h = HashLookOnly(&CifCellTable, (char *)(spointertype)cifNum); if ((h == NULL) || HashGetValue(h) == 0) { /* Cell was deleted with "DD". Don't rename anything */ return; } sprintf(name, "%d", cifNum); def = DBCellLookDef(name); if (def == (CellDef *)NULL) return; /* Cell may have been called but not yet defined---this is okay. */ else if ((def->cd_flags & CDAVAILABLE) == 0) return; testdef = def; while (testdef != NULL) { sprintf(name, "%d_%d", cifNum, ++reused); testdef = DBCellLookDef(name); } DBCellRenameDef(def, name); h = HashFind(&CifCellTable, (char *)(spointertype)cifNum); HashSetValue(h, 0); CIFReadError("Warning: cell definition %d reused.\n", cifNum); } /* * ---------------------------------------------------------------------------- * * cifFindCell -- * * This local procedure is used to find a cell in the subcell * table, and create a new subcell if there isn't already * one there. If a new subcell is created, its CDAVAILABLE * is left FALSE. * * Results: * The return value is a pointer to the definition for the * cell whose CIF number is cifNum. * * Side effects: * A new CellDef may be created. * * ---------------------------------------------------------------------------- */ CellDef * cifFindCell(cifNum) int cifNum; /* The CIF number of the desired cell. */ { HashEntry *h; CellDef *def, *testdef; int reused; h = HashFind(&CifCellTable, (char *)(spointertype)cifNum); if (HashGetValue(h) == 0) { char name[15]; sprintf(name, "%d", cifNum); def = DBCellLookDef(name); if (def == NULL) { def = DBCellNewDef(name); /* Tricky point: call DBReComputeBbox here to make SURE * that the cell has a valid bounding box. Otherwise, * if the cell is used in a parent before being defined * then it will cause a core dump. */ DBReComputeBbox(def); } HashSetValue(h, def); } return (CellDef *) HashGetValue(h); } /* * ---------------------------------------------------------------------------- * * CIFScalePlanes -- * * Scale all of the CIF planes by the amount (scalen / scaled) * * ---------------------------------------------------------------------------- */ void CIFScalePlanes(scalen, scaled, planearray) int scalen; int scaled; Plane **planearray; { int pNum; Plane *newplane; for (pNum = 0; pNum < MAXCIFRLAYERS; pNum++) { if (planearray[pNum] != NULL) { newplane = DBNewPlane((ClientData) TT_SPACE); DBClearPaintPlane(newplane); dbScalePlane(planearray[pNum], newplane, pNum, scalen, scaled, TRUE); DBFreePaintPlane(planearray[pNum]); TiFreePlane(planearray[pNum]); planearray[pNum] = newplane; } } } /* * ---------------------------------------------------------------------------- * * CIFInputRescale -- * * Scale all CIF distances by n / d. Normally, rescaling is done in * the upward direction (n > 1, d = 1) in response to a value in the * CIF input that does not divide evenly into the database units of * the CIF planes. Currently there is no call to CIFInputRescale * with d > 1, but it is left for the possibility that scalefactors * could be restored after finishing a subcell definition, possibly * preventing integer overflow in large designs. * * Results: * None. * * Side effects: * Many. Adjusts the CIF input style scalefactor (CIF vs. magic * units), multiplier (CIF units vs. centimicrons), distances of all * CIF boolean operations, and the scale of all existing planes in * the current CIF database. * * ---------------------------------------------------------------------------- */ void CIFInputRescale(n, d) int n, d; { CIFReadStyle *istyle = cifCurReadStyle; CIFReadLayer *cl; CIFOp *op; int i; /* 2-step process for efficiency */ if (n > 1) { istyle->crs_scaleFactor *= n; istyle->crs_multiplier *= n; for (i = 0; i < istyle->crs_nLayers; i++) { cl = istyle->crs_layers[i]; for (op = cl->crl_ops; op != NULL; op = op->co_next) if (op->co_distance) op->co_distance *= n; } } if (d > 1) { istyle->crs_scaleFactor /= d; istyle->crs_multiplier /= d; for (i = 0; i < istyle->crs_nLayers; i++) { cl = istyle->crs_layers[i]; for (op = cl->crl_ops; op != NULL; op = op->co_next) if (op->co_distance) op->co_distance /= d; } } CIFScalePlanes(n, d, cifCurReadPlanes); if (cifCurReadPlanes != cifEditCellPlanes) CIFScalePlanes(n, d, cifEditCellPlanes); if ((const Plane*)cifEditCellPlanes != (const Plane*)cifSubcellPlanes && cifCurReadPlanes != cifSubcellPlanes) CIFScalePlanes(n, d, cifSubcellPlanes); CIFReadWarning("CIF style %s: units rescaled by factor of %d / %d\n", istyle->crs_name, n, d); } /* * ---------------------------------------------------------------------------- * * CIFParseStart -- * * Parse the beginning of a symbol (cell) definition. * ds ::= D { blank } S integer [ sep integer sep integer ] * * Results: * TRUE is returned if the parse completed successfully, and * FALSE is returned otherwise. * * Side effects: * Set up information for the new cell, including the CIF * planes and creating a Magic cell (if one doesn't exist * already). * * ---------------------------------------------------------------------------- */ bool CIFParseStart() { int number; if (cifSubcellBeingRead) { CIFReadError("definition start inside other definition; ignored.\n"); CIFSkipToSemi(); return FALSE; } if (cifSubcellId != NULL) { CIFReadError("pending call identifier %s discarded.\n", cifSubcellId); (void) StrDup(&cifSubcellId, (char *) NULL); } /* Take the `S'. */ TAKE(); if (!CIFParseInteger(&number)) { CIFReadError("definition start, but no symbol number; ignored.\n"); CIFSkipToSemi(); return FALSE; } else if (number < 0) { CIFReadError("illegal negative symbol number; definition ignored.\n"); CIFSkipToSemi(); return FALSE; } if (!CIFParseInteger(&cifReadScale1)) { cifReadScale1 = 1; cifReadScale2 = 1; } else { cifReadScale1 *= cifCurReadStyle->crs_multiplier; /* Units not centimicrons */ if (!CIFParseInteger(&cifReadScale2)) { CIFReadError( "only one of two scale factors given; ignored.\n"); cifReadScale1 = 1; cifReadScale2 = 1; } } if (cifReadScale1 <= 0 || cifReadScale2 <= 0) { CIFReadError("Illegal scale %d / %d changed to 1 / 1\n", cifReadScale1, cifReadScale2); cifReadScale1 = 1; cifReadScale2 = 1; } /* * Set up the cell definition. */ cifUniqueCell(number); cifReadCellDef = cifFindCell(number); DBCellClearDef(cifReadCellDef); DBCellSetAvail(cifReadCellDef); cifOldReadPlane = cifReadPlane; cifReadPlane = (Plane *) NULL; cifSubcellBeingRead = TRUE; cifCurReadPlanes = cifSubcellPlanes; return TRUE; } /* * ---------------------------------------------------------------------------- * cifCheckPaintFunc --- * * Callback function for checking if any paint has been generated * on the CIF target plane for a "copyup" layer. * ---------------------------------------------------------------------------- */ int cifCheckPaintFunc(tile, clientData) Tile *tile; ClientData clientData; { return 1; } /* Callback function for copying paint from one CIF cell into another */ int cifCopyPaintFunc(tile, cifCopyRec) Tile *tile; CIFCopyRec *cifCopyRec; { int pNum; TileType dinfo; Rect sourceRect, targetRect; Transform *trans = cifCopyRec->trans; Plane *plane = cifCopyRec->plane; dinfo = TiGetTypeExact(tile); if (trans) { TiToRect(tile, &sourceRect); GeoTransRect(trans, &sourceRect, &targetRect); if (IsSplit(tile)) dinfo = DBTransformDiagonal(TiGetTypeExact(tile), trans); } else TiToRect(tile, &targetRect); DBNMPaintPlane(plane, dinfo, &targetRect, CIFPaintTable, (PaintUndoInfo *)NULL); 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; } /* * ---------------------------------------------------------------------------- * * CIFPaintCurrent -- * * This procedure does geometrical processing on the current * set of CIF planes, and paints the results into the current * CIF cell. * * Results: * Return 0 * * Side effects: * Lots of information gets added to the current Magic cell. * * ---------------------------------------------------------------------------- */ int CIFPaintCurrent(filetype) bool filetype; { 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; CIFOp *op; plane = CIFGenLayer(cifCurReadStyle->crs_layers[i]->crl_ops, &TiPlaneRect, (CellDef *)NULL, (CellDef *)NULL, cifCurReadPlanes, FALSE, (ClientData)NULL); /* Generate a paint/erase table, then paint from the CIF * plane into the current Magic cell. */ type = cifCurReadStyle->crs_layers[i]->crl_magicType; if (cifCurReadStyle->crs_layers[i]->crl_flags & CIFR_TEMPLAYER) { op = cifCurReadStyle->crs_layers[i]->crl_ops; while (op) { if (op->co_opcode == CIFOP_COPYUP) break; op = op->co_next; } /* Quick check to see if anything was generated */ /* on this layer. */ if (op && (DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect, &DBAllButSpaceBits, cifCheckPaintFunc, (ClientData)NULL) == 1)) { /* Copy-up function */ int pNum; Plane *newplane; Plane **parray; extern char *(cifReadLayers[MAXCIFRLAYERS]); /* NOTE: The condition cd_client == 0 when CDFLATGDS * indicates that the cell was already in memory when the * GDS was read. This condition should be properly caught * and handled. */ if ((cifReadCellDef->cd_flags & CDFLATGDS) && (cifReadCellDef->cd_client != (ClientData)0)) parray = (Plane **)cifReadCellDef->cd_client; else { parray = (Plane **)mallocMagic(MAXCIFRLAYERS * sizeof(Plane *)); cifReadCellDef->cd_flags |= CDFLATGDS; cifReadCellDef->cd_flags &= ~CDFLATTENED; cifReadCellDef->cd_client = (ClientData)parray; for (pNum = 0; pNum < MAXCIFRLAYERS; pNum++) parray[pNum] = NULL; } for (pNum = 0; pNum < MAXCIFRLAYERS; pNum++) { if (TTMaskHasType(&op->co_cifMask, pNum)) { CIFCopyRec cifCopyRec; newplane = parray[pNum]; if (newplane == NULL) { newplane = DBNewPlane((ClientData) TT_SPACE); DBClearPaintPlane(newplane); } cifCopyRec.plane = newplane; cifCopyRec.trans = NULL; DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect, &DBAllButSpaceBits, cifCopyPaintFunc, &cifCopyRec); parray[pNum] = newplane; } } } 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)filetype); } /* Swap planes */ swapplane = cifCurReadPlanes[type]; cifCurReadPlanes[type] = plane; plane = swapplane; } else { DBSrPaintArea((Tile *) NULL, plane, &TiPlaneRect, &CIFSolidBits, cifPaintCurrentFunc, (ClientData)type); } /* Recycle the plane, which was dynamically allocated. */ DBFreePaintPlane(plane); 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 != NULL) && (!TTMaskIsZero(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++) { if (!TTMaskHasType(CalmaMaskHints, i)) continue; /* 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, cifCurReadStyle->crs_scaleFactor, 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; if (!TTMaskHasType(CalmaMaskHints, i)) continue; 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++) DBClearPaintPlane(cifCurReadPlanes[i]); return 0; } /* 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; /* Pass the file type (CIF or CALMA) */ { /* 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; int savescale; bool filetype = (bool)clientdata; TiToRect(tile, &area); area.r_xtop = CIFScaleCoord(area.r_xtop, COORD_EXACT); savescale = cifCurReadStyle->crs_scaleFactor; area.r_ytop = CIFScaleCoord(area.r_ytop, COORD_EXACT); if (savescale != cifCurReadStyle->crs_scaleFactor) { area.r_xtop *= (savescale / cifCurReadStyle->crs_scaleFactor); savescale = cifCurReadStyle->crs_scaleFactor; } area.r_xbot = CIFScaleCoord(area.r_xbot, COORD_EXACT); if (savescale != cifCurReadStyle->crs_scaleFactor) { area.r_xtop *= (savescale / cifCurReadStyle->crs_scaleFactor); area.r_ytop *= (savescale / cifCurReadStyle->crs_scaleFactor); savescale = cifCurReadStyle->crs_scaleFactor; } area.r_ybot = CIFScaleCoord(area.r_ybot, COORD_EXACT); if (savescale != cifCurReadStyle->crs_scaleFactor) { area.r_xtop *= (savescale / cifCurReadStyle->crs_scaleFactor); area.r_ytop *= (savescale / cifCurReadStyle->crs_scaleFactor); area.r_xbot *= (savescale / cifCurReadStyle->crs_scaleFactor); } if (cifReadCellDef->cd_flags & CDFIXEDBBOX) { char *propvalue; bool found; /* Only flag a warning if the redefined boundary was */ /* different from the original. */ propvalue = (char *)DBPropGet(cifReadCellDef, "FIXED_BBOX", &found); if (found) { Rect bbox; if (sscanf(propvalue, "%d %d %d %d", &bbox.r_xbot, &bbox.r_ybot, &bbox.r_xtop, &bbox.r_ytop) == 4) { if ((bbox.r_xbot != area.r_xbot) || (bbox.r_ybot != area.r_ybot) || (bbox.r_xtop != area.r_xtop) || (bbox.r_ytop != area.r_ytop)) { if (filetype == FILE_CIF) CIFReadError("Warning: Cell %s boundary was redefined.\n", cifReadCellDef->cd_name); else CalmaReadError("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; return 0; } /* Paint CIF layer geometry into the current cell def as magic layer "type" */ int cifPaintCurrentFunc(tile, type) Tile *tile; /* Tile of CIF information. */ TileType type; /* Magic type to be painted. */ { Rect area; int pNum; int savescale; bool snap_type = COORD_EXACT; /* Contact types are allowed to be on half-lambda spacing, and are */ /* snapped to the nearest magic coordinate if the result is a */ /* fractional magic coordinate. */ if (DBIsContact(type)) snap_type = COORD_HALF_U; /* Compute the area of the CIF tile, then scale it into * Magic coordinates. */ TiToRect(tile, &area); area.r_xtop = CIFScaleCoord(area.r_xtop, snap_type); savescale = cifCurReadStyle->crs_scaleFactor; area.r_ytop = CIFScaleCoord(area.r_ytop, snap_type); if (snap_type == COORD_HALF_U) snap_type = COORD_HALF_L; if (savescale != cifCurReadStyle->crs_scaleFactor) { area.r_xtop *= (savescale / cifCurReadStyle->crs_scaleFactor); savescale = cifCurReadStyle->crs_scaleFactor; } area.r_xbot = CIFScaleCoord(area.r_xbot, snap_type); if (savescale != cifCurReadStyle->crs_scaleFactor) { area.r_xtop *= (savescale / cifCurReadStyle->crs_scaleFactor); area.r_ytop *= (savescale / cifCurReadStyle->crs_scaleFactor); savescale = cifCurReadStyle->crs_scaleFactor; } area.r_ybot = CIFScaleCoord(area.r_ybot, snap_type); if (savescale != cifCurReadStyle->crs_scaleFactor) { area.r_xtop *= (savescale / cifCurReadStyle->crs_scaleFactor); area.r_ytop *= (savescale / cifCurReadStyle->crs_scaleFactor); area.r_xbot *= (savescale / cifCurReadStyle->crs_scaleFactor); } /* Check for degenerate areas (from rescale limiting) before painting */ if ((area.r_xbot == area.r_xtop) || (area.r_ybot == area.r_ytop)) return 0; for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++) if (DBPaintOnPlane(type, pNum)) { DBNMPaintPlane(cifReadCellDef->cd_planes[pNum], TiGetTypeExact(tile), &area, DBStdPaintTbl(type, pNum), (PaintUndoInfo *) NULL); } return 0; /* To keep the search alive. */ } /* * ---------------------------------------------------------------------------- * * CIFParseFinish -- * * This procedure is called at the end of a cell definition. * * Results: * TRUE is returned if the parse completed successfully, and * FALSE is returned otherwise. * * Side effects: * Process the CIF planes and paint the results into the Magic * cell. * * ---------------------------------------------------------------------------- */ bool CIFParseFinish() { if (!cifSubcellBeingRead) { CIFReadError("definition finish without definition start; ignored.\n"); CIFSkipToSemi(); return FALSE; } if (cifSubcellId != NULL) { CIFReadError("pending call identifier %s discarded.\n", cifSubcellId); (void) StrDup(&cifSubcellId, (char *) NULL); } /* Take the `F'. */ TAKE(); /* Do the geometrical processing and paint this material back into * the appropriate cell of the database. Then restore the saved * layer info. */ CIFPaintCurrent(FILE_CIF); DBAdjustLabels(cifReadCellDef, &TiPlaneRect); DBReComputeBbox(cifReadCellDef); cifReadCellDef = EditCellUse->cu_def; cifReadPlane = cifOldReadPlane; cifReadScale1 = 1; cifReadScale2 = 1; cifSubcellBeingRead = FALSE; cifCurReadPlanes = cifEditCellPlanes; return TRUE; } /* * ---------------------------------------------------------------------------- * * CIFParseDelete -- * * This procedure is called to handle delete-symbol statements. * * Results: * TRUE is returned if the parse completed successfully, and * FALSE is returned otherwise. * * Side effects: * The mapping between numbers and cells is modified to eliminate * some symbols. * * ---------------------------------------------------------------------------- */ bool CIFParseDelete() { int number; /* Take the `D'. */ TAKE(); if (!CIFParseInteger(&number)) { CIFReadError("definition delete, but no symbol number; ignored.\n"); CIFSkipToSemi(); return FALSE; } /* Unlink the hash entry from its target definition */ cifForgetCell(number); CIFSkipToSemi(); return TRUE; } /* * ---------------------------------------------------------------------------- * * cifParseName -- * * Parse a name, which is a string of alphabetics, numerics, * or underscores, possibly preceded by whitespace. * * Results: * The return value is a pointer to the name read from the * CIF file. This is a statically-allocated area, so the * caller should copy out of this area before invoking this * procedure again. * * Side effects: * None. * * ---------------------------------------------------------------------------- */ char * cifParseName() { char ch; char *bufferp; static char buffer[128]; /* Skip white space. */ for (ch = PEEK() ; ch == ' ' || ch == '\t' ; ch = PEEK()) TAKE(); /* Read the string. */ bufferp = &buffer[0]; for (ch = PEEK() ; (! isspace(ch)) && ch != ';' ; ch = PEEK()) { *bufferp++ = TAKE(); } *bufferp = '\0'; return buffer; } /* * ---------------------------------------------------------------------------- * * cifParseUser9 -- * * This procedure processes user extension 9: the name of the * current symbol (cell) definition. * * Results: * TRUE is returned if the parse completed successfully, and * FALSE is returned otherwise. * * Side effects: * The current CIF symbol is renamed from its default "cifxx" name * to the given name. * * ---------------------------------------------------------------------------- */ bool cifParseUser9() { char *name; name = cifParseName(); if (!DBCellRenameDef(cifReadCellDef, name)) { CIFReadError("%s already exists, so cell from CIF is named %s.\n", name, cifReadCellDef->cd_name); } return TRUE; } /* * ---------------------------------------------------------------------------- * * CIFParseCall -- * * This procedure processes subcell uses. The syntax of a call is * call ::= C integer transform * * Results: * TRUE is returned if the parse completed successfully, and * FALSE is returned otherwise. * * Side effects: * A subcell is added to the current Magic cell we're generating. * * ---------------------------------------------------------------------------- */ bool CIFParseCall() { int called; Transform transform; CellUse *use; CellDef *def; /* Take the `C'. */ TAKE(); if (!CIFParseInteger(&called)) { CIFReadError("call, but no symbol number; ignored.\n"); CIFSkipToSemi(); return FALSE; } /* Get optional transformation. */ (void) CIFParseTransform(&transform); def = cifFindCell(called); /* avoid recursion */ if (DBIsAncestor(def, cifReadCellDef)) { CIFReadError("attempt to place cell use inside its own definition!\n"); CIFSkipToSemi(); return FALSE; } /* Find the use and add it to the current cell. Give it an * id also. */ use = DBCellNewUse(def, cifSubcellId); (void) DBLinkCell(use, cifReadCellDef); DBSetTrans(use, &transform); DBPlaceCell(use, cifReadCellDef); (void) StrDup(&cifSubcellId, (char *) NULL); return TRUE; } /* * ---------------------------------------------------------------------------- * * cifParseUser91 -- * * This procedure handles 91 user commands, which provide id's * for following cell calls. The syntax is: * 91 ::= 91 blanks name * * Results: * TRUE is returned if the parse completed successfully, and * FALSE is returned otherwise. * * Side effects: * The identifier is saved until the call is read. Then it is * used as the identifier for the cell. * * ---------------------------------------------------------------------------- */ bool cifParseUser91() { if (cifSubcellId != NULL) { CIFReadError("91 command with identifier %s pending; %s discarded.\n" , cifSubcellId , cifSubcellId); } (void) StrDup(&cifSubcellId, cifParseName()); return TRUE; } /* * ---------------------------------------------------------------------------- * * cifParseUser94 -- * * This procedure parses 94 user commands, which are labelled * points. The syntax is: * 94 ::= 94 blanks name point * * Results: * TRUE is returned if the parse completed successfully, and * FALSE is returned otherwise. * * Side effects: * A label is added to the current cell. * * ---------------------------------------------------------------------------- */ bool cifParseUser94() { Rect rectangle; char *name = NULL; TileType type; int layer, flags, i; int savescale; (void) StrDup(&name, cifParseName()); if (! CIFParsePoint(&rectangle.r_ll, 1)) { CIFReadError("94 command, but no location; ignored.\n"); CIFSkipToSemi(); return FALSE; } /* Scale the coordinates, then make the location into a * rectangle. */ rectangle.r_xbot = CIFScaleCoord(rectangle.r_xbot, COORD_ANY); savescale = cifCurReadStyle->crs_scaleFactor; rectangle.r_ybot = CIFScaleCoord(rectangle.r_ybot, COORD_ANY); if (savescale != cifCurReadStyle->crs_scaleFactor) rectangle.r_xbot *= (savescale / cifCurReadStyle->crs_scaleFactor); rectangle.r_ur = rectangle.r_ll; /* Get a layer, lookup the layer, then add the label to the * current cell. Tricky business: in order for the default * label location to be computed */ CIFSkipBlanks(); if (PEEK() != ';') { char *lname = cifParseName(); layer = CIFReadNameToType(lname, FALSE); if (layer < 0) { CIFReadError("label attached to unknown layer %s.\n", lname); type = TT_SPACE; } else { type = cifCurReadStyle->crs_labelLayer[layer]; } } else { type = cifCurLabelType; /* Should do this better, by defining cifCurLabelFlags. . . */ layer = -1; for (i = 0; i < cifCurReadStyle->crs_nLayers; i++) if (cifCurReadStyle->crs_labelLayer[i] == type) { layer = i; break; } } if (type >=0 ) { if (layer >= 0 && cifCurReadStyle->crs_labelSticky[layer]) flags = LABEL_STICKY; else flags = 0; (void) DBPutLabel(cifReadCellDef, &rectangle, -1, name, type, flags, 0); } freeMagic(name); return TRUE; } /* * ---------------------------------------------------------------------------- * * cifParseUser95 -- * * This procedure parses 95 user commands, which are labelled * points. The syntax is: * 95 ::= 95 blanks name length width point * * Results: * TRUE is returned if the parse completed successfully, and * FALSE is returned otherwise. * * Side effects: * An area label is added to the current cell. * * ---------------------------------------------------------------------------- */ bool cifParseUser95() { /* Modified by BIM 1/8/2018 */ Rect rectangle; Point size, center, lowerleft, upperright; char *name = NULL; TileType type; int layer, i; int savescale; (void) StrDup(&name, cifParseName()); if (! CIFParsePoint(&size, 1)) { CIFReadError("95 command, but no size; ignored.\n"); CIFSkipToSemi(); return FALSE; } savescale = cifCurReadStyle->crs_scaleFactor; /* The center coordinates returned are in CIF units *2 */ /* the values will be halved later before conversion to magic units */ if (! CIFParsePoint(¢er, 2)) { CIFReadError("95 command, but no location; ignored.\n"); CIFSkipToSemi(); return FALSE; } /* If reading the center causes a CIF input scale to be redefined, */ /* then the length and width must also be changed. */ if (savescale != cifCurReadStyle->crs_scaleFactor) { size.p_x *= (cifCurReadStyle->crs_scaleFactor / savescale); size.p_y *= (cifCurReadStyle->crs_scaleFactor / savescale); } /* Scale the coordinates and create the rectangular area. */ /* Explicitly calculate lowerleft and upperright using CIF units *2 */ /* so that half-lambda centers are resolved before remapping to */ /* magic coordinates. */ lowerleft.p_x = center.p_x - size.p_x; lowerleft.p_y = center.p_y - size.p_y; upperright.p_x = center.p_x + size.p_x; upperright.p_y = center.p_y + size.p_y; if ((lowerleft.p_x % 2 == 0) && (lowerleft.p_y % 2 == 0)) { /* if possible convert values to CIF units by dividing by two */ lowerleft.p_x /= 2; lowerleft.p_y /= 2; upperright.p_x /= 2; upperright.p_y /= 2; } else { /* if division by two would create inaccuracy then rescale to accommodate */ CIFInputRescale(2, 1); } /* now scale each of the co-ordinates in turn */ lowerleft.p_x = CIFScaleCoord(lowerleft.p_x, COORD_ANY); savescale = cifCurReadStyle->crs_scaleFactor; lowerleft.p_y = CIFScaleCoord(lowerleft.p_y, COORD_ANY); if (savescale != cifCurReadStyle->crs_scaleFactor) { lowerleft.p_x *= (savescale / cifCurReadStyle->crs_scaleFactor); savescale = cifCurReadStyle->crs_scaleFactor; } upperright.p_x = CIFScaleCoord(upperright.p_x, COORD_ANY); if (savescale != cifCurReadStyle->crs_scaleFactor) { lowerleft.p_x *= (savescale / cifCurReadStyle->crs_scaleFactor); lowerleft.p_y *= (savescale / cifCurReadStyle->crs_scaleFactor); savescale = cifCurReadStyle->crs_scaleFactor; } upperright.p_y = CIFScaleCoord(upperright.p_y, COORD_ANY); if (savescale != cifCurReadStyle->crs_scaleFactor) { lowerleft.p_x *= (savescale / cifCurReadStyle->crs_scaleFactor); lowerleft.p_y *= (savescale / cifCurReadStyle->crs_scaleFactor); upperright.p_x *= (savescale / cifCurReadStyle->crs_scaleFactor); } rectangle.r_xbot = lowerleft.p_x; rectangle.r_ybot = lowerleft.p_y; rectangle.r_xtop = upperright.p_x; rectangle.r_ytop = upperright.p_y; /* Get a layer, lookup the layer, then add the label to the * current cell. Tricky business: in order for the default * label location to be computed */ CIFSkipBlanks(); if (PEEK() != ';') { char *name = cifParseName(); layer = CIFReadNameToType(name, FALSE); if (layer < 0) { CIFReadError("label attached to unknown layer %s.\n", name); type = TT_SPACE; } else type = cifCurReadStyle->crs_labelLayer[layer]; } else { type = TT_SPACE; layer = -1; for (i = 0; i < cifCurReadStyle->crs_nLayers; i++) if (cifCurReadStyle->crs_labelLayer[i] == type) { layer = i; break; } } if (type >=0 ) { int flags; if (layer >= 0 && cifCurReadStyle->crs_labelSticky[layer]) flags = LABEL_STICKY; else flags = 0; (void) DBPutLabel(cifReadCellDef, &rectangle, -1, name, type, flags, 0); } freeMagic(name); return TRUE; } /* * ---------------------------------------------------------------------------- * * CIFParseUser -- * * This procedure is called to process user-defined statements. * The syntax is user ::= digit usertext. * * Results: * TRUE is returned if the parse completed successfully, and * FALSE is returned otherwise. * * Side effects: * Depends on the user command. * * ---------------------------------------------------------------------------- */ bool CIFParseUser() { char ch; ch = TAKE(); switch (ch) { case '9': ch = PEEK(); switch (ch) { case '1': (void) TAKE(); return cifParseUser91(); case '4': (void) TAKE(); return cifParseUser94(); case '5': (void) TAKE(); return cifParseUser95(); default: if (isspace(ch)) return cifParseUser9(); } default: CIFReadError("unimplemented user extension; ignored.\n"); CIFSkipToSemi(); return FALSE; } } /* * ---------------------------------------------------------------------------- * * CIFReadCellCleanup -- * * This procedure is called after processing the CIF file. * It performs various cleanup functions on the cells that * have been read in. * * Results: * None. * * Side effects: * The area of each cell is DRC'ed and redisplayed. Error * messages are output for any cells whose contents weren't * in the CIF file. An error message is also output if * we're still in the middle of reading a subcell. * * ---------------------------------------------------------------------------- */ void CIFReadCellCleanup(filetype) bool filetype; { HashEntry *h; HashSearch hs; CellDef *def; MagWindow *window; int flags; if (cifSubcellBeingRead) { if (filetype == FILE_CIF) CIFReadError("CIF ended partway through a symbol definition.\n"); else CalmaReadError("GDS ended partway through a symbol definition.\n"); (void) CIFParseFinish(); } HashStartSearch(&hs); while (TRUE) { h = HashNext(&CifCellTable, &hs); if (h == NULL) break; def = (CellDef *) HashGetValue(h); if (def == NULL) { if (filetype == FILE_CIF) CIFReadError("cell table has NULL entry (Magic error).\n"); else CalmaReadError("cell table has NULL entry (Magic error).\n"); continue; } flags = def->cd_flags; if (!(flags & CDAVAILABLE)) { if (filetype == FILE_CIF) CIFReadError("cell %s was used but not defined.\n", def->cd_name); else CalmaReadError("cell %s was used but not defined.\n", def->cd_name); } def->cd_flags &= ~CDPROCESSEDGDS; if ((filetype == FILE_CIF && CIFNoDRCCheck == FALSE) || (filetype == 1 && CalmaNoDRCCheck == FALSE)) DRCCheckThis(def, TT_CHECKPAINT, &def->cd_bbox); DBWAreaChanged(def, &def->cd_bbox, DBW_ALLWINDOWS, &DBAllButSpaceBits); DBCellSetModified(def, TRUE); /* Only mark cell as needing a timestamp update if the timestamp is zero */ if (def->cd_timestamp != 0) def->cd_flags &= ~CDGETNEWSTAMP; } /* Do geometrical processing on the top-level cell. */ CIFPaintCurrent(FILE_CIF); DBAdjustLabels(EditCellUse->cu_def, &TiPlaneRect); DBReComputeBbox(EditCellUse->cu_def); DBWAreaChanged(EditCellUse->cu_def, &EditCellUse->cu_def->cd_bbox, DBW_ALLWINDOWS, &DBAllButSpaceBits); DBCellSetModified(EditCellUse->cu_def, TRUE); /* Clean up saved CIF/GDS planes in cd_client records of cells */ HashStartSearch(&hs); while (TRUE) { h = HashNext(&CifCellTable, &hs); if (h == NULL) break; def = (CellDef *) HashGetValue(h); if (def == NULL) continue; if (def->cd_flags & CDFLATGDS) { /* These cells have been flattened and are no longer needed. */ /* Do not remove the actual CellDef, though, because it is */ /* still instanced, and that instance tells the GDS write */ /* routine that the subcell needs to be included in the */ /* output. But all clientdata and labels should be removed. */ int pNum; Plane **cifplanes = (Plane **)def->cd_client; UndoDisable(); /* cifplanes should be valid, but don't crash magic if not */ if (cifplanes != (Plane **)0) { for (pNum = 0; pNum < MAXCIFRLAYERS; pNum++) { if (cifplanes[pNum] != NULL) { DBFreePaintPlane(cifplanes[pNum]); TiFreePlane(cifplanes[pNum]); } } freeMagic((char *)def->cd_client); } def->cd_client = (ClientData)0; def->cd_flags &= ~CDFLATGDS; UndoEnable(); } } HashKill(&CifCellTable); }