1029 lines
25 KiB
C
1029 lines
25 KiB
C
/* gcrDebug.c -
|
|
*
|
|
* The greedy router, debug routines.
|
|
*
|
|
* *********************************************************************
|
|
* * 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/gcrDebug.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
|
#endif /* not lint */
|
|
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <sys/types.h>
|
|
#include <sys/times.h>
|
|
|
|
#include "utils/magic.h"
|
|
#include "utils/geometry.h"
|
|
#include "textio/textio.h"
|
|
#include "tiles/tile.h"
|
|
#include "utils/hash.h"
|
|
#include "database/database.h"
|
|
#include "gcr/gcr.h"
|
|
#include "utils/heap.h"
|
|
#include "router/router.h"
|
|
#include "utils/malloc.h"
|
|
|
|
int gcrViaCount;
|
|
bool GcrShowEnd = FALSE;
|
|
bool GcrShowMap = FALSE;
|
|
int gcrStandalone=FALSE; /*Flag to control standalone/integrated operation*/
|
|
|
|
/* Forward declarations */
|
|
void gcrDumpResult();
|
|
void gcrStats();
|
|
void gcrShowMap();
|
|
bool gcrMakeChannel();
|
|
|
|
void gcrPrintCol(GCRChannel *, int, int);
|
|
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* GCRRouteFromFile --
|
|
*
|
|
* Reads a routing problem from the named file and performs the routing.
|
|
*
|
|
* Results:
|
|
* Returns a pointer to the routed channel.
|
|
*
|
|
* Side effects:
|
|
* Allocates memory.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
GCRChannel *
|
|
GCRRouteFromFile(fname)
|
|
char *fname;
|
|
{
|
|
static Point initOrigin = { 0, 0 };
|
|
struct tms tbuf1, tbuf2;
|
|
GCRChannel *ch;
|
|
Transform trans;
|
|
FILE *fp;
|
|
Rect box;
|
|
|
|
fp = fopen(fname, "r");
|
|
if (fp == NULL)
|
|
{
|
|
perror(fname);
|
|
return ((GCRChannel *) NULL);
|
|
}
|
|
|
|
ch = (GCRChannel *) mallocMagic((unsigned) (sizeof (GCRChannel)));
|
|
ch->gcr_type = CHAN_NORMAL;
|
|
/* ch->gcr_area = box; */
|
|
ch->gcr_transform = GeoIdentityTransform;
|
|
ch->gcr_lCol = (GCRColEl *) NULL;
|
|
ch->gcr_nets = (GCRNet *) NULL;
|
|
ch->gcr_result = (short **) NULL;
|
|
ch->gcr_origin = initOrigin;
|
|
|
|
if (!gcrMakeChannel(ch, fp))
|
|
{
|
|
TxError("Couldn't initialize channel routing problem\n");
|
|
(void) fclose(fp);
|
|
freeMagic((char *) ch);
|
|
return ((GCRChannel *) NULL);
|
|
}
|
|
|
|
(void) fclose(fp);
|
|
ch->gcr_lCol = (GCRColEl *) mallocMagic((unsigned) ((ch->gcr_width+2) * sizeof (GCRColEl)));
|
|
times(&tbuf1);
|
|
(void) GCRroute(ch);
|
|
times(&tbuf2);
|
|
TxPrintf("Time : %5.2fu %5.2fs\n", (tbuf2.tms_utime -
|
|
tbuf1.tms_utime)/60.0, (double)(tbuf2.tms_stime-tbuf1.tms_stime)*60);
|
|
|
|
gcrDumpResult(ch, GcrShowEnd);
|
|
gcrShowMap(ch);
|
|
return (ch);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* gcrMakeChannel --
|
|
*
|
|
* Read a channel in the new file format.
|
|
*
|
|
* Results:
|
|
* TRUE if successful, FALSE if not.
|
|
*
|
|
* Side effects:
|
|
* Sets values in *channel.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
bool
|
|
gcrMakeChannel(ch, fp)
|
|
GCRChannel *ch;
|
|
FILE *fp;
|
|
{
|
|
GCRPin *gcrMakePinLR();
|
|
unsigned lenWds, widWds;
|
|
int i, j, c, pid;
|
|
char s[25];
|
|
|
|
c = getc(fp);
|
|
if (c != '*')
|
|
{
|
|
TxError("Old-style channel format no longer supported.\n");
|
|
return (FALSE);
|
|
}
|
|
|
|
if (fscanf(fp, "%d %d", &ch->gcr_width, &ch->gcr_length) != 2)
|
|
{
|
|
TxError("Format error in input file width or length.\n");
|
|
return (FALSE);
|
|
}
|
|
|
|
lenWds = ch->gcr_length + 2;
|
|
widWds = ch->gcr_width + 2;
|
|
ch->gcr_density = (int *) mallocMagic((unsigned) (lenWds * sizeof (int)));
|
|
ch->gcr_lPins = gcrMakePinLR(fp, 0, ch->gcr_width);
|
|
ch->gcr_tPins = (GCRPin *) mallocMagic((unsigned) (lenWds * sizeof (GCRPin)));
|
|
ch->gcr_bPins = (GCRPin *) mallocMagic((unsigned) (lenWds * sizeof (GCRPin)));
|
|
ch->gcr_result = (short **) mallocMagic((unsigned) (lenWds * sizeof (short *)));
|
|
|
|
/* Initialize end columns */
|
|
ch->gcr_result[0] = (short *) mallocMagic((unsigned) (widWds * sizeof (short)));
|
|
ch->gcr_result[ch->gcr_length+1] = (short *) mallocMagic((unsigned) (widWds * sizeof (short)));
|
|
for (i = 0; i < widWds; i++)
|
|
{
|
|
ch->gcr_result[0][i] = 0;
|
|
ch->gcr_result[ch->gcr_length + 1][i] = 0;
|
|
}
|
|
|
|
/* Initialize internal columns */
|
|
for (i = 1; i <= ch->gcr_length; i++)
|
|
{
|
|
/* Allocate the column */
|
|
ch->gcr_result[i] = (short *) mallocMagic((unsigned) (widWds * sizeof (short)));
|
|
|
|
/* Initialize the bottom pin */
|
|
if (fscanf(fp, "%d", &pid) != 1)
|
|
{
|
|
TxError("Format error in pin-id in channel file\n");
|
|
return (FALSE);
|
|
}
|
|
ch->gcr_bPins[i].gcr_pId = (GCRNet *)(spointertype) pid;
|
|
ch->gcr_bPins[i].gcr_x = i;
|
|
ch->gcr_bPins[i].gcr_y = 0;
|
|
|
|
ch->gcr_result[i][0] = 0;
|
|
ch->gcr_result[i][ch->gcr_width+1] = 0;
|
|
for (j = 1; j <= ch->gcr_width; j++)
|
|
{
|
|
/*
|
|
* Read a column of obstacles. m and M mean metal is blocked,
|
|
* p and P mean poly is blocked. Upper case means vacate the
|
|
* column, lower case means vacate the track.
|
|
*/
|
|
if (fscanf(fp, "%24s", s) != 1)
|
|
{
|
|
TxError("Format error in router input file\n");
|
|
return (FALSE);
|
|
}
|
|
switch (s[0])
|
|
{
|
|
case 'M': case 'm':
|
|
ch->gcr_result[i][j] = GCRBLKM;
|
|
break;
|
|
case 'P': case 'p':
|
|
ch->gcr_result[i][j] = GCRBLKP;
|
|
break;
|
|
case '.':
|
|
ch->gcr_result[i][j] = 0;
|
|
break;
|
|
default:
|
|
ch->gcr_result[i][j] = GCRBLKP | GCRBLKM;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Read bottom pin id */
|
|
if (fscanf(fp, "%d", &pid) != 1)
|
|
{
|
|
TxError("Format error in router input file\n");
|
|
return (FALSE);
|
|
}
|
|
ch->gcr_tPins[i].gcr_pId = (GCRNet *)(spointertype) pid;
|
|
ch->gcr_tPins[i].gcr_x = i;
|
|
ch->gcr_tPins[i].gcr_y = ch->gcr_width + 1;
|
|
}
|
|
|
|
ch->gcr_rPins = gcrMakePinLR(fp, ch->gcr_length + 1, ch->gcr_width);
|
|
ch->gcr_area.r_xbot = 0;
|
|
ch->gcr_area.r_ybot = 0;
|
|
ch->gcr_area.r_xtop = (ch->gcr_length + 1) * RtrGridSpacing;
|
|
ch->gcr_area.r_ytop = (ch->gcr_width + 1) * RtrGridSpacing;
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
GCRPin *
|
|
gcrMakePinLR(fp, x, size)
|
|
FILE *fp;
|
|
int x, size;
|
|
{
|
|
GCRPin *result;
|
|
int i;
|
|
|
|
result = (GCRPin *) mallocMagic((unsigned) ((size+2) * sizeof (GCRPin)));
|
|
result[0].gcr_x = result[0].gcr_y = 0;
|
|
result[0].gcr_pId = (GCRNet *) NULL;
|
|
result[size + 1].gcr_x = result[size + 1].gcr_y = 0;
|
|
result[size + 1].gcr_pId = (GCRNet *) NULL;
|
|
for (i = 1; i <= size; i++)
|
|
{
|
|
/* FIXME: Reading a pointer from file is almost guaranteed to break. */
|
|
dlong pointer_bits;
|
|
(void) fscanf(fp, "%"DLONG_PREFIX"d", &pointer_bits);
|
|
result[i].gcr_pId = (struct gcrnet *) pointer_bits;
|
|
result[i].gcr_x = x;
|
|
result[i].gcr_y = i;
|
|
}
|
|
|
|
return (result);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* gcrSaveChannel --
|
|
*
|
|
* Write a channel file for subsequent use in debugging.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Creates a disk file named by the channel address,
|
|
* e.g, chan.1efb0
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
gcrSaveChannel(ch)
|
|
GCRChannel *ch;
|
|
{
|
|
FILE *fp;
|
|
char name[128];
|
|
int flags, i, j;
|
|
|
|
(void) sprintf(name, "chan.%p", ch);
|
|
fp = fopen(name, "w");
|
|
if (fp == NULL)
|
|
{
|
|
TxPrintf("Can't dump channel to file; "); TxFlush();
|
|
perror(name);
|
|
return;
|
|
}
|
|
|
|
/* Output the prologue */
|
|
fprintf(fp, "* %d %d\n", ch->gcr_width, ch->gcr_length);
|
|
|
|
#define NETID(pin) ((pin).gcr_pId ? (pin).gcr_pId->gcr_Id : 0)
|
|
|
|
/* Output the left pin array */
|
|
for (j = 1; j <= ch->gcr_width; j++)
|
|
fprintf(fp, "%d ", NETID(ch->gcr_lPins[j]));
|
|
fprintf(fp, "\n");
|
|
|
|
/* Process main body of channel */
|
|
for (i = 1; i <= ch->gcr_length; i++)
|
|
{
|
|
/* Bottom pin */
|
|
fprintf(fp, "%d ", NETID(ch->gcr_bPins[i]));
|
|
|
|
/*
|
|
* Interior points (for obstacle map).
|
|
* Codes are as follows:
|
|
*
|
|
* m metal blocked vacate track
|
|
* M metal blocked vacate column
|
|
* p poly blocked vacate track
|
|
* P poly blocked vacate column
|
|
*/
|
|
for (j = 1; j <= ch->gcr_width; j++)
|
|
{
|
|
flags = ch->gcr_result[i][j];
|
|
switch (flags & (GCRBLKM|GCRBLKP))
|
|
{
|
|
case 0: fprintf(fp, ". "); break;
|
|
case GCRBLKM: fprintf(fp, "m "); break;
|
|
case GCRBLKP: fprintf(fp, "p "); break;
|
|
case GCRBLKM|GCRBLKP: fprintf(fp, "x "); break;
|
|
}
|
|
}
|
|
|
|
/* Top pin */
|
|
fprintf(fp, "%d\n", NETID(ch->gcr_tPins[i]));
|
|
}
|
|
|
|
/* Output the right pin array */
|
|
for (j = 1; j <= ch->gcr_width; j++)
|
|
fprintf(fp, "%d ", NETID(ch->gcr_rPins[j]));
|
|
fprintf(fp, "\n");
|
|
(void) fclose(fp);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* gcrPrDensity --
|
|
*
|
|
* Create a file of the form "dens.xbot.ybot.xtop.ytop", where
|
|
* xbot, ybot are the lower-left coordinates of ch->gcr_area
|
|
* and xtop, ytop are the upper right coordinates. This file
|
|
* contains a comparison of the density computed by the global
|
|
* router with that computed by the channel router; it is used
|
|
* for debugging only.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Creates a file named as described above.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
gcrPrDensity(ch, chanDensity)
|
|
GCRChannel *ch;
|
|
int chanDensity;
|
|
{
|
|
int i, diff;
|
|
char name[256];
|
|
FILE *fp, *fp_always_close;
|
|
|
|
(void) sprintf(name, "dens.%d.%d.%d.%d",
|
|
ch->gcr_area.r_xbot, ch->gcr_area.r_ybot,
|
|
ch->gcr_area.r_xtop, ch->gcr_area.r_ytop);
|
|
fp_always_close = fopen(name, "w");
|
|
fp = fp_always_close ? fp_always_close : stdout;
|
|
|
|
fprintf(fp, "Chan width: %d\n", ch->gcr_width);
|
|
fprintf(fp, "Chan length: %d\n", ch->gcr_length);
|
|
fprintf(fp, "Chan area: ll=(%d,%d) ur=(%d,%d)\n",
|
|
ch->gcr_area.r_xbot, ch->gcr_area.r_ybot,
|
|
ch->gcr_area.r_xtop, ch->gcr_area.r_ytop);
|
|
fprintf(fp, "Max column density (global): %d\n", ch->gcr_dMaxByCol);
|
|
fprintf(fp, "Max column density (channel): %d\n", chanDensity);
|
|
fprintf(fp, "Column density by column:\n");
|
|
fprintf(fp, "%3s %5s", "COL", "GLOB");
|
|
#ifdef IDENSITY
|
|
fprintf(fp, " %5s %5s", "INIT", "DIFF");
|
|
#endif /* IDENSITY */
|
|
fprintf(fp, " %5s\n", "CHAN");
|
|
for (i = 1; i <= ch->gcr_length; i++)
|
|
{
|
|
fprintf(fp, "%3d %5d", i, ch->gcr_dRowsByCol[i]);
|
|
diff = ch->gcr_dRowsByCol[i];
|
|
#ifdef IDENSITY
|
|
diff -= ch->gcr_iRowsByCol[i];
|
|
fprintf(fp, " %5d %5d", ch->gcr_iRowsByCol[i], diff);
|
|
#endif /* IDENSITY */
|
|
fprintf(fp, "%5d%s\n", ch->gcr_density[i],
|
|
(diff != ch->gcr_density[i]) ? " *****" : "");
|
|
}
|
|
fprintf(fp, "------\n");
|
|
fprintf(fp, "Row density by column (global only):\n");
|
|
fprintf(fp, "%3s %5s", "ROW", "GLOB");
|
|
#ifdef IDENSITY
|
|
fprintf(fp, " %5s %5s", "INIT", "DIFF");
|
|
#endif /* IDENSITY */
|
|
fprintf(fp, "\n");
|
|
for (i = 1; i <= ch->gcr_width; i++)
|
|
{
|
|
fprintf(fp, "%3d %5d", i, ch->gcr_dColsByRow[i]);
|
|
#ifdef IDENSITY
|
|
fprintf(fp, " %5d %5d", ch->gcr_iColsByRow[i],
|
|
ch->gcr_dColsByRow[i] - ch->gcr_iColsByRow[i]);
|
|
#endif /* IDENSITY */
|
|
fprintf(fp, "\n");
|
|
}
|
|
|
|
(void) fflush(fp);
|
|
if (fp_always_close != NULL)
|
|
(void) fclose(fp_always_close);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* gcrDumpPins --
|
|
*
|
|
* Prints a pin array.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
gcrDumpPins(ch)
|
|
GCRChannel *ch;
|
|
{
|
|
int i;
|
|
GCRPin * pinArray;
|
|
|
|
pinArray=ch->gcr_lPins;
|
|
TxPrintf("LEFT PINS\n");
|
|
for(i=0; i<=ch->gcr_width; i++)
|
|
{
|
|
TxPrintf("Location [%d]=%ld: x=%d, y=%d, pNext=%ld, pPrev=%ld, id=%ld\n",
|
|
i, (intmax_t) &pinArray[i], pinArray[i].gcr_x, pinArray[i].gcr_y,
|
|
(intmax_t) pinArray[i].gcr_pNext, (intmax_t) pinArray[i].gcr_pPrev, (intmax_t) pinArray[i].gcr_pId);
|
|
}
|
|
pinArray=ch->gcr_rPins;
|
|
TxPrintf("RIGHT PINS\n");
|
|
for(i=0; i<=ch->gcr_width; i++)
|
|
{
|
|
TxPrintf("Location [%d]=%ld: x=%d, y=%d, pNext=%ld, pPrev=%ld, id=%ld\n",
|
|
i, (intmax_t) &pinArray[i], pinArray[i].gcr_x, pinArray[i].gcr_y,
|
|
(intmax_t) pinArray[i].gcr_pNext, (intmax_t) pinArray[i].gcr_pPrev, (intmax_t) pinArray[i].gcr_pId);
|
|
}
|
|
pinArray=ch->gcr_bPins;
|
|
TxPrintf("BOTTOM PINS\n");
|
|
for(i=0; i<=ch->gcr_length; i++)
|
|
{
|
|
TxPrintf("Location [%d]=%ld: x=%d, y=%d, pNext=%ld, pPrev=%ld, id=%ld\n",
|
|
i, (intmax_t) &pinArray[i], pinArray[i].gcr_x, pinArray[i].gcr_y,
|
|
(intmax_t) pinArray[i].gcr_pNext, (intmax_t) pinArray[i].gcr_pPrev, (intmax_t) pinArray[i].gcr_pId);
|
|
}
|
|
pinArray=ch->gcr_tPins;
|
|
TxPrintf("TOP PINS\n");
|
|
for(i=0; i<=ch->gcr_length; i++)
|
|
{
|
|
TxPrintf("Location [%d]=%ld: x=%d, y=%d, pNext=%ld, pPrev=%ld, id=%ld\n",
|
|
i, (intmax_t) &pinArray[i], pinArray[i].gcr_x, pinArray[i].gcr_y,
|
|
(intmax_t) pinArray[i].gcr_pNext, (intmax_t) pinArray[i].gcr_pPrev, (intmax_t) pinArray[i].gcr_pId);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* gcrDumpPinList --
|
|
*
|
|
* Prints a list of pins for a net.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
gcrDumpPinList(pin, dir)
|
|
GCRPin *pin;
|
|
bool dir;
|
|
{
|
|
if (pin)
|
|
{
|
|
TxPrintf("Location (%d, %d)=%lx: pNext=%ld, pPrev=%ld, id=%ld\n",
|
|
pin->gcr_x, pin->gcr_y, (intmax_t) pin,
|
|
(intmax_t) pin->gcr_pNext, (intmax_t) pin->gcr_pPrev, (intmax_t) pin->gcr_pId);
|
|
if (dir) gcrDumpPinList(pin->gcr_pNext, dir);
|
|
else gcrDumpPinList(pin->gcr_pPrev, dir);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* gcrDumpCol --
|
|
*
|
|
* Print the left column contents.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
gcrDumpCol(col, size)
|
|
GCRColEl *col;
|
|
int size;
|
|
{
|
|
int i;
|
|
|
|
if (!gcrStandalone)
|
|
return;
|
|
|
|
for (i = size; i >= 0; i--)
|
|
TxPrintf("[%2d] hi=%6d(%c) lo=%6d(%c) h=%6d v=%6d w=%6d f=%4d\n", i,
|
|
col[i].gcr_hi, col[i].gcr_hOk ? 'T' : 'F',
|
|
col[i].gcr_lo, col[i].gcr_lOk ? 'T' : 'F',
|
|
col[i].gcr_h, col[i].gcr_v,
|
|
col[i].gcr_wanted, col[i].gcr_flags);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* gcrDumpResult --
|
|
*
|
|
* Print the results of the routing, up to the current column
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
gcrDumpResult(ch, showResult)
|
|
GCRChannel *ch;
|
|
bool showResult;
|
|
{
|
|
int j;
|
|
|
|
if(!showResult)
|
|
return;
|
|
|
|
gcrStats(ch);
|
|
TxPrintf(" ");
|
|
for (j = 1; j <= ch->gcr_width; j++)
|
|
if (ch->gcr_lPins[j].gcr_pId)
|
|
TxPrintf("%2d", ch->gcr_lPins[j].gcr_pId->gcr_Id);
|
|
else
|
|
TxPrintf(" ");
|
|
TxPrintf("\n");
|
|
|
|
for (j = 0; j <= ch->gcr_length; j++)
|
|
gcrPrintCol(ch, j, showResult);
|
|
|
|
TxPrintf(" ");
|
|
for (j = 1; j <= ch->gcr_width; j++)
|
|
if (ch->gcr_rPins[j].gcr_pId)
|
|
TxPrintf("%2d", ch->gcr_rPins[j].gcr_pId->gcr_Id);
|
|
else
|
|
TxPrintf(" ");
|
|
TxPrintf("\n");
|
|
}
|
|
|
|
void gcrPrintCol(ch, i, showResult)
|
|
GCRChannel *ch;
|
|
int i, showResult;
|
|
{
|
|
short **res = ch->gcr_result;
|
|
int j;
|
|
|
|
if (!showResult)
|
|
return;
|
|
|
|
if (i>0)
|
|
{
|
|
if(ch->gcr_bPins[i].gcr_pId)
|
|
TxPrintf("[%3d] %2d:", i, (int) ch->gcr_bPins[i].gcr_pId->gcr_Id);
|
|
else TxPrintf("[%3d] :", i);
|
|
for (j = 0; j <= ch->gcr_width; j++)
|
|
{
|
|
if (j != 0)
|
|
{
|
|
if ((res[i][j] & GCRX) && (!(res[i][j] & (GCRBLKM|GCRBLKP))))
|
|
{
|
|
TxPrintf("X");
|
|
gcrViaCount++;
|
|
}
|
|
else if ((res[i][j] & GCRR) || (i > 0 && (res[i-1][j] & GCRR)))
|
|
{
|
|
if (res[i][j] & GCRBLKM) TxPrintf("|");
|
|
else if ((res[i][j] & GCRU)
|
|
|| (j != 0 && (res[i][j-1] & GCRU)))
|
|
{
|
|
if ((res[i][j]&GCRBLKM) && !(res[i][j]&GCRR))
|
|
TxPrintf("+");
|
|
else if (res[i][j]&GCRBLKP)
|
|
TxPrintf("#");
|
|
else
|
|
TxPrintf(")");
|
|
}
|
|
else TxPrintf("#");
|
|
}
|
|
else if ((res[i][j] & GCRU) || (j != 0 && (res[i][j-1] & GCRU)))
|
|
{
|
|
if((res[i][j]&GCRCC) && (!(res[i][j]&(GCRBLKM|GCRBLKP))))
|
|
{
|
|
gcrViaCount++;
|
|
TxPrintf("X");
|
|
}
|
|
else
|
|
if(res[i][j] & GCRBLKP)
|
|
TxPrintf("#");
|
|
else
|
|
if(res[i][j+1] & GCRBLKP)
|
|
TxPrintf("#");
|
|
else
|
|
if(res[i][j] & GCRVM)
|
|
TxPrintf("#");
|
|
else
|
|
TxPrintf("-");
|
|
}
|
|
else
|
|
if((res[i][j] & GCRBLKM) && (res[i][j] & GCRBLKP))
|
|
TxPrintf("~");
|
|
else
|
|
if(res[i][j] & GCRBLKM)
|
|
TxPrintf("'");
|
|
else
|
|
if(res[i][j] & GCRBLKP)
|
|
TxPrintf("`");
|
|
else
|
|
TxPrintf(" ");
|
|
}
|
|
|
|
if(res[i][j] & GCRU)
|
|
if(res[i][j] & GCRBLKP)
|
|
TxPrintf("#");
|
|
else
|
|
if(res[i][j+1] & GCRBLKP)
|
|
TxPrintf("#");
|
|
else
|
|
if(res[i][j] & GCRVM)
|
|
TxPrintf("#");
|
|
else
|
|
TxPrintf("-");
|
|
else
|
|
if((res[i][j] & GCRBLKM) && (res[i][j] & GCRBLKP))
|
|
TxPrintf("~");
|
|
else
|
|
if( ((res[i][j] & GCRBLKM) && (res[i][j+1] & GCRBLKP)) ||
|
|
((res[i][j] & GCRBLKP) && (res[i][j+1] & GCRBLKM)) )
|
|
TxPrintf("~");
|
|
else
|
|
if((res[i][j+1] & GCRBLKM) && (res[i][j+1] & GCRBLKP))
|
|
TxPrintf("~");
|
|
else
|
|
if((res[i][j] & GCRBLKM) || (res[i][j+1] & GCRBLKM))
|
|
TxPrintf("'");
|
|
else
|
|
if((res[i][j] & GCRBLKP) || (res[i][j+1] & GCRBLKP))
|
|
TxPrintf("`");
|
|
else
|
|
TxPrintf(" ");
|
|
}
|
|
if(ch->gcr_tPins[i].gcr_pId!=(GCRNet *) 0)
|
|
TxPrintf(":%2d {%2d}", (int) ch->gcr_tPins[i].gcr_pId->gcr_Id,
|
|
ch->gcr_density[i]);
|
|
else
|
|
TxPrintf(": {%2d}", ch->gcr_density[i]);
|
|
}
|
|
|
|
TxPrintf("\n :");
|
|
for(j=0; j<=ch->gcr_width; j++)
|
|
{
|
|
if(j!=0)
|
|
{
|
|
if(res[i][j] & GCRR)
|
|
if(res[i][j] & GCRBLKM)
|
|
TxPrintf("|");
|
|
else
|
|
if((i<=ch->gcr_length) && (res[i+1][j] & GCRBLKM))
|
|
TxPrintf("|");
|
|
else
|
|
TxPrintf("#");
|
|
else
|
|
if(((res[i][j] & GCRBLKM)&&(res[i][j] & GCRBLKP)) ||
|
|
((res[i+1][j] & GCRBLKM)&&(res[i+1][j] & GCRBLKP)))
|
|
TxPrintf("~");
|
|
else
|
|
if((res[i][j] & GCRBLKM) || (res[i+1][j] & GCRBLKM))
|
|
TxPrintf("'");
|
|
else
|
|
if((res[i][j] & GCRBLKP) || (res[i+1][j] & GCRBLKP))
|
|
TxPrintf("`");
|
|
else
|
|
TxPrintf(" ");
|
|
}
|
|
else
|
|
if((j!=0) && (i!=0))
|
|
{
|
|
if(res[i-1][j] & GCRR)
|
|
if(res[i-1][j] & GCRBLKM)
|
|
TxPrintf("|");
|
|
else
|
|
if((i<ch->gcr_length) && (res[i][j] & GCRBLKM))
|
|
TxPrintf("|");
|
|
else
|
|
TxPrintf("#");
|
|
else
|
|
if(((res[i-1][j] & GCRBLKM)&&(res[i-1][j] & GCRBLKP)) ||
|
|
((res[i ][j] & GCRBLKM)&&(res[i ][j] & GCRBLKP)))
|
|
TxPrintf("~");
|
|
else
|
|
if((res[i-1][j] & GCRBLKM) || (res[i][j] & GCRBLKM))
|
|
TxPrintf("'");
|
|
else
|
|
if((res[i-1][j] & GCRBLKP) || (res[i][j] & GCRBLKP))
|
|
TxPrintf("`");
|
|
else
|
|
TxPrintf(" ");
|
|
}
|
|
|
|
if((((res[i][j] & GCRBLKM) && (res[i][j] & GCRBLKP)) ||
|
|
((res[i][j+1] & GCRBLKM) && (res[i][j+1] & GCRBLKP))) ||
|
|
(((res[i+1][j] & GCRBLKM) && (res[i+1][j] & GCRBLKP)) ||
|
|
((res[i+1][j+1] & GCRBLKM) && (res[i+1][j+1] & GCRBLKP))))
|
|
TxPrintf("~");
|
|
else
|
|
if(((res[i][j] & GCRBLKM) || (res[i][j+1] & GCRBLKM))||
|
|
((res[i+1][j] & GCRBLKM) || (res[i+1][j+1] & GCRBLKM)))
|
|
TxPrintf("'");
|
|
else
|
|
if(((res[i][j] & GCRBLKP) || (res[i][j+1] & GCRBLKP))||
|
|
((res[i+1][j] & GCRBLKP) || (res[i+1][j+1] & GCRBLKP)))
|
|
TxPrintf("`");
|
|
else
|
|
TxPrintf(" ");
|
|
}
|
|
TxPrintf(":\n");
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* gcrStats --
|
|
*
|
|
* Print routing statistics.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
gcrStats(ch)
|
|
GCRChannel * ch;
|
|
{
|
|
int wireLength=0, viaCount=0, row, col;
|
|
short **res, mask, code, code2;
|
|
int hWire=0, vWire=0;
|
|
|
|
viaCount=0;
|
|
res=ch->gcr_result;
|
|
for(col=0; col<=ch->gcr_length; col++)
|
|
for(row=0; row<=ch->gcr_width; row++)
|
|
{
|
|
code=res[col][row];
|
|
if(code & GCRR)
|
|
{
|
|
wireLength++;
|
|
hWire++;
|
|
}
|
|
if(code & GCRU)
|
|
{
|
|
wireLength++;
|
|
vWire++;
|
|
}
|
|
if(code & GCRX)
|
|
{
|
|
/* There is a connection at the crossing. Count a contact if metal
|
|
* and poly come together here.
|
|
*/
|
|
mask=0;
|
|
code2=ch->gcr_result[col][row+1];
|
|
if(code&GCRU)
|
|
{
|
|
if(code&GCRVM) mask|=GCRBLKM; /*What type is up*/
|
|
else mask|=GCRBLKP;
|
|
}
|
|
code2=ch->gcr_result[col+1][row];
|
|
if(code&GCRR)
|
|
{
|
|
if(code2&GCRBLKM) mask|=GCRBLKP; /*What type is right*/
|
|
else mask|=GCRBLKM;
|
|
}
|
|
code2=ch->gcr_result[col][row-1];
|
|
if(code2&GCRU)
|
|
{
|
|
if(code2&GCRVM) mask|=GCRBLKM; /*What type is down*/
|
|
else mask|=GCRBLKP;
|
|
}
|
|
code2=ch->gcr_result[col-1][row];
|
|
if(code2&GCRR)
|
|
{
|
|
if(code2&GCRBLKM) mask|=GCRBLKP; /*What type is left*/
|
|
else mask|=GCRBLKM;
|
|
}
|
|
if((mask!=GCRBLKM)&&(mask!=GCRBLKP))
|
|
viaCount++;
|
|
}
|
|
}
|
|
TxPrintf("Length : %d\n", wireLength);
|
|
TxPrintf("Vias : %d\n", viaCount);
|
|
TxPrintf("Hwire : %d\n", hWire);
|
|
TxPrintf("Vwire : %d\n", vWire);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* gcrCheckCol --
|
|
*
|
|
* Check the accuracy of the column's hi and lo pointers. Abort if there
|
|
* is a mistake.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
gcrCheckCol(ch, c, where)
|
|
GCRChannel *ch;
|
|
int c;
|
|
char *where;
|
|
{
|
|
int i, j;
|
|
GCRColEl * col;
|
|
|
|
if(GcrNoCheck)
|
|
return;
|
|
col=ch->gcr_lCol;
|
|
for(i=0; i<=ch->gcr_width; i++)
|
|
{
|
|
if( (col[i].gcr_hOk || col[i].gcr_lOk) && (col[i].gcr_h==(GCRNet *) 0))
|
|
{
|
|
if(gcrStandalone)
|
|
{
|
|
TxError("Botch at column %d, %s (bad hOk/lOk at %d)\n",
|
|
c, where, i);
|
|
gcrDumpCol(col, ch->gcr_width);
|
|
}
|
|
if(GcrDebug)
|
|
niceabort();
|
|
}
|
|
if(((col[i].gcr_hi==i)||(col[i].gcr_lo==i))&&(i!=0))
|
|
{
|
|
if(gcrStandalone)
|
|
{
|
|
TxError("Botch at column %d, %s(pointer loop at %d)\n",
|
|
c, where, i);
|
|
gcrDumpCol(col, ch->gcr_width);
|
|
}
|
|
if(GcrDebug)
|
|
niceabort();
|
|
}
|
|
if(col[i].gcr_h!=(GCRNet *) NULL)
|
|
|
|
/* Look upward from the track for the next higher track assigned to
|
|
* the net, if any. Just take the first one, breaking afterwards.
|
|
*/
|
|
for(j=i+1; j<=ch->gcr_width; j++)
|
|
{
|
|
if(col[j].gcr_h==col[i].gcr_h)
|
|
{
|
|
/* Check to see if the lower track at i points to the higher
|
|
* track at j, and vice versa. If an error, abort.
|
|
*/
|
|
if( ((col[j].gcr_lo!=i) && !col[j].gcr_lOk &&
|
|
!col[i].gcr_hOk) ||
|
|
((col[i].gcr_hi!=j) && !col[i].gcr_hOk &&
|
|
!col[j].gcr_lOk) )
|
|
{
|
|
if(gcrStandalone)
|
|
{
|
|
TxError("Botch at column %d, %s", c, where);
|
|
TxError(" (link error from %d to %d)\n", i, j);
|
|
gcrDumpCol(col, ch->gcr_width);
|
|
}
|
|
if(GcrDebug) niceabort();
|
|
}
|
|
else break;
|
|
}
|
|
}
|
|
if((col[i].gcr_hi>ch->gcr_width)||(col[i].gcr_hi< EMPTY)||
|
|
(col[i].gcr_lo>ch->gcr_width)||(col[i].gcr_lo< EMPTY))
|
|
{
|
|
if(gcrStandalone)
|
|
{
|
|
TxError("Botch at column %d, %s (bounds)\n", c, where);
|
|
gcrDumpCol(col, ch->gcr_width);
|
|
}
|
|
if(GcrDebug) niceabort();
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* gcrShowMap --
|
|
*
|
|
* Print the bit map in the result array for the selected field.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
gcrShowMap(ch)
|
|
GCRChannel * ch;
|
|
{
|
|
int i, j, field;
|
|
short ** res;
|
|
char buff[512];
|
|
|
|
if (!GcrShowMap)
|
|
return;
|
|
|
|
while (1)
|
|
{
|
|
TxPrintf("Field selector (0 terminates): ");
|
|
if(scanf("%d", &field) != 1) /*typed something funny or EOF*/
|
|
{
|
|
if (feof(stdin)) {
|
|
TxPrintf("End of input detected. Terminating.\n");
|
|
return;
|
|
}
|
|
TxPrintf("Bad input. Legal responses are\n");
|
|
TxPrintf(" GCRBLKM 1\n");
|
|
TxPrintf(" GCRBLKP 2\n");
|
|
TxPrintf(" GCRU 4\n");
|
|
TxPrintf(" GCRR 8\n");
|
|
TxPrintf(" GCRX 16\n");
|
|
TxPrintf(" GCRVL 32\n");
|
|
TxPrintf(" GCRV2 64\n");
|
|
TxPrintf(" GCRTC 128\n");
|
|
TxPrintf(" GCRCC 256\n");
|
|
TxPrintf(" GCRTE 512\n");
|
|
TxPrintf(" GCRCE 1024\n");
|
|
TxPrintf(" GCRVM 2048\n");
|
|
TxPrintf(" GCRXX 4096\n");
|
|
TxPrintf(" GCRVR 8192\n");
|
|
TxPrintf(" GCRVU 16384\n");
|
|
TxPrintf(" GCRVD 32768\n");
|
|
(void) fgets(buff, 512, stdin);
|
|
}
|
|
TxPrintf("\n%d\n", field);
|
|
if(field==0)
|
|
return;
|
|
|
|
TxPrintf("\n ");
|
|
for(j=0; j<=ch->gcr_width+1; j++)
|
|
TxPrintf("%2d", j);
|
|
|
|
for(i=0; i<=ch->gcr_length+1; i++)
|
|
{
|
|
res=ch->gcr_result;
|
|
TxPrintf("\n[%3d] ", i);
|
|
for(j=0; j<=ch->gcr_width+1; j++)
|
|
{
|
|
if(res[i][j] & field)
|
|
TxPrintf("1 ");
|
|
else
|
|
TxPrintf(". ");
|
|
}
|
|
}
|
|
TxPrintf("\n");
|
|
}
|
|
}
|