/* * mzMain.c -- * * Global Data Definitions and interface procedures for the Maze Router. * * OTHER ENTRY POINTS (not in this file): * Technology readin - mzTech.c * Initialization (after tech readin) - mzInit.c * Test command interface - TestCmd.c * * ********************************************************************* * * 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[] = "$Header: /ufs/repository/magic/mzrouter/mzMain.c,v 1.2 2001/01/12 22:13:02 jsolomon Exp $"; #endif not lint /*--- includes --- */ #include #include "misc/magic.h" #include "utils/geometry.h" #include "tiles/tile.h" #include "utils/hash.h" #include "database/database.h" #include "drc/drc.h" #include "select/select.h" #include "signals/signals.h" #include "textio/textio.h" #include "windows/windows.h" #include "dbwind/dbwind.h" #include "misc/styles.h" #include "debug/debug.h" #include "undo/undo.h" #include "textio/txcommands.h" #include "utils/malloc.h" #include "main/main.h" #include "utils/geofast.h" #include "../utils/list.h" #include "utils/doubleint.h" #include "utils/heap.h" #include "utils/touchingtypes.h" #include "mzrouter/mzrouter.h" #include "mzrouter/mzInternal.h" /*---- Global Data Definitions ----*/ /* (Actual storage for static global structures for maze router defined here)*/ /* Debug flags */ ClientData mzDebugID; int mzDebMaze; /* identify flags to debug module */ int mzDebStep; /* parameter sets - from tech file */ MazeStyle *mzStyles; /* Toplevel cell visible to the router */ CellUse *mzRouteUse; /* Route types */ /* (Specifies what types are permitted during routing, and related design * rules.) */ RouteType *mzRouteTypes; RouteType *mzActiveRTs; /* Only route types that are turned on */ RouteLayer *mzRouteLayers; RouteLayer *mzActiveRLs; /* Only route layers that are turned on */ RouteContact *mzRouteContacts; /* Routing is confined to this rectangle */ Rect mzBoundingRect; /* Expansion mask - defines which subcells to treat as expanded */ int mzCellExpansionMask; /* If reset, degenerate estimation plane used (just 4 tiles - one for each * quadrant with respect to destination point). */ int mzEstimate; /* If set dest areas are expanded to include all electrically * connected geometry. */ int mzExpandDests; /* If set only hints in toplevel cell are recognized */ int mzTopHintsOnly; /* Maximum distance route will extend into blocked area to connect to dest. * terminal. If set to -1, a max value is computed as a function of the * design rules for the active route types prior to each route. */ int mzMaxWalkLength; /* if nonnull, limits area of search for performance. * (NOTE: USER MUST LIMIT ROUTE TO THIS AREA WITH FENCES - OTHERWISE * RESULT IS UNPREDICTABLE). */ Rect *mzBoundsHint; /* how many messages to print */ int mzVerbosity; /* if positive, upper bound on number of blooms */ int mzBloomLimit; /* maskdata tiles, and unexpanded subcells, marked because they are part of * dest. nodes. */ List *mzMarkedTilesList; List *mzMarkedCellsList; /* start terminals */ List *mzStartTerms; /* internal cell for dest areas */ CellDef *mzDestAreasDef = (CellDef *) NULL; CellUse *mzDestAreasUse = (CellUse *) NULL; /* Fence parity */ bool mzInsideFence; /* largest design rule distance - used during incremental blockage gen. */ int mzContextRadius; /* Internal cell for completed route */ CellDef *mzResultDef = (CellDef *) NULL; CellUse *mzResultUse = (CellUse *) NULL; /* HINT PLANES */ TileTypeBitMask mzHintTypesMask; Plane *mzHHintPlane; Plane *mzVHintPlane; /* FENCE PLANE */ TileTypeBitMask mzFenceTypesMask; Plane *mzHFencePlane; /* ROTATE PLANES */ TileTypeBitMask mzRotateTypesMask; Plane *mzHRotatePlane; Plane *mzVRotatePlane; /* BOUNDS PLANES */ PaintResultType mzBoundsPaintTbl[TT_MAXTYPES][TT_MAXTYPES]; Plane *mzHBoundsPlane; Plane *mzVBoundsPlane; /* BLOCKAGE PLANES */ PaintResultType mzBlockPaintTbl[TT_MAXTYPES][TT_MAXTYPES]; /* ESTIMATE PLANE */ PaintResultType mzEstimatePaintTbl[TT_MAXTYPES][TT_MAXTYPES]; Plane *mzEstimatePlane; /* dest terminal alignment coordinates */ NumberLine mzXAlignNL; NumberLine mzYAlignNL; /* minimum radius of blockage plane info required around point being expanded. * (Areas twice this size are gened. whenever the minimum is not met.) */ int mzBoundsIncrement; /* minimum estimated total cost for initial path */ DoubleInt mzMinInitialCost; /* where current path came from */ int mzPathSource; /* Parameters controlling search */ RouteFloat mzPenalty; DoubleInt mzWRate; DoubleInt mzBloomDeltaCost; DoubleInt mzWWidth; /* Statistics */ DoubleInt mzInitialEstimate; /* Initial estimated cost of route */ int mzNumBlooms; int mzNumOutsideBlooms; /* num blooms from outside window */ int mzNumComplete; /* number of complete paths so far */ int mzBlockGenCalls; /* # of calls to blockage gen. code */ double mzBlockGenArea; /* area over which blockage planes have been gened. */ int mzNumPathsGened; /* number of partial paths added to heap */ int mzNumPaths; /* number of paths processed */ int mzReportInterval; /* frequency that # of paths etc. * is reported. */ int mzPathsTilReport; /* counts down to next path report */ /* Variables controling search */ DoubleInt mzWInitialMinToGo; DoubleInt mzWInitialMaxToGo; DoubleInt mzBloomMaxCost; /* Search status */ DoubleInt mzWindowMinToGo; /* Window location */ DoubleInt mzWindowMaxToGo; /* Hash table to avoid repeated expansion from same point during search */ HashTable mzPointHash; /* Queues for partial paths */ Heap mzMaxToGoHeap; /* paths nearer destination than WINDOW */ Heap mzMinCostHeap; /* paths in WINDOW */ Heap mzMinAdjCostHeap; /* paths farther from dest than WINDOW*/ List *mzBloomStack; /* paths in current local focus */ List *mzStraightStack; /* focus paths expanded in a straight line */ List *mzDownHillStack; /* focus paths expanded as long as * estimated total cost doesn't increase. */ List *mzWalkStack; /* paths in walks, i.e. blocks adjacent * to dest areas. */ Heap mzMinCostCompleteHeap; /* completed paths */ /*----------- static data - referenced only in this file ------------------- */ /* set when storage that needs to be reclaimed has been allocated by router */ bool mzDirty = FALSE; /* set when path queues and hast table have been allocated */ bool mzPathsDirty = FALSE; /* macro for adding address pairs to translation table */ #define AT_EQUIV(a1,a2) \ if(TRUE) \ { \ HashSetValue(HashFind(&aT, (ClientData) (a1)), (ClientData) (a2)); \ HashSetValue(HashFind(&aT, (ClientData) (a2)), (ClientData) (a1)); \ } else /* macro for translating address to address paired with it in address table */ #define AT(type,a) \ if (TRUE) \ { \ HashEntry *he = HashLookOnly(&aT, (ClientData) (a)); \ if(he) \ { \ a = (type) HashGetValue(he); \ } \ } else /* * ---------------------------------------------------------------------------- * * MZCopyParms -- * * Allocate and setup duplicate maze parameters with same values. * (Duplicates substructures as well) * * Results: * Pointer to new parameters. * * Side effects: * See above. * * ---------------------------------------------------------------------------- */ MazeParameters * MZCopyParms(oldParms) MazeParameters *oldParms; /* Maze routing parameters */ { MazeParameters *newParms; HashTable aT; /* Address translation hash table */ /* If passed NULL parms, just return NULL */ if(oldParms==NULL) { return NULL; } /* Initialize address translation table */ HashInit(&aT, 1000, HT_WORDKEYS); /* allocate new structure and copy MazeParameters */ { MALLOC(MazeParameters *, newParms, sizeof(MazeParameters)); *newParms = *oldParms; } /* Copy RouteLayers (and sub-structures) */ { RouteLayer *rLOld; for(rLOld = oldParms->mp_rLayers; rLOld != NULL; rLOld = rLOld->rl_next) { RouteLayer *rLNew; /* allocate and equivalence new rL and its rT */ { MALLOC(RouteLayer *, rLNew, sizeof(RouteLayer)); AT_EQUIV(rLOld, rLNew); AT_EQUIV(&(rLOld->rl_routeType),&(rLNew->rl_routeType)); } /* copy the rL */ *rLNew = *rLOld; /* make a copy of the routeLayer contact list */ LIST_COPY(rLOld->rl_contactL, rLNew->rl_contactL); /* allocate new blockage planes */ rLNew->rl_routeType.rt_hBlock = DBNewPlane((ClientData) TT_SPACE); rLNew->rl_routeType.rt_vBlock = DBNewPlane((ClientData) TT_SPACE); } } /* Copy RouteContacts (and sub-structures) */ { RouteContact *rCOld; for(rCOld = oldParms->mp_rContacts; rCOld != NULL; rCOld = rCOld->rc_next) { RouteContact *rCNew; /* allocate and equivalence new rC and its rT */ { MALLOC(RouteContact *, rCNew, sizeof(RouteContact)); AT_EQUIV(rCOld, rCNew); AT_EQUIV(&(rCOld->rc_routeType),&(rCNew->rc_routeType)); } /* copy the rC */ *rCNew = *rCOld; /* allocate new blockage planes */ rCNew->rc_routeType.rt_hBlock = DBNewPlane((ClientData) TT_SPACE); rCNew->rc_routeType.rt_vBlock = DBNewPlane((ClientData) TT_SPACE); } } /* Translate addresses in MazeParameters */ AT(RouteLayer *, newParms->mp_rLayers); AT(RouteContact *, newParms->mp_rContacts); AT(RouteType *, newParms->mp_rTypes); /* Translate addresses in RouteLayers (and sub-structures) */ { RouteLayer *rLOld; for(rLOld = oldParms->mp_rLayers; rLOld != NULL; rLOld = rLOld->rl_next) { RouteLayer *rLNew = rLOld; AT(RouteLayer *, rLNew); AT(RouteLayer *, rLNew->rl_next); AT(RouteType *, rLNew->rl_routeType.rt_next); /* translate RouteContact addresses in contact list */ { List *l; for(l = rLNew->rl_contactL; l!=NULL; l=LIST_TAIL(l)) { AT(ClientData, LIST_FIRST(l)); } } } } /* Translate addresses in RouteContacts (and sub-structures) */ { RouteContact *rCOld; for(rCOld = oldParms->mp_rContacts; rCOld != NULL; rCOld = rCOld->rc_next) { RouteContact *rCNew =rCOld; AT(RouteContact *, rCNew); AT(RouteLayer *, rCNew->rc_rLayer1); AT(RouteLayer *, rCNew->rc_rLayer2); AT(RouteContact *, rCNew->rc_next); AT(RouteType *, rCNew->rc_routeType.rt_next); } } HashKill(&aT); return newParms; } /* * ---------------------------------------------------------------------------- * * MZFindStyle -- * * Find style of given name. * * Results: * Pointer to maze parameters for given style, or NULL if not found. * * Side effects: * None. * * ---------------------------------------------------------------------------- */ MazeParameters * MZFindStyle(name) char *name; /* name of style we are looking for */ { MazeStyle *style = mzStyles; while(style!=NULL && strcmp(name,style->ms_name)!=0) { style = style->ms_next; } if(style==NULL) { return NULL; } else { return &(style->ms_parms); } } /* * ---------------------------------------------------------------------------- * * MZInitRoute -- * * * Set up datastructures for maze route, and initialize per/route statistics * * Results: * None. * * Side effects: * See above. * * NOTE: RouteUse supplied as parm to MZInitRoute is toplevel cell visible * to router. However resulting route is painted to current edit cell. * * ---------------------------------------------------------------------------- */ Void MZInitRoute(parms, routeUse, expansionMask) MazeParameters *parms; /* Maze routing parameters */ CellUse *routeUse; /* toplevel cell router sees */ int expansionMask; /* which subcells are expanded - NOTE: the * maze router interpets a 0 mask to mean * all cells are expanded */ { /* Disable undo to avoid overhead on paint operations to internal planes */ UndoDisable(); /* Clean up after last route - if necessary */ if(mzDirty) { MZClean(); } /* Set dirty flag - since we are about to alloc storage for this route */ mzDirty = TRUE; /* initial source of paths is initialization routine */ mzPathSource = SOURCE_INIT; /* initial estimated cost is infinity */ mzMinInitialCost = DIMaxInt; /* initialize per-route statistics */ mzBlockGenCalls = 0; mzBlockGenArea = 0.0; mzNumComplete = 0; mzNumPathsGened = 0; mzNumPaths = 0; mzNumBlooms = 0; mzNumOutsideBlooms = 0; mzPathsTilReport = mzReportInterval; /* Make supplied parms current */ { mzRouteLayers = parms->mp_rLayers; mzRouteContacts = parms->mp_rContacts; mzRouteTypes = parms->mp_rTypes; mzPenalty = parms->mp_penalty; mzWWidth = parms->mp_wWidth; mzWRate = parms->mp_wRate; mzBloomDeltaCost = parms->mp_bloomDeltaCost; mzBoundsIncrement = parms->mp_boundsIncrement; mzEstimate = parms->mp_estimate; mzExpandDests = parms->mp_expandDests; mzTopHintsOnly = parms->mp_topHintsOnly; mzMaxWalkLength = parms->mp_maxWalkLength; mzBoundsHint = parms->mp_boundsHint; mzVerbosity = parms->mp_verbosity; mzBloomLimit = parms->mp_bloomLimit; } /* Some parms are computed from the supplied ones */ mzComputeDerivedParms(); /* set route cell (toplevel cell visible during routing */ mzRouteUse = routeUse; /* set expansion mask */ mzCellExpansionMask = expansionMask; /* Build hint fence and rotate planes */ mzBuildHFR(mzRouteUse, &mzBoundingRect); /* Initialize Blockage Planes */ { RouteType *rT; /* Clear bounds planes = regions for which blockage has been generated */ DBClearPaintPlane(mzHBoundsPlane); DBClearPaintPlane(mzVBoundsPlane); /* Clear blockage planes */ for (rT=mzRouteTypes; rT!=NULL; rT=rT->rt_next) { DBClearPaintPlane(rT->rt_hBlock); DBClearPaintPlane(rT->rt_vBlock); } } /* Initialize Dest Area Cell */ DBCellClearDef(mzDestAreasUse->cu_def); /* take our hold off undo */ UndoEnable(); return; } /* * ---------------------------------------------------------------------------- * * MZAddStart -- * * Add a starting terminal for the maze router. * * Results: * None. * * Side effects: * Builds mzStartTerms list. * * ---------------------------------------------------------------------------- */ Void MZAddStart(point, type) Point *point; TileType type; { /* Disable undo to avoid overhead on paint operations to internal planes */ UndoDisable(); /* check fence parity */ if(mzStartTerms == NULL) { /* This is first start terminal, set fence parity by it, i.e. * whether route is inside or outside of fence */ Tile *tFencePlane = TiSrPointNoHint(mzHFencePlane, point); mzInsideFence = (TiGetType(tFencePlane) != TT_SPACE); /* If inside fence, clip mzBounds to fence bounding box * to save processing. */ if(mzInsideFence) { Rect r; DBBoundPlane(mzHFencePlane, &r); r.r_xbot -= 2*mzContextRadius; r.r_ybot -= 2*mzContextRadius; r.r_xtop += 2*mzContextRadius; r.r_ytop += 2*mzContextRadius; GEOCLIP(&mzBoundingRect, &r); } } else { /* not first start terminal, check for consistency with respect * to fence parity. */ Tile *tFencePlane = TiSrPointNoHint(mzHFencePlane, point); int newInside = (TiGetType(tFencePlane) != TT_SPACE); if(newInside != mzInsideFence) { TxPrintf("Start points on both sides of fence. "); TxPrintf("Arbitrarily choosing those %s fence.\n", (mzInsideFence ? "inside" : "outside")); return; } } /* mark tiles connected to start point */ { Rect rect; /* build degenerate rect containing point to initiate the * marking process; */ rect.r_ll = *point; rect.r_ur = *point; mzMarkConnectedTiles(&rect, type, FALSE /* Don't make connected tiles dest areas! */ ); } /* add point to start terminal list */ { ColoredPoint *newTerm; MALLOC(ColoredPoint *, newTerm, sizeof(ColoredPoint)); newTerm->cp_point = *point; newTerm->cp_type = type; LIST_ADD(newTerm, mzStartTerms); } /* Take our hold of undo */ UndoEnable(); /* and return */ return; } /* * ---------------------------------------------------------------------------- * * MZAddDest -- * * Add a destination terminal. * * Results: * none. * * Side effects: * Paints dest area into mzDestAreasDef. * * Marks mask data tiles connected to supplied dest area (rect and type * passed to this func), also keeps list of marked tiles for cleanup. * * Tiles are marked with TRUE on the clientdata field. The default * clientdata value of MINFINITY should be restored by the router * before it returns. * * ---------------------------------------------------------------------------- */ Void MZAddDest(rect, type) Rect *rect; TileType type; { ColoredRect *dTerm; UndoDisable(); /* Paint dest area into mzDestAreas cell */ { DBPaint(mzDestAreasUse->cu_def, rect, type); } /* Mark all tiles connected to dest terminal. */ mzMarkConnectedTiles(rect, type, mzExpandDests /* if set, make connected tiles dest * areas. */ ); UndoEnable(); return; } /* * ---------------------------------------------------------------------------- * * MZRoute -- * * Do the route. * * Results: * Zero-width route path. NOTE: route path is allocated from temporary * storage that will be reused for next route. * * Side effects: * * * ---------------------------------------------------------------------------- */ RoutePath * MZRoute() { RoutePath *path; /* handle for result of search */ /* Disable undo to avoid overhead on paint operations to internal planes */ UndoDisable(); /* Clear result cell */ DBCellClearDef(mzResultDef); /* Generate dest areas and walks in blockage planes. * (also adds alignment coords for dest areas to alignment structs.) */ mzBuildDestAreaBlocks(); /* Check that there is an unblocked destination */ if(mzXAlignNL.nl_sizeUsed==2) /* No alignment marks, so no destination areas */ { TxPrintf("No reachable destination area!\n"); goto abort; } /* Build Estimate Plane. * (allowing for end points in unexpanded subcells) */ mzBuildEstimate(mzStartTerms); if (SigInterruptPending) goto abort; /* allocating queues and hashtable so set dirty flag */ mzPathsDirty = TRUE; /* * Initialize queues (actually heaps and lists) for partial paths * Double Precision Integer keys used in cost keyed heaps * to avoid overflow. */ HeapInitType(&mzMaxToGoHeap, INITHEAPSIZE, TRUE, FALSE, HE_DINT); HeapInitType(&mzMinCostHeap, INITHEAPSIZE, FALSE, FALSE, HE_DINT); HeapInitType(&mzMinAdjCostHeap, INITHEAPSIZE, FALSE, FALSE, HE_DINT); HeapInitType(&mzMinCostCompleteHeap, INITHEAPSIZE, FALSE, FALSE, HE_DINT); mzBloomStack = NULL; mzStraightStack = NULL; mzDownHillStack = NULL; mzWalkStack = NULL; /* * A hash table is used to hold all points reached, * so we can avoid redundant expansion. */ HashInit(&mzPointHash, INITHASHSIZE, HashSize(sizeof (PointKey))); /* Build blockage planes at start points and create initial * partial paths */ { List *terms; /* set bloom threshold to zero, so that initial points are placed * on Max ToGo heap. */ mzBloomMaxCost = DIZero; for(terms=mzStartTerms; terms!=NULL; terms=LIST_TAIL(terms)) { ColoredPoint *term = (ColoredPoint *) LIST_FIRST(terms); /* Build blockage planes around start point */ mzExtendBlockBounds(&(term->cp_point)); /* Generate initial paths for start point */ mzStart(term); } } /* initialize search window */ { List *terms; /* estimated total cost is min estimated cost for initial paths */ mzInitialEstimate = mzMinInitialCost; mzWInitialMinToGo = mzInitialEstimate; DOUBLE_ADD(mzWInitialMaxToGo, mzWInitialMinToGo, mzWWidth); } /* Make sure we got here without interruption */ if (SigInterruptPending) goto abort; /* Do the route */ path = mzSearch(); /* On interruption mzSearch returns best complete path * found prior to interruption */ UndoEnable(); return path; abort: UndoEnable(); return NULL; } /* * ---------------------------------------------------------------------------- * * MZPaintPath -- * * Given a RoutePath constructed by mzRoute, convert it to paint. * The input RoutePath specifies a sequence of points completely, so * each leg can be painted as we go. * * Results: * Pointer to result cell containing painted path. * * Side effects: * Paints into result cell. * * ---------------------------------------------------------------------------- */ CellUse * MZPaintPath(pathList) RoutePath *pathList; { register RoutePath *path, *prev; /* * Each segment of the path contains no bends, so is * either horizontal, vertical, or a contact. */ for (path = pathList; (prev = path->rp_back)!= NULL && !SigInterruptPending; path = prev) { RouteLayer *rL; Rect r; int t; /* * Special handling for a contact if different planes. * In this case, no x- or y- motion is allowed. */ if (path->rp_rLayer != prev->rp_rLayer) { ASSERT(path->rp_entry.p_x == prev->rp_entry.p_x, "MZPaintPath"); ASSERT(path->rp_entry.p_y == prev->rp_entry.p_y, "MZPaintPath"); mzPaintContact(path, prev); continue; } /* * Leg on the same plane. * Generate a box between the start and end points * with the width specified for this layer. * Flip the rectangle as necessary to ensure that * LL <= UR. */ r.r_ll = path->rp_entry; r.r_ur = prev->rp_entry; if (r.r_xbot > r.r_xtop) t = r.r_xbot, r.r_xbot = r.r_xtop, r.r_xtop = t; if (r.r_ybot > r.r_ytop) t = r.r_ybot, r.r_ybot = r.r_ytop, r.r_ytop = t; r.r_xtop += path->rp_rLayer->rl_routeType.rt_width; r.r_ytop += path->rp_rLayer->rl_routeType.rt_width; rL = path->rp_rLayer; DBPaintPlane(mzResultDef->cd_planes[rL->rl_planeNum], &r, DBStdPaintTbl(rL->rl_routeType.rt_tileType,rL->rl_planeNum), (PaintUndoInfo *) NULL); } /* Update bounding box of result cell */ DBReComputeBbox(mzResultDef); /* return pointer to result cell use */ return mzResultUse; } /* * ---------------------------------------------------------------------------- * * MZClean -- * * Reclaim storage space gobbled up during route, and reset tile client * fields. After a MZInitRoute() has been issued, MZClean() should always * be called prior to returning from Magic command. * * Results: * None * * Side effects: * See above. * * ---------------------------------------------------------------------------- */ Void MZClean() { if(mzDirty) { /* clear estimate plane */ mzCleanEstimate(); /* Reclaim storage and reset mzStartList */ { ListDeallocC(mzStartTerms); mzStartTerms = NULL; } /* Reset dest alignment structures */ mzNLClear(&mzXAlignNL); mzNLClear(&mzYAlignNL); /* Unmark marked tiles, and cells and dealloc marked lists */ { List *l; /* Reset Marked tiles client fields to MINFINITY */ for(l=mzMarkedTilesList; l!=NULL; l=LIST_TAIL(l)) { Tile *tile = (Tile *) LIST_FIRST(l); /* Restore tile client field to its "unmarked" value */ tile->ti_client = (ClientData) MINFINITY; } /* Dealloc list of marked tiles */ ListDealloc(mzMarkedTilesList); mzMarkedTilesList = NULL; /* Reset Marked subcell client fields to MINFINITY */ for(l=mzMarkedCellsList; l!=NULL; l=LIST_TAIL(l)) { CellUse *cu = (CellUse *) LIST_FIRST(l); /* Restore celluse client field to its "unmarked" value */ cu->cu_client = (ClientData) MINFINITY; } /* Dealloc list of marked cells */ ListDealloc(mzMarkedCellsList); mzMarkedCellsList = NULL; } /* Free up route-path queues */ if(mzPathsDirty) { HeapKill(&mzMaxToGoHeap, (void (*)()) NULL); HeapKill(&mzMinCostHeap, (void (*)()) NULL); HeapKill(&mzMinAdjCostHeap, (void (*)()) NULL); HeapKill(&mzMinCostCompleteHeap, (void (*)()) NULL); ListDealloc(mzBloomStack); ListDealloc(mzStraightStack); ListDealloc(mzDownHillStack); ListDealloc(mzWalkStack); /* Free up hash table */ HashKill(&mzPointHash); /* Reclaims route path entries */ mzFreeAllRPaths(); /* reset flag */ mzPathsDirty = FALSE; } /* reset flag */ mzDirty = FALSE; } return; }