2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
#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 $";
|
2020-05-23 23:13:14 +02:00
|
|
|
#endif
|
2017-04-25 14:41:48 +02:00
|
|
|
|
|
|
|
|
#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) \
|
2025-02-21 18:54:11 +01:00
|
|
|
if (TiGetClient(tp) == DRC_UNPROCESSED) { \
|
|
|
|
|
TiSetClientINT(tp, DRC_PENDING); \
|
2017-04-25 14:41:48 +02:00
|
|
|
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.
|
|
|
|
|
*
|
2022-04-20 22:16:20 +02:00
|
|
|
* NOTES: Tile has been determined to be a split tile before this
|
|
|
|
|
* routine is called.
|
|
|
|
|
*
|
2017-04-25 14:41:48 +02:00
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
drcCheckAngles(tile, arg, cptr)
|
|
|
|
|
Tile *tile;
|
|
|
|
|
struct drcClientData *arg;
|
|
|
|
|
DRCCookie *cptr;
|
|
|
|
|
{
|
|
|
|
|
Rect rect;
|
2022-04-20 22:16:20 +02:00
|
|
|
bool ortho = (cptr->drcc_flags & DRC_ANGLES_45) ? FALSE : TRUE;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
2022-04-20 22:16:20 +02:00
|
|
|
if (ortho || ((RIGHT(tile) - LEFT(tile)) != (TOP(tile) - BOTTOM(tile))))
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2022-04-20 22:16:20 +02:00
|
|
|
TiToRect(tile, &rect);
|
|
|
|
|
GeoClip(&rect, arg->dCD_clip);
|
|
|
|
|
if (!GEO_RECTNULL(&rect))
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2022-04-20 22:16:20 +02:00
|
|
|
arg->dCD_cptr = cptr;
|
|
|
|
|
(*(arg->dCD_function)) (arg->dCD_celldef, &rect,
|
2017-04-25 14:41:48 +02:00
|
|
|
arg->dCD_cptr, arg->dCD_clientData);
|
2022-04-20 22:16:20 +02:00
|
|
|
(*(arg->dCD_errors))++;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-04 23:35:43 +01:00
|
|
|
/*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* 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))++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* drcCheckArea- checks to see that a collection of tiles of a given
|
2017-04-25 14:41:48 +02:00
|
|
|
* 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;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
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);
|
2025-02-21 18:54:11 +01:00
|
|
|
if (TiGetClientINT(tile) != DRC_PENDING) continue;
|
2017-04-25 14:41:48 +02:00
|
|
|
area += (long)(RIGHT(tile)-LEFT(tile))*(TOP(tile)-BOTTOM(tile));
|
2025-02-21 18:54:11 +01:00
|
|
|
TiSetClientINT(tile, DRC_PROCESSED);
|
2017-04-25 14:41:48 +02:00
|
|
|
/* 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 */
|
2025-02-21 18:54:11 +01:00
|
|
|
TiSetClient(starttile, DRC_UNPROCESSED);
|
2017-04-25 14:41:48 +02:00
|
|
|
STACKPUSH(starttile, DRCstack);
|
|
|
|
|
while (!StackEmpty(DRCstack))
|
|
|
|
|
{
|
|
|
|
|
tile = (Tile *) STACKPOP(DRCstack);
|
|
|
|
|
|
|
|
|
|
/* Top */
|
|
|
|
|
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
|
2025-02-21 18:54:11 +01:00
|
|
|
if (TiGetClient(tp) != DRC_UNPROCESSED)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2025-02-21 18:54:11 +01:00
|
|
|
TiSetClient(tp, DRC_UNPROCESSED);
|
|
|
|
|
STACKPUSH(tp,DRCstack);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Left */
|
|
|
|
|
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
|
2025-02-21 18:54:11 +01:00
|
|
|
if (TiGetClient(tp) != DRC_UNPROCESSED)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2025-02-21 18:54:11 +01:00
|
|
|
TiSetClient(tp, DRC_UNPROCESSED);
|
|
|
|
|
STACKPUSH(tp,DRCstack);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Bottom */
|
|
|
|
|
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
|
2025-02-21 18:54:11 +01:00
|
|
|
if (TiGetClient(tp) != DRC_UNPROCESSED)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2025-02-21 18:54:11 +01:00
|
|
|
TiSetClient(tp, DRC_UNPROCESSED);
|
|
|
|
|
STACKPUSH(tp,DRCstack);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Right */
|
|
|
|
|
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
|
2025-02-21 18:54:11 +01:00
|
|
|
if (TiGetClient(tp) != DRC_UNPROCESSED)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2025-02-21 18:54:11 +01:00
|
|
|
TiSetClient(tp, DRC_UNPROCESSED);
|
|
|
|
|
STACKPUSH(tp,DRCstack);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* 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
|
2021-02-18 02:53:17 +01:00
|
|
|
drcCheckMaxwidth(starttile,arg,cptr,both)
|
2017-04-25 14:41:48 +02:00
|
|
|
Tile *starttile;
|
|
|
|
|
struct drcClientData *arg;
|
|
|
|
|
DRCCookie *cptr;
|
2021-02-18 02:53:17 +01:00
|
|
|
bool both;
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2021-02-18 02:53:17 +01:00
|
|
|
int width;
|
|
|
|
|
int height;
|
2017-04-25 14:41:48 +02:00
|
|
|
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);
|
2025-02-21 18:54:11 +01:00
|
|
|
if (TiGetClientINT(tile) != DRC_PENDING) continue;
|
|
|
|
|
TiSetClientINT(tile, DRC_PROCESSED);
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-18 02:53:17 +01:00
|
|
|
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)) )
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* reset the tiles */
|
2025-02-21 18:54:11 +01:00
|
|
|
TiSetClient(starttile, DRC_UNPROCESSED);
|
2017-04-25 14:41:48 +02:00
|
|
|
STACKPUSH(starttile, DRCstack);
|
|
|
|
|
while (!StackEmpty(DRCstack))
|
|
|
|
|
{
|
|
|
|
|
tile = (Tile *) STACKPOP(DRCstack);
|
|
|
|
|
|
|
|
|
|
/* Top */
|
|
|
|
|
for (tp = RT(tile); RIGHT(tp) > LEFT(tile); tp = BL(tp))
|
2025-02-21 18:54:11 +01:00
|
|
|
if (TiGetClient(tp) != DRC_UNPROCESSED)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2025-02-21 18:54:11 +01:00
|
|
|
TiSetClient(tp, DRC_UNPROCESSED);
|
|
|
|
|
STACKPUSH(tp,DRCstack);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Left */
|
|
|
|
|
for (tp = BL(tile); BOTTOM(tp) < TOP(tile); tp = RT(tp))
|
2025-02-21 18:54:11 +01:00
|
|
|
if (TiGetClient(tp) != DRC_UNPROCESSED)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2025-02-21 18:54:11 +01:00
|
|
|
TiSetClient(tp, DRC_UNPROCESSED);
|
|
|
|
|
STACKPUSH(tp,DRCstack);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Bottom */
|
|
|
|
|
for (tp = LB(tile); LEFT(tp) < RIGHT(tile); tp = TR(tp))
|
2025-02-21 18:54:11 +01:00
|
|
|
if (TiGetClient(tp) != DRC_UNPROCESSED)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2025-02-21 18:54:11 +01:00
|
|
|
TiSetClient(tp, DRC_UNPROCESSED);
|
|
|
|
|
STACKPUSH(tp,DRCstack);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Right */
|
|
|
|
|
for (tp = TR(tile); TOP(tp) > BOTTOM(tile); tp = LB(tp))
|
2025-02-21 18:54:11 +01:00
|
|
|
if (TiGetClient(tp) != DRC_UNPROCESSED)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2025-02-21 18:54:11 +01:00
|
|
|
TiSetClient(tp, DRC_UNPROCESSED);
|
2017-04-25 14:41:48 +02:00
|
|
|
STACKPUSH(tp,DRCstack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* drcCheckRectSize-
|
2017-04-25 14:41:48 +02:00
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* Checks to see that a collection of tiles of given
|
2017-04-25 14:41:48 +02:00
|
|
|
* 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");
|
2020-05-23 23:13:14 +02:00
|
|
|
for (t = starttile; TTMaskHasType(oktypes, TiGetType(t)); t = TR(t))
|
2017-04-25 14:41:48 +02:00
|
|
|
/* loop has empty body */ ;
|
|
|
|
|
errwidth = width = LEFT(t) - LEFT(starttile);
|
2020-05-23 23:13:14 +02:00
|
|
|
for (t = starttile; TTMaskHasType(oktypes, TiGetType(t)); t = RT(t))
|
2017-04-25 14:41:48 +02:00
|
|
|
/* 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))++;
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-30 21:39:54 +01:00
|
|
|
/*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* 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(
|
2026-01-03 02:12:37 +01:00
|
|
|
Tile *tile, /* (unused) */
|
|
|
|
|
TileType dinfo, /* (unused) */
|
|
|
|
|
ClientData clientdata) /* (unused) */
|
2025-10-30 21:39:54 +01:00
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* 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 *
|
Fixed an error that was discovered with the drcCanonicalMaxwidth()
routine, which in turn affects various DRC rules like maxrect,
widespacing, and runlength spacing. drcTile() was computing
the drcCanonicalMaxwidth() result for the tile and reusing it,
failing to account for the fact that within the loop over
DRCCookies, other rules might require calling drcCanonicalMaxwidth()
on a neighboring tile, or on the same tile with a different width
requirement. Implemented a cached version, in which three results
are kept: One for neighboring tiles (which can never be reused on
the same edge), one for the first required use of the routine for
the tile, and one for any other use required for the tile. If
there are one or two such rules for an edge, then the routine will
work at maximum efficiency. If there are three rules, then one
will always be a cache hit and reduce the total amount of
computation, although it will still be doing a massive amount of
redundant computation. If this seems to be something that
occurs regularly, then it can be revisited. The existing
implementation works fine for all the open PDKs. Some more
advanced PDKs with a number of staged wide-spacing rules could
have issues.
2026-04-14 23:37:10 +02:00
|
|
|
drcCanonicalMaxwidth(starttile, dir, arg, cptr, mrdptr)
|
2017-04-25 14:41:48 +02:00
|
|
|
Tile *starttile;
|
|
|
|
|
int dir; /* direction of rule */
|
|
|
|
|
struct drcClientData *arg;
|
|
|
|
|
DRCCookie *cptr;
|
Fixed an error that was discovered with the drcCanonicalMaxwidth()
routine, which in turn affects various DRC rules like maxrect,
widespacing, and runlength spacing. drcTile() was computing
the drcCanonicalMaxwidth() result for the tile and reusing it,
failing to account for the fact that within the loop over
DRCCookies, other rules might require calling drcCanonicalMaxwidth()
on a neighboring tile, or on the same tile with a different width
requirement. Implemented a cached version, in which three results
are kept: One for neighboring tiles (which can never be reused on
the same edge), one for the first required use of the routine for
the tile, and one for any other use required for the tile. If
there are one or two such rules for an edge, then the routine will
work at maximum efficiency. If there are three rules, then one
will always be a cache hit and reduce the total amount of
computation, although it will still be doing a massive amount of
redundant computation. If this seems to be something that
occurs regularly, then it can be revisited. The existing
implementation works fine for all the open PDKs. Some more
advanced PDKs with a number of staged wide-spacing rules could
have issues.
2026-04-14 23:37:10 +02:00
|
|
|
MaxRectsData **mrdptr;
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
int s, edgelimit;
|
|
|
|
|
Tile *tile,*tp;
|
|
|
|
|
TileTypeBitMask wrongtypes;
|
Fixed an error that was discovered with the drcCanonicalMaxwidth()
routine, which in turn affects various DRC rules like maxrect,
widespacing, and runlength spacing. drcTile() was computing
the drcCanonicalMaxwidth() result for the tile and reusing it,
failing to account for the fact that within the loop over
DRCCookies, other rules might require calling drcCanonicalMaxwidth()
on a neighboring tile, or on the same tile with a different width
requirement. Implemented a cached version, in which three results
are kept: One for neighboring tiles (which can never be reused on
the same edge), one for the first required use of the routine for
the tile, and one for any other use required for the tile. If
there are one or two such rules for an edge, then the routine will
work at maximum efficiency. If there are three rules, then one
will always be a cache hit and reduce the total amount of
computation, although it will still be doing a massive amount of
redundant computation. If this seems to be something that
occurs regularly, then it can be revisited. The existing
implementation works fine for all the open PDKs. Some more
advanced PDKs with a number of staged wide-spacing rules could
have issues.
2026-04-14 23:37:10 +02:00
|
|
|
MaxRectsData *mrd = *mrdptr;
|
2017-04-25 14:41:48 +02:00
|
|
|
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;
|
Fixed an error that was discovered with the drcCanonicalMaxwidth()
routine, which in turn affects various DRC rules like maxrect,
widespacing, and runlength spacing. drcTile() was computing
the drcCanonicalMaxwidth() result for the tile and reusing it,
failing to account for the fact that within the loop over
DRCCookies, other rules might require calling drcCanonicalMaxwidth()
on a neighboring tile, or on the same tile with a different width
requirement. Implemented a cached version, in which three results
are kept: One for neighboring tiles (which can never be reused on
the same edge), one for the first required use of the routine for
the tile, and one for any other use required for the tile. If
there are one or two such rules for an edge, then the routine will
work at maximum efficiency. If there are three rules, then one
will always be a cache hit and reduce the total amount of
computation, although it will still be doing a massive amount of
redundant computation. If this seems to be something that
occurs regularly, then it can be revisited. The existing
implementation works fine for all the open PDKs. Some more
advanced PDKs with a number of staged wide-spacing rules could
have issues.
2026-04-14 23:37:10 +02:00
|
|
|
*mrdptr = mrd;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
if (starttile == NULL) return mrd;
|
|
|
|
|
|
|
|
|
|
boundrect = &(mrd->rlist[0]);
|
|
|
|
|
mrd->match = CLIENTDEFAULT;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
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;
|
2025-10-30 21:39:54 +01:00
|
|
|
DBSrPaintArea(starttile, arg->dCD_celldef->cd_planes[cptr->drcc_edgeplane],
|
2017-04-25 14:41:48 +02:00
|
|
|
&boundorig, &wrongtypes, FindMaxRects, mrd);
|
|
|
|
|
if (mrd->entries == 0)
|
|
|
|
|
return NULL;
|
2025-10-30 21:39:54 +01:00
|
|
|
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;
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
else
|
|
|
|
|
return (MaxRectsData *)mrd;
|
|
|
|
|
}
|
|
|
|
|
|