/* * mzExtendDown.c -- * * Code for finding next interesting point down. * * ********************************************************************* * * 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/mzXtndDown.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" /* * ---------------------------------------------------------------------------- * * mzExtendDown -- * * Find next interesting point down. * * Results: * None. * * Side effects: * mzAddPoint() called to added extended path to appropriate queue. * * ---------------------------------------------------------------------------- */ void mzExtendDown(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 DOWN\n"); /* pOrg = current end of path */ pOrg = path->rp_entry; /* pStep = point just one unit beyond pOrg */ pStep = pOrg; --(pStep.p_y); /* 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(mzVBoundsPlane, &pOrg); pNew.p_x = pOrg.p_x; pNew.p_y = BOTTOM(tp); 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 a 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_hBlock, &pOrg); /* org point should not be blocked */ ASSERT(TiGetType(tpThis) == TT_SPACE, "mzExtendDown"); /* check to see if covered, if not extend bounds and start over */ covered = TRUE; tpBounds = TiSrPointNoHint(mzHBoundsPlane, &pOrg); while(covered && TOP(tpBounds)>=BOTTOM(tpThis) && TOP(tpBounds)>=mzRouteUse->cu_def->cd_bbox.r_ybot) { if(TiGetType(tpBounds) == TT_SPACE) { /* hit edge of bounds before jog found */ goto downEndJog; } else if(RIGHT(tpBounds)<=RIGHT(tpThis) && RIGHT(tpBounds)<=mzRouteUse->cu_def->cd_bbox.r_xtop) { Point p; p.p_x = RIGHT(tpBounds); p.p_y = MIN(TOP(tpBounds), pOrg.p_y); mzExtendBlockBounds(&p); if(SigInterruptPending) return; covered = FALSE; } else if(LEFT(tpBounds)>=LEFT(tpThis) && LEFT(tpBounds)>=mzRouteUse->cu_def->cd_bbox.r_xbot) { Point p; p.p_x = LEFT(tpBounds); p.p_y = MIN(TOP(tpBounds), pOrg.p_y); mzExtendBlockBounds(&p); if(SigInterruptPending) return; covered = FALSE; } /* move to next tile in bounds plane */ if(covered) { NEXT_TILE_DOWN(tpBounds, tpBounds, pOrg.p_x); } } } /* also get next tile over */ NEXT_TILE_DOWN(tpNext, tpThis, pOrg.p_x); ntype = TiGetType(tpNext); if ((ntype != TT_SPACE) && (ntype != TT_SAMENODE)) { /* path blocked */ if(BOTTOM(tpThis)==pOrg.p_y) { /* pOrg right up against block */ if(ntype==TT_TOP_WALK) { /* Block is walk, enter it */ pNew.p_y = pOrg.p_y - 1; reasons = RC_WALK; goto donePruning; } else if (ntype == TT_ABOVE_UD_WALK || ntype == TT_BELOW_UD_WALK) { /* Block is contact walk, enter it */ pNew.p_y = pOrg.p_y - 1; reasons = RC_WALKUDC; goto donePruning; } else if (ntype == TT_ABOVE_LR_WALK || ntype == TT_BELOW_LR_WALK) { /* Block is contact walk, enter it */ pNew.p_y = pOrg.p_y - 1; reasons = RC_WALKLRC; goto donePruning; } else if (ntype == TT_DEST_AREA) { /* Block is destination, enter it */ pNew.p_y = pOrg.p_y - 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_y, BOTTOM(tpThis), reasons, RC_JOG); } } else { /* path not blocked */ if((RIGHT(tpNext)LEFT(tpThis)) && BOTTOM(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_hBlock, &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_hBlock, &pOrg); /* org point should not be blocked */ ASSERT(TiGetType(tpThis)==TT_SPACE,"mzExtendDown, other"); /* check to see if covered, if not extend bounds and start over */ covered = TRUE; tpBounds = TiSrPointNoHint(mzHBoundsPlane, &pOrg); while(covered && TOP(tpBounds)>=BOTTOM(tpThis) && TOP(tpBounds)>=mzRouteUse->cu_def->cd_bbox.r_ybot) { if(TiGetType(tpBounds) == TT_SPACE) { /* hit edge of bounds before jog found */ goto downNextLayer; } else if(RIGHT(tpBounds)<=RIGHT(tpThis) && RIGHT(tpBounds)<= mzRouteUse->cu_def->cd_bbox.r_xtop) { Point p; p.p_x = RIGHT(tpBounds); p.p_y = MIN(TOP(tpBounds), pOrg.p_y); mzExtendBlockBounds(&p); if(SigInterruptPending) return; covered = FALSE; } else if(LEFT(tpBounds)>=LEFT(tpThis) && LEFT(tpBounds)>=mzRouteUse->cu_def->cd_bbox.r_xbot) { Point p; p.p_x = LEFT(tpBounds); p.p_y = MIN(TOP(tpBounds), pOrg.p_y); mzExtendBlockBounds(&p); if(SigInterruptPending) return; covered = FALSE; } /* move to next tile in bounds plane */ if(covered) { NEXT_TILE_DOWN(tpBounds, tpBounds, pOrg.p_x); } } } /* get next tile over */ NEXT_TILE_DOWN(tpNext, tpThis, pOrg.p_x); ntype = TiGetType(tpNext); if ((ntype != TT_SPACE) && (ntype != TT_SAMENODE)) { /* path blocked */ if(BOTTOM(tpThis)==pOrg.p_y) { /* 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_y, BOTTOM(tpThis), reasons, RC_ALIGNOTHER); } } else { /* path not blocked */ if((RIGHT(tpNext)LEFT(tpThis)) && BOTTOM(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(TOP(tp)-1 < pOrg.p_y) /* prune to beginning of tile */ PRUNE_TO_MAX(pNew.p_y, TOP(tp)-1, reasons, RC_CONTACT); else /* prune to end of tile */ PRUNE_TO_MAX(pNew.p_y, BOTTOM(tp), reasons, RC_CONTACT); } else { /* BLOCK TILE - so prune to just beyond tile */ PRUNE_TO_MAX(pNew.p_y, BOTTOM(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_WALKLRC | RC_WALKUDC | RC_DONE)) { if(reasons & RC_WALK) { extendCode = EC_WALKDOWN; } 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_DOWN; 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_RIGHT | EC_LEFT; } } /* If we end inside SAMENODE, then the cost at this point is */ /* set to zero, if we are at the start or if the previous cost was */ /* zero. */ tpThis = TiSrPointNoHint(path->rp_rLayer->rl_routeType.rt_hBlock, &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(mzHRotatePlane, &pOrg); rotate = (TiGetType(tp) != TT_SPACE); if (rotate) segCost = (dlong) ((pOrg.p_y - pNew.p_y) * path->rp_rLayer->rl_hCost); else if (overroute) segCost = (dlong) ((pOrg.p_y - pNew.p_y) * path->rp_rLayer->rl_overCost); else segCost = (dlong) ((pOrg.p_y - pNew.p_y) * path->rp_rLayer->rl_vCost); } /* 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 deltaRight, deltaLeft, delta; Point lowPt; for(lowPt = pNew; lowPt.p_y < pOrg.p_y; lowPt.p_y = TOP(tp)) { /* find tile in hint plane containing lowPt */ tp = TiSrPointNoHint(mzHHintPlane,&lowPt); /* find nearest hint segment and add appropriate cost */ if(TiGetType(tp) != TT_MAGNET) { deltaRight = (TiGetType(TR(tp)) == TT_MAGNET) ? RIGHT(tp) - lowPt.p_x : -1; deltaLeft = (TiGetType(BL(tp)) == TT_MAGNET) ? lowPt.p_x - LEFT(tp) : -1; /* delta = distance to nearest hint */ if (deltaRight < 0) { if (deltaLeft < 0) delta = 0; else delta = deltaLeft; } else { if (deltaLeft < 0) delta = deltaRight; else delta = MIN(deltaRight,deltaLeft); } if(delta>0) { hintCost = (dlong) ((MIN(TOP(tp),pOrg.p_y) - lowPt.p_y) * path->rp_rLayer->rl_hintCost); hintCost = (dlong)(hintCost * delta); segCost += hintCost; } } } } /* Process the new point */ mzAddPoint(path, &pNew, path->rp_rLayer, 'V', extendCode, &segCost); return; }