640 lines
16 KiB
C
640 lines
16 KiB
C
/*
|
||
* mzExtendLeft.c --
|
||
*
|
||
* Code for finding next interesting point to left.
|
||
*
|
||
* *********************************************************************
|
||
* * Copyright (C) 1988, 1990 Michael H. Arnold and the 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/mzrouter/mzXtndLeft.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 "utils/geofast.h"
|
||
#include "tiles/tile.h"
|
||
#include "utils/hash.h"
|
||
#include "utils/heap.h"
|
||
#include "database/database.h"
|
||
#include "utils/signals.h"
|
||
#include "textio/textio.h"
|
||
#include "utils/list.h"
|
||
#include "debug/debug.h"
|
||
#include "mzrouter/mzrouter.h"
|
||
#include "mzrouter/mzInternal.h"
|
||
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* mzExtendLeft --
|
||
*
|
||
* Find next interesting point to the left.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* mzAddPoint() called to added extended path to appropriate queue.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
void
|
||
mzExtendLeft(path)
|
||
RoutePath *path;
|
||
{
|
||
Point pOrg; /* point to extend from */
|
||
Point pStep; /* one unit from pOrg in direction of extension */
|
||
Point pNew; /* next interesting point in direction of extension */
|
||
dlong segCost; /* cost of segment between pOrg and pNew */
|
||
RouteLayer *rL; /* temp variable for routelayers */
|
||
int reasons; /* Reasons point is interesting. Used to
|
||
* avoid extensions in uninteresting directions.
|
||
*/
|
||
int extendCode; /* Interesting directions to extend in */
|
||
bool overroute = FALSE; /* Is crossing another route layer */
|
||
TileType ntype;
|
||
Tile *tpThis;
|
||
|
||
/* DEBUG - trace calls to this routine. */
|
||
if (DebugIsSet(mzDebugID, mzDebMaze))
|
||
TxPrintf("EXTENDING LEFT\n");
|
||
|
||
/* pOrg = current end of path */
|
||
pOrg = path->rp_entry;
|
||
|
||
/* pStep = point just one unit beyond pOrg */
|
||
pStep = pOrg;
|
||
--(pStep.p_x);
|
||
|
||
|
||
/* Initial pNew to BOUNDS edge. Must stop there
|
||
* since blockage planes haven't been generated past there.
|
||
*/
|
||
{
|
||
Tile *tp;
|
||
|
||
/* get bounds tile under pOrg */
|
||
tp = TiSrPointNoHint(mzHBoundsPlane, &pOrg);
|
||
pNew.p_x = LEFT(tp);
|
||
pNew.p_y = pOrg.p_y;
|
||
reasons = RC_BOUNDS;
|
||
}
|
||
|
||
/*
|
||
* Initial pNew to next pt where there is a change in the amount of
|
||
* space on the BLOCKAGE plane in the direction perpendicular to the
|
||
* extension. (A special case of this is an actual block
|
||
* of the extension). Want to consider jogs at such points.
|
||
*
|
||
*/
|
||
{
|
||
Tile *tpNext;
|
||
bool covered;
|
||
|
||
/* get tpThis, extending bounds plane and iterating, until
|
||
* completely covered by bounds plane.
|
||
*/
|
||
covered = FALSE;
|
||
while(!covered)
|
||
{
|
||
Tile *tpBounds;
|
||
|
||
/* get blockage plane tile under pOrg */
|
||
tpThis = TiSrPointNoHint(path->rp_rLayer->rl_routeType.rt_vBlock,
|
||
&pOrg);
|
||
|
||
/* org point should not be blocked */
|
||
ASSERT(TiGetType(tpThis) == TT_SPACE, "mzExtendLeft");
|
||
|
||
|
||
/* check to see if covered, if not extend bounds and start over */
|
||
covered = TRUE;
|
||
tpBounds = TiSrPointNoHint(mzVBoundsPlane, &pOrg);
|
||
while(covered && RIGHT(tpBounds)>=LEFT(tpThis) &&
|
||
RIGHT(tpBounds)>=mzRouteUse->cu_def->cd_bbox.r_xbot)
|
||
{
|
||
if(TiGetType(tpBounds) == TT_SPACE)
|
||
{
|
||
/* hit edge of bounds before jog found */
|
||
goto leftEndJog;
|
||
}
|
||
else if(TOP(tpBounds)<=TOP(tpThis) &&
|
||
TOP(tpBounds)<=mzRouteUse->cu_def->cd_bbox.r_ytop)
|
||
{
|
||
Point p;
|
||
|
||
p.p_x = MIN(RIGHT(tpBounds), pOrg.p_x);
|
||
p.p_y = TOP(tpBounds);
|
||
|
||
mzExtendBlockBounds(&p);
|
||
if(SigInterruptPending) return;
|
||
|
||
covered = FALSE;
|
||
}
|
||
else if(BOTTOM(tpBounds)>=BOTTOM(tpThis) &&
|
||
BOTTOM(tpBounds)>=mzRouteUse->cu_def->cd_bbox.r_ybot)
|
||
{
|
||
Point p;
|
||
p.p_x = MIN(RIGHT(tpBounds), pOrg.p_x);
|
||
p.p_y = BOTTOM(tpBounds);
|
||
|
||
mzExtendBlockBounds(&p);
|
||
if(SigInterruptPending) return;
|
||
|
||
covered = FALSE;
|
||
}
|
||
|
||
/* move to next tile in bounds plane */
|
||
if(covered)
|
||
{
|
||
NEXT_TILE_LEFT(tpBounds, tpBounds, pOrg.p_y);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* also get next tile over */
|
||
NEXT_TILE_LEFT(tpNext, tpThis, pOrg.p_y);
|
||
ntype = TiGetType(tpNext);
|
||
|
||
if ((ntype != TT_SPACE) && (ntype != TT_SAMENODE))
|
||
{
|
||
/* path blocked */
|
||
if (LEFT(tpThis) == pOrg.p_x)
|
||
{
|
||
/* pOrg right up against block */
|
||
if (ntype == TT_RIGHT_WALK)
|
||
{
|
||
/* Block is walk, enter it */
|
||
pNew.p_x = pOrg.p_x - 1;
|
||
reasons = RC_WALK;
|
||
goto donePruning;
|
||
}
|
||
else if (ntype == TT_ABOVE_LR_WALK ||
|
||
ntype == TT_BELOW_LR_WALK)
|
||
{
|
||
/* Block is contact walk, enter it */
|
||
pNew.p_x = pOrg.p_x - 1;
|
||
reasons = RC_WALKLRC;
|
||
goto donePruning;
|
||
}
|
||
else if (ntype == TT_ABOVE_UD_WALK ||
|
||
ntype == TT_BELOW_UD_WALK)
|
||
{
|
||
/* Block is contact walk, enter it */
|
||
pNew.p_x = pOrg.p_x - 1;
|
||
reasons = RC_WALKUDC;
|
||
goto donePruning;
|
||
}
|
||
else if (ntype == TT_DEST_AREA)
|
||
{
|
||
/* Block is destination, enter it */
|
||
pNew.p_x = pOrg.p_x - 1;
|
||
reasons = RC_DONE;
|
||
goto donePruning;
|
||
}
|
||
else
|
||
{
|
||
/* Path blocked from expansion, just return */
|
||
return;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* prune pNew to just this side of block */
|
||
PRUNE_TO_MAX(pNew.p_x, LEFT(tpThis), reasons, RC_JOG);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* path not blocked */
|
||
if((TOP(tpNext)<TOP(tpThis) || BOTTOM(tpNext)>BOTTOM(tpThis)) &&
|
||
LEFT(tpThis)<pOrg.p_x)
|
||
{
|
||
/* space is constricting, prune pNew to far
|
||
* end of this tile
|
||
*/
|
||
PRUNE_TO_MAX(pNew.p_x, LEFT(tpThis), reasons, RC_JOG);
|
||
}
|
||
else
|
||
{
|
||
/* prune pNew to just inside next tile */
|
||
PRUNE_TO_MAX(pNew.p_x, LEFT(tpThis)-1, reasons, RC_JOG);
|
||
}
|
||
}
|
||
leftEndJog:;
|
||
}
|
||
|
||
/*
|
||
* Prune pNew to next pt where there is a change in the amount of
|
||
* space on other active BLOCKAGE planes in the direction perpendicular
|
||
* to the
|
||
* extension. (A special case of this is a actual block
|
||
* of the extension). Want to consider jogs at such points.
|
||
*
|
||
*/
|
||
for(rL=mzActiveRLs; rL!=NULL; rL=rL->rl_nextActive)
|
||
{
|
||
Tile *tpNext;
|
||
TileType tpType;
|
||
bool covered;
|
||
|
||
/* skip current layer (already handled above) */
|
||
if(rL == path->rp_rLayer)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
/* get blockage plane tile under pOrg */
|
||
tpThis = TiSrPointNoHint(rL->rl_routeType.rt_vBlock,
|
||
&pOrg);
|
||
|
||
tpType = TiGetType(tpThis);
|
||
|
||
if ((tpType != TT_SPACE) && (tpType != TT_SAMENODE))
|
||
{
|
||
/* ORG POINT BLOCKED */
|
||
/* this case handled by contact code below, so skip to next layer*/
|
||
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
/* ORG POINT NOT BLOCKED, LOOK FOR NARROWING OR GROWING OF SPACE */
|
||
|
||
/* get tpThis, extending bounds plane and iterating, until
|
||
* completely covered by bounds plane.
|
||
*/
|
||
covered = FALSE;
|
||
while(!covered)
|
||
{
|
||
Tile *tpBounds;
|
||
|
||
/* get blockage plane tile under pOrg */
|
||
tpThis = TiSrPointNoHint(rL->rl_routeType.rt_vBlock,
|
||
&pOrg);
|
||
|
||
/* org point should not be blocked */
|
||
ASSERT(TiGetType(tpThis)==TT_SPACE,
|
||
"mzExtendLeft, others");
|
||
|
||
/* check to see if covered,
|
||
if not extend bounds and start over */
|
||
covered = TRUE;
|
||
tpBounds = TiSrPointNoHint(mzVBoundsPlane, &pOrg);
|
||
while(covered && RIGHT(tpBounds)>=LEFT(tpThis) &&
|
||
RIGHT(tpBounds)>=mzRouteUse->cu_def->cd_bbox.r_xbot)
|
||
{
|
||
if(TiGetType(tpBounds) == TT_SPACE)
|
||
{
|
||
/* hit edge of bounds before jog found */
|
||
goto leftNextLayer;
|
||
}
|
||
else if(TOP(tpBounds)<=TOP(tpThis) &&
|
||
TOP(tpBounds)<=mzRouteUse->cu_def->cd_bbox.r_ytop)
|
||
{
|
||
Point p;
|
||
|
||
p.p_x = MIN(RIGHT(tpBounds), pOrg.p_x);
|
||
p.p_y = TOP(tpBounds);
|
||
|
||
mzExtendBlockBounds(&p);
|
||
if(SigInterruptPending) return;
|
||
|
||
covered = FALSE;
|
||
}
|
||
else if(BOTTOM(tpBounds)>=BOTTOM(tpThis) &&
|
||
BOTTOM(tpBounds)>=
|
||
mzRouteUse->cu_def->cd_bbox.r_ybot)
|
||
{
|
||
Point p;
|
||
p.p_x = MIN(RIGHT(tpBounds), pOrg.p_x);
|
||
p.p_y = BOTTOM(tpBounds);
|
||
|
||
mzExtendBlockBounds(&p);
|
||
if(SigInterruptPending) return;
|
||
|
||
covered = FALSE;
|
||
}
|
||
|
||
/* move to next tile in bounds plane */
|
||
if(covered)
|
||
{
|
||
NEXT_TILE_LEFT(tpBounds, tpBounds, pOrg.p_y);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* get next tile over */
|
||
NEXT_TILE_LEFT(tpNext, tpThis, pOrg.p_y);
|
||
ntype = TiGetType(tpNext);
|
||
|
||
if ((ntype != TT_SPACE) && (ntype != TT_SAMENODE))
|
||
{
|
||
/* path blocked */
|
||
if(LEFT(tpThis)==pOrg.p_x)
|
||
{
|
||
/* pOrg right up against obstacle, can't extend so
|
||
go to next layer */
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
/* prune pNew to just this side of block */
|
||
PRUNE_TO_MAX(pNew.p_x,
|
||
LEFT(tpThis),
|
||
reasons,
|
||
RC_ALIGNOTHER);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* path not blocked */
|
||
if((TOP(tpNext)<TOP(tpThis) || BOTTOM(tpNext)>BOTTOM(tpThis))
|
||
&& LEFT(tpThis)<pOrg.p_x)
|
||
{
|
||
/* space is constricting, initial pNew to far
|
||
* end of this tile
|
||
*/
|
||
PRUNE_TO_MAX(pNew.p_x,
|
||
LEFT(tpThis),
|
||
reasons,
|
||
RC_ALIGNOTHER);
|
||
}
|
||
else
|
||
{
|
||
/* initial pNew to just inside next tile */
|
||
PRUNE_TO_MAX(pNew.p_x,
|
||
LEFT(tpThis)-1,
|
||
reasons,
|
||
RC_ALIGNOTHER);
|
||
}
|
||
}
|
||
}
|
||
leftNextLayer:;
|
||
}
|
||
|
||
/* Prune pNew to next alignment with a DESTINATION terminal */
|
||
{
|
||
int *xAlign = &(mzNLGetContainingInterval(&mzXAlignNL,pOrg.p_x)[0]);
|
||
if(*xAlign == pOrg.p_x)
|
||
/* On alignment mark, get previous one */
|
||
{
|
||
xAlign--;
|
||
}
|
||
PRUNE_TO_MAX(pNew.p_x, *xAlign, reasons, RC_ALIGNGOAL);
|
||
}
|
||
|
||
/* Prune pNew to alignment with perpendicular HINT edges */
|
||
{
|
||
Tile *tp;
|
||
|
||
tp = TiSrPointNoHint(mzVHintPlane, &pStep);
|
||
PRUNE_TO_MAX(pNew.p_x, LEFT(tp), reasons, RC_HINT);
|
||
}
|
||
|
||
/* Prune pNew to either side of tile edges on ROTATE plane (organized
|
||
* into maximum strips in perpendicular direction). Jogging
|
||
* at such points can effect cost.
|
||
* NOTE: Also must have intermediate path points at boundaries between
|
||
* rotate and non-rotate since edge cost different in these regions.
|
||
*/
|
||
{
|
||
Tile *tp;
|
||
|
||
tp = TiSrPointNoHint(mzVRotatePlane, &pStep);
|
||
|
||
if(RIGHT(tp)-1 < pOrg.p_x)
|
||
/* prune to beginning of tile */
|
||
PRUNE_TO_MAX(pNew.p_x, RIGHT(tp)-1, reasons, RC_ROTBEFORE);
|
||
else
|
||
/* prune to end of tile */
|
||
PRUNE_TO_MAX(pNew.p_x, LEFT(tp), reasons, RC_ROTINSIDE);
|
||
}
|
||
|
||
/* Prune to just before or just after CONTACT BLOCKS.
|
||
* These are last and first opportunites for contacts.
|
||
*/
|
||
{
|
||
List *cL;
|
||
Tile *tp;
|
||
TileType tpType;
|
||
|
||
/* Loop thru contact types connecting to current route layer */
|
||
for (cL=path->rp_rLayer->rl_contactL; cL!=NULL; cL=LIST_TAIL(cL))
|
||
{
|
||
/* find tile in contact blockage plane under pOrg */
|
||
tp = TiSrPointNoHint(
|
||
((RouteContact*) LIST_FIRST(cL))->rc_routeType.rt_hBlock,
|
||
&pStep);
|
||
tpType = TiGetType(tp);
|
||
|
||
if ((tpType == TT_SPACE) || (tpType == TT_SAMENODE))
|
||
{
|
||
/* SPACE TILE */
|
||
if(RIGHT(tp)-1 < pOrg.p_x)
|
||
/* prune to beginning of tile */
|
||
PRUNE_TO_MAX(pNew.p_x, RIGHT(tp)-1, reasons, RC_CONTACT);
|
||
else
|
||
/* prune to end of tile */
|
||
PRUNE_TO_MAX(pNew.p_x, LEFT(tp), reasons, RC_CONTACT);
|
||
}
|
||
else
|
||
{
|
||
/* BLOCK TILE - so prune to just beyond tile */
|
||
PRUNE_TO_MAX(pNew.p_x, LEFT(tp)-1, reasons, RC_CONTACT);
|
||
if (tpType == TT_BLOCKED) overroute = TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
donePruning:;
|
||
/* DONE PRUNING pNew */
|
||
|
||
/* debug - print point and reasons its interesting. */
|
||
if (DebugIsSet(mzDebugID, mzDebMaze))
|
||
{
|
||
TxPrintf("Done Pruning, new point: (%d, %d) ",
|
||
pNew.p_x, pNew.p_y);
|
||
TxPrintf("is interesting because:\n ");
|
||
if(reasons & RC_JOG)
|
||
{
|
||
TxPrintf("jog ");
|
||
}
|
||
if(reasons & RC_ALIGNOTHER)
|
||
{
|
||
TxPrintf("alignOther ");
|
||
}
|
||
if(reasons & RC_CONTACT)
|
||
{
|
||
TxPrintf("contact ");
|
||
}
|
||
if(reasons & RC_ALIGNGOAL)
|
||
{
|
||
TxPrintf("alignGoal ");
|
||
}
|
||
if(reasons & RC_HINT)
|
||
{
|
||
TxPrintf("hint ");
|
||
}
|
||
if(reasons & RC_ROTBEFORE)
|
||
{
|
||
TxPrintf("rotBefore ");
|
||
}
|
||
if(reasons & RC_ROTINSIDE)
|
||
{
|
||
TxPrintf("rotInside ");
|
||
}
|
||
if(reasons & RC_BOUNDS)
|
||
{
|
||
TxPrintf("bounds ");
|
||
}
|
||
if(reasons & RC_WALK)
|
||
{
|
||
TxPrintf("walk ");
|
||
}
|
||
if(reasons & RC_WALKLRC || reasons & RC_WALKUDC)
|
||
{
|
||
TxPrintf("walkc ");
|
||
}
|
||
if(reasons & RC_DONE)
|
||
{
|
||
TxPrintf("done ");
|
||
}
|
||
TxPrintf("\n");
|
||
}
|
||
|
||
/* Compute extend code - i.e. interesting directions to extend from
|
||
* new point */
|
||
if(reasons & (RC_WALK | RC_WALKUDC | RC_WALKLRC | RC_DONE))
|
||
{
|
||
if(reasons & RC_WALK)
|
||
{
|
||
extendCode = EC_WALKLEFT;
|
||
}
|
||
else if(reasons & RC_WALKUDC)
|
||
{
|
||
extendCode = EC_WALKUDCONTACT;
|
||
}
|
||
else if(reasons & RC_WALKLRC)
|
||
{
|
||
extendCode = EC_WALKLRCONTACT;
|
||
}
|
||
else
|
||
{
|
||
extendCode = EC_COMPLETE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
/* initial with just straight ahead */
|
||
extendCode = EC_LEFT;
|
||
|
||
if(reasons & (RC_ALIGNOTHER | RC_CONTACT | RC_ALIGNGOAL |
|
||
RC_HINT | RC_ROTINSIDE))
|
||
{
|
||
extendCode |= EC_UDCONTACTS | EC_LRCONTACTS;
|
||
}
|
||
|
||
if(reasons & (RC_JOG | RC_ALIGNGOAL | RC_HINT | RC_ROTINSIDE))
|
||
{
|
||
extendCode |= EC_UP | EC_DOWN;
|
||
}
|
||
}
|
||
|
||
/* If we end inside SAMENODE, then the cost to this point is */
|
||
/* zeroed, and that section of the path will not be painted. */
|
||
|
||
tpThis = TiSrPointNoHint(path->rp_rLayer->rl_routeType.rt_vBlock, &pNew);
|
||
if (TiGetType(tpThis) == TT_SAMENODE)
|
||
if ((!path->rp_back) || (path->rp_back->rp_cost == (dlong)0))
|
||
path->rp_cost = (dlong)0;
|
||
|
||
/* compute cost of path segment from pOrg to pNew */
|
||
{
|
||
Tile *tp;
|
||
bool rotate;
|
||
|
||
tp = TiSrPointNoHint(mzVRotatePlane, &pOrg);
|
||
rotate = (TiGetType(tp) != TT_SPACE);
|
||
|
||
if (rotate)
|
||
segCost = (dlong) ((pOrg.p_x - pNew.p_x) *
|
||
path->rp_rLayer->rl_vCost);
|
||
else if (overroute)
|
||
segCost = (dlong) ((pOrg.p_x - pNew.p_x) *
|
||
path->rp_rLayer->rl_overCost);
|
||
else
|
||
segCost = (dlong) ((pOrg.p_x - pNew.p_x) *
|
||
path->rp_rLayer->rl_hCost);
|
||
}
|
||
|
||
/* Compute additional cost for paralleling nearest hint segment */
|
||
/* (Start at low end of segment and move to high end computing hint cost
|
||
* as we go)
|
||
*/
|
||
{
|
||
Tile *tp;
|
||
dlong hintCost;
|
||
int deltaUp, deltaDown, delta;
|
||
Point lowPt;
|
||
|
||
for(lowPt = pNew; lowPt.p_x < pOrg.p_x; lowPt.p_x = RIGHT(tp))
|
||
{
|
||
/* find tile in hint plane containing lowPt */
|
||
tp = TiSrPointNoHint(mzVHintPlane,&lowPt);
|
||
|
||
/* find nearest hint segment and add appropriate cost */
|
||
if(TiGetType(tp) != TT_MAGNET)
|
||
{
|
||
deltaUp = (TiGetType(RT(tp)) == TT_MAGNET) ?
|
||
TOP(tp) - lowPt.p_y : -1;
|
||
deltaDown = (TiGetType(LB(tp)) == TT_MAGNET) ?
|
||
lowPt.p_y - BOTTOM(tp) : -1;
|
||
|
||
/* delta = distance to nearest hint */
|
||
if (deltaUp < 0)
|
||
{
|
||
if (deltaDown < 0)
|
||
delta = 0;
|
||
else
|
||
delta = deltaDown;
|
||
}
|
||
else
|
||
{
|
||
if (deltaDown < 0)
|
||
delta = deltaUp;
|
||
else
|
||
delta = MIN(deltaUp,deltaDown);
|
||
}
|
||
|
||
if(delta>0)
|
||
{
|
||
hintCost = (dlong) ((MIN(RIGHT(tp),pOrg.p_x) - lowPt.p_x) *
|
||
path->rp_rLayer->rl_hintCost);
|
||
hintCost *= delta;
|
||
segCost += hintCost;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Process the new point */
|
||
mzAddPoint(path, &pNew, path->rp_rLayer, 'H', extendCode, &segCost);
|
||
|
||
return;
|
||
}
|