magic/grouter/grouteMain.c

394 lines
12 KiB
C

/*
* grouteMain.c --
*
* Top level code for the global signal router.
*
* The global router's job is to find the sequence of channel pins
* through which each signal must pass, and mark these pins so the
* channel router can connect them within each channel.
*
* Our overall approach is greedy: we compute the area of the bounding
* box of all terminals in a net for each net, and perform global routing
* of each net in order of increasing area of this bounding box. This
* has the effect of routing more constrained nets first, and less
* constrained ones later.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 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. *
* *********************************************************************
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/times.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/styles.h"
#include "utils/hash.h"
#include "utils/heap.h"
#include "utils/utils.h"
#include "tiles/tile.h"
#include "database/database.h"
#include "debug/debug.h"
#include "gcr/gcr.h"
#include "windows/windows.h"
#include "utils/main.h"
#include "dbwind/dbwind.h"
#include "utils/signals.h"
#include "router/router.h"
#include "grouter/grouter.h"
#include "utils/netlist.h"
#include "utils/styles.h"
#include "textio/textio.h"
#include "utils/malloc.h"
/* Global data */
Heap glMazeHeap; /* Heap of search points for global routing */
FILE *glLogFile; /* Used for debugging to remember crossings processed */
int glNumTries; /* Debugging too -- # calls to glProcessLoc() */
/* Forward declarations */
void glClientInit();
void glClientFree();
/*
* ----------------------------------------------------------------------------
*
* GlGlobalRoute --
*
* Build a heap of nets, ordered with smallest area first.
* Globally route nets on the heap, decomposing multi-pin nets using
* Steiner-like trees. Leave routing problems in channel structures.
*
* Results:
* None.
*
* Side effects:
* On completion crossing points for nets have been set. Channel
* structures are ready to be routed by the channel structure.
*
* ----------------------------------------------------------------------------
*/
void
GlGlobalRoute(chanList, netList)
GCRChannel *chanList; /* List of all channels in routing problem */
NLNetList *netList; /* Netlist built by caller */
{
HeapEntry entry;
Heap netHeap;
bool doFast;
int numTerms;
NLNet *net;
GlInit();
glStatsInit();
doFast = DebugIsSet(glDebugID, glDebFast);
/*
* Initialize the client-specific portion of each channel and
* of each net. These fields point to structures holding
* (respectively) density information and blocked regions
* during global routing.
*/
glClientInit(chanList, netList);
/*
* Build a tile plane that represents all the channels in the
* routing problem. This tile plane will be used to search
* for nearby channels during global routing.
*/
glChanBuildMap(chanList);
if (DebugIsSet(glDebugID, glDebChan))
{
SigInterruptPending = TRUE;
return;
}
/* Compute penalties for passing through congested zones */
if (DebugIsSet(glDebugID, glDebPen))
glPenCompute(chanList, netList);
/*
* Build a heap of nets sorted in order of increasing size, then
* successively remove the topmost entry of the heap and route its
* net. Make almost-Steiner tree global routes for multi-pin nets.
*/
numTerms = 0;
NLSort(netList, &netHeap);
while (HeapRemoveTop(&netHeap, &entry) && !SigInterruptPending)
{
net = (NLNet *) entry.he_id;
if (DebugIsSet(glDebugID, glDebPen))
{
glCrossUnreserve(net);
glPenSetPerChan(net);
}
numTerms += glMultiSteiner(EditCellUse, net, glProcessLoc,
glCrossMark, INT2CD(doFast), (ClientData) 0);
if (DebugIsSet(glDebugID, glDebPen))
glPenClearPerChan(net);
RtrMilestonePrint();
}
HeapKill(&netHeap, (cb_heap_kill_t) NULL);
glClientFree(chanList, netList);
glChanFreeMap();
glStatsDone(netList->nnl_numNets, numTerms);
}
/*
* ----------------------------------------------------------------------------
*
* glClientInit --
*
* Allocate and initialize the structures that go in the gcr_client and
* nnet_cdata fields of all the channels and nets respectively in chanList
* and netList, and leave these fields pointing to the newly allocated and
* initialized structures.
*
* Results:
* None.
*
* Side effects:
* Allocates memory; see above.
*
* ----------------------------------------------------------------------------
*/
void
glClientInit(chanList, netList)
GCRChannel *chanList;
NLNetList *netList;
{
GCRChannel *ch;
GlobChan *gc;
NLNet *net;
int nrow, ncol;
for (ch = chanList; ch; ch = ch->gcr_next)
{
gc = (GlobChan *) mallocMagic((unsigned) (sizeof (GlobChan)));
gc->gc_penList = (CZone *) NULL;
nrow = ch->gcr_width;
ncol = ch->gcr_length;
glDMAlloc(&gc->gc_prevDens[CZ_COL], ncol, nrow);
glDMAlloc(&gc->gc_prevDens[CZ_ROW], nrow, ncol);
glDMAlloc(&gc->gc_postDens[CZ_COL], ncol, nrow);
glDMAlloc(&gc->gc_postDens[CZ_ROW], nrow, ncol);
glDensInit(gc->gc_prevDens, ch);
glDMCopy(&gc->gc_prevDens[CZ_COL], &gc->gc_postDens[CZ_COL]);
glDMCopy(&gc->gc_prevDens[CZ_ROW], &gc->gc_postDens[CZ_ROW]);
ch->gcr_client = (ClientData) gc;
}
for (net = netList->nnl_nets; net; net = net->nnet_next)
net->nnet_cdata = (ClientData) callocMagic((unsigned) (sizeof (NetClient)));
}
/*
* ----------------------------------------------------------------------------
*
* glClientFree --
*
* Free the memory allocated by glClientInit() above (as well as any
* memory allocated to CZone lists pointed to by the NetClient structs
* in the NLNetList netList).
*
* Results:
* None.
*
* Side effects:
* Frees memory.
*
* ----------------------------------------------------------------------------
*/
void
glClientFree(chanList, netList)
GCRChannel *chanList;
NLNetList *netList;
{
GlobChan *gc;
CZone *cz;
NetClient *nclient;
GCRChannel *ch;
NLNet *net;
for (ch = chanList; ch; ch = ch->gcr_next)
{
gc = (GlobChan *) ch->gcr_client;
glDMFree(&gc->gc_prevDens[CZ_COL]);
glDMFree(&gc->gc_prevDens[CZ_ROW]);
glDMFree(&gc->gc_postDens[CZ_COL]);
glDMFree(&gc->gc_postDens[CZ_ROW]);
freeMagic((char *) gc);
ch->gcr_client = (ClientData) NULL;
}
for (net = netList->nnl_nets; net; net = net->nnet_next)
{
nclient = (NetClient *) net->nnet_cdata;
for (cz = nclient->nc_pens; cz; cz = cz->cz_next)
freeMagic((char *) cz);
net->nnet_cdata = (ClientData) NULL;
}
}
/*
* ----------------------------------------------------------------------------
*
* glProcessLoc --
*
* Function called for all but the first NLTermLoc in a net: finds and
* returns the best-cost path from any of the points in the starting
* point list to loc->nloc_stem.
*
* Algorithm:
* We use two passes. The first attempts to find the shortest
* distance path between the source and the destination, if
* such a path exists. It uses a mechanism for storing the
* best cost so far to each crossing point considered, so
* we avoid looping. If no path can be found, we simply
* give up; otherwise, we perform a second pass where we
* try to generate not only the shortest path, but the
* next shortest, etc, until we find one whose distance
* plus crossing penalty is minimized.
*
* Results:
* Returns the best path. The first element on the list
* (linked by gl_path pointers) is the destination point.
* If no path could be found with cost less than bestCost,
* returns NULL.
*
* Side effects:
* Allocates memory from the temporary GlPoint arena.
*
* ----------------------------------------------------------------------------
*/
GlPoint *
glProcessLoc(startList, loc, bestCost, doFast)
GlPoint *startList; /* List of starting points */
NLTermLoc *loc; /* Location of terminal being routed to */
int bestCost; /* Best cost so far; if we can't find a path in
* less than this cost, give up.
*/
bool doFast; /* If TRUE, only wiggle crossings around within the
* channels on the shortest path; don't bother
* considering other sequences of channels. If FALSE,
* we keep generating longer and longer paths until
* the sheer length of a path exceeds our best
* adjusted cost to date.
*/
{
extern bool glMazeShortest;
extern Tile *glMazeDestTile;
extern Point glMazeDestPoint;
extern GlPoint *glMazeFindPath();
extern GlPoint *glCrossAdjust();
int headFree, shortLength, bestLength;
GlPoint *lastPt, *bestPt, *adjustedPt;
GlPage *headPage;
glNumTries++;
glCrossScalePenalties();
/* Sanity checks */
ASSERT(GEO_SAMEPOINT(loc->nloc_pin->gcr_point, loc->nloc_stem),
"glProcessLoc");
/*
* Passed to glMazeFindPath() for use in estimating the remaining
* distance to the destination point. Also figure out which
* channel tile contains the destination, so we can handle
* points in it specially. If the destination point is inside
* a blocked area, give up immediately.
*/
glMazeDestPoint = loc->nloc_stem;
glMazeDestTile = glChanPinToTile((Tile *) NULL, loc->nloc_pin);
/* Abort immediately if destination is obviously unreachable */
if (glMazeDestTile == NULL)
return (GlPoint *) NULL;
/*
* First try finding the shortest path.
* This goes very quickly, because we are able to chop
* off unpromising paths at an early stage.
*/
glMazeShortest = TRUE;
HeapInit(&glMazeHeap, 128, FALSE, FALSE);
glListToHeap(startList, &loc->nloc_stem);
headPage = glPathCurPage;
headFree = glPathCurPage->glp_free;
bestPt = glMazeFindPath(loc, bestCost);
glMazeResetCost(headPage, headFree);
HeapKill(&glMazeHeap, (cb_heap_kill_t) NULL);
if (bestPt == (GlPoint *) NULL)
{
glBadRoutes++;
return bestPt;
}
shortLength = bestPt->gl_cost;
/*
* Now try finding a path that minimizes the crossing penalty.
* We do this by continuing to generate paths in order of
* increasing length, then adjusting the crossing points
* along the path to minimize (locally) the penalty for
* the path, until we find a path whose unadjusted length
* exceeds the best cost we've been able to achieve so far.
* The gl_cost fields in the paths generated by glCrossAdjust
* incorporate the penalties as well as distance.
*/
HeapInit(&glMazeHeap, 128, FALSE, FALSE);
glListToHeap(startList, &loc->nloc_stem);
if (doFast)
{
headPage = glPathCurPage;
headFree = glPathCurPage->glp_free;
}
else glMazeShortest = FALSE;
bestPt = (GlPoint *) NULL;
while ((lastPt = glMazeFindPath(loc, bestCost)))
{
adjustedPt = glCrossAdjust((GlPoint *) NULL, lastPt);
if (adjustedPt->gl_cost < bestCost)
{
bestCost = adjustedPt->gl_cost;
bestLength = lastPt->gl_cost;
bestPt = adjustedPt;
}
}
if (doFast)
glMazeResetCost(headPage, headFree);
HeapKill(&glMazeHeap, (cb_heap_kill_t) NULL);
if (bestPt)
{
if (glLogFile)
{
fprintf(glLogFile, "%d\t%d (%.2f)\t%d (%.2f)\n",
shortLength, bestLength,
(float) bestLength / (float) shortLength * 100.0,
bestPt->gl_cost,
(float) bestPt->gl_cost / (float) shortLength * 100.0);
}
glGoodRoutes++;
return bestPt;
}
glBadRoutes++;
glNoRoutes++;
return (GlPoint *) NULL;
}