/* -*- tab-width: 4 -*-
 *
 * 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 SIMTOOL

#include "global.h"
#include "efunction.h"
#include "sim.h"
#include "network.h"
#include "usr.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_statekey;			/* key for "SIM_verilog_state" */
static INTBIG      sim_verstate;
static FILE       *sim_verfile;
static INTBIG      sim_verilogcodekey = 0;
static INTBIG      sim_verilogdeclarationkey = 0;
static INTBIG      sim_verilogwiretypekey = 0;
static INTBIG      sim_verilogtemplatekey = 0;		/* key for "ATTR_verilog_template" */
static char        sim_verdeclarationline[MAXDECLARATIONWIDTH];
static INTBIG      sim_verdeclarationprefix;
static char      **sim_verilognamelist;
static INTBIG      sim_verilognamelisttotal = 0;
static INTBIG     *sim_verilognamelistlow;
static INTBIG     *sim_verilognamelisthigh;
static INTBIG     *sim_verilognamelisttempval;
static INTBIG      sim_verilogglobalnetcount;		/* number of global nets */
static INTBIG      sim_verilogglobalnettotal = 0;	/* size of global net array */
static char      **sim_verilogglobalnets;			/* global net names */
static INTBIG     *sim_verilogglobalchars;			/* global net characteristics */

typedef struct
{
	NETWORK   *net;
	PORTPROTO *pp;
} WIRELIST;

static WIRELIST   *sim_verilogwirelist;
static INTBIG      sim_verilogwirelisttotal = 0;

/* prototypes for local routines */
static BOOLEAN  sim_verwritefacet(NODEPROTO*);
static char    *sim_verconvertname(char *p);
static BOOLEAN  sim_verincludetypedcode(NODEPROTO*, INTBIG, char*);
static void     sim_verinitdeclaration(char *header);
static void     sim_veradddeclaration(char *signame);
static void     sim_vertermdeclaration(void);
static INTBIG   sim_vergetnetworks(NODEPROTO *facet, char ***namelist, INTBIG **lowindex,
					INTBIG **highindex, INTBIG **tempval, WIRELIST **wirelist, INTBIG *netcount,
					NETWORK **pwrnet, NETWORK **gndnet, INTBIG quiet);
static void     sim_verwritelongline(char *s);
static int      sim_versortwirelistsbyname(const void *e1, const void *e2);
static char    *sim_vernamenoindices(char *p);
static char    *sim_verstartofindex(char *name);
static void     sim_vergatherglobals(NODEPROTO *np);
static NETWORK *sim_vergetnetonport(NODEINST *ni, PORTPROTO *pp);
static void     sim_verwritebus(NETWORK **outernetlist, INTBIG lowindex, INTBIG highindex, INTBIG tempval,
					INTBIG *unconnectednet, char *name, NETWORK *pwrnet, NETWORK *gndnet, void *infstr);
static char    *sim_vercellname(CELL *c);

/*
 * Routine to free all memory associated with this module.
 */
