/* * 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 #include #include #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, (cb_heap_kill_t) NULL); HeapKill(&glProximityHeap, (cb_heap_kill_t) 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); }