magic/drc/DRCarray.c

345 lines
11 KiB
C

/*
* DRCarray.c --
*
* This file provides routines that check arrays to be sure
* there are no unpleasant interactions between adjacent
* elements. Note: the routines in this file are NOT generally
* re-entrant.
*
* *********************************************************************
* * 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/DRCarray.c,v 1.2 2009/05/01 18:59:44 tim Exp $";
#endif /* not lint */
#include <sys/types.h>
#include <stdio.h>
#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 "windows/windows.h"
#include "commands/commands.h"
/* Forward references: */
extern int drcArrayYankFunc(), drcArrayOverlapFunc();
/* Dummy DRC cookie used to pass the error message to DRC error
* routines.
*/
static DRCCookie drcArrayCookie = {
0, 0, 0, 0,
{ 0 }, { 0 },
0, 0, 0,
DRC_ARRAY_OVERLAP_TAG,
(DRCCookie *) NULL
};
/*
* ----------------------------------------------------------------------------
*
* drcArrayFunc --
*
* This procedure is invoked by DBCellSrArea once for each cell
* overlapping the area being checked. If the celluse is for
* an array, then it is checked for array correctness.
*
* Results:
* Always returns 2, to skip the remaining instances in the
* current array.
*
* Side effects:
* Design rules are checked for the subcell, if it is an array,
* and the count of errors is added into drcSubCount.
*
* Design:
* To verify that an array is correct, we only have to check
* four interaction areas, shaded as A, B, C, and D in the diagram
* below. The exact size of the interaction areas depends on
* how much overlap there is. In the extreme cases, there may be
* no areas to check at all (instances widely separated), or there
* may even be areas with more than four instances overlapping
* (spacing less than half the size of the instance).
*
* --------------DDDDD------------------------------
* | DDDDD | |
* | | | |
* | | | |
* | | | |
* -------------------------------------------------
* | | | |
* | | | |
* | | | |
* AAAAAAAAAAAAAAAAAAA | CCC
* AAAAAAAAAAAAAAAAAAA---------------------------CCC
* AAAAAAAAAAAAAAAAAAA | CCC
* | BBBBB | |
* | BBBBB | |
* | BBBBB | |
* --------------BBBBB------------------------------
*
* ----------------------------------------------------------------------------
*/
int
drcArrayFunc(scx, arg)
SearchContext *scx; /* Information about the search. */
struct drcClientData *arg; /* Information used in overlap */
{
int xsep, ysep;
int xsize, ysize;
int rval, oldTiles;
Rect errorArea, yankArea, tmp, tmp2, saveClip;
DRCCookie *save_cptr;
CellUse *use = scx->scx_use;
Rect *area;
int drcArrayCount; /* Count of number of errors found. */
void (*drcArrayErrorFunc)(); /* Function to call on violations. */
ClientData drcArrayClientData; /* Extra parameter to pass to func. */
PaintResultType (*savedPaintTable)[NT][NT];
PaintResultType (*savedEraseTable)[NT][NT];
int (*savedPaintPlane)();
if ((use->cu_xlo == use->cu_xhi) && (use->cu_ylo == use->cu_yhi))
return 2;
oldTiles = DRCstatTiles;
/* During array processing, switch the paint table to catch
* illegal overlaps.
*/
savedPaintTable = DBNewPaintTable(DRCCurStyle->DRCPaintTable);
savedPaintPlane = DBNewPaintPlane(DBPaintPlaneMark);
/* Set up the client data that will be passed down during
* checks for exact overlaps.
*/
save_cptr = arg->dCD_cptr;
arg->dCD_cptr = &drcArrayCookie;
area = arg->dCD_clip;
drcArrayCount = *arg->dCD_errors;
drcArrayErrorFunc = arg->dCD_function;
drcArrayClientData = arg->dCD_clientData;
/* Compute the sizes and separations of elements, in coordinates
* of the parend. If the array is 1-dimensional, we set the
* corresponding spacing to an impossibly large distance.
*/
tmp.r_xbot = 0;
tmp.r_ybot = 0;
if (use->cu_xlo == use->cu_xhi)
tmp.r_xtop = DRCTechHalo + use->cu_def->cd_bbox.r_xtop
- use->cu_def->cd_bbox.r_xbot;
else tmp.r_xtop = use->cu_xsep;
if (use->cu_ylo == use->cu_yhi)
tmp.r_ytop = DRCTechHalo + use->cu_def->cd_bbox.r_ytop
- use->cu_def->cd_bbox.r_ybot;
else tmp.r_ytop = use->cu_ysep;
GeoTransRect(&use->cu_transform, &tmp, &tmp2);
xsep = tmp2.r_xtop - tmp2.r_xbot;
ysep = tmp2.r_ytop - tmp2.r_ybot;
GeoTransRect(&use->cu_transform, &use->cu_def->cd_bbox, &tmp2);
xsize = tmp2.r_xtop - tmp2.r_xbot;
ysize = tmp2.r_ytop - tmp2.r_ybot;
/* Check each of the four areas A, B, C, and D. Remember that
* absolutely arbitrary overlaps between cells are allowed.
* Skip some or all of the areas if the cell isn't arrayed in
* that direction or if the instances are widely spaced.
*/
if (ysep < ysize + DRCTechHalo)
{
/* A */
errorArea.r_xbot = use->cu_bbox.r_xbot;
errorArea.r_xtop = use->cu_bbox.r_xbot + xsize + DRCTechHalo;
errorArea.r_ybot = use->cu_bbox.r_ybot + ysep - DRCTechHalo;
errorArea.r_ytop = use->cu_bbox.r_ybot + ysize + DRCTechHalo;
GeoClip(&errorArea, area);
if (!GEO_RECTNULL(&errorArea))
{
GEO_EXPAND(&errorArea, DRCTechHalo, &yankArea);
DBCellClearDef(DRCdef);
(void) DBArraySr(use, &yankArea, drcArrayYankFunc,
(ClientData) &yankArea);
drcArrayCount += DRCBasicCheck(DRCdef, &yankArea, &errorArea,
drcArrayErrorFunc, drcArrayClientData);
*arg->dCD_clip = *area;
GeoClip(arg->dCD_clip, &yankArea);
(void) DBArraySr(use, &errorArea, drcArrayOverlapFunc,
(ClientData) arg);
}
/* C */
errorArea.r_xtop = use->cu_bbox.r_xtop;
errorArea.r_xbot = use->cu_bbox.r_xtop - DRCTechHalo;
GeoClip(&errorArea, area);
if (!GEO_RECTNULL(&errorArea))
{
GEO_EXPAND(&errorArea, DRCTechHalo, &yankArea);
DBCellClearDef(DRCdef);
(void) DBArraySr(use, &yankArea, drcArrayYankFunc,
(ClientData) &yankArea);
drcArrayCount += DRCBasicCheck(DRCdef, &yankArea, &errorArea,
drcArrayErrorFunc, drcArrayClientData);
*arg->dCD_clip = *area;
GeoClip(arg->dCD_clip, &yankArea);
(void) DBArraySr(use, &errorArea, drcArrayOverlapFunc,
(ClientData) arg);
}
}
if (xsep < xsize + DRCTechHalo)
{
/* B */
errorArea.r_xbot = use->cu_bbox.r_xbot + xsep - DRCTechHalo;
errorArea.r_xtop = use->cu_bbox.r_xbot + xsize + DRCTechHalo;
errorArea.r_ybot = use->cu_bbox.r_ybot;
errorArea.r_ytop = errorArea.r_ybot + ysep - DRCTechHalo;
GeoClip(&errorArea, area);
if (!GEO_RECTNULL(&errorArea))
{
GEO_EXPAND(&errorArea, DRCTechHalo, &yankArea);
DBCellClearDef(DRCdef);
(void) DBArraySr(use, &yankArea, drcArrayYankFunc,
(ClientData) &yankArea);
drcArrayCount += DRCBasicCheck(DRCdef, &yankArea, &errorArea,
drcArrayErrorFunc, drcArrayClientData);
*arg->dCD_clip = *area;
GeoClip(arg->dCD_clip, &yankArea);
(void) DBArraySr(use, &errorArea, drcArrayOverlapFunc,
(ClientData) arg);
}
/* D */
errorArea.r_ytop = use->cu_bbox.r_ytop;
errorArea.r_ybot = use->cu_bbox.r_ytop - DRCTechHalo;
GeoClip(&errorArea, area);
if (!GEO_RECTNULL(&errorArea))
{
GEO_EXPAND(&errorArea, DRCTechHalo, &yankArea);
DBCellClearDef(DRCdef);
(void) DBArraySr(use, &yankArea, drcArrayYankFunc,
(ClientData) &yankArea);
drcArrayCount += DRCBasicCheck(DRCdef, &yankArea, &errorArea,
drcArrayErrorFunc, drcArrayClientData);
*arg->dCD_clip = *area;
GeoClip(arg->dCD_clip, &yankArea);
(void) DBArraySr(use, &errorArea, drcArrayOverlapFunc,
(ClientData) arg);
}
}
/* Restore original clip rect */
*arg->dCD_clip = *area;
(void) DBNewPaintTable(savedPaintTable);
(void) DBNewPaintPlane(savedPaintPlane);
/* Update count of array tiles processed. */
DRCstatArrayTiles += DRCstatTiles - oldTiles;
/* Restore original DRC cookie pointer in the argument */
arg->dCD_cptr = save_cptr;
return 2;
}
/*
* ----------------------------------------------------------------------------
*
* drcArrayYankFunc --
*
* Search action function called while yanking pieces of an array.
*
* Results:
* Always returns 0, to keep the search going.
*
* Side effects:
* Yanks from an array element into the DRC yank buffer.
*
* ----------------------------------------------------------------------------
*/
/* ARGSUSED */
int
drcArrayYankFunc(use, transform, x, y, yankArea)
CellUse *use; /* CellUse being array-checked. */
Transform *transform; /* Transform from instance to parent.*/
int x, y; /* Element indices (not used). */
Rect *yankArea; /* Area to yank (in parent coords). */
{
SearchContext scx;
Transform tinv;
GeoInvertTrans(transform, &tinv);
GeoTransRect(&tinv, yankArea, &scx.scx_area);
scx.scx_use = use;
scx.scx_trans = *transform;
(void) DBCellCopyAllPaint(&scx, &DBAllButSpaceBits, 0, DRCuse);
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* drcArrayOverlapFunc --
*
* This is a search action function called while checking pieces
* of an array to be sure that there aren't any illegal partial
* overlaps. It just invokes overlap checking facilities in
* DRCsubcell.c
*
* Results:
* Always returns 0 to keep the search alive.
*
* Side effects:
* The client's error function may be invoked.
*
* ----------------------------------------------------------------------------
*/
/* ARGSUSED */
int
drcArrayOverlapFunc(use, transform, x, y, arg)
CellUse *use; /* CellUse for array element. */
Transform *transform; /* Transform from use to parent. */
int x, y; /* Indices of element. */
struct drcClientData *arg; /* Information used in overlap
* checking. See drcExactOverlapTile.
*/
{
Transform tinv;
SearchContext scx;
GeoInvertTrans(transform, &tinv);
GeoTransRect(&tinv, arg->dCD_clip, &scx.scx_area);
scx.scx_use = use;
scx.scx_trans = *transform;
(void) DBTreeSrTiles(&scx, &DRCCurStyle->DRCExactOverlapTypes, 0,
drcExactOverlapTile, (ClientData) arg);
return 0;
}