/* 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, (char *) NULL); /* 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, cifEditCellPlanes); if (cifEditCellPlanes != 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; Rect sourceRect, targetRect; Transform *trans = cifCopyRec->trans; Plane *plane = cifCopyRec->plane; if (trans) { TiToRect(tile, &sourceRect); GeoTransRect(trans, &sourceRect, &targetRect); } else TiToRect(tile, &targetRect); DBNMPaintPlane(plane, TiGetTypeExact(tile), &targetRect, CIFPaintTable, (PaintUndoInfo *)NULL); 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() { 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, &TiPlaneRect, (CellDef *) NULL, cifCurReadPlanes); /* 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]); if (cifReadCellDef->cd_flags & CDFLATGDS) 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 = DBNewPlane((ClientData) TT_SPACE); DBClearPaintPlane(newplane); cifCopyRec.plane = newplane; cifCopyRec.trans = NULL; DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect, &DBAllButSpaceBits, cifCopyPaintFunc, &cifCopyRec); parray[pNum] = newplane; } } } /* 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); } /* Now go through all the current planes and zero them out. */ for (i = 0; i < MAXCIFRLAYERS; i++) DBClearPaintPlane(cifCurReadPlanes[i]); return 0; } /* Below is the search function invoked for each CIF tile type * found for the current layer. */ 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(); 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_layers[layer]->crl_flags & CIFR_TEXTLABELS)) flags = LABEL_STICKY; else flags = 0; (void) DBPutLabel(cifReadCellDef, &rectangle, -1, name, type, flags); } 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() { Rect rectangle; Point size, center; 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; } if (! CIFParsePoint(¢er, 1)) { CIFReadError("95 command, but no location; ignored.\n"); CIFSkipToSemi(); return FALSE; } /* Scale the coordinates and create the rectangular area. */ /* Remap center and size to lowerleft and upperright, respectively, */ /* so that half-lambda centers are resolved before remapping to */ /* magic coordinates. */ center.p_x = CIFScaleCoord(center.p_x - size.p_x/2, COORD_ANY); savescale = cifCurReadStyle->crs_scaleFactor; center.p_y = CIFScaleCoord(center.p_y - size.p_y/2, COORD_ANY); if (savescale != cifCurReadStyle->crs_scaleFactor) { center.p_x *= (savescale / cifCurReadStyle->crs_scaleFactor); savescale = cifCurReadStyle->crs_scaleFactor; } size.p_x = CIFScaleCoord(center.p_x + (size.p_x - size.p_x/2), COORD_ANY); if (savescale != cifCurReadStyle->crs_scaleFactor) { center.p_x *= (savescale / cifCurReadStyle->crs_scaleFactor); center.p_y *= (savescale / cifCurReadStyle->crs_scaleFactor); savescale = cifCurReadStyle->crs_scaleFactor; } size.p_y = CIFScaleCoord(center.p_y + (size.p_y - size.p_y/2), COORD_ANY); if (savescale != cifCurReadStyle->crs_scaleFactor) { center.p_x *= (savescale / cifCurReadStyle->crs_scaleFactor); center.p_y *= (savescale / cifCurReadStyle->crs_scaleFactor); size.p_x *= (savescale / cifCurReadStyle->crs_scaleFactor); } rectangle.r_xbot = center.p_x; rectangle.r_ybot = center.p_y; rectangle.r_xtop = size.p_x; rectangle.r_ytop = size.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_layers[layer]->crl_flags & CIFR_TEXTLABELS)) flags = LABEL_STICKY; else flags = 0; (void) DBPutLabel(cifReadCellDef, &rectangle, -1, name, type, flags); } 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(type) int type; // 0 = CIF, 1 = GDS, because routine is used by both { HashEntry *h; HashSearch hs; CellDef *def; MagWindow *window; int flags; if (cifSubcellBeingRead) { if (type == 0) 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 (type == 0) 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 (type == 0) 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 ((type == 0 && CIFNoDRCCheck == FALSE) || (type == 1 && CalmaNoDRCCheck == FALSE)) DRCCheckThis(def, TT_CHECKPAINT, &def->cd_bbox); DBWAreaChanged(def, &def->cd_bbox, DBW_ALLWINDOWS, &DBAllButSpaceBits); DBCellSetModified(def, TRUE); } /* Do geometrical processing on the top-level cell. */ CIFPaintCurrent(); 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. */ int pNum; Plane **cifplanes = (Plane **)def->cd_client; UndoDisable(); 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)CLIENTDEFAULT; /* If the CDFLATTENED flag was not set, then this geometry */ /* was never instantiated, and should generate a warning. */ if (!(def->cd_flags & CDFLATTENED)) CIFReadError("%s read error: Unresolved geometry in cell" " %s maps to no magic layers\n", (type == 0) ? "CIF" : "GDS", def->cd_name); #if 0 /* Remove the cell if it has no parents, no children, and no geometry */ /* To-do: Check that these conditions are valid */ if (def->cd_parents == (CellUse *)NULL) { char *savename = StrDup((char **)NULL, def->cd_name); if (DBCellDeleteDef(def) == FALSE) { CIFReadError("%s read error: Unable to delete cell %s\n", (type == 0) ? "CIF" : "GDS", savename); } else { if (type == 0) TxPrintf("CIF read: Removed flattened cell %s\n", savename); else TxPrintf("GDS read: Removed flattened cell %s\n", savename); } freeMagic(savename); } #endif UndoEnable(); } } HashKill(&CifCellTable); }