796 lines
24 KiB
C
796 lines
24 KiB
C
|
|
/*
|
|||
|
|
* grouteCross.c -
|
|||
|
|
*
|
|||
|
|
* Global signal router. Code to do crossing placement.
|
|||
|
|
*
|
|||
|
|
* *********************************************************************
|
|||
|
|
* * 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. *
|
|||
|
|
* *********************************************************************
|
|||
|
|
* Lawrence Livermore National Laboratory
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
#ifndef lint
|
|||
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/grouter/grouteCrss.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
|||
|
|
#endif /* not lint */
|
|||
|
|
|
|||
|
|
#include <stdio.h>
|
|||
|
|
#include <string.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"
|
|||
|
|
|
|||
|
|
/* Passed to glCrossChoose() */
|
|||
|
|
GlPoint *glCrossLookAhead;
|
|||
|
|
|
|||
|
|
/* The following penalties get scaled by RtrGridSpacing */
|
|||
|
|
int glJogPenalty = 5;
|
|||
|
|
int glObsPenalty1 = 5, glObsPenalty2 = 3;
|
|||
|
|
int glNbrPenalty1 = 2, glNbrPenalty2 = 5;
|
|||
|
|
int glOrphanPenalty = 3;
|
|||
|
|
int glChanPenalty = 1;
|
|||
|
|
bool glPenaltiesScaled = FALSE;
|
|||
|
|
|
|||
|
|
/* Forward declarations */
|
|||
|
|
GlPoint *glCrossAdjust();
|
|||
|
|
int glCrossChoose();
|
|||
|
|
void glCrossTakePin();
|
|||
|
|
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*
|
|||
|
|
* glCrossMark --
|
|||
|
|
*
|
|||
|
|
* Mark all the pins crossed by the linked list of GlPoints pointed to
|
|||
|
|
* by 'path' as taken. This list is linked along the gl_path pointers.
|
|||
|
|
* The starting entry 'path' indicates a pin reserved for a NLTermLoc;
|
|||
|
|
* the last entry is one of the pins on the previous starting-point list.
|
|||
|
|
*
|
|||
|
|
* Results:
|
|||
|
|
* None.
|
|||
|
|
*
|
|||
|
|
* Side effects:
|
|||
|
|
* Marks the pins along the path as taken by 'net'.
|
|||
|
|
* Assigns a segment identifier to each pin that is different
|
|||
|
|
* for each pair of GlPoints in the path.
|
|||
|
|
* Increments pNetId->netid_seg once for each new segment identifier
|
|||
|
|
* created.
|
|||
|
|
* Updates the density information in each channel as the pins are
|
|||
|
|
* marked as taken.
|
|||
|
|
*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
void
|
|||
|
|
glCrossMark(rootUse, path, pNetId)
|
|||
|
|
CellUse *rootUse; /* For error feedback if non-NULL */
|
|||
|
|
GlPoint *path; /* Path linked via gl_path pointers */
|
|||
|
|
NetId *pNetId; /* Net and segment identifier; netid_seg is updated */
|
|||
|
|
{
|
|||
|
|
GCRPin *srcPin, *dstPin;
|
|||
|
|
GlPoint *rp;
|
|||
|
|
bool srcTaken;
|
|||
|
|
NetId markNetId;
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* Walk from path back along gl_path pointers down the list.
|
|||
|
|
* At each step, process the segment between srcPin and
|
|||
|
|
* dstPin in the channel srcPin->gcr_ch.
|
|||
|
|
*/
|
|||
|
|
for (rp = path; rp->gl_path; rp = rp->gl_path)
|
|||
|
|
{
|
|||
|
|
/*
|
|||
|
|
* Increment the segment id once for each channel the net passes
|
|||
|
|
* through. The intent is to make this net appear different to
|
|||
|
|
* the channel router for each global segment processed.
|
|||
|
|
*/
|
|||
|
|
pNetId->netid_seg++;
|
|||
|
|
glCrossingsUsed++;
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* Figure out which segment number to use:
|
|||
|
|
* If srcPin has already been assigned a net, use its segment id
|
|||
|
|
* to mark dstPin and don't do anything to srcPin; otherwise,
|
|||
|
|
* use pNetId->netid_seg as the segment identifier and mark
|
|||
|
|
* both pins as taken.
|
|||
|
|
*/
|
|||
|
|
markNetId = *pNetId;
|
|||
|
|
srcPin = rp->gl_path->gl_pin;
|
|||
|
|
srcTaken = srcPin->gcr_pId && srcPin->gcr_pSeg != GCR_STEMSEGID;
|
|||
|
|
if (srcTaken)
|
|||
|
|
markNetId.netid_seg = srcPin->gcr_pSeg;
|
|||
|
|
|
|||
|
|
/* Pick the dest pin in the same channel as srcPin */
|
|||
|
|
dstPin = rp->gl_pin;
|
|||
|
|
if (dstPin->gcr_ch != srcPin->gcr_ch) dstPin = dstPin->gcr_linked;
|
|||
|
|
ASSERT(dstPin&&dstPin->gcr_ch == srcPin->gcr_ch, "glCrossMark");
|
|||
|
|
|
|||
|
|
/* Adjust the density -- must happen before pins are marked! */
|
|||
|
|
if (glDensAdjust(((GlobChan *) srcPin->gcr_ch->gcr_client)->gc_postDens,
|
|||
|
|
srcPin, dstPin, markNetId))
|
|||
|
|
glChanBlockDens(srcPin->gcr_ch);
|
|||
|
|
|
|||
|
|
/* Mark pins as taken */
|
|||
|
|
if (!srcTaken)
|
|||
|
|
glCrossTakePin(rootUse, srcPin, markNetId);
|
|||
|
|
glCrossTakePin(rootUse, dstPin, markNetId);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*
|
|||
|
|
* glCrossTakePin --
|
|||
|
|
*
|
|||
|
|
* Reserve a channel's pin for the given net.
|
|||
|
|
* Make a number of sanity checks.
|
|||
|
|
*
|
|||
|
|
* Results:
|
|||
|
|
* None.
|
|||
|
|
*
|
|||
|
|
* Side effects:
|
|||
|
|
* Marks the pin as being taken by the net, by setting
|
|||
|
|
* gcr_pId and gcr_pSeg.
|
|||
|
|
*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
void
|
|||
|
|
glCrossTakePin(rootUse, pin, netid)
|
|||
|
|
CellUse *rootUse; /* For error feedback if non-NULL */
|
|||
|
|
GCRPin *pin; /* Pin to take */
|
|||
|
|
NetId netid; /* Identifier to assign */
|
|||
|
|
{
|
|||
|
|
char c[256], name1[1024], name2[1024];
|
|||
|
|
Rect r;
|
|||
|
|
|
|||
|
|
if (DebugIsSet(glDebugID, glDebGreedy))
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
if (DebugIsSet(glDebugID, glDebCross))
|
|||
|
|
{
|
|||
|
|
glShowCross(pin, netid, CROSS_PERM);
|
|||
|
|
TxMore("-- crossing --");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
r.r_ll = r.r_ur = pin->gcr_point; r.r_xtop++; r.r_ytop++;
|
|||
|
|
ASSERT(netid.netid_net != (NLNet *) NULL, "glCrossTakePin");
|
|||
|
|
|
|||
|
|
if (pin->gcr_pId == (GCRNet *) NULL
|
|||
|
|
|| (pin->gcr_pId == (GCRNet *) netid.netid_net
|
|||
|
|
&& pin->gcr_pSeg == GCR_STEMSEGID))
|
|||
|
|
{
|
|||
|
|
pin->gcr_pId = (GCRNet *) netid.netid_net;
|
|||
|
|
pin->gcr_pSeg = netid.netid_seg;
|
|||
|
|
|
|||
|
|
/* Unlink from list along channel side */
|
|||
|
|
if (pin->gcr_pPrev && (pin->gcr_pPrev->gcr_pNext = pin->gcr_pNext))
|
|||
|
|
pin->gcr_pNext->gcr_pPrev = pin->gcr_pPrev;
|
|||
|
|
}
|
|||
|
|
else if (pin->gcr_pId == (GCRNet *) netid.netid_net
|
|||
|
|
&& pin->gcr_pSeg == netid.netid_seg)
|
|||
|
|
{
|
|||
|
|
(void) sprintf(c, "Warning: crossing reassigned to same net/seg");
|
|||
|
|
if (rootUse)
|
|||
|
|
DBWFeedbackAdd(&r, c, rootUse->cu_def, 1, STYLE_PALEHIGHLIGHTS);
|
|||
|
|
else TxError("%s\n", c);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
/* Shouldn't happen: indicates a bug elsewhere */
|
|||
|
|
(void) strcpy(name1, NLNetName(pin->gcr_pId));
|
|||
|
|
(void) strcpy(name2, NLNetName(netid.netid_net));
|
|||
|
|
(void) sprintf(c, "Crossing multiply used, nets %s/%d, %s/%d",
|
|||
|
|
name1, pin->gcr_pSeg, name2, netid.netid_seg);
|
|||
|
|
if (rootUse)
|
|||
|
|
DBWFeedbackAdd(&r, c, rootUse->cu_def, 1, STYLE_PALEHIGHLIGHTS);
|
|||
|
|
else TxError("%s\n", c);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*
|
|||
|
|
* glCrossUnreserve --
|
|||
|
|
*
|
|||
|
|
* Visit all of the pins used by the stems of the NLNet 'net' and reset
|
|||
|
|
* the gcr_pId and gcr_pSeg fields to show a NULL net and no segment id.
|
|||
|
|
* This procedure is called only just prior to the global routing for each
|
|||
|
|
* net; it keeps the crossings that might be used by this net reserved up
|
|||
|
|
* until the last possible minute, but makes sure that they don't stay
|
|||
|
|
* reserved once we actually know the routing for this net (since otherwise
|
|||
|
|
* the channel router would try to connect them up!).
|
|||
|
|
*
|
|||
|
|
* Results:
|
|||
|
|
* None.
|
|||
|
|
*
|
|||
|
|
* Side effects:
|
|||
|
|
* See above.
|
|||
|
|
*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
void
|
|||
|
|
glCrossUnreserve(net)
|
|||
|
|
NLNet *net;
|
|||
|
|
{
|
|||
|
|
NLTermLoc *loc;
|
|||
|
|
NLTerm *term;
|
|||
|
|
GCRPin *pin;
|
|||
|
|
|
|||
|
|
/* De-reserve the pins taken by each terminal location in this net */
|
|||
|
|
for (term = net->nnet_terms; term; term = term->nterm_next)
|
|||
|
|
for (loc = term->nterm_locs; loc; loc = loc->nloc_next)
|
|||
|
|
{
|
|||
|
|
pin = loc->nloc_pin;
|
|||
|
|
ASSERT(pin->gcr_pSeg == GCR_STEMSEGID, "glCrossUnreserve");
|
|||
|
|
pin->gcr_pId = (GCRNet *) NULL;
|
|||
|
|
pin->gcr_pSeg = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*
|
|||
|
|
* glCrossEnum --
|
|||
|
|
*
|
|||
|
|
* Enumerate the crossing points between the tile inPt->gl_tile
|
|||
|
|
* and 'tp'. The two tiles should overlap different channels.
|
|||
|
|
*
|
|||
|
|
* For each available crossing (i.e., a pin that is yet unassigned
|
|||
|
|
* and has a linked pin), call the procedure (*func)(), which should
|
|||
|
|
* be of the following form:
|
|||
|
|
*
|
|||
|
|
* int
|
|||
|
|
* (*func)(inPt, tp, pin, cdata)
|
|||
|
|
* GlPoint *inPt; /# Same as inPt passed to glCrossEnum #/
|
|||
|
|
* Tile *tp; /# Same as tp passed to glCrossEnum #/
|
|||
|
|
* GCRPin *pin; /# A free pin in 'tp' #/
|
|||
|
|
* ClientData cdata; /# Same as cdata passed to glCrossEnum #/
|
|||
|
|
* {
|
|||
|
|
* }
|
|||
|
|
*
|
|||
|
|
* If (*func)() returns 1, glCrossEnum() immediately stops visiting
|
|||
|
|
* further crossing points and returns 1 itself; otherwise, we keep
|
|||
|
|
* going until we run out of crossing points to visit.
|
|||
|
|
*
|
|||
|
|
* Results:
|
|||
|
|
* Returns 1 if (*func)() returned 1; otherwise, returns 0.
|
|||
|
|
*
|
|||
|
|
* Side effects:
|
|||
|
|
* Whatever (*func)() does.
|
|||
|
|
*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
int
|
|||
|
|
glCrossEnum(inPt, tp, func, cdata)
|
|||
|
|
GlPoint *inPt; /* Top of heap point being expanded */
|
|||
|
|
Tile *tp; /* Tile adjacent to inPt->gl_tile */
|
|||
|
|
int (*func)(); /* Called for each crossing */
|
|||
|
|
ClientData cdata; /* Passed to (*func)() */
|
|||
|
|
{
|
|||
|
|
int outSide, origin, lo, hi, max, start, n, nhi;
|
|||
|
|
GCRChannel *ch = inPt->gl_pin->gcr_ch;
|
|||
|
|
Tile *inTile = inPt->gl_tile;
|
|||
|
|
GCRPin *pins, *pin;
|
|||
|
|
|
|||
|
|
/* Sanity checks: callers should ensure that these are true */
|
|||
|
|
ASSERT(tp->ti_client != (ClientData) CLIENTDEFAULT, "glCrossEnum");
|
|||
|
|
ASSERT((GCRChannel *) tp->ti_client != ch, "glCrossEnum");
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* Find out the direction from inTile to tp.
|
|||
|
|
* We assume that the two tiles share a side, so this
|
|||
|
|
* is pretty straightforward.
|
|||
|
|
*/
|
|||
|
|
if (LEFT(inTile) == RIGHT(tp)) outSide = GEO_WEST;
|
|||
|
|
else if (RIGHT(inTile) == LEFT(tp)) outSide = GEO_EAST;
|
|||
|
|
else if (TOP(inTile) == BOTTOM(tp)) outSide = GEO_NORTH;
|
|||
|
|
else if (BOTTOM(inTile) == TOP(tp)) outSide = GEO_SOUTH;
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* Find the range of points shared between the two tiles.
|
|||
|
|
* Note that we look at the TILES, not the CHANNELS, since
|
|||
|
|
* there can be many tiles for a single channel.
|
|||
|
|
*/
|
|||
|
|
if (outSide == GEO_NORTH || outSide == GEO_SOUTH)
|
|||
|
|
{
|
|||
|
|
lo = MAX(LEFT(inTile), LEFT(tp));
|
|||
|
|
hi = MIN(RIGHT(inTile), RIGHT(tp));
|
|||
|
|
origin = ch->gcr_origin.p_x;
|
|||
|
|
max = ch->gcr_length;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
lo = MAX(BOTTOM(inTile), BOTTOM(tp));
|
|||
|
|
hi = MIN(TOP(inTile), TOP(tp));
|
|||
|
|
origin = ch->gcr_origin.p_y;
|
|||
|
|
max = ch->gcr_width;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* Now find the range of pins shared between the two tiles.
|
|||
|
|
* We're careful about which pins are actually shared: we
|
|||
|
|
* round the lower coordinate up unless it's grid-aligned,
|
|||
|
|
* but round the higher coordinate down even if it is
|
|||
|
|
* grid-aligned. I.e.,
|
|||
|
|
*
|
|||
|
|
* lo' = pin with least coordinate >= lo
|
|||
|
|
* hi' = pin with greatest coordinate < hi
|
|||
|
|
*
|
|||
|
|
* The range of pins shared should be non-NULL; if it's not,
|
|||
|
|
* something is wrong (most likely the channel is too small).
|
|||
|
|
* The pins range from lo to hi, inclusive, and should not
|
|||
|
|
* include pin[0] or pin[length+1] or pin[width+1] (the latter
|
|||
|
|
* respectively for vertical or horizontal edges between tiles).
|
|||
|
|
*/
|
|||
|
|
lo = (lo + RtrGridSpacing - 1 - origin) / RtrGridSpacing;
|
|||
|
|
hi = (hi - origin - 1) / RtrGridSpacing;
|
|||
|
|
ASSERT(lo >= 1 && lo <= max, "glCrossEnum");
|
|||
|
|
if (lo > hi)
|
|||
|
|
return 0;
|
|||
|
|
|
|||
|
|
switch (outSide)
|
|||
|
|
{
|
|||
|
|
case GEO_NORTH: pins = ch->gcr_tPins; break;
|
|||
|
|
case GEO_SOUTH: pins = ch->gcr_bPins; break;
|
|||
|
|
case GEO_EAST: pins = ch->gcr_rPins; break;
|
|||
|
|
case GEO_WEST: pins = ch->gcr_lPins; break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* Now comes the fun part: enumerating pins in the range
|
|||
|
|
* from lo .. hi inclusive in such a way that we visit
|
|||
|
|
* the CLOSEST pin to inPt FIRST. Choose start so that
|
|||
|
|
* it's the index of the closest pin on the exit side to
|
|||
|
|
* inPt, and then worry about whether or not it's in the
|
|||
|
|
* range of pins shared with the next tile.
|
|||
|
|
*/
|
|||
|
|
start = (outSide == GEO_NORTH || outSide == GEO_SOUTH)
|
|||
|
|
? inPt->gl_pin->gcr_x
|
|||
|
|
: inPt->gl_pin->gcr_y;
|
|||
|
|
|
|||
|
|
/* CASE 1: visit from bottom to top (or left to right) */
|
|||
|
|
if (start <= lo)
|
|||
|
|
{
|
|||
|
|
for (n = lo; n <= hi; n++, glCrossingsSeen++)
|
|||
|
|
{
|
|||
|
|
pin = &pins[n];
|
|||
|
|
if (PINOK(pin) && PINOK(pin->gcr_linked)
|
|||
|
|
&& (*func)(inPt, tp, pin->gcr_linked, cdata))
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* CASE 1: visit from top to bottom (or right to left) */
|
|||
|
|
if (start >= hi)
|
|||
|
|
{
|
|||
|
|
for (n = hi; n >= lo; n--, glCrossingsSeen++)
|
|||
|
|
{
|
|||
|
|
pin = &pins[n];
|
|||
|
|
if (PINOK(pin) && PINOK(pin->gcr_linked)
|
|||
|
|
&& (*func)(inPt, tp, pin->gcr_linked, cdata))
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* CASE 3:
|
|||
|
|
* Have to consider candidates alternating from
|
|||
|
|
* left to right (or top to bottom) to find the
|
|||
|
|
* closest available pin. Start at the center.
|
|||
|
|
*/
|
|||
|
|
for (n = start, nhi = start+1; n >= lo || nhi <= hi; n--, nhi++)
|
|||
|
|
{
|
|||
|
|
if (n >= lo)
|
|||
|
|
{
|
|||
|
|
glCrossingsSeen++;
|
|||
|
|
pin = &pins[n];
|
|||
|
|
if (PINOK(pin) && PINOK(pin->gcr_linked)
|
|||
|
|
&& (*func)(inPt, tp, pin->gcr_linked, cdata))
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
if (nhi <= hi)
|
|||
|
|
{
|
|||
|
|
glCrossingsSeen++;
|
|||
|
|
pin = &pins[nhi];
|
|||
|
|
if (PINOK(pin) && PINOK(pin->gcr_linked)
|
|||
|
|
&& (*func)(inPt, tp, pin->gcr_linked, cdata))
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*
|
|||
|
|
* glCrossAdjust --
|
|||
|
|
*
|
|||
|
|
* Given a path of crossing points, wiggle them around in each channel
|
|||
|
|
* to try to reduce the total penalty on the path. Construct a new
|
|||
|
|
* path of crossing points that uses the points we select in this way,
|
|||
|
|
* and whose cost fields (gl_cost) include both distance and the
|
|||
|
|
* penalties. Be careful when wiggling crossings through a river
|
|||
|
|
* routing channel: they all have to wiggle at the same time.
|
|||
|
|
*
|
|||
|
|
* Algorithm:
|
|||
|
|
* Two crossing points in the input path are already fixed:
|
|||
|
|
* path itself, and the crossing point at the very end (the
|
|||
|
|
* one for which gl_path is NULL). Starting from the crossing
|
|||
|
|
* point at the end and working back toward 'path', assign
|
|||
|
|
* crossings to all points in the middle. The procedure to
|
|||
|
|
* do this is recursive, considering at each stage three
|
|||
|
|
* crossing points: one that has already been assigned
|
|||
|
|
* (which is either the last point in the path, or the result
|
|||
|
|
* of the previous recursive call), one that is to be assigned
|
|||
|
|
* (the current point along the path), and a "lookahead" point
|
|||
|
|
* (the one that will be next assigned, so we can consider
|
|||
|
|
* it as well when positining the current point.
|
|||
|
|
*
|
|||
|
|
* Results:
|
|||
|
|
* Returns a pointer to the final point in a new path of crossings,
|
|||
|
|
* linked via their gl_path pointers.
|
|||
|
|
*
|
|||
|
|
* Side effects:
|
|||
|
|
* See above.
|
|||
|
|
*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
GlPoint *
|
|||
|
|
glCrossAdjust(lookAhead, path)
|
|||
|
|
GlPoint *lookAhead; /* Normally, lookAhead->gl_path == path, except on the
|
|||
|
|
* initial call, in which case lookAhead == NULL.
|
|||
|
|
*/
|
|||
|
|
GlPoint *path; /* Adjust crossings along this path */
|
|||
|
|
{
|
|||
|
|
GlPoint *newPath, *newRest;
|
|||
|
|
GCRPin *linkedPin, *pin;
|
|||
|
|
GCRChannel *ch;
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* The location of the last crossing along the path is fixed,
|
|||
|
|
* since it's the "starting point". Simply return when we
|
|||
|
|
* reach this point, since there's no penalty to be computed
|
|||
|
|
* yet.
|
|||
|
|
*/
|
|||
|
|
ASSERT(path != (GlPoint *) NULL, "glCrossAdjust");
|
|||
|
|
if (path->gl_path == (GlPoint *) NULL)
|
|||
|
|
return path;
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* Basic recursive step: assign crossings to everything
|
|||
|
|
* in the remainder of the path, then cons a new GlPoint
|
|||
|
|
* to the front of the path and adjust its position
|
|||
|
|
* below. The initial cost of newPath will be that
|
|||
|
|
* to the pin it initially occupies, before being
|
|||
|
|
* wiggled by glCrossChoose() later. This gives
|
|||
|
|
* us an upper bound on an acceptable cost.
|
|||
|
|
*/
|
|||
|
|
newRest = glCrossAdjust(path, path->gl_path);
|
|||
|
|
newPath = glPathNew(path->gl_pin, 0, newRest);
|
|||
|
|
newPath->gl_cost = newRest->gl_cost + glCrossCost(lookAhead, path, newRest);
|
|||
|
|
newPath->gl_tile = path->gl_tile;
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* If this was the first crossing in the path, it's also
|
|||
|
|
* immutable and so we just cons it to the path and return.
|
|||
|
|
* We still use a new GlPoint, though, since the cost of
|
|||
|
|
* this point has to include the penalties along the path.
|
|||
|
|
*/
|
|||
|
|
if (lookAhead == (GlPoint *) NULL)
|
|||
|
|
return newPath;
|
|||
|
|
|
|||
|
|
if (TiGetType(newRest->gl_tile) != CHAN_NORMAL)
|
|||
|
|
{
|
|||
|
|
/*
|
|||
|
|
* If newRest was through a river-routing channel, it fixes
|
|||
|
|
* the pin on the exit side.
|
|||
|
|
*/
|
|||
|
|
pin = newRest->gl_pin;
|
|||
|
|
ch = pin->gcr_ch;
|
|||
|
|
switch (pin->gcr_side)
|
|||
|
|
{
|
|||
|
|
case GEO_NORTH: linkedPin = &ch->gcr_bPins[pin->gcr_x]; break;
|
|||
|
|
case GEO_EAST: linkedPin = &ch->gcr_lPins[pin->gcr_y]; break;
|
|||
|
|
case GEO_SOUTH: linkedPin = &ch->gcr_tPins[pin->gcr_x]; break;
|
|||
|
|
case GEO_WEST: linkedPin = &ch->gcr_rPins[pin->gcr_y]; break;
|
|||
|
|
}
|
|||
|
|
ASSERT(PINOK(linkedPin), "glCrossAdjust");
|
|||
|
|
newPath->gl_pin = linkedPin->gcr_linked;
|
|||
|
|
newPath->gl_cost = newRest->gl_cost;
|
|||
|
|
newPath->gl_cost += glCrossCost(lookAhead, newPath, newRest);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
/*
|
|||
|
|
* Time to choose a crossing for 'path'.
|
|||
|
|
* It has to lie somewhere along the boundary between path->gl_tile
|
|||
|
|
* and newRest->gl_tile. (These two tiles will be different unless
|
|||
|
|
* path is the destination point, but we checked for that above when
|
|||
|
|
* we looked for lookAhead being NULL). Enumerate the crossings
|
|||
|
|
* along this boundary looking for the best one.
|
|||
|
|
*/
|
|||
|
|
glCrossLookAhead = lookAhead;
|
|||
|
|
(void) glCrossEnum(newRest, path->gl_tile, glCrossChoose,
|
|||
|
|
(ClientData) newPath);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return newPath;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*
|
|||
|
|
* glCrossChoose --
|
|||
|
|
*
|
|||
|
|
* Called by glCrossEnum() on behalf of glCrossAdjust() above.
|
|||
|
|
* Evaluate 'pin' as a possible crossing by computing the penalty of
|
|||
|
|
* a segment from newRest through newPath (setting newPath->gl_pin to
|
|||
|
|
* pin), and on through to glCrossLookAhead (if it's non-NULL).
|
|||
|
|
*
|
|||
|
|
* Results:
|
|||
|
|
* Returns 0 normally, or 1 to tell glCrossEnum() that it
|
|||
|
|
* can stop looking at further crossings.
|
|||
|
|
*
|
|||
|
|
* Side effects:
|
|||
|
|
* May modify newPath->gl_cost and newPath->gl_pin.
|
|||
|
|
*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
/*ARGSUSED*/
|
|||
|
|
int
|
|||
|
|
glCrossChoose(newRest, tp, pin, newPath)
|
|||
|
|
GlPoint *newRest; /* Portion of path already assigned */
|
|||
|
|
Tile *tp; /* UNUSED */
|
|||
|
|
GCRPin *pin; /* Pin on boundary of tp being considered */
|
|||
|
|
GlPoint *newPath; /* Update newPath->gl_pin, newPath->gl_cost */
|
|||
|
|
{
|
|||
|
|
GCRPin *savePin;
|
|||
|
|
int cost;
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* We've been visiting crossings in order of increasing distance
|
|||
|
|
* from newRest. If the distance to 'pin' plus newRest->gl_cost
|
|||
|
|
* already exceeds the best cost we've been able to find for
|
|||
|
|
* newPath, then we can't gain any more improvement by considering
|
|||
|
|
* any more crossing point, so we stop.
|
|||
|
|
*/
|
|||
|
|
cost = ABSDIFF(pin->gcr_point.p_x, newRest->gl_pin->gcr_point.p_x)
|
|||
|
|
+ ABSDIFF(pin->gcr_point.p_y, newRest->gl_pin->gcr_point.p_y)
|
|||
|
|
+ newRest->gl_cost;
|
|||
|
|
if (cost >= newPath->gl_cost)
|
|||
|
|
return 1;
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* Evaluate the cost of using 'pin' as the crossing point.
|
|||
|
|
* If it's a better choice than what's currently stored in newPath,
|
|||
|
|
* then use it and update the cost in newPath.
|
|||
|
|
*/
|
|||
|
|
savePin = newPath->gl_pin;
|
|||
|
|
newPath->gl_pin = pin;
|
|||
|
|
cost = newRest->gl_cost + glCrossCost(glCrossLookAhead, newPath, newRest);
|
|||
|
|
if (cost < newPath->gl_cost)
|
|||
|
|
newPath->gl_cost = cost;
|
|||
|
|
else
|
|||
|
|
newPath->gl_pin = savePin;
|
|||
|
|
|
|||
|
|
/* Keep looking at more crossing points */
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*
|
|||
|
|
* glCrossCost --
|
|||
|
|
*
|
|||
|
|
* Evaluate the cost of the segment from 'entryPt' to 'exitPt' (and on through
|
|||
|
|
* 'lookAhead' if it is non-NULL).
|
|||
|
|
*
|
|||
|
|
* Results:
|
|||
|
|
* Returns the sum of the distance from rest to path and the
|
|||
|
|
* penalties associated with this segment.
|
|||
|
|
*
|
|||
|
|
* Side effects:
|
|||
|
|
* None.
|
|||
|
|
*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
int
|
|||
|
|
glCrossCost(lookAhead, exitPt, entryPt)
|
|||
|
|
GlPoint *lookAhead;
|
|||
|
|
GlPoint *exitPt;
|
|||
|
|
GlPoint *entryPt;
|
|||
|
|
{
|
|||
|
|
GCRPin *entryPin, *exitPin, *otherPin;
|
|||
|
|
GCRPin *opposite;
|
|||
|
|
int count, cost;
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* Make sure that both entryPin and exitPin are in the same
|
|||
|
|
* channel, and otherPin is in the next channel.
|
|||
|
|
*/
|
|||
|
|
entryPin = entryPt->gl_pin;
|
|||
|
|
exitPin = exitPt->gl_pin;
|
|||
|
|
if (exitPin->gcr_ch != entryPin->gcr_ch)
|
|||
|
|
exitPin = exitPin->gcr_linked;
|
|||
|
|
otherPin = exitPin->gcr_linked;
|
|||
|
|
ASSERT(exitPin != NULL, "glCrossCost");
|
|||
|
|
|
|||
|
|
/* Distance cost */
|
|||
|
|
cost = ABSDIFF(entryPin->gcr_point.p_x, exitPin->gcr_point.p_x)
|
|||
|
|
+ ABSDIFF(entryPin->gcr_point.p_y, exitPin->gcr_point.p_y);
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* If exitPt is in a river-routing tile, and we have to continue
|
|||
|
|
* across the channel (lookAhead is non-NULL), then make sure the pin
|
|||
|
|
* on the opposite side is free; otherwise, exitPt has "infinite"
|
|||
|
|
* penalty since it's unusable.
|
|||
|
|
*/
|
|||
|
|
if (lookAhead && TiGetType(exitPt->gl_tile) != CHAN_NORMAL)
|
|||
|
|
{
|
|||
|
|
switch (otherPin->gcr_side)
|
|||
|
|
{
|
|||
|
|
case GEO_NORTH:
|
|||
|
|
opposite = &otherPin->gcr_ch->gcr_bPins[otherPin->gcr_x];
|
|||
|
|
break;
|
|||
|
|
case GEO_SOUTH:
|
|||
|
|
opposite = &otherPin->gcr_ch->gcr_tPins[otherPin->gcr_x];
|
|||
|
|
break;
|
|||
|
|
case GEO_EAST:
|
|||
|
|
opposite = &otherPin->gcr_ch->gcr_lPins[otherPin->gcr_y];
|
|||
|
|
break;
|
|||
|
|
case GEO_WEST:
|
|||
|
|
opposite = &otherPin->gcr_ch->gcr_rPins[otherPin->gcr_y];
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
if (!PINOK(opposite))
|
|||
|
|
return INFINITY;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* Penalty for using lots of channels */
|
|||
|
|
cost += glChanPenalty;
|
|||
|
|
|
|||
|
|
/* Penalize if the net doesn't run straight across the channel */
|
|||
|
|
if (entryPin->gcr_x != exitPin->gcr_x && entryPin->gcr_y != exitPin->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)
|
|||
|
|
if (otherPin && otherPin->gcr_ch->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 channel is used for river-routing (in which
|
|||
|
|
* case the subsequent penalty computation is not needed).
|
|||
|
|
*/
|
|||
|
|
if (entryPin->gcr_ch->gcr_type != CHAN_NORMAL)
|
|||
|
|
return cost;
|
|||
|
|
|
|||
|
|
if ((exitPin->gcr_pFlags & BADCROSSFLAGS) || exitPin->gcr_pSize != 0)
|
|||
|
|
{
|
|||
|
|
ASSERT(exitPin->gcr_pSize >= 0, "glCrossPenalty");
|
|||
|
|
cost += glObsPenalty1;
|
|||
|
|
if (exitPin->gcr_pFlags & GCROBST)
|
|||
|
|
cost += glObsPenalty2 * exitPin->gcr_pSize;
|
|||
|
|
else if (exitPin->gcr_pFlags & GCRHAZRD)
|
|||
|
|
cost += MAX(glObsPenalty2 * exitPin->gcr_pSize
|
|||
|
|
- exitPin->gcr_pDist, 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* Penalty for "congestion" (neighboring pins in use) */
|
|||
|
|
count = 0;
|
|||
|
|
if ((exitPin + 1)->gcr_pId) count++;
|
|||
|
|
if ((exitPin - 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, assess a penalty.
|
|||
|
|
*/
|
|||
|
|
if (exitPin->gcr_side != GeoOppositePos[entryPin->gcr_side])
|
|||
|
|
{
|
|||
|
|
switch (exitPin->gcr_side)
|
|||
|
|
{
|
|||
|
|
case GEO_NORTH:
|
|||
|
|
otherPin = &entryPin->gcr_ch->gcr_bPins[exitPin->gcr_x];
|
|||
|
|
break;
|
|||
|
|
case GEO_SOUTH:
|
|||
|
|
otherPin = &entryPin->gcr_ch->gcr_tPins[exitPin->gcr_x];
|
|||
|
|
break;
|
|||
|
|
case GEO_EAST:
|
|||
|
|
otherPin = &entryPin->gcr_ch->gcr_lPins[exitPin->gcr_y];
|
|||
|
|
break;
|
|||
|
|
case GEO_WEST:
|
|||
|
|
otherPin = &entryPin->gcr_ch->gcr_rPins[exitPin->gcr_y];
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
if (otherPin->gcr_pId == (GCRNet *) NULL)
|
|||
|
|
cost += glOrphanPenalty;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return cost;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
* ----------------------------------------------------------------------------
|
|||
|
|
*
|
|||
|
|
* glCrossScalePenalties --
|
|||
|
|
*
|
|||
|
|
* 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
|
|||
|
|
glCrossScalePenalties()
|
|||
|
|
{
|
|||
|
|
if (glPenaltiesScaled)
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
glPenaltiesScaled = TRUE;
|
|||
|
|
glJogPenalty *= RtrGridSpacing;
|
|||
|
|
glObsPenalty1 *= RtrGridSpacing;
|
|||
|
|
glObsPenalty2 *= RtrGridSpacing;
|
|||
|
|
glNbrPenalty1 *= RtrGridSpacing;
|
|||
|
|
glNbrPenalty2 *= RtrGridSpacing;
|
|||
|
|
glOrphanPenalty *= RtrGridSpacing;
|
|||
|
|
glChanPenalty *= RtrGridSpacing;
|
|||
|
|
}
|