/*
 * Electric(tm) VLSI Design System
 *
 * File: simverilog.c
 * Generator for Verilog simulator
 * Written by: Steven M. Rubin
 *
 * Copyright (c) 2000 Static Free Software.
 *
 * Electric(tm) is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Electric(tm) is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Electric(tm); see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, Mass 02111-1307, USA.
 *
 * Static Free Software
 * 4119 Alpine Road
 * Portola Valley, California 94028
 * info@staticfreesoft.com
 */

#include "config.h"
#if SIMAID

#include "global.h"
#include "efunction.h"
#include "sim.h"
#include "network.h"
#include "tecgen.h"
#include "tecschem.h"

#define IMPLICITINVERTERNODENAME "Imp"			/* name of inverters generated from negated wires */
#define IMPLICITINVERTERSIGNAME  "ImpInv"		/* name of signals generated from negated wires */
#define MAXDECLARATIONWIDTH      80				/* maximum size of output line */

INTBIG sim_verilog_state;			/* key for "SIM_verilog_state" */
INTBIG sim_verstate;
FILE  *sim_verfile;
INTBIG sim_verilogcodekey = 0;
INTBIG sim_verilogdeclarationkey = 0;
char   sim_verdeclarationline[MAXDECLARATIONWIDTH];
INTBIG sim_verdeclarationprefix;

/* prototypes for local routines */
INTSML sim_writeverfacet(NODEPROTO*);
void sim_writesilinstances(NODEPROTO*, INTSML);
INTSML sim_vernegated(PORTARCINST*);
char *sim_convertvername(char *p);
INTBIG sim_includetypedcode(NODEPROTO*, INTBIG, char*);
void sim_verinitdeclaration(char *header);
void sim_veradddeclaration(char *signame);
void sim_vertermdeclaration(void);

/*
 * routine to write a ".v" file from the facet "np"
 */
void sim_writevernetlist(NODEPROTO *np)
{
	char name[100], numberstring[100], *truename;
	REGISTER NODEPROTO *lnp;
	REGISTER LIBRARY *lib;
	REGISTER VARIABLE *var;

	/* make sure network tool is on */
	if ((net_aid->aidstate&AIDON) == 0)
	{
		ttyputerr(_("Network tool must be running...turning it on"));
		aidturnon(net_aid, 0);
		ttyputerr(_("...now reissue the simulation command"));
		return;
	}
	if (sim_verilogcodekey == 0)
		sim_verilogcodekey = makekey("VERILOG_code");
	if (sim_verilogdeclarationkey == 0)
		sim_verilogdeclarationkey = makekey("VERILOG_declaration");
	var = getvalkey((INTBIG)sim_aid, VAID, VINTEGER, sim_verilog_state);
	if (var == NOVARIABLE) sim_verstate = 0; else
		sim_verstate = var->addr;

	/* first write the "ver" file */
	(void)strcpy(name, np->cell->cellname);
	(void)strcat(name, ".v");
	sim_verfile = xcreate(name, sim_filetypeverilog, _("VERILOG File"), &truename);
	if (sim_verfile == NULL)
	{
		if (truename != 0) ttyputerr(_("Cannot write %s"), truename);
		return;
	}

	/* write header information */
	xprintf(sim_verfile, "/* Verilog for facet %s from Library %s */\n",
		describenodeproto(np), np->cell->lib->libname);
	if (np->creationdate)
		xprintf(sim_verfile, "/* Created on %s */\n",
			timetostring(np->creationdate));
	if (np->revisiondate)
		xprintf(sim_verfile, "/* Last revised on %s */\n",
			timetostring(np->revisiondate));
	(void)sprintf(numberstring, "%s", timetostring(getcurrenttime()));
	xprintf(sim_verfile, "/* Written on %s by Electric VLSI Design System, version %s */\n",
		numberstring, el_version);

	/* reset flags for facets that have been written */
	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
		for(lnp = lib->firstnodeproto; lnp != NONODEPROTO; lnp = lnp->nextnodeproto)
			lnp->temp1 = 0;
	if (sim_writeverfacet(np) != 0)
		ttyputmsg(_("Back-annotation information has been added (library must be saved)"));

	/* clean up */
	xclose(sim_verfile);
	ttyputmsg(_("%s written"), truename);
}

