599 lines
14 KiB
C
599 lines
14 KiB
C
/*
|
|
* grouteTest.c --
|
|
*
|
|
* Testing code for the global router.
|
|
*
|
|
* *********************************************************************
|
|
* * 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/grouter/grouteTest.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
|
#endif /* not lint */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "utils/magic.h"
|
|
#include "utils/geometry.h"
|
|
#include "utils/hash.h"
|
|
#include "utils/heap.h"
|
|
#include "tiles/tile.h"
|
|
#include "database/database.h"
|
|
#include "utils/signals.h"
|
|
#include "textio/textio.h"
|
|
#include "debug/debug.h"
|
|
#include "gcr/gcr.h"
|
|
#include "router/router.h"
|
|
#include "grouter/grouter.h"
|
|
#include "graphics/graphics.h"
|
|
#include "windows/windows.h"
|
|
#include "dbwind/dbwind.h"
|
|
#include "textio/txcommands.h"
|
|
#include "utils/main.h"
|
|
#include "utils/utils.h"
|
|
#include "commands/commands.h"
|
|
#include "utils/malloc.h"
|
|
#include "utils/styles.h"
|
|
#include "utils/netlist.h"
|
|
|
|
bool glInitialized = FALSE;
|
|
|
|
ClientData glDebugID = 0;
|
|
|
|
int glDebAllPoints = 0;
|
|
int glDebChan = 0;
|
|
int glDebCross = 0;
|
|
int glDebFast = 0;
|
|
int glDebHeap = 0;
|
|
int glDebHisto = 0;
|
|
int glDebLog = 0;
|
|
int glDebGreedy = 0;
|
|
int glDebMaze = 0;
|
|
int glDebNet = 0;
|
|
int glDebNewHeaps = 0;
|
|
int glDebPen = 0;
|
|
int glDebShowPins = 0;
|
|
int glDebStemsOnly = 0;
|
|
int glDebStraight = 0;
|
|
int glDebTiles = 0;
|
|
int glDebVerbose = 0;
|
|
|
|
/* Statistics */
|
|
int glCrossingsSeen; /* Total crossings seen */
|
|
int glCrossingsAdded; /* Total crossings added to heap */
|
|
int glCrossingsExpanded; /* Total crossings expanded from */
|
|
int glCrossingsUsed; /* Total crossings used */
|
|
int glGoodRoutes; /* Good point to point routes */
|
|
int glBadRoutes; /* Bad point to point routes */
|
|
int glNoRoutes;
|
|
|
|
/* Used in debugging; if set, we only route a single net */
|
|
char *glOnlyNet = NULL;
|
|
|
|
/*
|
|
* Used to remember the number of frontier points visited, and the
|
|
* number of points removed from the top of the heap, for each two
|
|
* point net routed.
|
|
*/
|
|
GlNetHisto *glNetHistoList = NULL;
|
|
|
|
/* Forward declarations */
|
|
void GlInit();
|
|
void glShowCross();
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* GlTest --
|
|
*
|
|
* Command interface for testing the global router.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Depends on the command; see below.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
GlTest(w, cmd)
|
|
MagWindow *w;
|
|
TxCommand *cmd;
|
|
{
|
|
int glDebugSides();
|
|
typedef enum { CLRDEBUG, ONLYNET, SETDEBUG, SHOWDEBUG, SIDES } cmdType;
|
|
Rect editArea;
|
|
int n;
|
|
static struct
|
|
{
|
|
char *cmd_name;
|
|
cmdType cmd_val;
|
|
} cmds[] = {
|
|
"clrdebug", CLRDEBUG,
|
|
"onlynet", ONLYNET,
|
|
"setdebug", SETDEBUG,
|
|
"showdebug", SHOWDEBUG,
|
|
"sides", SIDES,
|
|
0
|
|
};
|
|
|
|
if (!glInitialized)
|
|
GlInit();
|
|
|
|
if (cmd->tx_argc == 1)
|
|
{
|
|
TxError("Must give subcommand\n");
|
|
goto badCmd;
|
|
}
|
|
|
|
n = LookupStruct(cmd->tx_argv[1], (LookupTable *) cmds, sizeof cmds[0]);
|
|
if (n < 0)
|
|
{
|
|
TxError("Unrecognized subcommand: %s\n", cmd->tx_argv[1]);
|
|
badCmd:
|
|
TxError("Valid subcommands:");
|
|
for (n = 0; cmds[n].cmd_name; n++)
|
|
TxError(" %s", cmds[n].cmd_name);
|
|
TxError("\n");
|
|
return;
|
|
}
|
|
|
|
switch (cmds[n].cmd_val)
|
|
{
|
|
case SETDEBUG:
|
|
DebugSet(glDebugID, cmd->tx_argc - 2, &cmd->tx_argv[2], TRUE);
|
|
break;
|
|
case CLRDEBUG:
|
|
DebugSet(glDebugID, cmd->tx_argc - 2, &cmd->tx_argv[2], FALSE);
|
|
break;
|
|
case SHOWDEBUG:
|
|
DebugShow(glDebugID);
|
|
break;
|
|
case SIDES:
|
|
if (!ToolGetEditBox(&editArea)) return;
|
|
n = -1;
|
|
if (cmd->tx_argc > 2)
|
|
{
|
|
if (!StrIsInt(cmd->tx_argv[2]))
|
|
{
|
|
TxError("Minimum channel width must be numeric\n");
|
|
break;
|
|
}
|
|
n = atoi(cmd->tx_argv[2]);
|
|
}
|
|
(void) rtrEnumSides(EditCellUse, &editArea, n,
|
|
glDebugSides, (ClientData) NULL);
|
|
case ONLYNET:
|
|
if (cmd->tx_argc == 2)
|
|
{
|
|
if (glOnlyNet)
|
|
TxPrintf("Routing only net: %s\n", glOnlyNet);
|
|
else
|
|
TxPrintf("Routing all nets.\n");
|
|
}
|
|
else if (cmd->tx_argc == 3)
|
|
{
|
|
if (strcmp(cmd->tx_argv[2], "-") == 0)
|
|
{
|
|
if (glOnlyNet)
|
|
{
|
|
freeMagic(glOnlyNet);
|
|
glOnlyNet = NULL;
|
|
}
|
|
TxPrintf("Routing all nets.\n");
|
|
}
|
|
else
|
|
{
|
|
(void) StrDup(&glOnlyNet, cmd->tx_argv[2]);
|
|
TxPrintf("Routing only net: %s\n", glOnlyNet);
|
|
}
|
|
}
|
|
else TxError("Usage: *groute onlynet [net | -]\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
int
|
|
glDebugSides(side)
|
|
Side *side;
|
|
{
|
|
char mesg[256];
|
|
CellDef *def = EditCellUse->cu_def;
|
|
Rect r;
|
|
|
|
GeoTransRect(&side->side_trans, &side->side_search, &r);
|
|
ShowRect(def, &r, STYLE_SOLIDHIGHLIGHTS);
|
|
(void) sprintf(mesg, "SEARCH %d %d %d %d\n",
|
|
r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop);
|
|
TxMore(mesg);
|
|
ShowRect(def, &r, STYLE_ERASEHIGHLIGHTS);
|
|
|
|
GeoTransRect(&side->side_trans, &side->side_used, &r);
|
|
ShowRect(def, &r, STYLE_MEDIUMHIGHLIGHTS);
|
|
(void) sprintf(mesg, "USED %d %d %d %d\n",
|
|
r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop);
|
|
TxMore(mesg);
|
|
ShowRect(def, &r, STYLE_ERASEHIGHLIGHTS);
|
|
|
|
(void) TxPrintf("--------\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* GlInit --
|
|
*
|
|
* One-time-only initialization for the global router.
|
|
* Called after technology initialization.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Register ourself with the debug module and list all
|
|
* debugging flags.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
GlInit()
|
|
{
|
|
int n;
|
|
static struct
|
|
{
|
|
char *di_name;
|
|
int *di_id;
|
|
} dflags[] = {
|
|
"allpoints", &glDebAllPoints,
|
|
"chan", &glDebChan,
|
|
"cross", &glDebCross,
|
|
"fast", &glDebFast,
|
|
"heap", &glDebHeap,
|
|
"histo", &glDebHisto,
|
|
"log", &glDebLog,
|
|
"greedy", &glDebGreedy,
|
|
"maze", &glDebMaze,
|
|
"net", &glDebNet,
|
|
"newheaps", &glDebNewHeaps,
|
|
"penalties", &glDebPen,
|
|
"showpins", &glDebShowPins,
|
|
"stemsonly", &glDebStemsOnly,
|
|
"straight", &glDebStraight,
|
|
"tiles", &glDebTiles,
|
|
"verbose", &glDebVerbose,
|
|
0
|
|
};
|
|
|
|
if (glInitialized)
|
|
return;
|
|
|
|
glInitialized = TRUE;
|
|
|
|
/* Register ourselves with the debugging module */
|
|
glDebugID = DebugAddClient("grouter", sizeof dflags/sizeof dflags[0]);
|
|
for (n = 0; dflags[n].di_name; n++)
|
|
*(dflags[n].di_id) = DebugAddFlag(glDebugID, dflags[n].di_name);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* glShowPath --
|
|
*
|
|
* Display the crossing points along an entire path for debugging.
|
|
* The type of crossing point is indicated by 'kind'.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Causes redisplay.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
glShowPath(dest, root, kind)
|
|
GlPoint *dest, *root;
|
|
int kind;
|
|
{
|
|
static NetId dummyId = { 0, 0 };
|
|
GlPoint *temp;
|
|
|
|
for (temp = dest; temp != root; temp = temp->gl_path)
|
|
glShowCross(temp->gl_pin, dummyId, kind);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* glShowCross --
|
|
*
|
|
* Display a crossing point for debugging.
|
|
* Two kinds of crossing points can be shown: CROSS_TEMP, which
|
|
* is only being considered, and CROSS_PERM, which has been permanently
|
|
* assigned to a net. In addition, CROSS_ERASE will cause the crossing
|
|
* point to be erased.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Causes redisplay.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
glShowCross(pin, netId, kind)
|
|
GCRPin *pin; /* Pin itself */
|
|
NetId netId; /* Identifies net and segment for this pin */
|
|
int kind; /* Determines kind of display; see above */
|
|
{
|
|
char *name, name1[1024], name2[1024];
|
|
int style;
|
|
Rect r;
|
|
|
|
switch (kind)
|
|
{
|
|
case CROSS_TEMP:
|
|
name = "temp";
|
|
style = STYLE_MEDIUMHIGHLIGHTS;
|
|
break;
|
|
case CROSS_PERM:
|
|
name = "PERM";
|
|
style = STYLE_SOLIDHIGHLIGHTS;
|
|
break;
|
|
case CROSS_ERASE:
|
|
name = (char *) NULL;
|
|
style = STYLE_ERASEHIGHLIGHTS;
|
|
break;
|
|
}
|
|
|
|
if (name && DebugIsSet(glDebugID, glDebMaze))
|
|
{
|
|
(void) strcpy(name1, NLNetName(pin->gcr_pId));
|
|
(void) strcpy(name2, NLNetName(netId.netid_net));
|
|
TxPrintf("%s (%d,%d), Net %s/%d->%s/%d, Ch %d\n",
|
|
name, pin->gcr_point.p_x, pin->gcr_point.p_y,
|
|
name1, pin->gcr_pSeg, name2, netId.netid_seg, pin->gcr_ch);
|
|
}
|
|
|
|
r.r_ll = r.r_ur = pin->gcr_point;
|
|
r.r_xtop += RtrMetalWidth;
|
|
r.r_ytop += RtrMetalWidth;
|
|
ShowRect(EditCellUse->cu_def, &r, style);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* glHistoAdd --
|
|
*
|
|
* Remember the number of heap, frontier, and starting points
|
|
* used during a given route by adding them to the GlNetHisto
|
|
* list.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Allocates memory; prepends a new entry to glNetHistoList.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
glHistoAdd(heapPtsBefore, frontierPtsBefore, startPtsBefore)
|
|
int heapPtsBefore, frontierPtsBefore, startPtsBefore;
|
|
{
|
|
GlNetHisto *gh;
|
|
|
|
gh = (GlNetHisto *) mallocMagic((unsigned) (sizeof (GlNetHisto)));
|
|
gh->glh_heap = glCrossingsExpanded - heapPtsBefore;
|
|
gh->glh_frontier = glCrossingsAdded - frontierPtsBefore;
|
|
gh->glh_start = startPtsBefore;
|
|
gh->glh_next = glNetHistoList;
|
|
glNetHistoList = gh;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* glHistoDump --
|
|
*
|
|
* Dump the information accumulated by glHistoAdd() above
|
|
* to the file HISTO.out in the current directory.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Creates HISTO.out.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
glHistoDump()
|
|
{
|
|
static char hname[] = "HISTO.out";
|
|
int lastsize, count, total;
|
|
GlNetHisto *gh;
|
|
Heap histoHeap;
|
|
HeapEntry entry;
|
|
FILE *fp;
|
|
|
|
fp = fopen(hname, "w");
|
|
if (fp == NULL)
|
|
{
|
|
perror(hname);
|
|
return;
|
|
}
|
|
|
|
/* Raw data */
|
|
fprintf(fp, "--------- raw data ---------\n");
|
|
fprintf(fp, "%9s %9s %9s\n", "HEAP", "FRONTIER", "START");
|
|
for (gh = glNetHistoList; gh; gh = gh->glh_next)
|
|
{
|
|
fprintf(fp, "%9d %9d %9d\n",
|
|
gh->glh_heap, gh->glh_frontier, gh->glh_start);
|
|
}
|
|
|
|
/* Output sorted by number of heap points */
|
|
fprintf(fp, "--------- by heap points ---------\n");
|
|
HeapInit(&histoHeap, 128, FALSE, FALSE);
|
|
for (gh = glNetHistoList; gh; gh = gh->glh_next)
|
|
HeapAddInt(&histoHeap, gh->glh_heap, (char *) gh);
|
|
count = lastsize = total = 0;
|
|
while (HeapRemoveTop(&histoHeap, &entry))
|
|
{
|
|
gh = (GlNetHisto *) entry.he_id;
|
|
if (gh->glh_heap != lastsize)
|
|
{
|
|
if (count > 0)
|
|
fprintf(fp, "%d: %d\n", lastsize, count);
|
|
lastsize = gh->glh_heap;
|
|
count = 0;
|
|
}
|
|
count++, total++;
|
|
}
|
|
HeapKill(&histoHeap, (void (*)()) NULL);
|
|
if (count > 0)
|
|
fprintf(fp, "%d: %d\n", lastsize, count);
|
|
fprintf(fp, "TOTAL: %d\n", total);
|
|
|
|
/* Output sorted by number of frontier points */
|
|
fprintf(fp, "--------- by frontier points ---------\n");
|
|
HeapInit(&histoHeap, 128, FALSE, FALSE);
|
|
for (gh = glNetHistoList; gh; gh = gh->glh_next)
|
|
HeapAddInt(&histoHeap, gh->glh_frontier, (char *) gh);
|
|
count = lastsize = total = 0;
|
|
while (HeapRemoveTop(&histoHeap, &entry))
|
|
{
|
|
gh = (GlNetHisto *) entry.he_id;
|
|
if (gh->glh_frontier != lastsize)
|
|
{
|
|
if (count > 0)
|
|
fprintf(fp, "%d: %d\n", lastsize, count);
|
|
lastsize = gh->glh_frontier;
|
|
count = 0;
|
|
}
|
|
count++, total++;
|
|
}
|
|
HeapKill(&histoHeap, (void (*)()) NULL);
|
|
if (count > 0)
|
|
fprintf(fp, "%d: %d\n", lastsize, count);
|
|
fprintf(fp, "TOTAL: %d\n", total);
|
|
|
|
/* Free memory */
|
|
for (gh = glNetHistoList; gh; gh = gh->glh_next)
|
|
freeMagic((char *) gh);
|
|
glNetHistoList = NULL;
|
|
|
|
/* Done */
|
|
(void) fclose(fp);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* glStatsInit --
|
|
*
|
|
* Initialize statistics and debugging info for this
|
|
* global routing session.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Zeroes lots of global counters.
|
|
* Zeroes glNetHistoList.
|
|
* May create the crossings log file ("CROSSINGS.log") and
|
|
* leave glLogFile pointing to the open file.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
glStatsInit()
|
|
{
|
|
char *logFileName = "CROSSINGS.log";
|
|
|
|
glCrossingsSeen = 0;
|
|
glCrossingsAdded = 0;
|
|
glCrossingsExpanded = 0;
|
|
glCrossingsUsed = 0;
|
|
glGoodRoutes = 0;
|
|
glBadRoutes = 0;
|
|
glNoRoutes = 0;
|
|
glNumTries = 0;
|
|
|
|
glNetHistoList = NULL;
|
|
if (DebugIsSet(glDebugID, glDebLog))
|
|
{
|
|
glLogFile = fopen(logFileName, "w");
|
|
if (glLogFile == (FILE *) NULL)
|
|
perror(logFileName);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* glStatsDone --
|
|
*
|
|
* Print statistics accumulated during this routing session.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Prints statistics.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
glStatsDone(numNets, numTerms)
|
|
int numNets;
|
|
int numTerms;
|
|
{
|
|
|
|
if (DebugIsSet(glDebugID, glDebVerbose))
|
|
{
|
|
TxPrintf("\n");
|
|
TxPrintf(" %d nets, %d terminals.\n", numNets, numTerms);
|
|
TxPrintf(" %d good, %d bad two-point routes,\n",
|
|
glGoodRoutes, glBadRoutes);
|
|
TxPrintf(" %d failed when considering penalties,\n", glNoRoutes);
|
|
TxPrintf(" %d total connections.\n", glGoodRoutes + glBadRoutes);
|
|
TxPrintf(" %d crossings seen, %d added to heap.\n",
|
|
glCrossingsSeen, glCrossingsAdded);
|
|
TxPrintf(" %d crossings %d used.\n",
|
|
glCrossingsExpanded, glCrossingsUsed);
|
|
}
|
|
|
|
if (DebugIsSet(glDebugID, glDebLog) && glLogFile)
|
|
(void) fclose(glLogFile);
|
|
if (DebugIsSet(glDebugID, glDebHisto))
|
|
glHistoDump();
|
|
}
|