mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-08-29 09:30:46 +02:00
and forcing it to be passed as an argument to all the callback functions for the search routines that require it. Magic now compiles and runs with the new code, but there are a number of known issues that need to be fixed up. Committing now so that I can rebase on the last update to the master branch.
1316 lines
31 KiB
C
1316 lines
31 KiB
C
/*
|
|
* CmdWizard.c --
|
|
*
|
|
* *** Wizard commands ***
|
|
*
|
|
* These commands are not intended to be used by the ordinary magic
|
|
* user, but are provided for the benefit of system maintainers/implementors.
|
|
*
|
|
* *********************************************************************
|
|
* * 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 const char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/commands/CmdWizard.c,v 1.2 2008/02/10 19:30:19 tim Exp $";
|
|
#endif /* not lint */
|
|
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/times.h>
|
|
|
|
#include "utils/magic.h"
|
|
#include "utils/geometry.h"
|
|
#include "utils/malloc.h"
|
|
#include "tiles/tile.h"
|
|
#include "utils/hash.h"
|
|
#include "database/database.h"
|
|
#include "windows/windows.h"
|
|
#include "dbwind/dbwind.h"
|
|
#include "utils/main.h"
|
|
#include "commands/commands.h"
|
|
#include "utils/runstats.h"
|
|
#include "textio/textio.h"
|
|
#include "graphics/graphics.h"
|
|
#include "utils/signals.h"
|
|
#include "utils/utils.h"
|
|
#include "textio/txcommands.h"
|
|
|
|
/* For diagnostics */
|
|
#include "cif/CIFint.h"
|
|
#include "database/databaseInt.h"
|
|
|
|
/* C99 compat */
|
|
#include "extract/extract.h"
|
|
|
|
/* Forward declarations */
|
|
|
|
extern void cmdPsearchStats(char *str, struct tms *tl, struct tms *td, int count);
|
|
|
|
void cmdStatsHier(CellDef *, int, CellDef *);
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* CmdCoord --
|
|
*
|
|
* Show the coordinates of various things:
|
|
* Point tool edit coords, root coords, curr coords
|
|
* Box tool edit coords, root coords, curr coords
|
|
* Edit cell bounding box edit coords, root coords
|
|
* Root cell bounding box edit coords, root coords
|
|
* Curr cell bounding box curr coords, root coords
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
CmdCoord(
|
|
MagWindow *w,
|
|
TxCommand *cmd)
|
|
{
|
|
MagWindow *pointW = (MagWindow *) NULL;
|
|
Rect editRect, rootRect;
|
|
Transform tinv;
|
|
CellDef *rootDef;
|
|
|
|
if ((w = ToolGetPoint((Point *) NULL, &rootRect)) != (MagWindow *) NULL)
|
|
{
|
|
pointW = w;
|
|
rootDef = ((CellUse *)w->w_surfaceID)->cu_def;
|
|
TxPrintf("Point:\tr=(%d,%d)::(%d,%d)",
|
|
rootRect.r_xbot, rootRect.r_ybot,
|
|
rootRect.r_xtop, rootRect.r_ytop);
|
|
if (EditRootDef == rootDef)
|
|
{
|
|
GeoTransRect(&RootToEditTransform, &rootRect, &editRect);
|
|
TxPrintf("\te=(%d,%d)::(%d,%d)",
|
|
editRect.r_xbot, editRect.r_ybot,
|
|
editRect.r_xtop, editRect.r_ytop);
|
|
}
|
|
TxPrintf("\n");
|
|
}
|
|
|
|
if (ToolGetBox(&rootDef, &rootRect))
|
|
{
|
|
TxPrintf("Box:\tr=(%d,%d)::(%d,%d)",
|
|
rootRect.r_xbot, rootRect.r_ybot,
|
|
rootRect.r_xtop, rootRect.r_ytop);
|
|
if (EditRootDef == rootDef)
|
|
{
|
|
GeoTransRect(&RootToEditTransform, &rootRect, &editRect);
|
|
TxPrintf("\te=(%d,%d)::(%d,%d)",
|
|
editRect.r_xbot, editRect.r_ybot,
|
|
editRect.r_xtop, editRect.r_ytop);
|
|
}
|
|
TxPrintf("\n");
|
|
}
|
|
|
|
if (pointW == (MagWindow *) NULL)
|
|
{
|
|
rootRect.r_xbot = rootRect.r_ybot = 0;
|
|
rootRect.r_xtop = rootRect.r_ytop = 1;
|
|
rootDef = EditRootDef;
|
|
}
|
|
else
|
|
{
|
|
rootDef = ((CellUse *) pointW->w_surfaceID)->cu_def;
|
|
rootRect = ((CellUse *) pointW->w_surfaceID)->cu_bbox;
|
|
}
|
|
|
|
TxPrintf("Root cell:\tr=(%d,%d)::(%d,%d)",
|
|
rootRect.r_xbot, rootRect.r_ybot,
|
|
rootRect.r_xtop, rootRect.r_ytop);
|
|
if (EditRootDef == rootDef)
|
|
{
|
|
GeoTransRect(&RootToEditTransform, &rootRect, &editRect);
|
|
TxPrintf("\te=(%d,%d)::(%d,%d)",
|
|
editRect.r_xbot, editRect.r_ybot,
|
|
editRect.r_xtop, editRect.r_ytop);
|
|
}
|
|
TxPrintf("\n");
|
|
|
|
GeoInvertTrans(&EditCellUse->cu_transform, &tinv);
|
|
GeoTransRect(&tinv, &EditCellUse->cu_bbox, &editRect);
|
|
TxPrintf("Edit cell:");
|
|
if (EditRootDef == rootDef)
|
|
{
|
|
GeoTransRect(&EditToRootTransform, &editRect, &rootRect);
|
|
TxPrintf("\tr=(%d,%d)::(%d,%d)",
|
|
rootRect.r_xbot, rootRect.r_ybot,
|
|
rootRect.r_xtop, rootRect.r_ytop);
|
|
}
|
|
TxPrintf("\te=(%d,%d)::(%d,%d)",
|
|
editRect.r_xbot, editRect.r_ybot,
|
|
editRect.r_xtop, editRect.r_ytop);
|
|
TxPrintf("\n");
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* CmdExtractTest --
|
|
*
|
|
* Debugging of circuit extraction.
|
|
*
|
|
* Usage:
|
|
* *extract cmd [args]
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* See comments in ExtractTest() in extract/ExtTest.c for details.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
#ifndef NO_EXT
|
|
void
|
|
CmdExtractTest(
|
|
MagWindow *w,
|
|
TxCommand *cmd)
|
|
{
|
|
ExtractTest(w, cmd);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* tileCountProc --
|
|
*
|
|
* Routine to count tiles.
|
|
*
|
|
* Return:
|
|
* 0 to keep the search going
|
|
*
|
|
* Side effects:
|
|
* Keeps count in clientData
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
tileCountProc(
|
|
Tile *tile, /* (unused) */
|
|
TileType dinfo, /* (unused) */
|
|
int *tcount)
|
|
{
|
|
(*tcount)++;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* showMem --
|
|
* CmdShowmem --
|
|
*
|
|
* Usage:
|
|
*
|
|
* showmem [outfile]
|
|
*
|
|
* Display all the (principle) internal memory usage for tiles, including
|
|
* all cell defs, and all CIF generated planes.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* May write to a disk file.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
showMem(
|
|
FILE *outf, /* File to which information is to be output */
|
|
bool verbose) /* If TRUE, output detailed erase table */
|
|
{
|
|
int ttotal, ttotal1, ttotal2;
|
|
int i;
|
|
Plane *plane;
|
|
CellDef *def;
|
|
int pNum;
|
|
HashSearch hs;
|
|
HashEntry *entry;
|
|
|
|
fprintf(outf, "Tile memory usage summary\n");
|
|
fprintf(outf, "Technology %s\n", DBTechName);
|
|
|
|
/* Search every cell def (including internal ones), count tiles,
|
|
* and add up the tile memory usage on every plane.
|
|
*/
|
|
|
|
/* Search the CIFPlanes and count tiles. */
|
|
/* CIFPlanes, CIFTotalPlanes, CIFComponentPlanes */
|
|
|
|
ttotal2 = 0;
|
|
if (CIFCurStyle != NULL)
|
|
{
|
|
fprintf(outf, "\nCIFPlanes:\n");
|
|
ttotal1 = 0;
|
|
for (i = 0; i < MAXCIFLAYERS; i++)
|
|
{
|
|
plane = CIFPlanes[i];
|
|
if (plane != NULL)
|
|
{
|
|
ttotal = 0;
|
|
DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect,
|
|
&DBAllTypeBits, tileCountProc, &ttotal);
|
|
ttotal1 += ttotal;
|
|
|
|
if (CIFCurStyle->cs_layers[i])
|
|
fprintf(outf, " layer %s: %ld\n",
|
|
CIFCurStyle->cs_layers[i]->cl_name,
|
|
(long)ttotal * (long)sizeof(Tile));
|
|
else
|
|
fprintf(outf, " layer %d: %d\n", i,
|
|
(long)ttotal * (long)sizeof(Tile));
|
|
}
|
|
}
|
|
fprintf(outf, " Subtotal: %ld bytes\n",
|
|
(long)ttotal1 * (long)sizeof(Tile));
|
|
ttotal2 += ttotal1;
|
|
|
|
fprintf(outf, "\nCIFTotalPlanes\n");
|
|
ttotal1 = 0;
|
|
for (i = 0; i < MAXCIFLAYERS; i++)
|
|
{
|
|
plane = CIFTotalPlanes[i];
|
|
if (plane != NULL)
|
|
{
|
|
ttotal = 0;
|
|
DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect,
|
|
&DBAllTypeBits, tileCountProc, &ttotal);
|
|
ttotal1 += ttotal;
|
|
|
|
if (CIFCurStyle->cs_layers[i])
|
|
fprintf(outf, " layer %s: %ld\n",
|
|
CIFCurStyle->cs_layers[i]->cl_name,
|
|
(long)ttotal * (long)sizeof(Tile));
|
|
else
|
|
fprintf(outf, " layer %d: %d\n", i,
|
|
(long)ttotal * (long)sizeof(Tile));
|
|
}
|
|
}
|
|
fprintf(outf, " Subtotal: %ld bytes\n",
|
|
(long)ttotal1 * (long)sizeof(Tile));
|
|
ttotal2 += ttotal1;
|
|
|
|
fprintf(outf, "\nCIFComponentPlanes\n");
|
|
ttotal1 = 0;
|
|
for (i = 0; i < MAXCIFLAYERS; i++)
|
|
{
|
|
plane = CIFComponentPlanes[i];
|
|
if (plane != NULL)
|
|
{
|
|
ttotal = 0;
|
|
DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect,
|
|
&DBAllTypeBits, tileCountProc, &ttotal);
|
|
ttotal1 += ttotal;
|
|
|
|
if (CIFCurStyle->cs_layers[i])
|
|
fprintf(outf, " layer %s: %ld bytes\n",
|
|
CIFCurStyle->cs_layers[i]->cl_name,
|
|
(long)ttotal * (long)sizeof(Tile));
|
|
else
|
|
fprintf(outf, " layer %d: %ld bytes\n", i,
|
|
(long)ttotal * (long)sizeof(Tile));
|
|
}
|
|
}
|
|
fprintf(outf, " Subtotal: %ld bytes\n",
|
|
(long)ttotal1 * (long)sizeof(Tile));
|
|
ttotal2 += ttotal1;
|
|
}
|
|
else
|
|
{
|
|
fprintf(outf, "CIF planes: No memory usage\n");
|
|
}
|
|
|
|
HashStartSearch(&hs);
|
|
while ((entry = HashNext(&dbCellDefTable, &hs)) != NULL)
|
|
{
|
|
def = (CellDef *)HashGetValue(entry);
|
|
if (def != (CellDef *)NULL)
|
|
{
|
|
fprintf(outf, "\nCell def %s\n", def->cd_name);
|
|
ttotal1 = 0;
|
|
for (pNum = 0; pNum < DBNumPlanes; pNum++)
|
|
{
|
|
plane = def->cd_planes[pNum];
|
|
if (plane != NULL)
|
|
{
|
|
ttotal = 0;
|
|
DBSrPaintArea((Tile *)NULL, plane, &TiPlaneRect,
|
|
&DBAllTypeBits, tileCountProc, &ttotal);
|
|
|
|
fprintf(outf, " plane %s: %ld bytes\n",
|
|
DBPlaneLongNameTbl[pNum],
|
|
(long)ttotal * (long)sizeof(Tile));
|
|
ttotal1 += ttotal;
|
|
}
|
|
}
|
|
fprintf(outf, " Subtotal: %ld bytes\n",
|
|
(long)ttotal1 * (long)sizeof(Tile));
|
|
ttotal2 += ttotal1;
|
|
}
|
|
}
|
|
fprintf(outf, " Grand total: %ld bytes\n",
|
|
(long)ttotal2 * (long)sizeof(Tile));
|
|
}
|
|
|
|
void
|
|
CmdShowmem(
|
|
MagWindow *w,
|
|
TxCommand *cmd)
|
|
{
|
|
FILE *outf;
|
|
bool verbose;
|
|
char **av;
|
|
int ac;
|
|
|
|
if (cmd->tx_argc > 3)
|
|
{
|
|
TxError("Usage: showmem [-v] [file]\n");
|
|
return;
|
|
}
|
|
|
|
verbose = FALSE;
|
|
av = &cmd->tx_argv[1];
|
|
ac = cmd->tx_argc - 1;
|
|
|
|
outf = stdout;
|
|
if (ac > 0 && strcmp(av[0], "-v") == 0)
|
|
{
|
|
verbose = TRUE;
|
|
av++, ac--;
|
|
}
|
|
|
|
if (ac > 0)
|
|
{
|
|
outf = fopen(av[0], "w");
|
|
if (outf == (FILE *) NULL)
|
|
{
|
|
perror(av[0]);
|
|
TxError("Nothing written\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
showMem(outf, verbose);
|
|
if (outf != stdout)
|
|
(void) fclose(outf);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* showTech --
|
|
* CmdShowtech --
|
|
*
|
|
* Usage:
|
|
*
|
|
* showtech [outfile]
|
|
*
|
|
* Display all the internal technology tables.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* May write to a disk file.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
showTech(
|
|
FILE *outf, /* File to which information is to be output */
|
|
bool verbose) /* If TRUE, output detailed erase table */
|
|
{
|
|
int i, j;
|
|
int pNum;
|
|
bool first, any;
|
|
TileTypeBitMask *rMask;
|
|
|
|
fprintf(outf, "Technology %s\n", DBTechName);
|
|
fprintf(outf, "%d tile planes, %d tile types\n\n",
|
|
DBNumPlanes, DBNumTypes);
|
|
fprintf(outf, "Planes:\n");
|
|
for (i = 0; i < DBNumPlanes; i++)
|
|
fprintf(outf, "%s\t%s\n", DBPlaneShortName(i),
|
|
DBPlaneLongName(i));
|
|
|
|
fprintf(outf, "\n");
|
|
fprintf(outf, "Types:\n");
|
|
for (i = 0; i < DBNumTypes; i++) {
|
|
int pl ; const char *spl ;
|
|
|
|
pl = DBPlane(i);
|
|
spl = ( pl <= 0 || pl > DBNumPlanes ) ? "??" : DBPlaneLongName(pl);
|
|
fprintf(outf, "%s\t%s\t%s\n", spl,
|
|
DBTypeShortName(i), DBTypeLongName(i));
|
|
}
|
|
|
|
fprintf(outf, "\n");
|
|
fprintf(outf, "\014Connectivity:\n");
|
|
for (j = 0; j < DBNumTypes; j++)
|
|
for (i = 0; i < j; i++)
|
|
if (DBConnectsTo(i, j))
|
|
fprintf(outf, "%s :: %s\n",
|
|
DBTypeLongName(j), DBTypeLongName(i));
|
|
fprintf(outf, "\n");
|
|
|
|
fprintf(outf, "\n\014Component Layers:\n");
|
|
for (i = 0; i < DBNumUserLayers; i++)
|
|
for (j = 0; j < DBNumUserLayers; j++)
|
|
{
|
|
rMask = DBResidueMask(j);
|
|
if ((j != i) && TTMaskHasType(rMask, i))
|
|
fprintf(outf, "%s is a component of %s\n",
|
|
DBTypeLongName(i), DBTypeLongName(j));
|
|
}
|
|
fprintf(outf, "\n");
|
|
|
|
fprintf(outf, "\014Planes affected by painting:\n");
|
|
fprintf(outf, "Type Planes\n");
|
|
fprintf(outf, "---- ------\n");
|
|
for (i = 0; i < DBNumTypes; i++)
|
|
{
|
|
fprintf(outf, "%-22.22s", DBTypeLongName(i));
|
|
first = TRUE;
|
|
for (pNum = 0; pNum < DBNumPlanes; pNum++)
|
|
{
|
|
if (DBPaintOnPlane(i, pNum))
|
|
{
|
|
if (first)
|
|
first = FALSE;
|
|
else
|
|
fprintf(outf, ", ");
|
|
fprintf(outf, "%s", DBPlaneLongName(pNum));
|
|
}
|
|
}
|
|
fprintf(outf, "\n");
|
|
}
|
|
|
|
fprintf(outf, "\014Planes affected by erasing:\n");
|
|
fprintf(outf, "Type Planes\n");
|
|
fprintf(outf, "---- ------\n");
|
|
for (i = 0; i < DBNumTypes; i++)
|
|
{
|
|
fprintf(outf, "%-22.22s", DBTypeLongName(i));
|
|
first = TRUE;
|
|
for (pNum = 0; pNum < DBNumPlanes; pNum++)
|
|
{
|
|
if (DBEraseOnPlane(i, pNum))
|
|
{
|
|
if (!first)
|
|
fprintf(outf, ", ");
|
|
first = FALSE;
|
|
fprintf(outf, "%s", DBPlaneLongName(pNum));
|
|
}
|
|
}
|
|
fprintf(outf, "\n");
|
|
}
|
|
|
|
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
|
|
{
|
|
fprintf(outf, "\014Paint: %s\n", DBPlaneLongName(pNum));
|
|
fprintf(outf, "=======================================\n");
|
|
for (i = 0; i < DBNumTypes; i++)
|
|
{
|
|
if (i == TT_SPACE || DBPlane(i) == pNum)
|
|
{
|
|
any = FALSE;
|
|
for (j = 0; j < DBNumTypes; j++)
|
|
{
|
|
if (!verbose && (i == TT_SPACE || j == TT_SPACE))
|
|
continue;
|
|
if (DBStdPaintEntry(i, j, pNum) != i)
|
|
{
|
|
fprintf(outf, "%s + %s --> %s\n",
|
|
DBTypeLongName(i), DBTypeLongName(j),
|
|
DBTypeLongName(DBStdPaintEntry(i, j, pNum)));
|
|
any = TRUE;
|
|
}
|
|
}
|
|
if (any)
|
|
fprintf(outf,
|
|
"--------------------------------------\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
for (pNum = PL_PAINTBASE; pNum < DBNumPlanes; pNum++)
|
|
{
|
|
fprintf(outf, "\014Erase: %s\n", DBPlaneLongName(pNum));
|
|
fprintf(outf, "=======================================\n");
|
|
for (i = 0; i < DBNumTypes; i++)
|
|
{
|
|
if (i == TT_SPACE || DBPlane(i) == pNum)
|
|
{
|
|
any = FALSE;
|
|
for (j = 0; j < DBNumTypes; j++)
|
|
{
|
|
if (!verbose && i == j)
|
|
continue;
|
|
if (DBStdEraseEntry(i, j, pNum) != i)
|
|
{
|
|
fprintf(outf, "%s - %s --> %s\n",
|
|
DBTypeLongName(i), DBTypeLongName(j),
|
|
DBTypeLongName(DBStdEraseEntry(i, j, pNum)));
|
|
any = TRUE;
|
|
}
|
|
}
|
|
if (any)
|
|
fprintf(outf,
|
|
"--------------------------------------\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
CmdShowtech(
|
|
MagWindow *w,
|
|
TxCommand *cmd)
|
|
{
|
|
FILE *outf;
|
|
bool verbose;
|
|
char **av;
|
|
int ac;
|
|
|
|
if (cmd->tx_argc > 3)
|
|
{
|
|
TxError("Usage: showtech [-v] [file]\n");
|
|
return;
|
|
}
|
|
|
|
verbose = FALSE;
|
|
av = &cmd->tx_argv[1];
|
|
ac = cmd->tx_argc - 1;
|
|
|
|
outf = stdout;
|
|
if (ac > 0 && strcmp(av[0], "-v") == 0)
|
|
{
|
|
verbose = TRUE;
|
|
av++, ac--;
|
|
}
|
|
|
|
if (ac > 0)
|
|
{
|
|
outf = fopen(av[0], "w");
|
|
if (outf == (FILE *) NULL)
|
|
{
|
|
perror(av[0]);
|
|
TxError("Nothing written\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
showTech(outf, verbose);
|
|
if (outf != stdout)
|
|
(void) fclose(outf);
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* CmdTilestats --
|
|
*
|
|
* Generate statistics on tile utilization.
|
|
* The output is either to the terminal or to the file supplied.
|
|
* Usage:
|
|
* *tilestats -a [file] to generate statistics for all cells
|
|
* *tilestats [file] to generate statistics for the currently
|
|
* selected cell.
|
|
*
|
|
* If the argument 'file' is specified, it is created to hold the
|
|
* output of the *tilestats command.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* May create a disk file.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
CmdTilestats(
|
|
MagWindow *w,
|
|
TxCommand *cmd)
|
|
{
|
|
CellUse *selectedUse;
|
|
FILE *outf = stdout;
|
|
bool allDefs = FALSE;
|
|
char **av = cmd->tx_argv + 1;
|
|
int ac = cmd->tx_argc - 1;
|
|
int cmdStatsFunc(CellDef *def, FILE *outf);
|
|
|
|
if (ac > 2)
|
|
{
|
|
TxError("Usage: tilestats [-a] [outputfile]\n");
|
|
return;
|
|
}
|
|
|
|
if (ac > 0 && strcmp(av[0], "-a") == 0)
|
|
allDefs = TRUE, ac--, av++;
|
|
|
|
if (ac > 0 && (outf = fopen(av[0], "w")) == NULL)
|
|
{
|
|
perror(av[0]);
|
|
return;
|
|
}
|
|
|
|
selectedUse = CmdGetSelectedCell((Transform *) NULL);
|
|
if (allDefs)
|
|
(void) DBCellSrDefs(0, cmdStatsFunc, (ClientData) outf);
|
|
else if (selectedUse != NULL)
|
|
(void) cmdStatsFunc(selectedUse->cu_def, outf);
|
|
else
|
|
TxError("No cell selected.\n");
|
|
if (outf != stdout)
|
|
(void) fclose(outf);
|
|
}
|
|
|
|
|
|
/* Stored with each CellDef in the cd_client field */
|
|
struct cellInfo
|
|
{
|
|
int ci_count[TT_MAXTYPES]; /* Count of tiles of each
|
|
* type in this cell.
|
|
*/
|
|
int ci_hierCount[TT_MAXTYPES]; /* Count of tiles of each
|
|
* type in all subtrees,
|
|
* weighted by the number
|
|
* of times each subtree is
|
|
* used.
|
|
*/
|
|
bool ci_countedHier; /* TRUE if ci_hierCount has
|
|
* yet been computed.
|
|
*/
|
|
};
|
|
|
|
/* Passed by DBTreeCountPaint to the clients */
|
|
struct countClient
|
|
{
|
|
FILE *cc_outFile; /* Output statistics to this file */
|
|
CellDef *cc_rootDef; /* Root definition for which we're computing
|
|
* all the statistics.
|
|
*/
|
|
};
|
|
|
|
/* Records the total number of drawn tiles of each type */
|
|
int totalTiles[TT_MAXTYPES];
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* cmdStatsFunc --
|
|
*
|
|
* Generate the hierarchical statistics for a single cell def.
|
|
*
|
|
* Results:
|
|
* Returns 0 always.
|
|
*
|
|
* Side effects:
|
|
* Writes to the file outf.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
cmdStatsFunc(
|
|
CellDef *def,
|
|
FILE *outf)
|
|
{
|
|
int cmdStatsCount(CellDef *def, struct countClient *cc);
|
|
int cmdStatsOutput(CellDef *def, struct countClient *cc);
|
|
struct countClient cc;
|
|
int total;
|
|
TileType t;
|
|
|
|
cc.cc_outFile = outf;
|
|
cc.cc_rootDef = def;
|
|
for (t = 0; t < DBNumTypes; t++)
|
|
totalTiles[t] = 0;
|
|
|
|
DBTreeCountPaint(def, cmdStatsCount, cmdStatsHier,
|
|
cmdStatsOutput, (ClientData) &cc);
|
|
|
|
total = 0;
|
|
for (t = TT_SPACE; t < DBNumTypes; t++)
|
|
{
|
|
if (totalTiles[t])
|
|
{
|
|
fprintf(outf, "%s\tTOTAL\t%s\t%d\n",
|
|
def->cd_name, DBTypeLongName(t), totalTiles[t]);
|
|
total += totalTiles[t];
|
|
}
|
|
}
|
|
|
|
fprintf(outf, "%s\tTOTAL\tALL\t%d\n", def->cd_name, total);
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* cmdStatsCount --
|
|
*
|
|
* Count the number of tiles in a single cell.
|
|
* If def->cd_client has already been filled in, we just return;
|
|
* otherwise, we make def->cd_client point to a newly allocated
|
|
* cellInfo struct, and fill in the ci_count field.
|
|
*
|
|
* Results:
|
|
* Returns 1 if def->cd_client had already been filled in,
|
|
* 0 otherwise.
|
|
*
|
|
* Side effects:
|
|
* May modify def->cd_client.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
cmdStatsCount(
|
|
CellDef *def,
|
|
struct countClient *cc)
|
|
{
|
|
int pNum;
|
|
struct cellInfo *ci;
|
|
TileType t;
|
|
|
|
/* Forward declaration */
|
|
int cmdStatsCountTile(Tile *tile, TileType dinfo, struct cellInfo *ci);
|
|
|
|
if (def->cd_client)
|
|
return (1);
|
|
|
|
/* Allocate a new cellInfo struct for this CellDef */
|
|
ci = (struct cellInfo *) mallocMagic(sizeof (struct cellInfo));
|
|
def->cd_client = (ClientData) ci;
|
|
for (t = TT_SPACE; t < DBNumTypes; t++)
|
|
{
|
|
ci->ci_count[t] = ci->ci_hierCount[t] = 0;
|
|
ci->ci_countedHier = FALSE;
|
|
}
|
|
|
|
/* Visit all tiles */
|
|
for (pNum = PL_SELECTBASE; pNum < DBNumPlanes; pNum++)
|
|
(void) DBSrPaintArea((Tile *) NULL, def->cd_planes[pNum],
|
|
&TiPlaneRect, &DBAllTypeBits,
|
|
cmdStatsCountTile, def->cd_client);
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
cmdStatsCountTile(
|
|
Tile *tile,
|
|
TileType dinfo, /* (unused) */
|
|
struct cellInfo *ci)
|
|
{
|
|
TileType type = TiGetType(tile);
|
|
|
|
/*
|
|
* Count this tile both toward the cell being visited,
|
|
* and the overall total.
|
|
*/
|
|
ci->ci_count[type]++;
|
|
totalTiles[type]++;
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* cmdStatsHier --
|
|
*
|
|
* Add to the hierarchical statistics for a given CellDef.
|
|
* If parent's cd_client cellInfo struct has ci_countedHier
|
|
* set, we just return. (It means that the subtree we are now
|
|
* visiting has already been visited, but since we are called
|
|
* in bottom-up order, there's not much we can do about it).
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Adds the hierarchical statistics for child, plus the
|
|
* per-cell statistics for child, to the hierarchical
|
|
* statistics for 'parent'.
|
|
*
|
|
* Since we are guaranteed to be called only after all
|
|
* children of 'child' have been visited, we know that
|
|
* we can mark 'child' as having ci_countedHier TRUE.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
cmdStatsHier(
|
|
CellDef *parent,
|
|
int nuses,
|
|
CellDef *child)
|
|
{
|
|
struct cellInfo *pi, *ci;
|
|
TileType t;
|
|
|
|
pi = (struct cellInfo *) parent->cd_client;
|
|
if (pi->ci_countedHier)
|
|
return;
|
|
|
|
ci = (struct cellInfo *) child->cd_client;
|
|
ci->ci_countedHier = TRUE;
|
|
for (t = TT_SPACE; t < DBNumTypes; t++)
|
|
pi->ci_hierCount[t] += nuses * (ci->ci_hierCount[t] + ci->ci_count[t]);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* cmdStatsOutput --
|
|
*
|
|
* Output the hierarchical statistics for a single cell def.
|
|
* If 'def' has not yet had its statistics output, we output
|
|
* for each tile type having non-zero counts:
|
|
* - the number of tiles of this type in this cell, plus
|
|
* hierarchically in all of its children, pretending
|
|
* that the entire subtree was flattened (so each tile
|
|
* is counted as many times as it logically appears in
|
|
* the hierarchy).
|
|
* - the number of tiles of this type in this cell alone.
|
|
* These numbers are also output for the total number of tiles
|
|
* of all types.
|
|
*
|
|
* Results:
|
|
* If we had already output statistics for this cell, we
|
|
* return 1; otherwise we return 0.
|
|
*
|
|
* Side effects:
|
|
* Writes to the file outf.
|
|
* If def->cd_client points to a cellInfo struct, we free it
|
|
* and clear def->cd_client.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
cmdStatsOutput(
|
|
CellDef *def,
|
|
struct countClient *cc)
|
|
{
|
|
TileType t;
|
|
struct cellInfo *ci;
|
|
int count, hiercount;
|
|
|
|
if (def->cd_client == (ClientData) NULL)
|
|
return (1);
|
|
|
|
ci = (struct cellInfo *) def->cd_client;
|
|
def->cd_client = (ClientData) NULL;
|
|
|
|
count = hiercount = 0;
|
|
for (t = TT_SPACE; t < DBNumTypes; t++)
|
|
{
|
|
if (ci->ci_hierCount[t] | ci->ci_count[t])
|
|
{
|
|
/* Root-def this-def type-name num-flat num-paint */
|
|
fprintf(cc->cc_outFile, "%s\t%s\t%s\t%d\t%d\n",
|
|
cc->cc_rootDef->cd_name, def->cd_name,
|
|
DBTypeLongName(t),
|
|
ci->ci_hierCount[t] + ci->ci_count[t], ci->ci_count[t]);
|
|
count += ci->ci_count[t];
|
|
hiercount += ci->ci_hierCount[t];
|
|
}
|
|
}
|
|
|
|
/* Root-def this-def ALL num-flat num-paint */
|
|
if (hiercount | count)
|
|
{
|
|
fprintf(cc->cc_outFile, "%s\t%s\tALL\t%d\t%d\n",
|
|
cc->cc_rootDef->cd_name, def->cd_name,
|
|
hiercount + count, count);
|
|
}
|
|
|
|
freeMagic((char *) ci);
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* CmdPsearch --
|
|
*
|
|
* Run point search a number of times the point at the lower-left
|
|
* corner of the box tool to each point in the edit cell.
|
|
*
|
|
* Usage:
|
|
* psearch plane count
|
|
*
|
|
* Where plane is the name of the plane on which the search is to be
|
|
* carried out, and count is the number of searches to be performed.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
CmdPsearch(
|
|
MagWindow *w,
|
|
TxCommand *cmd)
|
|
{
|
|
char *RunStats(int flags, struct tms *lastt, struct tms *deltat);
|
|
static struct tms tlast, tdelta;
|
|
Point p;
|
|
Plane *plane;
|
|
Rect rtool;
|
|
Rect *ebox;
|
|
Tile *tp;
|
|
Tile *TiSrPointNew();
|
|
int i, pNum, count;
|
|
|
|
if (cmd->tx_argc != 3)
|
|
{
|
|
TxError("Usage: psearch plane count\n");
|
|
return;
|
|
}
|
|
|
|
pNum = DBTechNamePlane(cmd->tx_argv[1]);
|
|
if (pNum < 0)
|
|
{
|
|
TxError("Unrecognized plane: %s\n", cmd->tx_argv[1]);
|
|
return;
|
|
}
|
|
|
|
if (!StrIsInt(cmd->tx_argv[2]))
|
|
{
|
|
TxError("Count must be numeric\n");
|
|
return;
|
|
}
|
|
|
|
count = atoi(cmd->tx_argv[2]);
|
|
|
|
ebox = &EditCellUse->cu_def->cd_bbox;
|
|
if (!ToolGetEditBox(&rtool)) return;
|
|
|
|
plane = EditCellUse->cu_def->cd_planes[pNum];
|
|
|
|
tp = TiSrPoint((Tile *) NULL, plane, &rtool.r_ll);
|
|
(void) RunStats(RS_TINCR, &tlast, &tdelta);
|
|
|
|
#define BUMP(p, b) \
|
|
if (++((p).p_x) >= (b)->r_xtop) { (p).p_y++; (p).p_x = (b)->r_xbot; } \
|
|
if ((p).p_y >= (b)->r_ytop) (p) = (b)->r_ll;
|
|
|
|
/* Procedural search */
|
|
for (p = ebox->r_ll, i = count; i-- > 0; )
|
|
{
|
|
BUMP(p, ebox);
|
|
(void) TiSrPoint(tp, plane, &p);
|
|
}
|
|
cmdPsearchStats("proc", &tlast, &tdelta, count);
|
|
|
|
/* Macro search */
|
|
for (p = ebox->r_ll, i = count; i-- > 0; )
|
|
{
|
|
Tile *txp = tp;
|
|
BUMP(p, ebox);
|
|
GOTOPOINT(txp, &p);
|
|
}
|
|
cmdPsearchStats("macro", &tlast, &tdelta, count);
|
|
}
|
|
|
|
void
|
|
cmdPsearchStats(
|
|
char *str,
|
|
struct tms *tl,
|
|
struct tms *td,
|
|
int count)
|
|
{
|
|
char *RunStats(int flags, struct tms *lastt, struct tms *deltat);
|
|
char *rstatp;
|
|
int us, ups;
|
|
|
|
rstatp = RunStats(RS_TINCR, tl, td);
|
|
us = td->tms_utime * (1000000 / 60);
|
|
ups = us / count;
|
|
TxPrintf("%s: %d searches, %d us/search [%s]\n", str, count, ups, rstatp);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* CmdTsearch --
|
|
*
|
|
* Call DBSrPaintArea() a number of times over an area the size and shape of
|
|
* that specified by the box, each time over a different area in the
|
|
* edit cell.
|
|
*
|
|
* Usage:
|
|
* tsearch plane count mask searchroutine
|
|
*
|
|
* Where plane is the name of the plane on which the search is to be
|
|
* carried out, and count is the number of searches to be performed.
|
|
* If 'searchroutine' is 'mayo', use Bob's routine. If it is 'new', use
|
|
* Walter's routine. Else use old routine.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* None.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int numTilesFound;
|
|
bool cmdTsearchDebug = FALSE;
|
|
|
|
void
|
|
CmdTsearch(
|
|
MagWindow *w,
|
|
TxCommand *cmd)
|
|
{
|
|
char *rstatp;
|
|
static TileTypeBitMask mask;
|
|
static struct tms tlast, tdelta;
|
|
Rect rtool, rsearch;
|
|
Plane *plane;
|
|
int i, pNum, count;
|
|
int usPerSearch, usPerTile, usPerL2, us, boxarea;
|
|
|
|
/* Forward declarations */
|
|
int cmdTsrFunc(Tile *tp, TileType dinfo, ClientData clientdata);
|
|
char *RunStats(int flags, struct tms *lastt, struct tms *deltat);
|
|
|
|
if (cmd->tx_argc < 3 || cmd->tx_argc > 5)
|
|
{
|
|
TxError("Usage: tsearch plane count [mask [new|mayo]]\n");
|
|
return;
|
|
}
|
|
|
|
pNum = DBTechNamePlane(cmd->tx_argv[1]);
|
|
if (pNum < 0)
|
|
{
|
|
TxError("Unrecognized plane: %s\n", cmd->tx_argv[1]);
|
|
return;
|
|
}
|
|
|
|
if (!StrIsInt(cmd->tx_argv[2]))
|
|
{
|
|
TxError("Count must be numeric\n");
|
|
return;
|
|
}
|
|
|
|
count = atoi(cmd->tx_argv[2]);
|
|
|
|
if (!ToolGetEditBox(&rtool)) return;
|
|
|
|
/*****
|
|
ebox = &EditCellUse->cu_def->cd_bbox;
|
|
if (rtool.r_xtop - rtool.r_xbot >= ebox->r_xtop - ebox->r_xbot
|
|
|| rtool.r_ytop - rtool.r_ybot >= ebox->r_ytop - ebox->r_ybot)
|
|
{
|
|
TxError("Box must be smaller than edit cell\n");
|
|
return;
|
|
}
|
|
*****/
|
|
|
|
rsearch = rtool;
|
|
plane = EditCellUse->cu_def->cd_planes[pNum];
|
|
|
|
(void) RunStats(RS_TINCR, &tlast, &tdelta);
|
|
if (cmd->tx_argc >= 4)
|
|
(void) CmdParseLayers(cmd->tx_argv[3], &mask);
|
|
else mask = DBAllTypeBits;
|
|
|
|
if (!TTMaskEqual(&mask, &DBZeroTypeBits))
|
|
numTilesFound = 0;
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
/*****
|
|
rsearch.r_xtop++;
|
|
rsearch.r_xbot++;
|
|
if (rsearch.r_xtop >= ebox->r_xtop)
|
|
{
|
|
rsearch.r_ybot--;
|
|
rsearch.r_ytop--;
|
|
rsearch.r_xbot = ebox->r_xbot;
|
|
rsearch.r_xtop = rsearch.r_xbot + (rtool.r_xtop - rtool.r_xbot);
|
|
}
|
|
|
|
if (rsearch.r_ybot <= ebox->r_ybot)
|
|
{
|
|
rsearch.r_ytop = ebox->r_ytop;
|
|
rsearch.r_ybot = rsearch.r_ytop - (rtool.r_ytop - rtool.r_ybot);
|
|
rsearch.r_xbot = ebox->r_xbot;
|
|
rsearch.r_xtop = rsearch.r_xbot + (rtool.r_xtop - rtool.r_xbot);
|
|
}
|
|
*****/
|
|
|
|
if (cmdTsearchDebug)
|
|
TxPrintf("----- (%d,%d) :: (%d,%d) -----\n",
|
|
rsearch.r_xbot, rsearch.r_ybot, rsearch.r_xtop, rsearch.r_ytop);
|
|
|
|
if (cmd->tx_argc < 5)
|
|
{
|
|
(void) DBSrPaintArea((Tile *) NULL, plane, &rsearch, &DBAllTypeBits,
|
|
cmdTsrFunc, (ClientData) 0);
|
|
}
|
|
else
|
|
{
|
|
(void) DBSrPaintArea((Tile *) NULL, plane, &rsearch, &mask,
|
|
cmdTsrFunc, (ClientData) 0);
|
|
}
|
|
}
|
|
|
|
if (numTilesFound == 0) numTilesFound = 1;
|
|
rstatp = RunStats(RS_TINCR, &tlast, &tdelta);
|
|
boxarea = (rsearch.r_xtop-rsearch.r_xbot)*(rsearch.r_ytop-rsearch.r_ybot);
|
|
us = tdelta.tms_utime * (1000000 / 60);
|
|
usPerL2 = us / (boxarea * count);
|
|
usPerTile = us / numTilesFound;
|
|
usPerSearch = us / count;
|
|
TxPrintf("[%s]: box = %dh x %dw (area=%d l**2)\n", rstatp,
|
|
rsearch.r_ytop-rsearch.r_ybot,
|
|
rsearch.r_xtop-rsearch.r_xbot,
|
|
boxarea);
|
|
TxPrintf("%d searches, %d tiles, %d us/l**2, %d us/tile, %d us/search\n",
|
|
count, numTilesFound, usPerL2, usPerTile, usPerSearch);
|
|
}
|
|
|
|
int
|
|
cmdTsrFunc(
|
|
Tile *tp,
|
|
TileType dinfo, /* (unused) */
|
|
ClientData clientdata) /* (unused) */
|
|
{
|
|
if (cmdTsearchDebug)
|
|
TxPrintf("%lx\n", (intptr_t) tp);
|
|
numTilesFound++;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* CmdWatch --
|
|
*
|
|
* Enable/disable watching of tile planes in the given window.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Causes the display package to display the actual tile structure
|
|
* for a given plane, or disables such display.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
CmdWatch(
|
|
MagWindow *w,
|
|
TxCommand *cmd)
|
|
{
|
|
DBWclientRec *crec;
|
|
int pNum;
|
|
int i,flags=0;
|
|
|
|
if (w == (MagWindow *) NULL)
|
|
{
|
|
TxError("Gee, you don't seem like a wizard!\n");
|
|
TxError("Cursor not in a layout window.\n");
|
|
return;
|
|
}
|
|
crec = (DBWclientRec *) w->w_clientData;
|
|
for (i =2 ; i < cmd->tx_argc;i++)
|
|
{
|
|
if (strcmp("demo", cmd->tx_argv[i]) ==0)
|
|
{
|
|
flags |= DBW_WATCHDEMO;
|
|
}
|
|
else
|
|
if (strcmp("types", cmd->tx_argv[i]) ==0)
|
|
{
|
|
flags |= DBW_SEETYPES;
|
|
}
|
|
else
|
|
{
|
|
TxError("Gee, you don't sound like a wizard!\n");
|
|
TxError("Usage: %s [plane] [demo] [types]\n", cmd->tx_argv[0]);
|
|
return;
|
|
}
|
|
}
|
|
if (cmd->tx_argc == 1)
|
|
{
|
|
pNum = -1;
|
|
crec->dbw_watchDef = NULL;
|
|
}
|
|
else
|
|
{
|
|
pNum = DBTechNamePlane(cmd->tx_argv[1]);
|
|
if (pNum < 0)
|
|
{
|
|
const char *cp;
|
|
TxError("Unrecognized plane: %s. Legal names are:\n",
|
|
cmd->tx_argv[1]);
|
|
for(pNum=0; pNum < PL_MAXTYPES; pNum++) {
|
|
cp = DBPlaneLongName(pNum);
|
|
if (cp != NULL)
|
|
TxError(" %s\n", cp);
|
|
};
|
|
return;
|
|
}
|
|
if (EditCellUse != NULL)
|
|
{
|
|
crec->dbw_watchDef = EditCellUse->cu_def;
|
|
crec->dbw_watchTrans = EditToRootTransform;
|
|
}
|
|
else
|
|
{
|
|
crec->dbw_watchDef = ((CellUse *)w->w_surfaceID)->cu_def;
|
|
crec->dbw_watchTrans = ((CellUse *)w->w_surfaceID)->cu_transform;
|
|
}
|
|
}
|
|
|
|
crec->dbw_watchPlane = pNum;
|
|
crec->dbw_flags &= ~(DBW_WATCHDEMO|DBW_SEETYPES);
|
|
crec->dbw_flags |= flags;
|
|
|
|
WindAreaChanged(w, (Rect *) NULL);
|
|
}
|