/* * 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 #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)BOTTOM(tpThis)) && LEFT(tpThis)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)BOTTOM(tpThis)) && LEFT(tpThis)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; }