/*
 * recursively called routine to print the Verilog description of facet "np".
 */
INTSML sim_writeverfacet(NODEPROTO *np)
{
	REGISTER INTBIG i, j, l, nodetype, backannotate, first, portfound, implicitports,
		impinv, bussig, buswidth, warned, signals, wireswritten, isnegated,
		save, wholenegated;
	REGISTER NODEINST *ni;
	REGISTER ARCINST *ai;
	REGISTER PORTPROTO *pp, *lastpp;
	REGISTER NODEPROTO *onp;
	REGISTER PORTARCINST *pi;
	REGISTER PORTEXPINST *pe;
	REGISTER NETWORK *net;
	REGISTER VARIABLE *var;
	char *extra, *porttype, *thisline, *nodename, *signame, impsigname[100],
		invsigname[100], num[20], *op, *pt;
	char **strings;

	/* stop if requested */
	if (el_pleasestop != 0)
	{
		(void)stopping(STOPREASONDECK);
		return(0);
	}
	backannotate = 0;

	/* use attached file if specified */
	var = getval((INTBIG)np, VNODEPROTO, VSTRING, "SIM_verilog_behave_file");
	if (var != NOVARIABLE)
	{
		xprintf(sim_verfile, "`include \"%s\"\n", (char *)var->addr);

		/* mark this facet as written */
		np->temp1++;
		return((INTSML)backannotate);
	}

	/* use library behavior if it is available */
	onp = anyview(np, el_verilogview);
	if (onp != NONODEPROTO)
	{
		var = getvalkey((INTBIG)onp, VNODEPROTO, VSTRING|VISARRAY, el_facet_message);
		if (var != NOVARIABLE)
		{
			l = getlength(var);
			for(i=0; i<l; i++)
			{
				thisline = ((char **)var->addr)[i];
				xprintf(sim_verfile, "%s\n", thisline);
			}
		}

		/* mark this facet as written */
		np->temp1++;
		return((INTSML)backannotate);
	}

	/* write netlist for this facet, first recurse on sub-facets */
	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
	{
		if (ni->proto->primindex != 0) continue;

		/* get actual subfacet (including contents/body distinction) */
		/* NOTE: this gets the schematic before the layout */
		onp = contentsview(ni->proto);
		if (onp == NONODEPROTO) onp = ni->proto;

		/* write the subfacet */
		if (onp->temp1 == 0)
		{
			if (sim_writeverfacet(onp) != 0) backannotate = 1;
		}
	}

	/* make sure that all networks have names on them */
	if (askaid(net_aid, "name-nodes", (INTBIG)np) != 0) backannotate++;
	if (askaid(net_aid, "name-nets", (INTBIG)np) != 0) backannotate++;

	/* mark this facet as written */
	np->temp1++;

	/* prepare arcs to store implicit inverters */
	impinv = 1;
	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
		ai->temp1 = 0;
	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
	{
		if ((ai->userbits&ISNEGATED) == 0) continue;
		if ((ai->userbits&REVERSEEND) == 0)
		{
			ni = ai->end[0].nodeinst;
			pi = ai->end[0].portarcinst;
		} else
		{
			ni = ai->end[1].nodeinst;
			pi = ai->end[1].portarcinst;
		}
		if (ni->proto == sch_bufprim || ni->proto == sch_andprim ||
			ni->proto == sch_orprim || ni->proto == sch_xorprim)
		{
			if ((sim_verstate&VERILOGUSEASSIGN) != 0) continue;
			if (strcmp(pi->proto->protoname, "y") == 0) continue;
		}

		/* must create implicit inverter here */
		ai->temp1 = impinv;
		if (ai->proto != sch_busarc) impinv++; else
		{
			net = ai->network;
			if (net == NONETWORK) impinv++; else
				impinv += net->signals;
		}
	}

	/* write the module header */
	xprintf(sim_verfile, "\nmodule %s(", sim_convertvername(np->cell->cellname));
	for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
	{
		if (pp != np->firstportproto) xprintf(sim_verfile, ", ");
		signals = pp->network->signals;
		if (signals > 1)
		{
			for(pt = pp->protoname; *pt != 0; pt++) if (*pt == '[') break;
			save = *pt;
			*pt = 0;
			xprintf(sim_verfile, "%s", sim_convertvername(pp->protoname));
			*pt = (char)save;
		} else
		{
			xprintf(sim_verfile, "%s", sim_convertvername(pp->protoname));
		}
	}
	xprintf(sim_verfile, ");\n");

	/* write the ports again */
	for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
	{
		switch (pp->userbits&STATEBITS)
		{
			case OUTPORT:   porttype = "output";  break;
			default:        porttype = "input";   break;
		}
		signals = pp->network->signals;
		if (signals > 1)
		{
			for(pt = pp->protoname; *pt != 0; pt++) if (*pt == '[') break;
			xprintf(sim_verfile, "  %s %s", porttype, pt);
			save = *pt;
			*pt = 0;
			xprintf(sim_verfile, " %s;\n", sim_convertvername(pp->protoname));
			*pt = (char)save;
		} else
		{
			xprintf(sim_verfile, "  %s %s;\n", porttype,
				sim_convertvername(pp->protoname));
		}
	}
	xprintf(sim_verfile, "\n");

	/* add "wire" declarations for implicit inverters and internal signals */
	if (impinv > 1)
	{
		sim_verinitdeclaration("  wire");
		for(i=1; i<impinv; i++)
		{
			sprintf(impsigname, "%s%d", IMPLICITINVERTERSIGNAME, i);
			sim_veradddeclaration(impsigname);
		}
		sim_vertermdeclaration();
	}

	/* write "wire" declarations for internal busses */
	for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
	{
		if (net->namecount <= 0) continue;
		if (net->portcount > 0) continue;
		if (net->signals <= 1) continue;
		for(pt = net->netname; *pt != 0; pt++) if (*pt == '[') break;

		xprintf(sim_verfile, "  wire %s", pt);
		save = *pt;
		*pt = 0;
		xprintf(sim_verfile, " %s;\n", net->netname);
		*pt = (char)save;
	}

	/* write "wire" declarations for internal signals */
	wireswritten = 0;
	for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
	{
		if (net->namecount <= 0) continue;
		if (net->portcount > 0) continue;
		if (net->signals > 1) continue;
		if (net->buslinkcount > 0) continue;
		if (wireswritten == 0) sim_verinitdeclaration("  wire");
		sim_veradddeclaration(net->netname);
		wireswritten++;
	}
	if (wireswritten != 0)
	{
		sim_vertermdeclaration();
		xprintf(sim_verfile, "\n");
	}

	first = sim_includetypedcode(np, sim_verilogdeclarationkey, "declarations");
	first += sim_includetypedcode(np, sim_verilogcodekey, "code");

	if (first == 0)
		xprintf(sim_verfile, "  /* automatically generated Verilog */\n");

	/* look at every node in this facet */
	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
	{
		/* not interested in passive nodes (ports electrically connected) */
		j = 0;
		lastpp = ni->proto->firstportproto;
		if (lastpp == NOPORTPROTO) continue;
		for(pp = lastpp->nextportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
			if (pp->network != lastpp->network) j++;
		if (j == 0) continue;

		/* determine the number of signals passing through this node */
		buswidth = 0;
		warned = 0;
		for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
		{
			ai = pi->conarcinst;
			if (ai->proto != sch_busarc) signals = 1; else
				signals = ai->network->signals;
			if (buswidth == 0) buswidth = signals; else
			{
				if (buswidth != signals)
				{
					if (warned == 0)
						ttyputerr(_("Warning: node %s is connected to different-width busses (%d and %d wide)"),
							describenodeinst(ni), buswidth, signals);
					warned++;
					if (signals < buswidth) buswidth = signals;
				}
			}
		}
		if (buswidth == 0) buswidth = 1;
		nodetype = nodefunction(ni, &extra);

		/* use "assign" statement if possible */
		if ((sim_verstate&VERILOGUSEASSIGN) != 0)
		{
			if (nodetype == NPGATEAND || nodetype == NPGATEOR ||
				nodetype == NPGATEXOR || nodetype == NPBUFFER)
			{
				/* assign possible: determine operator */
				switch (nodetype)
				{
					case NPGATEAND:  op = " & ";   break;
					case NPGATEOR:   op = " | ";   break;
					case NPGATEXOR:  op = " ^ ";   break;
					case NPBUFFER:   op = "";      break;
				}
				for(bussig=0; bussig<buswidth; bussig++)
				{
					/* write a line describing this signal */
					(void)initinfstr();
					wholenegated = 0;
					first = 1;
					for(i=0; i<2; i++)
					{
						for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
						{
							if (i == 0)
							{
								if (strcmp(pi->proto->protoname, "y") != 0) continue;
							} else
							{
								if (strcmp(pi->proto->protoname, "a") != 0) continue;
							}

							/* determine the network name at this port */
							net = pi->conarcinst->network;
							if (buswidth > 1)
							{
								(void)net_evalbusname(
									(INTSML)((pi->conarcinst->proto->userbits&AFUNCTION)>>AFUNCTIONSH),
										net->netname, &strings, pi->conarcinst, np, 1);
								strcpy(impsigname, strings[bussig]);
								signame = impsigname;
							} else
							{
								if (net != NONETWORK && net->namecount > 0)
									signame = net->netname; else
										signame = describenetwork(net);
							}

							/* see if this end is negated */
							isnegated = 0;
							ai = pi->conarcinst;
							if ((ai->userbits&ISNEGATED) != 0)
							{
								if ((ai->end[0].nodeinst == ni && (ai->userbits&REVERSEEND) == 0) ||
									(ai->end[1].nodeinst == ni && (ai->userbits&REVERSEEND) != 0))
								{
									isnegated = 1;
								}
							}

							/* write the port name */
							if (i == 0)
							{
								/* got the output port: do the left-side of the "assign" */
								(void)addstringtoinfstr("assign ");
								(void)addstringtoinfstr(signame);
								(void)addstringtoinfstr(" = ");
								if (isnegated != 0)
								{
									(void)addstringtoinfstr("~(");
									wholenegated = 1;
								}
								break;
							} else
							{
								if (first == 0)
									(void)addstringtoinfstr(op);
								first = 0;
								if (isnegated != 0) (void)addstringtoinfstr("~");
								(void)addstringtoinfstr(signame);
							}
						}
					}
					if (wholenegated != 0)
						(void)addstringtoinfstr(")");
					xprintf(sim_verfile, "  %s;\n", returninfstr());
				}
				continue;
			}
		}

		/* get the name of the node */
		implicitports = 0;
		if (ni->proto->primindex == 0)
		{
			nodename = sim_convertvername(ni->proto->cell->cellname);
		} else
		{
			nodename = ni->proto->primname;
			switch (nodetype)
			{
				case NPGATEAND:
					implicitports = 1;
					nodename = "and";
					for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
						if (strcmp(pi->proto->protoname, "y") == 0) break;
					if (pi != NOPORTARCINST && (pi->conarcinst->userbits&ISNEGATED) != 0)
						nodename = "nand";
					break;
				case NPGATEOR:
					implicitports = 1;
					nodename = "or";
					for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
						if (strcmp(pi->proto->protoname, "y") == 0) break;
					if (pi != NOPORTARCINST && (pi->conarcinst->userbits&ISNEGATED) != 0)
						nodename = "nor";
					break;
				case NPGATEXOR:
					implicitports = 1;
					nodename = "xor";
					for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
						if (strcmp(pi->proto->protoname, "y") == 0) break;
					if (pi != NOPORTARCINST && (pi->conarcinst->userbits&ISNEGATED) != 0)
						nodename = "xnor";
					break;
				case NPBUFFER:
					implicitports = 1;
					nodename = "buf";
					for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
						if (strcmp(pi->proto->protoname, "y") == 0) break;
					if (pi != NOPORTARCINST && (pi->conarcinst->userbits&ISNEGATED) != 0)
						nodename = "not";
					break;
			}
		}

		/* write the node (may be arrayed) */
		for(bussig=0; bussig<buswidth; bussig++)
		{
			/* write the type of the node */
			(void)initinfstr();
			(void)addstringtoinfstr("  ");
			(void)addstringtoinfstr(nodename);

			/* write the name of the node */
			var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name);
			if (var != NOVARIABLE)
			{
				(void)addstringtoinfstr(" ");
				(void)addstringtoinfstr(sim_convertvername((char *)var->addr));
				if (buswidth > 1)
				{
					sprintf(num, "_%ld", bussig);
					(void)addstringtoinfstr(num);
				}
			}
			(void)addstringtoinfstr("(");

			/* write the rest of the ports */
			first = 1;
			if (implicitports != 0)
			{
				/* write ports in proper order with implicit names */
				for(i=0; i<2; i++)
				{
					for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
					{
						if (i == 0)
						{
							if (strcmp(pi->proto->protoname, "y") != 0) continue;
						} else
						{
							if (strcmp(pi->proto->protoname, "a") != 0) continue;
						}
						if (first != 0) first = 0; else
							(void)addstringtoinfstr(", ");
						net = pi->conarcinst->network;
						if (buswidth > 1)
						{
							(void)net_evalbusname(
								(INTSML)((pi->conarcinst->proto->userbits&AFUNCTION)>>AFUNCTIONSH),
									net->netname, &strings, pi->conarcinst, np, 1);
							strcpy(impsigname, strings[bussig]);
							signame = impsigname;
						} else
						{
							if (net != NONETWORK && net->namecount > 0)
								signame = net->netname; else
									signame = describenetwork(net);
						}
						if (i != 0 && pi->conarcinst->temp1 != 0)
						{
							/* this input is negated: write the implicit inverter */
							sprintf(invsigname, "%s%ld", IMPLICITINVERTERSIGNAME,
								pi->conarcinst->temp1+bussig);
							xprintf(sim_verfile, "  inv %s%ld (%s, %s);\n",
								IMPLICITINVERTERNODENAME, pi->conarcinst->temp1+bussig,
									invsigname, signame);
							signame = invsigname;
						}
						(void)addstringtoinfstr(signame);
					}
				}
			} else
			{
				/* write explicit port names */
				for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
				{
					/* get all wires on this port */
					portfound = 0;
					for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
					{
						if (pi->proto != pp) continue;
						if (first != 0) first = 0; else
							(void)addstringtoinfstr(", ");
						(void)addstringtoinfstr(".");
						(void)addstringtoinfstr(sim_convertvername(pp->protoname));
						(void)addstringtoinfstr("(");
						net = pi->conarcinst->network;
						if (net != NONETWORK && net->namecount > 0)
							signame = net->netname; else
								signame = describenetwork(net);
						if (i != 0 && pi->conarcinst->temp1 != 0)
						{
							/* this input is negated: write the implicit inverter */
							sprintf(impsigname, "%s%ld", IMPLICITINVERTERSIGNAME,
								pi->conarcinst->temp1+bussig);
							xprintf(sim_verfile, "  inv %s%ld (%s, %s);\n",
								IMPLICITINVERTERNODENAME, pi->conarcinst->temp1+bussig,
									impsigname, signame);
							signame = impsigname;
						}
						(void)addstringtoinfstr(signame);
						(void)addstringtoinfstr(")");
						portfound++;
					}
					if (portfound == 0)
					{
						for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
						{
							if (pe->proto != pp) continue;
							if (first != 0) first = 0; else
								(void)addstringtoinfstr(", ");
							(void)addstringtoinfstr(".");
							(void)addstringtoinfstr(sim_convertvername(pp->protoname));
							(void)addstringtoinfstr("(");
							(void)addstringtoinfstr(pe->exportproto->protoname);
							(void)addstringtoinfstr(")");
							portfound++;
						}
					}
					if (portfound == 0)
					{
						if (first != 0) first = 0; else
							(void)addstringtoinfstr(", ");
						(void)addstringtoinfstr(".");
						(void)addstringtoinfstr(sim_convertvername(pp->protoname));
						(void)addstringtoinfstr("()");
					}
				}
			}
			(void)addstringtoinfstr(");");
			xprintf(sim_verfile, "%s\n", returninfstr());
		}
	}
	xprintf(sim_verfile, "endmodule   /* %s */\n",
		sim_convertvername(np->cell->cellname));

	return((INTSML)backannotate);
}

