mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-09-05 00:50:50 +02:00
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.
1105 lines
30 KiB
C
1105 lines
30 KiB
C
/*
|
|
* PlowRules2.c --
|
|
*
|
|
* Plowing rules.
|
|
* These are applied by plowProcessEdge() for each edge that is to be moved.
|
|
*
|
|
* *********************************************************************
|
|
* * 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/plow/PlowRules2.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
|
#endif /* not lint */
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "utils/magic.h"
|
|
#include "utils/geometry.h"
|
|
#include "tiles/tile.h"
|
|
#include "utils/hash.h"
|
|
#include "database/database.h"
|
|
#include "utils/undo.h"
|
|
#include "plow/plow.h"
|
|
#include "plow/plowInt.h"
|
|
#include "drc/drc.h"
|
|
|
|
/* Imports from other rules files */
|
|
extern int plowApplyRule();
|
|
|
|
/* Forward declarations */
|
|
int plowFoundCell();
|
|
int plowCellDragPaint(), plowCellPushPaint();
|
|
int plowCoverTopProc(), plowCoverBotProc();
|
|
int plowIllegalTopProc(), plowIllegalBotProc();
|
|
int plowDragEdgeProc();
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* prFixedLHS --
|
|
* prFixedRHS --
|
|
*
|
|
* The type on the LHS or RHS of an edge is a fixed-width.
|
|
* Make sure that the opposite edge of the tile also moves.
|
|
* When processing an edge whose RHS is fixed-width, we also
|
|
* walk along the top and bottom of each tilef making sure all
|
|
* fixed-width tiles move by the same amount. This is necessary
|
|
* in order to preserve transistor geometries.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* May add edges to the queue of edges to be processed.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
prFixedLHS(edge)
|
|
Edge *edge; /* Edge being moved */
|
|
{
|
|
int distance = edge->e_newx - edge->e_x;
|
|
Tile *tpL;
|
|
Point startPoint;
|
|
Rect atomRect;
|
|
Plane *plane;
|
|
|
|
restart:
|
|
startPoint.p_x = edge->e_x - 1;
|
|
startPoint.p_y = edge->e_ybot;
|
|
plane = plowYankDef->cd_planes[edge->e_pNum];
|
|
for (tpL = TiSrPointNoHint(plane, &startPoint);
|
|
BOTTOM(tpL) < edge->e_ytop;
|
|
tpL = RT(tpL))
|
|
{
|
|
/* Add the entire LHS of each of the tiles comprising this edge */
|
|
atomRect.r_xbot = LEFT(tpL);
|
|
atomRect.r_xtop = LEFT(tpL) + distance;
|
|
atomRect.r_ybot = BOTTOM(tpL);
|
|
atomRect.r_ytop = TOP(tpL);
|
|
if (plowYankMore(&atomRect, 1, 1))
|
|
goto restart;
|
|
|
|
/* Only queue if it hasn't already moved far enough */
|
|
if (TRAILING(tpL) < LEFT(tpL) + distance)
|
|
(void) plowAtomize(edge->e_pNum, &atomRect,
|
|
plowPropagateProcPtr, (ClientData) NULL);
|
|
}
|
|
}
|
|
|
|
int
|
|
prFixedRHS(edge)
|
|
Edge *edge; /* Edge being moved */
|
|
{
|
|
int distance = edge->e_newx - edge->e_x;
|
|
Tile *tpR, *tp;
|
|
Point startPoint;
|
|
Rect atomRect;
|
|
Plane *plane;
|
|
|
|
restart:
|
|
startPoint.p_x = edge->e_x;
|
|
startPoint.p_y = edge->e_ytop - 1;
|
|
plane = plowYankDef->cd_planes[edge->e_pNum];
|
|
tpR = TiSrPointNoHint(plane, &startPoint);
|
|
|
|
/* Move the RHS of all the tiles comprising this edge */
|
|
for ( ; TOP(tpR) > edge->e_ybot; tpR = LB(tpR))
|
|
{
|
|
/* Queue the RHS of this tile */
|
|
atomRect.r_xbot = RIGHT(tpR);
|
|
atomRect.r_xtop = RIGHT(tpR) + distance;
|
|
atomRect.r_ybot = BOTTOM(tpR);
|
|
atomRect.r_ytop = TOP(tpR);
|
|
if (plowYankMore(&atomRect, 1, 1))
|
|
goto restart;
|
|
|
|
/* Only queue RHS if it hasn't already moved far enough */
|
|
if (LEADING(tpR) < RIGHT(tpR) + distance)
|
|
(void) plowAtomize(edge->e_pNum, &atomRect,
|
|
plowPropagateProcPtr, (ClientData) NULL);
|
|
|
|
/* Move all fixed-width tiles along the top */
|
|
for (tp = RT(tpR); RIGHT(tp) > LEFT(tpR); tp = BL(tp))
|
|
{
|
|
if (TTMaskHasType(&PlowFixedTypes, TiGetTypeExact(tp)))
|
|
{
|
|
atomRect.r_xbot = LEFT(tp);
|
|
atomRect.r_xtop = LEFT(tp) + distance;
|
|
atomRect.r_ybot = BOTTOM(tp);
|
|
atomRect.r_ytop = TOP(tp);
|
|
if (plowYankMore(&atomRect, 1, 1))
|
|
goto restart;
|
|
|
|
/* Only queue if it hasn't moved far enough */
|
|
if (TRAILING(tp) < LEFT(tp) + distance)
|
|
(void) plowAtomize(edge->e_pNum, &atomRect,
|
|
plowPropagateProcPtr, (ClientData) NULL);
|
|
}
|
|
}
|
|
|
|
/* Move all fixed-width tiles along the bottom */
|
|
for (tp = LB(tpR); LEFT(tp) < RIGHT(tpR); tp = TR(tp))
|
|
{
|
|
if (TTMaskHasType(&PlowFixedTypes, TiGetTypeExact(tp)))
|
|
{
|
|
atomRect.r_xbot = LEFT(tp);
|
|
atomRect.r_xtop = LEFT(tp) + distance;
|
|
atomRect.r_ybot = BOTTOM(tp);
|
|
atomRect.r_ytop = TOP(tp);
|
|
if (plowYankMore(&atomRect, 1, 1))
|
|
goto restart;
|
|
|
|
/* Only queue if it hasn't moved far enough */
|
|
if (TRAILING(tp) < LEFT(tp) + distance)
|
|
(void) plowAtomize(edge->e_pNum, &atomRect,
|
|
plowPropagateProcPtr, (ClientData) NULL);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* prFixedPenumbraTop --
|
|
* prFixedPenumbraBot --
|
|
*
|
|
* When the RHS material is fixed-width and no spacing rules apply
|
|
* across the edge, these rules get applied. The case handled is
|
|
* the following (E is the edge):
|
|
*
|
|
* OOOOOOOOOOOOOOOOO
|
|
* O O
|
|
* O ------------> O
|
|
* top O O
|
|
* OOOOOOOOOOOOOOOOO
|
|
* =========
|
|
* E
|
|
* ltype E rtype ------>
|
|
* E
|
|
*
|
|
* where spacing rules DO apply across the ltype -- top edge.
|
|
* For each such spacing rule, we search the area O above, where
|
|
* the height of O is the distance of the spacing rule. All
|
|
* edges not in the 'oktypes' for the spacing rule are moved as
|
|
* far as the edge E.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* May add edges to the queue of edges to be processed.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
prFixedPenumbraTop(edge)
|
|
Edge *edge; /* Edge being moved */
|
|
{
|
|
struct applyRule ar;
|
|
PlowRule *pr;
|
|
Tile *tp;
|
|
Rect searchRect;
|
|
Point p;
|
|
|
|
p.p_x = edge->e_x - 1;
|
|
p.p_y = edge->e_ytop;
|
|
tp = TiSrPointNoHint(plowYankDef->cd_planes[edge->e_pNum], &p);
|
|
pr = plowSpacingRulesTbl[edge->e_ltype][TiGetTypeExact(tp)];
|
|
if (pr == (PlowRule *) NULL)
|
|
return;
|
|
|
|
searchRect.r_xbot = edge->e_x - 1;
|
|
searchRect.r_ybot = edge->e_ytop;
|
|
searchRect.r_xtop = edge->e_newx;
|
|
ar.ar_rule = (PlowRule *) NULL;
|
|
ar.ar_moving = edge;
|
|
for ( ; pr; pr = pr->pr_next)
|
|
{
|
|
searchRect.r_ytop = edge->e_ytop + pr->pr_dist;
|
|
(void) plowSrShadow(pr->pr_pNum, &searchRect, &pr->pr_oktypes,
|
|
plowApplyRule, (ClientData) &ar);
|
|
}
|
|
}
|
|
|
|
int
|
|
prFixedPenumbraBot(edge)
|
|
Edge *edge; /* Edge being moved */
|
|
{
|
|
struct applyRule ar;
|
|
PlowRule *pr;
|
|
Tile *tp;
|
|
Rect searchRect;
|
|
Point p;
|
|
|
|
p.p_x = edge->e_x - 1;
|
|
p.p_y = edge->e_ybot - 1;
|
|
tp = TiSrPointNoHint(plowYankDef->cd_planes[edge->e_pNum], &p);
|
|
pr = plowSpacingRulesTbl[edge->e_ltype][TiGetTypeExact(tp)];
|
|
if (pr == (PlowRule *) NULL)
|
|
return 0;
|
|
|
|
searchRect.r_xbot = edge->e_x - 1;
|
|
searchRect.r_ytop = edge->e_ybot;
|
|
searchRect.r_xtop = edge->e_newx;
|
|
ar.ar_rule = (PlowRule *) NULL;
|
|
ar.ar_moving = edge;
|
|
for ( ; pr; pr = pr->pr_next)
|
|
{
|
|
searchRect.r_ybot = edge->e_ybot - pr->pr_dist;
|
|
(void) plowSrShadow(pr->pr_pNum, &searchRect, &pr->pr_oktypes,
|
|
plowApplyRule, (ClientData) &ar);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* prFixedDragStubs --
|
|
*
|
|
* The type on the RHS of an edge is a fixed-width, and the type on the
|
|
* LHS is neither fixed-width nor space. Our job is to drag alone the
|
|
* left-hand side of the LHS tiles if they are minimum-width or less.
|
|
*
|
|
* The purpose of this rule is mainly to prevent transistors from
|
|
* leaving their gates trailing behind.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* May add edges to the queue of edges to be processed.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
prFixedDragStubs(edge)
|
|
Edge *edge; /* Edge being moved; RHS is fixed-width */
|
|
{
|
|
int distance = edge->e_newx - edge->e_x;
|
|
Tile *tpL;
|
|
Point startPoint;
|
|
Rect atomRect;
|
|
Plane *plane;
|
|
|
|
restart:
|
|
startPoint.p_x = edge->e_x - 1;
|
|
startPoint.p_y = edge->e_ybot;
|
|
plane = plowYankDef->cd_planes[edge->e_pNum];
|
|
for (tpL = TiSrPointNoHint(plane, &startPoint);
|
|
BOTTOM(tpL) < edge->e_ytop;
|
|
tpL = RT(tpL))
|
|
{
|
|
/*
|
|
* Add the entire LHS of each of the tiles comprising this edge,
|
|
* if the LHS is minimum-width and exposed to space.
|
|
*/
|
|
atomRect.r_xbot = LEFT(tpL);
|
|
atomRect.r_xtop = LEFT(tpL) + distance;
|
|
atomRect.r_ybot = BOTTOM(tpL);
|
|
atomRect.r_ytop = TOP(tpL);
|
|
if (plowYankMore(&atomRect, 1, 1))
|
|
goto restart;
|
|
|
|
if (TRAILING(tpL) < atomRect.r_xtop)
|
|
(void) plowAtomize(edge->e_pNum, &atomRect,
|
|
plowDragEdgeProc, (ClientData) edge);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* plowDragEdgeProc --
|
|
*
|
|
* Called for each segment along the LHS of the tiles processed by
|
|
* prFixedDragStubs() above. If lhsEdge->e_ltype is space, and
|
|
* lhsEdge is the minimum-distance from movingEdge, we queue it
|
|
* to move by the same amount as movingEdge.
|
|
*
|
|
* Results:
|
|
* Returns 0 always.
|
|
*
|
|
* Side effects:
|
|
* May add edges to the queue of edges to be processed.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
plowDragEdgeProc(lhsEdge, movingEdge)
|
|
Edge *lhsEdge; /* Edge on LHS; the caller has already
|
|
* determined that this edge has not
|
|
* already moved far enough.
|
|
*/
|
|
Edge *movingEdge; /* RHS of this edge is fixed-width */
|
|
{
|
|
PlowRule *pr;
|
|
int xsep, width;
|
|
|
|
/* Don't move the edge if it isn't to space */
|
|
if (lhsEdge->e_ltype != TT_SPACE)
|
|
return (0);
|
|
|
|
/* Don't bother doing any more work if it's too far to the left */
|
|
if (lhsEdge->e_x + DRCTechHalo < movingEdge->e_x)
|
|
return (0);
|
|
|
|
/*
|
|
* Try to guess at minimum width.
|
|
* Then, if lhsEdge is less than minimum width to the left
|
|
* of movingEdge, we queue lhsEdge to move by the same
|
|
* amount.
|
|
*/
|
|
width = INFINITY;
|
|
|
|
/* Apply width rules from lhsEdge rightward */
|
|
for (pr = plowWidthRulesTbl[lhsEdge->e_ltype][lhsEdge->e_rtype];
|
|
pr; pr = pr->pr_next)
|
|
width = MIN(width, pr->pr_dist);
|
|
|
|
/* Apply spacing rules from movingEdge leftward */
|
|
for (pr = plowSpacingRulesTbl[movingEdge->e_rtype][movingEdge->e_ltype];
|
|
pr; pr = pr->pr_next)
|
|
if (!TTMaskHasType(&pr->pr_oktypes, TT_SPACE))
|
|
width = MIN(width, pr->pr_dist);
|
|
|
|
/* No width, so assume we don't move it */
|
|
if (width == INFINITY)
|
|
return (0);
|
|
|
|
/* Only move if minimum width or less */
|
|
xsep = movingEdge->e_x - lhsEdge->e_x;
|
|
if (xsep <= width)
|
|
(*plowPropagateProcPtr)(lhsEdge);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* prContactLHS --
|
|
* prContactRHS --
|
|
*
|
|
* The type on the LHS or RHS of an edge is a contact.
|
|
* Couple to each of the planes connected by the contact.
|
|
* Contacts must be fixed-width.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* May add edges to the queue of edges to be processed.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
prContactLHS(edge)
|
|
Edge *edge; /* Edge being moved (LHS is contact) */
|
|
{
|
|
int pNum;
|
|
PlaneMask connPlanes = DBConnPlanes[edge->e_ltype];
|
|
|
|
/* Remove the plane that has already been processed from the mask */
|
|
connPlanes &= ~PlaneNumToMaskBit(edge->e_pNum);
|
|
|
|
/* Add the edges of the contact on its other planes */
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
if (PlaneMaskHasPlane(connPlanes, pNum))
|
|
(void) plowAtomize(pNum, &edge->e_rect,
|
|
plowPropagateProcPtr, (ClientData) NULL);
|
|
}
|
|
|
|
int
|
|
prContactRHS(edge)
|
|
Edge *edge; /* Edge being moved (RHS is contact) */
|
|
{
|
|
int pNum;
|
|
PlaneMask connPlanes = DBConnPlanes[edge->e_rtype];
|
|
|
|
/* Remove the plane that has already been processed from the mask */
|
|
connPlanes &= ~PlaneNumToMaskBit(edge->e_pNum);
|
|
|
|
/* Add the edges of the contact on its other planes */
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
if (PlaneMaskHasPlane(connPlanes, pNum))
|
|
(void) plowAtomize(pNum, &edge->e_rect,
|
|
plowPropagateProcPtr, (ClientData) NULL);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* prCoverTop --
|
|
* prCoverBot --
|
|
*
|
|
* SEARCH RULE.
|
|
* The material on the LHS of this edge must always stay covered.
|
|
* To insure this, we drag along the material attached to its top
|
|
* right and bottom right corners.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* May add edges to the queue of edges to be moved.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
prCoverTop(edge)
|
|
Edge *edge; /* Edge being moved */
|
|
{
|
|
TileType ltype, rtype;
|
|
PlowRule *pr;
|
|
Tile *tp;
|
|
struct applyRule ar;
|
|
Point startPoint;
|
|
Rect searchArea;
|
|
|
|
startPoint.p_x = edge->e_x - 1;
|
|
startPoint.p_y = edge->e_ytop;
|
|
tp = TiSrPointNoHint(plowYankDef->cd_planes[edge->e_pNum], &startPoint);
|
|
if (TiGetTypeExact(tp) == TT_SPACE)
|
|
return;
|
|
|
|
ltype = edge->e_ltype;
|
|
rtype = TiGetTypeExact(tp);
|
|
ar.ar_moving = edge;
|
|
ar.ar_rule = (PlowRule *) NULL;
|
|
searchArea.r_xbot = edge->e_x - 1;
|
|
searchArea.r_xtop = edge->e_newx;
|
|
searchArea.r_ybot = edge->e_ytop;
|
|
for (pr = plowWidthRulesTbl[ltype][rtype]; pr; pr = pr->pr_next)
|
|
{
|
|
searchArea.r_ytop = edge->e_ytop + pr->pr_dist;
|
|
(void) plowSrShadow(edge->e_pNum, &searchArea, &pr->pr_oktypes,
|
|
plowApplyRule, (ClientData) &ar);
|
|
}
|
|
for (pr = plowSpacingRulesTbl[ltype][rtype]; pr; pr = pr->pr_next)
|
|
{
|
|
searchArea.r_ytop = edge->e_ytop + pr->pr_dist;
|
|
(void) plowSrShadow(edge->e_pNum, &searchArea, &pr->pr_oktypes,
|
|
plowApplyRule, (ClientData) &ar);
|
|
}
|
|
}
|
|
|
|
int
|
|
prCoverBot(edge)
|
|
Edge *edge; /* Edge being moved */
|
|
{
|
|
TileType ltype, rtype;
|
|
PlowRule *pr;
|
|
Tile *tp;
|
|
struct applyRule ar;
|
|
Point startPoint;
|
|
Rect searchArea;
|
|
|
|
startPoint.p_x = edge->e_x - 1;
|
|
startPoint.p_y = edge->e_ybot - 1;
|
|
tp = TiSrPointNoHint(plowYankDef->cd_planes[edge->e_pNum], &startPoint);
|
|
if (TiGetTypeExact(tp) == TT_SPACE)
|
|
return 0;
|
|
|
|
ltype = edge->e_ltype;
|
|
rtype = TiGetTypeExact(tp);
|
|
ar.ar_moving = edge;
|
|
ar.ar_rule = (PlowRule *) NULL;
|
|
searchArea.r_xbot = edge->e_x - 1;
|
|
searchArea.r_xtop = edge->e_newx;
|
|
searchArea.r_ytop = edge->e_ybot;
|
|
for (pr = plowWidthRulesTbl[ltype][rtype]; pr; pr = pr->pr_next)
|
|
{
|
|
searchArea.r_ybot = edge->e_ybot - pr->pr_dist;
|
|
(void) plowSrShadow(edge->e_pNum, &searchArea, &pr->pr_oktypes,
|
|
plowApplyRule, (ClientData) &ar);
|
|
}
|
|
for (pr = plowSpacingRulesTbl[ltype][rtype]; pr; pr = pr->pr_next)
|
|
{
|
|
searchArea.r_ybot = edge->e_ybot - pr->pr_dist;
|
|
(void) plowSrShadow(edge->e_pNum, &searchArea, &pr->pr_oktypes,
|
|
plowApplyRule, (ClientData) &ar);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* prIllegalTop --
|
|
* prIllegalBot --
|
|
*
|
|
* Insure that the material on the LHS of 'edge' doesn't form an illegal
|
|
* edge with material to its top or bottom, as it slides to the right.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* May add edges to the queue of edges to be moved.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
prIllegalTop(edge)
|
|
Edge *edge;
|
|
{
|
|
TileTypeBitMask insideTypes;
|
|
struct applyRule ar;
|
|
Point startPoint;
|
|
|
|
ar.ar_moving = edge;
|
|
startPoint.p_x = edge->e_x;
|
|
startPoint.p_y = edge->e_ytop;
|
|
TTMaskSetOnlyType(&insideTypes, edge->e_rtype);
|
|
TTMaskCom(&insideTypes);
|
|
ar.ar_slivtype = (TileType) -1;
|
|
ar.ar_clip.p_x = edge->e_newx;
|
|
|
|
plowSrOutline(edge->e_pNum, &startPoint, &insideTypes, GEO_NORTH,
|
|
GMASK_EAST|GMASK_WEST|GMASK_NORTH|GMASK_SOUTH,
|
|
plowIllegalTopProc, (ClientData) &ar);
|
|
if (ar.ar_slivtype == (TileType) -1)
|
|
return;
|
|
|
|
startPoint.p_x = ar.ar_mustmove;
|
|
TTMaskSetOnlyType(&insideTypes, ar.ar_slivtype);
|
|
TTMaskCom(&insideTypes);
|
|
plowSrOutline(edge->e_pNum, &startPoint, &insideTypes, GEO_NORTH,
|
|
GMASK_WEST|GMASK_NORTH|GMASK_SOUTH,
|
|
plowCoverTopProc, (ClientData) &ar);
|
|
}
|
|
|
|
int
|
|
prIllegalBot(edge)
|
|
Edge *edge;
|
|
{
|
|
TileTypeBitMask insideTypes;
|
|
struct applyRule ar;
|
|
Point startPoint;
|
|
|
|
ar.ar_moving = edge;
|
|
startPoint.p_x = edge->e_x;
|
|
startPoint.p_y = edge->e_ybot;
|
|
TTMaskSetOnlyType(&insideTypes, edge->e_rtype);
|
|
ar.ar_slivtype = (TileType) -1;
|
|
ar.ar_clip.p_x = edge->e_newx;
|
|
|
|
plowSrOutline(edge->e_pNum, &startPoint, &insideTypes, GEO_SOUTH,
|
|
GMASK_EAST|GMASK_WEST|GMASK_NORTH|GMASK_SOUTH,
|
|
plowIllegalBotProc, (ClientData) &ar);
|
|
if (ar.ar_slivtype == (TileType) -1)
|
|
return 0;
|
|
|
|
startPoint.p_x = ar.ar_mustmove;
|
|
TTMaskSetOnlyType(&insideTypes, ar.ar_slivtype);
|
|
plowSrOutline(edge->e_pNum, &startPoint, &insideTypes, GEO_SOUTH,
|
|
GMASK_WEST|GMASK_NORTH|GMASK_SOUTH,
|
|
plowCoverBotProc, (ClientData) &ar);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* plowCoverTopProc --
|
|
* plowCoverBotProc --
|
|
*
|
|
* Called by plowSrOutline() on behalf of prIllegalTop() or prIllegalBot()
|
|
* above. Move all vertical edges found along the outline being searched
|
|
* until we reach either ar->ar_clip.p_x in the X direction, or ar->ar_clip.p_y
|
|
* in the Y direction, or turn left.
|
|
*
|
|
* Results:
|
|
* Returns 0 if we will keep going, or 1 if any of the termination
|
|
* conditions above are met.
|
|
*
|
|
* Side effects:
|
|
* May add edges to the queue of edges to be moved.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
plowCoverTopProc(outline, ar)
|
|
Outline *outline;
|
|
struct applyRule *ar;
|
|
{
|
|
Edge edge;
|
|
int ret = 0;
|
|
|
|
/* Done if not headed north */
|
|
if (outline->o_currentDir != GEO_NORTH)
|
|
return (1);
|
|
|
|
/* Done if outside of the clip area */
|
|
if (outline->o_rect.r_xbot >= ar->ar_clip.p_x)
|
|
return (1);
|
|
|
|
/* Done after this time if we touch the clip area */
|
|
edge.e_rect = outline->o_rect;
|
|
if (edge.e_ytop >= ar->ar_clip.p_y)
|
|
edge.e_ytop = ar->ar_clip.p_y, ret = 1;
|
|
|
|
if (edge.e_ytop > edge.e_ybot
|
|
&& TRAILING(outline->o_outside) < ar->ar_moving->e_newx)
|
|
{
|
|
edge.e_newx = ar->ar_moving->e_newx;
|
|
edge.e_pNum = ar->ar_moving->e_pNum;
|
|
edge.e_use = (CellUse *) NULL;
|
|
edge.e_flags = 0;
|
|
edge.e_ltype = TiGetTypeExact(outline->o_inside);
|
|
edge.e_rtype = TiGetTypeExact(outline->o_outside);
|
|
(void) (*plowPropagateProcPtr)(&edge);
|
|
}
|
|
|
|
return (ret);
|
|
}
|
|
|
|
int
|
|
plowCoverBotProc(outline, ar)
|
|
Outline *outline;
|
|
struct applyRule *ar;
|
|
{
|
|
Edge edge;
|
|
int ret = 0;
|
|
|
|
/* Done if not headed south */
|
|
if (outline->o_currentDir != GEO_SOUTH)
|
|
return (1);
|
|
|
|
/* Done if outside of the clip area */
|
|
if (outline->o_rect.r_xbot >= ar->ar_clip.p_x)
|
|
return (1);
|
|
|
|
/* Done after this time if we touch the clip area */
|
|
edge.e_rect = outline->o_rect;
|
|
if (edge.e_ybot <= ar->ar_clip.p_y)
|
|
edge.e_ybot = ar->ar_clip.p_y, ret = 1;
|
|
|
|
if (edge.e_ytop > edge.e_ybot
|
|
&& TRAILING(outline->o_inside) < ar->ar_moving->e_newx)
|
|
{
|
|
edge.e_newx = ar->ar_moving->e_newx;
|
|
edge.e_pNum = ar->ar_moving->e_pNum;
|
|
edge.e_use = (CellUse *) NULL;
|
|
edge.e_flags = 0;
|
|
edge.e_ltype = TiGetTypeExact(outline->o_outside);
|
|
edge.e_rtype = TiGetTypeExact(outline->o_inside);
|
|
(void) (*plowPropagateProcPtr)(&edge);
|
|
}
|
|
|
|
return (ret);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* plowIllegalTopProc --
|
|
* plowIllegalBotProc --
|
|
*
|
|
* Called by plowSrOutline() on behalf of prIllegalTop() and prIllegalBot()
|
|
* above. We walk along the outline of the RHS of the edge ar->ar_moving.
|
|
* If the outline turns up, down, or west, we're done. If the outline
|
|
* segment is to the right of ar->ar_clip.p_x, we're also done. Otherwise,
|
|
* we keep going until the type to the top/bottom of the outline is one
|
|
* that cannot be adjacent to ar->ar_moving->e_ltype. At this point,
|
|
* set ar->ar_slivtype to this type and ar->ar_mustmove to the LHS of this
|
|
* segment. Set ar->ar_clip.p_y to 'width' above the top of the edge
|
|
* ar->ar_moving or below its bottom, where 'width' is the minimum spacing
|
|
* between the LHS material of ar->ar_moving and the illegal type.
|
|
*
|
|
* Results:
|
|
* Returns 0 to continue, or 1 if the above termination conditions
|
|
* are met.
|
|
*
|
|
* Side effects:
|
|
* Sets ar_slivtype and ar_clip.p_y.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
plowIllegalTopProc(outline, ar)
|
|
Outline *outline;
|
|
struct applyRule *ar;
|
|
{
|
|
TileType badType = TiGetTypeExact(outline->o_inside), leftType;
|
|
Edge *movingEdge = ar->ar_moving;
|
|
DRCCookie *dp;
|
|
PlowRule *pr;
|
|
int width;
|
|
|
|
if (outline->o_currentDir != GEO_EAST
|
|
|| outline->o_rect.r_xbot >= ar->ar_clip.p_x)
|
|
return (1);
|
|
|
|
/* Ignore if this is a legal edge */
|
|
for (dp = DRCCurStyle->DRCRulesTbl[movingEdge->e_ltype][badType];
|
|
dp; dp = dp->drcc_next)
|
|
{
|
|
if (!TTMaskHasType(&dp->drcc_mask, badType))
|
|
goto found_bad;
|
|
}
|
|
return (0);
|
|
|
|
/* Found a bad type */
|
|
found_bad:
|
|
|
|
/* Don't do anything if there was already a design-rule violation */
|
|
if (LEFT(outline->o_inside) < movingEdge->e_x)
|
|
return (0);
|
|
|
|
ar->ar_slivtype = badType;
|
|
ar->ar_mustmove = outline->o_rect.r_xbot;
|
|
leftType = TiGetTypeExact(BL(outline->o_inside));
|
|
width = 1;
|
|
for (pr = plowSpacingRulesTbl[movingEdge->e_ltype][leftType];
|
|
pr; pr = pr->pr_next)
|
|
{
|
|
if (!TTMaskHasType(&pr->pr_oktypes, badType))
|
|
width = MAX(width, pr->pr_dist);
|
|
}
|
|
ar->ar_clip.p_y = movingEdge->e_ytop + width;
|
|
return (1);
|
|
}
|
|
|
|
int
|
|
plowIllegalBotProc(outline, ar)
|
|
Outline *outline;
|
|
struct applyRule *ar;
|
|
{
|
|
TileType badType = TiGetTypeExact(outline->o_outside), leftType;
|
|
Edge *movingEdge = ar->ar_moving;
|
|
DRCCookie *dp;
|
|
PlowRule *pr;
|
|
Tile *tp;
|
|
int width;
|
|
|
|
if (outline->o_currentDir != GEO_EAST
|
|
|| outline->o_rect.r_xbot >= ar->ar_clip.p_x)
|
|
return (1);
|
|
|
|
/* Ignore if this is a legal edge */
|
|
for (dp = DRCCurStyle->DRCRulesTbl[movingEdge->e_ltype][badType];
|
|
dp; dp = dp->drcc_next)
|
|
{
|
|
if (!TTMaskHasType(&dp->drcc_mask, badType))
|
|
goto found_bad;
|
|
}
|
|
return (0);
|
|
|
|
/* Found a bad type */
|
|
found_bad:
|
|
|
|
/* Don't do anything if there was already a design-rule violation */
|
|
if (LEFT(outline->o_outside) < movingEdge->e_x)
|
|
return (0);
|
|
|
|
ar->ar_slivtype = badType;
|
|
ar->ar_mustmove = outline->o_rect.r_xbot;
|
|
for (tp = BL(outline->o_outside);
|
|
TOP(tp) < outline->o_rect.r_ybot; tp = RT(tp))
|
|
/* Nothing */;
|
|
leftType = TiGetTypeExact(tp);
|
|
|
|
width = 1;
|
|
for (pr = plowSpacingRulesTbl[movingEdge->e_ltype][leftType];
|
|
pr; pr = pr->pr_next)
|
|
{
|
|
if (!TTMaskHasType(&pr->pr_oktypes, badType))
|
|
width = MAX(width, pr->pr_dist);
|
|
}
|
|
ar->ar_clip.p_y = movingEdge->e_ybot - width;
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* prFindCells --
|
|
*
|
|
* Find any cells within a DRC halo of the swath cut by the edge 'edge'
|
|
* as it moves, and move them.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* May add cells to the queue of edges to be processed.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
prFindCells(edge)
|
|
Edge *edge; /* Edge being moved */
|
|
{
|
|
BPlane *cellPlane = plowYankDef->cd_cellPlane;
|
|
struct applyRule ar;
|
|
Rect searchArea;
|
|
|
|
searchArea.r_xbot = edge->e_x - 1;
|
|
searchArea.r_ybot = edge->e_ybot - DRCTechHalo;
|
|
searchArea.r_ytop = edge->e_ytop + DRCTechHalo;
|
|
searchArea.r_xtop = edge->e_newx + DRCTechHalo;
|
|
ar.ar_moving = edge;
|
|
|
|
(void) DBSrCellPlaneArea(cellPlane, &searchArea, plowFoundCell,
|
|
(ClientData) &ar);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* prCell --
|
|
*
|
|
* The Edge 'edge' corresponds to a cell that is moving. Search the
|
|
* area of the cell plus a DRCTechHalo around it for geometry to move,
|
|
* and queue each edge found. Also, search to its right for other
|
|
* cells to move and move them.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* May add cells or edges to the queue of edges to be processed.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
prCell(edge)
|
|
Edge *edge; /* Cell edge being moved */
|
|
{
|
|
Rect cellArea, shadowArea;
|
|
CellUse *use = edge->e_use;
|
|
struct applyRule ar;
|
|
int pNum;
|
|
|
|
ar.ar_moving = edge;
|
|
|
|
/* Search area for paint to drag */
|
|
ar.ar_search.r_xbot = use->cu_bbox.r_xbot - 1;
|
|
ar.ar_search.r_xtop = use->cu_bbox.r_xtop + DRCTechHalo;
|
|
ar.ar_search.r_ybot = edge->e_ybot - DRCTechHalo;
|
|
ar.ar_search.r_ytop = edge->e_ytop + DRCTechHalo;
|
|
|
|
/* Shadow search area for the paint planes */
|
|
shadowArea.r_xbot = edge->e_x - 1;
|
|
shadowArea.r_xtop = edge->e_newx + DRCTechHalo;
|
|
shadowArea.r_ybot = edge->e_ybot - DRCTechHalo;
|
|
shadowArea.r_ytop = edge->e_ytop + DRCTechHalo;
|
|
|
|
/* Search all the paint planes */
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
{
|
|
ar.ar_pNum = pNum;
|
|
(void) DBSrPaintArea((Tile *) NULL, plowYankDef->cd_planes[pNum],
|
|
&ar.ar_search, &DBAllTypeBits,
|
|
plowCellDragPaint, (ClientData) &ar);
|
|
(void) plowSrShadow(pNum, &shadowArea, &DBZeroTypeBits,
|
|
plowCellPushPaint, (ClientData) &ar);
|
|
}
|
|
|
|
/*
|
|
* Search for cells to move.
|
|
* We could do a shadow search, but just use area search instead
|
|
* since we don't expect there to be too many cells in the path.
|
|
* Cells to the left of the RHS of use get dragged by the same
|
|
* amount as use is moving; cells to its right stay DRCTechHalo away
|
|
* (or closer if they were originally closer).
|
|
*/
|
|
cellArea.r_xbot = use->cu_bbox.r_xbot - 1;
|
|
cellArea.r_xtop = edge->e_newx + DRCTechHalo;
|
|
cellArea.r_ybot = edge->e_ybot - DRCTechHalo;
|
|
cellArea.r_ytop = edge->e_ytop + DRCTechHalo;
|
|
(void) DBSrCellPlaneArea(plowYankDef->cd_cellPlane,
|
|
&cellArea, plowFoundCell,
|
|
(ClientData) &ar);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* plowCellDragPaint --
|
|
*
|
|
* Called by DBSrPaintArea() on behalf of prCell() above for each tile
|
|
* overlapping the cell being moved (ar->ar_moving->e_use), or a DRCTechHalo
|
|
* wide halo around it to the right, top, or bottom.
|
|
*
|
|
* If the LHS of the tile lies to the right of the LHS of the cell, we
|
|
* move it; otherwise, we move the RHS of the tile.
|
|
*
|
|
* Results:
|
|
* Returns 0 always.
|
|
*
|
|
* Side effects:
|
|
* May add edges to the queue of edges to be processed.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
plowCellDragPaint(tile, dinfo, ar)
|
|
Tile *tile;
|
|
TileType dinfo; /* (unused) */
|
|
struct applyRule *ar;
|
|
{
|
|
Edge *movingEdge = ar->ar_moving;
|
|
int distance = movingEdge->e_newx - movingEdge->e_x;
|
|
Rect atomRect;
|
|
|
|
if (LEFT(tile) <= ar->ar_search.r_xbot)
|
|
{
|
|
if (LEADING(tile) >= ar->ar_search.r_xtop)
|
|
return (0);
|
|
atomRect.r_xtop = RIGHT(tile) + distance;
|
|
if (LEADING(tile) >= atomRect.r_xtop)
|
|
return (0);
|
|
atomRect.r_xbot = RIGHT(tile);
|
|
}
|
|
else
|
|
{
|
|
atomRect.r_xtop = LEFT(tile) + distance;
|
|
if (TRAILING(tile) >= atomRect.r_xtop)
|
|
return (0);
|
|
atomRect.r_xbot = LEFT(tile);
|
|
}
|
|
atomRect.r_ybot = MAX(BOTTOM(tile), ar->ar_search.r_ybot);
|
|
atomRect.r_ytop = MIN(TOP(tile), ar->ar_search.r_ytop);
|
|
(void) plowAtomize(ar->ar_pNum, &atomRect,
|
|
plowPropagateProcPtr, (ClientData) NULL);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* plowCellPushPaint --
|
|
*
|
|
* Filter procedure called by plowSrShadow() on behalf of prCell above.
|
|
* Each paint tile in the shadow of the RHS of the cell being moved
|
|
* gets pushed DRCTechHalo in front of the cell when it moves. (If the
|
|
* paint was already closer than DRCTechHalo to the front of the cell,
|
|
* it stays that close).
|
|
*
|
|
* Results:
|
|
* Returns 0 always.
|
|
*
|
|
* Side effects:
|
|
* May add edges to the queue of edges to be processed.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
plowCellPushPaint(impactedEdge, ar)
|
|
Edge *impactedEdge; /* Edge found by shadow search */
|
|
struct applyRule *ar; /* Describes edge being moved and search area */
|
|
{
|
|
Edge *movingEdge = ar->ar_moving;
|
|
int xsep, newx;
|
|
|
|
xsep = impactedEdge->e_x - movingEdge->e_x;
|
|
if (xsep > DRCTechHalo) xsep = DRCTechHalo;
|
|
|
|
/* Queue the edge if it hasn't already moved far enough */
|
|
newx = movingEdge->e_newx + xsep;
|
|
if (newx > impactedEdge->e_newx)
|
|
{
|
|
impactedEdge->e_newx = newx;
|
|
(void) (*plowPropagateProcPtr)(impactedEdge);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* plowFoundCell --
|
|
*
|
|
* Called for each cell tile found by an area enumeration of the umbra of
|
|
* a moving edge, plus a DRCTechHalo-wide halo above, below, and to its right.
|
|
* Determine how far each use associated with that cell tile must move. If
|
|
* that cell has not already moved far enough, queue it.
|
|
*
|
|
* Results:
|
|
* Returns 0 always.
|
|
*
|
|
* Side effects:
|
|
* May add cells to the queue of edges to be processed.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
plowFoundCell(use, ar)
|
|
CellUse *use;
|
|
struct applyRule *ar;
|
|
{
|
|
Edge *movingEdge = ar->ar_moving;
|
|
int xmove, xsep;
|
|
Edge edge;
|
|
|
|
edge.e_pNum = PL_ROUTER;
|
|
|
|
if (use->cu_bbox.r_xbot <= movingEdge->e_x)
|
|
{
|
|
/*
|
|
* If dragging the cell, move it by as much as this edge.
|
|
*/
|
|
xmove = movingEdge->e_newx - movingEdge->e_x;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* If pushing the cell, keep it DRCTechHalo in front of the edge
|
|
* unless it was already closer.
|
|
*/
|
|
xsep = use->cu_bbox.r_xbot - movingEdge->e_x;
|
|
if (xsep > DRCTechHalo) xsep = DRCTechHalo;
|
|
xmove = movingEdge->e_newx + xsep - use->cu_bbox.r_xbot;
|
|
}
|
|
|
|
/* Only queue the edge if the cell has not moved far enough */
|
|
if ((use->cu_client != (ClientData)CLIENTDEFAULT) &&
|
|
((int)CD2INT(use->cu_client) < xmove))
|
|
{
|
|
edge.e_use = use;
|
|
edge.e_flags = 0;
|
|
edge.e_ytop = use->cu_bbox.r_ytop;
|
|
edge.e_ybot = use->cu_bbox.r_ybot;
|
|
edge.e_x = use->cu_bbox.r_xtop;
|
|
edge.e_newx = use->cu_bbox.r_xtop + xmove;
|
|
edge.e_ltype = PLOWTYPE_CELL;
|
|
edge.e_rtype = PLOWTYPE_CELL;
|
|
(void) (*plowPropagateProcPtr)(&edge);
|
|
}
|
|
|
|
return (0);
|
|
}
|