magic/plow/PlowRules2.c

1104 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, ar)
Tile *tile;
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);
}