mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-09-06 09:06:54 +02:00
Added a ARG_UNUSED macro in utils/magic.h, which produces a simple cast to void to silence the warnings. The reasons this is used as opposed to an attribute is that most compilers should support this. Besides this, the macro can be easily searched for in the future to potentially remove (where possible) the unused parameters.
1319 lines
35 KiB
C
1319 lines
35 KiB
C
/*
|
|
* 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[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/mzrouter/mzMain.c,v 1.3 2010/06/24 12:37:19 tim Exp $";
|
|
#endif /* not lint */
|
|
|
|
/*--- includes --- */
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "utils/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 "utils/signals.h"
|
|
#include "textio/textio.h"
|
|
#include "windows/windows.h"
|
|
#include "dbwind/dbwind.h"
|
|
#include "utils/styles.h"
|
|
#include "debug/debug.h"
|
|
#include "utils/undo.h"
|
|
#include "textio/txcommands.h"
|
|
#include "utils/malloc.h"
|
|
#include "utils/main.h"
|
|
#include "utils/geofast.h"
|
|
#include "../utils/list.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 = NULL;
|
|
|
|
/* 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 mzExpandEndpoints;
|
|
/* 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 unexpanded subcells, marked because they are part of
|
|
* dest. nodes. */
|
|
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_MAXROUTETYPES][TT_MAXROUTETYPES];
|
|
Plane *mzHBoundsPlane;
|
|
Plane *mzVBoundsPlane;
|
|
|
|
/* BLOCKAGE PLANES */
|
|
TileTypeBitMask mzStartTypesMask;
|
|
PaintResultType mzBlockPaintTbl[TT_MAXROUTETYPES][TT_MAXROUTETYPES];
|
|
|
|
/* ESTIMATE PLANE */
|
|
PaintResultType mzEstimatePaintTbl[TT_MAXROUTETYPES][TT_MAXROUTETYPES];
|
|
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 */
|
|
dlong mzMinInitialCost;
|
|
|
|
/* where current path came from */
|
|
int mzPathSource;
|
|
|
|
/* Parameters controlling search */
|
|
RouteFloat mzPenalty;
|
|
dlong mzWRate;
|
|
dlong mzBloomDeltaCost;
|
|
dlong mzWWidth;
|
|
|
|
/* Statistics */
|
|
dlong 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 controlling search */
|
|
dlong mzWInitialMinToGo;
|
|
dlong mzWInitialMaxToGo;
|
|
dlong mzBloomMaxCost;
|
|
|
|
/* Search status */
|
|
dlong mzWindowMinToGo; /* Window location */
|
|
dlong 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 ADDR_TBL_EQUIV(a1,a2) \
|
|
do \
|
|
{ \
|
|
HashSetValue(HashFind(&aT, (char *) (a1)), (char *) (a2)); \
|
|
HashSetValue(HashFind(&aT, (char *) (a2)), (char *) (a1)); \
|
|
} while(0)
|
|
|
|
/* macro for translating address to address paired with it in address table */
|
|
#define ADDR_TBL(type,a) \
|
|
do \
|
|
{ \
|
|
HashEntry *he = HashLookOnly(&aT, (char *) (a)); \
|
|
if(he) \
|
|
{ \
|
|
a = (type) HashGetValue(he); \
|
|
} \
|
|
} while(0)
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* 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 */
|
|
{
|
|
newParms = (MazeParameters *) mallocMagic((unsigned)(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 */
|
|
{
|
|
rLNew = (RouteLayer *) mallocMagic((unsigned)(sizeof(RouteLayer)));
|
|
ADDR_TBL_EQUIV(rLOld, rLNew);
|
|
ADDR_TBL_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 */
|
|
{
|
|
rCNew = (RouteContact *) mallocMagic((unsigned)(sizeof(RouteContact)));
|
|
ADDR_TBL_EQUIV(rCOld, rCNew);
|
|
ADDR_TBL_EQUIV(&(rCOld->rc_routeType),&(rCNew->rc_routeType));
|
|
}
|
|
|
|
/* copy the rC */
|
|
*rCNew = *rCOld;
|
|
|
|
rCNew->rc_routeType.rt_hBlock = DBNewPlane((ClientData) TT_SPACE);
|
|
rCNew->rc_routeType.rt_vBlock = DBNewPlane((ClientData) TT_SPACE);
|
|
}
|
|
}
|
|
|
|
/* Translate addresses in MazeParameters */
|
|
ADDR_TBL(RouteLayer *, newParms->mp_rLayers);
|
|
ADDR_TBL(RouteContact *, newParms->mp_rContacts);
|
|
ADDR_TBL(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;
|
|
ADDR_TBL(RouteLayer *, rLNew);
|
|
|
|
ADDR_TBL(RouteLayer *, rLNew->rl_next);
|
|
ADDR_TBL(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))
|
|
{
|
|
ADDR_TBL(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;
|
|
ADDR_TBL(RouteContact *, rCNew);
|
|
|
|
ADDR_TBL(RouteLayer *, rCNew->rc_rLayer1);
|
|
ADDR_TBL(RouteLayer *, rCNew->rc_rLayer2);
|
|
ADDR_TBL(RouteContact *, rCNew->rc_next);
|
|
ADDR_TBL(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 = COST_MAX;
|
|
|
|
/* 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;
|
|
mzExpandEndpoints = parms->mp_expandEndpoints;
|
|
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 */
|
|
|
|
/* Comment added by Tim 8/5/06 */
|
|
/* TO DO: If mzExpandEndpoints is FALSE, mzMarkConnectedTiles */
|
|
/* should still add all tiles immediately under the point to the */
|
|
/* start list. */
|
|
|
|
{
|
|
Rect rect;
|
|
|
|
/* build degenerate rect containing point to initiate the
|
|
* marking process;
|
|
*/
|
|
rect.r_ll = *point;
|
|
rect.r_ur = *point;
|
|
|
|
mzMarkConnectedTiles(&rect, type, (mzExpandEndpoints) ?
|
|
MZ_EXPAND_START : MZ_EXPAND_NONE);
|
|
}
|
|
|
|
/* Take our hold off 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 CLIENTDEFAULT should be restored by the router
|
|
* before it returns.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
MZAddDest(rect, type)
|
|
Rect *rect;
|
|
TileType type;
|
|
{
|
|
|
|
UndoDisable();
|
|
|
|
/* If we're not marking all connected tiles, we need to paint */
|
|
/* this specific rectangle into the mzDestAreasUse cell. */
|
|
|
|
if (!mzExpandEndpoints)
|
|
{
|
|
RouteLayer *rL;
|
|
|
|
for(rL = mzRouteLayers; rL != NULL; rL = rL->rl_next)
|
|
{
|
|
if (rL->rl_routeType.rt_active &&
|
|
TTMaskHasType(&(DBConnectTbl[type]),
|
|
rL->rl_routeType.rt_tileType))
|
|
DBPaint(mzDestAreasUse->cu_def, rect,
|
|
rL->rl_routeType.rt_tileType);
|
|
}
|
|
}
|
|
|
|
/* Mark all tiles connected to dest terminal and paint them into */
|
|
/* the mzDestAreasUse cell. */
|
|
|
|
mzMarkConnectedTiles(rect, type,
|
|
(mzExpandEndpoints) ? MZ_EXPAND_DEST : MZ_EXPAND_NONE);
|
|
|
|
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(mzResult)
|
|
int *mzResult; /* Place to put result code */
|
|
{
|
|
RoutePath *path; /* handle for result of search */
|
|
ColoredRect *term;
|
|
List *terms;
|
|
|
|
/* Disable undo to avoid overhead on paint operations to internal planes */
|
|
UndoDisable();
|
|
|
|
/* Clear result cell */
|
|
DBCellClearDef(mzResultDef);
|
|
|
|
/* 1st pass over start terminals: */
|
|
/* paint TT_SAMENODE on each start terminal */
|
|
|
|
for(terms = mzStartTerms; terms != NULL; terms = LIST_TAIL(terms))
|
|
{
|
|
term = (ColoredRect *) LIST_FIRST(terms);
|
|
mzPaintBlockType(&term->cr_rect, term->cr_type, &mzBoundingRect,
|
|
TT_SAMENODE);
|
|
}
|
|
|
|
/* 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");
|
|
if (mzResult) *mzResult = MZ_UNROUTABLE;
|
|
goto abort;
|
|
}
|
|
|
|
/* Build Estimate Plane.
|
|
* (allowing for end points in unexpanded subcells)
|
|
*/
|
|
mzBuildEstimate();
|
|
if (SigInterruptPending)
|
|
{
|
|
if (mzResult) *mzResult = MZ_INTERRUPTED;
|
|
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_DLONG);
|
|
HeapInitType(&mzMinCostHeap, INITHEAPSIZE, FALSE, FALSE, HE_DLONG);
|
|
HeapInitType(&mzMinAdjCostHeap, INITHEAPSIZE, FALSE, FALSE, HE_DLONG);
|
|
HeapInitType(&mzMinCostCompleteHeap, INITHEAPSIZE, FALSE, FALSE, HE_DLONG);
|
|
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
|
|
*/
|
|
|
|
/* set bloom threshold to zero, so that initial points are placed
|
|
* on Max ToGo heap.
|
|
*/
|
|
mzBloomMaxCost = 0;
|
|
|
|
/* 2nd pass over start terminals: generate initial paths */
|
|
/* for each start point */
|
|
|
|
for(terms = mzStartTerms; terms != NULL; terms = LIST_TAIL(terms))
|
|
{
|
|
term = (ColoredRect *) LIST_FIRST(terms);
|
|
mzExtendBlockBounds(&(term->cr_rect.r_ll));
|
|
|
|
if (mzStart(term) == FALSE)
|
|
{
|
|
if (mzResult) *mzResult = MZ_ALREADY_ROUTED;
|
|
goto abort;
|
|
}
|
|
}
|
|
|
|
/* initialize search window */
|
|
/* estimated total cost is min estimated cost for initial paths */
|
|
|
|
mzInitialEstimate = mzMinInitialCost;
|
|
|
|
mzWInitialMinToGo = mzInitialEstimate;
|
|
mzWInitialMaxToGo = mzWInitialMinToGo + mzWWidth;
|
|
|
|
/* Make sure we got here without interruption */
|
|
if (SigInterruptPending) goto abort;
|
|
|
|
/* Do the route */
|
|
path = mzSearch(mzResult);
|
|
/* On interruption mzSearch returns best complete path
|
|
* found prior to interruption
|
|
*/
|
|
|
|
UndoEnable();
|
|
return path;
|
|
|
|
abort:
|
|
UndoEnable();
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* MZCleanupPath --
|
|
*
|
|
* Given a RoutePath constructed by mzRoute, check for conditions that
|
|
* result in DRC errors, and correct them. Conditions checked and
|
|
* the method to fix are as follows:
|
|
*
|
|
* 1) contact1->(any)->contact2 where contacts are the same type and
|
|
* would overlap to produce a non-rectangular area.
|
|
* FIX: replace second contact with its residues.
|
|
*
|
|
* 2) contact1->(any)->contact2 where contacts are the same type and
|
|
* would be spaced closer than the allowed contact->contact minimum
|
|
* DRC space.
|
|
* FIX: fill the area between the two contacts with the contact
|
|
* residue types.
|
|
*
|
|
* 3a) route1-(bend)->route2->contact where length(route2) is less than
|
|
* the spacing rule type(route2)->type(contact).
|
|
* FIX: pull route2 segment toward the inside corner of the bend
|
|
* until the route segment edge aligns with the contact edge.
|
|
*
|
|
* 3b) contact->route2-(bend)->route1, the reverse of the above.
|
|
*
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Messes with the path list.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
MZCleanupPath(pathList)
|
|
RoutePath *pathList;
|
|
{
|
|
RoutePath *path, *n1path, *n2path, *n3path;
|
|
RoutePath *spath, *cpath, *mpath;
|
|
RouteType *rT;
|
|
RouteContact *rC, *rC1, *rC2;
|
|
TileType ctype, ctype1, ctype2;
|
|
int pathlength, hdist, vdist, cdist1, cdist2;
|
|
|
|
|
|
/* 1st pass: Consolidate multiple V or H routes */
|
|
for (path = pathList; path != NULL; path = path->rp_back)
|
|
{
|
|
n1path = path->rp_back;
|
|
while (n1path && (((n1path->rp_orient == 'V') && (path->rp_orient == 'V')) ||
|
|
((n1path->rp_orient == 'H') && (path->rp_orient == 'H'))))
|
|
{
|
|
/* NOTE: Route paths are allocated by a special procedure; */
|
|
/* DON'T use freeMagic() on them! */
|
|
path->rp_back = n1path->rp_back;
|
|
n1path = path->rp_back;
|
|
}
|
|
}
|
|
|
|
/* 2nd pass: Look for route paths causing DRC errors */
|
|
for (path = pathList; path != NULL; path = path->rp_back)
|
|
{
|
|
/* Pick up the next two path segments, if they exist */
|
|
n1path = path->rp_back;
|
|
n2path = (n1path) ? n1path->rp_back : NULL;
|
|
|
|
if (n2path && (n1path->rp_rLayer != n2path->rp_rLayer))
|
|
{
|
|
/* Search backward until we reach the next contact */
|
|
for (spath = n2path->rp_back; spath && spath->rp_back;
|
|
spath = spath->rp_back)
|
|
{
|
|
cpath = spath->rp_back;
|
|
if (spath->rp_rLayer != cpath->rp_rLayer)
|
|
{
|
|
rC1 = MZGetContact(n1path, n2path);
|
|
rC2 = MZGetContact(spath, cpath);
|
|
hdist = abs(n1path->rp_entry.p_x - spath->rp_entry.p_x);
|
|
vdist = abs(n1path->rp_entry.p_y - spath->rp_entry.p_y);
|
|
ctype1 = rC1->rc_routeType.rt_tileType;
|
|
ctype2 = rC2->rc_routeType.rt_tileType;
|
|
cdist1 = rC1->rc_routeType.rt_width;
|
|
cdist2 = rC2->rc_routeType.rt_width;
|
|
|
|
/* To-do: split into cases based on ctype1 vs. ctype2 */
|
|
if ((cpath->rp_rLayer == n1path->rp_rLayer) &&
|
|
(hdist < cdist1 && vdist < cdist1) &&
|
|
(hdist > 0) && (vdist > 0))
|
|
{
|
|
/* Case 1 */
|
|
TxPrintf("Diagnostic: Overlapping contacts (%d:%d) at %d %d\n",
|
|
hdist, vdist,
|
|
path->rp_entry.p_x, path->rp_entry.p_y);
|
|
|
|
/* Replace orient code of one contact with 'C', */
|
|
/* to be handled by mzPaintContact */
|
|
|
|
if (n1path->rp_extendCode > EC_ALL
|
|
&& n1path->rp_orient != 'C')
|
|
spath->rp_orient = 'C';
|
|
else
|
|
n1path->rp_orient = 'C';
|
|
|
|
break;
|
|
}
|
|
hdist += rC1->rc_routeType.rt_width;
|
|
vdist += rC1->rc_routeType.rt_width;
|
|
cdist1 = rC1->rc_routeType.rt_spacing[ctype1];
|
|
if (hdist < cdist1 && vdist < cdist1 && hdist > 0 && vdist > 0)
|
|
{
|
|
/* Case 2 */
|
|
TxPrintf("Diagnostic: Contacts too close (%d:%d) at %d %d\n",
|
|
hdist, vdist,
|
|
n1path->rp_entry.p_x, n1path->rp_entry.p_y);
|
|
|
|
/* Replace orient code of route with 'M' if contacts */
|
|
/* are the same type, 'N' if they're different. */
|
|
/* To be handled by MZPaintPath */
|
|
|
|
for (mpath = n1path; mpath != spath; mpath = mpath->rp_back)
|
|
if (mpath->rp_orient != 'O')
|
|
{
|
|
if (cpath->rp_rLayer == n1path->rp_rLayer)
|
|
mpath->rp_orient = 'M';
|
|
else
|
|
mpath->rp_orient = 'N';
|
|
}
|
|
break;
|
|
}
|
|
|
|
break; /* Stop searching after 1st contact found */
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Pick up the following path segment, if it exists */
|
|
n3path = (n2path) ? n2path->rp_back : NULL;
|
|
|
|
/* Cases 3a and 3b */
|
|
if (n3path != NULL)
|
|
{
|
|
/* Cases 3a: route1->route2->contact */
|
|
|
|
if (n2path->rp_orient == 'O' &&
|
|
n1path->rp_orient != 'O' &&
|
|
path->rp_orient != 'O' &&
|
|
n1path->rp_orient != path->rp_orient)
|
|
{
|
|
rT = &(n1path->rp_rLayer->rl_routeType);
|
|
rC = MZGetContact(n2path, n3path);
|
|
ctype = rC->rc_routeType.rt_tileType;
|
|
|
|
if (n1path->rp_orient == 'V')
|
|
{
|
|
if (n1path->rp_entry.p_y > n2path->rp_entry.p_y)
|
|
{
|
|
/* Case 3a.1: route down to contact */
|
|
pathlength = n1path->rp_entry.p_y - n2path->rp_entry.p_y
|
|
- rC->rc_routeType.rt_width;
|
|
if (pathlength > 0 && pathlength < rT->rt_bloatTop[ctype])
|
|
{
|
|
TxPrintf("Diagnostic: Path needs fix for type "
|
|
"3a.1 DRC error at (%d, %d) dist %d\n",
|
|
path->rp_entry.p_x, path->rp_entry.p_y,
|
|
pathlength);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Case 3a.2: route up to contact */
|
|
pathlength = n2path->rp_entry.p_y - n1path->rp_entry.p_y
|
|
- rT->rt_width;
|
|
if (pathlength > 0 && pathlength < rT->rt_bloatTop[ctype])
|
|
{
|
|
TxPrintf("Diagnostic: Path needs fix for type "
|
|
"3a.2 DRC error at (%d, %d) dist %d\n",
|
|
path->rp_entry.p_x, path->rp_entry.p_y,
|
|
pathlength);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (n1path->rp_entry.p_x > n2path->rp_entry.p_x)
|
|
{
|
|
/* Case 3a.3: route left to contact */
|
|
pathlength = n1path->rp_entry.p_x - n2path->rp_entry.p_x
|
|
- rC->rc_routeType.rt_width;
|
|
if (pathlength > 0 && pathlength < rT->rt_bloatTop[ctype])
|
|
{
|
|
TxPrintf("Diagnostic: Path needs fix for type "
|
|
"3a.3 DRC error at (%d, %d) dist %d\n",
|
|
path->rp_entry.p_x, path->rp_entry.p_y,
|
|
pathlength);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Case 3a.4: route right to contact */
|
|
pathlength = n2path->rp_entry.p_x - n1path->rp_entry.p_x
|
|
- rT->rt_width;
|
|
if (pathlength > 0 && pathlength < rT->rt_bloatTop[ctype])
|
|
{
|
|
TxPrintf("Diagnostic: Path needs fix for type "
|
|
"3a.4 DRC error at (%d, %d) dist %d\n",
|
|
path->rp_entry.p_x, path->rp_entry.p_y,
|
|
pathlength);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Cases 3b: contact->route1->route2 */
|
|
|
|
if (n1path->rp_orient == 'O' &&
|
|
n2path->rp_orient != 'O' &&
|
|
n3path->rp_orient != 'O' &&
|
|
n2path->rp_orient != n3path->rp_orient)
|
|
{
|
|
rT = &(n2path->rp_rLayer->rl_routeType);
|
|
rC = MZGetContact(n1path, path);
|
|
ctype = rC->rc_routeType.rt_tileType;
|
|
|
|
if (n2path->rp_orient == 'V')
|
|
{
|
|
if (n2path->rp_entry.p_y > n1path->rp_entry.p_y)
|
|
{
|
|
/* Case 3b.1: route down from contact */
|
|
pathlength = n2path->rp_entry.p_y - n1path->rp_entry.p_y
|
|
- rC->rc_routeType.rt_width;
|
|
if (pathlength > 0 && pathlength < rT->rt_bloatTop[ctype])
|
|
{
|
|
TxPrintf("Diagnostic: Path needs fix for type "
|
|
"3b.1 DRC error at (%d, %d) dist %d\n",
|
|
path->rp_entry.p_x, path->rp_entry.p_y,
|
|
pathlength);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Case 3b.2: route up from contact */
|
|
pathlength = n1path->rp_entry.p_y - n2path->rp_entry.p_y
|
|
- rT->rt_width;
|
|
if (pathlength > 0 && pathlength < rT->rt_bloatTop[ctype])
|
|
{
|
|
TxPrintf("Diagnostic: Path needs fix for type "
|
|
"3b.2 DRC error at (%d, %d) dist %d\n",
|
|
path->rp_entry.p_x, path->rp_entry.p_y,
|
|
pathlength);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (n2path->rp_entry.p_x > n1path->rp_entry.p_x)
|
|
{
|
|
/* Case 3b.3: route left from contact */
|
|
pathlength = n2path->rp_entry.p_x - n1path->rp_entry.p_x
|
|
- rC->rc_routeType.rt_width;
|
|
if (pathlength > 0 && pathlength < rT->rt_bloatTop[ctype])
|
|
{
|
|
TxPrintf("Diagnostic: Path needs fix for type "
|
|
"3b.3 DRC error at (%d, %d) dist %d\n",
|
|
path->rp_entry.p_x, path->rp_entry.p_y,
|
|
pathlength);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Case 3b.4: route right from contact */
|
|
pathlength = n1path->rp_entry.p_x - n2path->rp_entry.p_x
|
|
- rT->rt_width;
|
|
if (pathlength > 0 && pathlength < rT->rt_bloatTop[ctype])
|
|
{
|
|
TxPrintf("Diagnostic: Path needs fix for type "
|
|
"3b.4 DRC error at (%d, %d) dist %d\n",
|
|
path->rp_entry.p_x, path->rp_entry.p_y,
|
|
pathlength);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* 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;
|
|
{
|
|
RoutePath *path, *prev;
|
|
RouteLayer *last_rL = NULL;
|
|
int cwidth = 0;
|
|
|
|
/*
|
|
* First, check the path for common problems causing DRC errors
|
|
*/
|
|
MZCleanupPath(pathList);
|
|
|
|
/*
|
|
* 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");
|
|
cwidth = mzPaintContact(path, prev);
|
|
last_rL = path->rp_rLayer;
|
|
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;
|
|
if (path->rp_orient == 'M' || path->rp_orient == 'N')
|
|
{
|
|
r.r_xtop += cwidth;
|
|
r.r_ytop += cwidth;
|
|
}
|
|
else
|
|
{
|
|
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);
|
|
|
|
/* Routes between close contacts of the same type should paint */
|
|
/* both residue types. */
|
|
|
|
if ((path->rp_orient == 'M') && (last_rL != NULL))
|
|
{
|
|
DBPaintPlane(mzResultDef->cd_planes[last_rL->rl_planeNum], &r,
|
|
DBStdPaintTbl(last_rL->rl_routeType.rt_tileType,
|
|
last_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 subcell client fields to CLIENTDEFAULT */
|
|
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) CLIENTDEFAULT;
|
|
}
|
|
|
|
/* Dealloc list of marked cells */
|
|
ListDealloc(mzMarkedCellsList);
|
|
mzMarkedCellsList = NULL;
|
|
}
|
|
|
|
/* Free up route-path queues */
|
|
if(mzPathsDirty)
|
|
{
|
|
HeapKill(&mzMaxToGoHeap, (cb_heap_kill_t) NULL);
|
|
HeapKill(&mzMinCostHeap, (cb_heap_kill_t) NULL);
|
|
HeapKill(&mzMinAdjCostHeap, (cb_heap_kill_t) NULL);
|
|
HeapKill(&mzMinCostCompleteHeap, (cb_heap_kill_t) 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;
|
|
}
|