void sim_freeverilogmemory(void)
{
	REGISTER INTBIG i;

	if (sim_verilognamelisttotal > 0)
	{
		for(i=0; i<sim_verilognamelisttotal; i++)
			efree(sim_verilognamelist[i]);
		efree((char *)sim_verilognamelist);
		efree((char *)sim_verilognamelistlow);
		efree((char *)sim_verilognamelisthigh);
		efree((char *)sim_verilognamelisttempval);
	}
	if (sim_verilogwirelisttotal > 0)
		efree((char *)sim_verilogwirelist);

	for(i=0; i<sim_verilogglobalnettotal; i++)
		if (sim_verilogglobalnets[i] != 0)
			efree((char *)sim_verilogglobalnets[i]);
	if (sim_verilogglobalnettotal > 0)
	{
		efree((char *)sim_verilogglobalnets);
		efree((char *)sim_verilogglobalchars);
	}
}

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

	/* make sure network tool is on */
	if ((net_tool->toolstate&TOOLON) == 0)
	{
		ttyputerr(_("Network tool must be running...turning it on"));
		toolturnon(net_tool);
		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");
	if (sim_verilogwiretypekey == 0)
		sim_verilogwiretypekey = makekey("SIM_verilog_wire_type");
	if (sim_verilogtemplatekey == 0)
		sim_verilogtemplatekey = makekey("ATTR_verilog_template");

	var = getvalkey((INTBIG)sim_tool, VTOOL, VINTEGER, sim_verilog_statekey);
	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 ((us_useroptions&NODATEORVERSION) == 0)
	{
		if (np->creationdate)
			xprintf(sim_verfile, "/* Created on %s */\n",
				timetostring((time_t)np->creationdate));
		if (np->revisiondate)
			xprintf(sim_verfile, "/* Last revised on %s */\n",
				timetostring((time_t)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);
	} else
	{
		xprintf(sim_verfile, "/* Written by Electric VLSI Design System */\n");
	}

	/*
	 * determine whether any facets have name clashes in other libraries
	 * (use "c->temp2" because "c->temp1" is used in node naming)
	 */
	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
		for(c = lib->firstcell; c != NOCELL; c = c->nextcell)
			c->temp2 = 0;
	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
	{
		if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
		for(c = lib->firstcell; c != NOCELL; c = c->nextcell)
		{
			for(olib = lib->nextlibrary; olib != NOLIBRARY; olib = olib->nextlibrary)
			{
				if ((olib->userbits&HIDDENLIBRARY) != 0) continue;
				for(oc = olib->firstcell; oc != NOCELL; oc = oc->nextcell)
					if (namesame(c->cellname, oc->cellname) == 0) break;
				if (oc != NOCELL)
					c->temp2 = oc->temp2 = 1;
			}
		}
	}

	/* gather all global signal names */
	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
		for(onp = lib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
			onp->temp1 = 0;
	sim_verilogglobalnetcount = 0;
	sim_vergatherglobals(np);
	if (sim_verilogglobalnetcount > 0)
	{
		xprintf(sim_verfile, "\nmodule glbl();\n");
		for(i=0; i<sim_verilogglobalnetcount; i++)
		{
			if (sim_verilogglobalchars[i] == PWRPORT)
			{
				xprintf(sim_verfile, "    supply1 %s;\n",
					sim_verilogglobalnets[i]);
			} else if (sim_verilogglobalchars[i] == GNDPORT)
			{
				xprintf(sim_verfile, "    supply0 %s;\n",
					sim_verilogglobalnets[i]);
			} else if ((sim_verstate&VERILOGUSETRIREG) != 0)
			{
				xprintf(sim_verfile, "    trireg %s;\n",
					sim_verilogglobalnets[i]);
			} else
			{
				xprintf(sim_verfile, "    wire %s;\n",
					sim_verilogglobalnets[i]);
			}
		}
		xprintf(sim_verfile, "endmodule\n");
	}

	/* 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;
	begintraversehierarchy();
	if (sim_verwritefacet(np))
		ttyputmsg(_("Back-annotation information has been added (library must be saved)"));
	endtraversehierarchy();

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

/*
 * recursively called routine to print the Verilog description of facet "np".
 */
BOOLEAN sim_verwritefacet(NODEPROTO *np)
{
	REGISTER INTBIG i, j, k, l, nodetype, implicitports, total, localwires, nindex, wt,
		impinv, nodewidth, isnegated, namecount, sigcount, wholenegated, dropbias, addednames;
	REGISTER BOOLEAN backannotate, first;
	REGISTER NODEINST *ni;
	REGISTER ARCINST *ai;
	REGISTER PORTPROTO *pp, *lastpp, *opp, *cpp;
	REGISTER NODEPROTO *onp, *cnp, *nip, *nipc;
	REGISTER PORTARCINST *pi;
	REGISTER PORTEXPINST *pe;
	REGISTER NETWORK *net, *onet, *gnet, **outernetlist;
	NETWORK *pwrnet, *gndnet, *pwrnetdummy, *gndnetdummy;
	WIRELIST *wirelist;
	INTBIG *lowindex, *highindex, *tempval, netcount, unconnectednet;
	REGISTER VARIABLE *var, *vartemplate;
	char **namelist, *porttype, *thisline, *signame, impsigname[100], *startpt, line[200],
		invsigname[100], *op, *pt, *opt, **ptr, *wiretype, save, osave,
		**strings, **nodenames, *nodename, *gn, *dir;
	REGISTER void *infstr;

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

	/* 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(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_key);
		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(backannotate);
	}

	/* make sure that all nodes and networks have names on them */
	addednames = 0;
	if (asktool(net_tool, "name-nodes", (INTBIG)np) != 0) addednames++;
	if (asktool(net_tool, "name-nets", (INTBIG)np) != 0) addednames++;
	if (addednames != 0)
	{
		backannotate = TRUE;
		net_endbatch();
	}

	/* 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;

		/* ignore recursive references (showing icon in contents) */
		if (ni->proto->cell == np->cell) continue;

		/* see if this facet has a template */
		var = getvalkey((INTBIG)ni->proto, VNODEPROTO, VSTRING, sim_verilogtemplatekey);
		if (var != NOVARIABLE) 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; else
		{
			/* see if this contents facet has a template */
			var = getvalkey((INTBIG)onp, VNODEPROTO, VSTRING, sim_verilogtemplatekey);
			if (var != NOVARIABLE) continue;
		}

		/* write the subfacet */
		if (onp->temp1 == 0)
		{
			downhierarchy(ni, onp, 0);
			if (sim_verwritefacet(onp)) backannotate = TRUE;
			uphierarchy();
		}
	}

	/* 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->buswidth;
		}
	}

	/* gather networks in the facet */
	namecount = sim_vergetnetworks(np, &namelist, &lowindex, &highindex,
		&tempval, &wirelist, &netcount, &pwrnet, &gndnet, 0);

	/* write the module header */
	xprintf(sim_verfile, "\n");
	infstr = initinfstr();
	formatinfstr(infstr, "module %s(", sim_vercellname(np->cell));
	first = TRUE;
	for(i=0; i<namecount; i++)
	{
		if (tempval[i] <= 1 || tempval[i] >= 6) continue;
		if (!first) addstringtoinfstr(infstr, ", ");
		addstringtoinfstr(infstr, namelist[i]);
		first = FALSE;
	}
	addstringtoinfstr(infstr, ");");
	sim_verwritelongline(returninfstr(infstr));

	/* look for "wire/trireg" overrides */
	for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
		net->temp2 = 0;
	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
	{
		var = getvalkey((INTBIG)ai, VARCINST, VSTRING, sim_verilogwiretypekey);
		if (var == NOVARIABLE) continue;
		if (namesame((char *)var->addr, "wire") == 0) ai->network->temp2 = 1; else
			if (namesame((char *)var->addr, "trireg") == 0) ai->network->temp2 = 2;
	}

	/* write description of formal parameters to module */
	first = TRUE;
	j = 0;
	for(i=0; i<namecount; i++)
	{
		if (tempval[i] > 1 && tempval[i] < 6)
		{
			switch (tempval[i])
			{
				case 2: case 3: porttype = "input";   break;
				case 4: case 5: porttype = "output";  break;
			}
			xprintf(sim_verfile, "  %s", porttype);
			if (lowindex[i] > highindex[i])
			{
				xprintf(sim_verfile, " %s;", namelist[i]);
				if (wirelist[j].net->temp2 != 0)
				{
					if (wirelist[j].net->temp2 == 1) xprintf(sim_verfile, "  wire"); else
						xprintf(sim_verfile, "  trireg");
					xprintf(sim_verfile, " %s;", namelist[i]);
				}
				xprintf(sim_verfile, "\n");
			} else
			{
				if ((tempval[i]&1) != 0)
				{
					xprintf(sim_verfile, " [%ld:%ld] %s;\n", highindex[i], lowindex[i],
						namelist[i]);
				} else
				{
					xprintf(sim_verfile, " [%ld:%ld] %s;\n", lowindex[i], highindex[i],
						namelist[i]);
				}
			}
			first = FALSE;
		}

		/* advance pointer to network information */
		if (lowindex[i] <= highindex[i]) j += highindex[i] - lowindex[i];
		j++;
	}
	if (!first) xprintf(sim_verfile, "\n");

	/* describe power and ground nets */
	if (pwrnet != NONETWORK) xprintf(sim_verfile, "  supply1 vdd;\n");
	if (gndnet != NONETWORK) xprintf(sim_verfile, "  supply0 gnd;\n");

	/* determine whether to use "wire" or "trireg" for networks */
	if ((sim_verstate&VERILOGUSETRIREG) != 0) wiretype = "trireg"; else
		wiretype = "wire";

	/* write "wire/trireg" declarations for internal single-wide signals */
	localwires = 0;
	for(wt=0; wt<2; wt++)
	{
		first = TRUE;
		j = 0;
		for(i=0; i<namecount; i++)
		{
			if (tempval[i] <= 1 && lowindex[i] > highindex[i])
			{
				if (wirelist[j].net->temp2 == 0) strcpy(impsigname, wiretype); else
				{
					if (wirelist[j].net->temp2 == 1) strcpy(impsigname, "wire"); else
						strcpy(impsigname, "trireg");
				}
				if ((wt == 0) ^ (namesame(wiretype, impsigname) == 0))
				{
					if (first)
					{
						sprintf(invsigname, "  %s", impsigname);
						sim_verinitdeclaration(invsigname);
					}
					sim_veradddeclaration(namelist[i]);
					localwires++;
					first = FALSE;
				}
			}

			/* advance pointer to network information */
			if (lowindex[i] <= highindex[i]) j += highindex[i] - lowindex[i];
			j++;
		}
		if (!first) sim_vertermdeclaration();
	}

	/* write "wire/trireg" declarations for internal busses */
	for(i=0; i<namecount; i++)
	{
		if (tempval[i] > 1) continue;
		if (lowindex[i] > highindex[i]) continue;

		if ((tempval[i]&1) != 0)
		{
			xprintf(sim_verfile, "  %s [%ld:%ld] %s;\n", wiretype,
				highindex[i], lowindex[i], namelist[i]);
		} else
		{
			xprintf(sim_verfile, "  %s [%ld:%ld] %s;\n", wiretype,
				lowindex[i], highindex[i], namelist[i]);
		}
		localwires++;
	}
	if (localwires != 0) xprintf(sim_verfile, "\n");

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

	/* add in any user-specified declarations and code */
	first = sim_verincludetypedcode(np, sim_verilogdeclarationkey, "declarations");
	first |= sim_verincludetypedcode(np, sim_verilogcodekey, "code");
	if (!first)
		xprintf(sim_verfile, "  /* automatically generated Verilog */\n");

	/* load Verilog names onto the networks */
	for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
		net->temp2 = 0;
	j = 0;
	for(i=0; i<namecount; i++)
	{
		if (lowindex[i] > highindex[i])
		{
			net = wirelist[j++].net;
			ptr = (char **)(&net->temp2);
			if (net->globalnet > 1 && net->globalnet < np->globalnetcount)
			{
				gn = sim_verconvertname(np->globalnetnames[net->globalnet]);
				*ptr = (char *)emalloc(strlen(gn)+7, sim_tool->cluster);
				strcpy(*ptr, " glbl.");
				strcat(*ptr, gn);
			} else
			{
				*ptr = (char *)emalloc(strlen(namelist[i])+2, sim_tool->cluster);
				strcpy(*ptr, " ");
				strcat(*ptr, namelist[i]);
			}
		} else
		{
			if ((tempval[i]&1) != 0) dir = "D"; else dir = "U";
			for(k=lowindex[i]; k<=highindex[i]; k++)
			{
				net = wirelist[j++].net;
				infstr = initinfstr();
				formatinfstr(infstr, "%s%s[%ld]", dir, namelist[i], k);
				ptr = (char **)(&net->temp2);
				(void)allocstring(ptr, returninfstr(infstr), sim_tool->cluster);
			}
		}
	}

	/* look at every node in this facet */
	unconnectednet = 1;
	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
	{
		/* not interested in passive nodes (ports electrically connected) */
		if (ni->proto->primindex != 0)
		{
			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;
		}

		nodewidth = ni->arraysize;
		if (nodewidth < 1) nodewidth = 1;

		nodetype = nodefunction(ni);

		/* special case: verilog should ignore R L C etc. */
		if (nodetype == NPRESIST || nodetype == NPCAPAC || nodetype == NPECAPAC ||
			nodetype == NPINDUCT) continue;

		/* 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(nindex=0; nindex<nodewidth; nindex++)
				{
					/* write a line describing this signal */
					infstr = initinfstr();
					wholenegated = 0;
					first = TRUE;
					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 (nodewidth > 1)
							{
								(void)net_evalbusname(
									(pi->conarcinst->proto->userbits&AFUNCTION)>>AFUNCTIONSH,
										net->netname, &strings, pi->conarcinst, np, 1);
								strcpy(impsigname, strings[nindex]);
								signame = impsigname;
							} else
							{
								if (net != NONETWORK && net->namecount > 0)
									signame = net->netname; else
										signame = describenetwork(net);
								if (net == pwrnet) signame = "vdd"; else
									if (net == gndnet) signame = "gnd";
							}

							/* 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" */
								addstringtoinfstr(infstr, "assign ");
								addstringtoinfstr(infstr, signame);
								addstringtoinfstr(infstr, " = ");
								if (isnegated != 0)
								{
									addstringtoinfstr(infstr, "~(");
									wholenegated = 1;
								}
								break;
							} else
							{
								if (!first)
									addstringtoinfstr(infstr, op);
								first = FALSE;
								if (isnegated != 0) addstringtoinfstr(infstr, "~");
								addstringtoinfstr(infstr, signame);
							}
						}
					}
					if (wholenegated != 0)
						addstringtoinfstr(infstr, ")");
					addstringtoinfstr(infstr, ";");
					sim_verwritelongline(returninfstr(infstr));
				}
				continue;
			}
		}

		/* get the name of the node */
		implicitports = 0;
		if (ni->proto->primindex == 0)
		{
			/* ignore recursive references (showing icon in contents) */
			if (ni->proto->cell == np->cell) continue;

			(void)allocstring(&nodename, sim_vercellname(ni->proto->cell),
				sim_tool->cluster);
		} else
		{
			pt = ni->proto->primname;
			dropbias = 0;
#if 1		/* convert 4-port transistors to 3-port */
			switch (nodetype)
			{
				case NPTRA4NMOS: nodetype = NPTRANMOS;  dropbias = 1;   break;
				case NPTRA4PMOS: nodetype = NPTRAPMOS;  dropbias = 1;   break;
			}
#endif
			switch (nodetype)
			{
				case NPTRANMOS:
					implicitports = 2;
					pt = "tranif1";
					var = getvalkey((INTBIG)ni, VNODEINST, -1, sim_weaknodekey);
					if (var != NOVARIABLE) pt = "rtranif1";
					break;
				case NPTRAPMOS:
					implicitports = 2;
					pt = "tranif0";
					var = getvalkey((INTBIG)ni, VNODEINST, -1, sim_weaknodekey);
					if (var != NOVARIABLE) pt = "rtranif0";
					break;
				case NPGATEAND:
					implicitports = 1;
					pt = "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)
						pt = "nand";
					break;
				case NPGATEOR:
					implicitports = 1;
					pt = "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)
						pt = "nor";
					break;
				case NPGATEXOR:
					implicitports = 1;
					pt = "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)
						pt = "xnor";
					break;
				case NPBUFFER:
					implicitports = 1;
					pt = "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)
						pt = "not";
					break;
			}
			(void)allocstring(&nodename, pt, sim_tool->cluster);
		}

		if (nodewidth > 1)
		{
			var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
			if (var == NOVARIABLE) nodewidth = 1; else
			{
				sigcount = net_evalbusname(APBUS, (char *)var->addr, &nodenames,
					NOARCINST, NONODEPROTO, 0);
				if (sigcount != nodewidth) nodewidth = 1;
			}
		}

		/* write the node (may be arrayed) */
		for(nindex=0; nindex<nodewidth; nindex++)
		{
			/* look for a Verilog template on the prototype */
			vartemplate = getvalkey((INTBIG)ni->proto, VNODEPROTO, VSTRING, sim_verilogtemplatekey);
			if (vartemplate == NOVARIABLE)
			{
				cnp = contentsview(ni->proto);
				if (cnp != NONODEPROTO)
					vartemplate = getvalkey((INTBIG)cnp, VNODEPROTO, VSTRING, sim_verilogtemplatekey);
			}

			if (vartemplate == NOVARIABLE)
			{
				/* write the type of the node */
				infstr = initinfstr();
				addstringtoinfstr(infstr, "  ");
				addstringtoinfstr(infstr, nodename);

				/* write the name of the node */
				if (nodewidth > 1)
				{
					addstringtoinfstr(infstr, " ");
					addstringtoinfstr(infstr, sim_vernamenoindices(nodenames[nindex]));
				} else
				{
					var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
					if (var != NOVARIABLE)
					{
						addstringtoinfstr(infstr, " ");
						addstringtoinfstr(infstr, sim_vernamenoindices((char *)var->addr));
					}
				}
				addstringtoinfstr(infstr, "(");
			}

			/* write the rest of the ports */
			first = TRUE;
			switch (implicitports)
			{
				case 0:		/* explicit ports */
					cnp = contentsview(ni->proto);
					if (cnp == NONODEPROTO) cnp = ni->proto;
					for(net = cnp->firstnetwork; net != NONETWORK; net = net->nextnetwork)
						net->temp2 = (INTBIG)NONETWORK;
					for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
					{
						cpp = equivalentport(ni->proto, pp, cnp);
						if (cpp == NOPORTPROTO) continue;
						net = sim_vergetnetonport(ni, pp);
						if (net != NONETWORK && net->buswidth > 1)
						{
							sigcount = net->buswidth;
							if (nodewidth > 1 && cpp->network->buswidth * nodewidth == net->buswidth)
							{
								/* map wide bus to a particular instantiation of an arrayed node */
								if (cpp->network->buswidth == 1)
								{
									onet = (NETWORK *)cpp->network->temp2;
									if (onet == NONETWORK)
										cpp->network->temp2 = (INTBIG)net->networklist[nindex];
								} else
								{
									for(i=0; i<cpp->network->buswidth; i++)
									{
										onet = (NETWORK *)cpp->network->networklist[i]->temp2;
										if (onet == NONETWORK)
											cpp->network->networklist[i]->temp2 =
												(INTBIG)net->networklist[i + nindex*cpp->network->buswidth];
									}
								}
							} else
							{
								if (cpp->network->buswidth != net->buswidth)
								{
									ttyputerr(_("***ERROR: port %s on node %s in facet %s is %d wide, but is connected/exported with width %d"),
										pp->protoname, describenodeinst(ni), describenodeproto(np),
											cpp->network->buswidth, net->buswidth);
									sigcount = mini(sigcount, cpp->network->buswidth);
									if (sigcount == 1) sigcount = 0;
								}
								onet = (NETWORK *)cpp->network->temp2;
								if (onet == NONETWORK) cpp->network->temp2 = (INTBIG)net;
								for(i=0; i<sigcount; i++)
								{
									onet = (NETWORK *)cpp->network->networklist[i]->temp2;
									if (onet == NONETWORK)
										cpp->network->networklist[i]->temp2 = (INTBIG)net->networklist[i];
								}
							}
						} else
						{
							onet = (NETWORK *)cpp->network->temp2;
							if (onet == NONETWORK) cpp->network->temp2 = (INTBIG)net;
						}
					}

					/* special case for Verilog templates */
					if (vartemplate != NOVARIABLE)
					{
						infstr = initinfstr();
						addstringtoinfstr(infstr, "  ");
						for(pt = (char *)vartemplate->addr; *pt != 0; pt++)
						{
							if (pt[0] != '$' || pt[1] != '(')
							{
								addtoinfstr(infstr, *pt);
								continue;
							}
							startpt = pt + 2;
							for(pt = startpt; *pt != 0; pt++)
								if (*pt == ')') break;
							save = *pt;
							*pt = 0;
							pp = getportproto(ni->proto, startpt);
							if (pp != NOPORTPROTO)
							{
								/* port name found: use its verilog node */
								net = sim_vergetnetonport(ni, pp);
								if (net == NONETWORK)
								{
									formatinfstr(infstr, "UNCONNECTED%ld", unconnectednet++);
								} else
								{
									if (net->buswidth > 1)
									{
										sigcount = net->buswidth;
										if (nodewidth > 1 && pp->network->buswidth * nodewidth == net->buswidth)
										{
											/* map wide bus to a particular instantiation of an arrayed node */
											if (pp->network->buswidth == 1)
											{
												onet = net->networklist[nindex];
												if (onet == pwrnet) addstringtoinfstr(infstr, "vdd"); else
													if (onet == gndnet) addstringtoinfstr(infstr, "gnd"); else
														addstringtoinfstr(infstr, &((char *)onet->temp2)[1]);
											} else
											{
												outernetlist = (NETWORK **)emalloc(pp->network->buswidth * (sizeof (NETWORK *)),
													sim_tool->cluster);
												for(j=0; j<pp->network->buswidth; j++)
													outernetlist[j] = net->networklist[i + nindex*pp->network->buswidth];
												for(opt = pp->protoname; *opt != 0; opt++)
													if (*opt == '[') break;
												osave = *opt;
												*opt = 0;
												sim_verwritebus(outernetlist, 0, net->buswidth-1, 1,
													&unconnectednet, pp->protoname, pwrnet, gndnet, infstr);
												*opt = osave;
												efree((char *)outernetlist);
											}
										} else
										{
											if (pp->network->buswidth != net->buswidth)
											{
												ttyputerr(_("***ERROR: port %s on node %s in facet %s is %d wide, but is connected/exported with width %d"),
													pp->protoname, describenodeinst(ni), describenodeproto(np),
														cpp->network->buswidth, net->buswidth);
												sigcount = mini(sigcount, cpp->network->buswidth);
												if (sigcount == 1) sigcount = 0;
											}
											outernetlist = (NETWORK **)emalloc(net->buswidth * (sizeof (NETWORK *)),
												sim_tool->cluster);
											for(j=0; j<net->buswidth; j++)
												outernetlist[j] = net->networklist[j];
											for(opt = pp->protoname; *opt != 0; opt++)
												if (*opt == '[') break;
											osave = *opt;
											*opt = 0;
											sim_verwritebus(outernetlist, 0, net->buswidth-1, 1,
												&unconnectednet, pp->protoname, pwrnet, gndnet, infstr);
											*opt = osave;
											efree((char *)outernetlist);
										}
									} else
									{
										if (net == pwrnet) addstringtoinfstr(infstr, "vdd"); else
											if (net == gndnet) addstringtoinfstr(infstr, "gnd"); else
												addstringtoinfstr(infstr, &((char *)net->temp2)[1]);
									}
								}
							} else if (namesame(startpt, "node_name") == 0)
							{
								if (nodewidth > 1) opt = nodenames[nindex]; else
								{
									var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
									if (var == NOVARIABLE) opt = ""; else
										opt = (char *)var->addr;
								}
								addstringtoinfstr(infstr, sim_vernamenoindices(opt));
							} else
							{
								/* no port name found, look for variable name */
								sprintf(line, "ATTR_%s", startpt);
								var = getval((INTBIG)ni, VNODEINST, -1, line);
								if (var == NOVARIABLE)
									var = getval((INTBIG)ni, VNODEINST, -1, startpt);
								if (var == NOVARIABLE)
								{
									/* value not found: see if this is a parameter and use default */
									nip = ni->proto;
									nipc = contentsview(nip);
									if (nipc != NONODEPROTO) nip = nipc;
									var = getval((INTBIG)nip, VNODEPROTO, -1, line);
								}
								if (var == NOVARIABLE)
									addstringtoinfstr(infstr, "??"); else
								{
									addstringtoinfstr(infstr, describesimplevariable(var));
								}
							}
							*pt = save;
							if (save == 0) break;
						}
						break;
					}

					/* generate the line the normal way */
					namecount = sim_vergetnetworks(cnp, &namelist, &lowindex, &highindex,
						&tempval, &wirelist, &netcount, &pwrnetdummy, &gndnetdummy, 1);
					l = 0;
					for(i=0; i<namecount; i++)
					{
						/* ignore networks that aren't exported */
						if (tempval[i] <= 1 || tempval[i] >= 6)
						{
							l++;
							if (lowindex[i] <= highindex[i])
								l += highindex[i] - lowindex[i];
							continue;
						}
						if (first) first = FALSE; else
							addstringtoinfstr(infstr, ", ");
						if (lowindex[i] > highindex[i])
						{
							/* single signal */
							addstringtoinfstr(infstr, ".");
							addstringtoinfstr(infstr, namelist[i]);
							addstringtoinfstr(infstr, "(");
							net = (NETWORK *)wirelist[l++].net->temp2;
							if (net == NONETWORK)
							{
								formatinfstr(infstr, "UNCONNECTED%ld", unconnectednet++);
							} else
							{
								if (net == pwrnet) addstringtoinfstr(infstr, "vdd"); else
									if (net == gndnet) addstringtoinfstr(infstr, "gnd"); else
										addstringtoinfstr(infstr, &((char *)net->temp2)[1]);
							}
							addstringtoinfstr(infstr, ")");
						} else
						{
							total = highindex[i]-lowindex[i]+1;
							outernetlist = (NETWORK **)emalloc(total * (sizeof (NETWORK *)),
								sim_tool->cluster);
							for(j=lowindex[i]; j<=highindex[i]; j++)
								outernetlist[j-lowindex[i]] = (NETWORK *)wirelist[j-lowindex[i]+l].net->temp2;

							sim_verwritebus(outernetlist, lowindex[i], highindex[i], tempval[i],
								&unconnectednet, namelist[i], pwrnet, gndnet, infstr);
							l += highindex[i] - lowindex[i] + 1;
							efree((char *)outernetlist);
						}
					}
					addstringtoinfstr(infstr, ");");
					break;

				case 1:		/* and/or gate: write ports in the proper order */
					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) first = FALSE; else
								addstringtoinfstr(infstr, ", ");
							net = pi->conarcinst->network;
							if (nodewidth > 1)
							{
								if (net->buswidth == nodewidth) net = net->networklist[nindex];
							} else
							{
								if (net->buswidth > 1)
								{
									ttyputerr(_("***ERROR: facet %s, node %s is not arrayed but is connected to a bus"),
										describenodeproto(np), describenodeinst(ni));
									net = net->networklist[0];
								}
							}
							signame = &((char *)net->temp2)[1];
							if (net == pwrnet) signame = "vdd"; else
								if (net == gndnet) signame = "gnd";
							if (i != 0 && pi->conarcinst->temp1 != 0)
							{
								/* this input is negated: write the implicit inverter */
								sprintf(invsigname, "%s%ld", IMPLICITINVERTERSIGNAME,
									pi->conarcinst->temp1+nindex);
								xprintf(sim_verfile, "  inv %s%ld (%s, %s);\n",
									IMPLICITINVERTERNODENAME, pi->conarcinst->temp1+nindex,
										invsigname, signame);
								signame = invsigname;
							}
							addstringtoinfstr(infstr, signame);
						}
					}
					addstringtoinfstr(infstr, ");");
					break;

				case 2:		/* transistors: write ports in the proper order */
					/* schem: g/s/d  mos: g/s/g/d */
					gnet = ni->proto->firstportproto->network;
					for(i=0; i<2; i++)
					{
						for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
						{
							for(opp = ni->proto->firstportproto; opp != pp; opp = opp->nextportproto)
								if (opp->network == pp->network) break;
							if (opp != pp) continue;
							if (dropbias != 0 && namesame(pp->protoname, "b") == 0) continue;
							if (i == 0)
							{
								if (pp->network == gnet) continue;
							} else
							{
								if (pp->network != gnet) continue;
							}
							net = NONETWORK;
							for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
								if (pi->proto->network == pp->network) break;
							if (pi != NOPORTARCINST) net = pi->conarcinst->network; else
							{
								for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
									if (pe->proto == pp) break;
								if (pe != NOPORTEXPINST) net = pe->exportproto->network;
							}
							if (first) first = FALSE; else
								addstringtoinfstr(infstr, ", ");
							if (net == NONETWORK)
							{
								ttyputmsg(_("***Warning: facet %s, node %s is not fully connected"),
									describenodeproto(np), describenodeinst(ni));
								sprintf(impsigname, "UNCONNECTED%ld", unconnectednet++);
								signame = impsigname;
							} else
							{
								if (nodewidth > 1)
								{
									(void)net_evalbusname(APBUS, net->netname, &strings, pi->conarcinst, np, 1);
									strcpy(impsigname, strings[nindex]);
									signame = impsigname;
								} else
								{
									signame = &((char *)net->temp2)[1];
									if (net == pwrnet) signame = "vdd"; else
										if (net == gndnet) signame = "gnd";
								}
								if (i != 0 && pi != NOPORTARCINST && pi->conarcinst->temp1 != 0)
								{
									/* this input is negated: write the implicit inverter */
									sprintf(invsigname, "%s%ld", IMPLICITINVERTERSIGNAME,
										pi->conarcinst->temp1+nindex);
									xprintf(sim_verfile, "  inv %s%ld (%s, %s);\n",
										IMPLICITINVERTERNODENAME, pi->conarcinst->temp1+nindex,
											invsigname, signame);
									signame = invsigname;
								}
							}
							addstringtoinfstr(infstr, signame);
						}
					}
					addstringtoinfstr(infstr, ");");
					break;
