/* CIFreadtech.c - * * This module processes the portions of technology files that * pertain to reading CIF files, and builds the tables used by * the CIF-reading code. * * ********************************************************************* * * 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/CIFrdtech.c,v 1.4 2010/09/15 15:45:30 tim Exp $"; #endif /* not lint */ #include #include #include #include #include "tcltk/tclmagic.h" #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 "textio/textio.h" #include "utils/utils.h" #include "cif/CIFint.h" #include "cif/CIFread.h" #include "calma/calmaInt.h" #include "utils/malloc.h" /* C99 compat */ #include "cif/cif.h" /* Pointer to a list of all the CIF-reading styles: */ CIFReadKeep *cifReadStyleList = NULL; /* Names of all the CIF layer types used by any read style: */ int cifNReadLayers = 0; char *(cifReadLayers[MAXCIFRLAYERS]); /* Table mapping from Calma layer numbers to CIF layers */ HashTable cifCalmaToCif; /* Variables used to keep track of progress in reading the tech file: */ CIFReadStyle *cifCurReadStyle = NULL; /* Current style being read. */ CIFReadLayer *cifCurReadLayer; /* Current layer being processed. */ CIFOp *cifCurReadOp; /* Last geometric operation seen. */ /* Forward declarations */ void cifReadStyleInit(void); void CIFReadLoadStyle(char *stylename); /* * ---------------------------------------------------------------------------- * * CIFReadTechLimitScale -- * * 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 "cifinput" section. * * 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 CIFReadTechLimitScale( int ns, int ds) { int gridup, scaledown; int scale, limit, mult; limit = cifCurReadStyle->crs_gridLimit; if (limit == 0) return FALSE; /* No limit */ scale = cifCurReadStyle->crs_scaleFactor; mult = cifCurReadStyle->crs_multiplier; gridup = limit * mult * ds; scaledown = scale * ns * 10; if ((scaledown / gridup) == 0) return TRUE; if ((scaledown % gridup) != 0) return TRUE; return FALSE; } /* * ---------------------------------------------------------------------------- * * CIFReadNameToType -- * * This procedure finds the type (integer index) of a given * layer name. * * Results: * The return value is the type. If we ran out of space in * the CIF layer table, or if the layer wasn't recognized and * it isn't OK to make a new layer, -1 gets returned. * * Side effects: * If no layer exists by the given name and newOK is TRUE, a * new layer is created. * * ---------------------------------------------------------------------------- */ int CIFReadNameToType( char *name, /* Name of a CIF layer. */ bool newOK) /* TRUE means OK to create a new layer if this * name is one we haven't seen before. */ { int i; static bool errorPrinted = FALSE; for (i=0; i < cifNReadLayers; i += 1) { /* Only accept this layer if it's in the current CIF style or * it's OK to add new layers to the current style. */ if (!TTMaskHasType(&cifCurReadStyle->crs_cifLayers, i) && !newOK) continue; if (strcmp(cifReadLayers[i], name) == 0) { if (newOK) TTMaskSetType(&cifCurReadStyle->crs_cifLayers, i); return i; } } /* This name isn't in the table. Return an error or make a new entry. */ if (!newOK) return -1; if (cifNReadLayers == MAXCIFRLAYERS) { if (!errorPrinted) { TxError("CIF read layer table ran out of space at %d layers.\n", MAXCIFRLAYERS); TxError("Get your Magic maintainer to increase the table size.\n"); errorPrinted = TRUE; } return -1; } (void) StrDup(&(cifReadLayers[cifNReadLayers]), name); TTMaskSetType(&cifCurReadStyle->crs_cifLayers, cifNReadLayers); cifNReadLayers += 1; return cifNReadLayers-1; } /* * ---------------------------------------------------------------------------- * * CIFCalmaLayerToCifLayer -- * * Find the CIF number of the layer matching the supplied Calma * layer number and datatype. * * Results: * Returns the CIF number of the above layer, or -1 if it * can't be found. * * Side effects: * None. * * ---------------------------------------------------------------------------- */ int CIFCalmaLayerToCifLayer( int layer, /* Calma layer number */ int datatype, /* Calma datatype */ CIFReadStyle *calmaStyle) { CalmaLayerType clt; HashEntry *he; clt.clt_layer = layer; clt.clt_type = datatype; if ((he = HashLookOnly(&(calmaStyle->cifCalmaToCif), (char *) &clt))) return ((spointertype) HashGetValue(he)); /* Try wildcarding the datatype */ clt.clt_type = -1; if ((he = HashLookOnly(&(calmaStyle->cifCalmaToCif), (char *) &clt))) return ((spointertype) HashGetValue(he)); /* Try wildcarding the layer */ clt.clt_layer = -1; clt.clt_type = datatype; if ((he = HashLookOnly(&(calmaStyle->cifCalmaToCif), (char *) &clt))) return ((spointertype) HashGetValue(he)); /* Try wildcarding them both, for a default value */ clt.clt_layer = -1; clt.clt_type = -1; if ((he = HashLookOnly(&(calmaStyle->cifCalmaToCif), (char *) &clt))) return ((spointertype) HashGetValue(he)); /* No luck */ return (-1); } /* * ---------------------------------------------------------------------------- * * CIFParseReadLayers -- * * Given a comma-separated list of CIF layer names, builds a * bit mask of all those layer names. * * Results: * None. * * Side effects: * Modifies the parameter pointed to by mask so that it contains * a mask of all the CIF layers indicated. If any of the CIF * layers didn't exist, new ones are created. If we run out * of CIF layers, an error message is output. * * ---------------------------------------------------------------------------- */ void CIFParseReadLayers( char *string, /* Comma-separated list of CIF layers. */ TileTypeBitMask *mask, /* Where to store bit mask. */ bool newok) /* If TRUE, create new layers if they don't exist */ { int i; char *p; TTMaskZero(mask); /* Break the string up into the chunks between commas. */ while (*string != 0) { p = strchr(string, ','); if (p != NULL) *p = 0; i = CIFReadNameToType(string, newok); if (i >= 0) TTMaskSetType(mask, i); else if (newok) { HashEntry *he; TileTypeBitMask *amask; he = HashLookOnly(&DBTypeAliasTable, string); if (he != NULL) { amask = (TileTypeBitMask *)HashGetValue(he); TTMaskSetMask(mask, amask); } } else TxError("Error: CIF layer \"%s\" is unknown.\n", string); if (p == NULL) break; *p = ','; for (string = p; *string == ','; string += 1) /* do nothing */; } } /* * ---------------------------------------------------------------------------- * * cifNewReadStyle -- * * This procedure creates a new CIF read style * and initializes it to completely null. cifCurReadStyle is * set to point to the new structure. * * Results: * None. * * Side effects: * Any information previously in cifCurReadStyle is destroyed and * the memory allocation freed. * * ---------------------------------------------------------------------------- */ void cifNewReadStyle(void) { int i; CIFOp *op; CIFReadLayer *layer; if (cifCurReadStyle != NULL) { /* Destroy old style and free all memory allocated to it */ for (i=0; icrs_layers[i]; if (layer != NULL) { for (op = layer->crl_ops; op != NULL; op = op->co_next) freeMagic((char *)op); freeMagic((char *)layer); } } /* Destroy the calma mapping HashTable */ HashKill(&(cifCurReadStyle->cifCalmaToCif)); freeMagic((char *)cifCurReadStyle); } cifCurReadStyle = (CIFReadStyle *) mallocMagic(sizeof(CIFReadStyle)); cifReadStyleInit(); } /* * ---------------------------------------------------------------------------- * * cifReadStyleInit -- * * Fill in the current cif input style structure with initial values * * ---------------------------------------------------------------------------- */ void cifReadStyleInit(void) { int i; cifCurReadStyle->crs_name = NULL; cifCurReadStyle->crs_status = TECH_NOT_LOADED; cifCurReadStyle->crs_cifLayers = DBZeroTypeBits; cifCurReadStyle->crs_nLayers = 0; cifCurReadStyle->crs_scaleFactor = 0; cifCurReadStyle->crs_multiplier = 1; cifCurReadStyle->crs_gridLimit = 0; cifCurReadStyle->crs_flags = 0; HashInit(&(cifCurReadStyle->cifCalmaToCif), 64, sizeof (CalmaLayerType) / sizeof (unsigned)); for (i = 0; i < MAXCIFRLAYERS; i++) { cifCurReadStyle->crs_labelLayer[i] = TT_SPACE; cifCurReadStyle->crs_labelSticky[i] = LABEL_TYPE_NONE; cifCurReadStyle->crs_layers[i] = NULL; } } /* * * ---------------------------------------------------------------------------- * * CIFReadTechInit -- * * Called to delete all structures associated with the CIF istyle * tech prior to reading a new technology. * * Results: * None. * * Side effects: * Clears out the layer data structure. * * ---------------------------------------------------------------------------- */ void CIFReadTechInit(void) { CIFReadKeep *style; /* Cleanup any old info. */ cifNewReadStyle(); freeMagic(cifCurReadStyle); cifCurReadStyle = NULL; /* forget the list of styles */ for (style = cifReadStyleList; style != NULL; style = style->crs_next) { freeMagic(style->crs_name); freeMagic(style); } cifReadStyleList = NULL; } /* * ---------------------------------------------------------------------------- * * CIFReadTechStyleInit -- * * Called once at the beginning of technology file read-in to * initialize data structures. * * Results: * None. * * Side effects: * Clears out the layer data structure. * * ---------------------------------------------------------------------------- */ void CIFReadTechStyleInit(void) { cifNReadLayers = 0; cifCurReadLayer = NULL; cifCurReadOp = NULL; } /* * ---------------------------------------------------------------------------- * * CIFReadTechLine -- * * This procedure is called once by the tech module for each line * in the "cifinput" section of the technology file. * * Results: * Always return TRUE. * * Side effects: * Sets up information in the tables used to read CIF, and prints * error messages if problems arise. * * ---------------------------------------------------------------------------- */ /* ARGSUSED */ bool CIFReadTechLine( char *sectionName, /* Name of this section ("cifinput"). */ int argc, /* Number of fields on line. */ char *argv[]) /* Values of fields. */ { CIFOp *newOp = NULL; CIFReadKeep *newStyle, *p; HashEntry *he; CalmaLayerType clt; int calmaLayers[CALMA_LAYER_MAX], calmaTypes[CALMA_LAYER_MAX]; int nCalmaLayers, nCalmaTypes, l, t, j; int calmaLabelType = LABEL_TYPE_NONE; if (argc <= 0) return TRUE; else if (argc >= 2) l = strlen(argv[1]); /* See if we're starting a new style. If so, create it. If not, * make sure there's already a style around, and create one if * there isn't. */ 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 = cifReadStyleList; newStyle != NULL; newStyle = newStyle->crs_next) { if (!strncmp(newStyle->crs_name, argv[1], l)) break; } if (newStyle == NULL) { if (argc == 2) { newStyle = (CIFReadKeep *)mallocMagic(sizeof(CIFReadKeep)); newStyle->crs_next = NULL; newStyle->crs_name = StrDup((char **) NULL, argv[1]); /* Append to end of style list */ if (cifReadStyleList == NULL) cifReadStyleList = newStyle; else { for (p = cifReadStyleList; p->crs_next; p = p->crs_next); p->crs_next = newStyle; } } else /* Handle style variants */ { CIFReadKeep *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 = (CIFReadKeep *)mallocMagic(sizeof(CIFReadKeep)); newStyle->crs_next = NULL; newStyle->crs_name = (char *)mallocMagic(strlen(argv[1]) + strlen(tptr) + 1); sprintf(newStyle->crs_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 (cifReadStyleList == NULL) cifReadStyleList = newStyle; else { for (p = cifReadStyleList; p->crs_next; p = p->crs_next); p->crs_next = newStyle; } if (cptr == NULL) break; else tptr = cptr + 1; } newStyle = saveStyle; } } if (cifCurReadStyle == NULL) { cifNewReadStyle(); cifCurReadStyle->crs_name = newStyle->crs_name; cifCurReadStyle->crs_status = TECH_PENDING; } else if ((cifCurReadStyle->crs_status == TECH_PENDING) || (cifCurReadStyle->crs_status == TECH_SUSPENDED)) cifCurReadStyle->crs_status = TECH_LOADED; else if (cifCurReadStyle->crs_status == TECH_NOT_LOADED) { if (cifCurReadStyle->crs_name == NULL) return (FALSE); else if (argc == 2) { if (!strcmp(argv[1], cifCurReadStyle->crs_name)) cifCurReadStyle->crs_status = TECH_PENDING; } else if (argc == 4) { /* Verify that the style matches one variant */ char *tptr, *cptr; if (!strncmp(cifCurReadStyle->crs_name, argv[1], l)) { tptr = argv[3]; while (*tptr != '\0') { cptr = strchr(tptr, ','); if (cptr != NULL) *cptr = '\0'; if (!strcmp(cifCurReadStyle->crs_name + l, tptr)) { cifCurReadStyle->crs_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 input style */ if (cifCurReadStyle == NULL) return FALSE; if ((cifCurReadStyle->crs_status != TECH_PENDING) && (cifCurReadStyle->crs_status != TECH_SUSPENDED)) return TRUE; /* Process scalefactor lines next. */ if (strcmp(argv[0], "scalefactor") == 0) { if ((argc < 2) || (argc > 4)) goto wrongNumArgs; cifCurReadStyle->crs_scaleFactor = CIFParseScale(argv[1], &cifCurReadStyle->crs_multiplier); /* * The "nanometers" keyword multiplies the multiplier by 10. * Keyword "calmaonly" is now ignored. */ if (argc >= 3) { if (!strncmp(argv[argc - 1], "nanom", 5)) cifCurReadStyle->crs_multiplier = 10; else if (!strncmp(argv[argc - 1], "angstr", 6)) cifCurReadStyle->crs_multiplier = 100; } if (cifCurReadStyle->crs_scaleFactor <= 0) { cifCurReadStyle->crs_scaleFactor = 0; TechError("Scalefactor must be a strictly positive value.\n"); goto errorReturn; } return TRUE; } /* Process "gridlimit" lines. */ if (strncmp(argv[0], "grid", 4) == 0) { if (StrIsInt(argv[1])) { cifCurReadStyle->crs_gridLimit = atoi(argv[1]); if (cifCurReadStyle->crs_gridLimit < 0) { TechError("Grid limit must be a positive integer.\n"); cifCurReadStyle->crs_gridLimit = 0; } } else { TechError("Unable to parse grid limit value.\n"); goto errorReturn; } 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 == '*') { cifCurReadStyle->crs_status = TECH_PENDING; return TRUE; } else { l = strlen(cifCurReadStyle->crs_name) - strlen(tptr); if (!strcmp(tptr, cifCurReadStyle->crs_name + l)) { cifCurReadStyle->crs_status = TECH_PENDING; return TRUE; } } if (cptr == NULL) break; else tptr = cptr + 1; } cifCurReadStyle->crs_status = TECH_SUSPENDED; } /* Anything below this line is not parsed if we're in TECH_SUSPENDED mode */ if (cifCurReadStyle->crs_status != TECH_PENDING) return TRUE; /* Process layer lines next. */ if (strcmp(argv[0], "layer") == 0) { TileType type; cifCurReadLayer = NULL; cifCurReadOp = NULL; if (cifCurReadStyle->crs_nLayers == MAXCIFRLAYERS) { TechError("Can't handle more than %d layers per style.\n", MAXCIFRLAYERS); TechError("Your local Magic wizard can increase the table size.\n"); goto errorReturn; } if ((argc != 2) && (argc != 3)) goto wrongNumArgs; type = DBTechNoisyNameType(argv[1]); if (type < 0) goto errorReturn; cifCurReadLayer = (CIFReadLayer *) mallocMagic(sizeof(CIFReadLayer)); cifCurReadStyle->crs_layers[cifCurReadStyle->crs_nLayers] = cifCurReadLayer; cifCurReadStyle->crs_nLayers += 1; cifCurReadLayer->crl_magicType = type; cifCurReadLayer->crl_ops = NULL; cifCurReadLayer->crl_flags = CIFR_SIMPLE; /* Handle a special case of a list of layer names on the * layer line. Turn them into an OR operation. */ if (argc == 3) { cifCurReadOp = (CIFOp *) mallocMagic(sizeof(CIFOp)); cifCurReadOp->co_opcode = CIFOP_OR; cifCurReadOp->co_client = (ClientData)NULL; CIFParseReadLayers(argv[2], &cifCurReadOp->co_cifMask, TRUE); TTMaskZero(&cifCurReadOp->co_paintMask); cifCurReadOp->co_next = NULL; cifCurReadOp->co_distance = 0; cifCurReadLayer->crl_ops = cifCurReadOp; } return TRUE; } /* Process templayer lines next. (templayers in cifinput added 5/3/09) */ /* Fault handling deprecated 5/5/16; treat as templayer and flag a */ /* warning. */ if ((strcmp(argv[0], "templayer") == 0) || (strcmp(argv[0], "fault") == 0)) { TileType type; cifCurReadLayer = NULL; cifCurReadOp = NULL; if (cifCurReadStyle->crs_nLayers == MAXCIFRLAYERS) { TechError("Can't handle more than %d layers per style.\n", MAXCIFRLAYERS); TechError("Your local Magic wizard can increase the table size.\n"); goto errorReturn; } if ((argc != 2) && (argc != 3)) goto wrongNumArgs; type = CIFReadNameToType(argv[1], TRUE); if (type < 0) goto errorReturn; if (*argv[0] == 'f') TechError("Error: Fault layers deprecated. Treating as templayer\n"); cifCurReadLayer = (CIFReadLayer *) mallocMagic(sizeof(CIFReadLayer)); cifCurReadStyle->crs_layers[cifCurReadStyle->crs_nLayers] = cifCurReadLayer; cifCurReadStyle->crs_nLayers += 1; cifCurReadLayer->crl_magicType = type; cifCurReadLayer->crl_ops = NULL; cifCurReadLayer->crl_flags = CIFR_TEMPLAYER | CIFR_SIMPLE; /* Handle a special case of a list of layer names on the * layer line. Turn them into an OR operation. */ if (argc == 3) { cifCurReadOp = (CIFOp *) mallocMagic(sizeof(CIFOp)); cifCurReadOp->co_opcode = CIFOP_OR; cifCurReadOp->co_client = (ClientData)NULL; CIFParseReadLayers(argv[2], &cifCurReadOp->co_cifMask, TRUE); TTMaskZero(&cifCurReadOp->co_paintMask); cifCurReadOp->co_next = NULL; cifCurReadOp->co_distance = 0; cifCurReadLayer->crl_ops = cifCurReadOp; } return TRUE; } /* Process mapping between CIF layers and calma layers/types */ if ((strcmp(argv[0], "calma") == 0) || (strncmp(argv[0], "gds", 3) == 0)) { int cifnum; if (argc != 4) goto wrongNumArgs; cifnum = CIFReadNameToType(argv[1], FALSE); if (cifnum < 0) { TechError("Unrecognized CIF layer: \"%s\"\n", argv[1]); return TRUE; } nCalmaLayers = cifParseCalmaNums(argv[2], calmaLayers, CALMA_LAYER_MAX); nCalmaTypes = cifParseCalmaNums(argv[3], calmaTypes, CALMA_LAYER_MAX); if (nCalmaLayers <= 0 || nCalmaTypes <= 0) return (TRUE); for (l = 0; l < nCalmaLayers; l++) { for (t = 0; t < nCalmaTypes; t++) { clt.clt_layer = calmaLayers[l]; clt.clt_type = calmaTypes[t]; he = HashFind(&(cifCurReadStyle->cifCalmaToCif), (char *) &clt); HashSetValue(he, (ClientData)(pointertype) cifnum); } } return TRUE; } /* Figure out which Magic layer should get labels from which * CIF layers. */ if (strcmp(argv[0], "labels") == 0) { TileTypeBitMask mask; int i; if (cifCurReadLayer == NULL) { TechError("Must define layer before giving labels it holds.\n"); goto errorReturn; } if (argc != 2) { if (argc == 3) { if (!strcmp(argv[2], "text")) calmaLabelType = LABEL_TYPE_TEXT; else if (!strcmp(argv[2], "sticky")) calmaLabelType = LABEL_TYPE_TEXT; else if (!strcmp(argv[2], "port")) calmaLabelType = LABEL_TYPE_PORT; else if (!strncmp(argv[2], "cell", 4)) calmaLabelType = LABEL_TYPE_CELLID; else goto wrongNumArgs; } else goto wrongNumArgs; } CIFParseReadLayers(argv[1], &mask, TRUE); for (i = 0; i < MAXCIFRLAYERS; i++) { if (TTMaskHasType(&mask, i)) { /* Only one magic type can be assigned to a GDS layer, so * multiple assignments should be flagged as errors. BUT, * this is a common historic error. Since reattachments * should be handled rationally (by code added 10/17/2023 * to DBlabel.c), there is no urgent need to flag an issue * unless the new layer does not exist on the same plane * as the old one. */ if (cifCurReadStyle->crs_labelLayer[i] != TT_SPACE) { int p1, p2; p1 = DBPlane(cifCurReadLayer->crl_magicType); p2 = DBPlane(cifCurReadStyle->crs_labelLayer[i]); if (!DBTypeOnPlane(cifCurReadLayer->crl_magicType, p2) && !DBTypeOnPlane(cifCurReadStyle->crs_labelLayer[i], p1)) TechError("Labels on layer \"%s\" attached to \"%s\" " "supersedes prior attachment to \"%s\".\n", cifReadLayers[i], DBTypeLongNameTbl[cifCurReadLayer->crl_magicType], DBTypeLongNameTbl[cifCurReadStyle->crs_labelLayer[i]]); } cifCurReadStyle->crs_labelLayer[i] = cifCurReadLayer->crl_magicType; if (argc == 3) cifCurReadStyle->crs_labelSticky[i] = calmaLabelType; } } return TRUE; } /* Parse "ignore" lines: look up the layers to enter them in * the table of known layers, but don't do anything else. This * will cause the layers to be ignored when encountered in * cells. */ if (strcmp(argv[0], "ignore") == 0) { TileTypeBitMask mask; int i; if (argc != 2) goto wrongNumArgs; CIFParseReadLayers(argv[1], &mask, TRUE); /* trash the value in crs_labelLayer so that any labels on this * layer get junked, also. dcs 4/11/90 */ for (i=0; i < cifNReadLayers; i++) { if (TTMaskHasType(&mask,i)) { if (cifCurReadStyle->crs_labelLayer[i] == TT_SPACE) { cifCurReadStyle->crs_labelLayer[i] = -1; } } } return TRUE; } /* miscellaneous cif-reading boolean options */ if (strcmp(argv[0], "options") == 0) { int i; if (argc < 2) goto wrongNumArgs; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "ignore-unknown-layer-labels") == 0) cifCurReadStyle->crs_flags |= CRF_IGNORE_UNKNOWNLAYER_LABELS; /* Allow "no-reconnect-labels", although it has been deprecated */ else if (strcmp(argv[i], "no-reconnect-labels") != 0) TechError("Unknown cifinput option \"%s\".\n", argv[i]); } return TRUE; } /* Anything below here is a geometric operation, so we can * do some set-up that is common to all the operations. */ if (cifCurReadLayer == NULL) { TechError("Must define layer before specifying operations.\n"); goto errorReturn; } newOp = (CIFOp *) mallocMagic(sizeof(CIFOp)); TTMaskZero(&newOp->co_paintMask); TTMaskZero(&newOp->co_cifMask); newOp->co_opcode = 0; newOp->co_distance = 0; newOp->co_next = NULL; newOp->co_client = (ClientData)NULL; if (strcmp(argv[0], "and") == 0) newOp->co_opcode = CIFOP_AND; else if (strcmp(argv[0], "and-not") == 0) newOp->co_opcode = CIFOP_ANDNOT; else if (strcmp(argv[0], "or") == 0) newOp->co_opcode = CIFOP_OR; else if (strcmp(argv[0], "grow") == 0) newOp->co_opcode = CIFOP_GROW; else if (strcmp(argv[0], "grow-grid") == 0) newOp->co_opcode = CIFOP_GROW_G; else if (strcmp(argv[0], "shrink") == 0) newOp->co_opcode = CIFOP_SHRINK; else if (strcmp(argv[0], "copyup") == 0) newOp->co_opcode = CIFOP_COPYUP; else if (strcmp(argv[0], "boundary") == 0) newOp->co_opcode = CIFOP_BOUNDARY; else { TechError("Unknown statement \"%s\".\n", argv[0]); goto errorReturn; } switch (newOp->co_opcode) { case CIFOP_AND: case CIFOP_ANDNOT: case CIFOP_OR: case CIFOP_COPYUP: if (argc != 2) goto wrongNumArgs; CIFParseReadLayers(argv[1], &newOp->co_cifMask, TRUE); break; case CIFOP_GROW: case CIFOP_GROW_G: case CIFOP_SHRINK: if (argc != 2) goto wrongNumArgs; newOp->co_distance = atoi(argv[1]); if (newOp->co_distance <= 0) { TechError("Grow/shrink distance must be greater than zero.\n"); goto errorReturn; } break; } /* Link the new CIFOp onto the list. */ if (cifCurReadOp == NULL) { cifCurReadLayer->crl_ops = newOp; if (newOp->co_opcode != CIFOP_OR) cifCurReadLayer->crl_flags &= ~CIFR_SIMPLE; } else { cifCurReadOp->co_next = newOp; cifCurReadLayer->crl_flags &= ~CIFR_SIMPLE; } cifCurReadOp = newOp; return TRUE; } /* * ---------------------------------------------------------------------------- * * CIFReadTechFinal -- * * This procedure is invoked after all the lines of a technology * file have been read. It checks to make sure that the information * read in "cifinput" sections is reasonably complete. * * Results: * None. * * Side effects: * Error messages may be output. * * ---------------------------------------------------------------------------- */ void CIFReadTechFinal(void) { /* Reduce the scale by the multiplier, as much as possible while */ /* keeping all CIF input ops in integer units. */ /* Calling with scale 1:1 does no actual scaling, but does find any */ /* common factors which can be divided out and reassigned to the */ /* cif input multiplier factor. */ if (cifCurReadStyle == NULL) return; /* Make sure the current style has a valid scalefactor. */ if (cifCurReadStyle->crs_scaleFactor <= 0) { TechError("CIF input style \"%s\" bad scalefactor; using 1.\n", cifCurReadStyle->crs_name); cifCurReadStyle->crs_scaleFactor = 1; } CIFTechInputScale(1, 1, TRUE); /* debug info --- Tim, 1/3/02 */ TxPrintf("Input style %s: scaleFactor=%d, multiplier=%d\n", cifCurReadStyle->crs_name, cifCurReadStyle->crs_scaleFactor, cifCurReadStyle->crs_multiplier); } /* * ---------------------------------------------------------------------------- * * CIFReadLoadStyle -- * * Re-read the technology file to load the specified technology cif input * style into structure cifCurReadStyle. This is much more memory-efficient than * keeping a separate structure for each cif input style. It incurs a complete * reading of the tech file on startup and every time the cif input style is * changed, but we can assume that this does not happen often. The first * style in the technology file is assumed to be default, so that re-reading * the tech file is not necessary on startup unless the default cif input * style is changed by a call to "cif istyle". * * ---------------------------------------------------------------------------- */ void CIFReadLoadStyle( char *stylename) { SectionID invcifr; if (cifCurReadStyle->crs_name == stylename) return; cifNewReadStyle(); cifCurReadStyle->crs_name = stylename; invcifr = TechSectionGetMask("cifinput", NULL); TechLoad(NULL, invcifr); /* CIFReadTechFinal(); */ /* Taken care of by TechLoad() */ CIFTechInputScale(DBLambda[0], DBLambda[1], TRUE); } /* * ---------------------------------------------------------------------------- * * CIFReadGetGrowSize -- * * Parse the rules for the given CIF/GDS layer "type" and return the * amount that it needs to be grown to create the magic contact layer * type. This assumes that the input manipulations are straightforward. * It is expected that any "and" or "and-not" operations are to separate * the via type from other via types, and that the amount to grow is the * sum of all grow and shrink operations. * * Note that the routine works to determine simple grow rules for any * layer but is specifically designed to determine how to convert cut * layers from a LEF file into magic contact types. * * Results: * Grow length, in magic units * * Side effects: * None * * ---------------------------------------------------------------------------- */ int CIFReadGetGrowSize( TileType type) { CIFReadStyle *istyle = cifCurReadStyle; CIFOp *op; int i, dist = 0; if (istyle == NULL) return 0; for (i = 0; i < istyle->crs_nLayers; i++) { /* Don't confuse CIF types with magic types! */ if (istyle->crs_layers[i]->crl_flags & CIFR_TEMPLAYER) continue; if (istyle->crs_layers[i]->crl_magicType == type) { dist = 0; for (op = istyle->crs_layers[i]->crl_ops; op != NULL; op = op->co_next) { if (op->co_opcode == CIFOP_GROW || op->co_opcode == CIFOP_GROW_G) { dist += op->co_distance; } if (op->co_opcode == CIFOP_SHRINK) { dist -= op->co_distance; } } if (dist > 0) break; } } return dist; } /* * ---------------------------------------------------------------------------- * * CIFGetInputScale -- * * This routine is given here so that the CIF input scale can be * accessed from the "commands" directory source without declaring * external references to CIF global variables. * * Results: * Internal units-to-(nanometers * convert) conversion factor (float). * * Side effects: * None. * * ---------------------------------------------------------------------------- */ float CIFGetInputScale( int convert) { /* Avoid divide-by-0 error if there is no cif input style */ /* in the tech file. */ if (!cifCurReadStyle) { TxError("Error: No style is set\n"); return (float)0; } /* NOTE: convert = 1000 for centimicrons to microns conversion */ return ((float)(10 * cifCurReadStyle->crs_scaleFactor) / (float)(cifCurReadStyle->crs_multiplier * convert)); } /* * ---------------------------------------------------------------------------- * * CIFPrintReadStyle -- * * Print the current CIF read style or a list of available styles. * * Results: * None. * * Side effects: * Output. * * ---------------------------------------------------------------------------- */ void CIFPrintReadStyle( bool dolist, /* Return as a list if true */ bool doforall, /* Return list of all styles if true */ bool docurrent) /* Return current style if true */ { CIFReadKeep *style; if (docurrent) { if (cifCurReadStyle == NULL) TxError("Error: No style is set\n"); else { if (!dolist) TxPrintf("The current style is \""); #ifdef MAGIC_WRAPPER if (dolist) Tcl_SetResult(magicinterp, cifCurReadStyle->crs_name, NULL); else #endif TxPrintf("%s", cifCurReadStyle->crs_name); if (!dolist) TxPrintf("\".\n"); } } if (doforall) { if (!dolist) TxPrintf("The CIF input styles are: "); for (style = cifReadStyleList; style != NULL; style = style->crs_next) { if (dolist) { #ifdef MAGIC_WRAPPER Tcl_AppendElement(magicinterp, style->crs_name); #else if (style != cifReadStyleList) TxPrintf(" "); TxPrintf("%s", style->crs_name); #endif } else { if (style != cifReadStyleList) TxPrintf(", "); TxPrintf("%s", style->crs_name); } } if (!dolist) TxPrintf(".\n"); } } /* * ---------------------------------------------------------------------------- * * CIFSetReadStyle -- * * This procedure changes the current style used for reading * CIF. * * Results: * None. * * Side effects: * The CIF style is changed to the one specified by name. If * there is no style by that name, then a list of all valid * styles is output. * * ---------------------------------------------------------------------------- */ void CIFSetReadStyle( char *name) /* Name of the new style. If NULL, * just print the name of the current * style. */ { CIFReadKeep *style, *match; int length; if (name == NULL) return; match = NULL; length = strlen(name); for (style = cifReadStyleList; style != NULL; style = style->crs_next) { if (strncmp(name, style->crs_name, length) == 0) { if (match != NULL) { TxError("CIF input style \"%s\" is ambiguous.\n", name); CIFPrintReadStyle(FALSE, TRUE, TRUE); return; } match = style; } } if (match != NULL) { CIFReadLoadStyle(match->crs_name); TxPrintf("CIF input style is now \"%s\"\n", name); return; } TxError("\"%s\" is not one of the CIF input styles Magic knows.\n", name); CIFPrintReadStyle(FALSE, TRUE, TRUE); } /* * ---------------------------------------------------------------------------- * * cifParseCalmaNums -- * * Parse a comma-separated list of Calma numbers. Each number in * the list must be between 0 and CALMA_LAYER_MAX, or an asterisk * "*". Store each number in the array 'numArray', which has space * for up to 'numNums' numbers. An asterisk is stored as -1. * * Results: * Returns the number of numbers added to the array, or * -1 on error. * * Side effects: * Adds numbers to the array. If there were too many numbers, * or some of the numbers were not legal Calma numbers, we * print an error message. * * ---------------------------------------------------------------------------- */ int cifParseCalmaNums( char *str, /* String to parse */ int *numArray, /* Array to fill in */ int numNums) /* Maximum number of entries in numArray */ { int numFilled, num; for (numFilled = 0; numFilled < numNums; numFilled++) { /* Done if at end of string */ if (*str == '\0') return (numFilled); /* Is it a wild-card (*)? */ if (*str == '*') num = -1; else { num = atoi(str); if (num < 0 || num > CALMA_LAYER_MAX) { TechError("Calma layer and type numbers must be 0 to %d.\n", CALMA_LAYER_MAX); return (-1); } } /* Skip to next number */ while (*str && *str != ',') { if (*str != '*' && !isdigit(*str)) { TechError("Calma layer/type numbers must be numeric or '*'\n"); return (-1); } str++; } while (*str && *str == ',') str++; numArray[numFilled] = num; } TechError("Too many layer/type numbers in line; maximum = %d\n", numNums); return (-1); } /* * ---------------------------------------------------------------------------- * * CIFTechInputScale(n, d, opt) * * Scale all CIF input scale factors to make them equivalent * to reducing the magic internal unit spacing by a factor of n/d. * * After scaling, we attempt to reduce the ratio scaleFactor : multiplier * if there is a common factor. If "opt" is TRUE, we reduce both values * by this factor. If FALSE, we do not reduce multiplier below its * original value. This is important if we are still in the process of * reading CIF or GDS input. * * ---------------------------------------------------------------------------- */ int CIFTechInputScale( int n, int d, bool opt) { CIFReadStyle *istyle = cifCurReadStyle; CIFReadLayer *cl; CIFOp *op; int lmult, i, lgcf; if (istyle == NULL) return 0; /* fprintf(stderr, "CIF input style %s:\n", istyle->crs_name); */ istyle->crs_scaleFactor *= n; istyle->crs_multiplier *= d; lmult = istyle->crs_multiplier; 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; lgcf = FindGCF(abs(op->co_distance), istyle->crs_multiplier); lmult = FindGCF(lmult, lgcf); if (lmult == 1) break; } } } /* fprintf(stderr, "All CIF units divisible by %d\n", lmult); */ lgcf = FindGCF(istyle->crs_scaleFactor, istyle->crs_multiplier); if (lgcf < lmult) lmult = lgcf; if (lmult == 0) return 0; /* fprintf(stderr, "Multiplier goes from %d to %d\n", istyle->crs_multiplier, istyle->crs_multiplier / lmult); */ if (!opt) { if ((lmult % d) == 0) lmult = d; else lmult = 1; } if (lmult > 1) { istyle->crs_scaleFactor /= lmult; istyle->crs_multiplier /= lmult; 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 /= lmult; } } return lmult; }