mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-08-30 09:58:55 +02:00
no way to implement boolean operators on labels, so any "label" statement in the section can apply only to one magic layer. This is regularly violated in most (all?) techfiles (due mainly to lack of explanation and guidance). The addition of the "no-reconnect- labels" option for cifinput made it worse, as it can cause a label to be attached to the wrong layer and be stuck that way. Even without the option, an attachment to a non-connecting type is a problem; DIFF cannot simultaneously have a connection to both ndiff and pdiff, so it will be one or the other, and the one not connected can easily get labels moved to other nets. To avoid this: (1) removed the "no-reconnect-labels" option, and (2) made the automatic label reconnection smarter, as well as splitting it into two different behaviors based on whether a label is being created or manipulated from the command line (more or less the original behavior) vs. being read from GDS or LEF. The new rules assume that labels attached to a GDS type will all map to the same plane in magic. To avoid excessive error messages from existing tech files, a warning is issued only if "labels" changes the plane of the target layer (a realistic solution rather than the preferred one). Also: Fixed an error that causes a crash on the "wizard" command "*watch" if the cell being observed is read-only (see github issue #271).
1073 lines
25 KiB
C
1073 lines
25 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 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 <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"
|
|
|
|
/* C99 compat */
|
|
#include "extract/extract.h"
|
|
|
|
/* Forward declarations */
|
|
|
|
extern void cmdPsearchStats();
|
|
|
|
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(w, cmd)
|
|
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(w, cmd)
|
|
MagWindow *w;
|
|
TxCommand *cmd;
|
|
{
|
|
ExtractTest(w, cmd);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* showTech --
|
|
* CmdShowtech --
|
|
*
|
|
* Usage:
|
|
*
|
|
* showtech [outfile]
|
|
*
|
|
* Display all the internal technology tables.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* May write to a disk file.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
showTech(outf, verbose)
|
|
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 ; 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(w, cmd)
|
|
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(w, cmd)
|
|
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();
|
|
|
|
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(def, outf)
|
|
CellDef *def;
|
|
FILE *outf;
|
|
{
|
|
int cmdStatsCount(), cmdStatsOutput();
|
|
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(def, cc)
|
|
CellDef *def;
|
|
struct countClient *cc;
|
|
{
|
|
int cmdStatsCountTile();
|
|
int pNum;
|
|
struct cellInfo *ci;
|
|
TileType t;
|
|
|
|
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, ci)
|
|
Tile *tile;
|
|
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(parent, nuses, child)
|
|
CellDef *parent, *child;
|
|
int nuses;
|
|
{
|
|
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(def, cc)
|
|
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(w, cmd)
|
|
MagWindow *w;
|
|
TxCommand *cmd;
|
|
{
|
|
char *RunStats();
|
|
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(str, tl, td, count)
|
|
char *str;
|
|
struct tms *tl, *td;
|
|
int count;
|
|
{
|
|
char *RunStats();
|
|
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(w, cmd)
|
|
MagWindow *w;
|
|
TxCommand *cmd;
|
|
{
|
|
int cmdTsrFunc();
|
|
char *RunStats(), *rstatp;
|
|
static TileTypeBitMask mask;
|
|
static struct tms tlast, tdelta;
|
|
Rect rtool, rsearch;
|
|
/**** Rect *ebox; ****/
|
|
Plane *plane;
|
|
int i, pNum, count;
|
|
int usPerSearch, usPerTile, usPerL2, us, boxarea;
|
|
|
|
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(tp)
|
|
Tile *tp;
|
|
{
|
|
if (cmdTsearchDebug)
|
|
TxPrintf("%x\n", 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(w, cmd)
|
|
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)
|
|
{
|
|
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);
|
|
}
|