417 lines
11 KiB
C
417 lines
11 KiB
C
/*
|
|
* gaTest.c --
|
|
*
|
|
* Testing code for the gate-array 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/garouter/gaTest.c,v 1.2 2009/05/01 18:59:44 tim Exp $";
|
|
#endif /* not lint */
|
|
|
|
#include <stdio.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 "garouter/garouter.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/styles.h"
|
|
|
|
bool gaInitialized = FALSE;
|
|
|
|
ClientData gaDebugID = 0;
|
|
|
|
int gaDebChanOnly = 0;
|
|
int gaDebChanStats = 0;
|
|
int gaDebMaze = 0;
|
|
int gaDebNoSimple = 0;
|
|
int gaDebPaintStems = 0;
|
|
int gaDebShowChans = 0;
|
|
int gaDebShowMaze = 0;
|
|
int gaDebStems = 0;
|
|
int gaDebVerbose = 0;
|
|
int gaDebNoClean = 0;
|
|
|
|
/* Used in the "*garoute split" command */
|
|
PlaneMask gaSplitPlaneMask;
|
|
int (*gaSplitPaintPlane)();
|
|
Rect gaSplitArea;
|
|
int gaSplitType;
|
|
|
|
/* Forward declarations */
|
|
|
|
void GAInit();
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* GATest --
|
|
*
|
|
* Command interface for testing the gate-array router.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Depends on the command; see below.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
GATest(w, cmd)
|
|
MagWindow *w;
|
|
TxCommand *cmd;
|
|
{
|
|
int n;
|
|
typedef enum { CLRDEBUG, SETDEBUG, SHOWDEBUG} cmdType;
|
|
static const struct
|
|
{
|
|
char *cmd_name;
|
|
cmdType cmd_val;
|
|
} cmds[] = {
|
|
{"clrdebug", CLRDEBUG},
|
|
{"setdebug", SETDEBUG},
|
|
{"showdebug", SHOWDEBUG},
|
|
{0}
|
|
};
|
|
|
|
GAInit();
|
|
if (cmd->tx_argc == 1)
|
|
{
|
|
TxError("Must give subcommand\n");
|
|
goto badCmd;
|
|
}
|
|
|
|
n = LookupStruct(cmd->tx_argv[1], (const 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(gaDebugID, cmd->tx_argc - 2, &cmd->tx_argv[2], TRUE);
|
|
break;
|
|
case CLRDEBUG:
|
|
DebugSet(gaDebugID, cmd->tx_argc - 2, &cmd->tx_argv[2], FALSE);
|
|
break;
|
|
case SHOWDEBUG:
|
|
DebugShow(gaDebugID);
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* GAGenChans --
|
|
*
|
|
* Generate gate-array channels over the area 'area'. These channels
|
|
* will be one of two types: CHAN_NORMAL, for channels over empty space,
|
|
* or chanType (either CHAN_HRIVER or CHAN_VRIVER) for channels over
|
|
* existing subcells. The output is a collection of "garoute channel"
|
|
* commands on the file 'f'.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Writes to 'f'.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
GAGenChans(chanType, area, f)
|
|
int chanType;
|
|
Rect *area;
|
|
FILE *f;
|
|
{
|
|
extern int DBPaintPlane0(), DBPaintPlaneVert();
|
|
int gaSplitFunc(), gaSplitOut();
|
|
static CellDef *genDef = (CellDef *) NULL;
|
|
static CellUse *genUse = (CellUse *) NULL;
|
|
TileTypeBitMask obstacleMask;
|
|
int halfUp, halfDown;
|
|
SearchContext scx;
|
|
Plane *plane;
|
|
|
|
if (genDef == NULL)
|
|
DBNewYank("__GENCHANNEL__", &genUse, &genDef);
|
|
|
|
/*
|
|
* Round the appropriate side of area down to the nearest
|
|
* center-grid line.
|
|
*/
|
|
halfDown = RtrGridSpacing / 2;
|
|
halfUp = RtrGridSpacing - halfDown;
|
|
switch (chanType)
|
|
{
|
|
case CHAN_HRIVER:
|
|
gaSplitPaintPlane = DBPaintPlane0;
|
|
area->r_ytop = RTR_GRIDDOWN(area->r_ytop - halfUp, RtrOrigin.p_y)
|
|
+ halfUp;
|
|
area->r_ybot = RTR_GRIDUP(area->r_ybot + halfDown, RtrOrigin.p_y)
|
|
- halfDown;
|
|
break;
|
|
case CHAN_VRIVER:
|
|
gaSplitPaintPlane = DBPaintPlaneVert;
|
|
area->r_xtop = RTR_GRIDDOWN(area->r_xtop - halfUp, RtrOrigin.p_x)
|
|
+ halfUp;
|
|
area->r_xbot = RTR_GRIDUP(area->r_xbot + halfDown, RtrOrigin.p_x)
|
|
- halfDown;
|
|
break;
|
|
}
|
|
|
|
/* Make sure everything in 'area' is read */
|
|
(void) DBCellReadArea(EditCellUse, area, FALSE);
|
|
DBFixMismatch();
|
|
|
|
/* Start with a clean slate */
|
|
DBCellClearDef(genDef);
|
|
|
|
/*
|
|
* Basic algorithm:
|
|
* Find all cells in 'area'. Compute the bounding rectangle for
|
|
* each plane that can affect routing. Bloat by RtrSubcellSepUp or
|
|
* RtrSubcellSepDown (appropriate direction). Extend this to the top
|
|
* and bottom of 'area' for CHAN_HRIVER channels, or to the left and
|
|
* right of 'area' for CHAN_VRIVER ones, and paint into the DRC error
|
|
* plane of genDef.
|
|
*/
|
|
TTMaskSetMask3(&obstacleMask, &RtrPolyObstacles, &RtrMetalObstacles);
|
|
TTMaskSetType(&obstacleMask, RtrMetalType);
|
|
TTMaskSetType(&obstacleMask, RtrPolyType);
|
|
TTMaskSetType(&obstacleMask, RtrContactType);
|
|
gaSplitPlaneMask = DBTechTypesToPlanes(&obstacleMask);
|
|
gaSplitArea = *area;
|
|
gaSplitType = chanType;
|
|
scx.scx_use = EditCellUse;
|
|
scx.scx_area = gaSplitArea;
|
|
scx.scx_trans = GeoIdentityTransform;
|
|
plane = genDef->cd_planes[PL_DRC_ERROR];
|
|
(void) DBCellSrArea(&scx, gaSplitFunc, (ClientData) plane);
|
|
|
|
/* Output all the tiles that lie inside 'area' in 'plane */
|
|
(void) DBSrPaintArea((Tile *) NULL, plane, &gaSplitArea, &DBAllTypeBits,
|
|
gaSplitOut, (ClientData) f);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* gaSplitOut --
|
|
*
|
|
* Called for each tile inside the area that was processed by GAGenChans()
|
|
* above. Outputs each tile as the appropriate type of channel (space
|
|
* tiles are CHAN_NORMAL, non-space are either CHAN_HRIVER or CHAN_VRIVER)
|
|
* after first clipping to the area gaSplitArea.
|
|
*
|
|
* Results:
|
|
* Always returns 0.
|
|
*
|
|
* Side effects:
|
|
* Writes to 'f'.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
gaSplitOut(tile, f)
|
|
Tile *tile;
|
|
FILE *f;
|
|
{
|
|
Rect r;
|
|
|
|
TITORECT(tile, &r);
|
|
GeoClip(&r, &gaSplitArea);
|
|
if (GEO_RECTNULL(&r))
|
|
return (0);
|
|
|
|
fprintf(f, "garoute channel %d %d %d %d",
|
|
r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop);
|
|
if (TiGetType(tile) != TT_SPACE)
|
|
fprintf(f, " %s", gaSplitType == CHAN_HRIVER ? "h" : "v");
|
|
fprintf(f, "\n");
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* gaSplitFunc --
|
|
*
|
|
* Called for each cell in the area being processed by GAGenChans()
|
|
* above. Computes a "true" bounding box for the cell (only looking
|
|
* at the layers that are obstacles to routing), and then extends the
|
|
* box as follows:
|
|
*
|
|
* If producing CHAN_HRIVER channels, we extend the box to the
|
|
* top and bottom of gaSplitArea, and bloat it to the right and
|
|
* left to the next farthest-out line between two grid lines.
|
|
*
|
|
* If producing CHAN_VRIVER channels, we extend the box to the
|
|
* left and right of gaSplitArea, and bloat it to the top and
|
|
* bottom to the next farthest-out line between two grid lines.
|
|
*
|
|
* Results:
|
|
* Always returns 0.
|
|
*
|
|
* Side effects:
|
|
* Paints the bloated area into the DRC error plane of 'plane'
|
|
* with a TileType of 1.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
gaSplitFunc(scx, plane)
|
|
SearchContext *scx;
|
|
Plane *plane;
|
|
{
|
|
int halfUp, halfDown;
|
|
CellDef *def = scx->scx_use->cu_def;
|
|
Rect r, rAll, rTrans;
|
|
int pNum;
|
|
|
|
/* Compute the bounding rect for the interesting planes */
|
|
rAll = GeoNullRect;
|
|
for (pNum = PL_TECHDEPBASE; pNum < DBNumPlanes; pNum++)
|
|
if (PlaneMaskHasPlane(gaSplitPlaneMask, pNum))
|
|
{
|
|
if (DBBoundPlane(def->cd_planes[pNum], &r))
|
|
(void) GeoInclude(&r, &rAll);
|
|
}
|
|
|
|
GeoTransRect(&scx->scx_trans, &rAll, &rTrans);
|
|
GeoClip(&rTrans, &gaSplitArea);
|
|
|
|
/* Skip if no area */
|
|
if (GEO_RECTNULL(&rTrans))
|
|
return (0);
|
|
|
|
/* Extend in the appropriate direction and bloat in the other one */
|
|
halfDown = RtrGridSpacing / 2;
|
|
halfUp = RtrGridSpacing - halfDown;
|
|
|
|
switch (gaSplitType)
|
|
{
|
|
case CHAN_HRIVER:
|
|
rTrans.r_ytop = gaSplitArea.r_ytop;
|
|
rTrans.r_ybot = gaSplitArea.r_ybot;
|
|
rTrans.r_xtop += RtrSubcellSepUp;
|
|
rTrans.r_xbot -= RtrSubcellSepDown;
|
|
rTrans.r_xtop = RTR_GRIDUP(rTrans.r_xtop + halfDown, RtrOrigin.p_x)
|
|
- halfUp;
|
|
rTrans.r_xbot = RTR_GRIDDOWN(rTrans.r_xbot - halfUp, RtrOrigin.p_x)
|
|
+ halfDown;
|
|
break;
|
|
case CHAN_VRIVER:
|
|
rTrans.r_xtop = gaSplitArea.r_xtop;
|
|
rTrans.r_xbot = gaSplitArea.r_xbot;
|
|
rTrans.r_ytop += RtrSubcellSepUp;
|
|
rTrans.r_ybot -= RtrSubcellSepDown;
|
|
rTrans.r_ytop = RTR_GRIDUP(rTrans.r_ytop + halfDown, RtrOrigin.p_y)
|
|
- halfUp;
|
|
rTrans.r_ybot = RTR_GRIDDOWN(rTrans.r_ybot - halfUp, RtrOrigin.p_y)
|
|
+ halfDown;
|
|
break;
|
|
}
|
|
|
|
/* Paint into DRC error plane */
|
|
(*gaSplitPaintPlane)(plane, &rTrans, DBStdWriteTbl(1),
|
|
(PaintUndoInfo *) NULL, PAINT_NORMAL);
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* GAInit --
|
|
*
|
|
* One-time-only initialization for the gate-array router.
|
|
* Called after technology initialization.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Register ourself with the debug module and list all
|
|
* debugging flags. Also initialize channel information.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
GAInit()
|
|
{
|
|
int n;
|
|
static struct
|
|
{
|
|
char *di_name;
|
|
int *di_id;
|
|
} dflags[] = {
|
|
{"chanonly", &gaDebChanOnly},
|
|
{"chanstats", &gaDebChanStats},
|
|
{"maze", &gaDebMaze},
|
|
{"nosimple", &gaDebNoSimple},
|
|
{"paintstems", &gaDebPaintStems},
|
|
{"showchans", &gaDebShowChans},
|
|
{"showmaze", &gaDebShowMaze},
|
|
{"stems", &gaDebStems},
|
|
{"verbose", &gaDebVerbose},
|
|
{"noclean", &gaDebNoClean},
|
|
{0}
|
|
};
|
|
|
|
if (gaInitialized)
|
|
return;
|
|
|
|
gaInitialized = TRUE;
|
|
|
|
/* Register ourselves with the debugging module */
|
|
gaDebugID = DebugAddClient("garouter", sizeof dflags/sizeof dflags[0]);
|
|
for (n = 0; dflags[n].di_name; n++)
|
|
*(dflags[n].di_id) = DebugAddFlag(gaDebugID, dflags[n].di_name);
|
|
|
|
/* Initialize channel information */
|
|
GAChannelInitOnce();
|
|
}
|