magic/grouter/grouteTest.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();
}