magic/netmenu/NMcmdAK.c

606 lines
14 KiB
C

/* NMcmd.c -
*
* This file contains routines to interpret commands typed inside
* netlist windows.
*
* *********************************************************************
* * 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/netmenu/NMcmdAK.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
#endif /* not lint */
#include <stdio.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 "textio/txcommands.h"
#include "netmenu/nmInt.h"
#include "netmenu/netmenu.h"
#include "utils/main.h"
#include "textio/textio.h"
#include "utils/malloc.h"
/*
* ----------------------------------------------------------------------------
*
* NMCmdAdd --
*
* Add a terminal to another terminal's net, removing it from
* its old net (if it was in one).
*
* Usage:
* add term1 term2
*
* Results:
* None.
*
* Side effects:
* The current netlist is modified.
*
* ----------------------------------------------------------------------------
*/
/* ARGSUSED */
void
NMCmdAdd(w, cmd)
MagWindow *w; /* Netlist window. */
TxCommand *cmd; /* Contains the command's argc and argv. */
{
if (cmd->tx_argc != 3)
{
TxError("Usage: add term1 term2\n");
return;
}
if (!NMHasList())
{
TxError("Select a netlist first.\n");
return;
}
(void) NMAddTerm(cmd->tx_argv[1], cmd->tx_argv[2]);
}
/*
* ----------------------------------------------------------------------------
*
* NMCmdCleanup --
*
* Check the current netlist for terminals that aren't present in
* the design and for nets with only one terminal. When found,
* tell the user and try to clean up automatically wherever
* possible.
*
* Usage:
* cleanup
*
* Results:
* None.
*
* Side effects:
* The current netlist is modified.
*
* ----------------------------------------------------------------------------
*/
/* The following definitions and variables are shared between the
* procedures that implement the cleanup command.
*/
struct nmcleanup
{
char *nmcl_name; /* Name of terminal. */
int nmcl_problem; /* Problem with this net: see defs. below. */
struct nmcleanup *nmcl_next;/* Troubles are linked together into list. */
};
#define NMCL_ONETERM 1
#define NMCL_NOLABEL 2
static struct nmcleanup *nmCleanupList;
/* List of problem terminals, formulated
* during first pass. These are processed
* during the second pass.
*/
static int nmCleanupCount; /* How many terminals have been seen in the
* current net.
*/
static char *nmCleanupTerm; /* Current (or previous) terminal in list. */
extern int nmCleanupFunc1(), nmCleanupFunc2();
extern void nmCleanupNet();
/* ARGSUSED */
void
NMCmdCleanup(w, cmd)
MagWindow *w; /* Netlist window. */
TxCommand *cmd; /* Contains the command's argc and argv. */
{
extern int nmCleanupFunc1(); /* Forward reference. */
struct nmcleanup *p;
if (cmd->tx_argc != 1)
{
TxError("Usage: cleanup\n");
return;
}
if (!NMHasList())
{
TxError("Select a netlist first.\n");
return;
}
/* Pass 1: collect information about problem areas. */
nmCleanupList = NULL;
nmCleanupCount = 0;
nmCleanupTerm = NULL;
(void) NMEnumNets(nmCleanupFunc1, (ClientData) NULL);
nmCleanupNet();
/* Pass 2: go over the list and ask the user what to do. This
* needs to be done in two passes because it may modify the
* netlist, and that is a dangerous thing to do while a search
* is in progress.
*/
for (p = nmCleanupList; p != NULL; p = p->nmcl_next)
{
char answer[30];
int indx, defaultValue;
static const char * const options[] = {"abort", "dnet", "dterm", "skip", NULL};
if (p->nmcl_problem == NMCL_ONETERM)
{
TxPrintf("Net \"%s\" has less than two terminals.\n", p->nmcl_name);
defaultValue = 1;
}
else
{
TxPrintf("\"%s\" doesn't exist in the circuit.\n", p->nmcl_name);
defaultValue = 2;
}
do
{
TxPrintf("Delete terminal (dterm), delete net (dnet), ");
TxPrintf("skip, or abort command? [%s] ", options[defaultValue]);
if (TxGetLine(answer, sizeof answer) == NULL) continue;
if (answer[0] == 0) indx = defaultValue;
else indx = Lookup(answer, options);
} while (indx < 0);
switch (indx)
{
case 0:
while (p != NULL)
{
freeMagic((char *) p);
p = p->nmcl_next;
}
return;
case 1:
NMDeleteNet(p->nmcl_name);
break;
case 2:
NMDeleteTerm(p->nmcl_name);
break;
}
freeMagic((char *) p);
}
if (nmCleanupList == NULL)
TxPrintf("No problems found.\n");
}
/* Search function for NMCmdCleanup. This one is called for each
* terminal name. Always return 0 to keep the search from aborting.
*/
/* ARGSUSED */
int
nmCleanupFunc1(name, firstInNet, cdarg)
char *name; /* Name of terminal. */
bool firstInNet; /* TRUE means first terminal of new net. */
ClientData cdarg; /* Not used. */
{
int count;
struct nmcleanup *p;
if (firstInNet)
{
nmCleanupNet();
nmCleanupCount = 0;
}
count = 0;
nmCleanupTerm = name;
(void) DBSrLabelLoc(EditCellUse, name, nmCleanupFunc2,
(ClientData) &count);
if (count == 0)
{
p = (struct nmcleanup *) mallocMagic(sizeof(struct nmcleanup));
p->nmcl_name = name;
p->nmcl_problem = NMCL_NOLABEL;
p->nmcl_next = nmCleanupList;
nmCleanupList = p;
}
else nmCleanupCount += count;
return 0;
}
/* Another search function for NMCleanup, called by DBSrLabelLoc.
* This function just counts the terminal instances for a net.
*/
/* ARGSUSED */
int
nmCleanupFunc2(rect, name, label, pCount)
Rect *rect; /* Not used. */
char *name; /* Not used. */
Label *label; /* Not used. */
int *pCount; /* Pointer to word to be incremented. */
{
*pCount += 1;
return 0;
}
/* Called after each net has been seen, to make sure there were at
* least two terminal instances for the net.
*/
void
nmCleanupNet()
{
struct nmcleanup *p;
if ((nmCleanupTerm != NULL) && (nmCleanupCount < 2))
{
p = (struct nmcleanup *) mallocMagic(sizeof(struct nmcleanup));
p->nmcl_name = nmCleanupTerm;
p->nmcl_problem = NMCL_ONETERM;
p->nmcl_next = nmCleanupList;
nmCleanupList = p;
}
}
/*
* ----------------------------------------------------------------------------
*
* NMCmdCull --
*
* Check the current netlist against routing in the edit cell
* to remove nets that are already wired correctly.
*
* Usage:
* cull
*
* Results:
* None.
*
* Side effects:
* Feedback is created where there are problems with the routing.
*
* ----------------------------------------------------------------------------
*/
/* ARGSUSED */
void
NMCmdCull(w, cmd)
MagWindow *w; /* Netlist window. */
TxCommand *cmd; /* Contains the command's argc and argv. */
{
if (cmd->tx_argc != 1)
{
TxError("Usage: cull\n");
return;
}
if (!NMHasList())
{
TxError("Select a netlist first.\n");
return;
}
NMCull();
}
/*
* ----------------------------------------------------------------------------
*
* NMCmdDnet --
*
* Delete the net containing a particular named terminal.
*
* Usage:
* dnet name name ...
*
* Results:
* None.
*
* Side effects:
* The current netlist is modified.
*
* ----------------------------------------------------------------------------
*/
/* ARGSUSED */
void
NMCmdDnet(w, cmd)
MagWindow *w; /* Netlist window. */
TxCommand *cmd; /* Contains the command's argc and argv. */
{
int i;
if (!NMHasList())
{
TxError("Select a netlist first.\n");
return;
}
if (cmd->tx_argc < 2)
{
if (NMCurNetName != NULL)
{
char *name;
name = NMCurNetName;
NMSelectNet((char *) NULL);
NMDeleteNet(name);
}
return;
}
for (i = 1; i < cmd->tx_argc; i++)
{
if (NMTermInList(cmd->tx_argv[i]) != NULL)
NMDeleteNet(cmd->tx_argv[i]);
else
{
TxError("\"%s\" isn't in the current netlist.", cmd->tx_argv[i]);
TxError(" Do you have the right netlist?.\n");
}
}
}
/*
* ----------------------------------------------------------------------------
*
* NMCmdDterm --
*
* Delete a particular terminal from its net.
*
* Usage:
* dterm name name ...
*
* Results:
* None.
*
* Side effects:
* The given terminal is removed from its net (if it's in a net).
*
* ----------------------------------------------------------------------------
*/
/* ARGSUSED */
void
NMCmdDterm(w, cmd)
MagWindow *w; /* Netlist window. */
TxCommand *cmd; /* Contains the command's argc and argv. */
{
int i;
if (cmd->tx_argc < 2)
{
TxError("Usage: dterm name name ...\n");
return;
}
if (!NMHasList())
{
TxError("Select a netlist first.\n");
return;
}
for (i = 1; i < cmd->tx_argc; i++)
{
if (NMTermInList(cmd->tx_argv[i]) != NULL)
NMDeleteTerm(cmd->tx_argv[i]);
else
{
TxError("\"%s\" isn't in the current netlist.", cmd->tx_argv[i]);
TxError(" Do you have the right netlist?.\n");
}
}
}
/*
* ----------------------------------------------------------------------------
*
* NMCmdExtract --
*
* Starting from paint underneath the box, chase out all
* electrically-connected material in the edit cell, locate
* terminals it touches, and put the terminals into a new
* net.
*
* Usage:
* extract
*
* Results:
* None.
*
* Side effects:
* The current netlist is modified.
*
* ----------------------------------------------------------------------------
*/
/* ARGSUSED */
void
NMCmdExtract(w, cmd)
MagWindow *w; /* Netlist window. */
TxCommand *cmd; /* Contains the command's argc and argv. */
{
if (cmd->tx_argc != 1)
{
TxError("Usage: extract\n");
return;
}
/*
if (!NMHasList())
{
TxError("Select a netlist first.\n");
return;
}
*/
NMExtract();
}
/*
* ----------------------------------------------------------------------------
*
* NMCmdFindLabels --
*
* Use the current label as a search pattern and create feedback
* areas for all instances of labels with that pattern that lie
* beneath the box.
*
* Results:
* None.
*
* Side effects:
* New feedback areas get created.
*
* ----------------------------------------------------------------------------
*/
/*ARGSUSED*/
void
NMCmdFindLabels(w, cmd)
MagWindow *w; /* Netlist window. */
TxCommand *cmd; /* Contains the command's argc and argv. */
{
TileTypeBitMask mask, *pMask;
char *pattern;
if (cmd->tx_argc < 2 || cmd->tx_argc > 3)
{
TxError("Usage: find pattern [layers]\n");
return;
}
pattern = cmd->tx_argv[1];
pMask = (TileTypeBitMask *) NULL;
if (cmd->tx_argc == 3)
{
if (!CmdParseLayers(cmd->tx_argv[2], &mask))
return;
pMask = &mask;
}
NMShowLabel(pattern, pMask);
}
/*
* ----------------------------------------------------------------------------
*
* NMCmdFlush --
*
* Flush a netlist, replacing it once again with the contents
* from disk.
*
* Usage:
* flush [netlist]
*
* Results:
* None.
*
* Side effects:
* Changes made to netlist "netlist" may be lost.
*
* ----------------------------------------------------------------------------
*/
/* ARGSUSED */
void
NMCmdFlush(w, cmd)
MagWindow *w; /* Netlist window. */
TxCommand *cmd; /* Contains the command's argc and argv. */
{
char *name;
if (cmd->tx_argc >= 3)
{
TxError("Usage: flush [netlist]\n");
return;
}
if (cmd->tx_argc == 1)
{
name = NMNetListButton.nmb_text;
if (name[0] == 0)
{
TxError("There's no current netlist to flush.\n");
return;
}
}
else name = cmd->tx_argv[1];
NMFlushNetlist(name);
}
/*
* ----------------------------------------------------------------------------
*
* NMCmdJoinNets --
*
* Join two nets together into a single net.
*
* Usage:
* joinnets term1 term2
*
* Results:
* None.
*
* Side effects:
* The current netlist is modified.
*
* Notes
* This command was previously called "join" but conflicts with
* the Tcl command of the same name, and for which the syntax is
* not distinct.
*
* ----------------------------------------------------------------------------
*/
/* ARGSUSED */
void
NMCmdJoinNets(w, cmd)
MagWindow *w; /* Netlist window. */
TxCommand *cmd; /* Contains the command's argc and argv. */
{
if (cmd->tx_argc != 3)
{
TxError("Usage: joinnets term1 term2\n");
return;
}
if (!NMHasList())
{
TxError("Select a netlist first.\n");
return;
}
if (NMTermInList(cmd->tx_argv[1]) == (char *) NULL)
{
TxError("\"%s\" isn't in a net, so can't join it.\n",
cmd->tx_argv[1]);
return;
}
if (NMTermInList(cmd->tx_argv[2]) == (char *) NULL)
{
TxError("\"%s\" isn't in a net, so can't join it.\n",
cmd->tx_argv[2]);
return;
}
NMJoinNets(cmd->tx_argv[1], cmd->tx_argv[2]);
}