481 lines
13 KiB
C
481 lines
13 KiB
C
/*
|
||
* groutePin.c --
|
||
*
|
||
* Global signal router code to implement operations on pins at
|
||
* the boundaries of channels.
|
||
*
|
||
* *********************************************************************
|
||
* * 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[] = "@(#)groutePin.c 4.9 MAGIC (Berkeley) 12/8/85";
|
||
#endif /* not lint */
|
||
|
||
#include <stdio.h>
|
||
#include "utils/magic.h"
|
||
#include "utils/geometry.h"
|
||
#include "utils/styles.h"
|
||
#include "utils/hash.h"
|
||
#include "utils/heap.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 "textio/textio.h"
|
||
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* glPointToPin --
|
||
*
|
||
* Given a point somewhere on the perimeter of a channel, determine
|
||
* which pin it refers to.
|
||
*
|
||
* Results:
|
||
* Pointer to the pin struct whose location is given by pt.
|
||
*
|
||
* Side effects:
|
||
* None.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
GCRPin *
|
||
glPointToPin(ch, side, point)
|
||
GCRChannel *ch; /* The channel containing the point */
|
||
int side; /* Side of ch that point lies on */
|
||
Point *point; /* The point to be converted to a pin */
|
||
{
|
||
int coord;
|
||
|
||
switch (side)
|
||
{
|
||
case GEO_NORTH:
|
||
coord = (point->p_x - ch->gcr_origin.p_x) / RtrGridSpacing;
|
||
ASSERT(coord <= ch->gcr_length && coord >= 1, "glPointToPin");
|
||
return &ch->gcr_tPins[coord];
|
||
break;
|
||
|
||
case GEO_SOUTH:
|
||
coord = (point->p_x - ch->gcr_origin.p_x) / RtrGridSpacing;
|
||
ASSERT(coord <= ch->gcr_length && coord >= 1, "glPointToPin");
|
||
return &ch->gcr_bPins[coord];
|
||
break;
|
||
|
||
case GEO_EAST:
|
||
coord = (point->p_y - ch->gcr_origin.p_y) / RtrGridSpacing;
|
||
ASSERT(coord <= ch->gcr_width && coord >= 1, "glPointToPin");
|
||
return &ch->gcr_rPins[coord];
|
||
break;
|
||
|
||
case GEO_WEST:
|
||
coord = (point->p_y - ch->gcr_origin.p_y) / RtrGridSpacing;
|
||
ASSERT(coord <= ch->gcr_width && coord >= 1, "glPointToPin");
|
||
return &ch->gcr_lPins[coord];
|
||
break;
|
||
}
|
||
|
||
/*
|
||
* The pin is not on a side of the channel.
|
||
* Recover by returning a strange value which should
|
||
* not hurt anything.
|
||
*/
|
||
ASSERT(FALSE, "Pin not on side of channel in glPointToPin");
|
||
return &ch->gcr_lPins[0];
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* GLInitPins --
|
||
*
|
||
* Initialize the global-router specific information for the pins
|
||
* around the periphery of the channel 'ch':
|
||
*
|
||
* gcr_ch Points back to the channel.
|
||
* gcr_cost Set to INFINITY.
|
||
* gcr_side Set to the side of the channel to which this pin
|
||
* belongs (GEO_NORTH, GEO_SOUTH, etc).
|
||
* gcr_point Set to the absolute (edit cell) coordinates
|
||
* of the crossing point associated with this pin.
|
||
* gcr_linked Points to the pin on the other side of this pin's
|
||
* crossing, or is NULL if there is no other pin.
|
||
* The gcr_linked field is set to NULL if crossing
|
||
* from a pin to the neighboring channel would exit
|
||
* a river-routing channel from an illegal side.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* See above.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
GLInitPins(ch)
|
||
GCRChannel *ch;
|
||
{
|
||
glPinArrayInit(ch, GEO_NORTH, ch->gcr_tPins, ch->gcr_length);
|
||
glPinArrayInit(ch, GEO_SOUTH, ch->gcr_bPins, ch->gcr_length);
|
||
glPinArrayInit(ch, GEO_WEST, ch->gcr_lPins, ch->gcr_width);
|
||
glPinArrayInit(ch, GEO_EAST, ch->gcr_rPins, ch->gcr_width);
|
||
}
|
||
|
||
int
|
||
glPinArrayInit(ch, side, pins, nPins)
|
||
GCRChannel *ch;
|
||
GCRPin *pins;
|
||
int nPins;
|
||
{
|
||
GCRPin *pin, *linked;
|
||
GCRChannel *adjacent;
|
||
GCRPin *lastPin;
|
||
Point point, p;
|
||
bool markLinked;
|
||
int otherSide;
|
||
Tile *tp;
|
||
|
||
/*
|
||
* If exiting this channel from an illegal side, all gcr_linked fields
|
||
* are set to NULL.
|
||
*/
|
||
markLinked = TRUE;
|
||
switch (side)
|
||
{
|
||
case GEO_EAST:
|
||
case GEO_WEST:
|
||
if (ch->gcr_type == CHAN_VRIVER)
|
||
markLinked = FALSE;
|
||
break;
|
||
case GEO_NORTH:
|
||
case GEO_SOUTH:
|
||
if (ch->gcr_type == CHAN_HRIVER)
|
||
markLinked = FALSE;
|
||
break;
|
||
}
|
||
|
||
lastPin = &pins[nPins + 1];
|
||
for (pin = pins; pin <= lastPin; pin++)
|
||
{
|
||
pin->gcr_ch = ch;
|
||
pin->gcr_side = side;
|
||
pin->gcr_cost = INFINITY;
|
||
pin->gcr_linked = (GCRPin *) NULL;
|
||
otherSide = GeoOppositePos[side];
|
||
|
||
/* Figure out the crossing point */
|
||
switch (side)
|
||
{
|
||
case GEO_WEST:
|
||
point.p_y = ch->gcr_origin.p_y + pin->gcr_y * RtrGridSpacing;
|
||
point.p_x = ch->gcr_area.r_xbot;
|
||
break;
|
||
case GEO_SOUTH:
|
||
point.p_x = ch->gcr_origin.p_x + pin->gcr_x * RtrGridSpacing;
|
||
point.p_y = ch->gcr_area.r_ybot;
|
||
break;
|
||
case GEO_EAST:
|
||
point.p_y = ch->gcr_origin.p_y + pin->gcr_y * RtrGridSpacing;
|
||
point.p_x = ch->gcr_area.r_xtop;
|
||
break;
|
||
case GEO_NORTH:
|
||
point.p_x = ch->gcr_origin.p_x + pin->gcr_x * RtrGridSpacing;
|
||
point.p_y = ch->gcr_area.r_ytop;
|
||
break;
|
||
default:
|
||
ASSERT(FALSE, "bad pin side in rtrInitPinArray");
|
||
break;
|
||
}
|
||
pin->gcr_point = point;
|
||
|
||
/* Don't set gcr_linked if exiting the channel from an illegal side */
|
||
if (!markLinked)
|
||
continue;
|
||
|
||
if (pin > pins && pin < lastPin)
|
||
{
|
||
/*
|
||
* Find the adjacent channel at that point.
|
||
* If one exists, find the pin in it that shares
|
||
* this pin's crossing.
|
||
*/
|
||
p = point;
|
||
if (side == GEO_WEST) p.p_x--;
|
||
if (side == GEO_SOUTH) p.p_y--;
|
||
tp = TiSrPointNoHint(RtrChannelPlane, &p);
|
||
if (adjacent = (GCRChannel *) tp->ti_client)
|
||
{
|
||
/* Only link if entering the linked channel from a legal side */
|
||
linked = glPointToPin(adjacent, otherSide, &point);
|
||
switch (side)
|
||
{
|
||
case GEO_EAST:
|
||
case GEO_WEST:
|
||
if (adjacent->gcr_type != CHAN_VRIVER)
|
||
pin->gcr_linked = linked;
|
||
break;
|
||
case GEO_NORTH:
|
||
case GEO_SOUTH:
|
||
if (adjacent->gcr_type != CHAN_HRIVER)
|
||
pin->gcr_linked = linked;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* GLBlockPins --
|
||
*
|
||
* Propagate blocked pin information. If a pin is blocked on one side
|
||
* of a channel BOUNDARY, it is blocked on the other side as well. If
|
||
* a pin on one side of a river-routing CHANNEL is blocked, the pin on
|
||
* the other side gets blocked too. Several iterations may be necessary
|
||
* to propagate blockages across all channel boundaries and river-routing
|
||
* channels.
|
||
*
|
||
* Also propagate obstacle flags for pins. If a pin's obstacle flags
|
||
* contain GCROBST, then set this bit in gcr_linked's flags as well.
|
||
*
|
||
* Results:
|
||
* TRUE if the blockage state of any pins changed, FALSE
|
||
* otherwise. The caller should iterate over all channels
|
||
* until no pins change any more.
|
||
*
|
||
* Side effects:
|
||
* Propagating a blockage to a pin consists of marking its
|
||
* gcr_pId with GCR_BLOCKEDNETID, and setting the GCRBLK flag
|
||
* in its gcr_pFlags (this latter only happens for gcr_linked
|
||
* pins, not for pins on the opposite side of a river-routing
|
||
* channel from a blocked pin).
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
bool
|
||
GLBlockPins(ch)
|
||
GCRChannel *ch;
|
||
{
|
||
bool changed;
|
||
|
||
changed = FALSE;
|
||
if (glPinArrayBlock(ch, ch->gcr_tPins, ch->gcr_bPins, ch->gcr_length))
|
||
changed = TRUE;
|
||
if (glPinArrayBlock(ch, ch->gcr_bPins, ch->gcr_tPins, ch->gcr_length))
|
||
changed = TRUE;
|
||
if (glPinArrayBlock(ch, ch->gcr_lPins, ch->gcr_rPins, ch->gcr_width))
|
||
changed = TRUE;
|
||
if (glPinArrayBlock(ch, ch->gcr_rPins, ch->gcr_lPins, ch->gcr_width))
|
||
changed = TRUE;
|
||
|
||
return changed;
|
||
}
|
||
|
||
bool
|
||
glPinArrayBlock(ch, pins, opins, nPins)
|
||
GCRChannel *ch; /* Channel pins belong to */
|
||
GCRPin *pins; /* Processing this side of channel */
|
||
GCRPin *opins; /* Pins on opposite side; used only if ch is a
|
||
* river-routing channel.
|
||
*/
|
||
int nPins; /* Number of internal pins (not counting pins[0]) */
|
||
{
|
||
bool changed, isRiver = (ch->gcr_type != CHAN_NORMAL);
|
||
GCRPin *pin, *opin, *linked;
|
||
GCRPin *lastPin;
|
||
|
||
changed = FALSE;
|
||
lastPin = &pins[nPins];
|
||
for (pin = pins + 1, opin = opins + 1; pin <= lastPin; pin++, opin++)
|
||
{
|
||
linked = pin->gcr_linked;
|
||
|
||
/* Propagate blockages */
|
||
if (pin->gcr_pId == GCR_BLOCKEDNETID)
|
||
{
|
||
if (linked && linked->gcr_pId == (GCRNet *) NULL)
|
||
{
|
||
linked->gcr_pFlags |= GCRBLK;
|
||
linked->gcr_pId = GCR_BLOCKEDNETID;
|
||
changed = TRUE;
|
||
}
|
||
if (isRiver && opin->gcr_pId == (GCRNet *) NULL)
|
||
opin->gcr_pId = GCR_BLOCKEDNETID, changed = TRUE;
|
||
}
|
||
|
||
/* Propagate obstacle flags */
|
||
if ((pin->gcr_pFlags & GCROBST) && linked)
|
||
linked->gcr_pFlags |= GCROBST;
|
||
}
|
||
|
||
return changed;
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* GLLinkPins --
|
||
*
|
||
* Link the "usable" pins along each side of a channel into a doubly-linked
|
||
* list headed by the zero-th pin along that side. Usable pins (for purposes
|
||
* of global routing) are those that are unassigned (gcr_pId == 0) and that
|
||
* have gcr_linked != NULL.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* See above.
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
GLLinkPins(ch)
|
||
GCRChannel *ch;
|
||
{
|
||
glPinArrayLink(ch->gcr_tPins, ch->gcr_length);
|
||
glPinArrayLink(ch->gcr_bPins, ch->gcr_length);
|
||
glPinArrayLink(ch->gcr_lPins, ch->gcr_width);
|
||
glPinArrayLink(ch->gcr_rPins, ch->gcr_width);
|
||
}
|
||
|
||
int
|
||
glPinArrayLink(pins, nPins)
|
||
GCRPin *pins;
|
||
int nPins;
|
||
{
|
||
GCRPin *pin, *lastPin, *lastValid;
|
||
|
||
lastPin = &pins[nPins];
|
||
lastValid = pins;
|
||
lastValid->gcr_pPrev = lastValid->gcr_pNext = (GCRPin *) NULL;
|
||
for (pin = pins + 1; pin <= lastPin; pin++)
|
||
{
|
||
pin->gcr_pNext = pin->gcr_pPrev = (GCRPin *) NULL;
|
||
if (pin->gcr_linked && pin->gcr_pId == (GCRNet *) NULL)
|
||
{
|
||
lastValid->gcr_pNext = pin;
|
||
pin->gcr_pPrev = lastValid;
|
||
lastValid = pin;
|
||
}
|
||
if (DebugIsSet(glDebugID, glDebShowPins))
|
||
glShowPin(pin);
|
||
}
|
||
}
|
||
|
||
glShowPin(pin)
|
||
GCRPin *pin;
|
||
{
|
||
char mesg[256];
|
||
Rect r, area;
|
||
Point p;
|
||
|
||
p = pin->gcr_point;
|
||
switch (pin->gcr_side)
|
||
{
|
||
case GEO_NORTH:
|
||
p.p_y = RTR_GRIDDOWN(p.p_y, RtrOrigin.p_y);
|
||
break;
|
||
case GEO_SOUTH:
|
||
p.p_y = RTR_GRIDUP(p.p_y, RtrOrigin.p_y);
|
||
break;
|
||
case GEO_EAST:
|
||
p.p_x = RTR_GRIDDOWN(p.p_x, RtrOrigin.p_x);
|
||
break;
|
||
case GEO_WEST:
|
||
p.p_x = RTR_GRIDUP(p.p_x, RtrOrigin.p_x);
|
||
break;
|
||
}
|
||
|
||
r.r_ll = r.r_ur = p;
|
||
r.r_xtop += 4, r.r_ytop += 4;
|
||
|
||
area = pin->gcr_ch->gcr_area;
|
||
(void) sprintf(mesg,
|
||
"ChanType=%d grid=(%d,%d) point=(%d,%d) Net=%d, linked=0x%x",
|
||
pin->gcr_ch->gcr_type,
|
||
pin->gcr_x, pin->gcr_y,
|
||
pin->gcr_point.p_x, pin->gcr_point.p_y,
|
||
pin->gcr_pId, pin->gcr_linked);
|
||
if (pin->gcr_pId || pin->gcr_linked == NULL)
|
||
(void) strcat(mesg, " **BLOCKED**");
|
||
else DBWFeedbackAdd(&r, mesg, EditCellUse->cu_def, 1, STYLE_PALEHIGHLIGHTS);
|
||
#ifdef notdef
|
||
nrShowRect(EditCellUse->cu_def, &r, STYLE_SOLIDHIGHLIGHTS);
|
||
nrMore(mesg);
|
||
nrShowRect(EditCellUse->cu_def, &r, STYLE_ERASEHIGHLIGHTS);
|
||
#endif /* notdef */
|
||
}
|
||
|
||
/*
|
||
* ----------------------------------------------------------------------------
|
||
*
|
||
* GLFixStemPins --
|
||
*
|
||
* Only some of the crossing points marked during stem assignment were
|
||
* actually used during global routing. The unused ones have gcr_pSeg
|
||
* equal to GCR_STEMSEGID and must be unmarked here (otherwise the channel
|
||
* router will try to route them!).
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* For each pin on the boundary of 'ch' that is marked as in use
|
||
* (gcr_pId != 0 && gcr_pId != GCR_BLOCKEDNETID) and that has a segment
|
||
* id of GCR_STEMSEGID (gcr_pSeg == GCR_STEMSEGID), mark it as unused
|
||
* (gcr_pId == 0).
|
||
*
|
||
* ----------------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
GLFixStemPins(ch)
|
||
GCRChannel *ch;
|
||
{
|
||
glPinArrayFixStems(ch->gcr_tPins, ch->gcr_length);
|
||
glPinArrayFixStems(ch->gcr_bPins, ch->gcr_length);
|
||
glPinArrayFixStems(ch->gcr_lPins, ch->gcr_width);
|
||
glPinArrayFixStems(ch->gcr_rPins, ch->gcr_width);
|
||
}
|
||
|
||
int
|
||
glPinArrayFixStems(pins, nPins)
|
||
GCRPin *pins;
|
||
int nPins;
|
||
{
|
||
GCRPin *pin, *lastPin;
|
||
|
||
lastPin = &pins[nPins];
|
||
for (pin = pins + 1; pin <= lastPin; pin++)
|
||
if (pin->gcr_pId
|
||
&& pin->gcr_pId != GCR_BLOCKEDNETID
|
||
&& pin->gcr_pSeg == GCR_STEMSEGID)
|
||
{
|
||
pin->gcr_pId = (GCRNet *) NULL;
|
||
}
|
||
}
|