/*
 * Routine to add text from all nodes in facet "np"
 * (which have "verilogkey" text on them)
 * to that text to the output file.  Returns nonzero if anything
 * was found.
 */
INTBIG sim_includetypedcode(NODEPROTO *np, INTBIG verilogkey, char *descript)
{
	INTSML first;
	REGISTER INTBIG len, i;
	REGISTER NODEINST *ni;
	REGISTER VARIABLE *var;

	/* write out any directly-typed Verilog code */
	first = 1;
	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
	{
		if (ni->proto != gen_invispinprim) continue;
		var = getvalkey((INTBIG)ni, VNODEINST, -1, verilogkey);
		if (var == NOVARIABLE) continue;
		if ((var->type&VTYPE) != VSTRING) continue;
		if ((var->type&VDISPLAY) == 0) continue;
		if (first != 0)
		{
			first = 0;
			xprintf(sim_verfile, "  /* user-specified Verilog %s */\n",
				descript);
		}
		if ((var->type&VISARRAY) == 0)
		{
			xprintf(sim_verfile, "  %s\n", (char *)var->addr);
		} else
		{
			len = getlength(var);
			for(i=0; i<len; i++)
				xprintf(sim_verfile, "  %s\n", ((char **)var->addr)[i]);
		}
	}
	xprintf(sim_verfile, "\n");
	return(first);
}

