Files
magic/drc/DRCextend.c
T
R. Timothy Edwards 516c9d7635 First cut of pulling the TT_SIDE bit out of the tile database
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.
2026-01-09 12:05:03 -05:00

621 lines
17 KiB
C

#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/drc/DRCextend.c,v 1.6 2010/09/20 21:13:22 tim Exp $";
#endif
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include "utils/magic.h"
#include "utils/malloc.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 "utils/signals.h"
#include "utils/stack.h"
#include "utils/maxrect.h"
Stack *DRCstack = (Stack *)NULL;
#define PUSHTILE(tp) \
if (TiGetClient(tp) == DRC_UNPROCESSED) { \
TiSetClientINT(tp, DRC_PENDING); \
STACKPUSH((ClientData) (tp), DRCstack); \
}
/*
*-------------------------------------------------------------------------
*
* drcCheckAngles --- checks whether a tile conforms to orthogonal-only
* geometry (90 degree angles only) or 45-degree geometry (x must
* be equal to y on all non-Manhattan tiles).
*
* Results: none
*
* Side Effects: may cause errors to be painted.
*
* NOTES: Tile has been determined to be a split tile before this
* routine is called.
*
*-------------------------------------------------------------------------
*/
void
drcCheckAngles(tile, arg, cptr)
Tile *tile;
struct drcClientData *arg;
DRCCookie *cptr;
{
Rect rect;
bool ortho = (cptr->drcc_flags & DRC_ANGLES_45) ? FALSE : TRUE;
if (ortho || ((RIGHT(tile) - LEFT(tile)) != (TOP(tile) - BOTTOM(tile))))
{
TiToRect(tile, &rect);
GeoClip(&rect, arg->dCD_clip);
if (!GEO_RECTNULL(&rect))
{
arg->dCD_cptr = cptr;
(*(arg->dCD_function)) (arg->dCD_celldef, &rect,
arg->dCD_cptr, arg->dCD_clientData);
(*(arg->dCD_errors))++;
}
}
}
/*
*-------------------------------------------------------------------------
*
* drcCheckOffGrid- checks to see that an edge is on the specified
* grid pitch.
*
* Results: none
*
* Side Effects: may cause errors to be painted.
*
*-------------------------------------------------------------------------
*/
void
drcCheckOffGrid(edgeRect, arg, cptr)
Rect *edgeRect;
struct drcClientData *arg;
DRCCookie *cptr;
{
Rect rect;
int gtest;
if (cptr->drcc_dist <= 1) return; /* No error by definition */
rect = *edgeRect;
GeoClip(&rect, arg->dCD_clip);
/* Expand rect to nearest pitch */
gtest = (rect.r_xbot / cptr->drcc_dist) * cptr->drcc_dist;
if (gtest < rect.r_xbot) rect.r_xbot = gtest;
gtest = (rect.r_xtop / cptr->drcc_dist) * cptr->drcc_dist;
if (gtest > rect.r_xtop) rect.r_xtop = gtest;
gtest = (rect.r_ybot / cptr->drcc_dist) * cptr->drcc_dist;
if (gtest < rect.r_ybot) rect.r_ybot = gtest;
gtest = (rect.r_ytop / cptr->drcc_dist) * cptr->drcc_dist;
if (gtest > rect.r_ytop) rect.r_ytop = gtest;
if (!GEO_RECTNULL(&rect)) {
(*(arg->dCD_function)) (arg->dCD_celldef, &rect,
arg->dCD_cptr, arg->dCD_clientData);
(*(arg->dCD_errors))++;
}
}
/*
*-------------------------------------------------------------------------
*
* drcCheckArea- checks to see that a collection of tiles of a given
* type have more than a minimum area.
*
* Results: none
*
* Side Effects: may cause errors to be painted.
*
*-------------------------------------------------------------------------
*/
void
drcCheckArea(starttile,arg,cptr)
Tile *starttile;
struct drcClientData *arg;
DRCCookie *cptr;
{
int arealimit;
long area = 0L;
TileTypeBitMask *oktypes = &cptr->drcc_mask;
Tile *tile,*tp;
Rect *cliprect = arg->dCD_rect;
arealimit = cptr->drcc_cdist;
arg->dCD_cptr = 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, TiGetBottomType(tp))) PUSHTILE(tp);
/* Left */
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
if (TTMaskHasType(oktypes, TiGetRightType(tp))) PUSHTILE(tp);
/* Bottom */
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
if (TTMaskHasType(oktypes, TiGetTopType(tp))) PUSHTILE(tp);
/* Right */
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
if (TTMaskHasType(oktypes, TiGetLeftType(tp))) PUSHTILE(tp);
}
if (area < (long)arealimit)
{
Rect rect;
TiToRect(starttile,&rect);
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:
while (!StackEmpty(DRCstack)) tile = (Tile *) STACKPOP(DRCstack);
/* 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);
}
}
}
/*
*-------------------------------------------------------------------------
*
* drcCheckMaxwidth - checks to see that at least one dimension of a region
* does not exceed some amount (original version---for "bends_illegal"
* option only).
*
* This should really be folded together with drcCheckArea, since the routines
* are nearly identical, but I'm feeling lazy, so I'm just duplicating
* the code for now.
*
* Results: 1 if within max bounds, 0 otherwise.
*
* Side Effects: may cause errors to be painted.
*
*-------------------------------------------------------------------------
*/
int
drcCheckMaxwidth(starttile,arg,cptr,both)
Tile *starttile;
struct drcClientData *arg;
DRCCookie *cptr;
bool both;
{
int width;
int height;
int edgelimit;
int retval = 0;
Rect boundrect;
TileTypeBitMask *oktypes;
Tile *tile,*tp;
oktypes = &cptr->drcc_mask;
edgelimit = cptr->drcc_dist;
arg->dCD_cptr = cptr;
if (DRCstack == (Stack *) NULL)
DRCstack = StackNew(64);
/* 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;
TiSetClientINT(tile, DRC_PROCESSED);
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);
if (boundrect.r_xtop - boundrect.r_xbot > edgelimit &&
boundrect.r_ytop - boundrect.r_ybot > edgelimit)
{
while (!StackEmpty(DRCstack)) tile = (Tile *) STACKPOP(DRCstack);
break;
}
/* Top */
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
if (TTMaskHasType(oktypes, TiGetBottomType(tp))) PUSHTILE(tp);
/* Left */
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
if (TTMaskHasType(oktypes, TiGetRightType(tp))) PUSHTILE(tp);
/* Bottom */
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
if (TTMaskHasType(oktypes, TiGetTopType(tp))) PUSHTILE(tp);
/* Right */
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
if (TTMaskHasType(oktypes, TiGetLeftType(tp))) PUSHTILE(tp);
}
width = boundrect.r_xtop - boundrect.r_xbot;
height = boundrect.r_ytop - boundrect.r_ybot;
if ( (width > edgelimit && height > edgelimit) ||
( both == TRUE && (width > edgelimit || height > edgelimit)) )
{
Rect rect;
TiToRect(starttile,&rect);
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))++;
retval = 1;
}
}
/* 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);
}
}
return retval;
}
/*
*-------------------------------------------------------------------------
*
* drcCheckRectSize-
*
* Checks to see that a collection of tiles of given
* types have the proper size (max size and also even or odd size).
*
* Results: none
*
* Side Effects: may cause errors to be painted.
*
*-------------------------------------------------------------------------
*/
void
drcCheckRectSize(starttile, arg, cptr)
Tile *starttile;
struct drcClientData *arg;
DRCCookie *cptr;
{
int maxsize, even;
TileTypeBitMask *oktypes = &cptr->drcc_mask;
int width;
int height;
int errwidth;
int errheight;
Tile *t;
bool error = FALSE;
maxsize = cptr->drcc_dist;
even = cptr->drcc_cdist;
/* This code only has to work for rectangular regions, since we always
* check for rectangular-ness using normal edge rules produced when
* we read in the tech file.
*/
arg->dCD_cptr = cptr;
ASSERT(TTMaskHasType(oktypes, TiGetType(starttile)), "drcCheckRectSize");
for (t = starttile; TTMaskHasType(oktypes, TiGetType(t)); t = TR(t))
/* loop has empty body */ ;
errwidth = width = LEFT(t) - LEFT(starttile);
for (t = starttile; TTMaskHasType(oktypes, TiGetType(t)); t = RT(t))
/* loop has empty body */ ;
errheight = height = BOTTOM(t) - BOTTOM(starttile);
ASSERT(width > 0 && height > 0, "drcCheckRectSize");
if (width > maxsize) {error = TRUE; errwidth = (width - maxsize);}
else if (height > maxsize) {error = TRUE; errheight = (height - maxsize);}
else if (even >= 0) {
/* meaning of "even" variable: -1, any; 0, even; 1, odd */
if (ABS(width - ((width/2)*2)) != even) {error = TRUE; errwidth = 1;}
else if (ABS(height - ((height/2)*2)) != even) {error = TRUE; errheight = 1;}
}
if (error) {
Rect rect;
TiToRect(starttile, &rect);
rect.r_xtop = rect.r_xbot + errwidth;
rect.r_ytop = rect.r_ybot + errheight;
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))++;
}
}
}
/*
*-------------------------------------------------------------------------
*
* MaxRectsExclude ---
*
* Trivial callback function which detects if a type is found
* overlapping a Maxrects area.
*
* Results:
* Always return 1 to immediately halt the search.
*
* Side effects:
* None.
*
*-------------------------------------------------------------------------
*/
int
MaxRectsExclude(
Tile *tile, /* (unused) */
TileType dinfo, /* (unused) */
ClientData clientdata) /* (unused) */
{
return 1;
}
/*
*-------------------------------------------------------------------------
*
* drcCanonicalMaxwidth - checks to see that at least one dimension of a
* rectangular region does not exceed some amount.
*
* This differs from "CheckMaxwidth" in being more rigorous about
* determining where a region of max width might be found. There
* is no "bend" rule here. We check from the edge being observed
* and back, and adjust the bounds on the sides, forking as
* necessary to consider alternative arrangements of the interior
* rectangle. A distance "dist" is passed to the routine. We
* may push the interior rectangle back by up to this amount from
* the observed edge. For "widespacing" rules, we check all
* interior regions that satisfy maxwidth and whose edge is
* within "dist" of the original edge. For slotting requirement
* rules, "dist" is zero (inability to find a rectangle touching
* the original edge ensures that no such rectangle exists that
* can't be found touching a different edge). Also, we only
* need to check one of the four possible edge combinations
* (this part of it is handled in the drcBasic code).
*
* Results:
* LinkedRect list of areas satisfying maxwidth. There may be
* more than one rectangle, and rectangles may overlap. It
* may make more sense to return only one rectangle, the union
* of all rectangles in the list.
*
* Side Effects:
* None.
*
*-------------------------------------------------------------------------
*/
MaxRectsData *
drcCanonicalMaxwidth(starttile, dir, arg, cptr)
Tile *starttile;
int dir; /* direction of rule */
struct drcClientData *arg;
DRCCookie *cptr;
{
int s, edgelimit;
Tile *tile,*tp;
TileTypeBitMask wrongtypes;
static MaxRectsData *mrd = (MaxRectsData *)NULL;
Rect *boundrect, boundorig;
/* Generate an initial array size of 8 for rlist and swap. */
if (mrd == (MaxRectsData *)NULL)
{
mrd = (MaxRectsData *)mallocMagic(sizeof(MaxRectsData));
mrd->rlist = (Rect *)mallocMagic(8 * sizeof(Rect));
mrd->swap = (Rect *)mallocMagic(8 * sizeof(Rect));
mrd->listdepth = 8;
}
if (starttile == NULL) return mrd;
boundrect = &(mrd->rlist[0]);
mrd->match = CLIENTDEFAULT;
edgelimit = cptr->drcc_dist;
arg->dCD_cptr = cptr;
TiToRect(starttile, boundrect);
/* Determine area to be searched */
switch (dir)
{
case GEO_NORTH:
boundrect->r_ytop = boundrect->r_ybot;
boundrect->r_xbot -= (edgelimit - 1);
boundrect->r_xtop += (edgelimit - 1);
boundrect->r_ytop += edgelimit;
break;
case GEO_SOUTH:
boundrect->r_ybot = boundrect->r_ytop;
boundrect->r_xbot -= (edgelimit - 1);
boundrect->r_xtop += (edgelimit - 1);
boundrect->r_ybot -= edgelimit;
break;
case GEO_EAST:
boundrect->r_xtop = boundrect->r_xbot;
boundrect->r_ybot -= (edgelimit - 1);
boundrect->r_ytop += (edgelimit - 1);
boundrect->r_xtop += edgelimit;
break;
case GEO_WEST:
boundrect->r_xbot = boundrect->r_xtop;
boundrect->r_ybot -= (edgelimit - 1);
boundrect->r_ytop += (edgelimit - 1);
boundrect->r_xbot -= edgelimit;
break;
case GEO_CENTER:
boundrect->r_xbot -= edgelimit;
boundrect->r_xtop += edgelimit;
boundrect->r_ybot -= edgelimit;
boundrect->r_ytop += edgelimit;
break;
}
/* Do an area search on boundrect to find all materials not */
/* in oktypes. Each such tile clips or subdivides */
/* boundrect. Any rectangles remaining after the search */
/* satisfy the maxwidth rule. */
mrd->entries = 1;
mrd->maxdist = edgelimit;
TTMaskCom2(&wrongtypes, &cptr->drcc_mask);
boundorig = *boundrect;
DBSrPaintArea(starttile, arg->dCD_celldef->cd_planes[cptr->drcc_edgeplane],
&boundorig, &wrongtypes, FindMaxRects, mrd);
if (mrd->entries == 0)
return NULL;
else if (cptr->drcc_plane != cptr->drcc_edgeplane)
{
/* If the "exclude" option is used, then the maxrect rule will be
* ignored for any metal area partially or totally covered by any
* type in cptr->drcc_corner on plane cptr->drcc_plane (!=
* cptr->drcc_edgeplane).
*/
for (s = 0; s < mrd->entries; s++)
{
Rect *r = &(mrd->rlist[s]);
if (DBSrPaintArea((Tile *)NULL,
arg->dCD_celldef->cd_planes[cptr->drcc_plane],
r, &cptr->drcc_corner, MaxRectsExclude, NULL) != 0)
{
/* Take this area out of consideration */
r->r_xtop = r->r_xbot;
r->r_ytop = r->r_ybot;
}
}
return (MaxRectsData *)mrd;
}
else
return (MaxRectsData *)mrd;
}