/* CIFtech.c - * * This module processes the portions of technology * files pertaining to CIF, and builds the tables * used by the CIF generator. * * ********************************************************************* * * 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/CIFtech.c,v 1.7 2010/10/20 20:34:19 tim Exp $"; #endif /* not lint */ #include #include /* for atof() */ #include #include #include /* for pow() */ #include "utils/magic.h" #include "utils/geometry.h" #include "tiles/tile.h" #include "utils/hash.h" #include "database/database.h" #include "utils/tech.h" #include "utils/utils.h" #include "utils/styles.h" #include "cif/CIFint.h" #include "calma/calmaInt.h" #include "textio/textio.h" #include "utils/malloc.h" #include "cif/cif.h" #include "drc/drc.h" /* For WRL's DRC-CIF extensions */ /* The following statics are used to keep track of things between * calls to CIFTechLine. */ static CIFLayer *cifCurLayer; /* Current layer whose spec. is being read. */ static CIFOp *cifCurOp; /* Last geometric operation read in. */ static bool cifGotLabels; /* TRUE means some labels have been assigned * to the current layer. */ /* The following is a TileTypeBitMask array with only the CIF_SOLIDTYPE * bit set in it. */ TileTypeBitMask CIFSolidBits; /* Forward Declarations */ void cifTechStyleInit(); bool cifCheckCalmaNum(); /* * ---------------------------------------------------------------------------- * * cifTechFreeStyle -- * * This procedure frees memory for the current CIF style, and * sets the current style to NULL. * * Results: * None. * * Side effects: * Memory is free'd. * * ---------------------------------------------------------------------------- */ void cifTechFreeStyle() { int i; CIFOp *op; CIFLayer *layer; if (CIFCurStyle != NULL) { /* Destroy old style structure and free memory allocated to it */ for (i = 0; i < MAXCIFLAYERS; i++) { layer = CIFCurStyle->cs_layers[i]; if (layer != NULL) { for (op = layer->cl_ops; op != NULL; op = op->co_next) { if (op->co_client != (ClientData)NULL) { switch (op->co_opcode) { case CIFOP_OR: case CIFOP_BBOX: case CIFOP_MAXRECT: case CIFOP_BOUNDARY: /* These options use co_client to hold a single */ /* integer value, so it is not allocated. */ break; default: freeMagic((char *)op->co_client); break; } } freeMagic((char *)op); } freeMagic((char *)layer); } } freeMagic(CIFCurStyle); CIFCurStyle = NULL; } } /* * ---------------------------------------------------------------------------- * * cifTechNewStyle -- * * This procedure creates a new CIF style at the end of * the list of style and initializes it to completely * null. * * Results: * None. * * Side effects: * A new element is added to the end of CIFStyleList, and CIFCurStyle * is set to point to it. * * ---------------------------------------------------------------------------- */ void cifTechNewStyle() { cifTechFreeStyle(); cifTechStyleInit(); } /* * ---------------------------------------------------------------------------- * * cifTechStyleInit -- * * Fill in the current cif input style structure with initial values * * ---------------------------------------------------------------------------- */ void cifTechStyleInit() { int i; if (CIFCurStyle == NULL) CIFCurStyle = (CIFStyle *) mallocMagic(sizeof(CIFStyle)); CIFCurStyle->cs_name = NULL; CIFCurStyle->cs_status = TECH_NOT_LOADED; CIFCurStyle->cs_nLayers = 0; CIFCurStyle->cs_scaleFactor = 0; CIFCurStyle->cs_stepSize = 0; CIFCurStyle->cs_gridLimit = 0; CIFCurStyle->cs_reducer = 0; CIFCurStyle->cs_expander = 1; CIFCurStyle->cs_yankLayers = DBZeroTypeBits; CIFCurStyle->cs_hierLayers = DBZeroTypeBits; CIFCurStyle->cs_flags = 0; for (i=0; ics_labelLayer[i] = -1; CIFCurStyle->cs_portLayer[i] = -1; } for (i = 0; i < MAXCIFLAYERS; i++) CIFCurStyle->cs_layers[i] = NULL; } /* * ---------------------------------------------------------------------------- * * cifParseLayers -- * * Takes a comma-separated list of layers and turns it into two * masks, one of paint layers and one of previously-defined CIF * layers. * * Results: * None. * * Side effects: * The masks pointed to by the paintMask and cifMask parameters * are modified. If some of the layers are unknown, then an error * message is printed. * * ---------------------------------------------------------------------------- */ void cifParseLayers(string, style, paintMask, cifMask, spaceOK) char *string; /* List of layers. */ CIFStyle *style; /* Gives CIF style for parsing string.*/ TileTypeBitMask *paintMask; /* Place to store mask of paint layers. If * NULL, then only CIF layer names are * considered. */ TileTypeBitMask *cifMask; /* Place to store mask of CIF layers. If * NULL, then only paint layer names are * considered. */ int spaceOK; /* are space layers permissible in this cif layer? */ { TileTypeBitMask curCifMask, curPaintMask; char curLayer[40], *p, *cp; TileType paintType; int i; bool allResidues; if (paintMask != NULL) TTMaskZero(paintMask); if (cifMask != NULL) TTMaskZero(cifMask); while (*string != 0) { p = curLayer; if (*string == '*') { allResidues = TRUE; string++; } else allResidues = FALSE; while ((*string != ',') && (*string != 0)) *p++ = *string++; *p = 0; while (*string == ',') string += 1; /* See if this is a paint type. */ if (paintMask != NULL) { paintType = DBTechNameTypes(curLayer, &curPaintMask); if (paintType >= 0) goto okpaint; } else paintType = -2; okpaint: /* See if this is the name of another CIF layer. Be * careful not to let the current layer be used in * generating itself. Exact match is requred on CIF * layer names, but the same name can appear multiple * times in different styles. */ TTMaskZero(&curCifMask); if (cifMask != NULL) { for (i = 0; i < style->cs_nLayers; i++) { if (style->cs_layers[i] == cifCurLayer) continue; if (strcmp(curLayer, style->cs_layers[i]->cl_name) == 0) { TTMaskSetType(&curCifMask, i); } } } /* Make sure that there's exactly one match among cif and * paint layers together. */ if ((paintType == -1) || ((paintType >= 0) && !TTMaskEqual(&curCifMask, &DBZeroTypeBits))) { TechError("Ambiguous layer (type) \"%s\".\n", curLayer); continue; } if (paintType >= 0) { if (paintType == TT_SPACE && spaceOK ==0) TechError("\"Space\" layer not permitted in CIF rules.\n"); else { TileType rtype; TileTypeBitMask *rMask; TTMaskSetMask(paintMask, &curPaintMask); /* Add residues from '*' notation */ if (allResidues) for (rtype = TT_TECHDEPBASE; rtype < DBNumUserLayers; rtype++) { rMask = DBResidueMask(rtype); if (TTMaskHasType(rMask, paintType)) TTMaskSetType(paintMask, rtype); } } } else if (!TTMaskEqual(&curCifMask, &DBZeroTypeBits)) { TTMaskSetMask(cifMask, &curCifMask); } else { HashEntry *he; TileTypeBitMask *amask; he = HashLookOnly(&DBTypeAliasTable, curLayer); if (he != NULL) { amask = (TileTypeBitMask *)HashGetValue(he); TTMaskSetMask(paintMask, amask); } else TechError("Unrecognized layer (type) \"%s\".\n", curLayer); } } } /* * ---------------------------------------------------------------------------- * * CIFTechInit -- * * Called before loading a new technology. * * Results: * None. * * Side effects: * Clears out list of styles and resets the current style. * * ---------------------------------------------------------------------------- */ void CIFTechInit() { CIFKeep *style; /* Cleanup any old info. */ cifTechFreeStyle(); /* forget the list of styles */ for (style = CIFStyleList; style != NULL; style = style->cs_next) { freeMagic(style->cs_name); freeMagic(style); } CIFStyleList = NULL; } /* * ---------------------------------------------------------------------------- * * CIFTechStyleInit -- * * Called once at beginning of technology file read-in to * initialize data structures. * * Results: * None. * * Side effects: * Just clears out the layer data structures. * * ---------------------------------------------------------------------------- */ void CIFTechStyleInit() { CalmaTechInit(); /* Create the TileTypeBitMask array with only the CIF_SOLIDTYPE bit set */ TTMaskZero(&CIFSolidBits); TTMaskSetType(&CIFSolidBits, CIF_SOLIDTYPE); cifCurOp = NULL; cifCurLayer = NULL; cifGotLabels = FALSE; } /* * ---------------------------------------------------------------------------- * * CIFTechLimitScale -- * * Determine if the scalefactor (ns / ds), applied to the current * grid scaling, would result in a grid finer than the minimum * resolution allowed by the process, as set by the "gridlimit" * statement in the "cifoutput" section (note that the scaling * depends on the output style chosen, and can be subverted by * scaling while a fine-grid output style is active, then switching * to a coarse-grid output style). * * Note that even if the scalefactor is larger than the minimum * grid, it must be a MULTIPLE of the minimum grid, or else geometry * can be generated off-grid. * * Results: * TRUE if scaling by (ns / ds) would violate minimum grid resolution, * FALSE if not. * * Side effects: * None. * * ---------------------------------------------------------------------------- */ bool CIFTechLimitScale(ns, ds) int ns, ds; { int gridup, scaledown; int scale, limit, expand; if (CIFCurStyle == NULL) return FALSE; scale = CIFCurStyle->cs_scaleFactor; limit = CIFCurStyle->cs_gridLimit; expand = CIFCurStyle->cs_expander; if (limit == 0) limit = 1; gridup = limit * expand * ds; scaledown = scale * ns * 10; if ((scaledown / gridup) == 0) return TRUE; if ((scaledown % gridup) != 0) return TRUE; return FALSE; } /* * ---------------------------------------------------------------------------- * * CIFParseScale -- * * Read a scale value and determine scaleFactor and expander values * * Results: * Returns the value for cs_scaleFactor * * Side effects: * Alters the value of expander (pointer to cs_expander) * * ---------------------------------------------------------------------------- */ int CIFParseScale(true_scale, expander) char *true_scale; int *expander; { char *decimal; short places; int n, d; decimal = strchr(true_scale, '.'); if (decimal == NULL) /* true_scale is integer */ { *expander = 1; return atoi(true_scale); } else { *decimal = '\0'; places = strlen(decimal + 1); d = pow(10,places); n = atoi(true_scale); *decimal = '.'; n *= d; n += atoi(decimal + 1); ReduceFraction(&n, &d); *expander = d; return n; } } /* * ---------------------------------------------------------------------------- * * CIFTechLine -- * * This procedure is called once for each line in the "cif" * section of the technology file. * * Results: * TRUE if line parsed correctly; FALSE if fatal error condition * encountered. * * Side effects: * Sets up information in the tables of CIF layers, and * prints error messages where there are problems. * * ---------------------------------------------------------------------------- */ bool CIFTechLine(sectionName, argc, argv) char *sectionName; /* The name of this section. */ int argc; /* Number of fields on line. */ char *argv[]; /* Values of fields. */ { TileTypeBitMask mask, tempMask, cifMask, bloatLayers; int i, j, l, distance; CIFLayer *newLayer; CIFOp *newOp = NULL; CIFKeep *newStyle, *p; char **bloatArg; BloatData *bloats; BridgeData *bridge; SquaresData *squares; SlotsData *slots; if (argc <= 0) return TRUE; else if (argc >= 2) l = strlen(argv[1]); /* See if we're starting a new CIF style. If not, make * sure that the current (maybe default?) CIF style has * a name. */ if (strcmp(argv[0], "style") == 0) { if (argc != 2) { if ((argc != 4) || (strncmp(argv[2], "variant", 7))) { wrongNumArgs: TechError("Wrong number of arguments in %s statement.\n", argv[0]); errorReturn: if (newOp != NULL) freeMagic((char *) newOp); return TRUE; } } for (newStyle = CIFStyleList; newStyle != NULL; newStyle = newStyle->cs_next) { /* Here we're only establishing existence; */ /* break on the first variant found. */ if (!strncmp(newStyle->cs_name, argv[1], l)) break; } if (newStyle == NULL) { if (argc == 2) { newStyle = (CIFKeep *)mallocMagic(sizeof(CIFKeep)); newStyle->cs_next = NULL; newStyle->cs_name = StrDup((char **) NULL, argv[1]); /* Append to end of style list */ if (CIFStyleList == NULL) CIFStyleList = newStyle; else { for (p = CIFStyleList; p->cs_next; p = p->cs_next); p->cs_next = newStyle; } } else /* Handle style variants */ { CIFKeep *saveStyle = NULL; char *tptr, *cptr; /* 4th argument is a comma-separated list of variants. */ /* In addition to the default name recorded above, */ /* record each of the variants. */ tptr = argv[3]; while (*tptr != '\0') { cptr = strchr(tptr, ','); if (cptr != NULL) *cptr = '\0'; newStyle = (CIFKeep *)mallocMagic(sizeof(CIFKeep)); newStyle->cs_next = NULL; newStyle->cs_name = (char *)mallocMagic(l + strlen(tptr) + 1); sprintf(newStyle->cs_name, "%s%s", argv[1], tptr); /* Remember the first variant as the default */ if (saveStyle == NULL) saveStyle= newStyle; /* Append to end of style list */ if (CIFStyleList == NULL) CIFStyleList = newStyle; else { for (p = CIFStyleList; p->cs_next; p = p->cs_next); p->cs_next = newStyle; } if (cptr == NULL) break; else tptr = cptr + 1; } newStyle = saveStyle; } } if (CIFCurStyle == NULL) { cifTechNewStyle(); CIFCurStyle->cs_name = newStyle->cs_name; CIFCurStyle->cs_status = TECH_PENDING; } else if ((CIFCurStyle->cs_status == TECH_PENDING) || (CIFCurStyle->cs_status == TECH_SUSPENDED)) CIFCurStyle->cs_status = TECH_LOADED; else if (CIFCurStyle->cs_status == TECH_NOT_LOADED) { if (CIFCurStyle->cs_name == NULL) return (FALSE); else if (argc == 2) { if (!strcmp(argv[1], CIFCurStyle->cs_name)) CIFCurStyle->cs_status = TECH_PENDING; } else if (argc == 4) { /* Verify that the style matches one variant */ char *tptr, *cptr; if (!strncmp(CIFCurStyle->cs_name, argv[1], l)) { tptr = argv[3]; while (*tptr != '\0') { cptr = strchr(tptr, ','); if (cptr != NULL) *cptr = '\0'; if (!strcmp(CIFCurStyle->cs_name + l, tptr)) { CIFCurStyle->cs_status = TECH_PENDING; return TRUE; } if (cptr == NULL) return TRUE; else tptr = cptr + 1; } } } } return (TRUE); } /* Only continue past this point if we are loading the cif output style */ if (CIFCurStyle == NULL) return FALSE; if ((CIFCurStyle->cs_status != TECH_PENDING) && (CIFCurStyle->cs_status != TECH_SUSPENDED)) return TRUE; /* Process scalefactor lines next. */ if (strcmp(argv[0], "scalefactor") == 0) { if ((argc < 2) || (argc > 4)) goto wrongNumArgs; CIFCurStyle->cs_scaleFactor = CIFParseScale(argv[1], &CIFCurStyle->cs_expander); /* * The "nanometers" keyword multiplies the expander by 10. * Any reducer value and keyword "calmaonly" are now both ignored. */ if (argc >= 3) { if (strncmp(argv[argc - 1], "nanom", 5) == 0) CIFCurStyle->cs_expander *= 10; else if (strncmp(argv[argc - 1], "angstr", 6) == 0) CIFCurStyle->cs_expander *= 100; } CIFCurStyle->cs_reducer = 1; /* initial value only */ if (CIFCurStyle->cs_scaleFactor <= 0) { CIFCurStyle->cs_scaleFactor = 0; TechError("Scalefactor must be a strictly positive value.\n"); goto errorReturn; } return TRUE; } /* New for magic-7.3.100---allow GDS database units to be other */ /* than nanometers. Really, there is only one option here, which */ /* is "units angstroms". This option does not affect CIF output, */ /* whose units are fixed at centimicrons. */ if (strcmp(argv[0], "units") == 0) { if (argc != 2) goto wrongNumArgs; if (!strncmp(argv[1], "angstr", 6)) CIFCurStyle->cs_flags |= CWF_ANGSTROMS; return TRUE; } if (strcmp(argv[0], "stepsize") == 0) { if (argc != 2) goto wrongNumArgs; CIFCurStyle->cs_stepSize = atoi(argv[1]); if (CIFCurStyle->cs_stepSize <= 0) { TechError("Step size must be positive integer.\n"); CIFCurStyle->cs_stepSize = 0; } return TRUE; } /* Process "gridlimit" line next. */ if (strncmp(argv[0], "grid", 4) == 0) { if (StrIsInt(argv[1])) { CIFCurStyle->cs_gridLimit = atoi(argv[1]); if (CIFCurStyle->cs_gridLimit < 0) { TechError("Grid limit must be a positive integer.\n"); CIFCurStyle->cs_gridLimit = 0; } } else TechError("Unable to parse grid limit value.\n"); return TRUE; } /* Process "variant" lines next. */ if (strncmp(argv[0], "variant", 7) == 0) { int l; char *cptr, *tptr; /* If our style variant is not one of the ones declared */ /* on the line, then we ignore all input until we */ /* either reach the end of the style, the end of the */ /* section, or another "variant" line. */ if (argc != 2) goto wrongNumArgs; tptr = argv[1]; while (*tptr != '\0') { cptr = strchr(tptr, ','); if (cptr != NULL) { *cptr = '\0'; for (j = 1; isspace(*(cptr - j)); j++) *(cptr - j) = '\0'; } if (*tptr == '*') { CIFCurStyle->cs_status = TECH_PENDING; return TRUE; } else { l = strlen(CIFCurStyle->cs_name) - strlen(tptr); if (!strcmp(tptr, CIFCurStyle->cs_name + l)) { CIFCurStyle->cs_status = TECH_PENDING; return TRUE; } } if (cptr == NULL) break; else tptr = cptr + 1; } CIFCurStyle->cs_status = TECH_SUSPENDED; } /* Anything below this line is not parsed if we're in TECH_SUSPENDED mode */ if (CIFCurStyle->cs_status != TECH_PENDING) return TRUE; newLayer = NULL; if ((strcmp(argv[0], "templayer") == 0) || (strcmp(argv[0], "layer") == 0) || (strcmp(argv[0], "labellayer") == 0)) { if (CIFCurStyle->cs_nLayers == MAXCIFLAYERS) { cifCurLayer = NULL; TechError("Can't handle more than %d CIF layers.\n", MAXCIFLAYERS); TechError("Your local Magic wizard can fix this.\n"); goto errorReturn; } if (argc != 2 && argc != 3) { cifCurLayer = NULL; goto wrongNumArgs; } newLayer = CIFCurStyle->cs_layers[CIFCurStyle->cs_nLayers] = (CIFLayer *) mallocMagic(sizeof(CIFLayer)); CIFCurStyle->cs_nLayers += 1; if ((cifCurOp == NULL) && (cifCurLayer != NULL) && !cifGotLabels) { TechError("Layer \"%s\" contains no material.\n", cifCurLayer->cl_name); } newLayer->cl_name = NULL; (void) StrDup(&newLayer->cl_name, argv[1]); newLayer->cl_ops = NULL; newLayer->cl_flags = 0; newLayer->cl_calmanum = newLayer->cl_calmatype = -1; newLayer->min_width = 0; /* for growSlivers */ #ifdef THREE_D newLayer->cl_height = 0.0; newLayer->cl_thick = 0.0; newLayer->cl_renderStyle = STYLE_PALEHIGHLIGHTS - TECHBEGINSTYLES; #endif if (strcmp(argv[0], "templayer") == 0) newLayer->cl_flags |= CIF_TEMP; else if (strcmp(argv[0], "labellayer") == 0) newLayer->cl_flags |= CIF_LABEL; cifCurLayer = newLayer; cifCurOp = NULL; cifGotLabels = FALSE; /* Handle a special case of a list of layer names on the layer * line. Turn them into an OR operation. */ if (argc == 3) { cifCurOp = (CIFOp *) mallocMagic(sizeof(CIFOp)); cifCurOp->co_opcode = CIFOP_OR; cifParseLayers(argv[2], CIFCurStyle, &cifCurOp->co_paintMask, &cifCurOp->co_cifMask, FALSE); cifCurOp->co_distance = 0; cifCurOp->co_next = NULL; cifCurOp->co_client = (ClientData)NULL; cifCurLayer->cl_ops = cifCurOp; } return TRUE; } if (strcmp(argv[0], "labels") == 0) { bool portOnly = FALSE, noPort = FALSE; if (cifCurLayer == NULL) { TechError("Must define layer before giving labels it holds.\n"); goto errorReturn; } if (cifCurLayer->cl_flags & CIF_TEMP) TechError("Why are you attaching labels to a temporary layer?\n"); if (argc == 3) { if (!strncmp(argv[2], "port", 4)) portOnly = TRUE; else if (!strncmp(argv[2], "noport", 6)) noPort = TRUE; else { TechError("Unknown option %s for labels statement.\n", argv[2]); goto wrongNumArgs; } } else if (argc != 2) goto wrongNumArgs; DBTechNoisyNameMask(argv[1], &mask); for (i=0; ics_labelLayer[i] = CIFCurStyle->cs_nLayers-1; if (noPort != TRUE) CIFCurStyle->cs_portLayer[i] = CIFCurStyle->cs_nLayers-1; } } cifGotLabels = TRUE; return TRUE; } if ((strcmp(argv[0], "calma") == 0) || (strncmp(argv[0], "gds", 3) == 0)) { if (cifCurLayer == NULL) { TechError("Must define layers before giving their Calma types.\n"); goto errorReturn; } if (cifCurLayer->cl_flags & CIF_TEMP) TechError("Why assign a Calma number to a temporary layer?\n"); if (argc != 3) goto wrongNumArgs; if (!cifCheckCalmaNum(argv[1]) || !cifCheckCalmaNum(argv[2])) TechError("Calma layer and type numbers must be 0 to %d.\n", CALMA_LAYER_MAX); cifCurLayer->cl_calmanum = atoi(argv[1]); cifCurLayer->cl_calmatype = atoi(argv[2]); return TRUE; } if (strcmp(argv[0], "min-width") == 0) /* used in growSliver */ { if (cifCurLayer == NULL) { TechError("Must define layers before assigning a minimum width.\n"); goto errorReturn; } if (argc != 2) goto wrongNumArgs; cifCurLayer->min_width = atoi(argv[1]); CIFCurStyle->cs_flags |= CWF_GROW_SLIVERS; return TRUE; } if (strcmp(argv[0], "render") == 0) /* used by specialopen wind3d client */ { #ifdef THREE_D float height, thick; int i, style, lcnt; CIFLayer *layer; if (argc != 5) goto wrongNumArgs; cifCurLayer = NULL; /* This is not in a layer definition */ style = DBWTechParseStyle(argv[2]); if (style < 0) { TechError("Error: Bad render style for CIF layer.\n"); goto errorReturn; } if (!StrIsNumeric(argv[3]) || !StrIsNumeric(argv[4])) { TechError("Syntax: render