/*
 * Routine to initialize the collection of signal names in a declaration.
 * The declaration starts with the string "header".
 */
void sim_verinitdeclaration(char *header)
{
	strcpy(sim_verdeclarationline, header);
	sim_verdeclarationprefix = strlen(sim_verdeclarationline);
}

/*
 * Routine to add "signame" to the collection of signal names in a declaration.
 */
void sim_veradddeclaration(char *signame)
{
	if (strlen(sim_verdeclarationline) + strlen(signame) + 3 > MAXDECLARATIONWIDTH)
	{
		xprintf(sim_verfile, "%s;\n", sim_verdeclarationline);
		sim_verdeclarationline[sim_verdeclarationprefix] = 0;
	}
	if ((INTBIG)strlen(sim_verdeclarationline) != sim_verdeclarationprefix)
		strcat(sim_verdeclarationline, ",");
	strcat(sim_verdeclarationline, " ");
	strcat(sim_verdeclarationline, signame);
}

/*
 * Routine to terminate the collection of signal names in a declaration
 * and write the declaration to the Verilog file.
 */
void sim_vertermdeclaration(void)
{
	xprintf(sim_verfile, "%s;\n", sim_verdeclarationline);
}

/*
 * routine to replace all non-printing characters
 * in the string "p" with the letter "X" and return the string
 * We will not permit a digit in the first location; replace it
 * with '_'
 */