#if 0
				case 3:		/* facet that has an external definition */
					for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
					{
						for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
							if (pi->proto->network == pp->network) break;
						if (first) first = FALSE; else
							addstringtoinfstr(infstr, ", ");
						if (pi == NOPORTARCINST)
						{
							ttyputmsg(_("Warning: facet %s, node %s is not fully connected"),
								describenodeproto(np), describenodeinst(ni));
							sprintf(impsigname, "UNCONNECTED%ld", unconnectednet++);
							signame = impsigname;
						} else
						{
							net = pi->conarcinst->network;
							if (nodewidth > 1)
							{
								(void)net_evalbusname(
									(pi->conarcinst->proto->userbits&AFUNCTION)>>AFUNCTIONSH,
										net->netname, &strings, pi->conarcinst, np, 1);
								strcpy(impsigname, strings[nindex]);
								signame = impsigname;
							} else
							{
								signame = &((char *)net->temp2)[1];
								if (net == pwrnet) signame = "vdd"; else
									if (net == gndnet) signame = "gnd";
							}
							if (pi->conarcinst->temp1 != 0)
							{
								/* this input is negated: write the implicit inverter */
								sprintf(invsigname, "%s%ld", IMPLICITINVERTERSIGNAME,
									pi->conarcinst->temp1+nindex);
								xprintf(sim_verfile, "  inv %s%ld (%s, %s);\n",
									IMPLICITINVERTERNODENAME, pi->conarcinst->temp1+nindex,
										invsigname, signame);
								signame = invsigname;
							}
						}
						formatinfstr(infstr, ".%s(%s)", sim_verconvertname(pp->protoname), signame);
					}
					addstringtoinfstr(infstr, ");");
					break;
