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;
|
|
}
|