magic/sim/SimSelect.c

829 lines
21 KiB
C

/* SimSelect.c -
*
* This file provides routines to make selections for Rsim by copying
* things into a special cell named "__SELECT__". It is based
* on code in the select module.
*
* *********************************************************************
* * 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. *
* *********************************************************************
* of California
*/
#ifndef lint
static char sccsid[] = "@(#)SimSelect.c 4.14 MAGIC (Berkeley) 10/3/85";
#endif /* not lint */
#include <stdio.h>
#include <string.h>
#include "tcltk/tclmagic.h"
#include "utils/magic.h"
#include "utils/geometry.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "windows/windows.h"
#include "dbwind/dbwind.h"
#include "utils/undo.h"
#include "commands/commands.h"
#include "select/selInt.h"
#include "utils/main.h"
#include "utils/malloc.h"
#include "utils/signals.h"
#include "sim/sim.h"
/* C99 compat */
#include "textio/textio.h"
#include "extract/extract.h"
/* Two cells worth of information are kept around by the selection
* module. SelectDef and SelectUse are for the cells whose contents
* are the current selection. Select2Def and Select2Use provide a
* temporary working space for procedures that manipulate the selection.
* for example, Select2Def is used to hold nets or regions while they
* are being extracted by SelectRegion or SelectNet. Once completely
* extracted, information is copied to SelectDef. Changes to
* SelectDef are undo-able and redo-able (so that the undo package
* can deal with selection changes), but changes to Select2Def are
* not undo-able (undoing is always disabled when the cell is modified).
*/
extern CellDef *SelectDef, *Select2Def;
extern CellUse *SelectUse, *Select2Use;
typedef struct def_list_elt
{
CellDef *dl_def;
struct def_list_elt *dl_next;
bool dl_isMarked;
} SimDefListElt;
static SimDefListElt *SimCellLabList = (SimDefListElt *) NULL;
/* list of all the cell defs we have
* put RSIM labels in
*/
/* Data structure for node names extracted from the current selection. For
* each node, save the node name, a tile which lies in the node, and
* the text for the label corresponding to the node's rsim value.
*/
typedef struct TLE {
char *tl_nodeName;
Tile *tl_nodeTile;
char *tl_simLabel;
struct TLE *tl_next;
} TileListElt;
TileListElt *NodeList = (TileListElt *) NULL;
/* list of all nodes in the selected area */
HashTable SimNodeNameTbl; /* node names found in the selected area */
HashTable SimGetnodeTbl; /* node names to abort name search on */
HashTable SimGNAliasTbl; /* node name aliases found during search */
HashTable SimAbortSeenTbl; /* aborted node names found during search */
bool SimRecomputeSel = TRUE; /* selection has changed */
bool SimInitGetnode = TRUE; /* Getnode called for the 1st time */
bool SimGetnodeAlias = FALSE; /* if node aliases are to be printed */
bool SimSawAbortString; /* if saw string to abort name search */
bool SimIsGetnode; /* true if command was issued from Getnode */
bool SimUseCoords; /* true if we should use trans. position */
bool SimIgnoreGlobals = TRUE; /* If FALSE, node names ending in "!" */
/* are treated as global node names. */
#ifndef RSIM_MODULE
bool SimRsimRunning = FALSE; /* Always false if there's no rsim module */
#endif
/*
* ----------------------------------------------------------------------------
*
* SimSelectNode --
*
* This procedure selects an entire node. It is similar to SelectNet.
*
* Results:
* Returns the node name.
*
* Side effects:
* Starting from material of type "type" under scx, this procedure
* finds all material in all expanded cells that are electrically-
* connected to the starting material through a chain of expanded
* cells.
*
* ----------------------------------------------------------------------------
*/
char *
SimSelectNode(scx, type, xMask, buffer)
SearchContext *scx; /* Area to tree-search for material. The
* transform must map to EditRoot coordinates.
*/
TileType type; /* The type of material to be considered. */
int xMask; /* Indicates window (or windows) where cells
* must be expanded for their contents to be
* considered. 0 means treat everything as
* expanded.
*/
char *buffer; /* buffer to hold node name */
{
TileTypeBitMask mask;
char *strptr;
TTMaskZero(&mask);
TTMaskSetType(&mask, type);
/* Clear out the temporary selection cell and yank all of the
* connected paint into it.
*/
UndoDisable();
DBCellClearDef(Select2Def);
SimTreeCopyConnect(scx, &mask, xMask, DBConnectTbl,
&TiPlaneRect, Select2Use, buffer);
UndoEnable();
/* Strip out path if name is global (ends with a "!") */
/* and flag SimIgnoreGlobals is not set. */
if (!SimIgnoreGlobals)
{
strptr = buffer + strlen(buffer) - 1;
if (*strptr == '!') {
*strptr = '\0';
while (strptr != buffer) {
if (*strptr == '/') {
strptr++;
break;
}
strptr--;
}
}
else {
strptr = buffer;
}
}
else
strptr = buffer;
return(strptr);
}
int
NullFunc()
{
return(0);
}
/*
* ----------------------------------------------------------------------------
* SimFreeNodeList
*
* This procedure frees all space allocated for the node list
* data structure.
*
* Results:
* None.
*
* Side effects:
* After the list has been deallocated, the head pointer is set to
* a NULL value.
* ----------------------------------------------------------------------------
*/
void
SimFreeNodeList(List)
TileListElt **List;
{
TileListElt *current;
TileListElt *temp;
temp = *List;
while (temp != NULL) {
current = temp;
temp = temp->tl_next;
freeMagic(current->tl_nodeName);
freeMagic(current);
}
*List = (TileListElt *) NULL;
}
TileListElt *
simFreeNodeEntry(list, entry)
TileListElt *list, *entry;
{
TileListElt *prev, *curr;
prev = list;
for( curr = prev->tl_next; curr != NULL; prev = curr,curr = curr->tl_next )
if( curr == entry )
{
prev->tl_next = curr->tl_next;
freeMagic( entry->tl_nodeName );
freeMagic( entry );
return( prev ); /* next element in list */
}
/* should never get here */
return(entry);
}
/*
* ----------------------------------------------------------------------------
* SimSelectArea
*
* This procedure checks the current selected paint in the circuit and
* extracts the names of all the nodes in the selected area.
*
* Results:
* Returns a list of node name data structures.
*
* Side Effects:
* The tiles of the selection cell definition are first marked in the
* search algorithm. After finishing the search, these marks are
* erased.
*
* ----------------------------------------------------------------------------
*/
TileListElt *
SimSelectArea(Rect *rect)
{
int plane;
int SimSelectFunc();
/* only need to extract node names if the selection has changed or
* if node aliases are to be printed.
*/
if (SimRecomputeSel || (SimGetnodeAlias && SimIsGetnode)) {
SimFreeNodeList(&NodeList);
HashInit(&SimAbortSeenTbl, 20, HT_STRINGKEYS);
/* find all nodes in the current selection */
for (plane = PL_TECHDEPBASE; plane < DBNumPlanes; plane++)
{
(void) DBSrPaintArea((Tile *) NULL, SelectDef->cd_planes[plane],
&TiPlaneRect, &DBAllButSpaceAndDRCBits,
SimSelectFunc, (ClientData) &NodeList);
}
HashKill(&SimAbortSeenTbl);
ExtResetTiles(SelectDef, (ClientData) CLIENTDEFAULT);
SimGetNodeCleanUp();
SimRecomputeSel = FALSE;
}
if (SigInterruptPending) {
/* if caught an interrupt, be sure to recompute the selection
* next time around.
*/
SimRecomputeSel = TRUE;
}
return(NodeList);
}
/*
* ----------------------------------------------------------------------------
* SimSelectFunc
*
* This procedure is called for each tile in the current selection.
* It first checks to see if the node the tile belongs to has not
* yet been visited. If it has not been visited, then the node name
* is extracted and all other tiles in the selection which belong to
* this node are marked.
*
* Results:
* Return 0 to keep the search going.
*
* Side effects:
* The tiles in the selection cell definition are left marked.
* It is the responsibility of the calling function to erase these
* tile marks when finished.
* ----------------------------------------------------------------------------
*/
int
SimSelectFunc(tile, pHead)
Tile *tile; /* Tile in SelectDef. */
TileListElt **pHead; /* list of node names found */
{
TileTypeBitMask mask;
SearchContext scx;
DBWclientRec *crec;
MagWindow *window;
char nameBuff[256], *nodeName;
TileListElt *newNodeTile;
TileType type;
bool coord;
window = CmdGetRootPoint((Point *) NULL, &scx.scx_area);
if (window == NULL) return 1;
/* check to see if the node has already been extracted */
if (TiGetClientINT(tile) == 1) {
return(0);
}
if (IsSplit(tile))
{
type = (SplitSide(tile)) ? SplitRightType(tile):
SplitLeftType(tile);
}
else
type = TiGetTypeExact(tile);
/* get the tile's area, and initialize the tile's search context. */
TITORECT(tile, &scx.scx_area);
/* make sure that search context isn't placed on an empty */
/* corner of a split tile. */
if (IsSplit(tile))
{
if (SplitSide(tile))
scx.scx_area.r_xbot = scx.scx_area.r_xtop - 1;
if (!(SplitDirection(tile) ^ SplitSide(tile)))
scx.scx_area.r_ybot = scx.scx_area.r_ytop - 1;
}
scx.scx_area.r_xtop = scx.scx_area.r_xbot + 1;
scx.scx_area.r_ytop = scx.scx_area.r_ybot + 1;
scx.scx_use = (CellUse *) window->w_surfaceID;
scx.scx_trans = GeoIdentityTransform;
crec = (DBWclientRec *) window->w_clientData;
TTMaskZero(&mask);
TTMaskSetType(&mask, type);
TTMaskAndMask(&mask, &crec->dbw_visibleLayers);
TTMaskAndMask(&mask, &DBAllButSpaceAndDRCBits);
/* Check if the area is above a layer which is not visible. */
if (TTMaskIsZero(&mask)) {
return(0);
}
/* mark all other tiles in the selection that are part of this node */
SimSrConnect(SelectDef, &scx.scx_area, &DBAllButSpaceAndDRCBits,
DBConnectTbl, &TiPlaneRect, NullFunc, (ClientData) NULL);
/* Pick a tile type to use for selection. */
for (type = TT_TECHDEPBASE; type < DBNumTypes; type += 1)
{
if (TTMaskHasType(&mask, type)) break;
}
nodeName = SimSelectNode(&scx, type, CU_DESCEND_ALL, nameBuff);
/* add the node name to the list only if it has not been seen yet */
coord = (nodeName[0] == '@' && nodeName[1] == '=') ? TRUE : FALSE;
if(coord || HashLookOnly(&SimNodeNameTbl, nodeName) == (HashEntry *) NULL)
{
if( ! coord )
HashFind(&SimNodeNameTbl, nodeName);
newNodeTile = (TileListElt *) mallocMagic((unsigned) (sizeof (TileListElt)));
newNodeTile->tl_nodeName = (char *) mallocMagic((unsigned) (strlen(nodeName) + 1));
strcpy(newNodeTile->tl_nodeName, nodeName);
newNodeTile->tl_nodeTile = tile;
newNodeTile->tl_next = *pHead;
*pHead = newNodeTile;
}
return(0);
}
#ifdef RSIM_MODULE
/*
* ----------------------------------------------------------------------------
* SimSelection
*
* This procedure applies the specified rsim command to the list of
* nodes in the current selection and also attaches the rsim node
* value string to each node.
*
* Results:
* returns FALSE if no nodes are in the selection.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
bool
SimSelection(cmd)
char *cmd; /* rsim command to apply to the selection */
{
static char Hstring[] = "RSIM=1";
static char Lstring[] = "RSIM=0";
static char Xstring[] = "RSIM=X";
static char QUESTstring[] = "?";
char timeString[256];
TileListElt *current, *node_list;
char *replyLine;
char *strPtr;
bool goodReply;
extern void RsimErrorMsg();
timeString[0] = 0;
/* check to see if Rsim has been started yet */
if (!SimRsimRunning) {
RsimErrorMsg();
return(FALSE);
}
/* get the list of all nodes in the selection */
SimIsGetnode = FALSE;
SimUseCoords = SimHasCoords;
HashInit(&SimNodeNameTbl, 60, HT_STRINGKEYS);
node_list = SimSelectArea((Rect *)NULL);
if (node_list == (TileListElt *) NULL) {
TxPrintf("You must select paint (rather than a cell) to use Rsim on \
the selection.\n");
goto bad;
}
/* Walk the list of node names, apply the rsim command to each node,
* and then process the results.
*/
for (current = node_list; current != NULL; current = current->tl_next)
{
current->tl_simLabel = QUESTstring;
SimRsimIt(cmd, current->tl_nodeName);
if (!SimGetReplyLine(&replyLine)) {
goto bad;
}
if (!replyLine) {
/* Rsim's reponse to the command was just a prompt. We are done
* with the current node, so process the next node in the
* selection.
*/
continue;
}
/* check for node names not recognized by Rsim */
if (strncmp(replyLine, "time = ", 7) == 0) {
if (timeString[0] == 0) {
strcpy(timeString, replyLine);
}
TxPrintf("%s not recognized in sim file\n", current->tl_nodeName);
while(replyLine) {
/* swallow Rsim reply until no more is left */
if (!SimGetReplyLine(&replyLine)) {
goto bad;
}
}
continue;
}
/* update the node value label strings */
if (*cmd == 'd')
{
char *name = current->tl_nodeName;
bool coord = (name[0] == '@' && name[1] == '=') ? TRUE : FALSE;
strPtr = strrchr( replyLine, '=' );
if( strPtr == NULL )
strPtr = QUESTstring;
else if( coord )
{
*strPtr = '\0';
name = replyLine;
if( HashLookOnly(&SimNodeNameTbl, name) == (HashEntry *) NULL)
{
freeMagic(current->tl_nodeName);
current->tl_nodeName = (char *) mallocMagic((unsigned) (strlen(name) + 1));
strcpy(current->tl_nodeName, name);
HashFind(&SimNodeNameTbl, current->tl_nodeName);
*strPtr++ = '=';
}
else
{
current = simFreeNodeEntry( node_list, current );
*strPtr = '=';
}
}
else
strPtr++;
switch (*strPtr) {
case '1' :
current->tl_simLabel = Hstring;
break;
case '0' :
current->tl_simLabel = Lstring;
break;
case 'X' :
current->tl_simLabel = Xstring;
break;
case '=' :
break;
default :
current->tl_simLabel = QUESTstring;
break;
}
}
/* read all lines of the Rsim reply */
goodReply = TRUE;
for (;replyLine; goodReply = SimGetReplyLine(&replyLine)) {
if (!goodReply) {
goto bad;
}
if (!strncmp(replyLine, "time = ", 7)) {
if (!(timeString[0])) {
strcpy(timeString, replyLine);
}
continue;
} else if( *strPtr != '=' ) {
TxPrintf("%s\n", replyLine);
}
}
}
if (timeString[0] != 0) {
TxPrintf("%s\n", timeString);
}
HashKill(&SimNodeNameTbl);
return(TRUE);
bad:
HashKill(&SimNodeNameTbl);
return(FALSE);
}
#endif
/*
* ----------------------------------------------------------------------------
* SimAddLabels
*
* This procedure adds the node value labels to the Magic database
* so they will be displayed in the layout.
*
* Results:
* None.
*
* Side effects:
* The cell modified flags are deliberately not set when these labels
* are added to the database.
*
* ----------------------------------------------------------------------------
*/
void
SimAddLabels(SelectNodeList, rootuse)
TileListElt *SelectNodeList;
CellDef *rootuse; /* the root cell def for the window */
{
TileListElt *current;
Rect selectBox;
int pos;
/* walk the list of selected nodes, add the node value label to the
* database.
*/
for (current = SelectNodeList; current != (TileListElt *) NULL;
current = current->tl_next) {
if (*(current->tl_simLabel) == '?') {
continue;
}
TiToRect(current->tl_nodeTile, &selectBox);
pos = SimPutLabel(rootuse, &selectBox, GEO_CENTER,
current->tl_simLabel, TT_SPACE);
DBReComputeBbox(rootuse);
DBWLabelChanged(rootuse, current->tl_simLabel, &selectBox,
pos, DBW_ALLWINDOWS);
}
}
#ifdef RSIM_MODULE
/*
* ----------------------------------------------------------------------------
* SimRsimMouse
*
* This procedure erases the old rsim node labels and display the
* node labels of the current selection.
*
* Results:
* None.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
void
SimRsimMouse(w)
MagWindow *w;
{
CellUse *cu;
bool sawcell;
SimDefListElt *dummy;
if ((w == (MagWindow *) NULL) || (w->w_client != DBWclientID))
{
TxError("Put the cursor in a layout window\n");
return;
}
cu = (CellUse *)w->w_surfaceID; /* get root cell use for wind */
/* check to see if the cell def is already in our list */
sawcell = FALSE;
for (dummy = SimCellLabList; dummy; dummy = dummy->dl_next) {
if (dummy->dl_def == cu->cu_def) {
sawcell = TRUE;
break;
}
}
if (!sawcell) {
/* add the cell def to the list */
if (SimCellLabList == (SimDefListElt *) NULL) {
SimCellLabList = (SimDefListElt *) mallocMagic((unsigned) (sizeof(SimDefListElt)));
SimCellLabList->dl_isMarked = FALSE;
SimCellLabList->dl_def = cu->cu_def;
SimCellLabList->dl_next = (SimDefListElt *) NULL;
dummy = SimCellLabList;
}
else {
dummy = (SimDefListElt *) mallocMagic((unsigned) (sizeof(SimDefListElt)));
dummy->dl_isMarked = FALSE;
dummy->dl_next = SimCellLabList;
dummy->dl_def = cu->cu_def;
SimCellLabList= dummy;
}
}
SimEraseLabels();
if (SimSelection("d")) {
dummy->dl_isMarked = TRUE;
SimAddLabels(NodeList, dummy->dl_def);
}
}
#endif
/*
* ----------------------------------------------------------------------------
* SimGetnode
*
* This procedure prints the node names of all selected nodes.
*
* Results:
* None.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
void
SimGetnode()
{
TileListElt *current;
/* get the list of node names */
SimIsGetnode = TRUE;
SimUseCoords = FALSE;
HashInit(&SimNodeNameTbl, 60, HT_STRINGKEYS);
current = SimSelectArea((Rect *)NULL);
HashKill(&SimNodeNameTbl);
if (current == (TileListElt *) NULL) {
TxPrintf("You must select paint (not a cell) to use getnode.\n");
return;
}
for (; current != (TileListElt *) NULL; current = current->tl_next)
{
#ifdef MAGIC_WRAPPER
/* Return the node name as the result of the command */
Tcl_AppendElement(magicinterp, current->tl_nodeName);
#else
TxPrintf("node name : %s\n", current->tl_nodeName);
#endif
}
}
/*
* ----------------------------------------------------------------------------
* SimGetsnode
*
* This procedure prints the short node names of all selected nodes.
*
* Results:
* None.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
void
SimGetsnode()
{
TileListElt *current;
/* get the list of node names */
SimIsGetnode = TRUE;
SimUseCoords = TRUE;
HashInit(&SimNodeNameTbl, 60, HT_STRINGKEYS);
current = SimSelectArea((Rect *)NULL);
HashKill(&SimNodeNameTbl);
if (current == (TileListElt *) NULL) {
TxPrintf("You must select paint (not a cell) to use getnode.\n");
return;
}
for (; current != (TileListElt *) NULL; current = current->tl_next)
{
#ifdef MAGIC_WRAPPER
/* Return the node short name as the result of the command */
Tcl_AppendElement(magicinterp, current->tl_nodeName);
#else
TxPrintf("short node name : %s\n", current->tl_nodeName);
#endif
}
}
/*
* ----------------------------------------------------------------------------
* SimEraseLabels
*
* This procedure erases the RSIM labels from any cell defs they
* may have been added to.
*
* Results:
* None.
*
* Side effects:
* Removes the RSIM labels from "marked" cell defs.
*
* ----------------------------------------------------------------------------
*/
void
SimEraseLabels()
{
SimDefListElt *p;
for (p = SimCellLabList; p; p = p->dl_next) {
if (p->dl_isMarked) {
p->dl_isMarked = FALSE;
DBEraseLabelsByContent(p->dl_def, (Rect *)NULL, -1, "RSIM=X");
DBEraseLabelsByContent(p->dl_def, (Rect *)NULL, -1, "RSIM=1");
DBEraseLabelsByContent(p->dl_def, (Rect *)NULL, -1, "RSIM=0");
}
}
}