#endif
			}
			sim_verwritelongline(returninfstr(infstr));
		}
		efree((char *)nodename);
	}
	xprintf(sim_verfile, "endmodule   /* %s */\n",
		sim_vercellname(np->cell));

	/* free net names */
	for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
		if (net->temp2 != 0) efree((char *)net->temp2);

	return(backannotate);
}

/*
 * Routine to add a bus of signals named "name" to the infinite string "infstr".  The signals are in
 * "outernetlist" and range in index from "lowindex" to "highindex".  They are described by a bus
 * with characteristic "tempval" (low bit is on if the bus descends).  Any unconnected networks can
 * be numbered starting at "*unconnectednet".  The power and grounds nets are "pwrnet" and "gndnet".
 */
void sim_verwritebus(NETWORK **outernetlist, INTBIG lowindex, INTBIG highindex, INTBIG tempval,
	INTBIG *unconnectednet, char *name, NETWORK *pwrnet, NETWORK *gndnet, void *infstr)
{
	REGISTER INTBIG breakbus, numexported, numinternal, j, k, start, end, order, li;
	REGISTER NETWORK *net, *onet, *lastnet;
	REGISTER char *thisnetname, *lastnetname, *pt, *lastpt;

	/* array signal: see if it gets split out */
	breakbus = 0;

	/* bus cannot have pwr/gnd, must be connected */
	numexported = numinternal = 0;
	for(j=lowindex; j<=highindex; j++)
	{
		net = outernetlist[j-lowindex];
		if (net == NONETWORK || net->temp1 == 6) break;
		if (net->temp1 > 1) numexported++; else
			numinternal++;
	}
	if (j <= highindex) breakbus = 1;

	/* must be all exported or all internal, not a mix */
	if (numexported > 0 && numinternal > 0) breakbus = 1;

	if (breakbus == 0)
	{
		/* see if all of the nets on this bus are distinct */
		for(j=lowindex+1; j<=highindex; j++)
		{
			net = outernetlist[j-lowindex];
			for(k=lowindex; k<j; k++)
			{
				onet = outernetlist[k-lowindex];
				if (net == onet) break;
			}
			if (k < j) break;
		}
		if (j <= highindex) breakbus = 1; else
		{
			/* bus entries must have the same root name and go in order */
			for(j=lowindex; j<=highindex; j++)
			{
				net = outernetlist[j-lowindex];
				thisnetname = (char *)net->temp2;
				if (*thisnetname == 'D')
				{
					if ((tempval&1) == 0) break;
				} else if (*thisnetname == 'U')
				{
					if ((tempval&1) != 0) break;
				}
				thisnetname++;

				for(pt = thisnetname; *pt != 0; pt++)
					if (*pt == '[') break;
				if (*pt == 0) break;
				if (j > lowindex)
				{
					lastnetname = &((char *)lastnet->temp2)[1];
					for(li = 0; lastnetname[li] != 0; li++)
					{
						if (thisnetname[li] != lastnetname[li]) break;
						if (lastnetname[li] == '[') break;
					}
					if (lastnetname[li] != '[' || thisnetname[li] != '[') break;
					if (myatoi(pt+1) != myatoi(&lastnetname[li+1])+1) break;
				}
				lastnet = net;
			}
			if (j <= highindex) breakbus = 1;
		}
	}

	addstringtoinfstr(infstr, ".");
	addstringtoinfstr(infstr, name);
	addstringtoinfstr(infstr, "(");
	if (breakbus != 0)
	{
		addstringtoinfstr(infstr, "{");
		if ((tempval&1) != 0)
		{
			start = highindex;
			end = lowindex;
			order = -1;
		} else
		{
			start = lowindex;
			end = highindex;
			order = 1;
		}
		for(j=start; ; j += order)
		{
			if (j != start)
				addstringtoinfstr(infstr, ", ");
			net = outernetlist[j-lowindex];
			if (net == NONETWORK)
			{
				formatinfstr(infstr, "UNCONNECTED%ld", *unconnectednet);
				(*unconnectednet)++;
			} else
			{
				if (net == pwrnet) addstringtoinfstr(infstr, "vdd"); else
					if (net == gndnet) addstringtoinfstr(infstr, "gnd"); else
						addstringtoinfstr(infstr, &((char *)net->temp2)[1]);
			}
			if (j == end) break;
		}
		addstringtoinfstr(infstr, "}");
	} else
	{
		lastnet = outernetlist[0];
		for(lastpt = &((char *)lastnet->temp2)[1]; *lastpt != 0; lastpt++)
			if (*lastpt == '[') break;
		net = outernetlist[highindex-lowindex];
		for(pt = &((char *)net->temp2)[1]; *pt != 0; pt++)
		{
			if (*pt == '[') break;
			addtoinfstr(infstr, *pt);
		}
		if ((tempval&1) != 0)
		{
			formatinfstr(infstr, "[%ld:%ld]", myatoi(pt+1), myatoi(lastpt+1));
		} else
		{
			formatinfstr(infstr, "[%ld:%ld]", myatoi(lastpt+1), myatoi(pt+1));
		}
	}
	addstringtoinfstr(infstr, ")");
}

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

	/* write out any directly-typed Verilog code */
	first = TRUE;
	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)
		{
			first = FALSE;
			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]);
		}
	}
	if (!first) xprintf(sim_verfile, "\n");
	return(first);
}

