1489 lines
39 KiB
C
1489 lines
39 KiB
C
/* 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 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
#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 CIFReadLoadStyle();
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* 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(ns, ds)
|
|
int ns, 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(name, newOK)
|
|
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(layer, datatype, calmaStyle)
|
|
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(string, mask, newok)
|
|
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()
|
|
{
|
|
int i;
|
|
CIFOp *op;
|
|
CIFReadLayer *layer;
|
|
|
|
if (cifCurReadStyle != NULL)
|
|
{
|
|
/* Destroy old style and free all memory allocated to it */
|
|
|
|
for (i=0; i<MAXCIFRLAYERS; i+=1)
|
|
{
|
|
layer = cifCurReadStyle->crs_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()
|
|
{
|
|
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()
|
|
{
|
|
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()
|
|
{
|
|
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(sectionName, argc, argv)
|
|
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()
|
|
{
|
|
/* 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(stylename)
|
|
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(type)
|
|
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(convert)
|
|
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(dolist, doforall, docurrent)
|
|
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(name)
|
|
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(str, numArray, numNums)
|
|
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(n, d, opt)
|
|
int n, 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;
|
|
}
|
|
|