1405 lines
40 KiB
C
1405 lines
40 KiB
C
/*
|
|
* DRCbasic.c --
|
|
*
|
|
* This file provides routines that make perform basic design-rule
|
|
* checking: given an area of a cell definition, this file will
|
|
* find all of the rule violations and call a client procedure for
|
|
* each one.
|
|
*
|
|
* *********************************************************************
|
|
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
|
* * Permission to use, copy, modify, and distribute this *
|
|
* * software and its documentation for any purpose and without *
|
|
* * fee is hereby granted, provided that the above copyright *
|
|
* * notice appear in all copies. The University of California *
|
|
* * makes no representations about the suitability of this *
|
|
* * software for any purpose. It is provided "as is" without *
|
|
* * express or implied warranty. Export of this software outside *
|
|
* * of the United States of America may require an export license. *
|
|
* *********************************************************************
|
|
*/
|
|
|
|
#ifndef lint
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/drc/DRCbasic.c,v 1.7 2010/09/20 21:13:22 tim Exp $";
|
|
#endif /* not lint */
|
|
|
|
#include <sys/types.h>
|
|
#include <stdio.h>
|
|
#include <string.h> // for memcpy()
|
|
#include <math.h> // for sqrt() for diagonal check
|
|
#include "utils/magic.h"
|
|
#include "utils/geometry.h"
|
|
#include "tiles/tile.h"
|
|
#include "utils/hash.h"
|
|
#include "database/database.h"
|
|
#include "drc/drc.h"
|
|
#include "utils/signals.h"
|
|
#include "utils/maxrect.h"
|
|
#include "utils/malloc.h"
|
|
#include "textio/textio.h"
|
|
|
|
int dbDRCDebug = 0;
|
|
|
|
/* The following DRC cookie is used when there are tiles of type
|
|
* TT_ERROR_S found during the basic DRC. These arise during
|
|
* hierarchical checking when there are illegal overlaps.
|
|
*/
|
|
|
|
static DRCCookie drcOverlapCookie = {
|
|
0, 0, 0, 0,
|
|
{ {0} }, { {0} },
|
|
0, 0, 0,
|
|
DRC_OVERLAP_TAG,
|
|
(DRCCookie *) NULL
|
|
};
|
|
|
|
/* Forward references: */
|
|
|
|
extern int areaCheck();
|
|
extern int drcTile();
|
|
extern MaxRectsData *drcCanonicalMaxwidth();
|
|
|
|
/*
|
|
*-----------------------------------------------------------------------
|
|
*
|
|
* drcCifPointToSegment
|
|
*
|
|
* Euclidean-distance point-to-segment distance (squared)
|
|
* calculation (borrowed from XCircuit)
|
|
*
|
|
* Results:
|
|
* Squared Euclidean distance of the closest approach of the
|
|
* line segment to the point (long result).
|
|
*
|
|
* Side Effects:
|
|
* None.
|
|
*
|
|
*-----------------------------------------------------------------------
|
|
*/
|
|
|
|
long
|
|
drcCifPointToSegment(px, py, s1x, s1y, s2x, s2y)
|
|
int px, py; /* The position of the point */
|
|
int s1x, s1y; /* One endpoint of the line segment */
|
|
int s2x, s2y; /* The other endpoint of the line segment */
|
|
{
|
|
long x, y;
|
|
long a, b, c, frac;
|
|
float protod;
|
|
|
|
x = (long)s2x - (long)s1x;
|
|
y = (long)s2y - (long)s1y;
|
|
c = (x * x + y * y);
|
|
|
|
x = (long)px - (long)s1x;
|
|
y = (long)py - (long)s1y;
|
|
a = (x * x + y * y);
|
|
|
|
x = (long)px - (long)s2x;
|
|
y = (long)py - (long)s2y;
|
|
b = (x * x + y * y);
|
|
|
|
frac = a - b;
|
|
if (frac >= c) return b;
|
|
else if (-frac >= c) return a;
|
|
else
|
|
{
|
|
protod = (float)(c + a - b);
|
|
return (a - (long)((protod * protod) / (float)(c << 2)));
|
|
}
|
|
}
|
|
|
|
/* Define Euclidean distance checks */
|
|
|
|
#define RADIAL_NW 0x1000
|
|
#define RADIAL_NE 0x8000
|
|
#define RADIAL_SW 0x2000
|
|
#define RADIAL_SE 0x4000
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* areaCheck --
|
|
*
|
|
* 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
|
|
areaCheck(tile, arg)
|
|
Tile *tile;
|
|
struct drcClientData *arg;
|
|
{
|
|
Rect rect; /* Area where error is to be recorded. */
|
|
|
|
TiToRect(tile, &rect);
|
|
|
|
/* Only consider the portion of the suspicious tile that overlaps
|
|
* the clip area for errors, unless this is a trigger rule, in
|
|
* which case it should be restricted only to the full check area.
|
|
*/
|
|
|
|
if (!(arg->dCD_cptr->drcc_flags & DRC_TRIGGER))
|
|
GeoClip(&rect, arg->dCD_clip);
|
|
else
|
|
GeoClip(&rect, arg->dCD_rect);
|
|
|
|
GeoClip(&rect, arg->dCD_constraint);
|
|
if ((rect.r_xbot >= rect.r_xtop) || (rect.r_ybot >= rect.r_ytop))
|
|
return 0;
|
|
|
|
/* Run-length rules are ignored unless the width of the error
|
|
* exceeds the run-length distance (which is held in the
|
|
* drcc_cdist entry for the rule).
|
|
*/
|
|
if (arg->dCD_cptr->drcc_flags & DRC_RUNLENGTH)
|
|
if (((rect.r_xtop - rect.r_xbot) < arg->dCD_cptr->drcc_cdist) &&
|
|
((rect.r_ytop - rect.r_ybot) < arg->dCD_cptr->drcc_cdist))
|
|
return 0;
|
|
|
|
/*
|
|
* When Euclidean distance checks are enabled, check for error tiles
|
|
* outside of the perimeter of the circle in the corner extension area
|
|
* that extends "sdist" from the corner of the edge.
|
|
*
|
|
* Also check the relatively rare case where the tile is inside the
|
|
* circle perimeter, but only the corner of the triangle projects into
|
|
* the error check rectangle, and is outside of the circle.
|
|
*/
|
|
|
|
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
|
|
- rect.r_xtop) >= 0) && ((sqy = rect.r_ybot
|
|
- arg->dCD_constraint->r_ytop + sdist) >= 0)
|
|
&& ((sqx * sqx + sqy * sqy) >= ssdist))
|
|
return 0;
|
|
else if (IsSplit(tile) && !SplitDirection(tile) && !SplitSide(tile))
|
|
{
|
|
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 = rect.r_xbot - arg->dCD_constraint->r_xtop
|
|
+ sdist) >= 0) && ((sqy = rect.r_ybot
|
|
- arg->dCD_constraint->r_ytop + sdist) >= 0)
|
|
&& ((sqx * sqx + sqy * sqy) >= ssdist))
|
|
return 0;
|
|
else if (IsSplit(tile) && SplitDirection(tile) && SplitSide(tile))
|
|
{
|
|
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
|
|
- rect.r_xtop) >= 0) &&
|
|
((sqy = arg->dCD_constraint->r_ybot
|
|
+ sdist - rect.r_ytop) >= 0)
|
|
&& ((sqx * sqx + sqy * sqy) >= ssdist))
|
|
return 0;
|
|
else if (IsSplit(tile) && SplitDirection(tile) && !SplitSide(tile))
|
|
{
|
|
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 = rect.r_xbot - arg->dCD_constraint->r_xtop
|
|
+ sdist) >= 0) &&
|
|
((sqy = arg->dCD_constraint->r_ybot
|
|
+ sdist - rect.r_ytop) >= 0)
|
|
&& ((sqx * sqx + sqy * sqy) >= ssdist))
|
|
return 0;
|
|
else if (IsSplit(tile) && !SplitDirection(tile) && SplitSide(tile))
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (arg->dCD_cptr->drcc_flags & DRC_TRIGGER)
|
|
{
|
|
Rect *newrlist;
|
|
int entries = arg->dCD_entries;
|
|
|
|
/* The following code allows the rect list to be expanded by */
|
|
/* multiples of 8, when necessary. */
|
|
|
|
arg->dCD_entries++;
|
|
if (arg->dCD_rlist == NULL)
|
|
arg->dCD_rlist = (Rect *)mallocMagic(8 * sizeof(Rect));
|
|
else if ((arg->dCD_entries & ~(entries | 7)) == arg->dCD_entries)
|
|
{
|
|
newrlist = (Rect *)mallocMagic((arg->dCD_entries << 1) * sizeof(Rect));
|
|
memcpy((void *)newrlist, (void *)arg->dCD_rlist, (size_t)entries *
|
|
sizeof(Rect));
|
|
freeMagic(arg->dCD_rlist);
|
|
arg->dCD_rlist = newrlist;
|
|
}
|
|
arg->dCD_rlist[arg->dCD_entries - 1] = rect;
|
|
}
|
|
/* "angles 45-only" needs to reject errors that are inside split tiles */
|
|
else if (!IsSplit(tile) ||
|
|
((arg->dCD_cptr->drcc_flags & (DRC_ANGLES_45 | DRC_ANGLES_90))
|
|
!= DRC_ANGLES_45))
|
|
{
|
|
(*(arg->dCD_function))(arg->dCD_celldef, &rect, arg->dCD_cptr,
|
|
arg->dCD_clientData);
|
|
(*(arg->dCD_errors))++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* areaNMReject ---
|
|
*
|
|
* Trivial callback function used by areaNMCheck to see if a tile
|
|
* found in the error area of a reverse non-manhattan check exists
|
|
* only on the other side of the original check boundary. If it
|
|
* is found in this search, return 1 to immediately stop the search.
|
|
*
|
|
* Results:
|
|
* Returns 1 if the tile indicated in the ClientData argument was
|
|
* found in the check area, otherwise return 0 to keep looking.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
areaNMReject(tile, arg)
|
|
Tile *tile;
|
|
ClientData *arg;
|
|
{
|
|
Tile *checktile = (Tile *)arg;
|
|
|
|
if (tile == checktile)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* areaNMCheck ---
|
|
*
|
|
* Check for errors in triangular area of a tile.
|
|
*
|
|
* Results:
|
|
* Return 0 always to keep the search going.
|
|
*
|
|
* Side effects:
|
|
* If the tile is not rejected due to being outside of the various
|
|
* clip areas, then call the function specified in the drcClientData
|
|
* argument.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
areaNMCheck(tile, arg)
|
|
Tile *tile;
|
|
struct drcClientData *arg;
|
|
{
|
|
Rect rect; /* Area where error is to be recorded. */
|
|
|
|
/* Ignore the tile that initiates the check, because the error area */
|
|
/* of a non-Manhattan check may fall inside of it. */
|
|
if (tile == arg->dCD_initial) return 0;
|
|
|
|
TiToRect(tile, &rect);
|
|
|
|
/* Only consider the portion of the suspicious tile that overlaps
|
|
* the clip area for errors, unless this is a trigger rule.
|
|
*/
|
|
|
|
if (!(arg->dCD_cptr->drcc_flags & DRC_TRIGGER))
|
|
GeoClip(&rect, arg->dCD_clip);
|
|
else
|
|
GeoClip(&rect, arg->dCD_rect);
|
|
|
|
GeoClip(&rect, arg->dCD_constraint);
|
|
if ((rect.r_xbot >= rect.r_xtop) || (rect.r_ybot >= rect.r_ytop))
|
|
return 0;
|
|
|
|
if (arg->dCD_entries & TT_DIAGONAL)
|
|
{
|
|
TileTypeBitMask mask;
|
|
int dinfo = arg->dCD_entries;
|
|
|
|
/* In the DRC_REVERSE case, the area being searched extends
|
|
* behind the edge that triggered the DRC check, but any
|
|
* tile that is outside that edge should be ignored. This
|
|
* requires a separate check.
|
|
*/
|
|
|
|
TTMaskSetOnlyType(&mask, TiGetLeftType(tile));
|
|
TTMaskSetType(&mask, TiGetRightType(tile));
|
|
if (DBSrPaintNMArea((Tile *)tile, (Plane *)NULL, dinfo, arg->dCD_rlist,
|
|
&mask, areaNMReject, (ClientData)tile) == 0)
|
|
return 0;
|
|
}
|
|
|
|
(*(arg->dCD_function))(arg->dCD_celldef, &rect, arg->dCD_cptr,
|
|
arg->dCD_clientData);
|
|
(*(arg->dCD_errors))++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* DRCBasicCheck --
|
|
*
|
|
* This is the top-level routine for basic design-rule checking.
|
|
*
|
|
* Results:
|
|
* Number of errors found.
|
|
*
|
|
* Side effects:
|
|
* Calls function for each design-rule violation in celldef
|
|
* that is triggered by an edge in rect and whose violation
|
|
* area falls within clipRect. This routine makes a flat check:
|
|
* it considers only information in the paint planes of celldef,
|
|
* and does not expand children. Function should have the form:
|
|
* void
|
|
* function(def, area, rule, cdarg)
|
|
* CellDef *def;
|
|
* Rect *area;
|
|
* DRCCookie *rule;
|
|
* ClientData cdarg;
|
|
* {
|
|
* }
|
|
*
|
|
* In the call to function, def is the definition containing the
|
|
* basic area being checked, area is the actual area where a
|
|
* rule is violated, rule is the rule being violated, and cdarg
|
|
* is the client data passed through all of our routines.
|
|
*
|
|
* Note:
|
|
* If an interrupt occurs (SigInterruptPending gets set), then
|
|
* the basic will be aborted immediately. This means the check
|
|
* may be incomplete.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
DRCBasicCheck (celldef, checkRect, clipRect, function, cdata)
|
|
CellDef *celldef; /* CellDef being checked */
|
|
Rect *checkRect; /* Check rules in this area -- usually two Haloes
|
|
* larger than the area where changes were made.
|
|
*/
|
|
Rect *clipRect; /* Clip error tiles against this area. */
|
|
void (*function)(); /* Function to apply for each error found. */
|
|
ClientData cdata; /* Passed to function as argument. */
|
|
{
|
|
struct drcClientData arg;
|
|
int errors;
|
|
int planeNum;
|
|
|
|
if (DRCCurStyle == NULL) return 0; /* No DRC, no errors */
|
|
|
|
/* Insist on top quality rectangles. */
|
|
|
|
if ((checkRect->r_xbot >= checkRect->r_xtop)
|
|
|| (checkRect->r_ybot >= checkRect->r_ytop))
|
|
return (0);
|
|
|
|
errors = 0;
|
|
|
|
arg.dCD_celldef = celldef;
|
|
arg.dCD_rect = checkRect;
|
|
arg.dCD_errors = &errors;
|
|
arg.dCD_function = function;
|
|
arg.dCD_clip = clipRect;
|
|
arg.dCD_clientData = cdata;
|
|
arg.dCD_rlist = NULL;
|
|
arg.dCD_entries = 0;
|
|
|
|
for (planeNum = PL_TECHDEPBASE; planeNum < DBNumPlanes; planeNum++)
|
|
{
|
|
arg.dCD_plane = planeNum;
|
|
DBResetTilePlane(celldef->cd_planes[planeNum], DRC_UNPROCESSED);
|
|
(void) DBSrPaintArea ((Tile *) NULL, celldef->cd_planes[planeNum],
|
|
checkRect, &DBAllTypeBits, drcTile, (ClientData) &arg);
|
|
}
|
|
drcCifCheck(&arg);
|
|
if (arg.dCD_rlist != NULL) freeMagic(arg.dCD_rlist);
|
|
return (errors);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* drcTile --
|
|
*
|
|
* This is a search function invoked once for each tile in
|
|
* the area to be checked. It checks design rules along the left
|
|
* and bottom of the given tile. If the tile extends beyond the
|
|
* clipping rectangle in any direction, then the boundary on that
|
|
* side of the tile will be skipped.
|
|
*
|
|
* 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
|
|
drcTile (tile, arg)
|
|
Tile *tile; /* Tile being examined */
|
|
struct drcClientData *arg;
|
|
{
|
|
DRCCookie *cptr; /* Current design rule on list */
|
|
Rect *rect = arg->dCD_rect; /* Area being checked */
|
|
Rect errRect; /* Area checked for an individual rule */
|
|
MaxRectsData *mrd; /* Used by widespacing rule */
|
|
TileTypeBitMask tmpMask, *rMask;
|
|
bool trigpending; /* Hack for widespacing rule */
|
|
bool firsttile;
|
|
int triggered;
|
|
int cdist, dist, ccdist, result;
|
|
|
|
arg->dCD_constraint = &errRect;
|
|
|
|
/*
|
|
* If we were interrupted, we want to
|
|
* abort the check as quickly as possible.
|
|
*/
|
|
if (SigInterruptPending) return 1;
|
|
DRCstatTiles++;
|
|
|
|
/* If this tile is an error tile, it arose because of an illegal
|
|
* overlap between things in adjacent cells. This means that
|
|
* there's an automatic violation over the area of the tile.
|
|
*/
|
|
|
|
if (TiGetType(tile) == TT_ERROR_S)
|
|
{
|
|
TiToRect(tile, &errRect);
|
|
GeoClip(&errRect, rect);
|
|
(*(arg->dCD_function)) (arg->dCD_celldef, &errRect,
|
|
&drcOverlapCookie, arg->dCD_clientData);
|
|
(*(arg->dCD_errors))++;
|
|
}
|
|
|
|
/* Diagonally split tiles are processed twice. Just like the */
|
|
/* DRC searches only one direction on regular tiles, the split */
|
|
/* tiles are only processed for one of the two cases. */
|
|
|
|
if (IsSplit(tile) && !SplitSide(tile))
|
|
{
|
|
int deltax, deltay;
|
|
TileType tt, to;
|
|
|
|
tt = TiGetLeftType(tile); /* inside type */
|
|
to = TiGetRightType(tile); /* outside type */
|
|
|
|
/* Check rules for DRC_ANGLES_90 rule and process */
|
|
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt];
|
|
cptr != (DRCCookie *) NULL; cptr = cptr->drcc_next)
|
|
if (cptr->drcc_flags & DRC_ANGLES_90)
|
|
{
|
|
drcCheckAngles(tile, arg, cptr);
|
|
break;
|
|
}
|
|
|
|
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
|
|
cptr = cptr->drcc_next)
|
|
{
|
|
int deltax, deltay, w, h;
|
|
double r;
|
|
TileType dinfo, dsplit;
|
|
|
|
/* Work to be done: Handle triggering rules for non-Manhattan */
|
|
/* edges; especially important for the wide-spacing rule. */
|
|
|
|
if (cptr->drcc_flags & DRC_TRIGGER)
|
|
{
|
|
cptr = cptr->drcc_next; // Skip both triggering and triggered rules
|
|
continue;
|
|
}
|
|
|
|
/* Note: Triggered wide-spacing rule will require handling */
|
|
/* the DRC_MAXWIDTH rule on non-Manhattan edges. */
|
|
|
|
if (cptr->drcc_flags & (DRC_ANGLES_90 | DRC_AREA | DRC_MAXWIDTH
|
|
| DRC_RECTSIZE | DRC_OFFGRID))
|
|
continue;
|
|
|
|
TiToRect(tile, &errRect);
|
|
|
|
/* Find the rule distances according to the scale factor */
|
|
dist = cptr->drcc_dist;
|
|
|
|
/* drcc_edgeplane is used to avoid checks on edges */
|
|
/* in more than one plane */
|
|
|
|
if (arg->dCD_plane != cptr->drcc_edgeplane) continue;
|
|
|
|
DRCstatRules++;
|
|
|
|
DRCstatSlow++;
|
|
arg->dCD_cptr = cptr;
|
|
arg->dCD_entries = 0;
|
|
TTMaskCom2(&tmpMask, &cptr->drcc_mask);
|
|
TTMaskClearType(&tmpMask, TT_ERROR_S);
|
|
arg->dCD_initial = tile;
|
|
|
|
/* Compute position that is the rule distance away from */
|
|
/* the tile's diagonal edge, by Euclidean measure */
|
|
/* (rounded down if fractional). Use the forward */
|
|
/* position, and negate if reversed. */
|
|
|
|
w = RIGHT(tile) - LEFT(tile);
|
|
h = TOP(tile) - BOTTOM(tile);
|
|
r = 1.0 / (1.0 + ((double)(w * w) / (double)(h * h)));
|
|
deltax = (int)((double)cptr->drcc_dist * sqrt(r));
|
|
deltay = (deltax * w) / h;
|
|
|
|
if (SplitDirection(tile) == 0) deltay = -deltay;
|
|
|
|
dinfo = TiGetTypeExact(tile) & (TT_DIAGONAL | TT_DIRECTION);
|
|
if (!(cptr->drcc_flags & DRC_REVERSE))
|
|
{
|
|
/* Forward case is behind the triangle */
|
|
deltax = -deltax;
|
|
deltay = -deltay;
|
|
|
|
/* Split side changes in the reverse case */
|
|
dinfo |= TT_SIDE;
|
|
}
|
|
|
|
/* The area to check is bounded between the diagonals of
|
|
* tile and errRect (which is the tile area, offset).
|
|
* Pass errRect and dinfo to areaNMCheck using the
|
|
* ClientData structure arg->dCD_rlist and arg->dCD_entries,
|
|
* which are not used by areaNMCheck.
|
|
*/
|
|
arg->dCD_rlist = (Rect *)mallocMagic(sizeof(Rect));
|
|
*(arg->dCD_rlist) = errRect;
|
|
arg->dCD_entries = dinfo;
|
|
if (dinfo & TT_SIDE)
|
|
arg->dCD_entries &= ~TT_SIDE;
|
|
else
|
|
arg->dCD_entries |= TT_SIDE;
|
|
|
|
/* errRect is the tile area offset by (deltax, deltay) */
|
|
errRect.r_xbot += deltax;
|
|
errRect.r_ybot += deltay;
|
|
errRect.r_xtop += deltax;
|
|
errRect.r_ytop += deltay;
|
|
|
|
DBSrPaintNMArea((Tile *) NULL,
|
|
arg->dCD_celldef->cd_planes[cptr->drcc_plane], dinfo,
|
|
&errRect, &tmpMask, areaNMCheck, (ClientData) arg);
|
|
|
|
arg->dCD_entries = 0;
|
|
freeMagic(arg->dCD_rlist);
|
|
arg->dCD_rlist = (Rect *)NULL;
|
|
}
|
|
DRCstatEdges++;
|
|
}
|
|
|
|
/*
|
|
* 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 (LEFT(tile) >= rect->r_xbot) /* check tile against rect */
|
|
{
|
|
Tile *tpleft, *tpl, *tpr;
|
|
TileType tt, to;
|
|
int edgeTop, edgeBot;
|
|
int top = MIN(TOP(tile), rect->r_ytop);
|
|
int bottom = MAX(BOTTOM(tile), rect->r_ybot);
|
|
int edgeX = LEFT(tile);
|
|
|
|
firsttile = TRUE;
|
|
mrd = NULL;
|
|
for (tpleft = BL(tile); BOTTOM(tpleft) < top; tpleft = RT(tpleft))
|
|
{
|
|
/* Get the tile types to the left and right of the edge */
|
|
|
|
tt = TiGetLeftType(tile);
|
|
to = TiGetRightType(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 read-in
|
|
* the user is warned that such edges are not checked).
|
|
*/
|
|
|
|
if (tt == to) 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;
|
|
|
|
triggered = 0;
|
|
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
|
|
cptr = cptr->drcc_next)
|
|
{
|
|
/* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
|
|
/* the code above for non-Manhattan shapes and do not */
|
|
/* need to be processed again. */
|
|
if (cptr->drcc_flags & (DRC_ANGLES_90 | DRC_SPLITTILE))
|
|
continue;
|
|
|
|
/* Find the rule distances according to the scale factor */
|
|
dist = cptr->drcc_dist;
|
|
cdist = cptr->drcc_cdist;
|
|
trigpending = (cptr->drcc_flags & DRC_TRIGGER) ? TRUE : FALSE;
|
|
|
|
/* drcc_edgeplane is used to avoid checks on edges */
|
|
/* in more than one plane */
|
|
|
|
if (arg->dCD_plane != cptr->drcc_edgeplane)
|
|
{
|
|
if (trigpending) cptr = cptr->drcc_next;
|
|
continue;
|
|
}
|
|
|
|
DRCstatRules++;
|
|
|
|
if (cptr->drcc_flags & DRC_AREA)
|
|
{
|
|
if (firsttile)
|
|
drcCheckArea(tile, arg, cptr);
|
|
continue;
|
|
}
|
|
|
|
if ((cptr->drcc_flags & (DRC_MAXWIDTH | DRC_BENDS)) ==
|
|
(DRC_MAXWIDTH | DRC_BENDS))
|
|
{
|
|
/* New algorithm --- Tim 3/6/05 */
|
|
Rect *lr;
|
|
int i;
|
|
|
|
if (!trigpending || (DRCCurStyle->DRCFlags
|
|
& DRC_FLAGS_WIDEWIDTH_NONINCLUSIVE))
|
|
cptr->drcc_dist++;
|
|
|
|
if (cptr->drcc_flags & DRC_REVERSE)
|
|
{
|
|
mrd = drcCanonicalMaxwidth(tpleft, GEO_WEST, arg, cptr);
|
|
triggered = 0;
|
|
}
|
|
else if (firsttile)
|
|
{
|
|
mrd = drcCanonicalMaxwidth(tile, GEO_EAST, arg, cptr);
|
|
triggered = 0;
|
|
}
|
|
if (!trigpending || (DRCCurStyle->DRCFlags
|
|
& DRC_FLAGS_WIDEWIDTH_NONINCLUSIVE))
|
|
cptr->drcc_dist--;
|
|
if (trigpending)
|
|
{
|
|
if (mrd)
|
|
{
|
|
if (cptr->drcc_cdist <= cptr->drcc_dist)
|
|
triggered = mrd->entries;
|
|
else if ((edgeTop - edgeBot) >= cptr->drcc_cdist)
|
|
{
|
|
/* Run-length rule */
|
|
for (i = 0; i < mrd->entries; i++)
|
|
{
|
|
lr = &mrd->rlist[i];
|
|
if ((lr->r_ytop - lr->r_ybot) > cptr->drcc_cdist)
|
|
{
|
|
triggered = mrd->entries;
|
|
break;
|
|
}
|
|
}
|
|
if (i == mrd->entries)
|
|
cptr = cptr->drcc_next;
|
|
}
|
|
else
|
|
cptr = cptr->drcc_next;
|
|
}
|
|
else
|
|
cptr = cptr->drcc_next;
|
|
}
|
|
else if (mrd)
|
|
{
|
|
for (i = 0; i < mrd->entries; i++)
|
|
{
|
|
lr = &mrd->rlist[i];
|
|
GeoClip(lr, arg->dCD_clip);
|
|
if (!GEO_RECTNULL(lr))
|
|
{
|
|
(*(arg->dCD_function)) (arg->dCD_celldef,
|
|
lr, cptr, arg->dCD_clientData);
|
|
(*(arg->dCD_errors))++;
|
|
}
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
else if (cptr->drcc_flags & DRC_MAXWIDTH)
|
|
{
|
|
if (cptr->drcc_flags & DRC_MAXWIDTH_BOTH)
|
|
{
|
|
if (firsttile)
|
|
drcCheckMaxwidth(tile, arg, cptr, TRUE);
|
|
}
|
|
else
|
|
{
|
|
/* bends_illegal option only */
|
|
if (firsttile)
|
|
drcCheckMaxwidth(tile, arg, cptr, FALSE);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (cptr->drcc_flags & DRC_RECTSIZE)
|
|
{
|
|
/* only checked for bottom-left tile in a rect area */
|
|
if (firsttile && !TTMaskHasType(&cptr->drcc_mask,
|
|
TiGetRightType(BL(tile))) &&
|
|
!TTMaskHasType(&cptr->drcc_mask,
|
|
TiGetTopType(LB(tile))))
|
|
drcCheckRectSize(tile, arg, cptr);
|
|
continue;
|
|
}
|
|
/* Off-grid checks apply only to edge */
|
|
if (cptr->drcc_flags & DRC_OFFGRID)
|
|
{
|
|
errRect.r_ytop = edgeTop;
|
|
errRect.r_ybot = edgeBot;
|
|
errRect.r_xtop = errRect.r_xbot = edgeX;
|
|
arg->dCD_cptr = cptr;
|
|
drcCheckOffGrid(&errRect, arg, cptr);
|
|
continue;
|
|
}
|
|
|
|
result = 0;
|
|
arg->dCD_radial = 0;
|
|
arg->dCD_entries = 0;
|
|
do {
|
|
if (triggered)
|
|
{
|
|
/* For triggered rules, we want to look at the */
|
|
/* clipped region found by the triggering rule */
|
|
|
|
if (mrd)
|
|
errRect = mrd->rlist[--triggered];
|
|
else
|
|
errRect = arg->dCD_rlist[--triggered];
|
|
errRect.r_ytop += cdist;
|
|
errRect.r_ybot -= cdist;
|
|
if (errRect.r_ytop > edgeTop) errRect.r_ytop = edgeTop;
|
|
if (errRect.r_ybot < edgeBot) errRect.r_ybot = edgeBot;
|
|
}
|
|
else
|
|
{
|
|
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 */
|
|
if (BOTTOM(tile) >= errRect.r_ybot) tpr = LB(tile);
|
|
else tpr = tile;
|
|
|
|
/* Also find point (2) to check for edge continuation */
|
|
if (BOTTOM(tpleft) >= errRect.r_ybot)
|
|
for (tpl = LB(tpleft); RIGHT(tpl) < edgeX; tpl = TR(tpl));
|
|
else tpl = tpleft;
|
|
|
|
/* Make sure the edge stops at edgeBot */
|
|
if ((TiGetRightType(tpl) != TiGetRightType(tpleft)) ||
|
|
(TiGetLeftType(tpr) != TiGetLeftType(tile)))
|
|
{
|
|
if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tpr)))
|
|
{
|
|
errRect.r_ybot -= cdist;
|
|
if (DRCEuclidean && !(cptr->drcc_flags & DRC_MANHATTAN))
|
|
arg->dCD_radial |= RADIAL_SW;
|
|
}
|
|
}
|
|
|
|
if (cptr->drcc_flags & DRC_BOTHCORNERS)
|
|
{
|
|
/*
|
|
* Check the other corner
|
|
*/
|
|
|
|
/* Find point (4) to the top right of pointT */
|
|
if (TOP(tile) <= errRect.r_ytop)
|
|
for (tpr = RT(tile); LEFT(tpr) > edgeX; tpr = BL(tpr));
|
|
else tpr = tile;
|
|
|
|
/* Also find point (1) to check for edge continuation */
|
|
if (TOP(tpleft) <= errRect.r_ytop) tpl = RT(tpleft);
|
|
else tpl = tpleft;
|
|
|
|
/* Make sure the edge stops at edgeTop */
|
|
if ((TiGetRightType(tpl) != TiGetRightType(tpleft)) ||
|
|
(TiGetLeftType(tpr) != TiGetLeftType(tile)))
|
|
{
|
|
if (TTMaskHasType(&cptr->drcc_corner,
|
|
TiGetBottomType(tpr)))
|
|
{
|
|
errRect.r_ytop += cdist;
|
|
if (DRCEuclidean &&
|
|
!(cptr->drcc_flags & DRC_MANHATTAN))
|
|
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 - dist;
|
|
if (cptr->drcc_flags & DRC_OUTSIDE) errRect.r_xbot--;
|
|
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,
|
|
TiGetRightType(tpleft)))
|
|
continue;
|
|
|
|
errRect.r_xtop = edgeX;
|
|
if (cptr->drcc_flags & DRC_OUTSIDE) errRect.r_xtop -= dist;
|
|
arg->dCD_initial = tile;
|
|
}
|
|
else /* FORWARD */
|
|
{
|
|
/*
|
|
* Determine corner extensions.
|
|
*/
|
|
|
|
/* Find the point (1) to the top left of pointT */
|
|
if (TOP(tpleft) <= errRect.r_ytop) tpl = RT(tpleft);
|
|
else tpl = tpleft;
|
|
|
|
/* Also find point (4) to check for edge continuation */
|
|
if (TOP(tile) <= errRect.r_ytop)
|
|
for (tpr = RT(tile); LEFT(tpr) > edgeX; tpr = BL(tpr));
|
|
else tpr = tile;
|
|
|
|
/* Make sure the edge stops at edgeTop */
|
|
if ((TiGetRightType(tpl) != TiGetRightType(tpleft)) ||
|
|
(TiGetLeftType(tpr) != TiGetLeftType(tile)))
|
|
{
|
|
if (TTMaskHasType(&cptr->drcc_corner, TiGetBottomType(tpl)))
|
|
{
|
|
errRect.r_ytop += cdist;
|
|
if (DRCEuclidean && !(cptr->drcc_flags & DRC_MANHATTAN))
|
|
arg->dCD_radial |= RADIAL_NE;
|
|
}
|
|
}
|
|
|
|
if (cptr->drcc_flags & DRC_BOTHCORNERS)
|
|
{
|
|
/*
|
|
* Check the other corner
|
|
*/
|
|
|
|
/* Find point (2) to the bottom left of pointB. */
|
|
if (BOTTOM(tpleft) >= errRect.r_ybot)
|
|
for (tpl = LB(tpleft); RIGHT(tpl) < edgeX; tpl = TR(tpl));
|
|
else tpl = tpleft;
|
|
|
|
/* Also find point (3) to check for edge continuation */
|
|
if (BOTTOM(tile) >= errRect.r_ybot) tpr = LB(tile);
|
|
else tpr = tile;
|
|
|
|
/* Make sure the edge stops at edgeBot */
|
|
if ((TiGetRightType(tpl) != TiGetRightType(tpleft)) ||
|
|
(TiGetLeftType(tpr) != TiGetLeftType(tile)))
|
|
{
|
|
if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tpl)))
|
|
{
|
|
errRect.r_ybot -= cdist;
|
|
if (DRCEuclidean &&
|
|
!(cptr->drcc_flags & DRC_MANHATTAN))
|
|
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 + dist;
|
|
if (cptr->drcc_flags & DRC_OUTSIDE) errRect.r_xtop++;
|
|
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;
|
|
if (cptr->drcc_flags & DRC_OUTSIDE) errRect.r_xbot += dist;
|
|
arg->dCD_initial= tpleft;
|
|
}
|
|
if (arg->dCD_radial)
|
|
{
|
|
arg->dCD_radial &= 0xf000;
|
|
arg->dCD_radial |= (0xfff & cdist);
|
|
}
|
|
|
|
DRCstatSlow++;
|
|
arg->dCD_cptr = cptr;
|
|
arg->dCD_entries = 0;
|
|
TTMaskCom2(&tmpMask, &cptr->drcc_mask);
|
|
TTMaskClearType(&tmpMask, TT_ERROR_S);
|
|
DBSrPaintArea((Tile *) NULL,
|
|
arg->dCD_celldef->cd_planes[cptr->drcc_plane],
|
|
&errRect, &tmpMask, areaCheck, (ClientData) arg);
|
|
} while (triggered);
|
|
|
|
if (arg->dCD_entries == 0)
|
|
{
|
|
/* Trigger rule: If rule check found errors, */
|
|
/* do the next rule. Otherwise, skip it. */
|
|
|
|
if (trigpending)
|
|
cptr = cptr->drcc_next;
|
|
}
|
|
else
|
|
triggered = arg->dCD_entries;
|
|
}
|
|
DRCstatEdges++;
|
|
firsttile = FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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, *tpx;
|
|
TileType tt, to;
|
|
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 */
|
|
firsttile = TRUE;
|
|
mrd = NULL;
|
|
for (tpbot = LB(tile); LEFT(tpbot) < right; tpbot = TR(tpbot))
|
|
{
|
|
/* Get the tile types to the top and bottom of the edge */
|
|
|
|
tt = TiGetBottomType(tile);
|
|
to = TiGetTopType(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 (tt == to) 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;
|
|
|
|
triggered = 0;
|
|
for (cptr = DRCCurStyle->DRCRulesTbl[to][tt]; cptr != (DRCCookie *) NULL;
|
|
cptr = cptr->drcc_next)
|
|
{
|
|
/* DRC_ANGLES_90 and DRC_SPLITTILE rules are handled by */
|
|
/* the code above for non-Manhattan shapes and do not */
|
|
/* need to be processed again. */
|
|
if (cptr->drcc_flags & (DRC_ANGLES_90 | DRC_SPLITTILE))
|
|
continue;
|
|
|
|
/* Find the rule distances according to the scale factor */
|
|
dist = cptr->drcc_dist;
|
|
cdist = (cptr->drcc_flags & DRC_RUNLENGTH) ? 0 : cptr->drcc_cdist;
|
|
trigpending = (cptr->drcc_flags & DRC_TRIGGER) ? TRUE : FALSE;
|
|
|
|
/* drcc_edgeplane is used to avoid checks on edges */
|
|
/* in more than one plane */
|
|
|
|
if (arg->dCD_plane != cptr->drcc_edgeplane)
|
|
{
|
|
if (trigpending) cptr = cptr->drcc_next;
|
|
continue;
|
|
}
|
|
|
|
DRCstatRules++;
|
|
|
|
/* top to bottom */
|
|
|
|
if ((cptr->drcc_flags & (DRC_MAXWIDTH | DRC_BENDS)) ==
|
|
(DRC_MAXWIDTH | DRC_BENDS))
|
|
{
|
|
/* New algorithm --- Tim 3/6/05 */
|
|
Rect *lr;
|
|
int i;
|
|
|
|
if (!trigpending || (DRCCurStyle->DRCFlags
|
|
& DRC_FLAGS_WIDEWIDTH_NONINCLUSIVE))
|
|
cptr->drcc_dist++;
|
|
|
|
if (cptr->drcc_flags & DRC_REVERSE)
|
|
{
|
|
mrd = drcCanonicalMaxwidth(tpbot, GEO_SOUTH, arg, cptr);
|
|
triggered = 0;
|
|
}
|
|
else if (firsttile)
|
|
{
|
|
mrd = drcCanonicalMaxwidth(tile, GEO_NORTH, arg, cptr);
|
|
triggered = 0;
|
|
}
|
|
if (!trigpending || (DRCCurStyle->DRCFlags
|
|
& DRC_FLAGS_WIDEWIDTH_NONINCLUSIVE))
|
|
cptr->drcc_dist--;
|
|
if (trigpending)
|
|
{
|
|
if (mrd)
|
|
{
|
|
if (cptr->drcc_cdist <= cptr->drcc_dist)
|
|
triggered = mrd->entries;
|
|
else if ((edgeRight - edgeLeft) >= cptr->drcc_cdist)
|
|
{
|
|
/* Run-length rule */
|
|
for (i = 0; i < mrd->entries; i++)
|
|
{
|
|
lr = &mrd->rlist[i];
|
|
if ((lr->r_xtop - lr->r_xbot) > cptr->drcc_cdist)
|
|
{
|
|
triggered = mrd->entries;
|
|
break;
|
|
}
|
|
}
|
|
if (i == mrd->entries)
|
|
cptr = cptr->drcc_next;
|
|
}
|
|
else
|
|
cptr = cptr->drcc_next;
|
|
}
|
|
else
|
|
cptr = cptr->drcc_next;
|
|
}
|
|
else if (mrd)
|
|
{
|
|
for (i = 0; i < mrd->entries; i++)
|
|
{
|
|
lr = &mrd->rlist[i];
|
|
GeoClip(lr, arg->dCD_clip);
|
|
if (!GEO_RECTNULL(lr))
|
|
{
|
|
(*(arg->dCD_function)) (arg->dCD_celldef,
|
|
lr, cptr, arg->dCD_clientData);
|
|
(*(arg->dCD_errors))++;
|
|
}
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
else if (cptr->drcc_flags & (DRC_AREA | DRC_RECTSIZE | DRC_MAXWIDTH))
|
|
{
|
|
/* only have to do these checks in one direction */
|
|
if (trigpending) cptr = cptr->drcc_next;
|
|
continue;
|
|
}
|
|
/* Off-grid checks apply only to edge */
|
|
if (cptr->drcc_flags & DRC_OFFGRID)
|
|
{
|
|
errRect.r_xtop = edgeRight;
|
|
errRect.r_xbot = edgeLeft;
|
|
errRect.r_ytop = errRect.r_ybot = edgeY;
|
|
arg->dCD_cptr = cptr;
|
|
drcCheckOffGrid(&errRect, arg, cptr);
|
|
continue;
|
|
}
|
|
|
|
result = 0;
|
|
arg->dCD_radial = 0;
|
|
arg->dCD_entries = 0;
|
|
do {
|
|
if (triggered)
|
|
{
|
|
/* For triggered rules, we want to look at the */
|
|
/* clipped region found by the triggering rule */
|
|
|
|
if (mrd)
|
|
errRect = mrd->rlist[--triggered];
|
|
else
|
|
errRect = arg->dCD_rlist[--triggered];
|
|
errRect.r_xtop += cdist;
|
|
errRect.r_xbot -= cdist;
|
|
if (errRect.r_xtop > edgeRight) errRect.r_xtop = edgeRight;
|
|
if (errRect.r_xbot < edgeLeft) errRect.r_xbot = edgeLeft;
|
|
}
|
|
else
|
|
{
|
|
errRect.r_xbot = edgeLeft;
|
|
errRect.r_xtop = edgeRight;
|
|
}
|
|
|
|
if (cptr->drcc_flags & DRC_REVERSE)
|
|
{
|
|
/*
|
|
* Determine corner extensions.
|
|
* Find the point (3) to the top right of pointR
|
|
*/
|
|
if (RIGHT(tile) <= errRect.r_xtop)
|
|
for (tpx = TR(tile); BOTTOM(tpx) > edgeY; tpx = LB(tpx));
|
|
else tpx = tile;
|
|
|
|
if (TTMaskHasType(&cptr->drcc_corner, TiGetBottomType(tpx)))
|
|
{
|
|
errRect.r_xtop += cdist;
|
|
if (DRCEuclidean && !(cptr->drcc_flags & DRC_MANHATTAN))
|
|
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.
|
|
*/
|
|
|
|
if (LEFT(tile) >= errRect.r_xbot) tpx = BL(tile);
|
|
else tpx = tile;
|
|
|
|
if (TTMaskHasType(&cptr->drcc_corner, TiGetBottomType(tpx)))
|
|
{
|
|
errRect.r_xbot -= cdist;
|
|
if (DRCEuclidean && !(cptr->drcc_flags & DRC_MANHATTAN))
|
|
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 - dist;
|
|
if (cptr->drcc_flags & DRC_OUTSIDE) errRect.r_ybot--;
|
|
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;
|
|
if (cptr->drcc_flags & DRC_OUTSIDE) errRect.r_ytop -= dist;
|
|
arg->dCD_initial = tile;
|
|
}
|
|
else /* FORWARD */
|
|
{
|
|
/*
|
|
* Determine corner extensions.
|
|
* Find the point (1) to the bottom left of pointL
|
|
*/
|
|
|
|
if (LEFT(tpbot) >= errRect.r_xbot)
|
|
for (tpx = BL(tpbot); TOP(tpx) < edgeY; tpx = RT(tpx));
|
|
else tpx = tpbot;
|
|
|
|
if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tpx)))
|
|
{
|
|
errRect.r_xbot -= cdist;
|
|
if (DRCEuclidean && !(cptr->drcc_flags & DRC_MANHATTAN))
|
|
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.
|
|
*/
|
|
if (RIGHT(tpbot) <= errRect.r_xtop) tpx = TR(tpbot);
|
|
else tpx = tpbot;
|
|
|
|
if (TTMaskHasType(&cptr->drcc_corner, TiGetTopType(tpx)))
|
|
{
|
|
errRect.r_xtop += cdist;
|
|
if (DRCEuclidean && !(cptr->drcc_flags & DRC_MANHATTAN))
|
|
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 + dist;
|
|
if (cptr->drcc_flags & DRC_OUTSIDE) errRect.r_ytop++;
|
|
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,
|
|
TiGetBottomType(tile)))
|
|
continue;
|
|
|
|
errRect.r_ybot = edgeY;
|
|
if (cptr->drcc_flags & DRC_OUTSIDE) errRect.r_ybot += dist;
|
|
arg->dCD_initial = tpbot;
|
|
}
|
|
if (arg->dCD_radial)
|
|
{
|
|
arg->dCD_radial &= 0xf000;
|
|
arg->dCD_radial |= (0xfff & cdist);
|
|
}
|
|
|
|
DRCstatSlow++;
|
|
arg->dCD_cptr = cptr;
|
|
arg->dCD_entries = 0;
|
|
TTMaskCom2(&tmpMask, &cptr->drcc_mask);
|
|
TTMaskClearType(&tmpMask, TT_ERROR_S);
|
|
DBSrPaintArea((Tile *) NULL,
|
|
arg->dCD_celldef->cd_planes[cptr->drcc_plane],
|
|
&errRect, &tmpMask, areaCheck, (ClientData) arg);
|
|
} while (triggered);
|
|
|
|
if (arg->dCD_entries == 0)
|
|
{
|
|
/* Trigger rule: If rule check found errors, */
|
|
/* do the next rule. Otherwise, skip it. */
|
|
|
|
if (trigpending)
|
|
cptr = cptr->drcc_next;
|
|
}
|
|
else
|
|
triggered = arg->dCD_entries;
|
|
}
|
|
DRCstatEdges++;
|
|
firsttile = FALSE;
|
|
}
|
|
}
|
|
return (0);
|
|
}
|