magic/mzrouter/mzSubrs.c

818 lines
20 KiB
C

/*
* mzSubrs.c --
*
* Misc. surport routines for the Maze router.
*
* *********************************************************************
* * 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/mzSubrs.c,v 1.2 2008/06/01 18:37:44 tim Exp $";
#endif /* not lint */
#include <stdio.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/touchingtypes.h"
#include "utils/heap.h"
#include "mzrouter/mzrouter.h"
#include "mzrouter/mzInternal.h"
/*
* ----------------------------------------------------------------------------
*
* mzComputeDerivedParms --
*
* Processes current parms deriving some parameters from others.
*
* Results:
* None
*
* Side effects:
* Modifies current parms.
*
* ----------------------------------------------------------------------------
*/
void
mzComputeDerivedParms()
{
RouteContact *rC;
RouteLayer *rL;
RouteType *rT;
/* Compute active routelayer list */
mzActiveRLs = NULL;
for(rL=mzRouteLayers; rL!=NULL; rL=rL->rl_next)
{
if(rL->rl_routeType.rt_active)
{
rL->rl_nextActive = mzActiveRLs;
mzActiveRLs = rL;
}
}
/* Compute active routetype list */
mzActiveRTs = NULL;
for(rT=mzRouteTypes; rT!=NULL; rT=rT->rt_next)
{
if(rT->rt_active)
{
rT->rt_nextActive = mzActiveRTs;
mzActiveRTs = rT;
}
}
/* Compute bloats and effWidth for route layers.
* Since we are routing bottom left edge of wires:
* bloat to bottom = spacing + width - 1;
* bloat to top = spacing
*/
for(rL=mzRouteLayers; rL!=NULL; rL=rL->rl_next)
{
RouteType *rT = &(rL->rl_routeType);
int i;
rT->rt_effWidth = rT->rt_width;
for(i=0;i<=TT_MAXTYPES;i++)
{
if(rT->rt_spacing[i]>=0)
{
rT->rt_bloatBot[i] = rT->rt_width + rT->rt_spacing[i] - 1;
rT->rt_bloatTop[i] = rT->rt_spacing[i];
}
else
{
rT->rt_bloatBot[i] = -1;
rT->rt_bloatTop[i] = -1;
}
}
}
/* contact widths and bloats are max of components */
for(rC=mzRouteContacts; rC!=NULL; rC=rC->rc_next)
{
RouteType *rT = &(rC->rc_routeType);
RouteType *rT1 = &(rC->rc_rLayer1->rl_routeType);
RouteType *rT2 = &(rC->rc_rLayer2->rl_routeType);
int i;
rT->rt_effWidth = MAX(MAX(rT1->rt_width,rT2->rt_width),rT->rt_width);
for(i=0;i<=TT_MAXTYPES;i++)
{
int bot, bot1, bot2;
int top, top1, top2;
if(rT->rt_spacing[i]>=0)
{
bot = rT->rt_width + rT->rt_spacing[i] - 1;
top = rT->rt_spacing[i];
}
else
{
bot = -1;
top = -1;
}
if(rT1->rt_spacing[i]>=0)
{
bot1 = rT1->rt_width + rT1->rt_spacing[i] - 1;
top1 = rT1->rt_spacing[i];
}
else
{
bot1 = -1;
top1 = -1;
}
if(rT2->rt_spacing[i]>=0)
{
bot2 = rT2->rt_width + rT2->rt_spacing[i] - 1;
top2 = rT2->rt_spacing[i];
}
else
{
bot2 = -1;
top2 = -1;
}
rT->rt_bloatBot[i] = MAX(MAX(bot1,bot2),bot);
rT->rt_bloatTop[i] = MAX(MAX(top1,top2),top);
}
}
/*
* compute context radius = how much to bloat blockage area
* to be built to obtain search area for mask data.
*/
{
int i;
mzContextRadius = 0;
for(rT=mzActiveRTs; rT!=NULL; rT=rT->rt_nextActive)
for(i=0;i<=TT_MAXTYPES;i++)
mzContextRadius = MAX(mzContextRadius,rT->rt_bloatBot[i]);
}
/* If max walk length is -1, set to twice the context radius */
if(mzMaxWalkLength==-1)
{
mzMaxWalkLength = mzContextRadius * 2;
}
/* If bounds increment is -1, set to 30 times min active pitch */
if(mzBoundsIncrement==-1)
{
int minPitch = INFINITY;
for(rL=mzActiveRLs; rL!=NULL; rL=rL->rl_nextActive)
{
RouteType *rT = &(rL->rl_routeType);
int pitch = rT->rt_width + rT->rt_spacing[rT->rt_tileType];
minPitch = MIN(minPitch, pitch);
}
if(minPitch==INFINITY)
/* Don't coredump just because no active rL's */
{
mzBoundsIncrement = 100;
}
else
{
mzBoundsIncrement = 30*minPitch;
}
}
/* Set up (global) bounding rect for route */
if(mzBoundsHint)
/* Blockage gen will be confined to user supplied hint (+ 2 units)
* generate slightly larger bounds for other purposes (estimate generation
* and marking of tiles connected to dest nodes, for example) to avoid
* edge effects.
*/
{
mzBoundingRect = *mzBoundsHint;
mzBoundingRect.r_xbot -= 2*mzContextRadius;
mzBoundingRect.r_ybot -= 2*mzContextRadius;
mzBoundingRect.r_xtop += 2*mzContextRadius;
mzBoundingRect.r_ytop += 2*mzContextRadius;
}
else
/* No user supplied bounds, shrink maximum paintable rect by a
* conservative amount (to avoid overflow during blockage
* plane generation etc.)
*/
{
int maxWidth, maxSpacing, safeHalo;
RouteType *rT;
mzBoundingRect = TiPlaneRect;
maxWidth = 0;
maxSpacing = 0;
for (rT = mzRouteTypes; rT!=NULL; rT=rT->rt_next)
{
int i;
maxWidth = MAX(maxWidth,rT->rt_width);
for(i=0;i<TT_MAXTYPES+1;i++)
maxSpacing = MAX(maxSpacing,rT->rt_spacing[i]);
}
safeHalo = 3 * (maxSpacing + maxWidth + 2);
mzBoundingRect.r_xbot += safeHalo;
mzBoundingRect.r_xtop -= safeHalo;
mzBoundingRect.r_ybot += safeHalo;
mzBoundingRect.r_ytop -= safeHalo;
ASSERT(mzBoundingRect.r_xbot < mzBoundingRect.r_xtop,
"mzComputeDerivedParms");
ASSERT(mzBoundingRect.r_ybot < mzBoundingRect.r_ytop,
"mzComputeDerivedParms");
}
}
int mzMakeEndpoints; /* Set to MZ_EXPAND_START, MZ_EXPAND_DEST, or
* MZ_EXPAND_NONE.
*/
/*
* ----------------------------------------------------------------------------
*
* mzMarkConnectedTiles --
*
* Marks tiles connected to given area on given layer in mask data.
* Used to mark tiles that are part of start or dest nodes.
*
* If mzExpandEndpoints is set, also adds dest areas for connected tiles.
*
* Results:
* none.
*
* Side effects:
* See above.
*
* ----------------------------------------------------------------------------
*/
void
mzMarkConnectedTiles(rect, type, expandType)
Rect *rect;
TileType type;
int expandType;
{
List *expandList = NULL; /* areas remaining to be expanded from */
/* set global controlling the creation of dest areas for each connected
* tile found.
*/
mzMakeEndpoints = expandType;
/* Create colored rect corresponding to passed args and initial
* expandList with it.
*/
{
ColoredRect *e;
e = (ColoredRect *) mallocMagic((unsigned)(sizeof(ColoredRect)));
e->cr_type = type;
e->cr_rect = *rect;
LIST_ADD(e, expandList);
}
/* repeatedly expand from top area on expandList */
while(expandList)
{
ColoredRect *e = (ColoredRect *) LIST_FIRST(expandList);
SearchContext scx;
TileTypeBitMask typeMask;
int mzConnectedTileFunc();
/* Restrict marking to route bounds */
if(GEO_OVERLAP(&mzBoundingRect, &(e->cr_rect)))
{
/* Set search area to colored rect */
scx.scx_trans = GeoIdentityTransform;
scx.scx_use = mzRouteUse;
scx.scx_area = e->cr_rect;
/* Grow search area by one unit in each direction so that in
* addition to overlapping
* tiles we also get those that just touch it.
*/
scx.scx_area.r_xbot -= 1;
scx.scx_area.r_ybot -= 1;
scx.scx_area.r_xtop += 1;
scx.scx_area.r_ytop += 1;
/* Build type mask with just the type of e set */
TTMaskSetOnlyType(&typeMask, e->cr_type);
/* search for connecting tiles, mark them, and add them to
* expandList (They are inserted
* AFTER the first (= current) element.)
*/
(void)
DBTreeSrTiles(
&scx,
&(DBConnectTbl[e->cr_type]), /* enumerate all
* tiles of connecting
* types */
mzCellExpansionMask,
mzConnectedTileFunc,
(ClientData) expandList);
}
/* Done processing top element of expandList, toss it */
e = (ColoredRect *) ListPop(&expandList);
freeMagic((char *) e);
}
/* mark unexpanded subcells intersecting dest area */
{
if(mzCellExpansionMask != 0)
{
int mzConnectedSubcellFunc();
SearchContext scx;
scx.scx_trans = GeoIdentityTransform;
scx.scx_use = mzRouteUse;
scx.scx_area = *rect;
/* clip area to bounding box to avoid overflow during transforms */
GEOCLIP(&(scx.scx_area),&(mzRouteUse->cu_def->cd_bbox));
/* clip to route bounds for performance */
GEOCLIP(&(scx.scx_area),&mzBoundingRect);
DBTreeSrCells(
&scx,
mzCellExpansionMask,
mzConnectedSubcellFunc,
(ClientData) NULL);
}
}
return;
}
/*
* ---------------------------------------------------------------------
*
* mzConnectedTileFunc --
*
* Called by MZAddDest to mark mask data tile connected to a dest terminal.
*
* Results:
* Always returns 0 to continue search.
*
* Side effects:
* Mark clientdata fileds of connected tiles.
* Add freshly marked tiles to expandList (for recursive expansion).
* If mzExpandEndpoints is set, also adds dest areas for connected
* tiles.
*
* ---------------------------------------------------------------------
*/
int
mzConnectedTileFunc(tile, cxp)
Tile *tile;
TreeContext *cxp;
{
/* If tile not marked, mark it, add it to marked list, and add
* corresponding area to expand list. Mark start tiles MZ_EXPAND_START
* and destination tiles MZ_EXPAND_DEST so that we don't have to run
* the tile cleanup routing (in MZClean()) unnecessarily between
* MZAddStart() and MZAddDest().
*/
if ((int)CD2INT(tile->ti_client) != mzMakeEndpoints)
{
SearchContext *scx = cxp->tc_scx;
List *expandList = (List *) (cxp->tc_filter->tf_arg);
Rect rRaw, r;
/* Get bounding box of tile */
TITORECT(tile, &rRaw);
GEOTRANSRECT(&scx->scx_trans, &rRaw, &r);
/* mark tile with destination type */
tile->ti_client = INT2CD(mzMakeEndpoints);
/* Add tiles connected to Start to mzStartTerms */
/* (Added by Tim, August 2006) */
if (INT2CD(mzMakeEndpoints) == MZ_EXPAND_START)
{
ColoredRect *newTerm;
extern List *mzStartTerms;
newTerm = (ColoredRect *) mallocMagic((unsigned)(sizeof(ColoredRect)));
newTerm->cr_rect = r;
newTerm->cr_type = TiGetType(tile);
LIST_ADD(newTerm, mzStartTerms);
}
/* Add dest area (if appropriate). Don't paint contact types, */
/* or the planes will get fractured up, possibly into areas too */
/* small to place a valid route. */
else if (INT2CD(mzMakeEndpoints) == MZ_EXPAND_DEST)
{
RouteLayer *rL;
TileType ttype = TiGetType(tile);
for(rL=mzRouteLayers; rL!=NULL; rL=rL->rl_next)
{
if (rL->rl_routeType.rt_active &&
TTMaskHasType(&(DBConnectTbl[ttype]),
rL->rl_routeType.rt_tileType))
{
DBPaint(mzDestAreasUse->cu_def,
&r,
rL->rl_routeType.rt_tileType);
}
}
}
/* add entry to expandList */
{
ColoredRect *e;
/* build colored rect corresponding to tile */
e = (ColoredRect *) mallocMagic((unsigned)(sizeof(ColoredRect)));
e->cr_type = TiGetType(tile);
e->cr_rect = r;
/* add new entry to second position of expandList (just
* past current entry)
*/
LIST_ADD(e, LIST_TAIL(expandList));
}
}
/* return 0 to continue search */
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* mzConnectedSubcellFunc --
*
* Called by MZAddDest to mark subcells overlapping a dest terminal.
* (The blockage generation code treats marked subcells as same-node geometry,
* allowing walks and dest areas near them.)
*
* Results:
* Always returns 0 (to continue search)
*
* Side effects:
* Mark client field in subcell use, and add use to list of marked
* subcells.
*
* ----------------------------------------------------------------------------
*/
int
mzConnectedSubcellFunc(scx, cdarg)
SearchContext *scx;
ClientData cdarg;
{
CellUse *cu = scx->scx_use;
/* If not already marked, mark celluse and add to marked list */
if (cu->cu_client == (ClientData)MZ_EXPAND_NONE)
{
cu->cu_client = (ClientData)MZ_EXPAND_DEST;
LIST_ADD(cu, mzMarkedCellsList);
}
/* continue search */
return (0);
}
/*
* ----------------------------------------------------------------------------
*
* mzGetContact --
*
* Get the RouteContact record that matches the contact type between
* planes path->rp_rLayer and prev->rp_rLayer,
*
* Results:
* A pointer to the appropriate RouteContact structure, or NULL if
* none exists (which shouldn't happen).
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
RouteContact *
MZGetContact(path, prev)
RoutePath *path, *prev;
{
RouteContact *rC;
List *cL;
/* Find RouteContact connecting the route layers of path and prev. */
for (cL = path->rp_rLayer->rl_contactL; cL != NULL &&
((RouteContact*)LIST_FIRST(cL))->rc_rLayer1 != prev->rp_rLayer &&
((RouteContact*)LIST_FIRST(cL))->rc_rLayer2 != prev->rp_rLayer;
cL = LIST_TAIL(cL));
ASSERT(cL != NULL, "mzPaintContact");
rC = ((RouteContact*)LIST_FIRST(cL));
return rC;
}
/*
* ----------------------------------------------------------------------------
*
* mzPaintContact --
*
* Paint a single contact between planes path->rp_rLayer and prev->rp_rLayer,
*
* Results:
* None.
*
* Side effects:
* Updates both mask and blockage planes.
*
* ----------------------------------------------------------------------------
*/
int
mzPaintContact(path, prev)
RoutePath *path, *prev;
{
RouteContact *rC;
int pNum, pNumC, cWidth;
Rect r;
TileType cType;
rC = MZGetContact(path, prev);
/* compute the contact tileType */
cType = rC->rc_routeType.rt_tileType;
cWidth = rC->rc_routeType.rt_width;
/* compute bounds of contact tile */
r.r_ll = path->rp_entry;
if (path->rp_orient == 'X')
{
r.r_xtop = r.r_xbot + cWidth;
r.r_ytop = r.r_ybot + rC->rc_routeType.rt_length;
}
else if (path->rp_orient == 'O')
{
r.r_xtop = r.r_xbot + rC->rc_routeType.rt_length;
r.r_ytop = r.r_ybot + cWidth;
}
else /* Type "C", residues only */
{
r.r_xtop = r.r_xbot + cWidth;
r.r_ytop = r.r_ybot + cWidth;
}
/* Paint the contact on all connected mask planes */
/* (should just let DBPaint() do this. . . ) */
if (DBIsContact(cType))
{
if (path->rp_orient != 'C')
{
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
if (PlaneMaskHasPlane(DBConnPlanes[cType], pNum))
DBPaintPlane(mzResultDef->cd_planes[pNum],
&r, DBStdPaintTbl(cType, pNum),
(PaintUndoInfo *) NULL);
}
else
{
/* Paint residues, not the contact type, to avoid DRC errors */
RouteLayer *rL;
rL = rC->rc_rLayer1;
DBPaintPlane(mzResultDef->cd_planes[rL->rl_planeNum], &r,
DBStdPaintTbl(rL->rl_routeType.rt_tileType,
rL->rl_planeNum), (PaintUndoInfo *)NULL);
rL = rC->rc_rLayer2;
DBPaintPlane(mzResultDef->cd_planes[rL->rl_planeNum], &r,
DBStdPaintTbl(rL->rl_routeType.rt_tileType,
rL->rl_planeNum), (PaintUndoInfo *)NULL);
}
}
return cWidth;
}
/*
* ----------------------------------------------------------------------------
*
* mzCopyPath --
*
* Copy a RoutePath from the temporary arena into permanent storage
* allocated via mallocMagic.
*
* Results:
* Returns a pointer to a copy of the RoutePath passed to us
* as an argument.
*
* Side effects:
* Allocates memory.
*
* ----------------------------------------------------------------------------
*/
RoutePath *
mzCopyPath(path)
RoutePath *path;
{
RoutePath *newHead, *newPrev, *new;
newPrev = newHead = (RoutePath *) NULL;
for (newPrev = NULL; path; newPrev = new, path = path->rp_back)
{
new = (RoutePath *) mallocMagic((unsigned)(sizeof (RoutePath)));
*new = *path;
if (newPrev) newPrev->rp_back = new;
if (newHead == NULL) newHead = new;
}
return (newHead);
}
/*--------------- Static variables only referenced by RPath allocation
and deallocation routines below ----------------------- */
/* First, last, and current RoutePages on list for allocating RoutePaths */
RoutePage *mzFirstPage = NULL;
RoutePage *mzLastPage = NULL;
RoutePage *mzCurPage = NULL;
/*
* ----------------------------------------------------------------------------
*
* mzAllocRPath --
*
* Allocate a new RoutePath from our temporary RoutePath arena.
*
* Results:
* Returns a pointer to a newly allocated RoutePath.
* This RoutePath is NOT allocated directly via
* mallocMagic/freeMagic,
* but rather via our own temporary mechanism. It goes away
* once mzFreeAllTemp() gets called, so callers that wish to
* retain the "best" RoutePath must call mzCopyPath() to
* preserve it.
*
* Side effects:
* May allocate memory.
*
* ----------------------------------------------------------------------------
*/
RoutePath *
mzAllocRPath()
{
/* Skip to next page if this one is full */
if (mzCurPage && mzCurPage->rpp_free >= PATHSPERSEG)
mzCurPage = mzCurPage->rpp_next;
/* If out of pages, allocate a new one */
if (mzCurPage == NULL)
{
mzCurPage = (RoutePage *) mallocMagic((unsigned)(sizeof (RoutePage)));
mzCurPage->rpp_next = (RoutePage *) NULL;
mzCurPage->rpp_free = 0;
if (mzLastPage == NULL)
mzFirstPage = mzLastPage = mzCurPage;
else
mzLastPage->rpp_next = mzCurPage, mzLastPage = mzCurPage;
}
return (&mzCurPage->rpp_array[mzCurPage->rpp_free++]);
}
/*
* ----------------------------------------------------------------------------
*
* mzFreeAllRPaths --
*
* Reset the temporary arena used for allocating RoutePaths.
*
* Results:
* None.
*
* Side effects:
* Any RoutePaths in the arena become available again for
* allocation. Callers wishing to preserve paths must
* do so by calling mzCopyPath().
*
* ----------------------------------------------------------------------------
*/
void
mzFreeAllRPaths()
{
RoutePage *rpage;
for (rpage = mzFirstPage; rpage; rpage = rpage->rpp_next)
{
/* Mark page of RoutePaths as being free */
rpage->rpp_free = 0;
/* Can stop after processing the last page used in this cycle */
if (rpage == mzCurPage)
break;
}
/* Start allocating again from the first page on the list */
mzCurPage = mzFirstPage;
}
/*
* ----------------------------------------------------------------------------
*
* mzPresent --
*
* Predicate, checkes if type corresponding to rL is set in touchingTypes
* mask.
*
* Results:
* TRUE if RL in touchingTypes, else FALSE
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
bool
mzPresent(rL,touchingTypes)
RouteLayer *rL;
TileTypeBitMask *touchingTypes;
{
List *l;
/* return true if rL present */
if(TTMaskHasType(touchingTypes, rL->rl_routeType.rt_tileType))
return TRUE;
/* return true if rL present as part of contact */
for(l=rL->rl_contactL; l!=NULL; l=LIST_TAIL(l))
{
RouteContact *rC = (RouteContact *)LIST_FIRST(l);
if(TTMaskHasType(touchingTypes, rC->rc_routeType.rt_tileType) &&
(rC->rc_rLayer1==rL || rC->rc_rLayer2==rL))
return TRUE;
}
return FALSE;
}