/*
 * Routine to write a long line to the Verilog file, breaking it where sensible.
 */
void sim_verwritelongline(char *s)
{
	char *pt, save;
	INTBIG i;
	char *lastspace;

	lastspace = NULL;
	i = 0;
	for (pt = s; *pt; pt++)
	{
		if (*pt == ' ' || *pt == ',') lastspace = pt;
		++i;
		if (i >= MAXDECLARATIONWIDTH)
		{
			if (lastspace != NULL)
			{
				if (*lastspace != ' ') lastspace++;
				save = *lastspace;   *lastspace = 0;
				xputs(s, sim_verfile);
				*lastspace = save;
				xputs("\n      ", sim_verfile);
				s = lastspace;
				if (*s == ' ') s++;
				i = 6 + pt-s+1;
				lastspace = NULL;
			} else
			{
				xputs("\n      ", sim_verfile);
				i = 6 + 1;
			}
		}
	}
	xputs(s, sim_verfile);
	xputs("\n", sim_verfile);
}

/*
 * 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 return the name of cell "c", given that it may be ambiguously used in multiple
 * libraries.
 */
char *sim_vercellname(CELL *c)
{
	REGISTER void *infstr;

	if (c->temp2 == 0)
		return(sim_verconvertname(c->cellname));

	infstr = initinfstr();
	formatinfstr(infstr, "%s__%s", c->lib->libname, c->cellname);
	return(returninfstr(infstr));
}

