Files
magic/drc/DRCextend.c
T
Patrick Kurth ea03883829 Fixed unused-parameters/unused-variables warnings
Added a ARG_UNUSED macro in utils/magic.h, which
produces a simple cast to void to silence the warnings.
The reasons this is used as opposed to an attribute is
that most compilers should support this.
Besides this, the macro can be easily searched for in
the future to potentially remove (where possible) the
unused parameters.
2025-10-10 22:12:19 +02:00

573 lines
16 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))++;
}
}
}
/*
*-------------------------------------------------------------------------
*
* 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 edgelimit;
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_plane],
&boundorig, &wrongtypes, FindMaxRects, mrd);
if (mrd->entries == 0)
return NULL;
else
return (MaxRectsData *)mrd;
}