/* * 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 #include #include #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; { ColoredRect *dTerm; 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; }