/*
 * routine to adjust name "p" and return the string.
 * Verilog does permit a digit in the first location; prepend a "_" if found.
 * Verilog only permits the "_" and "$" characters: all others are converted to "_".
 * Verilog does not permit nonnumeric indices, so "P[A]" is converted to "P_A_"
 * Verilog does not permit multidimensional arrays, so "P[1][2]" is converted to "P_1_[2]"
 *   and "P[1][T]" is converted to "P_1_T_"
 */
char *sim_verconvertname(char *p)
{
	REGISTER char *t, *end;
	REGISTER void *infstr;

	/* simple names are trivially accepted as is */
	for(t = p; *t != 0; t++) if (!isalnum(*t)) break;
	if (*t == 0 && !isdigit(*p)) return(p);

	infstr = initinfstr();
	end = sim_verstartofindex(p);
	for(t = p; t < end; t++)
	{
		if (*t == '[' || *t == ']')
		{
			addtoinfstr(infstr, '_');
			if (*t == ']' && t[1] == '[') t++;
		} else
		{
			if (isalnum(*t) || *t == '_' || *t == '$')
				addtoinfstr(infstr, *t); else
					addtoinfstr(infstr, '_');
		}
	}
	addstringtoinfstr(infstr, end);
	return(returninfstr(infstr));
}

/*
 * routine to adjust name "p" and return the string.
 * This code removes all index indicators and other special characters, turning
 * them into "_".
 */
char *sim_vernamenoindices(char *p)
{
	REGISTER char *t;
	REGISTER void *infstr;

	infstr = initinfstr();
	if (isdigit(*p)) addtoinfstr(infstr, '_');
	for(t = p; *t != 0 ; t++)
	{
		if (isalnum(*t) || *t == '_' || *t == '$')
			addtoinfstr(infstr, *t); else
				addtoinfstr(infstr, '_');
	}
	return(returninfstr(infstr));
}

/*
 * Routine to return the character position in network name "name" that is the start of indexing.
 * If there is no indexing ("clock"), this will point to the end of the string.
 * If there is simple indexing ("dog[12]"), this will point to the "[".
 * If the index is nonnumeric ("dog[cat]"), this will point to the end of the string.
 * If there are multiple indices, ("dog[12][45]") this will point to the last "[" (unless it is nonnumeric).
 */
char *sim_verstartofindex(char *name)
{
	REGISTER INTBIG len, i;

	len = strlen(name);
	if (name[len-1] != ']') return(name+len);
	for(i = len-2; i > 0; i--)
	{
		if (name[i] == '[') break;
		if (name[i] == ':' || name[i] == ',') continue;
		if (!isdigit(name[i])) break;
	}
	if (name[i] != '[') return(name+len);
	return(name+i);
}

/*
 * Routine to scan networks in facet "facet".  The "temp1" field is filled in with
 *    0: internal network (ascending order when in a bus)
 *    1: internal network (descending order when in a bus)
 *    2: exported input network (ascending order when in a bus)
 *    3: exported input network (descending order when in a bus)
 *    4: exported output network (ascending order when in a bus)
 *    5: exported output network (descending order when in a bus)
 *    6: power or ground network
 * All networks are sorted by name within "temp1" and the common array entries are
 * reduced to a list of names (in "namelist") and their low/high range of indices
 * (in "lowindex" and "highindex", with high < low if no indices apply).  The value
 * of "temp1" is returned in the array "tempval".  The list of "netcount" networks
 * found (uncombined by index) is returned in "wirelist".  The power and ground nets
 * are stored in "pwrnet" and "gndnet".  The total number of names is returned.
 */
