2017-04-25 14:41:48 +02:00
|
|
|
/* CIFtech.c -
|
|
|
|
|
*
|
|
|
|
|
* This module processes the portions of technology
|
|
|
|
|
* files pertaining to CIF, and builds the tables
|
|
|
|
|
* used by the CIF generator.
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
* * 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. *
|
2017-04-25 14:41:48 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef lint
|
2024-10-04 12:37:02 +02:00
|
|
|
static const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/cif/CIFtech.c,v 1.7 2010/10/20 20:34:19 tim Exp $";
|
2017-04-25 14:41:48 +02:00
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h> /* for atof() */
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <math.h> /* 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 */
|
|
|
|
|
|
2022-10-10 11:50:15 +02:00
|
|
|
/* C99 compat */
|
|
|
|
|
#include "calma/calma.h"
|
|
|
|
|
#include "dbwind/dbwind.h"
|
|
|
|
|
#include "drc/drc.h"
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* 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 */
|
|
|
|
|
|
2024-10-04 12:26:58 +02:00
|
|
|
void cifTechStyleInit(void);
|
|
|
|
|
bool cifCheckCalmaNum(char *str);
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* 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
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
cifTechFreeStyle(void)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
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:
|
2019-06-05 21:03:51 +02:00
|
|
|
case CIFOP_BOUNDARY:
|
2017-04-25 14:41:48 +02:00
|
|
|
/* 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
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
cifTechNewStyle(void)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
cifTechFreeStyle();
|
|
|
|
|
cifTechStyleInit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* cifTechStyleInit --
|
|
|
|
|
*
|
|
|
|
|
* Fill in the current cif input style structure with initial values
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
cifTechStyleInit(void)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
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; i<TT_MAXTYPES; i+=1)
|
2018-09-09 21:09:15 +02:00
|
|
|
{
|
2017-04-25 14:41:48 +02:00
|
|
|
CIFCurStyle->cs_labelLayer[i] = -1;
|
2018-09-09 21:09:15 +02:00
|
|
|
CIFCurStyle->cs_portLayer[i] = -1;
|
2022-12-21 23:49:43 +01:00
|
|
|
CIFCurStyle->cs_portText[i] = -1;
|
2018-09-09 21:09:15 +02:00
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
for (i = 0; i < MAXCIFLAYERS; i++)
|
|
|
|
|
CIFCurStyle->cs_layers[i] = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* 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
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
cifParseLayers(
|
|
|
|
|
char *string, /* List of layers. */
|
|
|
|
|
CIFStyle *style, /* Gives CIF style for parsing string.*/
|
|
|
|
|
TileTypeBitMask *paintMask, /* Place to store mask of paint layers. If
|
2017-04-25 14:41:48 +02:00
|
|
|
* NULL, then only CIF layer names are
|
|
|
|
|
* considered.
|
|
|
|
|
*/
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
TileTypeBitMask *cifMask, /* Place to store mask of CIF layers. If
|
2017-04-25 14:41:48 +02:00
|
|
|
* NULL, then only paint layer names are
|
|
|
|
|
* considered.
|
|
|
|
|
*/
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
int spaceOK) /* are space layers permissible in this cif
|
2017-04-25 14:41:48 +02:00
|
|
|
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.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
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);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFTechInit --
|
|
|
|
|
*
|
|
|
|
|
* Called before loading a new technology.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Clears out list of styles and resets the current style.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFTechInit(void)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
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
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFTechStyleInit(void)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
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
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFTechLimitScale(
|
|
|
|
|
int ns,
|
|
|
|
|
int ds)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
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
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFParseScale(
|
|
|
|
|
char *true_scale,
|
|
|
|
|
int *expander)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* 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
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFTechLine(
|
|
|
|
|
char *sectionName, /* The name of this section. */
|
|
|
|
|
int argc, /* Number of fields on line. */
|
|
|
|
|
char *argv[]) /* Values of fields. */
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2020-05-26 20:29:36 +02:00
|
|
|
TileTypeBitMask mask, tempMask, cifMask, bloatLayers;
|
2017-04-25 14:41:48 +02:00
|
|
|
int i, j, l, distance;
|
|
|
|
|
CIFLayer *newLayer;
|
|
|
|
|
CIFOp *newOp = NULL;
|
|
|
|
|
CIFKeep *newStyle, *p;
|
|
|
|
|
char **bloatArg;
|
|
|
|
|
BloatData *bloats;
|
2020-06-11 22:40:01 +02:00
|
|
|
BridgeData *bridge;
|
2017-04-25 14:41:48 +02:00
|
|
|
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.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
for (newStyle = CIFStyleList; newStyle != NULL;
|
2017-04-25 14:41:48 +02:00
|
|
|
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;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
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, ',');
|
2020-05-23 23:13:14 +02:00
|
|
|
if (cptr != NULL)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
*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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
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;
|
2021-11-16 16:58:18 +01:00
|
|
|
if ((strcmp(argv[0], "templayer") == 0) || (strcmp(argv[0], "layer") == 0) ||
|
|
|
|
|
(strcmp(argv[0], "labellayer") == 0))
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
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;
|
2021-11-16 16:58:18 +01:00
|
|
|
else if (strcmp(argv[0], "labellayer") == 0)
|
|
|
|
|
newLayer->cl_flags |= CIF_LABEL;
|
2017-04-25 14:41:48 +02:00
|
|
|
cifCurLayer = newLayer;
|
|
|
|
|
cifCurOp = NULL;
|
|
|
|
|
cifGotLabels = FALSE;
|
|
|
|
|
|
|
|
|
|
/* Handle a special case of a list of layer names on the layer
|
2020-05-23 23:13:14 +02:00
|
|
|
* line. Turn them into an OR operation.
|
2017-04-25 14:41:48 +02:00
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if (argc == 3)
|
|
|
|
|
{
|
|
|
|
|
cifCurOp = (CIFOp *) mallocMagic(sizeof(CIFOp));
|
|
|
|
|
cifCurOp->co_opcode = CIFOP_OR;
|
|
|
|
|
cifParseLayers(argv[2], CIFCurStyle, &cifCurOp->co_paintMask,
|
2020-05-26 20:29:36 +02:00
|
|
|
&cifCurOp->co_cifMask, FALSE);
|
2017-04-25 14:41:48 +02:00
|
|
|
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)
|
|
|
|
|
{
|
2022-12-21 23:49:43 +01:00
|
|
|
bool portOnly = FALSE, noPort = FALSE, textOnly = FALSE;
|
2018-09-09 21:09:15 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
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");
|
2018-09-09 21:09:15 +02:00
|
|
|
if (argc == 3)
|
|
|
|
|
{
|
|
|
|
|
if (!strncmp(argv[2], "port", 4))
|
|
|
|
|
portOnly = TRUE;
|
|
|
|
|
else if (!strncmp(argv[2], "noport", 6))
|
|
|
|
|
noPort = TRUE;
|
2022-12-21 23:49:43 +01:00
|
|
|
else if (!strncmp(argv[2], "text", 6))
|
|
|
|
|
textOnly = TRUE;
|
2018-09-09 21:09:15 +02:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
TechError("Unknown option %s for labels statement.\n", argv[2]);
|
|
|
|
|
goto wrongNumArgs;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (argc != 2) goto wrongNumArgs;
|
2017-04-25 14:41:48 +02:00
|
|
|
DBTechNoisyNameMask(argv[1], &mask);
|
|
|
|
|
for (i=0; i<TT_MAXTYPES; i+=1)
|
|
|
|
|
{
|
|
|
|
|
if (TTMaskHasType(&mask, i))
|
2018-09-09 21:09:15 +02:00
|
|
|
{
|
2022-12-21 23:49:43 +01:00
|
|
|
if (portOnly == TRUE)
|
|
|
|
|
{
|
|
|
|
|
/* With "port", use layer for port geometry.
|
|
|
|
|
* If the port text type has not been set, set it to
|
|
|
|
|
* this layer.
|
|
|
|
|
*/
|
2018-09-09 21:09:15 +02:00
|
|
|
CIFCurStyle->cs_portLayer[i] = CIFCurStyle->cs_nLayers-1;
|
2022-12-21 23:49:43 +01:00
|
|
|
if (CIFCurStyle->cs_portText[i] == -1)
|
|
|
|
|
CIFCurStyle->cs_portText[i] = CIFCurStyle->cs_nLayers-1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* For "noport" or no argument, the label text and data
|
|
|
|
|
* are set to this layer. If no argument, then set the
|
|
|
|
|
* port text type to this type. If a later "port" statement
|
|
|
|
|
* applies to the same layer, then the data type will be
|
|
|
|
|
* separate from the text type.
|
|
|
|
|
*/
|
|
|
|
|
CIFCurStyle->cs_labelLayer[i] = CIFCurStyle->cs_nLayers-1;
|
|
|
|
|
if (noPort == FALSE)
|
|
|
|
|
CIFCurStyle->cs_portText[i] = CIFCurStyle->cs_nLayers-1;
|
|
|
|
|
}
|
2018-09-09 21:09:15 +02:00
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
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 <layer> <style> <height> <thick>\n");
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
height = (float)atof(argv[3]);
|
|
|
|
|
thick = (float)atof(argv[4]);
|
|
|
|
|
|
|
|
|
|
lcnt = 0;
|
|
|
|
|
for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
|
|
|
|
|
{
|
|
|
|
|
layer = CIFCurStyle->cs_layers[i];
|
|
|
|
|
if (!strcmp(argv[1], layer->cl_name))
|
|
|
|
|
{
|
|
|
|
|
layer->cl_height = height;
|
|
|
|
|
layer->cl_thick = thick;
|
|
|
|
|
layer->cl_renderStyle = style;
|
|
|
|
|
lcnt++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (lcnt == 0)
|
|
|
|
|
{
|
|
|
|
|
TechError("Unknown layer name.\n");
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
/*
|
2017-04-25 14:41:48 +02:00
|
|
|
* miscellaneous cif/calma-writing 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], "calma-permissive-labels") == 0)
|
|
|
|
|
CIFCurStyle->cs_flags |= CWF_PERMISSIVE_LABELS;
|
2023-01-13 23:21:37 +01:00
|
|
|
else if (strcmp(argv[i], "set-minimum-grid") == 0)
|
|
|
|
|
CIFCurStyle->cs_flags |= CWF_MINIMUM_GRID;
|
2017-04-25 14:41:48 +02:00
|
|
|
else if (strcmp(argv[i], "grow-euclidean") == 0)
|
|
|
|
|
CIFCurStyle->cs_flags |= CWF_GROW_EUCLIDEAN;
|
2020-12-14 22:55:29 +01:00
|
|
|
else if (strcmp(argv[i], "see-no-vendor") == 0)
|
|
|
|
|
CIFCurStyle->cs_flags |= CWF_SEE_NO_VENDOR;
|
2017-04-25 14:41:48 +02:00
|
|
|
else if (strcmp(argv[i], "no-errors") == 0)
|
|
|
|
|
CIFCurStyle->cs_flags |= CWF_NO_ERRORS;
|
2019-12-19 23:28:06 +01:00
|
|
|
else if (strcmp(argv[i], "string-limit") == 0)
|
|
|
|
|
CIFCurStyle->cs_flags |= CWF_STRING_LIMIT;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Anything below here is a geometric operation, so we can
|
|
|
|
|
* do some set-up that is common to all the operations.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if (cifCurLayer == NULL)
|
|
|
|
|
{
|
|
|
|
|
TechError("Must define layer before specifying operation.\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;
|
2019-12-02 16:18:37 +01:00
|
|
|
else if (strcmp(argv[0], "grow-min") == 0)
|
|
|
|
|
newOp->co_opcode = CIFOP_GROWMIN;
|
2017-04-25 14:41:48 +02:00
|
|
|
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], "bloat-or") == 0)
|
|
|
|
|
newOp->co_opcode = CIFOP_BLOAT;
|
|
|
|
|
else if (strcmp(argv[0], "bloat-max") == 0)
|
|
|
|
|
newOp->co_opcode = CIFOP_BLOATMAX;
|
|
|
|
|
else if (strcmp(argv[0], "bloat-min") == 0)
|
|
|
|
|
newOp->co_opcode = CIFOP_BLOATMIN;
|
|
|
|
|
else if (strcmp(argv[0], "bloat-all") == 0)
|
|
|
|
|
newOp->co_opcode = CIFOP_BLOATALL;
|
|
|
|
|
else if (strcmp(argv[0], "squares") == 0)
|
|
|
|
|
newOp->co_opcode = CIFOP_SQUARES;
|
|
|
|
|
else if (strcmp(argv[0], "squares-grid") == 0)
|
|
|
|
|
newOp->co_opcode = CIFOP_SQUARES_G;
|
|
|
|
|
else if (strcmp(argv[0], "slots") == 0)
|
|
|
|
|
newOp->co_opcode = CIFOP_SLOTS;
|
|
|
|
|
else if (strcmp(argv[0], "bbox") == 0)
|
|
|
|
|
newOp->co_opcode = CIFOP_BBOX;
|
|
|
|
|
else if (strcmp(argv[0], "net") == 0)
|
|
|
|
|
newOp->co_opcode = CIFOP_NET;
|
|
|
|
|
else if (strcmp(argv[0], "maxrect") == 0)
|
|
|
|
|
newOp->co_opcode = CIFOP_MAXRECT;
|
2019-06-05 21:03:51 +02:00
|
|
|
else if (strcmp(argv[0], "boundary") == 0)
|
|
|
|
|
newOp->co_opcode = CIFOP_BOUNDARY;
|
2020-12-14 22:16:37 +01:00
|
|
|
else if (strcmp(argv[0], "mask-hints") == 0)
|
|
|
|
|
newOp->co_opcode = CIFOP_MASKHINTS;
|
2019-11-25 21:14:41 +01:00
|
|
|
else if (strcmp(argv[0], "close") == 0)
|
|
|
|
|
newOp->co_opcode = CIFOP_CLOSE;
|
2020-06-11 22:40:01 +02:00
|
|
|
else if (strcmp(argv[0], "bridge") == 0)
|
|
|
|
|
newOp->co_opcode = CIFOP_BRIDGE;
|
2020-07-27 22:40:31 +02:00
|
|
|
else if (strcmp(argv[0], "bridge-lim") == 0)
|
|
|
|
|
newOp->co_opcode = CIFOP_BRIDGELIM;
|
2017-04-25 14:41:48 +02:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
TechError("Unknown statement \"%s\".\n", argv[0]);
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (newOp->co_opcode)
|
|
|
|
|
{
|
|
|
|
|
case CIFOP_AND:
|
|
|
|
|
case CIFOP_ANDNOT:
|
|
|
|
|
case CIFOP_OR:
|
|
|
|
|
if (argc != 2) goto wrongNumArgs;
|
|
|
|
|
cifParseLayers(argv[1], CIFCurStyle, &newOp->co_paintMask,
|
|
|
|
|
&newOp->co_cifMask,FALSE);
|
|
|
|
|
break;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
case CIFOP_GROW:
|
2019-12-02 16:18:37 +01:00
|
|
|
case CIFOP_GROWMIN:
|
2017-04-25 14:41:48 +02:00
|
|
|
case CIFOP_GROW_G:
|
|
|
|
|
case CIFOP_SHRINK:
|
2019-11-25 21:14:41 +01:00
|
|
|
case CIFOP_CLOSE:
|
2017-04-25 14:41:48 +02:00
|
|
|
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;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2020-06-11 22:40:01 +02:00
|
|
|
case CIFOP_BRIDGE:
|
|
|
|
|
if (argc != 3) goto wrongNumArgs;
|
|
|
|
|
newOp->co_distance = atoi(argv[1]);
|
|
|
|
|
if (newOp->co_distance <= 0)
|
|
|
|
|
{
|
|
|
|
|
TechError("Bridge distance must be greater than zero.\n");
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
bridge = (BridgeData *)mallocMagic(sizeof(BridgeData));
|
|
|
|
|
bridge->br_width = atoi(argv[2]);
|
|
|
|
|
if (bridge->br_width <= 0)
|
|
|
|
|
{
|
|
|
|
|
TechError("Bridge width must be greater than zero.\n");
|
|
|
|
|
freeMagic(bridge);
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
newOp->co_client = (ClientData)bridge;
|
|
|
|
|
break;
|
|
|
|
|
|
2020-07-27 22:40:31 +02:00
|
|
|
case CIFOP_BRIDGELIM:
|
|
|
|
|
if (argc != 4) goto wrongNumArgs;
|
|
|
|
|
newOp->co_distance = atoi(argv[1]);
|
|
|
|
|
if (newOp->co_distance <= 0)
|
|
|
|
|
{
|
|
|
|
|
TechError("Bridge distance must be greater than zero.\n");
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
bridge = (BridgeData *)mallocMagic(sizeof(BridgeData));
|
|
|
|
|
bridge->br_width = atoi(argv[2]);
|
|
|
|
|
if (bridge->br_width <= 0)
|
|
|
|
|
{
|
|
|
|
|
TechError("Bridge width must be greater than zero.\n");
|
|
|
|
|
freeMagic(bridge);
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
cifParseLayers(argv[3], CIFCurStyle, &newOp->co_paintMask, &newOp->co_cifMask,FALSE);
|
|
|
|
|
newOp->co_client = (ClientData)bridge;
|
|
|
|
|
break;
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
case CIFOP_BLOATALL:
|
2024-12-26 02:46:25 +01:00
|
|
|
if (argc != 3 && argc != 4) goto wrongNumArgs;
|
2017-04-25 14:41:48 +02:00
|
|
|
cifParseLayers(argv[1], CIFCurStyle, &newOp->co_paintMask,
|
2019-10-17 22:21:56 +02:00
|
|
|
&newOp->co_cifMask, FALSE);
|
2017-04-25 14:41:48 +02:00
|
|
|
bloats = (BloatData *)mallocMagic(sizeof(BloatData));
|
|
|
|
|
for (i = 0; i < TT_MAXTYPES; i++)
|
|
|
|
|
bloats->bl_distance[i] = 0;
|
|
|
|
|
newOp->co_client = (ClientData)bloats;
|
2020-05-26 20:29:36 +02:00
|
|
|
cifParseLayers(argv[2], CIFCurStyle, &mask, &cifMask, TRUE);
|
|
|
|
|
|
|
|
|
|
/* 5/25/2020: Lifting restriction that bloatLayers types */
|
|
|
|
|
/* cannot be CIF or temp layers. However, CIF/temp layers */
|
|
|
|
|
/* and magic database layers may not be mixed. */
|
|
|
|
|
|
|
|
|
|
if (!TTMaskIsZero(&mask) && !TTMaskIsZero(&cifMask))
|
|
|
|
|
TechError("Can't mix CIF and magic layers in bloat statement.\n");
|
2019-10-15 22:24:49 +02:00
|
|
|
|
2024-12-26 02:46:25 +01:00
|
|
|
if (argc == 4)
|
|
|
|
|
{
|
|
|
|
|
/* 12/23/2024: Allow an additional argument, which is a
|
|
|
|
|
* maximum halo distance to bloat (i.e., clip mask)
|
|
|
|
|
*/
|
|
|
|
|
newOp->co_distance = atoi(argv[3]);
|
|
|
|
|
if (newOp->co_distance <= 0)
|
|
|
|
|
{
|
|
|
|
|
TechError("Bloat distance must be greater than zero.\n");
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
newOp->co_distance = 0;
|
|
|
|
|
|
2019-10-15 22:24:49 +02:00
|
|
|
/* 10/15/2019: Lifting restriction that the types that */
|
|
|
|
|
/* trigger the bloating must be in the same plane as the */
|
|
|
|
|
/* types that are bloated into. */
|
|
|
|
|
|
|
|
|
|
TTMaskZero(&bloatLayers);
|
2020-05-26 20:29:36 +02:00
|
|
|
if (!TTMaskIsZero(&mask))
|
|
|
|
|
{
|
|
|
|
|
TTMaskSetMask(&bloatLayers, &mask);
|
|
|
|
|
for (i = 0; i < TT_MAXTYPES; i++)
|
|
|
|
|
if (TTMaskHasType(&mask, i))
|
|
|
|
|
bloats->bl_distance[i] = 1;
|
2020-05-28 17:46:57 +02:00
|
|
|
|
|
|
|
|
goto bloatCheck;
|
2020-05-26 20:29:36 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
TTMaskSetMask(&bloatLayers, &cifMask);
|
|
|
|
|
for (i = 0; i < TT_MAXTYPES; i++)
|
|
|
|
|
if (TTMaskHasType(&cifMask, i))
|
|
|
|
|
bloats->bl_distance[i] = 1;
|
2020-05-28 17:46:57 +02:00
|
|
|
|
|
|
|
|
bloats->bl_plane = -1; /* Indicates CIF types */
|
2020-05-26 20:29:36 +02:00
|
|
|
}
|
|
|
|
|
break;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
case CIFOP_BLOAT:
|
|
|
|
|
case CIFOP_BLOATMIN:
|
|
|
|
|
case CIFOP_BLOATMAX:
|
|
|
|
|
if (argc < 4) goto wrongNumArgs;
|
|
|
|
|
cifParseLayers(argv[1], CIFCurStyle, &newOp->co_paintMask,
|
2020-05-26 20:29:36 +02:00
|
|
|
(TileTypeBitMask *)NULL, FALSE);
|
2017-04-25 14:41:48 +02:00
|
|
|
argc -= 2;
|
|
|
|
|
bloatArg = argv + 2;
|
|
|
|
|
bloatLayers = newOp->co_paintMask;
|
|
|
|
|
bloats = (BloatData *)mallocMagic(sizeof(BloatData));
|
|
|
|
|
for (i = 0; i < TT_MAXTYPES; i++)
|
|
|
|
|
bloats->bl_distance[i] = 0;
|
|
|
|
|
newOp->co_client = (ClientData)bloats;
|
|
|
|
|
|
|
|
|
|
while (argc > 0)
|
|
|
|
|
{
|
|
|
|
|
if (argc == 1) goto wrongNumArgs;
|
|
|
|
|
if (strcmp(*bloatArg, "*") == 0)
|
|
|
|
|
{
|
|
|
|
|
mask = DBAllTypeBits;
|
|
|
|
|
tempMask = DBZeroTypeBits;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-05-26 20:29:36 +02:00
|
|
|
cifParseLayers(*bloatArg, CIFCurStyle, &mask, &tempMask, TRUE);
|
2017-04-25 14:41:48 +02:00
|
|
|
TTMaskSetMask(&bloatLayers, &mask);
|
|
|
|
|
}
|
|
|
|
|
if (!TTMaskEqual(&tempMask, &DBZeroTypeBits))
|
|
|
|
|
TechError("Can't use templayers in bloat statement.\n");
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
distance = atoi(bloatArg[1]);
|
|
|
|
|
if ((distance < 0) && (newOp->co_opcode == CIFOP_BLOAT))
|
|
|
|
|
{
|
|
|
|
|
TechError("Bloat-or distances must not be negative.\n");
|
|
|
|
|
distance = 0;
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < TT_MAXTYPES; i++)
|
|
|
|
|
if (TTMaskHasType(&mask, i))
|
|
|
|
|
bloats->bl_distance[i] = distance;
|
|
|
|
|
|
|
|
|
|
argc -= 2;
|
|
|
|
|
bloatArg += 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bloatCheck:
|
|
|
|
|
/* Don't do any bloating at boundaries between tiles of the
|
|
|
|
|
* types being bloated. Otherwise a bloat could pass right
|
|
|
|
|
* through a skinny tile and out the other side.
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < TT_MAXTYPES; i++)
|
|
|
|
|
if (TTMaskHasType(&newOp->co_paintMask, i))
|
|
|
|
|
bloats->bl_distance[i] = 0;
|
|
|
|
|
|
|
|
|
|
/* Make sure that all the layers specified in the statement
|
|
|
|
|
* fall in a single plane.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
for (i = 0; i < PL_MAXTYPES; i++)
|
|
|
|
|
{
|
|
|
|
|
tempMask = bloatLayers;
|
|
|
|
|
TTMaskAndMask(&tempMask, &DBPlaneTypes[i]);
|
|
|
|
|
if (TTMaskEqual(&tempMask, &bloatLayers)) {
|
|
|
|
|
bloats->bl_plane = i;
|
|
|
|
|
goto bloatDone;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
TechError("Not all bloat layers fall in the same plane.\n");
|
2021-11-05 17:15:57 +01:00
|
|
|
bloats->bl_plane = 0; /* Prevents magic from segfaulting */
|
2017-04-25 14:41:48 +02:00
|
|
|
bloatDone: break;
|
|
|
|
|
|
|
|
|
|
case CIFOP_NET:
|
|
|
|
|
if (argc != 3) goto wrongNumArgs;
|
|
|
|
|
newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]);
|
|
|
|
|
cifParseLayers(argv[2], CIFCurStyle, &newOp->co_paintMask,
|
|
|
|
|
&newOp->co_cifMask, FALSE);
|
|
|
|
|
break;
|
|
|
|
|
|
2020-12-14 22:16:37 +01:00
|
|
|
case CIFOP_MASKHINTS:
|
|
|
|
|
if (argc != 2) goto wrongNumArgs;
|
|
|
|
|
newOp->co_client = (ClientData)StrDup((char **)NULL, argv[1]);
|
|
|
|
|
break;
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
case CIFOP_MAXRECT:
|
|
|
|
|
if (argc == 2)
|
|
|
|
|
{
|
|
|
|
|
if (!strncmp(argv[1], "ext", 3))
|
|
|
|
|
newOp->co_client = (ClientData)1;
|
|
|
|
|
else if (strncmp(argv[1], "int", 3))
|
|
|
|
|
TechError("Maxrect takes only one optional argument "
|
|
|
|
|
"\"external\" or \"internal\" (default).\n");
|
|
|
|
|
}
|
|
|
|
|
else if (argc != 1)
|
|
|
|
|
goto wrongNumArgs;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CIFOP_BBOX:
|
|
|
|
|
if (argc == 2)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp(argv[1], "top"))
|
|
|
|
|
newOp->co_client = (ClientData)1;
|
|
|
|
|
else
|
|
|
|
|
TechError("BBox takes only one optional argument \"top\".\n");
|
|
|
|
|
}
|
|
|
|
|
else if (argc != 1)
|
|
|
|
|
goto wrongNumArgs;
|
|
|
|
|
break;
|
|
|
|
|
|
2019-06-05 21:03:51 +02:00
|
|
|
case CIFOP_BOUNDARY:
|
|
|
|
|
/* CIFOP_BOUNDARY has no arguments */
|
|
|
|
|
if (argc != 1)
|
|
|
|
|
goto wrongNumArgs;
|
|
|
|
|
break;
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
case CIFOP_SQUARES_G:
|
|
|
|
|
case CIFOP_SQUARES:
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
squares = (SquaresData *)mallocMagic(sizeof(SquaresData));
|
|
|
|
|
newOp->co_client = (ClientData)squares;
|
|
|
|
|
|
|
|
|
|
if (argc == 2)
|
|
|
|
|
{
|
|
|
|
|
i = atoi(argv[1]);
|
|
|
|
|
squares->sq_border = atoi(argv[1]);
|
|
|
|
|
if ((i <= 0) || (i & 1))
|
|
|
|
|
{
|
|
|
|
|
TechError("Squares must have positive even sizes.\n");
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
squares->sq_border = i/2;
|
|
|
|
|
squares->sq_size = i;
|
|
|
|
|
squares->sq_sep = i;
|
|
|
|
|
squares->sq_gridx = 1; /* set default grid */
|
|
|
|
|
squares->sq_gridy = 1; /* set default grid */
|
|
|
|
|
}
|
|
|
|
|
else if (argc == 4 || ((argc == 5 || argc == 6)
|
|
|
|
|
&& newOp->co_opcode==CIFOP_SQUARES_G))
|
|
|
|
|
{
|
|
|
|
|
squares->sq_border = atoi(argv[1]);
|
|
|
|
|
if (squares->sq_border < 0)
|
|
|
|
|
{
|
|
|
|
|
TechError("Square border must not be negative.\n");
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
squares->sq_size = atoi(argv[2]);
|
|
|
|
|
if (squares->sq_size <= 0)
|
|
|
|
|
{
|
|
|
|
|
TechError("Squares must have positive sizes.\n");
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
squares->sq_sep = atoi(argv[3]);
|
|
|
|
|
if (squares->sq_sep <= 0)
|
|
|
|
|
{
|
|
|
|
|
TechError("Square separation must be positive.\n");
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
if (argc >= 5)
|
|
|
|
|
{
|
|
|
|
|
squares->sq_gridx = squares->sq_gridy = atoi(argv[4]);
|
|
|
|
|
if (squares->sq_gridx <= 0)
|
|
|
|
|
{
|
|
|
|
|
TechError("Square grid must be strictly positive.\n");
|
|
|
|
|
squares->sq_gridx = squares->sq_gridy = 1;
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
squares->sq_gridx = 1; /* set default grid */
|
|
|
|
|
squares->sq_gridy = 1; /* set default grid */
|
|
|
|
|
}
|
|
|
|
|
if (argc == 6)
|
|
|
|
|
{
|
|
|
|
|
squares->sq_gridy = atoi(argv[5]);
|
|
|
|
|
if (squares->sq_gridy <= 0)
|
|
|
|
|
{
|
|
|
|
|
TechError("Square y-grid must be strictly positive.\n");
|
|
|
|
|
squares->sq_gridy = 1;
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else goto wrongNumArgs;
|
|
|
|
|
|
|
|
|
|
/* Ensure that squares are never placed at less than the */
|
|
|
|
|
/* minimum allowed mask resolution. This may require that */
|
|
|
|
|
/* operation "squares" be changed to "squares-grid". */
|
|
|
|
|
|
|
|
|
|
if (squares->sq_gridx < CIFCurStyle->cs_gridLimit)
|
|
|
|
|
{
|
|
|
|
|
squares->sq_gridx = CIFCurStyle->cs_gridLimit;
|
|
|
|
|
newOp->co_opcode = CIFOP_SQUARES_G;
|
|
|
|
|
}
|
|
|
|
|
if (squares->sq_gridy < CIFCurStyle->cs_gridLimit)
|
|
|
|
|
{
|
|
|
|
|
squares->sq_gridy = CIFCurStyle->cs_gridLimit;
|
|
|
|
|
newOp->co_opcode = CIFOP_SQUARES_G;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CIFOP_SLOTS:
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
slots = (SlotsData *)mallocMagic(sizeof(SlotsData));
|
|
|
|
|
newOp->co_client = (ClientData)slots;
|
|
|
|
|
|
|
|
|
|
if (argc >= 4)
|
|
|
|
|
{
|
|
|
|
|
i = atoi(argv[1]);
|
|
|
|
|
slots->sl_sborder = i;
|
|
|
|
|
if (i < 0)
|
|
|
|
|
{
|
|
|
|
|
TechError("Slot border must be non-negative.\n");
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
i = atoi(argv[2]);
|
|
|
|
|
slots->sl_ssize = i;
|
|
|
|
|
if (i <= 0)
|
|
|
|
|
{
|
|
|
|
|
TechError("Slot short-side size must be strictly positive.\n");
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
i = atoi(argv[3]);
|
|
|
|
|
slots->sl_ssep = i;
|
|
|
|
|
if (i <= 0)
|
|
|
|
|
{
|
|
|
|
|
TechError("Slot separation must be strictly positive.\n");
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
/* Initialize other values, in case they are not specified */
|
|
|
|
|
slots->sl_lborder = 0;
|
|
|
|
|
slots->sl_lsize = 0;
|
|
|
|
|
slots->sl_lsep = 0;
|
|
|
|
|
slots->sl_offset = 0;
|
2019-11-20 19:36:03 +01:00
|
|
|
slots->sl_start = 0;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
if (argc >= 5)
|
|
|
|
|
{
|
|
|
|
|
i = atoi(argv[4]);
|
|
|
|
|
slots->sl_lborder = i;
|
|
|
|
|
if (i < 0)
|
|
|
|
|
{
|
|
|
|
|
TechError("Slot border must be non-negative.\n");
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (argc >= 6)
|
|
|
|
|
{
|
|
|
|
|
i = atoi(argv[5]);
|
|
|
|
|
slots->sl_lsize = i;
|
|
|
|
|
if (i < 0)
|
|
|
|
|
{
|
|
|
|
|
TechError("Slot long-side size must be positive or zero.\n");
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
i = atoi(argv[6]);
|
|
|
|
|
slots->sl_lsep = i;
|
|
|
|
|
if (i < 0)
|
|
|
|
|
{
|
|
|
|
|
TechError("Slot long-side separation must be non-negative.\n");
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
else if (i == 0 && (slots->sl_lsize > 0))
|
|
|
|
|
{
|
|
|
|
|
TechError("Slot long-side separation must be strictly positive"
|
|
|
|
|
" when long-side size is nonzero\n");
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-20 19:36:03 +01:00
|
|
|
if (argc >= 8)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
i = atoi(argv[7]);
|
|
|
|
|
slots->sl_offset = i;
|
|
|
|
|
if (i < 0)
|
|
|
|
|
{
|
|
|
|
|
TechError("Slot offset must be non-negative.\n");
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-20 19:36:03 +01:00
|
|
|
if (argc == 9)
|
|
|
|
|
{
|
|
|
|
|
i = atoi(argv[8]);
|
|
|
|
|
slots->sl_start = i;
|
|
|
|
|
if (i < 0)
|
|
|
|
|
{
|
|
|
|
|
TechError("Slot start must be non-negative.\n");
|
|
|
|
|
goto errorReturn;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ((argc < 4) || (argc == 6) || (argc > 9))
|
2017-04-25 14:41:48 +02:00
|
|
|
goto wrongNumArgs;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Link the new CIFOp into the list. */
|
|
|
|
|
|
|
|
|
|
if (cifCurOp == NULL)
|
|
|
|
|
cifCurLayer->cl_ops = newOp;
|
|
|
|
|
else
|
|
|
|
|
cifCurOp->co_next = newOp;
|
|
|
|
|
cifCurOp = newOp;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* cifCheckCalmaNum --
|
|
|
|
|
*
|
|
|
|
|
* This local procedure checks whether its argument is the ASCII
|
|
|
|
|
* representation of a positive integer between 0 and CALMA_LAYER_MAX.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* TRUE if the argument string is valid as described above, FALSE if not.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
cifCheckCalmaNum(
|
|
|
|
|
char *str)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
int n = atoi(str);
|
|
|
|
|
|
|
|
|
|
if (n < 0 || n > CALMA_LAYER_MAX)
|
|
|
|
|
return (FALSE);
|
|
|
|
|
|
|
|
|
|
while (*str) {
|
|
|
|
|
char ch = *str++;
|
2020-05-23 23:13:14 +02:00
|
|
|
if (ch < '0' || ch > '9')
|
2017-04-25 14:41:48 +02:00
|
|
|
return (FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (TRUE);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* cifComputeRadii --
|
|
|
|
|
*
|
|
|
|
|
* This local procedure computes and fills in the grow and
|
|
|
|
|
* shrink distances for a layer. Before calling this procedure,
|
|
|
|
|
* the distances must have been computed for all temporary
|
|
|
|
|
* layers used by this layer.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Modifies cl_growDist and cl_shrinkDist in layer.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
cifComputeRadii(
|
|
|
|
|
CIFLayer *layer, /* Layer for which to compute distances. */
|
|
|
|
|
CIFStyle *des) /* CIF style (used to find temp layer
|
2017-04-25 14:41:48 +02:00
|
|
|
* distances.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
int i, grow, shrink, curGrow, curShrink;
|
|
|
|
|
CIFOp *op;
|
|
|
|
|
BloatData *bloats;
|
|
|
|
|
|
|
|
|
|
grow = shrink = 0;
|
|
|
|
|
|
|
|
|
|
for (op = layer->cl_ops; op != NULL; op = op->co_next)
|
|
|
|
|
{
|
2020-12-14 22:16:37 +01:00
|
|
|
/* BBOX, NET, and MASKHINTS operators should never be used */
|
|
|
|
|
/* hierarchically so ignore any grow/shrink operators that */
|
|
|
|
|
/* come after them. */
|
2020-11-12 16:34:27 +01:00
|
|
|
|
2020-12-14 22:16:37 +01:00
|
|
|
if (op->co_opcode == CIFOP_BBOX || op->co_opcode == CIFOP_NET ||
|
|
|
|
|
op->co_opcode == CIFOP_MASKHINTS)
|
2020-11-12 16:34:27 +01:00
|
|
|
break;
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* If CIF layers are used, switch to the max of current
|
|
|
|
|
* distances and those of the layers used.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if (!TTMaskEqual(&op->co_cifMask, &DBZeroTypeBits))
|
|
|
|
|
{
|
|
|
|
|
for (i=0; i < des->cs_nLayers; i++)
|
|
|
|
|
{
|
|
|
|
|
if (TTMaskHasType(&op->co_cifMask, i))
|
|
|
|
|
{
|
|
|
|
|
if (des->cs_layers[i]->cl_growDist > grow)
|
|
|
|
|
grow = des->cs_layers[i]->cl_growDist;
|
|
|
|
|
if (des->cs_layers[i]->cl_shrinkDist > shrink)
|
|
|
|
|
shrink = des->cs_layers[i]->cl_shrinkDist;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add in grows and shrinks at this step. */
|
|
|
|
|
|
|
|
|
|
switch (op->co_opcode)
|
|
|
|
|
{
|
2020-12-14 22:16:37 +01:00
|
|
|
case CIFOP_AND:
|
|
|
|
|
case CIFOP_ANDNOT:
|
|
|
|
|
case CIFOP_OR:
|
|
|
|
|
case CIFOP_MASKHINTS:
|
|
|
|
|
break;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
case CIFOP_GROW:
|
2019-12-02 16:18:37 +01:00
|
|
|
case CIFOP_GROWMIN:
|
2017-04-25 14:41:48 +02:00
|
|
|
case CIFOP_GROW_G:
|
|
|
|
|
grow += op->co_distance;
|
|
|
|
|
break;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
case CIFOP_SHRINK:
|
|
|
|
|
shrink += op->co_distance;
|
|
|
|
|
break;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* For bloats use the largest distances (negative values are
|
|
|
|
|
* for shrinks).
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
case CIFOP_BLOAT:
|
|
|
|
|
curGrow = curShrink = 0;
|
|
|
|
|
bloats = (BloatData *)op->co_client;
|
|
|
|
|
for (i = 0; i < TT_MAXTYPES; i++)
|
|
|
|
|
{
|
|
|
|
|
if (bloats->bl_distance[i] > curGrow)
|
|
|
|
|
curGrow = bloats->bl_distance[i];
|
|
|
|
|
else if ((-bloats->bl_distance[i]) > curShrink)
|
|
|
|
|
curShrink = -bloats->bl_distance[i];
|
|
|
|
|
}
|
|
|
|
|
grow += curGrow;
|
|
|
|
|
shrink += curShrink;
|
|
|
|
|
break;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2020-06-11 22:40:01 +02:00
|
|
|
case CIFOP_BRIDGE: break;
|
2020-07-27 22:40:31 +02:00
|
|
|
case CIFOP_BRIDGELIM: break;
|
2017-04-25 14:41:48 +02:00
|
|
|
case CIFOP_SQUARES: break;
|
|
|
|
|
case CIFOP_SQUARES_G: break;
|
2020-11-12 16:34:27 +01:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
layer->cl_growDist = grow;
|
|
|
|
|
layer->cl_shrinkDist = shrink;
|
|
|
|
|
|
|
|
|
|
/* TxPrintf("Radii for %s: grow %d, shrink %d.\n", layer->cl_name,
|
|
|
|
|
grow, shrink);
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* cifComputeHalo --
|
|
|
|
|
*
|
|
|
|
|
* Compute grow and shrink distances for each layer, and remember the
|
|
|
|
|
* largest. Convert from CIF/GDS to Magic internal dimensions.
|
|
|
|
|
*
|
|
|
|
|
* Results: None.
|
|
|
|
|
* Side effects: Sets cs_radius value in the current cifoutput style.
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
cifComputeHalo(
|
|
|
|
|
CIFStyle *style)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
int maxGrow, maxShrink, i;
|
|
|
|
|
|
|
|
|
|
maxGrow = maxShrink = 0;
|
|
|
|
|
for (i = 0; i < style->cs_nLayers; i++)
|
|
|
|
|
{
|
|
|
|
|
cifComputeRadii(style->cs_layers[i], style);
|
|
|
|
|
if (style->cs_layers[i]->cl_growDist > maxGrow)
|
|
|
|
|
maxGrow = style->cs_layers[i]->cl_growDist;
|
|
|
|
|
if (style->cs_layers[i]->cl_shrinkDist > maxShrink)
|
|
|
|
|
maxShrink = style->cs_layers[i]->cl_shrinkDist;
|
|
|
|
|
}
|
|
|
|
|
if (maxGrow > maxShrink)
|
|
|
|
|
style->cs_radius = 2*maxGrow;
|
|
|
|
|
else style->cs_radius = 2*maxShrink;
|
|
|
|
|
style->cs_radius /= style->cs_scaleFactor;
|
|
|
|
|
style->cs_radius++;
|
|
|
|
|
|
|
|
|
|
/* TxPrintf("Radius for %s CIF is %d.\n",
|
|
|
|
|
* style->cs_name, style->cs_radius);
|
|
|
|
|
*/
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFTechFinal --
|
|
|
|
|
*
|
|
|
|
|
* This procedure is invoked after all the lines of a technology
|
|
|
|
|
* file have been read. It checks to make sure that the
|
|
|
|
|
* section ended at a consistent point, and computes the interaction
|
|
|
|
|
* distances for hierarchical CIF processing.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Error messages are output if there's incomplete stuff left.
|
|
|
|
|
* Interaction distances get computed for each CIF style
|
|
|
|
|
* in two steps. First, for each layer the total grow and
|
|
|
|
|
* shrink distances are computed. These are the maximum distances
|
|
|
|
|
* that edges may move because of grows and shrinks in creating
|
|
|
|
|
* the layer. Second, the radius for the style is computed.
|
|
|
|
|
* The radius is used in two ways: first to determine how far
|
|
|
|
|
* apart two subcells may be and still interact during CIF
|
|
|
|
|
* generation; and second, to see how much material to yank in
|
|
|
|
|
* order to find all additional CIF resulting from interactions.
|
|
|
|
|
* Right now, a conservative approach is used: use the greater
|
|
|
|
|
* of twice the largest grow distance or twice the largest shrink
|
|
|
|
|
* distance for both. Twice the grow distance must be considered
|
|
|
|
|
* because two pieces of material may each grow towards the other
|
|
|
|
|
* and interact in the middle. Twice the largest shrink distance
|
|
|
|
|
* is needed because subcells considered individually may each
|
|
|
|
|
* shrink away from a boundary where they touch; the parent must
|
|
|
|
|
* fill in the gap. To do this, it must include 2S additional
|
|
|
|
|
* material: S is the size of the gap that must be filled, but
|
|
|
|
|
* its outside edge will shrink in by S, so we must start with
|
|
|
|
|
* 2S material to have S left after the shrink. Finally, one extra
|
|
|
|
|
* unit gets added because two pieces of material one radius apart
|
|
|
|
|
* can interact: to find all this material we must look one unit
|
|
|
|
|
* farther out for anything overlapping (the search routines only
|
|
|
|
|
* look for overlapping material and ignore abutting material).
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFTechFinal(void)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
CIFStyle *style = CIFCurStyle;
|
|
|
|
|
CIFOp *op;
|
|
|
|
|
int i, minReduce;
|
|
|
|
|
|
|
|
|
|
/* Allow the case where there's no CIF at all. This is indicated
|
|
|
|
|
* by a NULL CIFCurStyle.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if (!style) return;
|
|
|
|
|
|
|
|
|
|
if ((cifCurLayer != NULL) && (cifCurOp == NULL) && !cifGotLabels)
|
|
|
|
|
{
|
|
|
|
|
TechError("Layer \"%s\" contains no material.\n",
|
|
|
|
|
cifCurLayer->cl_name);
|
|
|
|
|
}
|
|
|
|
|
cifCurLayer = NULL;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If cs_expander > 1, then all CIF op values must be scaled accordingly.
|
|
|
|
|
* This routine loops through all CIF output styles.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
CIFTechOutputScale(1, 1);
|
|
|
|
|
|
|
|
|
|
if (style->cs_scaleFactor <= 0)
|
|
|
|
|
{
|
|
|
|
|
TechError("No valid scale factor was given for %s CIF.\n",
|
|
|
|
|
style->cs_name);
|
|
|
|
|
style->cs_scaleFactor = 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Make sure that all contact layers include stacked contact types
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < style->cs_nLayers; i++)
|
|
|
|
|
for (op = style->cs_layers[i]->cl_ops; op != NULL; op = op->co_next)
|
|
|
|
|
{
|
|
|
|
|
TileType d, s;
|
|
|
|
|
TileTypeBitMask *rMask;
|
|
|
|
|
|
|
|
|
|
for (d = TT_TECHDEPBASE; d < DBNumUserLayers; d++)
|
|
|
|
|
if (TTMaskHasType(&op->co_paintMask, d) && DBIsContact(d))
|
|
|
|
|
for (s = DBNumUserLayers; s < DBNumTypes; s++)
|
|
|
|
|
{
|
|
|
|
|
rMask = DBResidueMask(s);
|
|
|
|
|
if (TTMaskHasType(rMask, d))
|
|
|
|
|
TTMaskSetType(&op->co_paintMask, s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Find the largest reducer value which divides into all of the CIF values.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
minReduce = style->cs_scaleFactor;
|
|
|
|
|
for (i = 0; i < style->cs_nLayers; i++)
|
|
|
|
|
{
|
|
|
|
|
for (op = style->cs_layers[i]->cl_ops; op != NULL; op = op->co_next)
|
|
|
|
|
{
|
|
|
|
|
int j, c, bvalue;
|
|
|
|
|
if (op->co_distance > 0)
|
|
|
|
|
{
|
|
|
|
|
c = FindGCF(style->cs_scaleFactor, op->co_distance);
|
|
|
|
|
if (c < minReduce) minReduce = c;
|
|
|
|
|
}
|
|
|
|
|
if (op->co_client)
|
|
|
|
|
{
|
|
|
|
|
BloatData *bloats;
|
2020-06-11 22:40:01 +02:00
|
|
|
BridgeData *bridge;
|
2017-04-25 14:41:48 +02:00
|
|
|
SquaresData *squares;
|
|
|
|
|
SlotsData *slots;
|
|
|
|
|
if (op->co_opcode == CIFOP_SLOTS)
|
|
|
|
|
{
|
|
|
|
|
slots = (SlotsData *)op->co_client;
|
|
|
|
|
|
2019-11-20 19:36:03 +01:00
|
|
|
for (j = 0; j < 8; j++)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
switch (j) {
|
|
|
|
|
case 0: bvalue = slots->sl_sborder; break;
|
|
|
|
|
case 1: bvalue = slots->sl_ssize; break;
|
|
|
|
|
case 2: bvalue = slots->sl_ssep; break;
|
|
|
|
|
case 3: bvalue = slots->sl_lborder; break;
|
|
|
|
|
case 4: bvalue = slots->sl_lsize; break;
|
|
|
|
|
case 5: bvalue = slots->sl_lsep; break;
|
|
|
|
|
case 6: bvalue = slots->sl_offset; break;
|
2019-11-20 19:36:03 +01:00
|
|
|
case 7: bvalue = slots->sl_start; break;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
if (bvalue != 0)
|
|
|
|
|
{
|
|
|
|
|
if ((j == 1) || (j == 2) || (j == 4) || (j == 5))
|
|
|
|
|
{
|
|
|
|
|
if (bvalue & 0x1)
|
|
|
|
|
TxError("Internal error: slot size/sep %d"
|
|
|
|
|
" cannot be halved.\n", bvalue);
|
|
|
|
|
bvalue >>= 1;
|
|
|
|
|
}
|
|
|
|
|
c = FindGCF(style->cs_scaleFactor, bvalue);
|
|
|
|
|
if (c < minReduce) minReduce = c;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (op->co_opcode == CIFOP_SQUARES)
|
|
|
|
|
{
|
|
|
|
|
squares = (SquaresData *)op->co_client;
|
|
|
|
|
|
|
|
|
|
for (j = 0; j < 3; j++)
|
|
|
|
|
{
|
|
|
|
|
switch (j) {
|
|
|
|
|
case 0: bvalue = squares->sq_border; break;
|
|
|
|
|
case 1: bvalue = squares->sq_size; break;
|
|
|
|
|
case 2: bvalue = squares->sq_sep; break;
|
|
|
|
|
}
|
|
|
|
|
if (bvalue != 0)
|
|
|
|
|
{
|
|
|
|
|
if ((j == 1) || (j == 2))
|
|
|
|
|
{
|
|
|
|
|
if (bvalue & 0x1)
|
|
|
|
|
TxError("Internal error: contact size/sep %d"
|
|
|
|
|
" cannot be halved.\n", bvalue);
|
|
|
|
|
bvalue >>= 1;
|
|
|
|
|
}
|
|
|
|
|
c = FindGCF(style->cs_scaleFactor, bvalue);
|
|
|
|
|
if (c < minReduce) minReduce = c;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (op->co_opcode == CIFOP_SQUARES_G)
|
|
|
|
|
{
|
|
|
|
|
squares = (SquaresData *)op->co_client;
|
|
|
|
|
for (j = 0; j < TT_MAXTYPES; j++)
|
|
|
|
|
{
|
|
|
|
|
switch (j) {
|
|
|
|
|
case 0: bvalue = squares->sq_border; break;
|
|
|
|
|
case 1: bvalue = squares->sq_size; break;
|
|
|
|
|
case 2: bvalue = squares->sq_sep; break;
|
|
|
|
|
case 3: bvalue = squares->sq_gridx; break;
|
|
|
|
|
case 4: bvalue = squares->sq_gridy; break;
|
|
|
|
|
}
|
|
|
|
|
if (bvalue != 0)
|
|
|
|
|
{
|
|
|
|
|
c = FindGCF(style->cs_scaleFactor, bvalue);
|
|
|
|
|
if (c < minReduce) minReduce = c;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Presence of op->co_opcode in CIFOP_OR indicates a copy */
|
|
|
|
|
/* of the SquaresData pointer from a following operator */
|
|
|
|
|
/* CIFOP_BBOX and CIFOP_MAXRECT uses the co_client field */
|
2020-12-14 22:16:37 +01:00
|
|
|
/* as a flag field, while CIFOP_NET and CIFOP_MASKHINTS */
|
|
|
|
|
/* uses it for a string. */
|
2017-04-25 14:41:48 +02:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
switch (op->co_opcode)
|
|
|
|
|
{
|
|
|
|
|
case CIFOP_OR:
|
|
|
|
|
case CIFOP_BBOX:
|
2020-12-14 22:16:37 +01:00
|
|
|
case CIFOP_MASKHINTS:
|
2019-06-05 21:03:51 +02:00
|
|
|
case CIFOP_BOUNDARY:
|
2017-04-25 14:41:48 +02:00
|
|
|
case CIFOP_MAXRECT:
|
|
|
|
|
case CIFOP_NET:
|
|
|
|
|
break;
|
2020-07-27 22:40:31 +02:00
|
|
|
case CIFOP_BRIDGELIM:
|
2020-06-11 22:40:01 +02:00
|
|
|
case CIFOP_BRIDGE:
|
|
|
|
|
bridge = (BridgeData *)op->co_client;
|
|
|
|
|
c = FindGCF(style->cs_scaleFactor,
|
|
|
|
|
bridge->br_width);
|
|
|
|
|
if (c < minReduce) minReduce = c;
|
|
|
|
|
break;
|
2017-04-25 14:41:48 +02:00
|
|
|
default:
|
|
|
|
|
bloats = (BloatData *)op->co_client;
|
|
|
|
|
for (j = 0; j < TT_MAXTYPES; j++)
|
|
|
|
|
{
|
|
|
|
|
if (bloats->bl_distance[j] != 0)
|
|
|
|
|
{
|
|
|
|
|
c = FindGCF(style->cs_scaleFactor,
|
|
|
|
|
bloats->bl_distance[j]);
|
|
|
|
|
if (c < minReduce) minReduce = c;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (minReduce == 1) break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
style->cs_reducer = minReduce;
|
|
|
|
|
|
|
|
|
|
/* Debug info --- Tim, 1/3/02 */
|
|
|
|
|
/* TxPrintf("Output style %s: scaleFactor=%d, reducer=%d, expander=%d.\n",
|
|
|
|
|
style->cs_name, style->cs_scaleFactor,
|
|
|
|
|
style->cs_reducer, style->cs_expander); */
|
|
|
|
|
|
|
|
|
|
/* Compute grow and shrink distances for each layer,
|
|
|
|
|
* and remember the largest.
|
|
|
|
|
*/
|
|
|
|
|
cifComputeHalo(style);
|
|
|
|
|
|
|
|
|
|
/* Go through the layers to see which ones depend on which
|
|
|
|
|
* other ones. The purpose of this is so that we don't
|
|
|
|
|
* have to yank unnecessary layers in processing subcell
|
|
|
|
|
* interactions. Also find out which layers involve only
|
|
|
|
|
* a single OR operation, and remember the others specially
|
|
|
|
|
* (they'll require fancy CIF geometry processing).
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
for (i = style->cs_nLayers-1; i >= 0; i -= 1)
|
|
|
|
|
{
|
|
|
|
|
TileTypeBitMask ourDepend, ourYank;
|
|
|
|
|
bool needThisLayer;
|
|
|
|
|
int j;
|
|
|
|
|
|
|
|
|
|
ourDepend = DBZeroTypeBits;
|
|
|
|
|
ourYank = DBZeroTypeBits;
|
|
|
|
|
|
|
|
|
|
/* This layer must be computed hierarchically if it is needed
|
|
|
|
|
* by some other layer that is computed hierarchically, or if
|
|
|
|
|
* it includes operations that require hierarchical processing.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
needThisLayer = TTMaskHasType(&style->cs_hierLayers, i);
|
|
|
|
|
|
|
|
|
|
for (op = style->cs_layers[i]->cl_ops; op != NULL;
|
|
|
|
|
op = op->co_next)
|
|
|
|
|
{
|
|
|
|
|
BloatData *bloats;
|
|
|
|
|
|
|
|
|
|
TTMaskSetMask(&ourDepend, &op->co_cifMask);
|
|
|
|
|
TTMaskSetMask(&ourYank, &op->co_paintMask);
|
|
|
|
|
switch (op->co_opcode)
|
|
|
|
|
{
|
|
|
|
|
case CIFOP_BLOAT:
|
|
|
|
|
case CIFOP_BLOATMAX:
|
|
|
|
|
case CIFOP_BLOATMIN:
|
2020-06-17 04:54:48 +02:00
|
|
|
bloats = (BloatData *)op->co_client;
|
|
|
|
|
for (j = 0; j < TT_MAXTYPES; j++)
|
|
|
|
|
if (bloats->bl_distance[j] != bloats->bl_distance[TT_SPACE])
|
|
|
|
|
TTMaskSetType(&ourYank, j);
|
|
|
|
|
needThisLayer = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
case CIFOP_BLOATALL:
|
|
|
|
|
bloats = (BloatData *)op->co_client;
|
|
|
|
|
for (j = 0; j < TT_MAXTYPES; j++)
|
|
|
|
|
{
|
2020-06-17 04:54:48 +02:00
|
|
|
if (bloats->bl_distance[j] != 0)
|
2020-05-26 20:29:36 +02:00
|
|
|
{
|
2020-05-28 17:46:57 +02:00
|
|
|
if (bloats->bl_plane < 0)
|
2020-05-26 20:29:36 +02:00
|
|
|
TTMaskSetType(&ourDepend, j);
|
|
|
|
|
else
|
|
|
|
|
TTMaskSetType(&ourYank, j);
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
needThisLayer = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case CIFOP_AND:
|
|
|
|
|
case CIFOP_ANDNOT:
|
|
|
|
|
case CIFOP_SHRINK:
|
2020-06-11 22:40:01 +02:00
|
|
|
case CIFOP_CLOSE:
|
2020-07-27 22:40:31 +02:00
|
|
|
case CIFOP_BRIDGELIM:
|
2020-06-11 22:40:01 +02:00
|
|
|
case CIFOP_BRIDGE:
|
2017-04-25 14:41:48 +02:00
|
|
|
needThisLayer = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (needThisLayer)
|
|
|
|
|
{
|
|
|
|
|
TTMaskSetMask(&style->cs_yankLayers, &ourYank);
|
|
|
|
|
TTMaskSetType(&style->cs_hierLayers, i);
|
|
|
|
|
TTMaskSetMask(&style->cs_hierLayers, &ourDepend);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-16 23:41:42 +02:00
|
|
|
/* Added by Tim, 5/16/19 */
|
|
|
|
|
/* Layers that depend on hierarchically generated layers */
|
|
|
|
|
/* (i.e., templayers) must themselves be hierarchically */
|
|
|
|
|
/* processed. */
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < style->cs_nLayers; i++)
|
|
|
|
|
{
|
|
|
|
|
TileTypeBitMask ourDepend, mmask;
|
|
|
|
|
|
|
|
|
|
ourDepend = DBZeroTypeBits;
|
|
|
|
|
for (op = style->cs_layers[i]->cl_ops; op != NULL; op = op->co_next)
|
|
|
|
|
TTMaskSetMask(&ourDepend, &op->co_cifMask);
|
|
|
|
|
|
|
|
|
|
TTMaskAndMask3(&mmask, &ourDepend, &style->cs_hierLayers);
|
|
|
|
|
if (!TTMaskIsZero(&mmask))
|
|
|
|
|
TTMaskSetType(&style->cs_hierLayers, i);
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-17 18:14:41 +02:00
|
|
|
/* Added by Tim, 6/17/20: Do not set dependencies of BOUNDARY */
|
|
|
|
|
/* or BBOX because these are unable to be represented in a */
|
|
|
|
|
/* hierarchy without producing conflicting parent/child mask */
|
|
|
|
|
/* geometry. Generally, BOUNDARY and BBOX operations are */
|
|
|
|
|
/* intended to be restricted to the child cell and should not */
|
|
|
|
|
/* interact hierarchically. Possibly it would be useful to */
|
|
|
|
|
/* provide some method to preserve the bounding box information */
|
|
|
|
|
/* when flattening? */
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < style->cs_nLayers; i++)
|
|
|
|
|
{
|
|
|
|
|
for (op = style->cs_layers[i]->cl_ops; op != NULL; op = op->co_next)
|
|
|
|
|
{
|
|
|
|
|
if (op->co_opcode == CIFOP_BOUNDARY || op->co_opcode == CIFOP_BBOX)
|
|
|
|
|
{
|
|
|
|
|
TTMaskClearType(&style->cs_hierLayers, i);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Added by Tim, 10/18/04 */
|
|
|
|
|
|
|
|
|
|
/* Go through the layer operators looking for those that */
|
|
|
|
|
/* contain only OR operators followed by a single SQUARES */
|
|
|
|
|
/* operator. If found, set the clientdata record of the OR */
|
|
|
|
|
/* operator to be a copy of that for the SQUARES operator. */
|
|
|
|
|
/* This is used by the GDS generator when the "gds contact */
|
|
|
|
|
/* on" option is enabled (CalmaContactArrays is TRUE) to */
|
|
|
|
|
/* translate contact areas into contact subcell arrays. */
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < style->cs_nLayers; i++)
|
|
|
|
|
{
|
|
|
|
|
ClientData clientdata;
|
|
|
|
|
for (op = style->cs_layers[i]->cl_ops; (op != NULL) &&
|
|
|
|
|
(op->co_opcode == CIFOP_OR) &&
|
|
|
|
|
(TTMaskIsZero(&op->co_cifMask)); op = op->co_next);
|
2022-11-10 20:08:58 +01:00
|
|
|
if (op && ((op->co_opcode == CIFOP_SQUARES) ||
|
2022-11-10 20:46:26 +01:00
|
|
|
(op->co_opcode == CIFOP_SQUARES_G)) && (op->co_next == NULL))
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
clientdata = op->co_client;
|
|
|
|
|
for (op = style->cs_layers[i]->cl_ops; op->co_opcode == CIFOP_OR;
|
|
|
|
|
op = op->co_next)
|
|
|
|
|
{
|
|
|
|
|
/* Copy the client record from the CIFOP_SQUARES operator
|
|
|
|
|
* into the CIFOP_OR operator.
|
|
|
|
|
*/
|
|
|
|
|
op->co_client = clientdata;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Uncomment this code to print out information about which
|
|
|
|
|
* layers have to be processed hierarchically.
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < DBNumUserLayers; i++)
|
|
|
|
|
{
|
|
|
|
|
if (TTMaskHasType(&style->cs_yankLayers, i))
|
|
|
|
|
TxPrintf("Will have to yank %s in style %s.\n",
|
|
|
|
|
DBTypeLongName(i), style->cs_name);
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < CIFCurStyle->cs_nLayers; i++)
|
|
|
|
|
{
|
|
|
|
|
if (TTMaskHasType(&style->cs_hierLayers, i))
|
|
|
|
|
TxPrintf("Layer %s must be processed hierarchically.\n",
|
|
|
|
|
style->cs_layers[i]->cl_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFLoadStyle --
|
|
|
|
|
*
|
|
|
|
|
* Re-read the technology file to load the specified technology cif output
|
|
|
|
|
* style into structure CIFCurStyle. This is much more memory-efficient than
|
|
|
|
|
* keeping a separate structure for each cif output style. It incurs a complete
|
|
|
|
|
* reading of the tech file on startup and every time the cif output 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 output
|
|
|
|
|
* style is changed by a call to "cif ostyle".
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFLoadStyle(
|
|
|
|
|
char *stylename)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
SectionID invcif;
|
|
|
|
|
|
2019-10-15 22:24:49 +02:00
|
|
|
if (CIFCurStyle && (CIFCurStyle->cs_name == stylename)) return;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
cifTechNewStyle();
|
|
|
|
|
CIFCurStyle->cs_name = stylename;
|
|
|
|
|
|
|
|
|
|
invcif = TechSectionGetMask("cifoutput", NULL);
|
|
|
|
|
TechLoad(NULL, invcif);
|
|
|
|
|
|
|
|
|
|
/* CIFTechFinal(); */ /* handled by TechLoad() */
|
|
|
|
|
CIFTechOutputScale(DBLambda[0], DBLambda[1]);
|
|
|
|
|
|
|
|
|
|
/* If the DRC section makes reference to CIF layers, then */
|
|
|
|
|
/* we need to re-read the DRC section as well. */
|
|
|
|
|
|
|
|
|
|
if ((DRCForceReload == TRUE) && (DRCCurStyle != NULL))
|
|
|
|
|
DRCReloadCurStyle();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFGetContactSize --
|
|
|
|
|
*
|
|
|
|
|
* Return the smallest allowable contact size in lambda units corresponding
|
|
|
|
|
* to the "squares" function operating on the indicated type. This value
|
|
|
|
|
* is computed as the (cut size) + 2 * (cut border).
|
|
|
|
|
*
|
|
|
|
|
* 9/12/2013: Added "squares-grid" and "slots" to the functions understood
|
|
|
|
|
* by the routine. "squares-grid" behaves the same as "squares". "slots"
|
|
|
|
|
* can be used for contact cuts with differing metal overlap on different
|
|
|
|
|
* sides. Normally this would define a square slot; this routine finds
|
|
|
|
|
* the minimum cut size for the slot.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Contact minimum dimension, in CIF/GDS units
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* If any of edge, border, or spacing is non-NULL, the appropriate
|
|
|
|
|
* cut dimension is filled in.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFGetContactSize(
|
|
|
|
|
TileType type,
|
|
|
|
|
int *edge,
|
|
|
|
|
int *spacing,
|
|
|
|
|
int *border)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
CIFStyle *style = CIFCurStyle;
|
|
|
|
|
CIFOp *op, *sop;
|
|
|
|
|
int i;
|
|
|
|
|
SquaresData *squares;
|
|
|
|
|
SlotsData *slots;
|
|
|
|
|
|
|
|
|
|
if (style == NULL)
|
|
|
|
|
{
|
|
|
|
|
edge = spacing = border = 0;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < style->cs_nLayers; i++)
|
|
|
|
|
{
|
|
|
|
|
for (op = style->cs_layers[i]->cl_ops; (op != NULL) &&
|
|
|
|
|
(op->co_opcode == CIFOP_OR) &&
|
|
|
|
|
(TTMaskIsZero(&op->co_cifMask)); op = op->co_next)
|
|
|
|
|
if (TTMaskHasType(&op->co_paintMask, type))
|
|
|
|
|
for (sop = op->co_next; sop != NULL; sop = sop->co_next)
|
|
|
|
|
{
|
|
|
|
|
if (sop->co_opcode == CIFOP_SQUARES ||
|
|
|
|
|
sop->co_opcode == CIFOP_SQUARES_G)
|
|
|
|
|
{
|
|
|
|
|
squares = (SquaresData *)sop->co_client;
|
|
|
|
|
if (edge != NULL) *edge = squares->sq_size;
|
|
|
|
|
if (border != NULL) *border = squares->sq_border;
|
|
|
|
|
if (spacing != NULL) *spacing = squares->sq_sep;
|
|
|
|
|
return (squares->sq_size + (squares->sq_border << 1));
|
|
|
|
|
}
|
|
|
|
|
else if (sop->co_opcode == CIFOP_SLOTS)
|
|
|
|
|
{
|
|
|
|
|
slots = (SlotsData *)sop->co_client;
|
|
|
|
|
if (edge != NULL) *edge = slots->sl_ssize;
|
|
|
|
|
if (border != NULL) *border = slots->sl_sborder;
|
|
|
|
|
if (spacing != NULL) *spacing = slots->sl_ssep;
|
|
|
|
|
return (slots->sl_ssize + (slots->sl_sborder << 1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Anything other than an OR function will break */
|
|
|
|
|
/* the relationship between magic layers and cuts. */
|
2020-07-31 20:11:24 +02:00
|
|
|
/* NOTE: Making an exception for AND_NOT, which is */
|
|
|
|
|
/* used to distinguish between small and large via */
|
|
|
|
|
/* areas. */
|
|
|
|
|
else if ((sop->co_opcode != CIFOP_OR) &&
|
|
|
|
|
(sop->co_opcode != CIFOP_ANDNOT))
|
2017-04-25 14:41:48 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* CIFTechOutputScale(n, d) --
|
|
|
|
|
*
|
|
|
|
|
* Scale all CIF output scale factors to make them equivalent
|
|
|
|
|
* to reducing the magic internal unit spacing by a factor of n/d.
|
|
|
|
|
* It is important not to reduce the scaleFactor to zero! So, we
|
|
|
|
|
* multiply scaleFactor by n and the expander by d, then reduce
|
|
|
|
|
* the fraction using the FindGCF routine (utils/fraction.c).
|
|
|
|
|
*
|
|
|
|
|
* Because all CIF operation distances (grow, shrink, bloat, squares)
|
|
|
|
|
* are in units of centimicrons multiplied by the expander (e.g.,
|
|
|
|
|
* expander = 10 means units are in nanometers), we need to rescale them
|
|
|
|
|
* by the expander. To optimize CIF output, the fraction scale/expander
|
|
|
|
|
* is reduced to minimize expander; that is, to make the numbers in the
|
|
|
|
|
* CIF output as small as possible while making sure all output can be
|
|
|
|
|
* represented by integers.
|
|
|
|
|
*
|
|
|
|
|
* Note that because contacts may be placed at 1/2 grid spacing to
|
2020-05-23 23:13:14 +02:00
|
|
|
* center them, the size and spacing of contacts as given in the
|
2017-04-25 14:41:48 +02:00
|
|
|
* "squares" function must *always* be an even number. To ensure this,
|
|
|
|
|
* we check for odd numbers in these positions. If there are any, and
|
|
|
|
|
* "d" is also an odd number, then we multiply both "n" and "d" by 2.
|
|
|
|
|
*
|
|
|
|
|
* (Added 2/23/05)---The above is not sufficient! If the contact size
|
|
|
|
|
* is an odd number, then centering may not be possible even if all
|
|
|
|
|
* the contact parameters are even numbers. e.g., for size=22 in a 0.18
|
|
|
|
|
* process (scalefactor=9), a 5x5 lambda contact is 45x45 centimicrons.
|
|
|
|
|
* 45 - 22 = 23, so border is 11.5 centimicrons. Therefore, when
|
|
|
|
|
* the scalefactor is even, the contact size must be even, but when the
|
|
|
|
|
* scalefactor is odd, then we have to multiply both "n" and "d" by 2
|
|
|
|
|
* regardless, since contact areas may be either odd or even (compare
|
|
|
|
|
* the above example to one where the contact is drawn 6x6 lambda).
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
K&R: cif/*.c bulk function implementation conversion
Beware of the MISMATCH with the prototype found in original
source, with the type declaration below.
External call sites checked to confirm argument order is
correct with the argument name order.
// nedges <> dir
bool
cifOrient(edges, nedges, dir)
CIFPath *edges[], /* Array of edges to be categorized. */
int dir[], /* Array to hold directions. */
int nedges) /* Size of arrays. */
// spacing <> border
int
CIFGetContactSize(type, edge, spacing, border)
TileType type,
int *edge,
int *border,
int *spacing)
K&R obsolete syntax removal for C23 compatibility series
2024-10-04 12:34:19 +02:00
|
|
|
CIFTechOutputScale(
|
|
|
|
|
int n,
|
|
|
|
|
int d)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
int i, j, lgcf, lexpand;
|
|
|
|
|
CIFStyle *ostyle = CIFCurStyle;
|
|
|
|
|
CIFLayer *cl;
|
|
|
|
|
CIFOp *op;
|
|
|
|
|
SquaresData *squares;
|
|
|
|
|
SlotsData *slots;
|
|
|
|
|
BloatData *bloats;
|
2020-06-11 22:40:01 +02:00
|
|
|
BridgeData *bridge;
|
2020-03-10 01:44:03 +01:00
|
|
|
bool has_odd_space = FALSE;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
if (ostyle == NULL) return;
|
|
|
|
|
|
|
|
|
|
/* For contact half-grid centering, check for odd numbers. . . */
|
|
|
|
|
|
|
|
|
|
if (ostyle->cs_scaleFactor & 0x1)
|
|
|
|
|
{
|
|
|
|
|
n *= 2;
|
|
|
|
|
d *= 2;
|
|
|
|
|
has_odd_space = TRUE;
|
|
|
|
|
}
|
|
|
|
|
else if (d & 0x1)
|
|
|
|
|
{
|
|
|
|
|
has_odd_space = FALSE;
|
|
|
|
|
for (i = 0; i < ostyle->cs_nLayers; i++)
|
|
|
|
|
{
|
|
|
|
|
cl = ostyle->cs_layers[i];
|
|
|
|
|
for (op = cl->cl_ops; op != NULL; op = op->co_next)
|
|
|
|
|
{
|
|
|
|
|
if (op->co_opcode == CIFOP_SQUARES)
|
|
|
|
|
{
|
|
|
|
|
squares = (SquaresData *)op->co_client;
|
|
|
|
|
if ((squares->sq_size & 0x01) || (squares->sq_sep & 0x01))
|
|
|
|
|
{
|
|
|
|
|
has_odd_space = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (op->co_opcode == CIFOP_SLOTS)
|
|
|
|
|
{
|
|
|
|
|
slots = (SlotsData *)op->co_client;
|
|
|
|
|
if ((slots->sl_lsize & 0x01) || (slots->sl_lsep & 0x01)
|
|
|
|
|
|| (slots->sl_ssize & 0x01) || (slots->sl_ssep & 0x01))
|
|
|
|
|
{
|
|
|
|
|
has_odd_space = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (has_odd_space)
|
|
|
|
|
{
|
|
|
|
|
n *= 2;
|
|
|
|
|
d *= 2;
|
|
|
|
|
has_odd_space = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* fprintf(stderr, "CIFTechOutputScale(%d, %d)\n", n, d); */
|
|
|
|
|
|
|
|
|
|
ostyle->cs_scaleFactor *= n;
|
|
|
|
|
ostyle->cs_expander *= d;
|
|
|
|
|
|
|
|
|
|
/* fprintf(stderr, "CIFStyle %s:\n", ostyle->cs_name); */
|
|
|
|
|
|
|
|
|
|
lexpand = ostyle->cs_expander;
|
|
|
|
|
for (i = 0; i < ostyle->cs_nLayers; i++)
|
|
|
|
|
{
|
|
|
|
|
cl = ostyle->cs_layers[i];
|
|
|
|
|
for (op = cl->cl_ops; op != NULL; op = op->co_next)
|
|
|
|
|
{
|
|
|
|
|
if (op->co_distance)
|
|
|
|
|
{
|
|
|
|
|
op->co_distance *= d;
|
|
|
|
|
lgcf = FindGCF(abs(op->co_distance), ostyle->cs_expander);
|
|
|
|
|
lexpand = FindGCF(lexpand, lgcf);
|
|
|
|
|
}
|
|
|
|
|
if (op->co_client)
|
|
|
|
|
{
|
|
|
|
|
int bvalue, *bptr;
|
|
|
|
|
if (op->co_opcode == CIFOP_SQUARES)
|
|
|
|
|
{
|
|
|
|
|
squares = (SquaresData *)op->co_client;
|
|
|
|
|
for (j = 0; j < 3; j++)
|
|
|
|
|
{
|
|
|
|
|
switch (j) {
|
|
|
|
|
case 0: bptr = &squares->sq_border; break;
|
|
|
|
|
case 1: bptr = &squares->sq_size; break;
|
|
|
|
|
case 2: bptr = &squares->sq_sep; break;
|
|
|
|
|
}
|
|
|
|
|
if (*bptr != 0)
|
|
|
|
|
{
|
|
|
|
|
(*bptr) *= d;
|
|
|
|
|
bvalue = abs(*bptr);
|
|
|
|
|
if ((j == 1) || (j == 2)) bvalue >>= 1; /* half-grid */
|
|
|
|
|
if (has_odd_space) bvalue >>= 1; /* force half-grid */
|
|
|
|
|
lgcf = FindGCF(bvalue, ostyle->cs_expander);
|
|
|
|
|
lexpand = FindGCF(lexpand, lgcf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (op->co_opcode == CIFOP_SLOTS)
|
|
|
|
|
{
|
|
|
|
|
slots = (SlotsData *)op->co_client;
|
2019-11-20 19:36:03 +01:00
|
|
|
for (j = 0; j < 8; j++)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
switch (j) {
|
|
|
|
|
case 0: bptr = &slots->sl_sborder; break;
|
|
|
|
|
case 1: bptr = &slots->sl_ssize; break;
|
|
|
|
|
case 2: bptr = &slots->sl_ssep; break;
|
|
|
|
|
case 3: bptr = &slots->sl_lborder; break;
|
|
|
|
|
case 4: bptr = &slots->sl_lsize; break;
|
|
|
|
|
case 5: bptr = &slots->sl_lsep; break;
|
|
|
|
|
case 6: bptr = &slots->sl_offset; break;
|
2019-11-20 19:36:03 +01:00
|
|
|
case 7: bptr = &slots->sl_start; break;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
if (*bptr != 0)
|
|
|
|
|
{
|
|
|
|
|
(*bptr) *= d;
|
|
|
|
|
bvalue = abs(*bptr);
|
|
|
|
|
if ((j == 1) || (j == 2) || (j == 4) || (j == 5))
|
|
|
|
|
bvalue >>= 1; /* half-grid */
|
|
|
|
|
if (has_odd_space) bvalue >>= 1; /* force half-grid */
|
|
|
|
|
lgcf = FindGCF(bvalue, ostyle->cs_expander);
|
|
|
|
|
lexpand = FindGCF(lexpand, lgcf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (op->co_opcode == CIFOP_SQUARES_G)
|
|
|
|
|
{
|
|
|
|
|
squares = (SquaresData *)op->co_client;
|
|
|
|
|
for (j = 0; j < 5; j++)
|
|
|
|
|
{
|
|
|
|
|
switch (j) {
|
|
|
|
|
case 0: bptr = &squares->sq_border; break;
|
|
|
|
|
case 1: bptr = &squares->sq_size; break;
|
|
|
|
|
case 2: bptr = &squares->sq_sep; break;
|
|
|
|
|
case 3: bptr = &squares->sq_gridx; break;
|
|
|
|
|
case 4: bptr = &squares->sq_gridy; break;
|
|
|
|
|
}
|
|
|
|
|
if (*bptr != 0)
|
|
|
|
|
{
|
|
|
|
|
(*bptr) *= d;
|
|
|
|
|
lgcf = FindGCF(abs(*bptr), ostyle->cs_expander);
|
|
|
|
|
lexpand = FindGCF(lexpand, lgcf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Presence of op->co_opcode in CIFOP_OR indicates a copy */
|
|
|
|
|
/* of the SquaresData pointer from a following operator */
|
|
|
|
|
/* CIFOP_BBOX uses the co_client field as a flag field. */
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
switch (op->co_opcode)
|
|
|
|
|
{
|
|
|
|
|
case CIFOP_OR:
|
|
|
|
|
case CIFOP_BBOX:
|
2019-06-05 21:03:51 +02:00
|
|
|
case CIFOP_BOUNDARY:
|
2020-12-14 22:16:37 +01:00
|
|
|
case CIFOP_MASKHINTS:
|
2017-04-25 14:41:48 +02:00
|
|
|
case CIFOP_MAXRECT:
|
|
|
|
|
case CIFOP_NET:
|
|
|
|
|
break;
|
2020-07-27 22:40:31 +02:00
|
|
|
case CIFOP_BRIDGELIM:
|
2020-06-11 22:40:01 +02:00
|
|
|
case CIFOP_BRIDGE:
|
|
|
|
|
bridge = (BridgeData *)op->co_client;
|
|
|
|
|
bridge->br_width *= d;
|
|
|
|
|
lgcf = FindGCF(abs(bridge->br_width),
|
|
|
|
|
ostyle->cs_expander);
|
|
|
|
|
lexpand = FindGCF(lexpand, lgcf);
|
|
|
|
|
break;
|
2017-04-25 14:41:48 +02:00
|
|
|
default:
|
|
|
|
|
bloats = (BloatData *)op->co_client;
|
|
|
|
|
for (j = 0; j < TT_MAXTYPES; j++)
|
|
|
|
|
{
|
|
|
|
|
if (bloats->bl_distance[j] != 0)
|
|
|
|
|
{
|
|
|
|
|
bloats->bl_distance[j] *= d;
|
|
|
|
|
lgcf = FindGCF(abs(bloats->bl_distance[j]),
|
|
|
|
|
ostyle->cs_expander);
|
|
|
|
|
lexpand = FindGCF(lexpand, lgcf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* time-saving quick check */
|
|
|
|
|
if ((lexpand == 1) && (d == 1)) break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Recompute drc-cif rule distances */
|
|
|
|
|
drcCifScale(d, 1);
|
|
|
|
|
|
|
|
|
|
/* Reduce the scale and all distances by the greatest common */
|
|
|
|
|
/* factor of everything. */
|
|
|
|
|
|
2021-01-24 19:29:20 +01:00
|
|
|
/* fprintf(stderr, "All CIF units divisible by %d\n", lexpand); */
|
2017-04-25 14:41:48 +02:00
|
|
|
/* fflush(stderr); */
|
|
|
|
|
|
|
|
|
|
lgcf = FindGCF(ostyle->cs_scaleFactor, ostyle->cs_expander);
|
|
|
|
|
if (lgcf < lexpand) lexpand = lgcf;
|
|
|
|
|
if (lexpand <= 1) return;
|
|
|
|
|
|
|
|
|
|
/* fprintf(stderr, "Expander goes from %d to %d\n", ostyle->cs_expander,
|
|
|
|
|
ostyle->cs_expander / lexpand); */
|
|
|
|
|
/* fprintf(stderr, "All CIF op distances are divided by %d\n", lexpand); */
|
|
|
|
|
/* fflush(stderr); */
|
|
|
|
|
|
|
|
|
|
ostyle->cs_scaleFactor /= lexpand;
|
|
|
|
|
ostyle->cs_expander /= lexpand;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ostyle->cs_nLayers; i++)
|
|
|
|
|
{
|
|
|
|
|
cl = ostyle->cs_layers[i];
|
|
|
|
|
for (op = cl->cl_ops; op != NULL; op = op->co_next)
|
|
|
|
|
{
|
|
|
|
|
if (op->co_distance)
|
|
|
|
|
op->co_distance /= lexpand;
|
|
|
|
|
|
|
|
|
|
if (op->co_client)
|
|
|
|
|
{
|
|
|
|
|
int nlayers;
|
|
|
|
|
switch (op->co_opcode)
|
|
|
|
|
{
|
|
|
|
|
case CIFOP_SLOTS:
|
|
|
|
|
slots = (SlotsData *)op->co_client;
|
|
|
|
|
if (slots->sl_sborder != 0)
|
|
|
|
|
slots->sl_sborder /= lexpand;
|
|
|
|
|
if (slots->sl_ssize != 0)
|
|
|
|
|
slots->sl_ssize /= lexpand;
|
|
|
|
|
if (slots->sl_ssep != 0)
|
|
|
|
|
slots->sl_ssep /= lexpand;
|
|
|
|
|
if (slots->sl_lborder != 0)
|
|
|
|
|
slots->sl_lborder /= lexpand;
|
|
|
|
|
if (slots->sl_lsize != 0)
|
|
|
|
|
slots->sl_lsize /= lexpand;
|
|
|
|
|
if (slots->sl_lsep != 0)
|
|
|
|
|
slots->sl_lsep /= lexpand;
|
|
|
|
|
if (slots->sl_offset != 0)
|
|
|
|
|
slots->sl_offset /= lexpand;
|
2019-11-20 19:36:03 +01:00
|
|
|
if (slots->sl_start != 0)
|
|
|
|
|
slots->sl_start /= lexpand;
|
2017-04-25 14:41:48 +02:00
|
|
|
break;
|
|
|
|
|
case CIFOP_SQUARES_G:
|
|
|
|
|
squares = (SquaresData *)op->co_client;
|
|
|
|
|
if (squares->sq_gridx != 0)
|
|
|
|
|
squares->sq_gridx /= lexpand;
|
|
|
|
|
if (squares->sq_gridy != 0)
|
|
|
|
|
squares->sq_gridy /= lexpand;
|
|
|
|
|
/* (drop through) */
|
|
|
|
|
case CIFOP_SQUARES:
|
|
|
|
|
squares = (SquaresData *)op->co_client;
|
|
|
|
|
if (squares->sq_border != 0)
|
|
|
|
|
squares->sq_border /= lexpand;
|
|
|
|
|
if (squares->sq_size != 0)
|
|
|
|
|
squares->sq_size /= lexpand;
|
|
|
|
|
if (squares->sq_sep != 0)
|
|
|
|
|
squares->sq_sep /= lexpand;
|
|
|
|
|
break;
|
|
|
|
|
case CIFOP_BLOAT:
|
|
|
|
|
case CIFOP_BLOATMIN:
|
|
|
|
|
case CIFOP_BLOATMAX:
|
|
|
|
|
bloats = (BloatData *)op->co_client;
|
|
|
|
|
for (j = 0; j < TT_MAXTYPES; j++)
|
|
|
|
|
if (bloats->bl_distance[j] != 0)
|
|
|
|
|
bloats->bl_distance[j] /= lexpand;
|
|
|
|
|
break;
|
2020-07-27 22:40:31 +02:00
|
|
|
case CIFOP_BRIDGELIM:
|
2020-06-11 22:40:01 +02:00
|
|
|
case CIFOP_BRIDGE:
|
|
|
|
|
bridge = (BridgeData *)op->co_client;
|
|
|
|
|
bridge->br_width /= lexpand;
|
|
|
|
|
break;
|
2017-04-25 14:41:48 +02:00
|
|
|
default:
|
2020-12-14 22:16:37 +01:00
|
|
|
/* op->co_opcode in CIFOP_OR is a pointer copy, */
|
|
|
|
|
/* in CIFOP_BBOX and CIFOP_MAXRECT is a flag, */
|
|
|
|
|
/* and in CIFOP_NET and CIFOP_MASKHINTS is a */
|
|
|
|
|
/* string. */
|
2017-04-25 14:41:48 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Recompute drc-cif rule distances */
|
|
|
|
|
drcCifScale(1, lexpand);
|
|
|
|
|
|
|
|
|
|
/* Recompute value of cs_radius */
|
|
|
|
|
cifComputeHalo(ostyle);
|
|
|
|
|
}
|