Files
magic/drc/DRCsubcell.c
T
Tim Edwards db4fa65bfc Corrected some issues related to the handling of substrate hierarchy.
Most of this had to do with the incorrect use of the parent's substrate
name in extHierSubstrate().  After the correction, there still remains
an issue that is caused when a labeled isolated substrate region overlaps
an extraction tile boundary.  I believe that this particular error has
existed for some time and is not new, so I am committing these changes.
2022-02-24 16:47:11 -05:00

968 lines
30 KiB
C

/*
* DRCsubcell.c --
*
* This file provides the facilities for finding design-rule
* violations that occur as a result of interactions between
* subcells and either paint or other subcells.
*
* *********************************************************************
* * 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/DRCsubcell.c,v 1.4 2009/05/01 18:59:44 tim Exp $";
#endif /* not lint */
#include <stdio.h>
#include <sys/types.h>
#include "utils/magic.h"
#include "textio/textio.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "drc/drc.h"
#include "windows/windows.h"
#include "commands/commands.h"
#include "utils/undo.h"
/* The variables below are made owns so that they can be used to
* pass information to the various search functions.
*/
static Rect drcSubIntArea; /* Accumulates area of interactions. */
static CellDef *drcSubDef; /* Cell definition we're checking. */
static int drcSubRadius; /* Interaction radius. */
static CellUse *drcCurSub; /* Holds current use while searching for interactions */
static Rect drcSubLookArea; /* Area where we're looking for interactions */
static void (*drcSubFunc)(); /* Error function. */
static ClientData drcSubClientData;
/* To be passed to error function. */
/* The cookie below is dummied up to provide an error message for
* errors that occur because of inexact overlaps between subcells.
*/
static DRCCookie drcSubcellCookie = {
0, 0, 0, 0,
{ 0 }, { 0 },
0, 0, 0,
DRC_SUBCELL_OVERLAP_TAG,
(DRCCookie *) NULL
};
/* The cookie below is dummied up to provide an error message for
* errors that are in a subcell non-interaction area and have been
* copied up into the parent without flattening
*/
static DRCCookie drcInSubCookie = {
0, 0, 0, 0,
{ 0 }, { 0 },
0, 0, 0,
DRC_IN_SUBCELL_TAG,
(DRCCookie *) NULL
};
/* The following DRC cookie is used when flattening non-Manhattan
* shapes results in a non-integer coordinate. Because the non-
* integer coordinate cannot be represented in magic, the position
* is flagged as a DRC error.
*/
static DRCCookie drcOffGridCookie = {
0, 0, 0, 0,
{ 0 }, { 0 },
0, 0, 0,
DRC_OFFGRID_TAG,
(DRCCookie *) NULL
};
extern int DRCErrorType;
extern CellDef *DRCErrorDef;
/*
* ----------------------------------------------------------------------------
*
* drcFindOtherCells --
*
* This is a search function invoked when looking around a given
* cell for interactions. If a cell use is found other than drcCurSub,
* then it constitutes an interaction, and its area is included into
* the area parameter.
*
* Results:
* Always returns 0 to keep the search alive.
*
* Side effects:
* The area parameter may be modified by including the area
* of the current use.
*
* ----------------------------------------------------------------------------
*/
int
drcFindOtherCells(use, area)
CellUse *use;
Rect *area;
{
if (use != drcCurSub)
GeoInclude(&use->cu_bbox, area);
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* drcSubCopyErrors ---
*
* For each tile found in drcCopyErrorsFunc(), translate the tile position
* into the coordinate system of the parent cell (represented by the drcTemp
* plane in ClientData) and apply the function passed in the filter, which is
* whatever function handles DRC errors inside an error tile (which is
* different for "drc why" commands than for "drc check".
*
* Returns:
* 0 to keep the search going.
*
* ----------------------------------------------------------------------------
*/
int
drcSubCopyErrors(tile, cxp)
Tile *tile;
TreeContext *cxp;
{
Rect area;
Rect destArea;
struct drcClientData *arg = (struct drcClientData *)cxp->tc_filter->tf_arg;
TiToRect(tile, &area);
GeoClip(&area, &cxp->tc_scx->scx_area);
GeoTransRect(&cxp->tc_scx->scx_trans, &area, &destArea);
(*(arg->dCD_function))(arg->dCD_celldef, &destArea, arg->dCD_cptr,
arg->dCD_clientData);
(*(arg->dCD_errors))++;
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* drcSubCopyFunc ---
*
* This routine is applied for each subcell of a parent def. It calls
* DBNoTreeSrTiles() with the above routine drcSubCopyErrors(), which
* copies all error tiles from the child cell up into the parent.
* This is used only within areas found to be non-interacting with the
* parent, such that any error found in the child cell is guaranteed to
* be a real error, and not one that might be resolved by additional
* material found in the parent or a sibling cell.
*
* Added 11/10/2020: Moved drcArrayFunc() here; this limits the array
* checks to non-interaction areas in the parent cell.
* 8/20/2021: Realized that TT_ERROR_S and (maybe?) TT_ERROR_PS tiles
* are also error types that must be copied up.
*
* Returns:
* Whatever DBNoTreeSrTiles() returns.
*
* ----------------------------------------------------------------------------
*/
int
drcSubCopyFunc(scx, cdarg)
SearchContext *scx;
ClientData cdarg;
{
TileTypeBitMask drcMask;
/* Create a mask with all of the DRC error types in it */
TTMaskZero(&drcMask);
TTMaskSetType(&drcMask, TT_ERROR_P);
TTMaskSetType(&drcMask, TT_ERROR_S);
TTMaskSetType(&drcMask, TT_ERROR_PS);
/* Use DBNoTreeSrTiles() because we want to search only one level down */
return DBNoTreeSrTiles(scx, &drcMask, 0, drcSubCopyErrors, cdarg);
}
/* Flags used by the client data for drcSubcellFunc() */
#define PROPAGATE_FLAG 1
#define CELLFOUND_FLAG 2
/*
* ----------------------------------------------------------------------------
*
* drcSubcellFunc --
*
* Called by DBSrCellPlaneArea when looking for interactions in
* a given area. It sees if this subcell participates
* in any interactions in the area we're rechecking.
*
* Results:
* Always returns 0 to keep the search alive.
*
* Side effects:
* The area drcSubIntArea is modified to include interactions
* stemming from this subcell.
*
* ----------------------------------------------------------------------------
*/
int
drcSubcellFunc(subUse, flags)
CellUse *subUse; /* Subcell instance. */
int *flags; /* Information to propagate up */
{
Rect area, haloArea, intArea, subIntArea, locIntArea;
int i;
/* A subcell has been seen, so set the "cell found" flag */
*flags |= CELLFOUND_FLAG;
/* To determine interactions, find the bounding box of
* all paint and other subcells within one halo of this
* subcell (and also within the original area where
* we're recomputing errors).
*/
area = subUse->cu_bbox;
GEO_EXPAND(&area, drcSubRadius, &haloArea);
GeoClip(&haloArea, &drcSubLookArea);
intArea = GeoNullRect;
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
{
(void) DBSrPaintArea((Tile *) NULL, drcSubDef->cd_planes[i],
&haloArea, &DBAllButSpaceBits, drcIncludeArea,
(ClientData) &intArea);
}
/* DRC error tiles in a subcell are automatically pulled into the */
/* interaction area of the parent. Ultimately this is recursive as */
/* all cells are checked and errors propagate to the top level. */
subIntArea = GeoNullRect;
#if (0)
/* NOTE: DRC errors inside a subcell should be ignored for */
/* the purpose of finding interactions. Errors should only */
/* be copied up into the parent when in a non-interaction */
/* area. This is done below in DRCFindInteractions(). */
/* (Method added by Tim, 10/15/2020) */
/* Maybe S and PS errors should be pulled here? */
DBSrPaintArea((Tile *) NULL, subUse->cu_def->cd_planes[PL_DRC_ERROR],
&TiPlaneRect, &DBAllButSpaceBits, drcIncludeArea,
(ClientData) &subIntArea);
GeoTransRect(&(subUse->cu_transform), &subIntArea, &locIntArea);
GeoInclude(&locIntArea, &intArea);
#endif
if (!GEO_RECTNULL(&subIntArea)) *flags |= PROPAGATE_FLAG;
drcCurSub = subUse;
(void) DBSrCellPlaneArea(drcSubDef->cd_cellPlane, &haloArea,
drcFindOtherCells, (ClientData)(&intArea));
if (GEO_RECTNULL(&intArea)) return 0;
GEO_EXPAND(&intArea, drcSubRadius, &intArea);
GeoClip(&intArea, &haloArea);
(void) GeoInclude(&intArea, &drcSubIntArea);
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* drcAlwaysOne --
*
* This is a utility procedure that always returns 1 when it
* is called. It aborts searches and notifies the invoker that
* an item was found during the search.
*
* Results:
* Always returns 1 to abort searches.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
int
drcAlwaysOne()
{
return 1;
}
/*
* ----------------------------------------------------------------------------
*
* drcSubCheckPaint --
*
* This procedure is invoked once for each subcell in a
* particular interaction area. It checks to see whether the
* subcell's subtree actually contains some paint in the potential
* interaction area. As soon as the second such subcell is found,
* it aborts the search.
*
* Results:
* Returns 0 to keep the search alive, unless we've found the
* second subcell containing paint in the interaction area.
* When this occurs, the search is aborted by returning 1.
*
* Side effects:
* When the first use with paint is found, curUse is modified
* to contain its address.
*
* ----------------------------------------------------------------------------
*/
int
drcSubCheckPaint(scx, curUse)
SearchContext *scx; /* Contains information about the celluse
* that was found.
*/
CellUse **curUse; /* Points to a celluse, or NULL, or -1. -1
* means paint was found in the root cell,
* and non-NULL means some other celluse had
* paint in it. If we find another celluse
* with paint, when this is non-NULL, it
* means there really are two cells with
* interacting paint, so we abort the
* search to tell the caller to really check
* this area.
*/
{
if (DBTreeSrTiles(scx, &DBAllButSpaceAndDRCBits, 0, drcAlwaysOne,
(ClientData) NULL) != 0)
{
/* This subtree has stuff under the interaction area. */
if (*curUse != NULL) return 1;
*curUse = scx->scx_use;
}
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* DRCFindInteractions --
*
* This procedure finds the bounding box of all subcell-subcell
* or subcell-paint interactions in a given area of a given cell.
*
* Results:
* Returns 1 if there were any interactions in the given
* area, 0 if there were none, and -1 if there were no subcells
* in the area (implies no interactions, but may be treated
* differently, e.g., by extSubtree()).
*
* Side effects:
* The parameter interaction is set to contain the bounding box
* of all places in area where one subcell comes within radius
* of another subcell, or where paint in def comes within radius
* of a subcell. Interactions between elements of array are not
* considered here, but interactions between arrays and other
* things are considered. This routine is a bit clever, in that
* it not only checks for bounding boxes interacting, but also
* makes sure the cells really contain material in the interaction
* area.
* ----------------------------------------------------------------------------
*/
int
DRCFindInteractions(def, area, radius, interaction)
CellDef *def; /* Cell to check for interactions. */
Rect *area; /* Area of def to check for interacting
* material.
*/
int radius; /* How close two pieces of material must be
* to be considered interacting. Two pieces
* radius apart do NOT interact, but if they're
* close than this they do.
*/
Rect *interaction; /* Gets filled in with the bounding box of
* the interaction area, if any. Doesn't
* have a defined value when FALSE is returned.
*/
{
int i;
CellUse *use;
SearchContext scx;
int flags;
drcSubDef = def;
drcSubRadius = radius;
DRCDummyUse->cu_def = def;
/* Find all the interactions in the area and compute the
* outer bounding box of all those interactions. An interaction
* exists whenever material in one cell approaches within radius
* of material in another cell. As a first approximation, assume
* each cell has material everywhere within its bounding box.
*/
drcSubIntArea = GeoNullRect;
GEO_EXPAND(area, radius, &drcSubLookArea);
flags = 0;
(void) DBSrCellPlaneArea(def->cd_cellPlane, &drcSubLookArea,
drcSubcellFunc, (ClientData)(&flags));
/* If there seems to be an interaction area, make a second pass
* to make sure there's more than one cell with paint in the
* area. This will save us a lot of work where two cells
* have overlapping bounding boxes without overlapping paint.
*/
if (!(flags & CELLFOUND_FLAG)) return -1;
if (GEO_RECTNULL(&drcSubIntArea)) return 0;
use = NULL;
/* If errors are being propagated up from child to parent, */
/* then the interaction area is always valid. */
if (!(flags & PROPAGATE_FLAG))
{
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
{
if (DBSrPaintArea((Tile *) NULL, def->cd_planes[i],
&drcSubIntArea, &DBAllButSpaceBits, drcAlwaysOne,
(ClientData) NULL) != 0)
{
use = (CellUse *) -1;
break;
}
}
scx.scx_use = DRCDummyUse;
scx.scx_trans = GeoIdentityTransform;
scx.scx_area = drcSubIntArea;
if (DBTreeSrCells(&scx, 0, drcSubCheckPaint, (ClientData) &use) == 0)
return 0;
}
/* OK, no more excuses, there's really an interaction area here. */
*interaction = drcSubIntArea;
GeoClip(interaction, area);
if (GEO_RECTNULL(interaction)) return 0;
return 1;
}
/*
* ----------------------------------------------------------------------------
*
* drcExactOverlapCheck --
*
* This procedure is invoked to check for overlap violations.
* It is invoked by DBSrPaintArea from drcExactOverlapTile.
* Any tiles passed to this procedure must lie within
* arg->dCD_rect, or an error is reported.
*
* Results:
* Always returns 0 to keep the search alive.
*
* Side effects:
* If an error occurs, the client error function is called and
* the error count is incremented.
*
* ----------------------------------------------------------------------------
*/
int
drcExactOverlapCheck(tile, arg)
Tile *tile; /* Tile to check. */
struct drcClientData *arg; /* How to detect and process errors. */
{
Rect rect;
TiToRect(tile, &rect);
GeoClip(&rect, arg->dCD_clip);
if (GEO_RECTNULL(&rect)) return 0;
(*(arg->dCD_function)) (arg->dCD_celldef, &rect, arg->dCD_cptr,
arg->dCD_clientData);
(*(arg->dCD_errors))++;
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* drcExactOverlapTile --
*
* This procedure is invoked by DBTreeSrTiles for each tile
* in each constituent cell of a subcell interaction. It
* makes sure that if this tile overlaps other tiles of the
* same type in other cells, then the overlaps are EXACT:
* each cell contains exactly the same information.
*
* Results:
* Always returns 0 to keep the search alive.
*
* Side effects:
* If there are errors, the client error handling routine
* is invoked and the count in the drcClientData record is
* incremented.
*
* ----------------------------------------------------------------------------
*/
int
drcExactOverlapTile(tile, cxp)
Tile *tile; /* Tile that must overlap exactly. */
TreeContext *cxp; /* Tells how to translate out of subcell.
* The client data must be a drcClientData
* record, and the caller must have filled
* in the celldef, clip, errors, function,
* cptr, and clientData fields.
*/
{
struct drcClientData *arg;
TileTypeBitMask typeMask, invMask, *rmask;
TileType type, t;
Tile *tp;
Rect r1, r2, r3, rex;
int i;
arg = (struct drcClientData *) cxp->tc_filter->tf_arg;
TiToRect(tile, &r1);
GeoTransRect(&(cxp->tc_scx->scx_trans), &r1, &r2);
GEO_EXPAND(&r2, 1, &rex); /* Area includes abutting tiles */
GeoClip(&rex, arg->dCD_clip); /* Except areas outside search area */
type = TiGetType(tile);
TTMaskSetOnlyType(&typeMask, type);
if (type < DBNumUserLayers)
{
for (t = DBNumUserLayers; t < DBNumTypes; t++)
{
rmask = DBResidueMask(t);
if (TTMaskHasType(rmask, type))
TTMaskSetType(&typeMask, t);
}
TTMaskCom2(&invMask, &typeMask);
}
else
{
rmask = DBResidueMask(type);
TTMaskSetMask(&typeMask, rmask); // Add residue types for inverse only
TTMaskCom2(&invMask, &typeMask);
TTMaskSetOnlyType(&typeMask, type); // Restore original type mask
}
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
{
if (DBSrPaintArea((Tile *) NULL, DRCdef->cd_planes[i],
&rex, &typeMask, drcAlwaysOne, (ClientData) NULL))
{
/* There is an overlap or abutment of ExactOverlap types. */
/* 1) Check if any invalid type is under this tile. */
arg->dCD_rect = &r2;
DBSrPaintArea((Tile *) NULL, DRCdef->cd_planes[i], &r2,
&invMask, drcExactOverlapCheck, (ClientData) arg);
/* 2) Search the neighboring tiles for types that do not */
/* match the exact overlap type, and flag abutment errors. */
/* Search bottom */
arg->dCD_rect = &r3;
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
if (TTMaskHasType(&invMask, TiGetType(tp)))
{
TiToRect(tp, &r1);
GeoTransRect(&(cxp->tc_scx->scx_trans), &r1, &r3);
GeoClip(&r3, &rex);
if (!GEO_RECTNULL(&r3))
DBSrPaintArea((Tile *) NULL, DRCdef->cd_planes[i],
&r3, &typeMask, drcExactOverlapCheck,
(ClientData) arg);
}
/* Search right */
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
if (TTMaskHasType(&invMask, TiGetType(tp)))
{
TiToRect(tp, &r1);
GeoTransRect(&(cxp->tc_scx->scx_trans), &r1, &r3);
GeoClip(&r3, &rex);
if (!GEO_RECTNULL(&r3))
DBSrPaintArea((Tile *) NULL, DRCdef->cd_planes[i],
&r3, &typeMask, drcExactOverlapCheck,
(ClientData) arg);
}
/* Search top */
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
if (TTMaskHasType(&invMask, TiGetType(tp)))
{
TiToRect(tp, &r1);
GeoTransRect(&(cxp->tc_scx->scx_trans), &r1, &r3);
GeoClip(&r3, &rex);
if (!GEO_RECTNULL(&r3))
DBSrPaintArea((Tile *) NULL, DRCdef->cd_planes[i],
&r3, &typeMask, drcExactOverlapCheck,
(ClientData) arg);
}
/* Search left */
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
if (TTMaskHasType(&invMask, TiGetType(tp)))
{
TiToRect(tp, &r1);
GeoTransRect(&(cxp->tc_scx->scx_trans), &r1, &r3);
GeoClip(&r3, &rex);
if (!GEO_RECTNULL(&r3))
DBSrPaintArea((Tile *) NULL, DRCdef->cd_planes[i],
&r3, &typeMask, drcExactOverlapCheck,
(ClientData) arg);
}
}
}
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* DRCOffGridError ---
*
* Function to call when a call to DBCellCheckCopyAllPaint() flags an error
* indicating that a subcell overlap of non-Manhattan geometry resolves to
* an off-grid intersection point. Note that this is different from the
* DRC off-grid check, which checks for geometry that does not match the
* manufacturing grid pitch. This checks for the case of geometry that
* is finer than the underlying database grid, which can only happen for
* two non-Manhattan shapes interacting between two different cells, and
* can only be caught during the process of flattening the cell contents.
*
* Results:
* None.
*
* Side effects:
* Creates a DRC error or prints the DRC error message, depending on
* the value of drcSubFunc.
*
* ----------------------------------------------------------------------------
*/
void
DRCOffGridError(rect)
Rect *rect; /* Area of error */
{
if (drcSubFunc == NULL) return;
(*drcSubFunc)(DRCErrorDef, rect, &drcOffGridCookie, drcSubClientData);
}
/*
* ----------------------------------------------------------------------------
*
* DRCInteractionCheck --
*
* This is the top-level procedure that performs subcell interaction
* checks. All interaction rule violations in area of def are
* found, and func is called for each one.
*
* Results:
* The number of errors found.
*
* Side effects:
* The procedure func is called for each violation found. See
* the header for DRCBasicCheck for information about how func
* is called. The violations passed to func are expressed in
* the coordinates of def. Only violations stemming from
* interactions in def, as opposed to def's children, are reported.
*
* Design Note:
* This procedure is trickier than you think. The problem is that
* DRC must be guaranteed to produce EXACTLY the same collection
* of errors in an area, no matter how the area is checked. Checking
* it all as one big area should produce the same results as
* checking it in several smaller pieces. Otherwise, "drc why"
* won't work correctly, and the error configuration will depend
* on how the chip was checked, which is intolerable. This problem
* is solved here by dividing the world up into squares along a grid
* of dimension DRCStepSize aligned at the origin. Interaction areas
* are always computed by considering everything inside one grid square
* at a time. We may have to consider several grid squares in order
* to cover the area passed in by the client.
* ----------------------------------------------------------------------------
*/
int
DRCInteractionCheck(def, area, erasebox, func, cdarg)
CellDef *def; /* Definition in which to do check. */
Rect *area; /* Area in which all errors are to be found. */
Rect *erasebox; /* Smaller area containing DRC check tiles */
void (*func)(); /* Function to call for each error. */
ClientData cdarg; /* Extra info to be passed to func. */
{
int oldTiles, count, x, y, errorSaveType;
Rect intArea, square, cliparea, subArea;
PaintResultType (*savedPaintTable)[NT][NT];
int (*savedPaintPlane)();
struct drcClientData arg;
SearchContext scx;
drcSubFunc = func;
drcSubClientData = cdarg;
oldTiles = DRCstatTiles;
count = 0;
/* Divide the area to be checked up into squares. Process each
* square separately.
*/
x = (area->r_xbot/DRCStepSize) * DRCStepSize;
if (x > area->r_xbot) x -= DRCStepSize;
y = (area->r_ybot/DRCStepSize) * DRCStepSize;
if (y > area->r_ybot) y -= DRCStepSize;
for (square.r_xbot = x; square.r_xbot < area->r_xtop;
square.r_xbot += DRCStepSize)
for (square.r_ybot = y; square.r_ybot < area->r_ytop;
square.r_ybot += DRCStepSize)
{
square.r_xtop = square.r_xbot + DRCStepSize;
square.r_ytop = square.r_ybot + DRCStepSize;
/* Limit square to erasebox. Otherwise, a huge processing */
/* penalty is incurred for finding a single error (e.g., */
/* using "drc find" or "drc why" in a large design with a */
/* large step size. */
cliparea = square;
GeoClip(&cliparea, area);
/* Prepare for subcell search */
DRCDummyUse->cu_def = def;
scx.scx_use = DRCDummyUse;
scx.scx_trans = GeoIdentityTransform;
arg.dCD_celldef = def;
arg.dCD_errors = &count;
arg.dCD_cptr = &drcInSubCookie;
arg.dCD_function = func;
arg.dCD_clientData = cdarg;
/* Find all the interactions in the square, and clip to the error
* area we're interested in. */
if (DRCFindInteractions(def, &cliparea, DRCTechHalo, &intArea) <= 0)
{
/* Added May 4, 2008---if there are no subcells, run the
* basic check over the area of the erasebox.
*/
subArea = *erasebox;
GeoClip(&subArea, &cliparea);
GEO_EXPAND(&subArea, DRCTechHalo, &intArea);
errorSaveType = DRCErrorType;
DRCErrorType = TT_ERROR_P; // Basic check is always ERROR_P
DRCBasicCheck(def, &intArea, &subArea, func, cdarg);
/* Copy errors up from all non-interacting children */
scx.scx_area = subArea;
arg.dCD_clip = &subArea;
DBCellSrArea(&scx, drcSubCopyFunc, &arg);
DBCellSrArea(&scx, drcArrayFunc, &arg);
DRCErrorType = errorSaveType;
continue;
}
else
{
/* Added March 6, 2012: Any area(s) outside the
* interaction area are processed with the basic
* check. This avoids unnecessary copying, so it
* speeds up the DRC without requiring that geometry
* passes DRC rules independently of subcell geometry
* around it.
*
* As intArea can be smaller than square, we may have
* to process as many as four independent rectangles.
* NOTE that the area of (intArea + halo) will be checked
* in the subcell interaction check, so we can ignore
* that.
*/
Rect eraseClip, eraseHalo, subArea;
errorSaveType = DRCErrorType;
DRCErrorType = TT_ERROR_P; // Basic check is always ERROR_P
eraseClip = *erasebox;
GeoClip(&eraseClip, &cliparea);
subArea = eraseClip;
arg.dCD_clip = &subArea;
/* check above */
if (intArea.r_ytop < eraseClip.r_ytop)
{
subArea.r_ybot = intArea.r_ytop;
GEO_EXPAND(&subArea, DRCTechHalo, &eraseHalo);
DRCBasicCheck(def, &eraseHalo, &subArea, func, cdarg);
/* Copy errors up from all non-interacting children */
scx.scx_area = subArea;
DBCellSrArea(&scx, drcSubCopyFunc, &arg);
DBCellSrArea(&scx, drcArrayFunc, &arg);
}
/* check below */
if (intArea.r_ybot > eraseClip.r_ybot)
{
subArea.r_ybot = eraseClip.r_ybot;
subArea.r_ytop = intArea.r_ybot;
GEO_EXPAND(&subArea, DRCTechHalo, &eraseHalo);
DRCBasicCheck(def, &eraseHalo, &subArea, func, cdarg);
/* Copy errors up from all non-interacting children */
scx.scx_area = subArea;
DBCellSrArea(&scx, drcSubCopyFunc, &arg);
DBCellSrArea(&scx, drcArrayFunc, &arg);
}
subArea.r_ytop = intArea.r_ytop;
subArea.r_ybot = intArea.r_ybot;
/* check right */
if (intArea.r_xtop < eraseClip.r_xtop)
{
subArea.r_xbot = intArea.r_xtop;
GEO_EXPAND(&subArea, DRCTechHalo, &eraseHalo);
DRCBasicCheck(def, &eraseHalo, &subArea, func, cdarg);
/* Copy errors up from all non-interacting children */
scx.scx_area = subArea;
DBCellSrArea(&scx, drcSubCopyFunc, &arg);
DBCellSrArea(&scx, drcArrayFunc, &arg);
}
/* check left */
if (intArea.r_xbot > eraseClip.r_xbot)
{
subArea.r_xtop = intArea.r_xbot;
subArea.r_xbot = eraseClip.r_xbot;
GEO_EXPAND(&subArea, DRCTechHalo, &eraseHalo);
DRCBasicCheck(def, &eraseHalo, &subArea, func, cdarg);
/* Copy errors up from all non-interacting children */
scx.scx_area = subArea;
DBCellSrArea(&scx, drcSubCopyFunc, &arg);
DBCellSrArea(&scx, drcArrayFunc, &arg);
}
DRCErrorType = errorSaveType;
}
/* Clip interaction area against subArea-expanded-by-halo */
subArea = *erasebox;
GEO_EXPAND(&subArea, DRCTechHalo, &cliparea);
GeoClip(&intArea, &cliparea);
/* Flatten the interaction area. */
DRCstatInteractions += 1;
GEO_EXPAND(&intArea, DRCTechHalo, &scx.scx_area);
DBCellClearDef(DRCdef);
savedPaintTable = DBNewPaintTable(DRCCurStyle->DRCPaintTable);
savedPaintPlane = DBNewPaintPlane(DBPaintPlaneMark);
(void) DBCellCheckCopyAllPaint(&scx, &DBAllButSpaceBits, 0,
DRCuse, func);
(void) DBNewPaintTable(savedPaintTable);
(void) DBNewPaintPlane(savedPaintPlane);
/* Run the basic checker over the interaction area. */
count += DRCBasicCheck(DRCdef, &scx.scx_area, &intArea,
func, cdarg);
/* TxPrintf("Interaction area: (%d, %d) (%d %d)\n",
intArea.r_xbot, intArea.r_ybot,
intArea.r_xtop, intArea.r_ytop);
*/
/* Check for illegal partial overlaps. */
scx.scx_area = intArea;
arg.dCD_clip = &intArea;
arg.dCD_celldef = DRCdef;
arg.dCD_cptr = &drcSubcellCookie;
(void) DBTreeSrUniqueTiles(&scx, &DRCCurStyle->DRCExactOverlapTypes,
0, drcExactOverlapTile, (ClientData) &arg);
}
/* Update count of interaction tiles processed. */
DRCstatIntTiles += DRCstatTiles - oldTiles;
return count;
}
void
DRCFlatCheck(use, area)
CellUse *use;
Rect *area;
{
int x, y;
Rect chunk;
SearchContext scx;
void drcIncCount();
PaintResultType (*savedPaintTable)[NT][NT];
int (*savedPaintPlane)();
int drcFlatCount = 0;
UndoDisable();
for (y = area->r_ybot; y < area->r_ytop; y += 300)
{
for (x = area->r_xbot; x < area->r_xtop; x += 300)
{
chunk.r_xbot = x;
chunk.r_ybot = y;
chunk.r_xtop = x+300;
chunk.r_ytop = y+300;
if (chunk.r_xtop > area->r_xtop) chunk.r_xtop = area->r_xtop;
if (chunk.r_ytop > area->r_ytop) chunk.r_ytop = area->r_ytop;
GEO_EXPAND(&chunk, DRCTechHalo, &scx.scx_area);
scx.scx_use = use;
scx.scx_trans = GeoIdentityTransform;
DBCellClearDef(DRCdef);
savedPaintTable = DBNewPaintTable(DRCCurStyle->DRCPaintTable);
savedPaintPlane = DBNewPaintPlane(DBPaintPlaneMark);
(void) DBCellCopyAllPaint(&scx, &DBAllButSpaceBits, 0, DRCuse);
(void) DBNewPaintTable(savedPaintTable);
(void) DBNewPaintPlane(savedPaintPlane);
(void) DRCBasicCheck(DRCdef, &scx.scx_area, &chunk,
drcIncCount, (ClientData) &drcFlatCount);
}
}
TxPrintf("%d total errors found.\n", drcFlatCount);
UndoEnable();
}
void
drcIncCount(def, area, rule, count)
CellDef *def;
Rect *area;
DRCCookie *rule;
int *count;
{
*count++;
}