mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-09-05 08:51:53 +02:00
and forcing it to be passed as an argument to all the callback functions for the search routines that require it. Magic now compiles and runs with the new code, but there are a number of known issues that need to be fixed up. Committing now so that I can rebase on the last update to the master branch.
1608 lines
44 KiB
C
1608 lines
44 KiB
C
/*
|
|
* 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"
|
|
|
|
/* C99 compat */
|
|
#include "utils/tech.h"
|
|
#include "textio/textio.h"
|
|
|
|
extern int drcCifTile();
|
|
extern int areaCifCheck();
|
|
extern void drcCheckCifMaxwidth();
|
|
extern void drcCheckCifArea();
|
|
|
|
extern Stack *DRCstack;
|
|
|
|
#define PUSHTILE(tp) \
|
|
if (TiGetClient(tp) == DRC_UNPROCESSED) { \
|
|
TiSetClientINT(tp, DRC_PENDING); \
|
|
STACKPUSH((ClientData) (tp), DRCstack); \
|
|
}
|
|
|
|
extern CIFStyle *drcCifStyle;
|
|
extern bool DRCForceReload;
|
|
TileTypeBitMask drcCifGenLayers;
|
|
|
|
DRCCookie *drcCifRules[MAXCIFLAYERS][2];
|
|
DRCCookie *drcCifCur = NULL;
|
|
int drcCifValid = FALSE;
|
|
bool beenWarned = FALSE;
|
|
char *drcNeedStyle = NULL;
|
|
|
|
#define DRC_CIF_SPACE 0
|
|
#define DRC_CIF_SOLID 1
|
|
|
|
/* Define Euclidean distance checks */
|
|
|
|
#define RADIAL_NW 0x1000
|
|
#define RADIAL_NE 0x8000
|
|
#define RADIAL_SW 0x2000
|
|
#define RADIAL_SE 0x4000
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* 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]))
|
|
{
|
|
drcNeedStyle = new->cs_name;
|
|
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.
|
|
*
|
|
* Notes: "centidistance" is by default in centimicrons, but it is really in
|
|
* whatever units are declared in the cifoutput section; so if cifoutput
|
|
* declares nanometers, then units are in nanometers. This may be in
|
|
* different units from the non-CIF part of the DRC section. The escape
|
|
* sequence substitution in the "Why" text will make sure that the correct
|
|
* physical dimensions are presented to the end user.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
drcCifWidth(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
char *layername = argv[1];
|
|
int scalefactor;
|
|
int centidistance = atoi(argv[2]);
|
|
int why = drcWhyCreate(argv[3]);
|
|
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)));
|
|
drcCifAssign(dpnew, centidistance, dpnext, &CIFSolidBits,
|
|
&CIFSolidBits, why, centidistance,
|
|
DRC_FORWARD | DRC_CIFRULE, 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];
|
|
int why = drcWhyCreate(argv[5]);
|
|
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));
|
|
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits,
|
|
&cmask, why, centidistance, DRC_FORWARD | DRC_CIFRULE, 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));
|
|
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits,
|
|
&cmask, why, centidistance, DRC_REVERSE | DRC_CIFRULE, 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)));
|
|
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits, &cmask,
|
|
why, centidistance, DRC_FORWARD | DRC_BOTHCORNERS | DRC_CIFRULE,
|
|
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));
|
|
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits, &cmask,
|
|
why, centidistance, DRC_REVERSE | DRC_BOTHCORNERS | DRC_CIFRULE,
|
|
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)));
|
|
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits,
|
|
&cmask, why, centidistance,
|
|
DRC_REVERSE | DRC_BOTHCORNERS | DRC_CIFRULE,
|
|
layer[0], 0);
|
|
drcCifRules[layer[1]][DRC_CIF_SPACE] = dpnew;
|
|
|
|
dpnext = drcCifRules[layer[0]][DRC_CIF_SPACE];
|
|
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
|
drcCifAssign(dpnew, centidistance, dpnext, &DBSpaceBits, &cmask,
|
|
why, centidistance,
|
|
DRC_REVERSE | DRC_BOTHCORNERS | DRC_CIFRULE,
|
|
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)));
|
|
drcCifAssign(dpnew, scalefactor, dpnext, &DBSpaceBits, &DBZeroTypeBits,
|
|
why, scalefactor, DRC_FORWARD | DRC_CIFRULE, layer[0], 0);
|
|
drcCifRules[layer[1]][DRC_CIF_SPACE] = dpnew;
|
|
|
|
dpnext = drcCifRules[layer[0]][DRC_CIF_SPACE];
|
|
dpnew = (DRCCookie *) mallocMagic((unsigned) (sizeof (DRCCookie)));
|
|
drcCifAssign(dpnew, scalefactor, dpnext, &DBSpaceBits, &DBZeroTypeBits,
|
|
why, scalefactor, DRC_FORWARD | DRC_CIFRULE, 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;
|
|
CIFStyle *CIFSaveStyle = NULL;
|
|
|
|
if (CIFCurStyle != drcCifStyle)
|
|
{
|
|
if (drcNeedStyle == NULL) return;
|
|
|
|
CIFSaveStyle = CIFCurStyle;
|
|
|
|
if (drcCifStyle == NULL)
|
|
{
|
|
TxPrintf("Loading DRC CIF style.\n");
|
|
CIFCurStyle = NULL;
|
|
CIFLoadStyle(drcNeedStyle);
|
|
if (drcCifValid != FALSE)
|
|
CIFCurStyle = CIFSaveStyle;
|
|
else
|
|
drcCifStyle = CIFCurStyle;
|
|
}
|
|
if (drcCifStyle == NULL)
|
|
{
|
|
TxError("Error: Failed to load CIF DRC style.\n");
|
|
return;
|
|
}
|
|
CIFCurStyle = drcCifStyle;
|
|
}
|
|
if (drcCifValid == FALSE)
|
|
{
|
|
if (CIFSaveStyle != NULL)
|
|
CIFCurStyle = CIFSaveStyle;
|
|
return;
|
|
}
|
|
|
|
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, arg->dCD_celldef, checkRect, CIFPlanes,
|
|
&DBAllTypeBits, TRUE, TRUE, FALSE, (ClientData)NULL);
|
|
|
|
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;
|
|
|
|
/* Put it back the way you found it */
|
|
if (CIFSaveStyle != NULL) CIFCurStyle = CIFSaveStyle;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* 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, dinfo, arg)
|
|
Tile *tile; /* Tile being examined */
|
|
TileType dinfo; /* Split tile information */
|
|
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++;
|
|
|
|
/* For non-Manhattan tiles, if the left side of tile is not the */
|
|
/* type that is declared by the rule, then skip the left-right */
|
|
/* check. */
|
|
|
|
if (IsSplit(tile))
|
|
if (dinfo & TT_SIDE)
|
|
goto tbcheck;
|
|
|
|
/*
|
|
* 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 |= RADIAL_SW;
|
|
}
|
|
|
|
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 |= RADIAL_NW;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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 |= RADIAL_NE;
|
|
}
|
|
|
|
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 |= RADIAL_SE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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 &= 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++;
|
|
}
|
|
}
|
|
|
|
tbcheck:
|
|
|
|
/* For non-Manhattan tiles, if the bottom side of tile is not */
|
|
/* the type that is declared by the rule, then skip the top- */
|
|
/* bottom check. */
|
|
|
|
if (IsSplit(tile))
|
|
if (((dinfo & TT_SIDE) ? 1 : 0) == SplitDirection(tile))
|
|
return 0;
|
|
|
|
/*
|
|
* 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 |= RADIAL_SE;
|
|
}
|
|
|
|
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 |= RADIAL_SW;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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 |= RADIAL_NW;
|
|
}
|
|
|
|
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 |= RADIAL_NE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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, dinfo, arg)
|
|
Tile *tile;
|
|
TileType dinfo;
|
|
struct drcClientData *arg;
|
|
{
|
|
Rect rect; /* Area where error is to be recorded. */
|
|
Rect cifrect; /* rect, in CIF coordinates */
|
|
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, &cifrect);
|
|
GeoClip(&cifrect, arg->dCD_constraint);
|
|
if ((cifrect.r_xbot >= cifrect.r_xtop) || (cifrect.r_ybot >= cifrect.r_ytop))
|
|
return 0;
|
|
rect = cifrect;
|
|
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;
|
|
|
|
/*
|
|
* Euclidean distance checks
|
|
*/
|
|
if (arg->dCD_radial != 0)
|
|
{
|
|
unsigned int i;
|
|
int sqx, sqy;
|
|
int sdist = arg->dCD_radial & 0xfff;
|
|
long sstest, ssdist = (long) sdist * sdist;
|
|
|
|
if ((arg->dCD_radial & RADIAL_NW) != 0)
|
|
{
|
|
if (((sqx = arg->dCD_constraint->r_xbot + sdist
|
|
- cifrect.r_xtop) >= 0) && ((sqy = cifrect.r_ybot
|
|
- arg->dCD_constraint->r_ytop + sdist) >= 0)
|
|
&& ((sqx * sqx + sqy * sqy) >= ssdist))
|
|
return 0;
|
|
else if (IsSplit(tile) && !SplitDirection(tile) && !(dinfo & TT_SIDE))
|
|
{
|
|
sstest = drcCifPointToSegment(arg->dCD_constraint->r_xbot + sdist,
|
|
arg->dCD_constraint->r_ytop - sdist,
|
|
LEFT(tile), BOTTOM(tile), RIGHT(tile), TOP(tile));
|
|
if (sstest > ssdist) return 0;
|
|
}
|
|
}
|
|
if ((arg->dCD_radial & RADIAL_NE) != 0)
|
|
{
|
|
if (((sqx = cifrect.r_xbot - arg->dCD_constraint->r_xtop
|
|
+ sdist) >= 0) && ((sqy = cifrect.r_ybot
|
|
- arg->dCD_constraint->r_ytop + sdist) >= 0)
|
|
&& ((sqx * sqx + sqy * sqy) >= ssdist))
|
|
return 0;
|
|
else if (IsSplit(tile) && SplitDirection(tile) && (dinfo & TT_SIDE))
|
|
{
|
|
sstest = drcCifPointToSegment(arg->dCD_constraint->r_xtop - sdist,
|
|
arg->dCD_constraint->r_ytop - sdist,
|
|
LEFT(tile), TOP(tile), RIGHT(tile), BOTTOM(tile));
|
|
if (sstest > ssdist) return 0;
|
|
}
|
|
}
|
|
if ((arg->dCD_radial & RADIAL_SW) != 0)
|
|
{
|
|
if (((sqx = arg->dCD_constraint->r_xbot + sdist
|
|
- cifrect.r_xtop) >= 0) &&
|
|
((sqy = arg->dCD_constraint->r_ybot
|
|
+ sdist - cifrect.r_ytop) >= 0)
|
|
&& ((sqx * sqx + sqy * sqy) >= ssdist))
|
|
return 0;
|
|
else if (IsSplit(tile) && SplitDirection(tile) && !(dinfo & TT_SIDE))
|
|
{
|
|
sstest = drcCifPointToSegment(arg->dCD_constraint->r_xbot + sdist,
|
|
arg->dCD_constraint->r_ybot + sdist,
|
|
LEFT(tile), TOP(tile), RIGHT(tile), BOTTOM(tile));
|
|
if (sstest > ssdist) return 0;
|
|
}
|
|
}
|
|
if ((arg->dCD_radial & RADIAL_SE) != 0)
|
|
{
|
|
if (((sqx = cifrect.r_xbot - arg->dCD_constraint->r_xtop
|
|
+ sdist) >= 0) &&
|
|
((sqy = arg->dCD_constraint->r_ybot
|
|
+ sdist - cifrect.r_ytop) >= 0)
|
|
&& ((sqx * sqx + sqy * sqy) >= ssdist))
|
|
return 0;
|
|
else if (IsSplit(tile) && !SplitDirection(tile) && (dinfo & TT_SIDE))
|
|
{
|
|
sstest = drcCifPointToSegment(arg->dCD_constraint->r_xtop - sdist,
|
|
arg->dCD_constraint->r_ybot + sdist,
|
|
LEFT(tile), BOTTOM(tile), RIGHT(tile), TOP(tile));
|
|
if (sstest > ssdist) 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]);
|
|
int why = drcWhyCreate(argv[4]);
|
|
TileTypeBitMask set, setC, tmp1;
|
|
DRCCookie *dpnext, *dpnew;
|
|
TileType i, j;
|
|
int plane;
|
|
int thislayer = -1;
|
|
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)));
|
|
drcCifAssign(dpnew, centihorizon, dpnext, &CIFSolidBits, &CIFSolidBits,
|
|
why, centiarea, DRC_AREA | DRC_FORWARD | DRC_CIFRULE, 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];
|
|
int why = drcWhyCreate(argv[4]);
|
|
TileTypeBitMask set, setC, tmp1;
|
|
DRCCookie *dpnext, *dpnew;
|
|
TileType i, j;
|
|
int plane;
|
|
int bend;
|
|
int thislayer = -1;
|
|
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 if (strcmp(bends, "both") == 0) bend = DRC_MAXWIDTH_BOTH;
|
|
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)));
|
|
drcCifAssign(dpnew, centidistance, dpnext, &CIFSolidBits, &CIFSolidBits,
|
|
why, centidistance, DRC_MAXWIDTH | DRC_CIFRULE | 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 (TiGetClientINT(tile) != DRC_PENDING) continue;
|
|
area += (long)(RIGHT(tile)-LEFT(tile))*(TOP(tile)-BOTTOM(tile));
|
|
TiSetClientINT(tile, 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 */
|
|
TiSetClient(starttile, 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 (TiGetClient(tp) != DRC_UNPROCESSED)
|
|
{
|
|
TiSetClient(tp, DRC_UNPROCESSED);
|
|
STACKPUSH(tp,DRCstack);
|
|
}
|
|
|
|
/* Left */
|
|
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
|
|
if (TiGetClient(tp) != DRC_UNPROCESSED)
|
|
{
|
|
TiSetClient(tp, DRC_UNPROCESSED);
|
|
STACKPUSH(tp,DRCstack);
|
|
}
|
|
|
|
/* Bottom */
|
|
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
|
|
if (TiGetClient(tp) != DRC_UNPROCESSED)
|
|
{
|
|
TiSetClient(tp, DRC_UNPROCESSED);
|
|
STACKPUSH(tp,DRCstack);
|
|
}
|
|
|
|
/* Right */
|
|
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
|
|
if (TiGetClient(tp) != DRC_UNPROCESSED)
|
|
{
|
|
TiSetClient(tp, 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
|
|
* both dimensions exceed the max. This is pretty stupid, but it
|
|
* correctly calculates, e.g., the trench width rule. dcs 12.06.89
|
|
*
|
|
* Do the same for the "both" case, checking on a tile-by-tile basis
|
|
* that either dimension exceeds the max.
|
|
*/
|
|
|
|
if (cptr->drcc_flags & DRC_MAXWIDTH_BOTH)
|
|
{
|
|
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;
|
|
}
|
|
else if (cptr->drcc_flags & DRC_BENDS)
|
|
{
|
|
Rect rect;
|
|
|
|
/* Ignore split tiles; this is a limitation but another
|
|
* algorithm is needed to check for maximum width in a
|
|
* non-Manhattan area.
|
|
*/
|
|
if (IsSplit(starttile)) return;
|
|
|
|
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 (TiGetClientINT(tile) != 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);
|
|
TiSetClientINT(tile, 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 */
|
|
TiSetClient(starttile, 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 (TiGetClient(tp) != DRC_UNPROCESSED)
|
|
{
|
|
TiSetClient(tp, DRC_UNPROCESSED);
|
|
STACKPUSH(tp, DRCstack);
|
|
}
|
|
|
|
/* Left */
|
|
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
|
|
if (TiGetClient(tp) != DRC_UNPROCESSED)
|
|
{
|
|
TiSetClient(tp, DRC_UNPROCESSED);
|
|
STACKPUSH(tp, DRCstack);
|
|
}
|
|
|
|
/* Bottom */
|
|
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
|
|
if (TiGetClient(tp) != DRC_UNPROCESSED)
|
|
{
|
|
TiSetClient(tp, DRC_UNPROCESSED);
|
|
STACKPUSH(tp, DRCstack);
|
|
}
|
|
|
|
/* Right */
|
|
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
|
|
if (TiGetClient(tp) != DRC_UNPROCESSED)
|
|
{
|
|
TiSetClient(tp, DRC_UNPROCESSED);
|
|
STACKPUSH(tp, DRCstack);
|
|
}
|
|
}
|
|
}
|
|
|