char *sim_convertvername(char *p)
{
	REGISTER char *t;

	for(t = p; *t != 0; t++) if (!isalnum(*t) && *t != '[' && *t != ']' && *t != ':') break;
	if (*t == 0 && !isdigit(*p)) return(p);

	(void)initinfstr();
	if (isdigit(*p)) (void)addtoinfstr('_');
	for(t = p; *t != 0 ; t++)
		if (isalnum(*t) || *t == '[' || *t == ']' || *t == ':') (void)addtoinfstr(*t); else
			(void)addtoinfstr('_');
	return(returninfstr());
}

/* Function to determine if this end of the connecting arc is negated */
INTSML sim_vernegated(PORTARCINST *pi)
{
	REGISTER ARCINST *ai;
	INTSML thisend;

	if (pi == NOPORTARCINST) return(0);

	ai = pi->conarcinst;
	if (ai == NOARCINST) return(0);
	if ((ai->userbits&ISNEGATED) == 0) return(0);

	if (ai->end[0].portarcinst == pi) thisend = 0; else
		thisend = 1;
	if ((thisend == 0 && (ai->userbits&REVERSEEND) == 0) ||
		(thisend == 1 && (ai->userbits&REVERSEEND) != 0)) return(1);
	return(0);
}

#endif  /* SIMAID - at top */
