magic/grouter/grouteNet.c

1795 lines
53 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* grouteNet.c -
*
* Global signal router. Code to route one segment of a
* net, from a set of possible starting points to a single
* destination point. Uses a Lee-like wavefront maze router
* approach, with several performance heuristics to focus
* the search strongly toward the destination rather than
* propagating isotropically from the starting points.
*
* *********************************************************************
* * 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. *
* *********************************************************************
*/
#ifndef lint
static char sccsid[] = "@(#)grouteNet.c 4.3 MAGIC (Berkeley) 12/6/85";
#endif /* not lint */
#include <stdio.h>
#include <sys/types.h>
#include <sys/times.h>
#include "utils/magic.h"
#include "utils/geometry.h"
#include "utils/geofast.h"
#include "utils/hash.h"
#include "utils/heap.h"
#include "utils/malloc.h"
#include "debug/debug.h"
#include "tiles/tile.h"
#include "database/database.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 "textio/textio.h"
#include "utils/styles.h"
Point glDestPoint; /* Point we're routing to */
/* The following penalties get scaled by RtrGridSpacing */
bool glPenaltiesScaled = FALSE;
int glJogPenalty = 5;
int glObsPenalty1 = 5, glObsPenalty2 = 3;
int glNbrPenalty1 = 2, glNbrPenalty2 = 5;
int glOrphanPenalty = 3;
int glChanPenalty = 1;
/* Used in glNormalPropagate() */
typedef struct
{
int pr_tmin, pr_tmax; /* Range of top pin indices */
int pr_bmin, pr_bmax; /* Range of bottom pin indices */
int pr_lmin, pr_lmax; /* Range of left pin indices */
int pr_rmin, pr_rmax; /* Range of right pin indices */
} PinRanges;
PinRanges glInitRange =
{
INFINITY, MINFINITY,
INFINITY, MINFINITY,
INFINITY, MINFINITY,
INFINITY, MINFINITY
};
/*
* Auxiliary information used by the new maze routing algorithm.
*
* Whenever the maze router is ready to select the next frontier
* point to expand, it first moves some points to these two heaps:
* glProximityHeap, which is sorted by distance to the destination
* glDestPoint, and glBestHeap, which is sorted by the same cost
* as glHeap, namely total estimated cost: gl_length plus distance
* to glDestPoint.
*
* In addition, glBestCost is used to remember the total estimated
* cost of the best total estimated cost point in any of the heaps.
*/
Heap glProximityHeap;
Heap glBestHeap;
int glBestCost;
GlPoint *glBestPt;
/*
* Points are transferred from glHeap to the two heaps above
* only when their cost is less than (fudgeNumer/fudgeDenom)
* times the best total cost of any point still in any of the
* heaps, i.e, (fudgeNumer * glBestCost) / fudgeDenom.
*/
int fudgeNumer = 13;
int fudgeDenom = 10;
/* Marker to indicate an already-processed GlPoint */
#define PROCESSED_MARK ((GlPoint *) 1)
/*
* ----------------------------------------------------------------------------
*
* glRouteToPoint --
*
* Perform the global routing for the given pin. The heap starts off
* with one or more starting points. This routine finds the least
* cost path from any starting point to the destination point,
* where cost includes both distance and crossing penalties.
*
* Results:
* Pointer to the ending point in the global routing. Chasing parent
* pointers to the root yields the global routing result. Returns
* NULL if no path was found.
*
* Side effects:
* The search point heap (glHeap) changes. If a successful global
* routing was found, all points along the path are removed from
* the heap, leaving other partial path points still on the heap.
* If no routing was found, the heap is empty.
*
* ----------------------------------------------------------------------------
*/
GlPoint *
glRouteToPoint(loc, bestCost)
NLTermLoc *loc; /* Route from points on heap to this point */
int bestCost; /* If we haven't found a path with less than
* this cost, return NULL.
*/
{
int heapPts, frontierPts, startPts, headFree;
GCRChannel *inCh;
GlPoint *inPt;
bool newBest, newPaths;
HeapEntry hEntry;
GlPage *headPage;
GlPoint *lastPt;
/* Initialize auxiliary heaps */
HeapInit(&glBestHeap, 64, FALSE, FALSE);
HeapInit(&glProximityHeap, 64, FALSE, FALSE);
glNumTries++;
if (glLogFile)
fprintf(glLogFile, "---\t%d\t0,0\t0\t0\n", glNumTries);
/* Initialization */
if (!glPenaltiesScaled)
glScalePenalties();
/* Remember for resetting GCRPins later */
headPage = glCurPage;
headFree = glCurPage->glp_free;
/* Remember for debugging */
heapPts = glCrossingsExpanded;
frontierPts = glCrossingsConsidered;
startPts = glHeap.he_used;
/*
* Passed to glPropagateFn() for use in estimating the remaining
* distance to the destination point. Invert sense of loc->nloc_dir
* (the direction of loc->nloc_ch relative to the cell) to give the
* side of the channel on which loc->nloc_stem lies.
*/
glDestPoint = loc->nloc_stem;
ASSERT(GEO_SAMEPOINT(loc->nloc_pin->gcr_point, loc->nloc_stem),
"glRouteToPoint");
/*
* The modified shortest path algorithm extends the partial path for
* which the sum of the current path cost plus the Manhattan distance
* to the destination point is the smallest.
*/
glBestCost = 0;
glBestPt = (GlPoint *) NULL;
newPaths = newBest = TRUE;
lastPt = (GlPoint *) NULL;
while (!SigInterruptPending && glPopFromHeap(&newBest, newPaths, &hEntry))
{
newPaths = FALSE;
glCrossingsExpanded++;
inPt = (GlPoint *) hEntry.he_id;
/* Done if we reach the destination crossing point */
if (GEO_SAMEPOINT(inPt->gl_point, glDestPoint))
{
lastPt = inPt;
break;
}
/* Done if the best path is already more expensive than best cost */
if (inPt->gl_length >= bestCost && !DebugIsSet(glDebugID,glDebNewHeaps))
break;
/* Reject if its pin has already been visited more cheaply */
if (inPt->gl_length > inPt->gl_pin->gcr_cost)
{
glCrossingsObsolete++;
continue;
}
if (glLogFile)
glLogPath(inPt, hEntry.he_int);
/*
* There are three possibilities:
* - inPt is in the destination channel, or
* - it is in a river-routing channel, or
* - it is in a normal channel.
* In the latter case, we use a trick to avoid having to process
* all the crossings in the channel at once.
*/
inCh = inPt->gl_ch;
if (inCh != loc->nloc_chan || !glFinalPropagate(inPt, loc))
{
if (inCh->gcr_type != CHAN_NORMAL)
(void) glRiverPropagate(inPt);
else
glNormalPropagate(inPt, inCh, hEntry.he_int);
}
/* Remember that points may have been added to glHeap */
newPaths = TRUE;
}
/* Reset the cost stored with each GCRPin */
glResetCost(headPage, headFree);
/* Record number of points processed if debugging */
if (DebugIsSet(glDebugID, glDebHisto))
glHistoAdd(heapPts, frontierPts, startPts);
/* Free the auxiliary heaps */
HeapKill(&glBestHeap, (void (*)()) NULL);
HeapKill(&glProximityHeap, (void (*)()) NULL);
return (lastPt);
}
/*
* ----------------------------------------------------------------------------
*
* glScalePenalties --
*
* Scale the penalties used in the global router cost function so they
* reflect the actual grid size used during routing.
*
* Results:
* None.
*
* Side effects:
* See above.
*
* ----------------------------------------------------------------------------
*/
void
glScalePenalties()
{
glJogPenalty *= RtrGridSpacing;
glObsPenalty1 *= RtrGridSpacing;
glObsPenalty2 *= RtrGridSpacing;
glNbrPenalty1 *= RtrGridSpacing;
glNbrPenalty2 *= RtrGridSpacing;
glOrphanPenalty *= RtrGridSpacing;
glChanPenalty *= RtrGridSpacing;
glPenaltiesScaled = TRUE;
}
/*
* ----------------------------------------------------------------------------
*
* glPopFromHeap --
*
* Obtain the next frontier point for consideration from the
* heap glHeap. The variable newPaths should be TRUE if
* points were added to glHeap since the last call to this
* procedure.
*
* Algorithm:
* We maintain three heaps.
* The first, glHeap, is the one to which points are added,
* and is referred to as the Reserve heap.
*
* The two remaining heaps are auxiliary: glProximityHeap is sorted
* in order of increasing distance to the goal, and glBestHeap is
* sorted using the same key as glHeap (cost so far plus an estimate
* of the cost remaining to the destination).
*
* The idea is to remove all points from glHeap that are
* within a certain percentage (fudgeNumer/fudgeDenom) of
* the best estimated cost so far (glBestCost), and add these
* to glProximityHeap. The actual points we return are then
* selected from glProximityHeap, which causes points closest
* to the destination to be preferred over points farther away.
*
* Results:
* Returns TRUE if a new entry was stored in hEntry, or
* FALSE if no more points were available.
*
* Side effects:
* May pop points from glHeap and store points in or pop
* points from glBestHeap or glProximityHeap. May change
* *pNewBest (it should be initially TRUE on the very first
* call to glPopFromHeap). Also, may modify glBestCost
* (which should be zero on the first call). Stores the
* entry popped from the top of glProximityHeap in the
* HeapEntry pointed to by hEntry.
*
* ----------------------------------------------------------------------------
*/
bool
glPopFromHeap(pNewBest, newPaths, hEntry)
bool *pNewBest; /* Should be TRUE on initial call; afterwards,
* we set it to TRUE when glBestCost is updated.
*/
bool newPaths; /* TRUE if points added to glHeap since the last
* call to glPopFromHeap().
*/
HeapEntry *hEntry; /* See above */
{
HeapEntry *bestCostTop, *glHeapTop;
int minAcceptableCost, newBestCost;
GlPoint *topPt;
if (!DebugIsSet(glDebugID, glDebNewHeaps))
return (HeapRemoveTop(&glHeap, hEntry) != NULL);
/*
* If the top element on glBestHeap changed (this occurs
* when it is popped from glProximityHeap in the previous
* call), we have to move more points from glHeap to
* glProximityHeap.
*/
if (*pNewBest)
{
/*
* Pop bestcost heap until path that hasn't already been
* processed is reached. (Already processed paths are marked
* by setting their gl_next field to PROCESSED_MARK). This
* point will be the one with the best possible cost plus
* estimate to the destination, and will be used to compute
* the minimum acceptable cost for transfer to glProximityHeap.
*/
while ((bestCostTop = HeapLookAtTop(&glBestHeap))
&& ((GlPoint *) bestCostTop->he_id)->gl_next == PROCESSED_MARK)
{
if (DebugIsSet(glDebugID, glDebHeap))
{
TxPrintf("Discarding point (cost=%d): ", bestCostTop->he_int);
glPrintPoint((GlPoint *) bestCostTop->he_id);
TxPrintf("\n");
}
HeapRemoveTop(&glBestHeap, hEntry);
}
/*
* The "new" best cost is min of cost of top of the best-cost
* heap and the reserve heap. If both heaps are empty, we've
* failed and should return FALSE.
*/
if (glHeapTop = HeapLookAtTop(&glHeap))
{
if (bestCostTop == NULL || glHeapTop->he_int < bestCostTop->he_int)
{
if (DebugIsSet(glDebugID, glDebHeap))
TxPrintf("Best cost really comes from glHeap\n");
bestCostTop = glHeapTop;
}
}
else if (bestCostTop == NULL)
return FALSE;
newBestCost = bestCostTop->he_int;
glBestPt = (GlPoint *) bestCostTop->he_id;
if (newBestCost == glBestCost)
*pNewBest = FALSE;
glBestCost = newBestCost;
if (DebugIsSet(glDebugID, glDebHeap))
{
TxPrintf("New best (cost=%d): ", newBestCost);
glPrintPoint(glBestPt);
TxPrintf("\nCost %s\n", *pNewBest ? "changed" : "didn't change");
}
}
/*
* Move acceptably cheap paths from reserve to best heaps.
* This has to happen if either the cutoff point changed in
* the code above (*pNewBest == TRUE), or if points had been
* added to glHeap since the last time we were called
* (newPaths == TRUE).
*/
if (*pNewBest || newPaths)
{
/*
* The minimum acceptable cost for transfer from the
* Reserve heap (glHeap) to the proximity and best heaps
* will be glBestCost * (fudgeNumer / fudgeDenom).
*/
minAcceptableCost = (glBestCost * fudgeNumer) / fudgeDenom;
if (DebugIsSet(glDebugID, glDebHeap))
TxPrintf("Min acceptable cost = %d\n", minAcceptableCost);
while ((glHeapTop = HeapRemoveTop(&glHeap, hEntry))
&& glHeapTop->he_int <= minAcceptableCost)
{
Point *p = &(((GlPoint *)(glHeapTop->he_id))->gl_point);
int dist = ABSDIFF(p->p_x, glDestPoint.p_x)
+ ABSDIFF(p->p_y, glDestPoint.p_y);
if (DebugIsSet(glDebugID, glDebHeap))
{
TxPrintf("Move to prox (pcost=%d,cost=%d): ",
dist, glHeapTop->he_int);
glPrintPoint((GlPoint *) glHeapTop->he_id);
TxPrintf("\n");
}
HeapAddInt(&glBestHeap, glHeapTop->he_int, glHeapTop->he_id);
HeapAddInt(&glProximityHeap, dist, glHeapTop->he_id);
}
if (glHeapTop)
HeapAddInt(&glHeap, glHeapTop->he_int, glHeapTop->he_id);
}
/*
* The next point to be processed is the one at the top of
* the proximity heap, i.e., the one closest to the destination.
* If we popped the current best, set newBest flag, so we know
* to compute a new "best cost" the next time we're called.
* Mark the point as "processed", so it will be discarded if
* it ever comes to the top of glBestHeap above.
*/
if (HeapRemoveTop(&glProximityHeap, hEntry) == NULL)
return FALSE;
topPt = (GlPoint *) hEntry->he_id;
*pNewBest = (topPt == glBestPt);
topPt->gl_next = PROCESSED_MARK;
/*
* Fix up the cost field of hEntry (remember, it was popped
* from the proximity heap, which is keyed only on the estimated
* distance remaining, while we want the cost plus the estimate
* to the destination).
*/
hEntry->he_int = topPt->gl_length
+ ABSDIFF(topPt->gl_point.p_x, glDestPoint.p_x)
+ ABSDIFF(topPt->gl_point.p_y, glDestPoint.p_y);
if (DebugIsSet(glDebugID, glDebHeap))
{
TxPrintf("Returning point (%s, cost=%d): ",
*pNewBest ? "best" : "not best", hEntry->he_int);
glPrintPoint(topPt);
TxPrintf("\n");
}
return TRUE;
}
/*
* ----------------------------------------------------------------------------
*
* glFinalPropagate --
*
* Process a point that lies in the destination channel.
* These points are treated specially since we don't need
* to find any more crossings to other channels.
*
* Note that we do perform a density computation here, so
* we should avoid attempts to route through a portion of
* a channel where its capacity has been exceeded.
*
* Results:
* FALSE if the path to the destination was blocked because
* it was unreachable; TRUE otherwise.
*
* Side effects:
* May add a point to the heap.
*
* ----------------------------------------------------------------------------
*/
bool
glFinalPropagate(inPt, loc)
GlPoint *inPt; /* Point being processed */
NLTermLoc *loc; /* Destination point */
{
GCRChannel *destCh = loc->nloc_chan;
GCRPin *destPin = loc->nloc_pin;
Point *destPoint = &loc->nloc_stem;
GlPoint *outPt;
int cost;
cost = inPt->gl_length;
cost += ABSDIFF(inPt->gl_point.p_x, destPoint->p_x);
cost += ABSDIFF(inPt->gl_point.p_y, destPoint->p_y);
/* Disallow the path if it exceeds the channel density */
if (destCh->gcr_dMaxByRow >= destCh->gcr_length
|| destCh->gcr_dMaxByCol >= destCh->gcr_width)
{
if (glDensityExceeded(destCh, inPt->gl_pin, destPin))
return (FALSE);
}
#ifdef notdef /* Don't make it too difficult in the final channel */
if (DebugIsSet(glDebugID, glDebStraight))
{
/* If the net runs across the channel, it must not jog */
if (!glJogsAcrossChannel(inPt->gl_pin, destPin))
return (FALSE);
}
#endif /* notdef */
cost = glCrossPenalty(cost, destCh, (GCRChannel *) NULL,
inPt->gl_pin, destPin);
if (cost >= destPin->gcr_cost)
return (TRUE);
glCrossingsComplete++;
outPt = glNewPoint(destPoint, destCh, destPin, cost, inPt);
HeapAddInt(&glHeap, cost, (char *) outPt);
if (glLogFile)
{
fprintf(glLogFile, "FIN\t%d\t%d,%d\t%d\n",
glNumTries,
outPt->gl_point.p_x, outPt->gl_point.p_y,
outPt->gl_length);
}
return (TRUE);
}
/*
* ----------------------------------------------------------------------------
*
* glRiverPropagate --
*
* Process a point belonging to a river-routing channel. Since these
* channels can only be used for routing straight across to their
* other side, we only need to consider a single crossing point.
*
* Results:
* Returns the cost with which the point was added to the heap,
* or -1 if the point wasn't added.
*
* Side effects:
* May add a point to the heap.
*
* ----------------------------------------------------------------------------
*/
int
glRiverPropagate(inPt)
GlPoint *inPt;
{
GCRPin *inPin = inPt->gl_pin, *outPin, *linkedPin;
GCRChannel *inCh = inPt->gl_ch;
int cost;
GlPoint *outPt;
/* Find the opposing pin */
switch (inPin->gcr_side)
{
case GEO_NORTH: outPin = &inCh->gcr_bPins[inPin->gcr_x]; break;
case GEO_SOUTH: outPin = &inCh->gcr_tPins[inPin->gcr_x]; break;
case GEO_EAST: outPin = &inCh->gcr_lPins[inPin->gcr_y]; break;
case GEO_WEST: outPin = &inCh->gcr_rPins[inPin->gcr_y]; break;
}
/* Propagate to this pin if it is free */
if ((linkedPin = outPin->gcr_linked)
&& linkedPin->gcr_pId == (GCRNet *) NULL)
{
/* Only add to heap if this path is cheapest so far */
cost = inPt->gl_length
+ ABSDIFF(inPt->gl_point.p_x, linkedPin->gcr_point.p_x)
+ ABSDIFF(inPt->gl_point.p_y, linkedPin->gcr_point.p_y);
if (cost < linkedPin->gcr_cost)
{
linkedPin->gcr_cost = outPin->gcr_cost = cost;
outPt = glNewPoint(&outPin->gcr_point, linkedPin->gcr_ch, linkedPin,
cost, inPt);
cost += ABSDIFF(glDestPoint.p_x, linkedPin->gcr_point.p_x)
+ ABSDIFF(glDestPoint.p_y, linkedPin->gcr_point.p_y);
HeapAddInt(&glHeap, cost, (char *) outPt);
if (glLogFile)
{
fprintf(glLogFile, "RIV\t%d\t%d,%d\t%d\t%d\n",
glNumTries,
outPt->gl_point.p_x, outPt->gl_point.p_y,
outPt->gl_length, cost);
}
return (cost);
}
}
return (-1);
}
/*
* ----------------------------------------------------------------------------
*
* glNormalPropagate --
*
* Process a point (inPt) that lies in a normal routing channel (inCh)
* that is not the destination channel. Use a trick to minimize the
* number of crossing points in inCh that must be processed, speeding
* up global routing by a factor of 3 - 5, particularly in the case
* of large channels with lots of crossing points per channel.
*
* Motivation:
* Most channels contain lots of pins. Usually, most of them
* aren't even close to being on the least-cost path, as in
* the case below:
*
* D
*
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | |
* + +
* | C |
* + +
* | |
* +---+---+---+---+---+---+---S---+---+---+---+---+---+---+
*
* (Here, "S" is a point on the boundary of channel "C", and "D"
* is the destination point, which happens to lie in the adjacent
* channel. "D" is a very short distance from "S" compared with
* the width of the channel).
*
* It's usually a waste of time to process the points of "C" that
* aren't on the direct path to the destination. However, we
* can't just throw them away, because it may turn out that the
* direct path is blocked, and we need to use one of the points
* to the side, e.g:
*
* D
* BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | |
* + +
* | C |
* + +
* | |
* +---+---+---+---+---+---+---S---+---+---+---+---+---+---+
*
* (Here "B" is a blockage in the channel containing "D", forcing
* points to the side of the channel to be used.)
*
* Algorithm:
* The trick is to ensure that the points to the side are added
* to the heap before they are needed, but not necessarily all
* at once.
*
* We compute a rectangle around the starting point "S" that
* will contain the crossing points most likely to be of interest.
* This rectangle "R" is a bloated version of the bounding rectangle
* containing "S" and the destination point, clipped against the
* reachable portion of the channel (reachable in the sense of
* passing through no regions of maximum density):
*
* ................D....
* : :
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+
* | : : |
* + : R : +
* | : : |
* + : : +
* | : : |
* +---+---+---+---+---+---+---S---+---+---+---+---+---+---+
*
* Only crossings inside of "R" are added to the heap. However,
* we put the point "S" BACK on the heap, remembering the area
* "R" already processed. The trick is the cost with which "S"
* is added to the heap: sufficiently high so that points on the
* direct path to the destination are processed before "S" is
* reprocessed, but sufficiently low so that "S" is processed
* BEFORE the points outside of "R" would have been removed
* from the heap, had they been added at the same time "S"
* was originally processed.
*
* When a point is removed from the heap, then, it may either
* be "virgin", or it may have been partially expanded. The
* state of its expansion is described in inPt->gl_visited,
* which gives grid coordinates of a rectangle (including its
* top and right coordinates) covering all pins visited so far.
*
* We determine a new set of pins to visit (based on heapCost,
* as described in the comments for glSetPinClip()), visit them,
* and then if all feasible points haven't yet been reached, we
* add a new point to the heap with a new gl_visited showing the
* points we processed on this iteration. The cost for this new
* heap point is chosen to be less than the cost of any of the
* remaining points, so we have a chance to process them and put
* them on the heap before they are needed.
*
* Results:
* None.
*
* Side effects:
* May add many points to the heap.
*
* ----------------------------------------------------------------------------
*/
void
glNormalPropagate(inPt, inCh, heapCost)
GlPoint *inPt; /* Point on the boundary of inCh */
GCRChannel *inCh; /* Channel through which we're passing */
int heapCost; /* Cost with which inPt was added to heap */
{
PinRanges pinRange, prevRange;
int x, y, baseCost, min, max;
GCRPin *inPin = inPt->gl_pin;
Rect pinRect, densRect;
GCRPin *outPin;
int i, cost;
bool noCheckJogs;
/*
* Starting at inPt, figure out how high, low, left, and right
* we can go based on density limits. If we're completely
* hemmed in and can't go anywhere, mark the pin as now being
* blocked and return.
*/
if (!glSetDensityClip(inPt, inCh, &densRect))
{
#ifdef notdef
inPin->gcr_pId = GCR_BLOCKEDNETID;
if (inPin->gcr_linked)
inPin->gcr_linked->gcr_pId = GCR_BLOCKEDNETID;
#endif /* notdef */
return;
}
/*
* Next, figure out the range of pins we're interested in
* visiting on this pass. This range will generally cover
* less than the entire channel, and will depend on the
* relative positions of inPt and glDestPoint. The range
* is clipped against densRect.
*/
glSetPinClip(inPt, inCh, heapCost, &densRect, &pinRect);
glRectToRange(inCh, &pinRect, &pinRange);
/*
* We've already visited the pins identified in pinRect.
* Visit all the pins that lie in pinClip but not in pinRect.
* At the end, if pinRect is not equal to densRect, create
* a new GlPoint like inPt but with gl_range equal to pinRect,
* and add this point back to the heap with a carefully-chosen
* new cost (see below).
*/
glRectToRange(inCh, &inPt->gl_range, &prevRange);
baseCost = inPt->gl_length + glChanPenalty;
x = inPt->gl_point.p_x;
y = inPt->gl_point.p_y;
#define OKPIN(p) \
((p)->gcr_pId == NULL \
&& (p)->gcr_linked && (p)->gcr_linked->gcr_pId == NULL)
#define XCOST(x, pin) ABSDIFF((x), (pin)->gcr_point.p_x)
#define YCOST(y, pin) ABSDIFF((y), (pin)->gcr_point.p_y)
/* Top */
min = pinRange.pr_tmin, max = pinRange.pr_tmax;
if (inCh->gcr_tPins->gcr_pNext && min <= max)
{
cost = baseCost + inCh->gcr_area.r_ytop - y;
noCheckJogs = TRUE;
if (inPin->gcr_side != GEO_SOUTH) cost += glJogPenalty;
else if (DebugIsSet(glDebugID, glDebStraight)) noCheckJogs = FALSE;
for (i = min, outPin = &inCh->gcr_tPins[i]; i <= max; i++, outPin++)
{
if (i == prevRange.pr_tmin)
{
i = prevRange.pr_tmax;
outPin += prevRange.pr_tmax - prevRange.pr_tmin;
continue;
}
if (OKPIN(outPin) && cost + XCOST(x, outPin) < outPin->gcr_cost)
if (noCheckJogs || !glJogsAcrossChannel(inPin, outPin))
(void) glPropagateFn(outPin->gcr_linked->gcr_ch,
outPin, inPt);
}
}
/* Bottom */
min = pinRange.pr_bmin, max = pinRange.pr_bmax;
if (inCh->gcr_bPins->gcr_pNext && min <= max)
{
cost = baseCost + y - inCh->gcr_area.r_ybot;
noCheckJogs = TRUE;
if (inPin->gcr_side != GEO_NORTH) cost += glJogPenalty;
else if (DebugIsSet(glDebugID, glDebStraight)) noCheckJogs = FALSE;
for (i = min, outPin = &inCh->gcr_bPins[i]; i <= max; i++, outPin++)
{
if (i == prevRange.pr_bmin)
{
i = prevRange.pr_bmax;
outPin += prevRange.pr_bmax - prevRange.pr_bmin;
continue;
}
if (OKPIN(outPin) && cost + XCOST(x, outPin) < outPin->gcr_cost)
if (noCheckJogs || !glJogsAcrossChannel(inPin, outPin))
(void) glPropagateFn(outPin->gcr_linked->gcr_ch,
outPin, inPt);
}
}
/* Left */
min = pinRange.pr_lmin, max = pinRange.pr_lmax;
if (inCh->gcr_lPins->gcr_pNext && min <= max)
{
cost = baseCost + x - inCh->gcr_area.r_xbot;
noCheckJogs = TRUE;
if (inPin->gcr_side != GEO_EAST) cost += glJogPenalty;
else if (DebugIsSet(glDebugID, glDebStraight)) noCheckJogs = FALSE;
for (i = min, outPin = &inCh->gcr_lPins[i]; i <= max; i++, outPin++)
{
if (i == prevRange.pr_lmin)
{
i = prevRange.pr_lmax;
outPin += prevRange.pr_lmax - prevRange.pr_lmin;
continue;
}
if (OKPIN(outPin) && cost + YCOST(y, outPin) < outPin->gcr_cost)
if (noCheckJogs || !glJogsAcrossChannel(inPin, outPin))
(void) glPropagateFn(outPin->gcr_linked->gcr_ch,
outPin, inPt);
}
}
/* Right */
min = pinRange.pr_rmin, max = pinRange.pr_rmax;
if (inCh->gcr_rPins->gcr_pNext && min <= max)
{
cost = baseCost + inCh->gcr_area.r_xtop - x;
noCheckJogs = TRUE;
if (inPin->gcr_side != GEO_WEST) cost += glJogPenalty;
else if (DebugIsSet(glDebugID, glDebStraight)) noCheckJogs = FALSE;
for (i = min, outPin = &inCh->gcr_rPins[i]; i <= max; i++, outPin++)
{
if (i == prevRange.pr_rmin)
{
i = prevRange.pr_rmax;
outPin += prevRange.pr_rmax - prevRange.pr_rmin;
continue;
}
if (OKPIN(outPin) && cost + YCOST(y, outPin) < outPin->gcr_cost)
if (noCheckJogs || !glJogsAcrossChannel(inPin, outPin))
(void) glPropagateFn(outPin->gcr_linked->gcr_ch,
outPin, inPt);
}
}
/*
* If we haven't visited all the points in this channel that
* are reachable because of density, create a copy of inPt and
* add it to the heap, marking its gl_range as the Rect equivalent
* of pinRange. The cost we use in adding this copy to the heap
* is chosen to ensure that we get a chance to add the least cost
* of the remaining points to the heap before anything else of that
* cost gets removed from the heap.
*/
cost = glMinRemainingCost(inPt, inCh, &pinRect, &densRect);
if (cost < INFINITY)
{
inPt = glNewPoint(&inPt->gl_point, inCh, inPin, inPt->gl_length,
inPt->gl_parent);
inPt->gl_range = pinRect;
HeapAddInt(&glHeap, cost - 1, (char *) inPt);
glCrossingsPartial++;
}
else glCrossingsComplete++;
}
/*
* ----------------------------------------------------------------------------
*
* glMinRemainingCost --
*
* Choose the cost with which glNormalPropagate will add a point to the
* heap. This cost is INFINITY if all the points inside of dRect have
* been processed (*pRect == *dRect); otherwise, it is the cost of a
* route from inPt to the closest pin in the set contained in *dRect
* but not in *pRect, plus an estimate of the cost from this pin to
* the destination point, plus the cost of inPt.
*
* Results:
* Returns the cost above.
*
* Side effects:
* May add many points to the heap.
*
* ----------------------------------------------------------------------------
*/
int
glMinRemainingCost(inPt, inCh, pRect, dRect)
GlPoint *inPt;
GCRChannel *inCh;
Rect *pRect, *dRect;
{
int cost, n;
GCRPin *pins;
/*
* In the code below, 'cost' represents the sum of the cost
* from inPt to a point in densRect but not in pinRect, plus
* the estimated cost from that point to the destination.
*/
cost = INFINITY;
/*
* Pins on top and bottom.
* Figure out which x-coordinate on the top or bottom will
* give minimum cost to the destination.
*/
n = (glDestPoint.p_x - inCh->gcr_origin.p_x) / RtrGridSpacing;
n = INRANGE(n, pRect->r_xbot - 1, pRect->r_xtop + 1);
n = INRANGE(n, dRect->r_xbot, dRect->r_xtop);
/* Top pins */
if (dRect->r_ytop == inCh->gcr_width + 1)
{
pins = inCh->gcr_tPins;
if (pRect->r_ytop < dRect->r_ytop)
{
/* Haven't reached top yet */
cost = glPinCost(inPt, &pins[n], cost);
}
else
{
/* Have processed part of the top already */
if (pRect->r_xbot > dRect->r_xbot)
cost = glPinCost(inPt, &pins[pRect->r_xbot - 1], cost);
if (pRect->r_xtop < dRect->r_xtop)
cost = glPinCost(inPt, &pins[pRect->r_xtop + 1], cost);
}
}
/* Bottom pins */
if (dRect->r_ybot == 0)
{
pins = inCh->gcr_bPins;
if (pRect->r_ybot > dRect->r_ybot)
{
/* Haven't reached bottom yet */
cost = glPinCost(inPt, &pins[n], cost);
}
else
{
/* Have processed part of the bottom already */
if (pRect->r_xbot > dRect->r_xbot)
cost = glPinCost(inPt, &pins[pRect->r_xbot - 1], cost);
if (pRect->r_xtop < dRect->r_xtop)
cost = glPinCost(inPt, &pins[pRect->r_xtop + 1], cost);
}
}
/* Pins on right and left */
n = (glDestPoint.p_y - inCh->gcr_origin.p_y) / RtrGridSpacing;
n = INRANGE(n, pRect->r_ybot - 1, pRect->r_ytop + 1);
n = INRANGE(n, dRect->r_ybot, dRect->r_ytop);
/* Right pins */
if (dRect->r_xtop == inCh->gcr_length + 1)
{
pins = inCh->gcr_rPins;
if (pRect->r_xtop < dRect->r_xtop)
{
/* Haven't reached RHS yet */
cost = glPinCost(inPt, &pins[n], cost);
}
else
{
/* Have processed part of the RHS already */
if (pRect->r_ybot > dRect->r_ybot)
cost = glPinCost(inPt, &pins[pRect->r_ybot - 1], cost);
if (pRect->r_ytop < dRect->r_ytop)
cost = glPinCost(inPt, &pins[pRect->r_ytop + 1], cost);
}
}
/* Left pins */
if (dRect->r_xbot == 0)
{
pins = inCh->gcr_lPins;
if (pRect->r_xbot > dRect->r_xbot)
{
/* Haven't reached LHS yet */
cost = glPinCost(inPt, &pins[n], cost);
}
else
{
/* Have processed part of the LHS already */
if (pRect->r_ybot > dRect->r_ybot)
cost = glPinCost(inPt, &pins[pRect->r_ybot - 1], cost);
if (pRect->r_ytop < dRect->r_ytop)
cost = glPinCost(inPt, &pins[pRect->r_ytop + 1], cost);
}
}
if (cost == INFINITY)
return (cost);
return (cost + inPt->gl_length);
}
/*
* glPinCost --
*
* Used by above to give the distance from inPt->gl_point to pin->gcr_point,
* plus the distance from pin->gcr_point to the destination, plus any
* penalties that are guaranteed to apply (the channel penalty and
* possibly a jog penalty are all we consider now).
*
* Results:
* Returns the minimum of the above cost and 'oldCost'.
*
* Side effects:
* None.
*/
int
glPinCost(inPt, pin, oldCost)
GlPoint *inPt;
GCRPin *pin;
int oldCost;
{
int cost;
/* Length from inPt to pin */
cost = ABSDIFF(inPt->gl_point.p_x, pin->gcr_point.p_x)
+ ABSDIFF(inPt->gl_point.p_y, pin->gcr_point.p_y);
/* Estimate of length from pin to destination */
cost += ABSDIFF(glDestPoint.p_x, pin->gcr_point.p_x)
+ ABSDIFF(glDestPoint.p_y, pin->gcr_point.p_y);
/* Penalties */
cost += glChanPenalty;
if (inPt->gl_point.p_x != pin->gcr_point.p_x
&& inPt->gl_point.p_y != pin->gcr_point.p_y)
cost += glJogPenalty;
return (MIN(cost, oldCost));
}
/*
* ----------------------------------------------------------------------------
*
* glSetDensityClip --
*
* Determine which pins in inCh are reachable from inPt->gl_pin,
* given density restrictions. Leaves *dRect set to the Rect
* (in grid coordinates for 'ch') describing visitable pins
* on each side. If a whole side of pins is not reachable
* (e.g, the top), then that coordinate of *dRect (e.g, r_ytop)
* won't reach all the way to the corresponding extreme value
* for the pin indices for 'ch' (e.g, ch->gcr_width+1).
*
* Results:
* Returns the cost above.
*
* Side effects:
* May add many points to the heap.
*
* ----------------------------------------------------------------------------
*/
bool
glSetDensityClip(inPt, ch, dRect)
GlPoint *inPt;
GCRChannel *ch;
Rect *dRect;
{
GCRPin *inPin = inPt->gl_pin;
short *den, maxdensity;
int n;
/*
* Default: in the absence of density violations, we can
* visit all the pins on each side of the channel.
*/
dRect->r_xbot = dRect->r_ybot = 0;
dRect->r_xtop = ch->gcr_length + 1;
dRect->r_ytop = ch->gcr_width + 1;
if (ch->gcr_dMaxByRow >= ch->gcr_length)
{
den = ch->gcr_dColsByRow;
maxdensity = ch->gcr_length;
glVDensityChecks++;
/* Walk up */
for (n = MAX(inPin->gcr_y, 1); n <= ch->gcr_width; n++)
{
if (den[n] >= maxdensity)
{
/* Can't reach top */
glVDensityFailures++;
dRect->r_ytop = n-1;
break;
}
}
/* Walk down */
for (n = MIN(inPin->gcr_y, ch->gcr_width); n >= 1; n--)
if (den[n] >= maxdensity)
{
/* Can't reach bottom */
glVDensityFailures++;
dRect->r_ybot = n+1;
break;
}
}
if (ch->gcr_dMaxByCol >= ch->gcr_width)
{
den = ch->gcr_dRowsByCol;
maxdensity = ch->gcr_width;
glHDensityChecks++;
/* Walk right */
for (n = MAX(inPin->gcr_x, 1); n <= ch->gcr_length; n++)
if (den[n] >= maxdensity)
{
/* Can't reach right hand side */
glHDensityFailures++;
dRect->r_xtop = n-1;
break;
}
/* Walk left */
for (n = MIN(inPin->gcr_x, ch->gcr_length); n >= 1; n--)
if (den[n] >= maxdensity)
{
/* Can't reach left hand side */
glHDensityFailures++;
dRect->r_xbot = n+1;
break;
}
}
if (dRect->r_xtop < dRect->r_xbot) dRect->r_ytop = dRect->r_ybot - 1;
else if (dRect->r_ytop < dRect->r_ybot) dRect->r_xtop = dRect->r_xbot - 1;
return (dRect->r_xtop >= dRect->r_xbot && dRect->r_ytop >= dRect->r_ybot);
}
/*
* ----------------------------------------------------------------------------
*
* glSetPinClip --
*
* Figure out the range of pins we're interested in visiting on this pass.
* The Rect for these pins will generally cover less than the entire channel,
* and will depend on the relative positions of inPt and glDestPoint. The
* Rect is clipped against dRect.
*
* Algorithm:
* Construct an imaginary rectangle ('R') with inPt at one corner and
* glDestPoint at the other. Bloat R on all sides by the amount
* described below and then determine all pins that lie both within
* this rectangle and dRange.
*
* The amount that R is bloated depends on heapCost, which is the
* value currently at the top of the heap. The simple case is when
* heapCost is just inPt->gl_length plus the Manhattan distance from
* inPt to glDestPoint (which we'll call estCost). This case should
* correspond to the first time inPt is processed. If we weren't to
* bloat R at all, all pins lying inside it could end up with the same
* total cost (gl_length plus estimated cost to glDestPoint) as inPt,
* so we at least have to add them.
*
* Things are more complex if heapCost is greater than inPt->gl_length
* plus estCost. Let diff be the difference. We will bloat the rect
* by diff/2. The reason is that points in the bloated rectangle could
* end up with a total cost equal to heapCost, since they involve a
* detour of diff/2 units out and then diff/2 units back to align
* with the destination point.
*
* The actual amount of the bloat is diff/2 + RtrGridSpacing*4 to
* give a little extra slop.
*
* Results:
* None.
*
* Side effects:
* Fills in *pRect.
*
* ----------------------------------------------------------------------------
*/
void
glSetPinClip(inPt, inCh, heapCost, dRect, pRect)
GlPoint *inPt;
GCRChannel *inCh;
int heapCost;
Rect *dRect, *pRect;
{
int bloat, estCost, t;
Rect r;
if (DebugIsSet(glDebugID, glDebAllPoints))
{
*pRect = *dRect;
return;
}
/*
* First construct the rectangle in lambda coordinates.
* Make it canonical: ll <= ur.
*/
r.r_ll = inPt->gl_point;
r.r_ur = glDestPoint;
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;
/* Bloat it */
estCost = ABSDIFF(inPt->gl_point.p_x, glDestPoint.p_x)
+ ABSDIFF(inPt->gl_point.p_y, glDestPoint.p_y);
bloat = (heapCost - (estCost + inPt->gl_length)) / 2;
bloat += RtrGridSpacing * 4;
GEO_EXPAND(&r, bloat, &r);
/* Convert to grid coordinates */
pRect->r_xbot = (r.r_xbot - inCh->gcr_origin.p_x) / RtrGridSpacing;
pRect->r_ybot = (r.r_ybot - inCh->gcr_origin.p_y) / RtrGridSpacing;
pRect->r_xtop = (r.r_xtop - inCh->gcr_origin.p_x) / RtrGridSpacing;
pRect->r_ytop = (r.r_ytop - inCh->gcr_origin.p_y) / RtrGridSpacing;
/* Clip against dRect */
GEOCLIP(pRect, dRect);
}
/*
* ----------------------------------------------------------------------------
*
* glResetCost --
*
* Reset the costs stored with each GlPin after we've completed
* the global routing for a single net.
*
* Results:
* None.
*
* Side effects:
* Sets each pin's cost to INFINITY.
*
* ----------------------------------------------------------------------------
*/
void
glResetCost(headPage, headFree)
GlPage *headPage;
int headFree;
{
GlPage *gpage;
GCRPin *pin;
int n;
for (gpage = headPage; gpage; gpage = gpage->glp_next)
{
for (n = headFree; n < gpage->glp_free; n++)
if (pin = gpage->glp_array[n].gl_pin)
{
pin->gcr_cost = INFINITY;
if (pin->gcr_linked)
pin->gcr_linked->gcr_cost = INFINITY;
}
if (gpage == glCurPage)
break;
headFree = 0;
}
}
/*
* ----------------------------------------------------------------------------
*
* glPropagateFn --
*
* Search function called by glRouteToPoint for each unused crossing
* point exiting the channel whose entry point is being processed.
*
* Results:
* Returns the cost with which the point was added to the heap,
* if it was added, or -1 if not.
*
* Side effects:
* If the crossing point is usable and the path through inPin
* is the cheapest, add the new crossing point to the heap.
*
* ----------------------------------------------------------------------------
*/
int
glPropagateFn(outCh, outPin, inPt)
GCRChannel *outCh; /* Channel entered from outPin */
GCRPin *outPin; /* Exit pin, also in inCh */
GlPoint *inPt; /* Point being considered */
{
int cost, n;
int finalCost;
GlPoint *outPt;
glCrossingsConsidered++;
/* Add the distance to the exit point to the cost */
cost = inPt->gl_length;
n = inPt->gl_point.p_x - outPin->gcr_point.p_x;
if (n < 0) cost -= n; else cost += n;
n = inPt->gl_point.p_y - outPin->gcr_point.p_y;
if (n < 0) cost -= n; else cost += n;
/* Adjust by penalty and see if we can throw out this path */
cost = glCrossPenalty(cost, inPt->gl_ch, outCh, inPt->gl_pin, outPin);
if (cost >= outPin->gcr_cost)
return (-1);
if (DebugIsSet(glDebugID, glDebMaze))
glPropagateDebug(inPt, inPt->gl_pin, outCh, outPin,
outPin->gcr_cost, cost);
/* Remember the new cheapest cost path and add point to the heap */
#ifdef notdef
if (outPin->gcr_point.p_x == iPt.p_x && outPin->gcr_point.p_y == iPt.p_y)
TxPrintf("Bingo! cost=%d\n", cost);
#endif /* notdef */
outPin->gcr_cost = cost;
if (outPin->gcr_linked)
outPin->gcr_linked->gcr_cost = cost;
outPt = glNewPoint(&outPin->gcr_point, outCh,
outPin->gcr_linked, cost, inPt);
/*
* Special handling if outPt is in a river-routing channel.
* There's no point in adding it to the heap, since we know
* the only point that is reachable from it. Just propagate
* depth-first from here.
*/
if (outCh->gcr_type != CHAN_NORMAL)
return (glRiverPropagate(outPt));
/*
* Estimate the least possible cost to reach the destination
* using this path.
*/
finalCost = cost + ABSDIFF(glDestPoint.p_x, outPin->gcr_point.p_x)
+ ABSDIFF(glDestPoint.p_y, outPin->gcr_point.p_y);
HeapAddInt(&glHeap, finalCost, (char *) outPt);
if (glLogFile)
{
fprintf(glLogFile, "ADD\t%d\t%d,%d\t%d\t%d\n",
glNumTries,
outPt->gl_point.p_x, outPt->gl_point.p_y,
outPt->gl_length, finalCost);
}
return (finalCost);
}
/*
* ----------------------------------------------------------------------------
*
* glCrossPenalty --
*
* Evaluate a set of crossing points through a channel to determine the
* total cost of bad crossing penalties. These penalties are added to
* 'cost' to give the total cost. (The argument 'cost' should be the
* sum of the cost to get to 'inPin' plus the Manhattan distance from
* 'inPin' to 'outPin').
*
* Density considerations are ignored here; they are the responsibilty
* of the caller.
*
* Results:
* The total cost plus penalty, in lambda units.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
int
glCrossPenalty(cost, inCh, outCh, inPin, outPin)
int cost; /* Distance cost */
GCRChannel *inCh; /* Both inPin and outPin are in this channel */
GCRChannel *outCh; /* Channel to which outPin exits, or NULL
* if outPin is the destination.
*/
GCRPin *inPin; /* Pin used to enter inCh */
GCRPin *outPin; /* Pin used to exit inCh into outCh */
{
GCRPin *otherPin;
int count;
/* Penalty for using lots of channels */
cost += glChanPenalty;
/* Penalize if the net doesn't run straight across the channel */
if (inPin->gcr_x != outPin->gcr_x && inPin->gcr_y != outPin->gcr_y)
cost += glJogPenalty;
/*
* If there is an obstacle or hazard over a crossing, or an
* obstacle somewhere along the track or column of the pin,
* then assess a penalty. Look on both sides of the crossing
* to get this penalty.
*/
#define BADCROSSFLAGS (GCROBST|GCRHAZRD|GCRTCC)
otherPin = outPin->gcr_linked;
if (outCh && outCh->gcr_type == CHAN_NORMAL)
{
if ((otherPin->gcr_pFlags & BADCROSSFLAGS)
|| otherPin->gcr_pSize != 0)
{
ASSERT(otherPin->gcr_pSize >= 0, "glCrossPenalty");
cost += glObsPenalty1;
if (otherPin->gcr_pFlags & GCROBST)
cost += glObsPenalty2 * otherPin->gcr_pSize;
else if (otherPin->gcr_pFlags & GCRHAZRD)
cost += MAX(glObsPenalty2*otherPin->gcr_pSize
- otherPin->gcr_pDist, 0);
}
}
/*
* Done if this is not a cheaper way of reaching outPin,
* or if this channel is used for river-routing (in which
* case the subsequent penalty computation is not needed).
*/
if (cost >= outPin->gcr_cost || inCh->gcr_type != CHAN_NORMAL)
return (cost);
if ((outPin->gcr_pFlags & BADCROSSFLAGS)
|| outPin->gcr_pSize != 0)
{
ASSERT(outPin->gcr_pSize >= 0, "glCrossPenalty");
cost += glObsPenalty1;
if (outPin->gcr_pFlags & GCROBST)
cost += glObsPenalty2 * outPin->gcr_pSize;
else if (outPin->gcr_pFlags & GCRHAZRD)
cost += MAX(glObsPenalty2 * outPin->gcr_pSize
- outPin->gcr_pDist, 0);
}
/* Done if this is not a cheaper way of reaching outPin */
if (cost >= outPin->gcr_cost)
return (cost);
/*
* If both neighboring pins are used, the penalty is 5.
* If only one of the neighboring pins is used, the penalty is only 2.
*/
count = 0;
if ((outPin + 1)->gcr_pId) count++;
if ((outPin - 1)->gcr_pId) count++;
if (count == 2) cost += glNbrPenalty2;
else if (count == 1) cost += glNbrPenalty1;
/*
* If the path turns in the channel and the exit crossing
* isn't a paired orphan, the penalty is 3.
*/
if (outPin->gcr_side != GeoOppositePos[inPin->gcr_side])
{
switch (outPin->gcr_side)
{
case GEO_NORTH: otherPin = &inCh->gcr_bPins[outPin->gcr_x]; break;
case GEO_SOUTH: otherPin = &inCh->gcr_tPins[outPin->gcr_x]; break;
case GEO_EAST: otherPin = &inCh->gcr_lPins[outPin->gcr_y]; break;
case GEO_WEST: otherPin = &inCh->gcr_rPins[outPin->gcr_y]; break;
}
if (otherPin->gcr_pId == (GCRNet *) NULL)
cost += glOrphanPenalty;
}
return (cost);
}
/*
* ----------------------------------------------------------------------------
*
* glDensityExceeded --
*
* Determine if the path from inPin to outPin through inCh passes
* through any region of maximum density.
*
* Results:
* Returns TRUE if the path passes through a maximum-density
* region, FALSE if not.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
bool
glDensityExceeded(inCh, inPin, outPin)
GCRChannel *inCh;
GCRPin *inPin, *outPin;
{
int min, max, maxdensity;
short *den;
short *dlast;
if (inCh->gcr_dMaxByRow >= inCh->gcr_length)
{
glVDensityChecks++;
maxdensity = inCh->gcr_length;
min = MIN(inPin->gcr_y, outPin->gcr_y);
min = INRANGE(min, 1, inCh->gcr_width);
max = MAX(inPin->gcr_y, outPin->gcr_y);
max = INRANGE(max, 1, inCh->gcr_width);
den = &inCh->gcr_dColsByRow[min];
dlast = &inCh->gcr_dColsByRow[max];
while (den <= dlast)
if (*den++ >= maxdensity)
{
glVDensityFailures++;
return (TRUE);
}
}
if (inCh->gcr_dMaxByCol >= inCh->gcr_width)
{
glHDensityChecks++;
maxdensity = inCh->gcr_width;
min = MIN(inPin->gcr_x, outPin->gcr_x);
min = INRANGE(min, 1, inCh->gcr_length);
max = MAX(inPin->gcr_x, outPin->gcr_x);
max = INRANGE(max, 1, inCh->gcr_length);
den = &inCh->gcr_dRowsByCol[min];
dlast = &inCh->gcr_dRowsByCol[max];
while (den <= dlast)
if (*den++ >= maxdensity)
{
glHDensityFailures++;
return (TRUE);
}
}
return (FALSE);
}
/*
* ----------------------------------------------------------------------------
*
* glRectToRange --
*
* Convert from a Rect to a PinRanges representation of a range of pin
* values. Both representations contain the same information, but the
* latter is more convenient to work with in glNormalPropagate(), while
* the former requires half the storage.
*
* The dimensions of 'ch' are used to determine whether the pins on a
* given side of a channel are to be excluded or not: if the Rect 'r'
* doesn't extend all the way to 0 on the left or bottom, or to
* ch->gcr_width + 1 on the top or ch->gcr_length + 1 on the right,
* then the pins on that side are excluded.
*
* Results:
* None.
*
* Side effects:
* Sets *pr to the PinRanges structure implied by 'r'.
*
* ----------------------------------------------------------------------------
*/
void
glRectToRange(ch, r, pr)
GCRChannel *ch;
Rect *r;
PinRanges *pr;
{
Rect clipR;
/* Initialize to empty */
*pr = glInitRange;
/* Actual ranges will be from 1 to height or width of channel */
clipR.r_xbot = MAX(r->r_xbot, 1);
clipR.r_ybot = MAX(r->r_ybot, 1);
clipR.r_xtop = MIN(r->r_xtop, ch->gcr_length);
clipR.r_ytop = MIN(r->r_ytop, ch->gcr_width);
/* Top */
if (r->r_ytop == ch->gcr_width + 1)
pr->pr_tmin = clipR.r_xbot, pr->pr_tmax = clipR.r_xtop;
/* Bottom */
if (r->r_ybot == 0)
pr->pr_bmin = clipR.r_xbot, pr->pr_bmax = clipR.r_xtop;
/* Left */
if (r->r_xbot == 0)
pr->pr_lmin = clipR.r_ybot, pr->pr_lmax = clipR.r_ytop;
/* Right */
if (r->r_xtop == ch->gcr_length + 1)
pr->pr_rmin = clipR.r_ybot, pr->pr_rmax = clipR.r_ytop;
}
/*
* ----------------------------------------------------------------------------
*
* glJogsAcrossChannel --
*
* Determine whether a signal crosses from one side of a channel
* to the other with a jog.
*
* Results:
* TRUE if inPin and outPin are on opposite sides of the channel
* but are not directly opposite each other.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
bool
glJogsAcrossChannel(inPin, outPin)
GCRPin *inPin, *outPin;
{
switch (inPin->gcr_side)
{
case GEO_NORTH:
if (outPin->gcr_side == GEO_SOUTH
&& outPin->gcr_point.p_x != inPin->gcr_point.p_x)
return (TRUE);
break;
case GEO_SOUTH:
if (outPin->gcr_side == GEO_NORTH
&& outPin->gcr_point.p_x != inPin->gcr_point.p_x)
return (TRUE);
break;
case GEO_EAST:
if (outPin->gcr_side == GEO_WEST
&& outPin->gcr_point.p_y != inPin->gcr_point.p_y)
return (TRUE);
break;
case GEO_WEST:
if (outPin->gcr_side == GEO_EAST
&& outPin->gcr_point.p_y != inPin->gcr_point.p_y)
return (TRUE);
break;
}
return (FALSE);
}
/*
* ----------------------------------------------------------------------------
*
* glPropagateDebug --
*
* Used for debugging; print lots of information about the pair of
* crossing points inPin and outPin (propagating through inPt->gl_ch).
*
* Results:
* None.
*
* Side effects:
* Prints stuff on the terminal; also displays the areas of
* the two crossing points on the screen.
*
* ----------------------------------------------------------------------------
*/
void
glPropagateDebug(inPt, inPin, outCh, outPin, prevCost, distCost)
GlPoint *inPt;
GCRPin *inPin, *outPin;
GCRChannel *outCh;
int prevCost, distCost;
{
char mesg[256];
Point linkedPt;
Rect r;
r.r_ll = r.r_ur = inPt->gl_point;
r.r_xtop++, r.r_ytop++;
nrShowRect(EditCellUse->cu_def, &r, STYLE_SOLIDHIGHLIGHTS);
if (inPin->gcr_linked) linkedPt = inPin->gcr_linked->gcr_point;
else linkedPt = TiPlaneRect.r_ll;
(void) sprintf(mesg,
"ENTRY ch=%x (%d,%d) (%d,%d) pin=%x (%d,%d) linked=%x (%d,%d)",
outCh,
outCh->gcr_area.r_xbot, outCh->gcr_area.r_ybot,
outCh->gcr_area.r_xtop, outCh->gcr_area.r_ytop,
inPin, inPin->gcr_point.p_x, inPin->gcr_point.p_y,
inPin->gcr_linked, linkedPt.p_x, linkedPt.p_y);
nrMore(mesg);
nrShowRect(EditCellUse->cu_def, &r, STYLE_ERASEHIGHLIGHTS);
if (outPin->gcr_linked) linkedPt = outPin->gcr_linked->gcr_point;
else linkedPt = TiPlaneRect.r_ll;
(void) sprintf(mesg,
"EXIT ch=%x (%d,%d) (%d,%d) %d/%d pin=%x (%d,%d) linked=%x (%d,%d)",
outCh,
outCh->gcr_area.r_xbot, outCh->gcr_area.r_ybot,
outCh->gcr_area.r_xtop, outCh->gcr_area.r_ytop,
prevCost, distCost,
outPin, outPin->gcr_point.p_x, outPin->gcr_point.p_y,
outPin->gcr_linked, linkedPt.p_x, linkedPt.p_y);
r.r_ll = r.r_ur = outPin->gcr_point;
r.r_xtop++, r.r_ytop++;
nrShowRect(EditCellUse->cu_def, &r, STYLE_SOLIDHIGHLIGHTS);
nrMore(mesg);
nrShowRect(EditCellUse->cu_def, &r, STYLE_ERASEHIGHLIGHTS);
}
/*
* ----------------------------------------------------------------------------
*
* glLogPath --
*
* Print information about the point 'inPt' to the file glLogFile,
* but only if this is the first time the point was removed from
* the heap (indicated by inPt->gl_range being the same as glInitRect.)
*
* Results:
* None.
*
* Side effects:
* May print to glLogFile.
*
* ----------------------------------------------------------------------------
*/
void
glLogPath(inPt, cost)
GlPoint *inPt;
int cost;
{
extern Rect glInitRect;
if (bcmp((char *)&inPt->gl_range, (char *)&glInitRect, sizeof (Rect)) == 0)
{
fprintf(glLogFile, "TOP\t%d\t%d,%d\t%d\t%d\n",
glNumTries,
inPt->gl_point.p_x, inPt->gl_point.p_y,
inPt->gl_length, cost);
}
}
/*
* ----------------------------------------------------------------------------
*
* glPrintPoint --
*
* Print information about the GlPoint 'inPt'.
*
* Results:
* None.
*
* Side effects:
* Prints to the terminal.
*
* ----------------------------------------------------------------------------
*/
void
glPrintPoint(inPt)
GlPoint *inPt;
{
TxPrintf("(%d,%d) l=%d p=0x%x c=0x%x",
inPt->gl_point.p_x, inPt->gl_point.p_y,
inPt->gl_length, inPt->gl_pin, inPt->gl_ch);
}