INTBIG sim_vergetnetworks(NODEPROTO *facet, char ***namelist,
	INTBIG **lowindex, INTBIG **highindex, INTBIG **tempval,
	WIRELIST **wirelist, INTBIG *netcount, NETWORK **pwrnet, NETWORK **gndnet, INTBIG quiet)
{
	REGISTER NETWORK *net, *endnet, *subnet;
	REGISTER PORTPROTO *pp, *widestpp;
	REGISTER BOOLEAN updir, downdir, randomdir, multipwr, multignd, found;
	REGISTER NODEINST *ni;
	REGISTER ARCINST *ai;
	REGISTER PORTARCINST *pi;
	REGISTER INTBIG wirecount, i, j, k, namelistcount, index, newtotal, dirbit,
		*newtemp, *newlow, *newhigh, comp, fun, last, widestfound,
		characteristics;
	REGISTER char **newnamelist, save, *pt, *ept, *name;
	REGISTER void *infstr;

	/* initialize to describe all nets */
	namelistcount = 0;
	wirecount = 0;
	for(net = facet->firstnetwork; net != NONETWORK; net = net->nextnetwork)
	{
		net->temp1 = 0;
		if (net->buswidth > 1) continue;
		wirecount++;
	}

	/* determine default direction of busses */
	if ((net_options&NETDEFBUSBASEDESC) != 0) dirbit = 1; else
		dirbit = 0;

	/* mark exported networks */
	for(pp = facet->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
	{
		switch (pp->userbits&STATEBITS)
		{
			case OUTPORT:   j = 4+dirbit;  break;
			default:        j = 2+dirbit;  break;
		}
		if (pp->network->buswidth > 1)
		{
			/* bus export: mark individual network entries */
			for(i=0; i<pp->network->buswidth; i++)
			{
				net = pp->network->networklist[i];
				net->temp1 = j;
			}
		} else
		{
			/* single wire export: mark the network */
			net = pp->network;
			net->temp1 = j;
		}
	}

	/* postprocess to ensure the directionality is correct */
	for(net = facet->firstnetwork; net != NONETWORK; net = net->nextnetwork)
	{
		if (net->temp1 == 0) continue;
		if (net->namecount <= 0) continue;
		for(pp = facet->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
		{
			if (pp->network->buswidth > 1) continue;
			if (namesame(pp->protoname, net->netname) != 0) continue;
			switch (pp->userbits&STATEBITS)
			{
				case OUTPORT:   j = 4+dirbit;  break;
				default:        j = 2+dirbit;  break;
			}
			net->temp1 = j;
		}
	}

	/* make sure all busses go in the same direction */
	for(net = facet->firstnetwork; net != NONETWORK; net = net->nextnetwork)
	{
		if (net->buswidth <= 1) continue;
		j = 0;
		for(i=0; i<net->buswidth; i++)
		{
			subnet = net->networklist[i];
			if (subnet->temp1 == 0) continue;
			if (j == 0) j = subnet->temp1;
			if (subnet->temp1 != j) break;
		}
		if (i >= net->buswidth) continue;

		/* mixed directionality: make it all nonoutput */
		for(i=0; i<net->buswidth; i++)
		{
			subnet = net->networklist[i];
			subnet->temp1 = 2+dirbit;
		}
	}

	/* scan all networks for those that go in descending order */
	for(net = facet->firstnetwork; net != NONETWORK; net = net->nextnetwork)
	{
		if (net->buswidth <= 1) continue;
		updir = downdir = randomdir = FALSE;
		for(i=0; i<net->buswidth; i++)
		{
			subnet = net->networklist[i];
			if (subnet->namecount == 0) break;
			for(pt = subnet->netname; *pt != 0; pt++)
				if (*pt == '[') break;
			if (*pt == 0) break;
			if (isdigit(pt[1]) == 0) break;
			index = myatoi(pt+1);
			if (i != 0)
			{
				if (index == last-1) downdir = TRUE; else
					if (index == last+1) updir = TRUE; else
						randomdir = TRUE;
			}
			last = index;
		}
		if (randomdir) continue;
		if (updir && downdir) continue;
		if (!updir && !downdir) continue;
		if (downdir) dirbit = 1; else
			dirbit = 0;
		for(i=0; i<net->buswidth; i++)
		{
			subnet = net->networklist[i];
			subnet->temp1 = (subnet->temp1 & ~1) | dirbit;
		}
	}

	/* find power and ground */
	*pwrnet = *gndnet = NONETWORK;
	multipwr = multignd = FALSE;
	for(pp = facet->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
	{
		if (portispower(pp))
		{
			if (*pwrnet != NONETWORK && *pwrnet != pp->network && !multipwr)
			{
				if (quiet == 0)
					ttyputmsg(_("Warning: multiple power networks in facet %s"),
						describenodeproto(facet));
				multipwr = TRUE;
			}
			*pwrnet = pp->network;
		}
		if (portisground(pp))
		{
			if (*gndnet != NONETWORK && *gndnet != pp->network && !multignd)
			{
				if (quiet == 0)
					ttyputmsg(_("Warning: multiple ground networks in facet %s"),
						describenodeproto(facet));
				multignd = TRUE;
			}
			*gndnet = pp->network;
		}
	}
	for(net = facet->firstnetwork; net != NONETWORK; net = net->nextnetwork)
	{
		if (net->globalnet >= 0 && net->globalnet < facet->globalnetcount)
		{
			characteristics = facet->globalnetchar[net->globalnet];
			if (characteristics == PWRPORT)
			{
				if (*pwrnet != NONETWORK && *pwrnet != net && !multipwr)
				{
					if (quiet == 0)
						ttyputmsg(_("Warning: multiple power networks in facet %s"),
							describenodeproto(facet));
					multipwr = TRUE;
				}
				*pwrnet = net;
			} else if (characteristics == GNDPORT)
			{
				if (*gndnet != NONETWORK && *gndnet != net && !multignd)
				{
					if (quiet == 0)
						ttyputmsg(_("Warning: multiple ground networks in facet %s"),
							describenodeproto(facet));
					multignd = TRUE;
				}
				*gndnet = net;
			}
		}
	}
	for(ni = facet->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
	{
		fun = nodefunction(ni);
		if (fun == NPCONPOWER || fun == NPCONGROUND)
		{
			for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
			{
				ai = pi->conarcinst;
				if (fun == NPCONPOWER)
				{
					if (*pwrnet != NONETWORK && *pwrnet != ai->network && !multipwr)
					{
						if (quiet == 0)
							ttyputmsg(_("Warning: multiple power networks in facet %s"),
								describenodeproto(facet));
						multipwr = TRUE;
					}
					*pwrnet = ai->network;
				} else
				{
					if (*gndnet != NONETWORK && *gndnet != ai->network && !multignd)
					{
						if (quiet == 0)
							ttyputmsg(_("Warning: multiple ground networks in facet %s"),
								describenodeproto(facet));
						multignd = TRUE;
					}
					*gndnet = ai->network;
				}
			}
		}
	}
	if (*pwrnet != NONETWORK) (*pwrnet)->temp1 = 6;
	if (*gndnet != NONETWORK) (*gndnet)->temp1 = 6;

	/* make sure there is room in the array of networks */
	if (wirecount > sim_verilogwirelisttotal)
	{
		if (sim_verilogwirelisttotal > 0)
			efree((char *)sim_verilogwirelist);
		sim_verilogwirelisttotal = 0;
		sim_verilogwirelist = (WIRELIST *)emalloc(wirecount * (sizeof (WIRELIST)),
			sim_tool->cluster);
		if (sim_verilogwirelist == 0) return(0);
		sim_verilogwirelisttotal = wirecount;
	}

	/* load the array */
	if (wirecount > 0)
	{
		i = 0;
		for(net = facet->firstnetwork; net != NONETWORK; net = net->nextnetwork)
		{
			if (net->buswidth > 1) continue;
			sim_verilogwirelist[i].net = net;
			sim_verilogwirelist[i].pp = NOPORTPROTO;

			/* find the widest export that touches this network */
			widestfound = -1;
			widestpp = NOPORTPROTO;
			for(pp = facet->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
			{
				found = FALSE;
				if (pp->network == net) found = TRUE; else
				{
					if (pp->network->buswidth > 1)
					{
						for(j=0; j<pp->network->buswidth; j++)
							if (pp->network->networklist[j] == net) break;
						if (j < pp->network->buswidth) found = TRUE;
					}
				}
				if (found)
				{
					if (pp->network->buswidth > widestfound)
					{
						widestfound = pp->network->buswidth;
						widestpp = pp;
					}
				}
			}
			if (widestpp != NOPORTPROTO) sim_verilogwirelist[i].pp = widestpp;
			i++;
		}

		/* sort the networks by name */
		esort(sim_verilogwirelist, wirecount, sizeof (WIRELIST), sim_versortwirelistsbyname);

		/* organize by name and index order */
		for(i=0; i<wirecount; i++)
		{
			net = sim_verilogwirelist[i].net;

			/* make sure there is room in the list */
			if (namelistcount >= sim_verilognamelisttotal)
			{
				newtotal = sim_verilognamelisttotal * 2;
				if (newtotal <= namelistcount) newtotal = namelistcount + 5;
				newnamelist = (char **)emalloc(newtotal * (sizeof (char *)),
					sim_tool->cluster);
				if (newnamelist == 0) return(0);
				newlow = (INTBIG *)emalloc(newtotal * SIZEOFINTBIG, sim_tool->cluster);
				if (newlow == 0) return(0);
				newhigh = (INTBIG *)emalloc(newtotal * SIZEOFINTBIG, sim_tool->cluster);
				if (newhigh == 0) return(0);
				newtemp = (INTBIG *)emalloc(newtotal * SIZEOFINTBIG, sim_tool->cluster);
				if (newtemp == 0) return(0);
				for(j=0; j<newtotal; j++) newnamelist[j] = 0;
				for(j=0; j<namelistcount; j++)
				{
					newnamelist[j] = sim_verilognamelist[j];
					newlow[j] = sim_verilognamelistlow[j];
					newhigh[j] = sim_verilognamelisthigh[j];
					newtemp[j] = sim_verilognamelisttempval[j];
				}
				if (sim_verilognamelisttotal > 0)
				{
					efree((char *)sim_verilognamelist);
					efree((char *)sim_verilognamelistlow);
					efree((char *)sim_verilognamelisthigh);
					efree((char *)sim_verilognamelisttempval);
				}
				sim_verilognamelist = newnamelist;
				sim_verilognamelistlow = newlow;
				sim_verilognamelisthigh = newhigh;
				sim_verilognamelisttempval = newtemp;
				sim_verilognamelisttotal = newtotal;
			}

			/* add this name to the list */
			if (net->globalnet > 1 && net->globalnet < net->parent->globalnetcount)
			{
				name = net->parent->globalnetnames[net->globalnet];
			} else
			{
				if (net->namecount == 0) name = describenetwork(net); else
					name = net->netname;
			}

			pt = sim_verstartofindex(name);
			save = *pt;
			*pt = 0;
			if (sim_verilognamelist[namelistcount] != 0)
				efree(sim_verilognamelist[namelistcount]);
			(void)allocstring(&sim_verilognamelist[namelistcount],
				sim_verconvertname(name), sim_tool->cluster);
			sim_verilognamelisttempval[namelistcount] = net->temp1;
			if (save == 0)
			{
				/* single wire: set range to show that */
				sim_verilognamelistlow[namelistcount] = 1;
				sim_verilognamelisthigh[namelistcount] = 0;
			} else
			{
				sim_verilognamelistlow[namelistcount] =
					sim_verilognamelisthigh[namelistcount] = myatoi(pt+1);
				for(j=i+1; j<wirecount; j++)
				{
					endnet = sim_verilogwirelist[j].net;
					if (endnet == NONETWORK) break;
					if (endnet->temp1 != net->temp1) break;
					if (sim_verilogwirelist[j].pp != sim_verilogwirelist[i].pp) break;
					if (endnet->globalnet != net->globalnet) break;
					if (endnet->namecount == 0) break;
					ept = sim_verstartofindex(endnet->netname);
					if (*ept != '[') break;
					*ept = 0;
					comp = namesame(name, endnet->netname);
					*ept = '[';
					if (comp != 0) break;
					index = myatoi(ept+1);

					/* make sure export indices go in order */
					if (index != sim_verilognamelisthigh[namelistcount]+1)
						break;
					if (index > sim_verilognamelisthigh[namelistcount])
						sim_verilognamelisthigh[namelistcount] = index;
					i = j;
				}
			}
			*pt = save;
			namelistcount++;
		}
	}

	/* make sure all names are unique */
	for(i=1; i<namelistcount; i++)
	{
		for(j=0; j<i; j++)
			if (namesame(sim_verilognamelist[i], sim_verilognamelist[j]) == 0) break;
		if (j < i)
		{
			/* name the same: rename */
			for(k=1; k<1000; k++)
			{
				infstr = initinfstr();
				formatinfstr(infstr, "%s_%ld", sim_verilognamelist[i], k);
				pt = returninfstr(infstr);
				for(j=0; j<namelistcount; j++)
					if (namesame(pt, sim_verilognamelist[j]) == 0) break;
				if (j >= namelistcount) break;
			}
			(void)reallocstring(&sim_verilognamelist[i], pt, sim_tool->cluster);
		}
	}

	*namelist = sim_verilognamelist;
	*lowindex = sim_verilognamelistlow;
	*highindex = sim_verilognamelisthigh;
	*tempval = sim_verilognamelisttempval;
	*wirelist = sim_verilogwirelist;
	*netcount = wirecount;
	return(namelistcount);
}

/*
 * Helper routine for "esort" that makes networks with names go in ascending name order.
 */
int sim_versortwirelistsbyname(const void *e1, const void *e2)
{
	REGISTER WIRELIST *w1, *w2;
	REGISTER NETWORK *net1, *net2;
	REGISTER char *pt1, *pt2;
	char empty[1];

	w1 = (WIRELIST *)e1;
	w2 = (WIRELIST *)e2;
	net1 = w1->net;
	net2 = w2->net;
	if (net1->temp1 != net2->temp1) return(net1->temp1 - net2->temp1);
	empty[0] = 0;
	if (net1->globalnet > 1 && net1->globalnet < net1->parent->globalnetcount)
	{
		pt1 = net1->parent->globalnetnames[net1->globalnet];
	} else
	{
		if (net1->namecount == 0) pt1 = empty; else pt1 = net1->netname;
	}
	if (net2->globalnet > 1 && net2->globalnet < net2->parent->globalnetcount)
	{
		pt2 = net2->parent->globalnetnames[net2->globalnet];
	} else
	{
		if (net2->namecount == 0) pt2 = empty; else pt2 = net2->netname;
	}
	return(namesamenumeric(pt1, pt2));
}

/*
 * Routine to return the network connected to node "ni", port "pp".
 */
NETWORK *sim_vergetnetonport(NODEINST *ni, PORTPROTO *pp)
{
	REGISTER PORTARCINST *pi;
	REGISTER PORTEXPINST *pe;

	for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
		if (pi->proto == pp) return(pi->conarcinst->network);
	for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
		if (pe->proto == pp) return(pe->exportproto->network);
	return(NONETWORK);
}

/*
 * Routine to recursively examine facets and gather global network names.
 */
void sim_vergatherglobals(NODEPROTO *np)
{
	REGISTER INTBIG i, newtotal, globalnet, *newchars;
	NETWORK *net;
	REGISTER char *gname, **newlist;
	REGISTER NODEPROTO *onp, *cnp;
	REGISTER NODEINST *ni;
	REGISTER PORTARCINST *pi;

	if (np->temp1 != 0) return;
	np->temp1 = 1;

	/* mark all exported nets */
	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
	{
		if (ni->proto != sch_globalprim) continue;
		pi = ni->firstportarcinst;
		if (pi == NOPORTARCINST) continue;
		net = pi->conarcinst->network;
		if (net == NONETWORK) continue;	
		globalnet = net->globalnet;
		if (globalnet < 2) continue;

		/* global net found: see if it is already in the list */
		gname = sim_verconvertname(np->globalnetnames[globalnet]);
		for(i=0; i<sim_verilogglobalnetcount; i++)
			if (namesame(gname, sim_verilogglobalnets[i]) == 0) break;
		if (i < sim_verilogglobalnetcount) continue;

		/* add the global net name */
		if (sim_verilogglobalnetcount >= sim_verilogglobalnettotal)
		{
			newtotal = sim_verilogglobalnettotal * 2;
			if (sim_verilogglobalnetcount >= newtotal)
				newtotal = sim_verilogglobalnetcount + 5;
			newlist = (char **)emalloc(newtotal * (sizeof (char *)), sim_tool->cluster);
			if (newlist == 0) return;
			newchars = (INTBIG *)emalloc(newtotal * SIZEOFINTBIG, sim_tool->cluster);
			if (newchars == 0) return;
			for(i=0; i<sim_verilogglobalnettotal; i++)
			{
				newlist[i] = sim_verilogglobalnets[i];
				newchars[i] = sim_verilogglobalchars[i];
			}
			for(i=sim_verilogglobalnettotal; i<newtotal; i++)
				newlist[i] = 0;
			if (sim_verilogglobalnettotal > 0)
			{
				efree((char *)sim_verilogglobalnets);
				efree((char *)sim_verilogglobalchars);
			}
			sim_verilogglobalnets = newlist;
			sim_verilogglobalchars = newchars;
			sim_verilogglobalnettotal = newtotal;
		}
		if (sim_verilogglobalnets[sim_verilogglobalnetcount] != 0)
			efree((char *)sim_verilogglobalnets[sim_verilogglobalnetcount]);
		(void)allocstring(&sim_verilogglobalnets[sim_verilogglobalnetcount], gname,
			sim_tool->cluster);

		/* should figure out the characteristics of this global!!! */
		sim_verilogglobalchars[sim_verilogglobalnetcount] =
			((ni->userbits&NTECHBITS) >> NTECHBITSSH) << STATEBITSSH;
		sim_verilogglobalnetcount++;
	}

	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
	{
		onp = ni->proto;
		if (onp->primindex != 0) continue;

		/* ignore recursive references (showing icon in contents) */
		if (onp->cell == np->cell) continue;

		if (onp->cellview == el_iconview)
		{
			cnp = contentsview(onp);
			if (cnp != NONODEPROTO) onp = cnp;
		}

		sim_vergatherglobals(onp);
	}
}

#endif  /* SIMTOOL - at top */
