495 lines
16 KiB
C
495 lines
16 KiB
C
/*
|
|
* gcrChannel.c -
|
|
*
|
|
* Channel manipulation: allocation, freeing, and transforming
|
|
* (e.g, flipping them left-to-right or rotating). Transforming
|
|
* is done so that the channel can be routed in the easiest
|
|
* direction.
|
|
*
|
|
* *********************************************************************
|
|
* * 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 rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/gcr/gcrChannel.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 "gcr/gcr.h"
|
|
#include "utils/malloc.h"
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* GCRNewChannel --
|
|
*
|
|
* This procedure allocates storage for a new channel structure,
|
|
* and initializes most of the structure.
|
|
*
|
|
* Results:
|
|
* The return value is a pointer to the new channel.
|
|
*
|
|
* Side effects:
|
|
* Storage is allocated. The initial state of the channel is
|
|
* completely empty, although all pin and result arrays are
|
|
* allocated. This procedure does not initialize the fields
|
|
* gcr_area, gcr_origin, or gcr_lCol, although it allocates
|
|
* storage for gcr_lCol. Also, it doesn't initialize the
|
|
* value of gcr_point for each pin.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
GCRChannel *
|
|
GCRNewChannel(length, width)
|
|
int length; /* Length of the channel (# of columns) */
|
|
int width; /* Width of the channel (# rows) */
|
|
{
|
|
unsigned lenWds, widWds, nBytes;
|
|
GCRChannel *ch;
|
|
int i;
|
|
|
|
lenWds = length + 2;
|
|
widWds = width + 2;
|
|
|
|
ch = (GCRChannel *) mallocMagic((unsigned) (sizeof (GCRChannel)));
|
|
ch->gcr_type = CHAN_NORMAL;
|
|
ch->gcr_length = length;
|
|
ch->gcr_width = width;
|
|
ch->gcr_transform = GeoIdentityTransform;
|
|
ch->gcr_nets = (GCRNet *) NULL;
|
|
|
|
/* Malloc storage for pin arrays and zero each */
|
|
nBytes = lenWds * sizeof (GCRPin);
|
|
ch->gcr_tPins = (GCRPin *) mallocMagic((unsigned) nBytes);
|
|
ch->gcr_bPins = (GCRPin *) mallocMagic((unsigned) nBytes);
|
|
bzero((char *) ch->gcr_tPins, (int) nBytes);
|
|
bzero((char *) ch->gcr_bPins, (int) nBytes);
|
|
|
|
nBytes = widWds * sizeof (GCRPin);
|
|
ch->gcr_lPins = (GCRPin *) mallocMagic((unsigned) nBytes);
|
|
ch->gcr_rPins = (GCRPin *) mallocMagic((unsigned) nBytes);
|
|
bzero((char *) ch->gcr_lPins, (int) nBytes);
|
|
bzero((char *) ch->gcr_rPins, (int) nBytes);
|
|
|
|
ch->gcr_lCol = (GCRColEl *) mallocMagic((unsigned) (widWds * sizeof (GCRColEl)));
|
|
ch->gcr_density = (int *) mallocMagic((unsigned) (lenWds * sizeof (int)));
|
|
|
|
/* Global router-specific initialization */
|
|
ch->gcr_dRowsByCol = (short *) mallocMagic((unsigned) (lenWds * sizeof (short)));
|
|
bzero((char *) ch->gcr_dRowsByCol, (int) lenWds * sizeof (short));
|
|
ch->gcr_dColsByRow = (short *) mallocMagic ((unsigned) (widWds * sizeof (short)));
|
|
bzero((char *) ch->gcr_dColsByRow, (int) widWds * sizeof (short));
|
|
ch->gcr_dMaxByRow = ch->gcr_dMaxByCol = 0;
|
|
|
|
#ifdef IDENSITY
|
|
/* For debugging */
|
|
ch->gcr_iRowsByCol = (short *) mallocMagic((unsigned) (lenWds * sizeof (short)));
|
|
bzero((char *) ch->gcr_iRowsByCol, (int) lenWds * sizeof (short));
|
|
ch->gcr_iColsByRow = (short *) mallocMagic((unsigned) (widWds * sizeof (short)));
|
|
bzero((char *) ch->gcr_iColsByRow, (int) widWds * sizeof (short));
|
|
#endif /* IDENSITY */
|
|
|
|
ch->gcr_client = (ClientData) NULL;
|
|
|
|
/* Allocate the result array */
|
|
ch->gcr_result = (short **) mallocMagic ((unsigned) (lenWds * sizeof (short *)));
|
|
|
|
/*
|
|
* Fill in fields of pins that aren't zero; also allocate
|
|
* and clear each row of the result array.
|
|
*/
|
|
nBytes = widWds * sizeof (short);
|
|
for (i = 0; i < lenWds; i++)
|
|
{
|
|
ch->gcr_result[i] = (short *) mallocMagic((unsigned) nBytes);
|
|
bzero((char *) ch->gcr_result[i], (int) nBytes);
|
|
|
|
/* BOTTOM */
|
|
ch->gcr_bPins[i].gcr_pDist = -1;
|
|
ch->gcr_bPins[i].gcr_x = i;
|
|
ch->gcr_bPins[i].gcr_y = 0;
|
|
|
|
/* TOP */
|
|
ch->gcr_tPins[i].gcr_pDist = -1;
|
|
ch->gcr_tPins[i].gcr_x = i;
|
|
ch->gcr_tPins[i].gcr_y = widWds - 1;
|
|
}
|
|
|
|
for (i = 0; i < widWds; i++)
|
|
{
|
|
/* LEFT */
|
|
ch->gcr_lPins[i].gcr_pDist = -1;
|
|
ch->gcr_lPins[i].gcr_x = 0;
|
|
ch->gcr_lPins[i].gcr_y = i;
|
|
|
|
/* RIGHT */
|
|
ch->gcr_rPins[i].gcr_pDist = -1;
|
|
ch->gcr_rPins[i].gcr_x = lenWds - 1;
|
|
ch->gcr_rPins[i].gcr_y = i;
|
|
}
|
|
|
|
return (ch);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* GCRFreeChannel --
|
|
*
|
|
* This procedure frees up all the storage associated with
|
|
* a channel
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* The storage of ch is completely freed. The caller should
|
|
* refrain from any use of the pointer after this procedure
|
|
* returns.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
GCRFreeChannel(ch)
|
|
GCRChannel *ch; /* Pointer to channel structure to be freed. */
|
|
{
|
|
GCRNet *net;
|
|
int i;
|
|
|
|
freeMagic((char *) ch->gcr_tPins);
|
|
freeMagic((char *) ch->gcr_bPins);
|
|
freeMagic((char *) ch->gcr_lPins);
|
|
freeMagic((char *) ch->gcr_rPins);
|
|
for (net = ch->gcr_nets; net; net = net->gcr_next)
|
|
freeMagic((char *) net);
|
|
freeMagic((char *) ch->gcr_lCol);
|
|
|
|
freeMagic((char *) ch->gcr_dRowsByCol);
|
|
freeMagic((char *) ch->gcr_dColsByRow);
|
|
|
|
#ifdef IDENSITY
|
|
/* For debugging */
|
|
freeMagic((char *) ch->gcr_iRowsByCol);
|
|
freeMagic((char *) ch->gcr_iColsByRow);
|
|
#endif /* IDENSITY */
|
|
|
|
freeMagic((char *) ch->gcr_density);
|
|
for (i = 0; i <= ch->gcr_length + 1; i++)
|
|
freeMagic((char *) ch->gcr_result[i]);
|
|
freeMagic((char *) ch->gcr_result);
|
|
freeMagic((char *) ch);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* GCRFlipLeftRight --
|
|
*
|
|
* This procedure will flip the contents of a channel left-to-right.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* The contents of channel dst are modified so that they are
|
|
* a left-to-right flip of src. Only the four pin arrays, the
|
|
* transform, the origin, the area, and the result array are
|
|
* modified. The other fields of dst are untouched. This means,
|
|
* in particular, that this procedure should be called BEFORE
|
|
* the linked lists for nets get set up, or else AFTER all the
|
|
* channel routing has been done and the nets have been freed up.
|
|
* Also, this procedure does not transform the flag bits GCRTE or
|
|
* GCRCE, so this procedure shouldn't be called when those flags
|
|
* are significant.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
GCRFlipLeftRight(src, dst)
|
|
GCRChannel *src; /* Original channel. */
|
|
GCRChannel *dst; /* Channel to be modified to contain
|
|
* transformed info from src. The two
|
|
* channels must have the same dimensions,
|
|
* but must not be the same channel.
|
|
*/
|
|
{
|
|
int y, lenWds, widWds;
|
|
short old, new;
|
|
int i, j;
|
|
Transform t;
|
|
|
|
ASSERT(src->gcr_length == dst->gcr_length, "GCRFlipLeftRight: mismatch");
|
|
ASSERT(src->gcr_width == dst->gcr_width, "GCRFlipLeftRight: mismatch");
|
|
|
|
lenWds = src->gcr_length + 1;
|
|
widWds = src->gcr_width + 1;
|
|
|
|
for (i = 0; i <= lenWds; i++)
|
|
{
|
|
j = lenWds - i;
|
|
|
|
/* Exchange pairs of pins in the top and bottom arrays */
|
|
dst->gcr_tPins[j] = src->gcr_tPins[i];
|
|
dst->gcr_tPins[j].gcr_x = j;
|
|
dst->gcr_bPins[j] = src->gcr_bPins[i];
|
|
dst->gcr_bPins[j].gcr_x = j;
|
|
|
|
/*
|
|
* Go through the result array, exchanging flag values. Also,
|
|
* be careful to switch the left-right hazard bits now that the
|
|
* sense of the channel is reversed. Also switch the GCRR bit
|
|
* in case there's been routing done.
|
|
*/
|
|
for (y = 0; y <= widWds; y++)
|
|
{
|
|
old = src->gcr_result[i][y];
|
|
new = old & ~(GCRVR|GCRVL|GCRR);
|
|
if (old & GCRVR) new |= GCRVL;
|
|
if (old & GCRVL) new |= GCRVR;
|
|
if (i != 0 && (src->gcr_result[i-1][y] & GCRR))
|
|
new |= GCRR;
|
|
dst->gcr_result[j][y] = new;
|
|
}
|
|
}
|
|
|
|
/* Switch the left and right end pins */
|
|
for (i = 0; i <= widWds; i++)
|
|
{
|
|
dst->gcr_lPins[i] = src->gcr_rPins[i];
|
|
dst->gcr_lPins[i].gcr_x = 0;
|
|
dst->gcr_rPins[i] = src->gcr_lPins[i];
|
|
dst->gcr_rPins[i].gcr_x = widWds;
|
|
}
|
|
|
|
/* Copy the horizontal and vertical density information */
|
|
dst->gcr_dMaxByCol = src->gcr_dMaxByCol;
|
|
dst->gcr_dMaxByRow = src->gcr_dMaxByRow;
|
|
bcopy((char *) src->gcr_dColsByRow, (char *) dst->gcr_dColsByRow,
|
|
sizeof (short) * widWds);
|
|
#ifdef IDENSITY
|
|
bcopy((char *) src->gcr_iColsByRow, (char *) dst->gcr_iColsByRow,
|
|
sizeof (short) * widWds);
|
|
#endif /* IDENSITY */
|
|
for (i = 0; i <= lenWds; i++)
|
|
{
|
|
/* Flip left-to-right */
|
|
j = lenWds - i;
|
|
dst->gcr_dRowsByCol[j] = src->gcr_dRowsByCol[i];
|
|
#ifdef IDENSITY
|
|
dst->gcr_iRowsByCol[j] = src->gcr_iRowsByCol[i];
|
|
#endif /* IDENSITY */
|
|
}
|
|
|
|
/* Now fix up the transform of the new channel */
|
|
GeoTranslateTrans(&GeoSidewaysTransform, src->gcr_length+1, 0, &t);
|
|
GeoTransTrans(&t, &src->gcr_transform, &dst->gcr_transform);
|
|
dst->gcr_origin = src->gcr_origin;
|
|
dst->gcr_area = src->gcr_area;
|
|
dst->gcr_type = src->gcr_type;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* GCRFlipXY --
|
|
*
|
|
* This procedure rotates and flips a channel to interchange
|
|
* x and y coordinates.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* The contents of channel dst are modified so that they are
|
|
* a x-y flip of src. See comments for GCRFlipLeftRight for
|
|
* warnings about when it is and isn't safe to call this
|
|
* procedure.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
GCRFlipXY(src, dst)
|
|
GCRChannel *src; /* Original channel. */
|
|
GCRChannel *dst; /* Channel to be modified to contain
|
|
* transformed info from src.
|
|
*/
|
|
{
|
|
static Transform flipxy = {0, 1, 0, 1, 0, 0};
|
|
int tmp, lenWds, widWds;
|
|
short old, new;
|
|
int i, j;
|
|
|
|
ASSERT(src->gcr_width == dst->gcr_length, "gcrFlipXY: channel mismatch");
|
|
ASSERT(src->gcr_length == dst->gcr_width, "gcrFlipXY: channel mismatch");
|
|
|
|
lenWds = src->gcr_length + 1;
|
|
widWds = src->gcr_width + 1;
|
|
|
|
/* First, flip the side pins to top and bottom */
|
|
for (i = 0; i <= widWds; i++)
|
|
{
|
|
dst->gcr_tPins[i] = src->gcr_rPins[i];
|
|
tmp = dst->gcr_tPins[i].gcr_x;
|
|
dst->gcr_tPins[i].gcr_x = dst->gcr_tPins[i].gcr_y;
|
|
dst->gcr_tPins[i].gcr_y = tmp;
|
|
dst->gcr_bPins[i] = src->gcr_lPins[i];
|
|
tmp = dst->gcr_bPins[i].gcr_x;
|
|
dst->gcr_bPins[i].gcr_x = dst->gcr_bPins[i].gcr_y;
|
|
dst->gcr_bPins[i].gcr_y = tmp;
|
|
}
|
|
|
|
/* Same thing except flip top and bottom pins to sides */
|
|
for (i = 0; i <= lenWds; i++)
|
|
{
|
|
dst->gcr_rPins[i] = src->gcr_tPins[i];
|
|
tmp = dst->gcr_rPins[i].gcr_x;
|
|
dst->gcr_rPins[i].gcr_x = dst->gcr_rPins[i].gcr_y;
|
|
dst->gcr_rPins[i].gcr_y = tmp;
|
|
dst->gcr_lPins[i] = src->gcr_bPins[i];
|
|
tmp = dst->gcr_lPins[i].gcr_x;
|
|
dst->gcr_lPins[i].gcr_x = dst->gcr_lPins[i].gcr_y;
|
|
dst->gcr_lPins[i].gcr_y = tmp;
|
|
}
|
|
|
|
/*
|
|
* Now flip the result array. EXTRA SPECIAL TRICKINESS: the
|
|
* GCRBLKM and GCRBLKP flags must get switched, because what
|
|
* blocked a column in the old channel blocks a row in the
|
|
* new one.
|
|
*/
|
|
for (i = 0; i <= lenWds; i++)
|
|
for (j = 0; j <= widWds; j++)
|
|
{
|
|
old = src->gcr_result[i][j];
|
|
new = old & ~(GCRVR|GCRVL|GCRVU|GCRVD|GCRR|GCRU|GCRBLKM|GCRBLKP);
|
|
if (old & GCRVR) new |= GCRVU;
|
|
if (old & GCRVU) new |= GCRVR;
|
|
if (old & GCRVL) new |= GCRVD;
|
|
if (old & GCRVD) new |= GCRVL;
|
|
if (old & GCRR) new |= GCRU;
|
|
if (old & GCRU) new |= GCRR;
|
|
if (old & GCRBLKM) new |= GCRBLKP;
|
|
if (old & GCRBLKP) new |= GCRBLKM;
|
|
dst->gcr_result[j][i] = new;
|
|
}
|
|
|
|
/* Copy the horizontal and vertical density information */
|
|
dst->gcr_dMaxByRow = src->gcr_dMaxByCol;
|
|
dst->gcr_dMaxByCol = src->gcr_dMaxByRow;
|
|
bcopy((char *) src->gcr_dRowsByCol, (char *) dst->gcr_dColsByRow,
|
|
sizeof (short) * lenWds);
|
|
bcopy((char *) src->gcr_dColsByRow, (char *) dst->gcr_dRowsByCol,
|
|
sizeof (short) * widWds);
|
|
#ifdef IDENSITY
|
|
bcopy((char *) src->gcr_iRowsByCol, (char *) dst->gcr_iColsByRow,
|
|
sizeof (short) * lenWds);
|
|
bcopy((char *) src->gcr_iColsByRow, (char *) dst->gcr_iRowsByCol,
|
|
sizeof (short) * widWds);
|
|
#endif /* IDENSITY */
|
|
|
|
/* Lastly, make a new transform */
|
|
GeoTransTrans(&flipxy, &src->gcr_transform, &dst->gcr_transform);
|
|
dst->gcr_origin = src->gcr_origin;
|
|
dst->gcr_area = src->gcr_area;
|
|
switch (src->gcr_type)
|
|
{
|
|
case CHAN_HRIVER: dst->gcr_type = CHAN_VRIVER; break;
|
|
case CHAN_VRIVER: dst->gcr_type = CHAN_HRIVER; break;
|
|
default: dst->gcr_type = CHAN_NORMAL; break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* GCRNoFlip --
|
|
*
|
|
* This procedure performs the identity transform. It makes a copy.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* The contents of channel dst are modified so that they are
|
|
* a copy of src. Only the four pin arrays, the transform, the
|
|
* the area, and the result array are modified. The other fields
|
|
* of dst are untouched. This means,
|
|
* in particular, that this procedure should be called BEFORE
|
|
* the linked lists for nets get set up, or else AFTER all the
|
|
* channel routing has been done and the nets have been freed up.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
GCRNoFlip(src, dst)
|
|
GCRChannel *src; /* Original channel. */
|
|
GCRChannel *dst; /* Channel to be modified to contain
|
|
* transformed info from src. The two
|
|
* channels must have the same dimensions,
|
|
* but must not be the same channel.
|
|
*/
|
|
{
|
|
int lenWds, widWds, pinBytes, resBytes;
|
|
int i;
|
|
|
|
ASSERT(src->gcr_length == dst->gcr_length, "GCRFlipLeftRight: mismatch");
|
|
ASSERT(src->gcr_width == dst->gcr_width, "GCRFlipLeftRight: mismatch");
|
|
|
|
lenWds = src->gcr_length + 1;
|
|
widWds = src->gcr_width + 1;
|
|
|
|
/* Copy pairs of pins in the top and bottom arrays */
|
|
pinBytes = lenWds * sizeof (GCRPin);
|
|
bcopy((char *) src->gcr_tPins, (char *) dst->gcr_tPins, pinBytes);
|
|
bcopy((char *) src->gcr_bPins, (char *) dst->gcr_bPins, pinBytes);
|
|
|
|
/* Copy flag values from the result array */
|
|
resBytes = widWds * sizeof (short);
|
|
for (i = 0; i <= lenWds; i++)
|
|
bcopy((char *)src->gcr_result[i], (char *)dst->gcr_result[i], resBytes);
|
|
|
|
/* Copy the left and right end pins */
|
|
pinBytes = widWds * sizeof (GCRPin);
|
|
bcopy((char *) src->gcr_lPins, (char *) dst->gcr_lPins, pinBytes);
|
|
bcopy((char *) src->gcr_rPins, (char *) dst->gcr_rPins, pinBytes);
|
|
|
|
/* Copy the horizontal and vertical density information */
|
|
dst->gcr_dMaxByCol = src->gcr_dMaxByCol;
|
|
dst->gcr_dMaxByRow = src->gcr_dMaxByRow;
|
|
bcopy((char *) src->gcr_dRowsByCol, (char *) dst->gcr_dRowsByCol,
|
|
sizeof (short) * lenWds);
|
|
bcopy((char *) src->gcr_dColsByRow, (char *) dst->gcr_dColsByRow,
|
|
sizeof (short) * widWds);
|
|
#ifdef IDENSITY
|
|
bcopy((char *) src->gcr_iRowsByCol, (char *) dst->gcr_iRowsByCol,
|
|
sizeof (short) * lenWds);
|
|
bcopy((char *) src->gcr_iColsByRow, (char *) dst->gcr_iColsByRow,
|
|
sizeof (short) * widWds);
|
|
#endif /* IDENSITY */
|
|
|
|
/* Now fix up the transform of the new channel */
|
|
dst->gcr_origin = src->gcr_origin;
|
|
dst->gcr_transform = src->gcr_transform;
|
|
dst->gcr_area = src->gcr_area;
|
|
dst->gcr_type = src->gcr_type;
|
|
}
|