2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* DRCcif.c --
|
|
|
|
|
*
|
|
|
|
|
******************************************************************************
|
|
|
|
|
* Copyright (C) 1989 Digital Equipment Corporation
|
|
|
|
|
* 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. Digital Equipment Corporation
|
|
|
|
|
* makes no representations about the suitability of this
|
|
|
|
|
* software for any purpose. It is provided "as is" without
|
|
|
|
|
* express or implied warranty.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
|
|
|
|
|
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
|
|
|
|
|
* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
|
|
|
|
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
|
|
|
|
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
|
|
|
|
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
|
|
|
|
* SOFTWARE.
|
|
|
|
|
****************************************************************************
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef lint
|
|
|
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/drc/DRCcif.c,v 1.5 2010/10/20 20:34:20 tim Exp $";
|
|
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
|
|
#include "utils/magic.h"
|
|
|
|
|
#include "utils/geometry.h"
|
|
|
|
|
#include "tiles/tile.h"
|
|
|
|
|
#include "utils/hash.h"
|
|
|
|
|
#include "database/database.h"
|
|
|
|
|
#include "windows/windows.h"
|
|
|
|
|
#include "dbwind/dbwind.h"
|
|
|
|
|
#include "dbwind/dbwtech.h"
|
|
|
|
|
#include "drc/drc.h"
|
|
|
|
|
#include "cif/cif.h"
|
|
|
|
|
#include "cif/CIFint.h"
|
|
|
|
|
#include "utils/signals.h"
|
|
|
|
|
#include "utils/stack.h"
|
|
|
|
|
#include "utils/malloc.h"
|
|
|
|
|
#include "utils/utils.h"
|
|
|
|
|
|
|
|
|
|
extern int drcCifTile();
|
|
|
|
|
extern int areaCifCheck();
|
|
|
|
|
extern void drcCheckCifMaxwidth();
|
|
|
|
|
extern void drcCheckCifArea();
|
|
|
|
|
|
|
|
|
|
extern Stack *DRCstack;
|
|
|
|
|
|
|
|
|
|
#define PUSHTILE(tp) \
|
|
|
|
|
if ((tp)->ti_client == (ClientData) DRC_UNPROCESSED) { \
|
|
|
|
|
(tp)->ti_client = (ClientData) DRC_PENDING; \
|
|
|
|
|
STACKPUSH((ClientData) (tp), DRCstack); \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extern CIFStyle *drcCifStyle;
|
|
|
|
|
extern bool DRCForceReload;
|
|
|
|
|
TileTypeBitMask drcCifGenLayers;
|
|
|
|
|
|
|
|
|
|
DRCCookie *drcCifRules[MAXCIFLAYERS][2];
|
2019-10-15 22:24:49 +02:00
|
|
|
DRCCookie *drcCifCur = NULL;
|
2017-04-25 14:41:48 +02:00
|
|
|
int drcCifValid = FALSE;
|
2019-10-15 22:24:49 +02:00
|
|
|
bool beenWarned = FALSE;
|
|
|
|
|
char *drcNeedStyle = NULL;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
#define DRC_CIF_SPACE 0
|
|
|
|
|
#define DRC_CIF_SOLID 1
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* drcCifSetStyle --
|
|
|
|
|
*
|
|
|
|
|
* Process a declaration of the cif style.
|
|
|
|
|
* This is of the form:
|
|
|
|
|
*
|
|
|
|
|
* cifstyle cif_style
|
|
|
|
|
*
|
|
|
|
|
* e.g,
|
|
|
|
|
*
|
|
|
|
|
* cifstyle pg
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns 0.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Updates drcCifStyle. Do NOT attempt to update the CIF style
|
|
|
|
|
* in the middle of reading the DRC section. Instead, if the
|
|
|
|
|
* reported CIF style is not current, flag a warning. The DRC
|
|
|
|
|
* will be re-read with the CIF extensions when the CIF output
|
|
|
|
|
* style is changed.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
drcCifSetStyle(argc, argv)
|
|
|
|
|
int argc;
|
|
|
|
|
char *argv[];
|
|
|
|
|
{
|
|
|
|
|
CIFKeep *new;
|
|
|
|
|
|
|
|
|
|
for (new = CIFStyleList; new != NULL; new = new->cs_next)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp(new->cs_name, argv[1]))
|
|
|
|
|
{
|
2019-10-15 22:24:49 +02:00
|
|
|
drcNeedStyle = new->cs_name;
|
2017-04-25 14:41:48 +02:00
|
|
|
DRCForceReload = TRUE;
|
|
|
|
|
if (!strcmp(new->cs_name, CIFCurStyle->cs_name))
|
|
|
|
|
drcCifStyle = CIFCurStyle;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
drcCifStyle = NULL;
|
|
|
|
|
beenWarned = TRUE; /* post no more error messages */
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
TechError("Unknown DRC cifstyle %s\n",argv[1]);
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
drcCifWarning()
|
|
|
|
|
{
|
|
|
|
|
if (!beenWarned)
|
|
|
|
|
{
|
|
|
|
|
TechError("Missing cif style for drc\n\t"
|
|
|
|
|
"This message will not be repeated.\n");
|
|
|
|
|
beenWarned = TRUE;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* drcCifWidth -- same this as drcCifWidth, except that it works on
|
|
|
|
|
* cif layers
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns distance.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Updates the DRC technology variables.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
drcCifWidth(argc, argv)
|
|
|
|
|
int argc;
|
|
|
|
|
char *argv[];
|
|
|
|
|
{
|
|
|
|
|
char *layername = argv[1];
|
|
|
|
|
int scalefactor;
|
|
|
|
|
int centidistance = atoi(argv[2]);
|
2020-02-25 19:57:41 +01:00
|
|
|
int why = drcWhyCreate(argv[3]);
|
2017-04-25 14:41:48 +02:00
|
|
|
TileTypeBitMask set, setC, tmp1;
|
|
|
|
|
int thislayer = -1;
|
|
|
|
|
DRCCookie *dpnew,*dpnext;
|
|
|
|
|
TileType i;
|
|
|
|
|
|
|
|
|
|
if (drcCifStyle == NULL)
|
|
|
|
|
return drcCifWarning();
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < drcCifStyle->cs_nLayers;i++)
|
|
|
|
|
{
|
|
|
|
|
CIFLayer *layer = drcCifStyle->cs_layers[i];
|
|
|
|
|
|
|
|
|
|
if (strcmp(layer->cl_name,layername) == 0)
|
|
|
|
|
{
|
|
|
|
|
thislayer = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (thislayer == -1)
|
|
|
|
|
{
|
|
|
|
|
TechError("Unknown cif layer: %s\n",layername);
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scalefactor = drcCifStyle->cs_scaleFactor;
|
|
|
|
|
centidistance *= drcCifStyle->cs_expander; // BSI
|
|
|
|
|
|
|
|
|
|
dpnext = drcCifRules[thislayer][DRC_CIF_SPACE];
|
|
|
|
|
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
2019-09-19 20:33:30 +02:00
|
|
|
drcCifAssign(dpnew, centidistance, dpnext, &CIFSolidBits,
|
2017-04-25 14:41:48 +02:00
|
|
|
&CIFSolidBits, why, centidistance,
|
|
|
|
|
DRC_FORWARD, thislayer, 0);
|
|
|
|
|
drcCifRules[thislayer][DRC_CIF_SPACE] = dpnew;
|
|
|
|
|
|
|
|
|
|
return ((centidistance+scalefactor-1)/scalefactor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* drcCifSpacing -- same this as drcSpacing, except that it works on cif
|
|
|
|
|
* layers.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns distance.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Updates the DRC technology variables.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
drcCifSpacing(argc, argv)
|
|
|
|
|
int argc;
|
|
|
|
|
char *argv[];
|
|
|
|
|
{
|
|
|
|
|
char *adjacency = argv[4];
|
2020-02-25 19:57:41 +01:00
|
|
|
int why = drcWhyCreate(argv[5]);
|
2017-04-25 14:41:48 +02:00
|
|
|
DRCCookie *dpnext, *dpnew;
|
|
|
|
|
int needReverse = FALSE;
|
|
|
|
|
TileType i, j;
|
|
|
|
|
int scalefactor;
|
|
|
|
|
int centidistance = atoi(argv[3]);
|
|
|
|
|
char *layers[2];
|
|
|
|
|
TileType layer[2];
|
|
|
|
|
TileTypeBitMask cmask;
|
|
|
|
|
int k;
|
|
|
|
|
|
|
|
|
|
layers[0] = argv[1];
|
|
|
|
|
layers[1] = argv[2];
|
|
|
|
|
|
|
|
|
|
if (drcCifStyle == NULL)
|
|
|
|
|
return drcCifWarning();
|
|
|
|
|
|
|
|
|
|
for (k=0; k!= 2;k++)
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; i < drcCifStyle->cs_nLayers;i++)
|
|
|
|
|
{
|
|
|
|
|
CIFLayer *l = drcCifStyle->cs_layers[i];
|
|
|
|
|
|
|
|
|
|
if (strcmp(l->cl_name,layers[k]) == 0)
|
|
|
|
|
{
|
|
|
|
|
layer[k]=i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (i == drcCifStyle->cs_nLayers || layer[k] == -1)
|
|
|
|
|
{
|
|
|
|
|
TechError("Unknown cif layer: %s",layers[k]);
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (strcmp (adjacency, "touching_ok") == 0)
|
|
|
|
|
{
|
|
|
|
|
/* If touching is OK, everything must fall in the same plane. */
|
|
|
|
|
if (layer[0] != layer[1])
|
|
|
|
|
{
|
|
|
|
|
TechError(
|
|
|
|
|
"Spacing check with touching ok must all be in one plane.\n");
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
cmask = DBSpaceBits;
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp (adjacency, "touching_illegal") == 0)
|
|
|
|
|
{
|
|
|
|
|
cmask = DBAllTypeBits;
|
|
|
|
|
needReverse = TRUE;
|
|
|
|
|
/* nothing for now */
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
TechError("Badly formed drc spacing line\n");
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scalefactor = drcCifStyle->cs_scaleFactor;
|
|
|
|
|
centidistance *= drcCifStyle->cs_expander; // BSI
|
|
|
|
|
dpnext = drcCifRules[layer[0]][DRC_CIF_SOLID];
|
|
|
|
|
dpnew = (DRCCookie *) mallocMagic((unsigned) sizeof (DRCCookie));
|
2019-09-19 20:33:30 +02:00
|
|
|
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits,
|
2017-04-25 14:41:48 +02:00
|
|
|
&cmask, why, centidistance, DRC_FORWARD, layer[1], 0);
|
|
|
|
|
drcCifRules[layer[0]][DRC_CIF_SOLID] = dpnew;
|
|
|
|
|
if (needReverse) dpnew->drcc_flags |= DRC_BOTHCORNERS;
|
|
|
|
|
|
|
|
|
|
// Add rule in reverse direction
|
|
|
|
|
dpnext = drcCifRules[layer[0]][DRC_CIF_SPACE];
|
|
|
|
|
dpnew = (DRCCookie *) mallocMagic((unsigned) sizeof (DRCCookie));
|
2019-09-19 20:33:30 +02:00
|
|
|
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits,
|
2017-04-25 14:41:48 +02:00
|
|
|
&cmask, why, centidistance, DRC_REVERSE, layer[1], 0);
|
|
|
|
|
drcCifRules[layer[0]][DRC_CIF_SPACE] = dpnew;
|
|
|
|
|
|
|
|
|
|
if (needReverse)
|
|
|
|
|
{
|
|
|
|
|
// This is not so much "reverse" as it is just the
|
|
|
|
|
// rule for b->a spacing that matches the a->b spacing.
|
|
|
|
|
|
|
|
|
|
dpnew->drcc_flags |= DRC_BOTHCORNERS;
|
|
|
|
|
dpnext = drcCifRules[layer[1]][DRC_CIF_SOLID];
|
|
|
|
|
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
2019-09-19 20:33:30 +02:00
|
|
|
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits, &cmask,
|
2017-04-25 14:41:48 +02:00
|
|
|
why, centidistance, DRC_FORWARD|DRC_BOTHCORNERS, layer[0], 0);
|
|
|
|
|
drcCifRules[layer[1]][DRC_CIF_SOLID] = dpnew;
|
|
|
|
|
|
|
|
|
|
// Add rule in reverse direction
|
|
|
|
|
dpnext = drcCifRules[layer[1]][DRC_CIF_SPACE];
|
|
|
|
|
dpnew = (DRCCookie *) mallocMagic((unsigned) sizeof (DRCCookie));
|
2019-09-19 20:33:30 +02:00
|
|
|
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits, &cmask,
|
2017-04-25 14:41:48 +02:00
|
|
|
why, centidistance, DRC_REVERSE|DRC_BOTHCORNERS, layer[0], 0);
|
|
|
|
|
drcCifRules[layer[1]][DRC_CIF_SPACE] = dpnew;
|
|
|
|
|
|
|
|
|
|
if (layer[0] == layer[1])
|
|
|
|
|
{
|
|
|
|
|
dpnext = drcCifRules[layer[1]][DRC_CIF_SPACE];
|
|
|
|
|
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
2019-09-19 20:33:30 +02:00
|
|
|
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits,
|
2017-04-25 14:41:48 +02:00
|
|
|
&cmask, why, centidistance, DRC_REVERSE | DRC_BOTHCORNERS,
|
|
|
|
|
layer[0], 0);
|
|
|
|
|
drcCifRules[layer[1]][DRC_CIF_SPACE] = dpnew;
|
|
|
|
|
|
|
|
|
|
dpnext = drcCifRules[layer[0]][DRC_CIF_SPACE];
|
|
|
|
|
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
2019-09-19 20:33:30 +02:00
|
|
|
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits, &cmask,
|
2017-04-25 14:41:48 +02:00
|
|
|
why, centidistance, DRC_REVERSE | DRC_BOTHCORNERS,
|
|
|
|
|
layer[1], 0);
|
|
|
|
|
drcCifRules[layer[0]][DRC_CIF_SPACE] = dpnew;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (layer[0] != layer[1]) /* make sure they don't overlap exactly */
|
|
|
|
|
{
|
|
|
|
|
dpnext = drcCifRules[layer[1]][DRC_CIF_SPACE];
|
|
|
|
|
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
2019-09-19 20:33:30 +02:00
|
|
|
drcCifAssign(dpnew, scalefactor, dpnext, &DBSpaceBits, &DBZeroTypeBits,
|
2017-04-25 14:41:48 +02:00
|
|
|
why, scalefactor, DRC_FORWARD, layer[0], 0);
|
|
|
|
|
drcCifRules[layer[1]][DRC_CIF_SPACE] = dpnew;
|
|
|
|
|
|
|
|
|
|
dpnext = drcCifRules[layer[0]][DRC_CIF_SPACE];
|
|
|
|
|
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
2019-09-19 20:33:30 +02:00
|
|
|
drcCifAssign(dpnew, scalefactor, dpnext, &DBSpaceBits, &DBZeroTypeBits,
|
2017-04-25 14:41:48 +02:00
|
|
|
why, scalefactor, DRC_FORWARD, layer[1], 0);
|
|
|
|
|
drcCifRules[layer[0]][DRC_CIF_SPACE] = dpnew;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ((centidistance+scalefactor-1)/scalefactor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* Scale CIF/DRC rules to match grid scaling. Scale by factor (n / d)
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
drcCifScale(int n, int d)
|
|
|
|
|
{
|
|
|
|
|
DRCCookie *dp;
|
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
|
|
if (DRCCurStyle != NULL)
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; i != MAXCIFLAYERS; i++)
|
|
|
|
|
for (j = 0; j < 2; j++)
|
|
|
|
|
for (dp = drcCifRules[i][j]; dp != NULL; dp = dp->drcc_next)
|
|
|
|
|
{
|
|
|
|
|
if (dp->drcc_dist != 0)
|
|
|
|
|
{
|
|
|
|
|
dp->drcc_dist *= n;
|
|
|
|
|
dp->drcc_dist /= d;
|
|
|
|
|
}
|
|
|
|
|
if (dp->drcc_cdist != 0)
|
|
|
|
|
{
|
|
|
|
|
dp->drcc_cdist *= n;
|
|
|
|
|
dp->drcc_cdist /= d;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
drcCifFreeStyle()
|
|
|
|
|
{
|
|
|
|
|
DRCCookie *dp;
|
|
|
|
|
int i;
|
|
|
|
|
char *old;
|
|
|
|
|
|
|
|
|
|
if (DRCCurStyle != NULL)
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; i != MAXCIFLAYERS; i++)
|
|
|
|
|
{
|
|
|
|
|
dp = drcCifRules[i][DRC_CIF_SPACE];
|
|
|
|
|
while (dp != NULL)
|
|
|
|
|
{
|
|
|
|
|
old = (char *)dp;
|
|
|
|
|
dp = dp->drcc_next;
|
|
|
|
|
freeMagic(old);
|
|
|
|
|
}
|
|
|
|
|
dp = drcCifRules[i][DRC_CIF_SOLID];
|
|
|
|
|
while (dp != NULL)
|
|
|
|
|
{
|
|
|
|
|
old = (char *)dp;
|
|
|
|
|
dp = dp->drcc_next;
|
|
|
|
|
freeMagic(old);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
drcCifInit()
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (drcCifValid == TRUE)
|
|
|
|
|
drcCifFreeStyle();
|
|
|
|
|
|
|
|
|
|
for (i = 0; i != MAXCIFLAYERS; i++)
|
|
|
|
|
{
|
|
|
|
|
drcCifRules[i][DRC_CIF_SPACE] = NULL;
|
|
|
|
|
drcCifRules[i][DRC_CIF_SOLID] = NULL;
|
|
|
|
|
}
|
|
|
|
|
drcCifValid = FALSE;
|
|
|
|
|
TTMaskZero(&drcCifGenLayers);
|
|
|
|
|
beenWarned = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
drcCifFinal()
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i != MAXCIFLAYERS; i++)
|
|
|
|
|
{
|
|
|
|
|
DRCCookie *dp;
|
|
|
|
|
|
|
|
|
|
for (dp = drcCifRules[i][DRC_CIF_SPACE]; dp; dp = dp->drcc_next)
|
|
|
|
|
{
|
|
|
|
|
drcCifValid = TRUE;
|
|
|
|
|
TTMaskSetType(&drcCifGenLayers, i);
|
|
|
|
|
TTMaskSetType(&drcCifGenLayers, dp->drcc_plane);
|
|
|
|
|
}
|
|
|
|
|
for (dp = drcCifRules[i][DRC_CIF_SOLID]; dp; dp = dp->drcc_next)
|
|
|
|
|
{
|
|
|
|
|
drcCifValid = TRUE;
|
|
|
|
|
TTMaskSetType(&drcCifGenLayers, i);
|
|
|
|
|
TTMaskSetType(&drcCifGenLayers, dp->drcc_plane);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* drcCifCheck---
|
|
|
|
|
*
|
|
|
|
|
* This is the primary routine for design-rule checking on CIF layers.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Error paint, CIF layer generation, lots of stuff going on.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
drcCifCheck(arg)
|
|
|
|
|
struct drcClientData *arg;
|
|
|
|
|
{
|
|
|
|
|
Rect *checkRect = arg->dCD_rect;
|
|
|
|
|
Rect cifrect;
|
|
|
|
|
int scale;
|
|
|
|
|
int i,j;
|
|
|
|
|
int oldTiles;
|
2019-10-15 22:24:49 +02:00
|
|
|
CIFStyle *CIFSaveStyle = NULL;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2019-10-15 22:24:49 +02:00
|
|
|
if (CIFCurStyle != drcCifStyle)
|
|
|
|
|
{
|
2019-10-16 16:14:44 +02:00
|
|
|
if (drcNeedStyle == NULL) return;
|
2019-10-15 22:24:49 +02:00
|
|
|
|
|
|
|
|
CIFSaveStyle = CIFCurStyle;
|
|
|
|
|
|
|
|
|
|
if (drcCifStyle == NULL)
|
|
|
|
|
{
|
|
|
|
|
TxPrintf("Loading DRC CIF style.\n");
|
|
|
|
|
CIFCurStyle = NULL;
|
|
|
|
|
CIFLoadStyle(drcNeedStyle);
|
2019-11-25 17:07:59 +01:00
|
|
|
if (drcCifValid != FALSE)
|
2019-10-15 22:24:49 +02:00
|
|
|
CIFCurStyle = CIFSaveStyle;
|
|
|
|
|
else
|
|
|
|
|
drcCifStyle = CIFCurStyle;
|
|
|
|
|
}
|
|
|
|
|
if (drcCifStyle == NULL)
|
|
|
|
|
{
|
|
|
|
|
TxError("Error: Failed to load CIF DRC style.\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
CIFCurStyle = drcCifStyle;
|
|
|
|
|
}
|
2019-11-25 17:07:59 +01:00
|
|
|
if (drcCifValid == FALSE)
|
|
|
|
|
{
|
2020-01-03 18:21:39 +01:00
|
|
|
if (CIFSaveStyle != NULL)
|
|
|
|
|
CIFCurStyle = CIFSaveStyle;
|
2019-11-25 17:07:59 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
scale = drcCifStyle->cs_scaleFactor;
|
|
|
|
|
cifrect = *checkRect;
|
|
|
|
|
cifrect.r_xbot *= scale;
|
|
|
|
|
cifrect.r_xtop *= scale;
|
|
|
|
|
cifrect.r_ybot *= scale;
|
|
|
|
|
cifrect.r_ytop *= scale;
|
|
|
|
|
arg->dCD_rect = &cifrect;
|
|
|
|
|
oldTiles = DRCstatTiles;
|
|
|
|
|
|
|
|
|
|
CIFGen(arg->dCD_celldef, checkRect, CIFPlanes, &DBAllTypeBits, TRUE, TRUE);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < drcCifStyle->cs_nLayers; i++)
|
|
|
|
|
{
|
|
|
|
|
for (j = 0; j != 2; j++)
|
|
|
|
|
{
|
|
|
|
|
for (drcCifCur = drcCifRules[i][j];
|
|
|
|
|
drcCifCur; drcCifCur = drcCifCur->drcc_next)
|
|
|
|
|
{
|
|
|
|
|
TileTypeBitMask *mask;
|
|
|
|
|
|
|
|
|
|
arg->dCD_plane = i;
|
|
|
|
|
DBSrPaintArea((Tile *) NULL, CIFPlanes[i], &cifrect,
|
|
|
|
|
(j == DRC_CIF_SOLID) ? &DBSpaceBits : &CIFSolidBits,
|
|
|
|
|
drcCifTile, arg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
arg->dCD_rect = checkRect;
|
|
|
|
|
DRCstatCifTiles += DRCstatTiles - oldTiles;
|
2019-10-15 22:24:49 +02:00
|
|
|
|
|
|
|
|
/* Put it back the way you found it */
|
|
|
|
|
if (CIFSaveStyle != NULL) CIFCurStyle = CIFSaveStyle;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* drcCifTile --
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Zero (so that the search will continue), unless an interrupt
|
|
|
|
|
* occurs, in which case 1 is returned to stop the check.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Calls the client's error function if errors are found.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
drcCifTile (tile, arg)
|
|
|
|
|
Tile *tile; /* Tile being examined */
|
|
|
|
|
struct drcClientData *arg;
|
|
|
|
|
{
|
|
|
|
|
DRCCookie *cptr; /* Current design rule on list */
|
|
|
|
|
Tile *tp; /* Used for corner checks */
|
|
|
|
|
Rect *rect = arg->dCD_rect; /* Area being checked */
|
|
|
|
|
Rect errRect; /* Area checked for an individual rule */
|
|
|
|
|
TileTypeBitMask tmpMask;
|
|
|
|
|
|
|
|
|
|
arg->dCD_constraint = &errRect;
|
|
|
|
|
arg->dCD_radial = 0;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If we were interrupted, we want to
|
|
|
|
|
* abort the check as quickly as possible.
|
|
|
|
|
*/
|
|
|
|
|
if (SigInterruptPending) return 1;
|
|
|
|
|
DRCstatTiles++;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Check design rules along a vertical boundary between two tiles.
|
|
|
|
|
*
|
|
|
|
|
* 1 | 4
|
|
|
|
|
* T
|
|
|
|
|
* |
|
|
|
|
|
* tpleft | tile
|
|
|
|
|
* |
|
|
|
|
|
* B
|
|
|
|
|
* 2 | 3
|
|
|
|
|
*
|
|
|
|
|
* The labels "T" and "B" indicate pointT and pointB respectively.
|
|
|
|
|
*
|
|
|
|
|
* If a rule's direction is FORWARD, then check from left to right.
|
|
|
|
|
*
|
|
|
|
|
* * Check the top right corner if the 1x1 lambda square
|
|
|
|
|
* on the top left corner (1) of pointT matches the design
|
|
|
|
|
* rule's "corner" mask.
|
|
|
|
|
*
|
|
|
|
|
* * Check the bottom right corner if the rule says check
|
|
|
|
|
* BOTHCORNERS and the 1x1 lambda square on the bottom left
|
|
|
|
|
* corner (2) of pointB matches the design rule's "corner" mask.
|
|
|
|
|
*
|
|
|
|
|
* If a rule's direction is REVERSE, then check from right to left.
|
|
|
|
|
*
|
|
|
|
|
* * Check the bottom left corner if the 1x1 lambda square
|
|
|
|
|
* on the bottom right corner (3) of pointB matches the design
|
|
|
|
|
* rule's "corner" mask.
|
|
|
|
|
*
|
|
|
|
|
* * Check the top left corner if the rule says check BOTHCORNERS
|
|
|
|
|
* and the 1x1 lambda square on the top right corner (4) of
|
|
|
|
|
* pointT matches the design rule's "corner" mask.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (drcCifCur->drcc_flags & DRC_AREA)
|
|
|
|
|
{
|
|
|
|
|
drcCheckCifArea(tile, arg, drcCifCur);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (drcCifCur->drcc_flags & DRC_MAXWIDTH)
|
|
|
|
|
{
|
|
|
|
|
drcCheckCifMaxwidth(tile, arg, drcCifCur);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (LEFT(tile) >= rect->r_xbot) /* check tile against rect */
|
|
|
|
|
{
|
|
|
|
|
Tile *tpleft;
|
|
|
|
|
int edgeTop, edgeBot;
|
|
|
|
|
int top = MIN(TOP(tile), rect->r_ytop);
|
|
|
|
|
int bottom = MAX(BOTTOM(tile), rect->r_ybot);
|
|
|
|
|
int edgeX = LEFT(tile);
|
|
|
|
|
|
|
|
|
|
for (tpleft = BL(tile); BOTTOM(tpleft) < top; tpleft = RT(tpleft))
|
|
|
|
|
{
|
|
|
|
|
/* Don't check synthetic edges, i.e. edges with same type on
|
|
|
|
|
* both sides. Such "edges" have no physical significance, and
|
|
|
|
|
* depend on internal-details of how paint is spit into tiles.
|
|
|
|
|
* Thus checking them just leads to confusion. (When edge rules
|
|
|
|
|
* involving such edges are encountered during technology readin
|
|
|
|
|
* the user is warned that such edges are not checked).
|
|
|
|
|
*/
|
|
|
|
|
if (TiGetRightType(tpleft) == TiGetLeftType(tile))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Go through list of design rules triggered by the
|
|
|
|
|
* left-to-right edge.
|
|
|
|
|
*/
|
|
|
|
|
edgeTop = MIN(TOP (tpleft), top);
|
|
|
|
|
edgeBot = MAX(BOTTOM(tpleft), bottom);
|
|
|
|
|
if (edgeTop <= edgeBot)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* do this more intelligently later XXX */
|
|
|
|
|
cptr = drcCifCur;
|
|
|
|
|
{
|
|
|
|
|
errRect.r_ytop = edgeTop;
|
|
|
|
|
errRect.r_ybot = edgeBot;
|
|
|
|
|
|
|
|
|
|
if (cptr->drcc_flags & DRC_REVERSE)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Determine corner extensions.
|
|
|
|
|
* Find the point (3) to the bottom right of pointB
|
|
|
|
|
*/
|
|
|
|
|
for (tp = tile; BOTTOM(tp) >= errRect.r_ybot; tp = LB(tp))
|
|
|
|
|
/* Nothing */;
|
|
|
|
|
if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tp)))
|
|
|
|
|
{
|
|
|
|
|
errRect.r_ybot -= cptr->drcc_cdist;
|
|
|
|
|
if (DRCEuclidean)
|
|
|
|
|
arg->dCD_radial |= 0x1000;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cptr->drcc_flags & DRC_BOTHCORNERS)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Check the other corner by finding the
|
|
|
|
|
* point (4) to the top right of pointT.
|
|
|
|
|
*/
|
|
|
|
|
if (TOP(tp = tile) <= errRect.r_ytop)
|
|
|
|
|
for (tp = RT(tp); LEFT(tp) > edgeX; tp = BL(tp))
|
|
|
|
|
/* Nothing */;
|
|
|
|
|
if (TTMaskHasType(&cptr->drcc_corner, TiGetBottomType(tp)))
|
|
|
|
|
{
|
|
|
|
|
errRect.r_ytop += cptr->drcc_cdist;
|
|
|
|
|
if (DRCEuclidean)
|
|
|
|
|
arg->dCD_radial |= 0x2000;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Just for grins, see if we could avoid a messy search
|
|
|
|
|
* by looking only at tpleft.
|
|
|
|
|
*/
|
|
|
|
|
errRect.r_xbot = edgeX - cptr->drcc_dist;
|
|
|
|
|
if (LEFT(tpleft) <= errRect.r_xbot
|
|
|
|
|
&& BOTTOM(tpleft) <= errRect.r_ybot
|
|
|
|
|
&& TOP(tpleft) >= errRect.r_ytop
|
|
|
|
|
&& arg->dCD_plane == cptr->drcc_plane
|
|
|
|
|
&& TTMaskHasType(&cptr->drcc_mask, TiGetType(tpleft)))
|
|
|
|
|
continue;
|
|
|
|
|
errRect.r_xtop = edgeX;
|
|
|
|
|
arg->dCD_initial = tile;
|
|
|
|
|
}
|
|
|
|
|
else /* FORWARD */
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Determine corner extensions.
|
|
|
|
|
* Find the point (1) to the top left of pointT
|
|
|
|
|
*/
|
|
|
|
|
for (tp = tpleft; TOP(tp) <= errRect.r_ytop; tp = RT(tp))
|
|
|
|
|
/* Nothing */;
|
|
|
|
|
if (TTMaskHasType(&cptr->drcc_corner, TiGetBottomType(tp)))
|
|
|
|
|
{
|
|
|
|
|
errRect.r_ytop += cptr->drcc_cdist;
|
|
|
|
|
if (DRCEuclidean)
|
|
|
|
|
arg->dCD_radial |= 0x8000;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cptr->drcc_flags & DRC_BOTHCORNERS)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Check the other corner by finding the
|
|
|
|
|
* point (2) to the bottom left of pointB.
|
|
|
|
|
*/
|
|
|
|
|
if (BOTTOM(tp = tpleft) >= errRect.r_ybot)
|
|
|
|
|
for (tp = LB(tp); RIGHT(tp) < edgeX; tp = TR(tp))
|
|
|
|
|
/* Nothing */;
|
|
|
|
|
if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tp)))
|
|
|
|
|
{
|
|
|
|
|
errRect.r_ybot -= cptr->drcc_cdist;
|
|
|
|
|
if (DRCEuclidean)
|
|
|
|
|
arg->dCD_radial |= 0x4000;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Just for grins, see if we could avoid a messy search
|
|
|
|
|
* by looking only at tile.
|
|
|
|
|
*/
|
|
|
|
|
errRect.r_xtop = edgeX + cptr->drcc_dist;
|
|
|
|
|
if (RIGHT(tile) >= errRect.r_xtop
|
|
|
|
|
&& BOTTOM(tile) <= errRect.r_ybot
|
|
|
|
|
&& TOP(tile) >= errRect.r_ytop
|
|
|
|
|
&& arg->dCD_plane == cptr->drcc_plane
|
|
|
|
|
&& TTMaskHasType(&cptr->drcc_mask, TiGetLeftType(tile)))
|
|
|
|
|
continue;
|
|
|
|
|
errRect.r_xbot = edgeX;
|
|
|
|
|
arg->dCD_initial= tpleft;
|
|
|
|
|
}
|
|
|
|
|
if (arg->dCD_radial)
|
|
|
|
|
{
|
|
|
|
|
arg->dCD_radial &= 0xf0000;
|
|
|
|
|
arg->dCD_radial |= (0xfff & cptr->drcc_cdist);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DRCstatSlow++;
|
|
|
|
|
arg->dCD_cptr = (DRCCookie *)cptr;
|
|
|
|
|
TTMaskCom2(&tmpMask, &cptr->drcc_mask);
|
|
|
|
|
(void) DBSrPaintArea((Tile *) NULL,
|
|
|
|
|
CIFPlanes[cptr->drcc_plane],
|
|
|
|
|
&errRect, &tmpMask, areaCifCheck, (ClientData) arg);
|
|
|
|
|
}
|
|
|
|
|
DRCstatEdges++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Check design rules along a horizontal boundary between two tiles.
|
|
|
|
|
*
|
|
|
|
|
* 4 tile 3
|
|
|
|
|
* --L----------------R--
|
|
|
|
|
* 1 tpbot 2
|
|
|
|
|
*
|
|
|
|
|
* The labels "L" and "R" indicate pointL and pointR respectively.
|
|
|
|
|
* If a rule's direction is FORWARD, then check from bottom to top.
|
|
|
|
|
*
|
|
|
|
|
* * Check the top left corner if the 1x1 lambda square on the bottom
|
|
|
|
|
* left corner (1) of pointL matches the design rule's "corner" mask.
|
|
|
|
|
*
|
|
|
|
|
* * Check the top right corner if the rule says check BOTHCORNERS and
|
|
|
|
|
* the 1x1 lambda square on the bottom right (2) corner of pointR
|
|
|
|
|
* matches the design rule's "corner" mask.
|
|
|
|
|
*
|
|
|
|
|
* If a rule's direction is REVERSE, then check from top to bottom.
|
|
|
|
|
*
|
|
|
|
|
* * Check the bottom right corner if the 1x1 lambda square on the top
|
|
|
|
|
* right corner (3) of pointR matches the design rule's "corner"
|
|
|
|
|
* mask.
|
|
|
|
|
*
|
|
|
|
|
* * Check the bottom left corner if the rule says check BOTHCORNERS
|
|
|
|
|
* and the 1x1 lambda square on the top left corner (4) of pointL
|
|
|
|
|
* matches the design rule's "corner" mask.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (BOTTOM(tile) >= rect->r_ybot)
|
|
|
|
|
{
|
|
|
|
|
Tile *tpbot;
|
|
|
|
|
int edgeLeft, edgeRight;
|
|
|
|
|
int left = MAX(LEFT(tile), rect->r_xbot);
|
|
|
|
|
int right = MIN(RIGHT(tile), rect->r_xtop);
|
|
|
|
|
int edgeY = BOTTOM(tile);
|
|
|
|
|
|
|
|
|
|
/* Go right across bottom of tile */
|
|
|
|
|
for (tpbot = LB(tile); LEFT(tpbot) < right; tpbot = TR(tpbot))
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/* Don't check synthetic edges, i.e. edges with same type on
|
|
|
|
|
* both sides. Such "edges" have no physical significance, and
|
|
|
|
|
* depend on internal-details of how paint is spit into tiles.
|
|
|
|
|
* Thus checking them just leads to confusion. (When edge rules
|
|
|
|
|
* involving such edges are encountered during technology readin
|
|
|
|
|
* the user is warned that such edges are not checked).
|
|
|
|
|
*/
|
|
|
|
|
if(TiGetTopType(tpbot) == TiGetBottomType(tile))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Check to insure that we are inside the clip area.
|
|
|
|
|
* Go through list of design rules triggered by the
|
|
|
|
|
* bottom-to-top edge.
|
|
|
|
|
*/
|
|
|
|
|
edgeLeft = MAX(LEFT(tpbot), left);
|
|
|
|
|
edgeRight = MIN(RIGHT(tpbot), right);
|
|
|
|
|
if (edgeLeft >= edgeRight)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
cptr = drcCifCur;
|
|
|
|
|
{
|
|
|
|
|
DRCstatRules++;
|
|
|
|
|
errRect.r_xbot = edgeLeft;
|
|
|
|
|
errRect.r_xtop = edgeRight;
|
|
|
|
|
|
|
|
|
|
/* top to bottom */
|
|
|
|
|
if (cptr->drcc_flags & DRC_REVERSE)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Determine corner extensions.
|
|
|
|
|
* Find the point (3) to the top right of pointR
|
|
|
|
|
*/
|
|
|
|
|
if (RIGHT(tp = tile) <= errRect.r_xtop)
|
|
|
|
|
for (tp = TR(tp); BOTTOM(tp) > edgeY; tp = LB(tp))
|
|
|
|
|
/* Nothing */;
|
|
|
|
|
if (TTMaskHasType(&cptr->drcc_corner, TiGetLeftType(tp)))
|
|
|
|
|
{
|
|
|
|
|
errRect.r_xtop += cptr->drcc_cdist;
|
|
|
|
|
if (DRCEuclidean)
|
|
|
|
|
arg->dCD_radial |= 0x4000;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cptr->drcc_flags & DRC_BOTHCORNERS)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Check the other corner by finding the
|
|
|
|
|
* point (4) to the top left of pointL.
|
|
|
|
|
*/
|
|
|
|
|
for (tp = tile; LEFT(tp) >= errRect.r_xbot; tp = BL(tp))
|
|
|
|
|
/* Nothing */;
|
|
|
|
|
if (TTMaskHasType(&cptr->drcc_corner, TiGetRightType(tp)))
|
|
|
|
|
{
|
|
|
|
|
errRect.r_xbot -= cptr->drcc_cdist;
|
|
|
|
|
if (DRCEuclidean)
|
|
|
|
|
arg->dCD_radial |= 0x1000;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Just for grins, see if we could avoid
|
|
|
|
|
* a messy search by looking only at tpbot.
|
|
|
|
|
*/
|
|
|
|
|
errRect.r_ybot = edgeY - cptr->drcc_dist;
|
|
|
|
|
if (BOTTOM(tpbot) <= errRect.r_ybot
|
|
|
|
|
&& LEFT(tpbot) <= errRect.r_xbot
|
|
|
|
|
&& RIGHT(tpbot) >= errRect.r_xtop
|
|
|
|
|
&& arg->dCD_plane == cptr->drcc_plane
|
|
|
|
|
&& TTMaskHasType(&cptr->drcc_mask, TiGetTopType(tpbot)))
|
|
|
|
|
continue;
|
|
|
|
|
errRect.r_ytop = edgeY;
|
|
|
|
|
arg->dCD_initial = tile;
|
|
|
|
|
}
|
|
|
|
|
else /* FORWARD */
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Determine corner extensions.
|
|
|
|
|
* Find the point (1) to the bottom left of pointL
|
|
|
|
|
*/
|
|
|
|
|
if (LEFT(tp = tpbot) >= errRect.r_xbot)
|
|
|
|
|
for (tp = BL(tp); TOP(tp) < edgeY; tp = RT(tp))
|
|
|
|
|
/* Nothing */;
|
|
|
|
|
|
|
|
|
|
if (TTMaskHasType(&cptr->drcc_corner, TiGetRightType(tp)))
|
|
|
|
|
{
|
|
|
|
|
errRect.r_xbot -= cptr->drcc_cdist;
|
|
|
|
|
if (DRCEuclidean)
|
|
|
|
|
arg->dCD_radial |= 0x2000;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cptr->drcc_flags & DRC_BOTHCORNERS)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Check the other corner by finding the
|
|
|
|
|
* point (2) to the bottom right of pointR.
|
|
|
|
|
*/
|
|
|
|
|
for (tp=tpbot; RIGHT(tp) <= errRect.r_xtop; tp=TR(tp))
|
|
|
|
|
/* Nothing */;
|
|
|
|
|
if (TTMaskHasType(&cptr->drcc_corner, TiGetLeftType(tp)))
|
|
|
|
|
{
|
|
|
|
|
errRect.r_xtop += cptr->drcc_cdist;
|
|
|
|
|
if (DRCEuclidean)
|
|
|
|
|
arg->dCD_radial |= 0x8000;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Just for grins, see if we could avoid
|
|
|
|
|
* a messy search by looking only at tile.
|
|
|
|
|
*/
|
|
|
|
|
errRect.r_ytop = edgeY + cptr->drcc_dist;
|
|
|
|
|
if (TOP(tile) >= errRect.r_ytop
|
|
|
|
|
&& LEFT(tile) <= errRect.r_xbot
|
|
|
|
|
&& RIGHT(tile) >= errRect.r_xtop
|
|
|
|
|
&& arg->dCD_plane == cptr->drcc_plane
|
|
|
|
|
&& TTMaskHasType(&cptr->drcc_mask, TiGetType(tile)))
|
|
|
|
|
continue;
|
|
|
|
|
errRect.r_ybot = edgeY;
|
|
|
|
|
arg->dCD_initial = tpbot;
|
|
|
|
|
}
|
|
|
|
|
if (arg->dCD_radial)
|
|
|
|
|
{
|
|
|
|
|
arg->dCD_radial &= 0xf000;
|
|
|
|
|
arg->dCD_radial |= (0xfff & cptr->drcc_cdist);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DRCstatSlow++;
|
|
|
|
|
arg->dCD_cptr = (DRCCookie *)cptr;
|
|
|
|
|
TTMaskCom2(&tmpMask, &cptr->drcc_mask);
|
|
|
|
|
(void) DBSrPaintArea((Tile *) NULL,
|
|
|
|
|
CIFPlanes[cptr->drcc_plane],
|
|
|
|
|
&errRect, &tmpMask, areaCifCheck, (ClientData) arg);
|
|
|
|
|
}
|
|
|
|
|
DRCstatEdges++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* areaCifCheck --
|
|
|
|
|
*
|
|
|
|
|
* Call the function passed down from DRCBasicCheck() if the current tile
|
|
|
|
|
* violates the rule in the given DRCCookie. If the rule's connectivity
|
|
|
|
|
* flag is set, then make sure the violating material isn't connected
|
|
|
|
|
* to what's on the initial side of the edge before calling the client
|
|
|
|
|
* error function.
|
|
|
|
|
*
|
|
|
|
|
* This function is called from DBSrPaintArea().
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Zero (so that the search will continue).
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Applies the function passed as an argument.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
areaCifCheck(tile, arg)
|
|
|
|
|
Tile *tile;
|
|
|
|
|
struct drcClientData *arg;
|
|
|
|
|
{
|
|
|
|
|
Rect rect; /* Area where error is to be recorded. */
|
|
|
|
|
int scale = drcCifStyle->cs_scaleFactor;
|
|
|
|
|
|
|
|
|
|
/* If the tile has a legal type, then return. */
|
|
|
|
|
|
|
|
|
|
if (TTMaskHasType(&arg->dCD_cptr->drcc_mask, TiGetType(tile))) return 0;
|
|
|
|
|
|
|
|
|
|
/* Only consider the portion of the suspicious tile that overlaps
|
|
|
|
|
* the clip area for errors.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
TiToRect(tile, &rect);
|
|
|
|
|
GeoClip(&rect, arg->dCD_constraint);
|
|
|
|
|
if ((rect.r_xbot >= rect.r_xtop) || (rect.r_ybot >= rect.r_ytop))
|
|
|
|
|
return 0;
|
|
|
|
|
rect.r_xbot /= scale;
|
|
|
|
|
rect.r_xtop /= scale;
|
|
|
|
|
if (rect.r_xbot == rect.r_xtop)
|
|
|
|
|
{
|
|
|
|
|
if (rect.r_xbot < 0) rect.r_xbot--; else rect.r_xtop++;
|
|
|
|
|
}
|
|
|
|
|
rect.r_ybot /= scale;
|
|
|
|
|
rect.r_ytop /= scale;
|
|
|
|
|
if (rect.r_ybot == rect.r_ytop)
|
|
|
|
|
{
|
|
|
|
|
if (rect.r_ybot < 0) rect.r_ybot--; else rect.r_ytop++;
|
|
|
|
|
}
|
|
|
|
|
GeoClip(&rect, arg->dCD_clip);
|
|
|
|
|
if ((rect.r_xbot >= rect.r_xtop) || (rect.r_ybot >= rect.r_ytop))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
(*(arg->dCD_function)) (arg->dCD_celldef, &rect,
|
|
|
|
|
arg->dCD_cptr, arg->dCD_clientData);
|
|
|
|
|
(*(arg->dCD_errors))++;
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* drcCifArea --
|
|
|
|
|
*
|
|
|
|
|
* Process an area rule.
|
|
|
|
|
* This is of the form:
|
|
|
|
|
*
|
|
|
|
|
* cifarea layers distance why
|
|
|
|
|
*
|
|
|
|
|
* e.g,
|
|
|
|
|
*
|
|
|
|
|
* cifarea VIA 4 "via area must be at least 4"
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns distance.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Updates the DRC technology variables.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
drcCifArea(argc, argv)
|
|
|
|
|
int argc;
|
|
|
|
|
char *argv[];
|
|
|
|
|
{
|
|
|
|
|
char *layers = argv[1];
|
|
|
|
|
int centiarea = atoi(argv[2]);
|
|
|
|
|
int centihorizon = atoi(argv[3]);
|
2020-02-25 19:57:41 +01:00
|
|
|
int why = drcWhyCreate(argv[4]);
|
2017-04-25 14:41:48 +02:00
|
|
|
TileTypeBitMask set, setC, tmp1;
|
|
|
|
|
DRCCookie *dpnext, *dpnew;
|
|
|
|
|
TileType i, j;
|
|
|
|
|
int plane;
|
|
|
|
|
int thislayer;
|
|
|
|
|
int scalefactor;
|
|
|
|
|
|
|
|
|
|
if (drcCifStyle == NULL)
|
|
|
|
|
return drcCifWarning();
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < drcCifStyle->cs_nLayers;i++)
|
|
|
|
|
{
|
|
|
|
|
CIFLayer *layer = drcCifStyle->cs_layers[i];
|
|
|
|
|
|
|
|
|
|
if (strcmp(layer->cl_name,layers) == 0)
|
|
|
|
|
{
|
|
|
|
|
thislayer = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (thislayer == -1)
|
|
|
|
|
{
|
|
|
|
|
TechError("Unknown cif layer: %s\n",layers);
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scalefactor = drcCifStyle->cs_scaleFactor;
|
|
|
|
|
centiarea *= (drcCifStyle->cs_expander * drcCifStyle->cs_expander);
|
|
|
|
|
dpnext = drcCifRules[thislayer][DRC_CIF_SPACE];
|
|
|
|
|
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
2019-09-19 20:33:30 +02:00
|
|
|
drcCifAssign(dpnew, centihorizon, dpnext, &CIFSolidBits, &CIFSolidBits,
|
2017-04-25 14:41:48 +02:00
|
|
|
why, centiarea, DRC_AREA | DRC_FORWARD, thislayer, 0);
|
|
|
|
|
drcCifRules[thislayer][DRC_CIF_SPACE] = dpnew;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ((centihorizon+scalefactor-1)/scalefactor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* drcCifMaxwidth -- cif version of drc list.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns distance.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Updates the DRC technology variables.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
drcCifMaxwidth(argc, argv)
|
|
|
|
|
int argc;
|
|
|
|
|
char *argv[];
|
|
|
|
|
{
|
|
|
|
|
char *layers = argv[1];
|
|
|
|
|
int centidistance = atoi(argv[2]);
|
|
|
|
|
char *bends = argv[3];
|
2020-02-25 19:57:41 +01:00
|
|
|
int why = drcWhyCreate(argv[4]);
|
2017-04-25 14:41:48 +02:00
|
|
|
TileTypeBitMask set, setC, tmp1;
|
|
|
|
|
DRCCookie *dpnext, *dpnew;
|
|
|
|
|
TileType i, j;
|
|
|
|
|
int plane;
|
|
|
|
|
int bend;
|
|
|
|
|
int thislayer;
|
|
|
|
|
int scalefactor;
|
|
|
|
|
|
|
|
|
|
if (drcCifStyle == NULL)
|
|
|
|
|
return drcCifWarning();
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < drcCifStyle->cs_nLayers;i++)
|
|
|
|
|
{
|
|
|
|
|
CIFLayer *layer = drcCifStyle->cs_layers[i];
|
|
|
|
|
|
|
|
|
|
if (strcmp(layer->cl_name,layers) == 0)
|
|
|
|
|
{
|
|
|
|
|
thislayer = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (thislayer == -1)
|
|
|
|
|
{
|
|
|
|
|
TechError("Unknown cif layer: %s\n",layers);
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (strcmp(bends,"bend_illegal") == 0) bend =0;
|
|
|
|
|
else if (strcmp(bends,"bend_ok") == 0) bend =DRC_BENDS;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
TechError("unknown bend option %s\n",bends);
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scalefactor = drcCifStyle->cs_scaleFactor;
|
|
|
|
|
centidistance *= drcCifStyle->cs_expander; // BSI
|
|
|
|
|
dpnext = drcCifRules[thislayer][DRC_CIF_SPACE];
|
|
|
|
|
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
2019-09-19 20:33:30 +02:00
|
|
|
drcCifAssign(dpnew, centidistance, dpnext, &CIFSolidBits, &CIFSolidBits,
|
2017-04-25 14:41:48 +02:00
|
|
|
why, centidistance, DRC_MAXWIDTH | bend, thislayer, 0);
|
|
|
|
|
drcCifRules[thislayer][DRC_CIF_SPACE] = dpnew;
|
|
|
|
|
|
|
|
|
|
return ((centidistance+scalefactor-1)/scalefactor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* drcCifCheckArea--
|
|
|
|
|
*
|
|
|
|
|
* checks to see that a collection of cif tiles
|
|
|
|
|
* have more than a minimum area.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None
|
|
|
|
|
*
|
|
|
|
|
* Side Effects:
|
|
|
|
|
* May cause errors to be painted.
|
|
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
drcCheckCifArea(starttile, arg, cptr)
|
|
|
|
|
Tile *starttile;
|
|
|
|
|
struct drcClientData *arg;
|
|
|
|
|
DRCCookie *cptr;
|
|
|
|
|
{
|
|
|
|
|
int arealimit = cptr->drcc_cdist;
|
|
|
|
|
long area = 0L;
|
|
|
|
|
TileTypeBitMask *oktypes = &cptr->drcc_mask;
|
|
|
|
|
Tile *tile,*tp;
|
|
|
|
|
Rect *cliprect = arg->dCD_rect;
|
|
|
|
|
int scale = drcCifStyle->cs_scaleFactor;
|
|
|
|
|
|
|
|
|
|
arg->dCD_cptr = (DRCCookie *)cptr;
|
|
|
|
|
if (DRCstack == (Stack *) NULL)
|
|
|
|
|
DRCstack = StackNew(64);
|
|
|
|
|
|
|
|
|
|
/* Mark this tile as pending and push it */
|
|
|
|
|
PUSHTILE(starttile);
|
|
|
|
|
|
|
|
|
|
while (!StackEmpty(DRCstack))
|
|
|
|
|
{
|
|
|
|
|
tile = (Tile *) STACKPOP(DRCstack);
|
|
|
|
|
if (tile->ti_client != (ClientData)DRC_PENDING) continue;
|
|
|
|
|
area += (long)(RIGHT(tile)-LEFT(tile))*(TOP(tile)-BOTTOM(tile));
|
|
|
|
|
tile->ti_client = (ClientData)DRC_PROCESSED;
|
|
|
|
|
/* are we at the clip boundary? If so, skip to the end */
|
|
|
|
|
if (RIGHT(tile) == cliprect->r_xtop ||
|
|
|
|
|
LEFT(tile) == cliprect->r_xbot ||
|
|
|
|
|
BOTTOM(tile) == cliprect->r_ybot ||
|
|
|
|
|
TOP(tile) == cliprect->r_ytop) goto forgetit;
|
|
|
|
|
|
|
|
|
|
if (area >= (long)arealimit) goto forgetit;
|
|
|
|
|
|
|
|
|
|
/* Top */
|
|
|
|
|
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
|
|
|
|
|
if (TTMaskHasType(oktypes, TiGetType(tp))) PUSHTILE(tp);
|
|
|
|
|
|
|
|
|
|
/* Left */
|
|
|
|
|
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
|
|
|
|
|
if (TTMaskHasType(oktypes, TiGetType(tp))) PUSHTILE(tp);
|
|
|
|
|
|
|
|
|
|
/* Bottom */
|
|
|
|
|
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
|
|
|
|
|
if (TTMaskHasType(oktypes, TiGetType(tp))) PUSHTILE(tp);
|
|
|
|
|
|
|
|
|
|
/* Right */
|
|
|
|
|
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
|
|
|
|
|
if (TTMaskHasType(oktypes, TiGetType(tp))) PUSHTILE(tp);
|
|
|
|
|
}
|
|
|
|
|
if (area < (long)arealimit)
|
|
|
|
|
{
|
|
|
|
|
Rect rect;
|
|
|
|
|
TiToRect(starttile,&rect);
|
|
|
|
|
rect.r_xbot /= scale;
|
|
|
|
|
rect.r_xtop /= scale;
|
|
|
|
|
rect.r_ybot /= scale;
|
|
|
|
|
rect.r_ytop /= scale;
|
|
|
|
|
GeoClip(&rect, arg->dCD_clip);
|
|
|
|
|
if (!GEO_RECTNULL(&rect)) {
|
|
|
|
|
(*(arg->dCD_function)) (arg->dCD_celldef, &rect,
|
|
|
|
|
arg->dCD_cptr, arg->dCD_clientData);
|
|
|
|
|
(*(arg->dCD_errors))++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
forgetit:
|
|
|
|
|
/* reset the tiles */
|
|
|
|
|
starttile->ti_client = (ClientData)DRC_UNPROCESSED;
|
|
|
|
|
STACKPUSH(starttile, DRCstack);
|
|
|
|
|
while (!StackEmpty(DRCstack))
|
|
|
|
|
{
|
|
|
|
|
tile = (Tile *) STACKPOP(DRCstack);
|
|
|
|
|
|
|
|
|
|
/* Top */
|
|
|
|
|
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
|
|
|
|
|
if (tp->ti_client != (ClientData)DRC_UNPROCESSED)
|
|
|
|
|
{
|
|
|
|
|
tp->ti_client = (ClientData)DRC_UNPROCESSED;
|
|
|
|
|
STACKPUSH(tp,DRCstack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Left */
|
|
|
|
|
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
|
|
|
|
|
if (tp->ti_client != (ClientData)DRC_UNPROCESSED)
|
|
|
|
|
{
|
|
|
|
|
tp->ti_client = (ClientData)DRC_UNPROCESSED;
|
|
|
|
|
STACKPUSH(tp,DRCstack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Bottom */
|
|
|
|
|
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
|
|
|
|
|
if (tp->ti_client != (ClientData)DRC_UNPROCESSED)
|
|
|
|
|
{
|
|
|
|
|
tp->ti_client = (ClientData)DRC_UNPROCESSED;
|
|
|
|
|
STACKPUSH(tp,DRCstack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Right */
|
|
|
|
|
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
|
|
|
|
|
if (tp->ti_client != (ClientData)DRC_UNPROCESSED)
|
|
|
|
|
{
|
|
|
|
|
tp->ti_client = (ClientData)DRC_UNPROCESSED;
|
|
|
|
|
STACKPUSH(tp,DRCstack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* drcCheckCifMaxwidth --
|
|
|
|
|
*
|
|
|
|
|
* Checks to see that at least one dimension of a region
|
|
|
|
|
* does not exceed some amount.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side Effects:
|
|
|
|
|
* May cause errors to be painted.
|
|
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
drcCheckCifMaxwidth(starttile,arg,cptr)
|
|
|
|
|
Tile *starttile;
|
|
|
|
|
struct drcClientData *arg;
|
|
|
|
|
DRCCookie *cptr;
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
int edgelimit = cptr->drcc_dist;
|
|
|
|
|
Rect boundrect;
|
|
|
|
|
TileTypeBitMask *oktypes = &cptr->drcc_mask;
|
|
|
|
|
Tile *tile,*tp;
|
|
|
|
|
int scale = drcCifStyle->cs_scaleFactor;
|
|
|
|
|
|
|
|
|
|
arg->dCD_cptr = (DRCCookie *)cptr;
|
|
|
|
|
if (DRCstack == (Stack *) NULL)
|
|
|
|
|
DRCstack = StackNew(64);
|
|
|
|
|
|
|
|
|
|
/* if bends are allowed, just check on a tile-by-tile basis that
|
|
|
|
|
one dimension is the max. This is pretty stupid, but it correctly
|
|
|
|
|
calculates the trench width rule. dcs 12.06.89 */
|
|
|
|
|
if (cptr->drcc_flags & DRC_BENDS)
|
|
|
|
|
{
|
|
|
|
|
Rect rect;
|
|
|
|
|
TiToRect(starttile,&rect);
|
|
|
|
|
if (rect.r_xtop-rect.r_xbot > edgelimit &&
|
|
|
|
|
rect.r_ytop-rect.r_ybot > edgelimit)
|
|
|
|
|
{
|
|
|
|
|
rect.r_xbot /= scale;
|
|
|
|
|
rect.r_xtop /= scale;
|
|
|
|
|
rect.r_ybot /= scale;
|
|
|
|
|
rect.r_ytop /= scale;
|
|
|
|
|
GeoClip(&rect, arg->dCD_clip);
|
|
|
|
|
if (!GEO_RECTNULL(&rect)) {
|
|
|
|
|
(*(arg->dCD_function)) (arg->dCD_celldef, &rect,
|
|
|
|
|
arg->dCD_cptr, arg->dCD_clientData);
|
|
|
|
|
(*(arg->dCD_errors))++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* Mark this tile as pending and push it */
|
|
|
|
|
PUSHTILE(starttile);
|
|
|
|
|
TiToRect(starttile,&boundrect);
|
|
|
|
|
|
|
|
|
|
while (!StackEmpty(DRCstack))
|
|
|
|
|
{
|
|
|
|
|
tile = (Tile *) STACKPOP(DRCstack);
|
|
|
|
|
if (tile->ti_client != (ClientData)DRC_PENDING) continue;
|
|
|
|
|
|
|
|
|
|
if (boundrect.r_xbot > LEFT(tile)) boundrect.r_xbot = LEFT(tile);
|
|
|
|
|
if (boundrect.r_xtop < RIGHT(tile)) boundrect.r_xtop = RIGHT(tile);
|
|
|
|
|
if (boundrect.r_ybot > BOTTOM(tile)) boundrect.r_ybot = BOTTOM(tile);
|
|
|
|
|
if (boundrect.r_ytop < TOP(tile)) boundrect.r_ytop = TOP(tile);
|
|
|
|
|
tile->ti_client = (ClientData)DRC_PROCESSED;
|
|
|
|
|
|
|
|
|
|
if (boundrect.r_xtop - boundrect.r_xbot > edgelimit &&
|
|
|
|
|
boundrect.r_ytop - boundrect.r_ybot > edgelimit) break;
|
|
|
|
|
|
|
|
|
|
/* Top */
|
|
|
|
|
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
|
|
|
|
|
if (TTMaskHasType(oktypes, TiGetType(tp))) PUSHTILE(tp);
|
|
|
|
|
|
|
|
|
|
/* Left */
|
|
|
|
|
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
|
|
|
|
|
if (TTMaskHasType(oktypes, TiGetType(tp))) PUSHTILE(tp);
|
|
|
|
|
|
|
|
|
|
/* Bottom */
|
|
|
|
|
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
|
|
|
|
|
if (TTMaskHasType(oktypes, TiGetType(tp))) PUSHTILE(tp);
|
|
|
|
|
|
|
|
|
|
/* Right */
|
|
|
|
|
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
|
|
|
|
|
if (TTMaskHasType(oktypes, TiGetType(tp))) PUSHTILE(tp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (boundrect.r_xtop - boundrect.r_xbot > edgelimit &&
|
|
|
|
|
boundrect.r_ytop - boundrect.r_ybot > edgelimit)
|
|
|
|
|
{
|
|
|
|
|
Rect rect;
|
|
|
|
|
TiToRect(starttile,&rect);
|
|
|
|
|
{
|
|
|
|
|
rect.r_xbot /= scale;
|
|
|
|
|
rect.r_xtop /= scale;
|
|
|
|
|
rect.r_ybot /= scale;
|
|
|
|
|
rect.r_ytop /= scale;
|
|
|
|
|
GeoClip(&rect, arg->dCD_clip);
|
|
|
|
|
if (!GEO_RECTNULL(&rect)) {
|
|
|
|
|
(*(arg->dCD_function)) (arg->dCD_celldef, &rect,
|
|
|
|
|
arg->dCD_cptr, arg->dCD_clientData);
|
|
|
|
|
(*(arg->dCD_errors))++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
/* reset the tiles */
|
|
|
|
|
starttile->ti_client = (ClientData)DRC_UNPROCESSED;
|
|
|
|
|
STACKPUSH(starttile, DRCstack);
|
|
|
|
|
while (!StackEmpty(DRCstack))
|
|
|
|
|
{
|
|
|
|
|
tile = (Tile *) STACKPOP(DRCstack);
|
|
|
|
|
|
|
|
|
|
/* Top */
|
|
|
|
|
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
|
|
|
|
|
if (tp->ti_client != (ClientData)DRC_UNPROCESSED)
|
|
|
|
|
{
|
|
|
|
|
tp->ti_client = (ClientData)DRC_UNPROCESSED;
|
|
|
|
|
STACKPUSH(tp,DRCstack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Left */
|
|
|
|
|
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
|
|
|
|
|
if (tp->ti_client != (ClientData)DRC_UNPROCESSED)
|
|
|
|
|
{
|
|
|
|
|
tp->ti_client = (ClientData)DRC_UNPROCESSED;
|
|
|
|
|
STACKPUSH(tp,DRCstack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Bottom */
|
|
|
|
|
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
|
|
|
|
|
if (tp->ti_client != (ClientData)DRC_UNPROCESSED)
|
|
|
|
|
{
|
|
|
|
|
tp->ti_client = (ClientData)DRC_UNPROCESSED;
|
|
|
|
|
STACKPUSH(tp,DRCstack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Right */
|
|
|
|
|
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
|
|
|
|
|
if (tp->ti_client != (ClientData)DRC_UNPROCESSED)
|
|
|
|
|
{
|
|
|
|
|
tp->ti_client = (ClientData)DRC_UNPROCESSED;
|
|
|
|
|
STACKPUSH(tp,DRCstack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|