/* * CIFwrite.c -- * * Output of CIF. * * ********************************************************************* * * 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 const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cif/CIFwrite.c,v 1.2 2010/06/24 12:37:15 tim Exp $"; #endif /* not lint */ #include #include #include #include #include "utils/magic.h" #include "utils/geometry.h" #include "tiles/tile.h" #include "utils/utils.h" #include "utils/hash.h" #include "database/database.h" #include "database/databaseInt.h" #include "utils/tech.h" #include "utils/stack.h" #include "utils/undo.h" #include "cif/cif.h" #include "cif/CIFint.h" #include "utils/signals.h" #include "windows/windows.h" #include "dbwind/dbwind.h" #include "utils/styles.h" #include "textio/textio.h" /* Forward declarations */ extern int cifWriteInitFunc(CellDef *def); extern int cifWriteMarkFunc(CellUse *use); extern int cifWritePaintFunc(Tile *tile, FILE *f); extern int cifWriteLabelFunc(Tile *tile, FILE *f); extern int cifWriteUseFunc(CellUse *use, FILE *f); extern void cifOutPreamble(FILE *outf, CellDef *cell); extern void cifOut(FILE *outf); extern void cifOutFunc(CellDef *def, FILE *f); extern void GrClipTriangle(Rect *r, Rect *c, int clipped, TileType dinfo, Point *points, int *np); /* Current cell number in CIF numbering scheme */ static int cifCellNum; /* Stack of definitions left to process for generating CIF */ Stack *cifStack; /* Scale factor for outputting paint: */ int cifPaintScale; /* Current layer name. If non-NULL, then cifWritePaintFunc outputs * this string to the file before outputting a rectangle, then nulls. * This way, the layer name only gets output when there's actually * stuff on that layer. */ char *cifPaintLayerName; /* TRUE if area labels should be output */ bool CIFDoAreaLabels = FALSE; /* TRUE if cell ids should be output */ bool CIFDoCellIdLabels = TRUE; /* prefix string for pathnames */ char *CIFPathPrefix = NULL; /* These are normally FALSE---enable at your own risk! */ bool CIFHierWriteDisable = FALSE; bool CIFArrayWriteDisable = FALSE; /* * ---------------------------------------------------------------------------- * * CIFWrite -- * * Write out the entire tree rooted at the supplied CellDef in CIF format, * to the specified file. * * Results: * TRUE if the cell could be written successfully, FALSE otherwise. * * Side effects: * Writes a file to disk. * In the event of an error while writing out the cell, * the external integer errno is set to the UNIX error * encountered. * * Algorithm: * We make a depth-first traversal of the entire design tree, * marking each cell with a CIF symbol number and then outputting * it to the CIF file. If a given cell is not read in when we * visit it, we read it in. * * No hierarchical design rule checking or bounding box computation * occur during this traversal -- both are explicitly avoided. * * ---------------------------------------------------------------------------- */ bool CIFWrite( CellDef *rootDef, /* Pointer to CellDef to be written */ FILE *f) /* Open output file */ { bool good; int oldCount = DBWFeedbackCount; CellDef *err_def; CellUse dummy; /* * Make sure that the entire hierarchy rooted at rootDef is * read into memory and that timestamp mismatches are resolved * (this is needed so that we know that bounding boxes are OK). */ dummy.cu_def = rootDef; err_def = DBCellReadArea(&dummy, &rootDef->cd_bbox, TRUE); if (err_def != NULL) { TxError("Failure to read in entire subtree of the cell.\n"); TxError("Failed on cell %s.\n", err_def->cd_name); return (FALSE); } DBFixMismatch(); if (CIFCurStyle->cs_reducer == 0) { TxError("The current CIF output style can only be used for writing\n"); TxError("Calma output. Try picking another output style.\n"); return (FALSE); } /* * Go through all cells currently having CellDefs in the * def symbol table and mark them with negative symbol numbers. */ (void) DBCellSrDefs(0, cifWriteInitFunc, (ClientData) NULL); cifCellNum = (-2); rootDef->cd_client = (ClientData) -1; /* * Start by pushing the root def on the stack of cell defs * to be processed. */ cifStack = StackNew(100); StackPush((ClientData) rootDef, cifStack); cifOutPreamble(f, rootDef); cifOut(f); StackFree(cifStack); if ((int) CD2INT(rootDef->cd_client) < 0) rootDef->cd_client = INT2CD(- (int) CD2INT(rootDef->cd_client)); /* See if any problems occurred. */ if (DBWFeedbackCount != oldCount) { TxPrintf("%d problems occurred. See feedback entries.\n", DBWFeedbackCount - oldCount); } /* * Now we are almost done. * Just output a call on the root cell */ fprintf(f, "C %d;\nEnd\n", (int) CD2INT(rootDef->cd_client)); good = !ferror(f); return (good); } /* * ---------------------------------------------------------------------------- * * cifWriteInitFunc -- * * Filter function called on behalf of CIFWrite() above. * Responsible for setting the cif number of each cell to zero. * * Results: * Returns 0 to indicate that the search should continue. * * Side effects: * Modify the cif numbers of the cells they are passed. * * ---------------------------------------------------------------------------- */ int cifWriteInitFunc( CellDef *def) { def->cd_client = (ClientData) 0; return (0); } /* * ---------------------------------------------------------------------------- * * cifWriteMarkFunc -- * * Called to add each cell def in the subcell plane of a parent * to the stack of cells to be processed. * * Results: * Returns 0 to indicate that DBCellEnum() should continue. * * Side effects: * Pushes the cell def on the stack. * ---------------------------------------------------------------------------- */ int cifWriteMarkFunc( CellUse *use) { if (use->cu_def->cd_client != (ClientData) 0) return 0; use->cu_def->cd_client = INT2CD(cifCellNum); cifCellNum -= 1; StackPush((ClientData) use->cu_def, cifStack); return (0); } /* * ---------------------------------------------------------------------------- * * cifOutPreamble -- * * Write preamble in front of a CIF file for version control. * * Results: * None. * * Side effects: * Preamble in CIF comment style - () are send to output file. * ---------------------------------------------------------------------------- */ void cifOutPreamble( FILE *outf, CellDef *cell) { extern char *MagicVersion; extern char *MagicCompileTime; char *now, *t; struct tm *clock; time_t t_stamp = time((time_t *) NULL); clock = localtime(&t_stamp); now = ctime(&t_stamp); /* remove the '\n' at the end of the string... */ now[strlen(now)-1] = '\0'; fprintf(outf,"( @@user : %s );\n", (t = getenv("USER")) ? t : "?"); fprintf(outf,"( @@machine : %s );\n", (t = getenv("HOSTNAME")) ? t : "?"); fprintf(outf,"( @@source : %s );\n",(cell->cd_file) ? cell->cd_file : "?"); fprintf(outf,"( @@tool : Magic %s.%s );\n", MagicVersion, MagicRevision); fprintf(outf,"( @@compiled : %s );\n", MagicCompileTime); fprintf(outf,"( @@technology : %s );\n", DBTechName); if (DBTechVersion) fprintf(outf,"( @@version : %s );\n", DBTechVersion); else fprintf(outf,"( @@version : unknown );\n"); if (DBTechDescription) fprintf(outf,"( @@techdesc : %s );\n", DBTechDescription); fprintf(outf,"( @@style : %s );\n", CIFCurStyle->cs_name); fprintf(outf,"( @@date : %s );\n", now); } /* * ---------------------------------------------------------------------------- * * cifOut -- * * Main loop of CIF generation. Pull a cell def from the stack * and process it. * * Results: * None. * * Side effects: * Causes CIF to be output. * Returns when the stack is empty. * ---------------------------------------------------------------------------- */ void cifOut( FILE *outf) { CellDef *def; bool needHier; while (!StackEmpty(cifStack)) { def = (CellDef *) StackPop(cifStack); if ((int) CD2INT(def->cd_client) >= 0) continue; /* Already output */ if (SigInterruptPending) continue; def->cd_client = INT2CD(- (int) CD2INT(def->cd_client)); /* Read the cell in if it is not already available. */ if ((def->cd_flags & CDAVAILABLE) == 0) if (!DBCellRead(def, TRUE, TRUE, NULL)) continue; /* Add any subcells to the stack. This must be done before * outputting CIF to make sure that the subcells all have * CIF numbers. */ (void) DBCellEnum(def, cifWriteMarkFunc, (ClientData) 0); /* Output CIF for this cell */ cifOutFunc(def, outf); } } /* * ---------------------------------------------------------------------------- * * cifOutFunc -- * * Write out the definition for a single cell as CIF. * * Results: * None. * * Side effects: * Appends to the open CIF output file. * * ---------------------------------------------------------------------------- */ void cifOutFunc( CellDef *def, /* Pointer to cell def to be written */ FILE *f) /* Open output file */ { Rect bigArea; Label *lab; int type; CIFLayer *layer; fprintf(f, "DS %d %d %d;\n", (int) CD2INT(def->cd_client), CIFCurStyle->cs_reducer, 2 * CIFCurStyle->cs_expander); if (def->cd_name != (char *) NULL) if (def->cd_name[0] != '\0') { if (strcmp(def->cd_name, "(UNNAMED)") == 0) fprintf(f, "9 UNNAMED;\n"); else { if (CIFPathPrefix && CIFPathPrefix[0]) fprintf(f, "9 %s/%s;\n", CIFPathPrefix, def->cd_name); else fprintf(f, "9 %s;\n", def->cd_name); } } /* * Output all the tiles associated with this cell. Skip temporary * layers. */ GEO_EXPAND(&def->cd_bbox, CIFCurStyle->cs_radius, &bigArea); CIFErrorDef = def; CIFGen(def, def, &bigArea, CIFPlanes, &DBAllTypeBits, TRUE, TRUE, FALSE, (ClientData)NULL); if (!CIFHierWriteDisable) CIFGenSubcells(def, &bigArea, CIFPlanes); if (!CIFArrayWriteDisable) CIFGenArrays(def, &bigArea, CIFPlanes); for (type = 0; type < CIFCurStyle->cs_nLayers; type++) { layer = CIFCurStyle->cs_layers[type]; if (layer->cl_flags & CIF_TEMP) continue; cifPaintLayerName = layer->cl_name; cifPaintScale = 1; if (layer->cl_flags & CIF_LABEL) DBSrPaintArea((Tile *) NULL, CIFPlanes[type], &TiPlaneRect, &CIFSolidBits, cifWriteLabelFunc, (ClientData) f); else DBSrPaintArea((Tile *) NULL, CIFPlanes[type], &TiPlaneRect, &CIFSolidBits, cifWritePaintFunc, (ClientData) f); } /* Output labels */ for (lab = def->cd_labels; lab; lab = lab->lab_next) { int type = CIFCurStyle->cs_labelLayer[lab->lab_type]; Point center, size; center.p_x = lab->lab_rect.r_xbot + lab->lab_rect.r_xtop; center.p_y = lab->lab_rect.r_ybot + lab->lab_rect.r_ytop; center.p_x *= CIFCurStyle->cs_scaleFactor; center.p_x /= CIFCurStyle->cs_reducer; center.p_y *= CIFCurStyle->cs_scaleFactor; center.p_y /= CIFCurStyle->cs_reducer; if (CIFDoAreaLabels) { size.p_x = lab->lab_rect.r_xtop - lab->lab_rect.r_xbot; size.p_y = lab->lab_rect.r_ytop - lab->lab_rect.r_ybot; size.p_x *= 2 * CIFCurStyle->cs_scaleFactor; size.p_x /= CIFCurStyle->cs_reducer; size.p_y *= 2 * CIFCurStyle->cs_scaleFactor; size.p_y /= CIFCurStyle->cs_reducer; if (type >= 0) { fprintf(f, "95 %s %d %d %d %d %s;\n", lab->lab_text, size.p_x, size.p_y, center.p_x, center.p_y, CIFCurStyle->cs_layers[type]->cl_name); } else { fprintf(f, "95 %s %d %d %d %d;\n", lab->lab_text, size.p_x, size.p_y, center.p_x, center.p_y); } } else { if (type >= 0) { fprintf(f, "94 %s %d %d %s;\n", lab->lab_text, center.p_x, center.p_y, CIFCurStyle->cs_layers[type]->cl_name); } else { fprintf(f, "94 %s %d %d;\n", lab->lab_text, center.p_x, center.p_y); } } } /* * Output the calls that the child makes to its children. For * arrays it is necessary to output one call for each instance. */ (void) DBCellEnum(def, cifWriteUseFunc, (ClientData) f); fprintf(f, "DF;\n"); } /* * ---------------------------------------------------------------------------- * * cifWriteUseFunc -- * * Filter function, called by DBCellEnum on behalf of cifOutFunc above, * to write out each CellUse called by the CellDef being output. * * Results: * Always return 0 * * Side effects: * Appends to the open CIF output file. * * ---------------------------------------------------------------------------- */ int cifWriteUseFunc( CellUse *use, FILE *f) { int x, y, topx, topy; int realx, realy; Transform *t; int cifnum; cifnum = (int) CD2INT(use->cu_def->cd_client); if (cifnum < 0) cifnum = (-cifnum); topx = use->cu_xhi - use->cu_xlo; if (topx < 0) topx = -topx; topy = use->cu_yhi - use->cu_ylo; if (topy < 0) topy = -topy; realx = use->cu_xlo; for (x = 0; x <= topx; x++) { realy = use->cu_ylo; for (y = 0; y <= topy; y++) { /* * We eventually want to tag each use with its unique * use identifier, which should include array subscripting * information. */ /* * Insert a 91 user command to label the next cell */ if (CIFDoCellIdLabels && use->cu_id && use->cu_id[0]) { fprintf (f, "91 %s", use->cu_id); if (topx > 0 || topy > 0) { if (topx > 0 && topy > 0) fprintf (f, "(%d,%d)", realy, realx); else { if (topx > 0) fprintf (f, "(%d)", realx); else fprintf (f, "(%d)", realy); } } fprintf (f, ";\n"); } fprintf(f, "C %d", cifnum); /* * The following translates from the abcdef transforms * that we use internally to the rotate and mirror * specs used in CIF. It only works because * orientations are orthogonal in magic. Check all * 8 possible positions if you don't believe this. */ t = &use->cu_transform; if ((t->t_a != t->t_e) || ((t->t_a == 0) && (t->t_b == t->t_d))) fprintf(f, " MX R %d %d", -(t->t_a), -(t->t_d)); else fprintf(f, " R %d %d", t->t_a, t->t_d); fprintf(f, " T %d %d;\n", ((t->t_c + t->t_a*(use->cu_xsep)*x + t->t_b*(use->cu_ysep)*y) * 2 * CIFCurStyle->cs_scaleFactor) / CIFCurStyle->cs_reducer, ((t->t_f + t->t_d*(use->cu_xsep)*x + t->t_e*(use->cu_ysep)*y) * 2 * CIFCurStyle->cs_scaleFactor) / CIFCurStyle->cs_reducer); if (use->cu_yhi > use->cu_ylo) realy++; else realy--; } if (use->cu_xhi > use->cu_xlo) realx++; else realx--; } return 0; } /* * ---------------------------------------------------------------------------- * * cifWriteLabelFunc -- * * Filter function used to write out a label corresponding to a * single paint tile. The CIF layer name is used as the label to * output. * * Results: * Always return 0 * * Side effects: * Writes to the disk file. * * ---------------------------------------------------------------------------- */ int cifWriteLabelFunc( Tile *tile, /* Tile to be written out. */ FILE *f) /* File in which to write. */ { Rect r; int type; Point center, size; if (IsSplit(tile)) return 0; /* Ignore non-manhattan tiles */ if (cifPaintLayerName == NULL) return 0; /* Shouldn't happen */ TiToRect(tile, &r); type = CIFCurStyle->cs_labelLayer[TiGetType(tile)]; center.p_x = r.r_xbot + r.r_xtop; center.p_y = r.r_ybot + r.r_ytop; center.p_x *= CIFCurStyle->cs_scaleFactor; center.p_x /= CIFCurStyle->cs_reducer; center.p_y *= CIFCurStyle->cs_scaleFactor; center.p_y /= CIFCurStyle->cs_reducer; if (CIFDoAreaLabels) { size.p_x = r.r_xtop - r.r_xbot; size.p_y = r.r_ytop - r.r_ybot; size.p_x *= 2 * CIFCurStyle->cs_scaleFactor; size.p_x /= CIFCurStyle->cs_reducer; size.p_y *= 2 * CIFCurStyle->cs_scaleFactor; size.p_y /= CIFCurStyle->cs_reducer; fprintf(f, "95 %s %d %d %d %d;\n", cifPaintLayerName, size.p_x, size.p_y, center.p_x, center.p_y); } else { fprintf(f, "94 %s %d %d;\n", cifPaintLayerName, center.p_x, center.p_y); } return 0; } /* * ---------------------------------------------------------------------------- * * cifWritePaintFunc -- * * Filter function used to write out a single paint tile. * * Results: * Always return 0 * * Side effects: * Writes to the disk file. * * ---------------------------------------------------------------------------- */ int cifWritePaintFunc( Tile *tile, /* Tile to be written out. */ FILE *f) /* File in which to write. */ { Rect r; /* Output the layer name if it hasn't been done already. */ if (cifPaintLayerName != NULL) { fprintf(f, "L %s;\n", cifPaintLayerName); cifPaintLayerName = NULL; } TiToRect(tile, &r); if (IsSplit(tile)) { Point points[5]; int i, np; GrClipTriangle(&r, NULL, FALSE, TiGetTypeExact(tile), points, &np); /* Write triangle as a CIF polygon */ fprintf(f, " P"); for (i = 0; i < np; i++) { fprintf(f, " %d %d", (2*cifPaintScale*(points[i].p_x))/CIFCurStyle->cs_reducer, (2*cifPaintScale*(points[i].p_y))/CIFCurStyle->cs_reducer); } fprintf(f, ";\n"); } else /* The only tricky thing here is that we MUST scale the rectangle * up by a factor of two to avoid round-off errors in computing * its center point (what a bogosity in CIF!!). This is compensated * by shrinking by a factor of two in the "DS" statement. */ fprintf(f, " B %d %d %d %d;\n", (2*cifPaintScale*(r.r_xtop - r.r_xbot))/CIFCurStyle->cs_reducer, (2*cifPaintScale*(r.r_ytop - r.r_ybot))/CIFCurStyle->cs_reducer, (cifPaintScale*(r.r_xtop + r.r_xbot))/CIFCurStyle->cs_reducer, (cifPaintScale*(r.r_ytop + r.r_ybot))/CIFCurStyle->cs_reducer); CIFRects += 1; return 0; } /* * ---------------------------------------------------------------------------- * * CIFWriteFlat -- * * Write out the entire tree rooted at the supplied CellDef in CIF format, * to the specified file, but write non-hierarchical CIF. * * Results: * TRUE if the cell could be written successfully, FALSE otherwise. * * Side effects: * Writes a file to disk. * In the event of an error while writing out the cell, * the external integer errno is set to the UNIX error * encountered. * * Algorithm: * We operate on the cell in chunks chosen to keep the memory utilization * reasonable. Foreach chunk, we use DBTreeSrTiles and cifHierCopyFunc to * flatten the * chunk into a yank buffer ("eliminating" the subcell problem), then use * cifOut to generate the CIF. * No hierarchical design rule checking or bounding box computation * occur during this operation -- both are explicitly avoided. * * ---------------------------------------------------------------------------- */ bool CIFWriteFlat( CellDef *rootDef, /* Pointer to CellDef to be written */ FILE *f) /* Open output file */ { bool good; int oldCount = DBWFeedbackCount; TileTypeBitMask cifMask; SearchContext scx; cifStack = StackNew(1); CIFInitCells(); UndoDisable(); CIFDummyUse->cu_def = rootDef; /* * Write CIF preamble out first. */ cifOutPreamble(f, rootDef); /* * Now process each chunk. We cheat and use cifOut(), so we need to have * a stack for the single flattened "component" to be on. */ { scx.scx_use = CIFDummyUse; scx.scx_trans = GeoIdentityTransform; GEO_EXPAND(&rootDef->cd_bbox, CIFCurStyle->cs_radius, &scx.scx_area); (void) DBTreeSrTiles(&scx, &DBAllButSpaceAndDRCBits, 0, cifHierCopyFunc, (ClientData) CIFComponentDef); DBReComputeBbox(CIFComponentDef); cifCellNum = (-2); CIFComponentDef->cd_client = (ClientData) -1; StackPush((ClientData) CIFComponentDef, cifStack); cifOut(f); /* cifStack SHould be empty now */ if(!StackEmpty(cifStack)) { TxPrintf("Stack error in CIFWriteInverted()!! " "Your CIF is probably corrupted.\n"); StackFree(cifStack); return FALSE; } DBCellClearDef(CIFComponentDef); } StackFree(cifStack); /* * Now we are almost done. * Just output a call on the root cell */ fprintf(f, "C %d;\nEnd\n", (int) CD2INT(CIFComponentDef->cd_client)); DBCellClearDef(CIFComponentDef); good = !ferror(f); /* Report any errors that occurred. */ if (DBWFeedbackCount != oldCount) { TxPrintf("%d problems occurred. See feedback entries.\n", DBWFeedbackCount-oldCount); } return good; }