1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: simverilog.c
6  * Generator for Verilog simulator
7  * Written by: Steven M. Rubin
8  *
9  * Copyright (c) 2000 Static Free Software.
10  *
11  * Electric(tm) is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * Electric(tm) is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with Electric(tm); see the file COPYING.  If not, write to
23  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24  * Boston, Mass 02111-1307, USA.
25  *
26  * Static Free Software
27  * 4119 Alpine Road
28  * Portola Valley, California 94028
29  * info@staticfreesoft.com
30  */
31 
32 #include "config.h"
33 #if SIMTOOL
34 
35 #include "global.h"
36 #include "efunction.h"
37 #include "sim.h"
38 #include "network.h"
39 #include "usr.h"
40 #include "tecgen.h"
41 #include "tecschem.h"
42 #include "edialogs.h"
43 
44 #define IMPLICITINVERTERNODENAME x_("Imp")			/* name of inverters generated from negated wires */
45 #define IMPLICITINVERTERSIGNAME  x_("ImpInv")		/* name of signals generated from negated wires */
46 #define MAXDECLARATIONWIDTH      80					/* maximum size of output line */
47 
48        INTBIG      sim_verilog_statekey;			/* key for "SIM_verilog_state" */
49 static INTBIG      sim_verstate;
50 static FILE       *sim_verfile;
51 static INTBIG      sim_verilogcodekey = 0;
52 static INTBIG      sim_verilogdeclarationkey = 0;
53 static INTBIG      sim_verilogwiretypekey = 0;
54 static INTBIG      sim_verilogtemplatekey = 0;		/* key for "ATTR_verilog_template" */
55 static CHAR        sim_verdeclarationline[MAXDECLARATIONWIDTH];
56 static INTBIG      sim_verdeclarationprefix;
57 static CHAR      **sim_verilognamelist;
58 static INTBIG      sim_verilognamelisttotal = 0;
59 static INTBIG     *sim_verilognamelistlow;
60 static INTBIG     *sim_verilognamelisthigh;
61 static INTBIG     *sim_verilognamelisttempval;
62 static INTBIG      sim_verilogglobalnetcount;		/* number of global nets */
63 static INTBIG      sim_verilogglobalnettotal = 0;	/* size of global net array */
64 static CHAR      **sim_verilogglobalnets;			/* global net names */
65 static UINTBIG    *sim_verilogglobalchars;			/* global net characteristics */
66 
67 typedef struct
68 {
69 	NETWORK   *net;
70 	PORTPROTO *pp;
71 } WIRELIST;
72 
73 static WIRELIST   *sim_verilogwirelist;
74 static INTBIG      sim_verilogwirelisttotal = 0;
75 
76 /* verilog signal plotting */
77 #define VERSIGNALSHOWN     1
78 #define DEFIRSIMTIMERANGE  10.0E-9f			/* initial size of simulation window: 10ns */
79 
80 #define NOVERSIGNAL ((VERSIGNAL *)-1)
81 
82 typedef struct Iversignal
83 {
84 	CHAR               *symbol;
85 	CHAR               *signalname;
86 	CHAR               *signalcontext;
87 	INTBIG              signal;			/* waveform window trace pointer */
88 	INTBIG              flags;
89 	INTBIG              level;
90 	INTBIG              width;			/* bus width */
91 	struct Iversignal **signals;		/* signals in the bus */
92 	INTBIG              count;			/* number of stimuli on this signal */
93 	INTBIG              total;			/* size of allocated array of stimuli on this signal */
94 	double             *stimtime;		/* array of time values for stimuli on this signal */
95 	INTSML             *stimstate;		/* state of signal for each stimuli */
96 	struct Iversignal  *realversignal;	/* repeat signals point to the main entry */
97 	struct Iversignal  *nextversignal;
98 } VERSIGNAL;
99 
100 static VERSIGNAL  *sim_verfirstsignal = NOVERSIGNAL;
101 static INTBIG      sim_verlineno;
102 static CHAR        sim_verline[300];
103 static CHAR        sim_vercurscope[1000];
104 static FILE       *sim_verfd;
105 static INTBIG      sim_vercurlevel;
106 static INTBIG      sim_verfilesize;
107 static void       *sim_verprogressdialog;		/* for showing input progress */
108 static INTBIG      sim_numcharsused;			/* number of characters used in signal symbols */
109 static INTBIG      sim_charused[256];			/* which characters are used in signal symbols */
110 static double      sim_timescale;				/* scale of Verilog time to real time (in secs) */
111 static INTBIG      sim_verignoresigname;		/* number of levels of verilog name to ignore */
112 static VERSIGNAL  *sim_verwindow_iter;
113 static VERSIGNAL  *sim_verwindow_lastiter;
114 
115 
116 /* prototypes for local routines */
117 static BOOLEAN  sim_verwritecell(NODEPROTO*, CHAR*);
118 static CHAR    *sim_verconvertname(CHAR *p);
119 static BOOLEAN  sim_verincludetypedcode(NODEPROTO*, INTBIG, CHAR*);
120 static void     sim_verinitdeclaration(CHAR *header);
121 static void     sim_veradddeclaration(CHAR *signame);
122 static void     sim_vertermdeclaration(void);
123 static INTBIG   sim_vergetnetworks(NODEPROTO *cell, CHAR ***namelist, INTBIG **lowindex,
124 					INTBIG **highindex, INTBIG **tempval, WIRELIST **wirelist, INTBIG *netcount,
125 					NETWORK **pwrnet, NETWORK **gndnet, INTBIG quiet);
126 static void     sim_verwritelongline(CHAR *s);
127 static int      sim_versortwirelistsbyname(const void *e1, const void *e2);
128 static CHAR    *sim_vernamenoindices(CHAR *p);
129 static CHAR    *sim_verstartofindex(CHAR *name);
130 static void     sim_vergatherglobals(NODEPROTO *np);
131 static NETWORK *sim_vergetnetonport(NODEINST *ni, PORTPROTO *pp);
132 static void     sim_verwritebus(NETWORK **outernetlist, INTBIG lowindex, INTBIG highindex, INTBIG tempval,
133 					INTBIG *unconnectednet, CHAR *name, NETWORK *pwrnet, NETWORK *gndnet, void *infstr);
134 static CHAR    *sim_vercellname(NODEPROTO *np);
135 static BOOLEAN  sim_vercharhandlerwave(WINDOWPART *w, INTSML chr, INTBIG special);
136 static BOOLEAN  sim_vertopofsignals(CHAR **c);
137 static CHAR    *sim_vernextsignals(void);
138 static void     sim_verhelpwindow(void);
139 static void     sim_verparsetoend(CHAR **pt);
140 static void     sim_vershowcurrentlevel(NODEPROTO *cell);
141 static int      sim_versortsignalnames(const void *e1, const void *e2);
142 static INTBIG   sim_vergetsignalhash(CHAR *name);
143 static void     sim_verfreesimdata(void);
144 static void     sim_versetvalue(VERSIGNAL *vs, double curtime, INTSML state);
145 static void     sim_veraddsignals(void);
146 
147 /*
148  * Routine to free all memory associated with this module.
149  */
sim_freeverilogmemory(void)150 void sim_freeverilogmemory(void)
151 {
152 	REGISTER INTBIG i;
153 
154 	if (sim_verilognamelisttotal > 0)
155 	{
156 		for(i=0; i<sim_verilognamelisttotal; i++)
157 			efree(sim_verilognamelist[i]);
158 		efree((CHAR *)sim_verilognamelist);
159 		efree((CHAR *)sim_verilognamelistlow);
160 		efree((CHAR *)sim_verilognamelisthigh);
161 		efree((CHAR *)sim_verilognamelisttempval);
162 	}
163 	if (sim_verilogwirelisttotal > 0)
164 		efree((CHAR *)sim_verilogwirelist);
165 
166 	for(i=0; i<sim_verilogglobalnettotal; i++)
167 		if (sim_verilogglobalnets[i] != 0)
168 			efree((CHAR *)sim_verilogglobalnets[i]);
169 	if (sim_verilogglobalnettotal > 0)
170 	{
171 		efree((CHAR *)sim_verilogglobalnets);
172 		efree((CHAR *)sim_verilogglobalchars);
173 	}
174 	sim_verfreesimdata();
175 }
176 
177 /*
178  * routine to write a ".v" file from the cell "np"
179  */
sim_writevernetlist(NODEPROTO * np)180 void sim_writevernetlist(NODEPROTO *np)
181 {
182 	CHAR name[100], numberstring[100], *truename, *respar[2];
183 	REGISTER NODEPROTO *lnp, *onp, *tnp;
184 	REGISTER LIBRARY *lib, *olib;
185 	REGISTER INTBIG i;
186 	REGISTER VARIABLE *var;
187 
188 	/* make sure network tool is on */
189 	if ((net_tool->toolstate&TOOLON) == 0)
190 	{
191 		ttyputerr(_("Network tool must be running...turning it on"));
192 		toolturnon(net_tool);
193 		ttyputerr(_("...now reissue the simulation command"));
194 		return;
195 	}
196 	if (sim_verilogcodekey == 0)
197 		sim_verilogcodekey = makekey(x_("VERILOG_code"));
198 	if (sim_verilogdeclarationkey == 0)
199 		sim_verilogdeclarationkey = makekey(x_("VERILOG_declaration"));
200 	if (sim_verilogwiretypekey == 0)
201 		sim_verilogwiretypekey = makekey(x_("SIM_verilog_wire_type"));
202 	if (sim_verilogtemplatekey == 0)
203 		sim_verilogtemplatekey = makekey(x_("ATTR_verilog_template"));
204 
205 	var = getvalkey((INTBIG)sim_tool, VTOOL, VINTEGER, sim_verilog_statekey);
206 	if (var == NOVARIABLE) sim_verstate = 0; else
207 		sim_verstate = var->addr;
208 
209 	/* first write the "ver" file */
210 	(void)estrcpy(name, np->protoname);
211 	(void)estrcat(name, x_(".v"));
212 	sim_verfile = xcreate(name, sim_filetypeverilog, _("VERILOG File"), &truename);
213 	if (sim_verfile == NULL)
214 	{
215 		if (truename != 0) ttyputerr(_("Cannot write %s"), truename);
216 		return;
217 	}
218 
219 	/* see if there are any resistors in this circuit */
220 	if (hasresistors(np))
221 	{
222 		/* has resistors: make sure they are being ignored */
223 		if (asktech(sch_tech, x_("ignoring-resistor-topology")) == 0)
224 		{
225 			/* must redo network topology to ignore resistors */
226 			respar[0] = x_("resistors");
227 			respar[1] = x_("ignore");
228 			(void)telltool(net_tool, 2, respar);
229 		}
230 	}
231 
232 	/* write header information */
233 	xprintf(sim_verfile, x_("/* Verilog for cell %s from Library %s */\n"),
234 		describenodeproto(np), np->lib->libname);
235 	us_emitcopyright(sim_verfile, x_("/* "), x_(" */"));
236 	if ((us_useroptions&NODATEORVERSION) == 0)
237 	{
238 		if (np->creationdate)
239 			xprintf(sim_verfile, x_("/* Created on %s */\n"),
240 				timetostring((time_t)np->creationdate));
241 		if (np->revisiondate)
242 			xprintf(sim_verfile, x_("/* Last revised on %s */\n"),
243 				timetostring((time_t)np->revisiondate));
244 		(void)esnprintf(numberstring, 100, x_("%s"), timetostring(getcurrenttime()));
245 		xprintf(sim_verfile, x_("/* Written on %s by Electric VLSI Design System, version %s */\n"),
246 			numberstring, el_version);
247 	} else
248 	{
249 		xprintf(sim_verfile, x_("/* Written by Electric VLSI Design System */\n"));
250 	}
251 
252 	/*
253 	 * determine whether any cells have name clashes in other libraries
254 	 */
255 	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
256 		for(tnp = lib->firstnodeproto; tnp != NONODEPROTO; tnp = tnp->nextnodeproto)
257 			tnp->temp2 = 0;
258 	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
259 	{
260 		if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
261 		for(tnp = lib->firstnodeproto; tnp != NONODEPROTO; tnp = tnp->nextnodeproto)
262 		{
263 			for(olib = lib->nextlibrary; olib != NOLIBRARY; olib = olib->nextlibrary)
264 			{
265 				if ((olib->userbits&HIDDENLIBRARY) != 0) continue;
266 				for(onp = olib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
267 					if (namesame(tnp->protoname, onp->protoname) == 0) break;
268 				if (onp != NONODEPROTO) {
269 					tnp->temp2 = onp->temp2 = 1;
270 				}
271 			}
272 		}
273 	}
274 
275 	/* gather all global signal names */
276 	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
277 		for(onp = lib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
278 			onp->temp1 = 0;
279 	sim_verilogglobalnetcount = 0;
280 	sim_vergatherglobals(np);
281 	if (sim_verilogglobalnetcount > 0)
282 	{
283 		xprintf(sim_verfile, x_("\nmodule glbl();\n"));
284 		for(i=0; i<sim_verilogglobalnetcount; i++)
285 		{
286 			if (sim_verilogglobalchars[i] == PWRPORT)
287 			{
288 				xprintf(sim_verfile, x_("    supply1 %s;\n"),
289 					sim_verilogglobalnets[i]);
290 			} else if (sim_verilogglobalchars[i] == GNDPORT)
291 			{
292 				xprintf(sim_verfile, x_("    supply0 %s;\n"),
293 					sim_verilogglobalnets[i]);
294 			} else if ((sim_verstate&VERILOGUSETRIREG) != 0)
295 			{
296 				xprintf(sim_verfile, x_("    trireg %s;\n"),
297 					sim_verilogglobalnets[i]);
298 			} else
299 			{
300 				xprintf(sim_verfile, x_("    wire %s;\n"),
301 					sim_verilogglobalnets[i]);
302 			}
303 		}
304 		xprintf(sim_verfile, x_("endmodule\n"));
305 	}
306 
307 	/* reset flags for cells that have been written */
308 	for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
309 		for(lnp = lib->firstnodeproto; lnp != NONODEPROTO; lnp = lnp->nextnodeproto)
310 			lnp->temp1 = 0;
311 	begintraversehierarchy();
312 	initparameterizedcells();
313 	if (sim_verwritecell(np, 0))
314 		ttyputmsg(_("Back-annotation information has been added (library must be saved)"));
315 	endtraversehierarchy();
316 
317 	/* clean up */
318 	xclose(sim_verfile);
319 	ttyputmsg(_("%s written"), truename);
320 }
321 
322 /*
323  * recursively called routine to print the Verilog description of cell "np".
324  */
sim_verwritecell(NODEPROTO * np,CHAR * paramname)325 BOOLEAN sim_verwritecell(NODEPROTO *np, CHAR *paramname)
326 {
327 	REGISTER INTBIG i, j, k, l, nodetype, implicitports, total, localwires, nindex, wt,
328 		impinv, nodewidth, isnegated, namecount, sigcount, wholenegated, dropbias,
329 		low, high, addednames;
330 	REGISTER BOOLEAN backannotate, first, dumpcell;
331 	REGISTER NODEINST *ni;
332 	REGISTER ARCINST *ai;
333 	REGISTER PORTPROTO *pp, *lastpp, *opp, *cpp;
334 	REGISTER NODEPROTO *onp, *cnp, *nip, *nipc;
335 	REGISTER PORTARCINST *pi;
336 	REGISTER PORTEXPINST *pe;
337 	REGISTER NETWORK *net, *onet, *gnet, **outernetlist;
338 	NETWORK *pwrnet, *gndnet, *pwrnetdummy, *gndnetdummy;
339 	WIRELIST *wirelist;
340 	INTBIG *lowindex, *highindex, *tempval, netcount, unconnectednet;
341 	REGISTER VARIABLE *var, *vartemplate;
342 	CHAR **namelist, *porttype, *thisline, *signame, impsigname[100], *startpt, line[200],
343 		invsigname[100], *op, *pt, *opt, **ptr, *wiretype, save, osave, *pname, *modulename,
344 		**strings, **nodenames, *nodename, *gn, *dir, *cellname, *behavefile;
345 	REGISTER void *infstr;
346 
347 	/* stop if requested */
348 	if (el_pleasestop != 0)
349 	{
350 		(void)stopping(STOPREASONDECK);
351 		return(FALSE);
352 	}
353 	backannotate = FALSE;
354 
355 	/* use attached file if specified */
356 	var = getval((INTBIG)np, VNODEPROTO, VSTRING, x_("SIM_verilog_behave_file"));
357 	if (var != NOVARIABLE)
358 	{
359 		behavefile = (CHAR *)var->addr;
360 		if (*behavefile != 0)
361 		{
362 			xprintf(sim_verfile, x_("`include \"%s\"\n"), behavefile);
363 
364 			/* mark this cell as written */
365 			np->temp1++;
366 			return(backannotate);
367 		}
368 	}
369 
370 	/* use library behavior if it is available */
371 	onp = anyview(np, el_verilogview);
372 	if (onp != NONODEPROTO)
373 	{
374 		var = getvalkey((INTBIG)onp, VNODEPROTO, VSTRING|VISARRAY, el_cell_message_key);
375 		if (var != NOVARIABLE)
376 		{
377 			l = getlength(var);
378 			for(i=0; i<l; i++)
379 			{
380 				thisline = ((CHAR **)var->addr)[i];
381 				xprintf(sim_verfile, x_("%s\n"), thisline);
382 			}
383 		}
384 
385 		/* mark this cell as written */
386 		np->temp1++;
387 		return(backannotate);
388 	}
389 
390 	/* make sure that all nodes and networks have names on them */
391 	addednames = 0;
392 	if (asktool(net_tool, x_("name-nodes"), (INTBIG)np) != 0) addednames++;
393 	if (asktool(net_tool, x_("name-nets"), (INTBIG)np) != 0) addednames++;
394 	if (addednames != 0)
395 	{
396 		backannotate = TRUE;
397 		net_endbatch();
398 	}
399 
400 	/* write netlist for this cell, first recurse on sub-cells */
401 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
402 	{
403 		if (ni->proto->primindex != 0) continue;
404 
405 		/* ignore recursive references (showing icon in contents) */
406 		if (isiconof(ni->proto, np)) continue;
407 
408 		/* see if this cell has a template */
409 		var = getvalkey((INTBIG)ni->proto, VNODEPROTO, VSTRING, sim_verilogtemplatekey);
410 		if (var != NOVARIABLE) continue;
411 
412 		/* get actual subcell (including contents/body distinction) */
413 		/* NOTE: this gets the schematic before the layout */
414 		onp = contentsview(ni->proto);
415 		if (onp == NONODEPROTO) onp = ni->proto; else
416 		{
417 			/* see if this contents cell has a template */
418 			var = getvalkey((INTBIG)onp, VNODEPROTO, VSTRING, sim_verilogtemplatekey);
419 			if (var != NOVARIABLE) continue;
420 		}
421 		dumpcell = TRUE;
422 		if (onp->temp1 != 0) dumpcell = FALSE;
423 		cellname = sim_vercellname(ni->proto);
424 		pname = parameterizedname(ni, cellname);
425 		if (pname != 0)
426 		{
427 			/* do not force multiple writes if there is a behavioral file */
428 			var = getval((INTBIG)onp, VNODEPROTO, VSTRING, x_("SIM_verilog_behave_file"));
429 			if (var == NOVARIABLE)
430 			{
431 				if (inparameterizedcells(onp, pname) == 0)
432 				{
433 					dumpcell = TRUE;
434 					addtoparameterizedcells(onp, pname, 0);
435 				}
436 			}
437 		}
438 
439 		/* write the subcell */
440 		if (dumpcell)
441 		{
442 			downhierarchy(ni, onp, 0);
443 			if (sim_verwritecell(onp, pname)) backannotate = TRUE;
444 			uphierarchy();
445 		}
446 	}
447 
448 	/* mark this cell as written */
449 	np->temp1++;
450 
451 	/* prepare arcs to store implicit inverters */
452 	impinv = 1;
453 	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
454 		ai->temp1 = 0;
455 	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
456 	{
457 		if ((ai->userbits&ISNEGATED) == 0) continue;
458 		if ((ai->userbits&REVERSEEND) == 0)
459 		{
460 			ni = ai->end[0].nodeinst;
461 			pi = ai->end[0].portarcinst;
462 		} else
463 		{
464 			ni = ai->end[1].nodeinst;
465 			pi = ai->end[1].portarcinst;
466 		}
467 		if (ni->proto == sch_bufprim || ni->proto == sch_andprim ||
468 			ni->proto == sch_orprim || ni->proto == sch_xorprim)
469 		{
470 			if ((sim_verstate&VERILOGUSEASSIGN) != 0) continue;
471 			if (estrcmp(pi->proto->protoname, x_("y")) == 0) continue;
472 		}
473 
474 		/* must create implicit inverter here */
475 		ai->temp1 = impinv;
476 		if (ai->proto != sch_busarc) impinv++; else
477 		{
478 			net = ai->network;
479 			if (net == NONETWORK) impinv++; else
480 				impinv += net->buswidth;
481 		}
482 	}
483 
484 	/* gather networks in the cell */
485 	namecount = sim_vergetnetworks(np, &namelist, &lowindex, &highindex,
486 		&tempval, &wirelist, &netcount, &pwrnet, &gndnet, 0);
487 
488 	/* write the module header */
489 	xprintf(sim_verfile, x_("\n"));
490 	infstr = initinfstr();
491 	if (paramname == 0) modulename = sim_vercellname(np); else
492 		modulename = sim_verconvertname(paramname);
493 	formatinfstr(infstr, x_("module %s("), modulename);
494 	first = TRUE;
495 	for(i=0; i<namecount; i++)
496 	{
497 		if (tempval[i] <= 1 || tempval[i] >= 6) continue;
498 		if (!first) addstringtoinfstr(infstr, x_(", "));
499 		addstringtoinfstr(infstr, namelist[i]);
500 		first = FALSE;
501 	}
502 	addstringtoinfstr(infstr, x_(");"));
503 	sim_verwritelongline(returninfstr(infstr));
504 
505 	/* look for "wire/trireg" overrides */
506 	for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
507 		net->temp2 = 0;
508 	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
509 	{
510 		var = getvalkey((INTBIG)ai, VARCINST, VSTRING, sim_verilogwiretypekey);
511 		if (var == NOVARIABLE) continue;
512 		if (namesame((CHAR *)var->addr, x_("wire")) == 0) ai->network->temp2 = 1; else
513 			if (namesame((CHAR *)var->addr, x_("trireg")) == 0) ai->network->temp2 = 2;
514 	}
515 
516 	/* write description of formal parameters to module */
517 	first = TRUE;
518 	j = 0;
519 	for(i=0; i<namecount; i++)
520 	{
521 		if (tempval[i] > 1 && tempval[i] < 6)
522 		{
523 			switch (tempval[i])
524 			{
525 				case 2: case 3: porttype = x_("input");   break;
526 				case 4: case 5: porttype = x_("output");  break;
527 			}
528 			xprintf(sim_verfile, x_("  %s"), porttype);
529 			if (lowindex[i] > highindex[i])
530 			{
531 				xprintf(sim_verfile, x_(" %s;"), namelist[i]);
532 				if (wirelist[j].net->temp2 != 0)
533 				{
534 					if (wirelist[j].net->temp2 == 1) xprintf(sim_verfile, x_("  wire")); else
535 						xprintf(sim_verfile, x_("  trireg"));
536 					xprintf(sim_verfile, x_(" %s;"), namelist[i]);
537 				}
538 			} else
539 			{
540 				if ((tempval[i]&1) != 0)
541 				{
542 					low = highindex[i];   high = lowindex[i];
543 				} else
544 				{
545 					low = lowindex[i];   high = highindex[i];
546 				}
547 				xprintf(sim_verfile, x_(" [%ld:%ld] %s;"), low, high, namelist[i]);
548 				if (wirelist[j].net->temp2 != 0)
549 				{
550 					if (wirelist[j].net->temp2 == 1) xprintf(sim_verfile, x_("  wire")); else
551 						xprintf(sim_verfile, x_("  trireg"));
552 					xprintf(sim_verfile, x_(" [%ld:%ld] %s;"), low, high, namelist[i]);
553 				}
554 			}
555 			xprintf(sim_verfile, x_("\n"));
556 			first = FALSE;
557 		}
558 
559 		/* advance pointer to network information */
560 		if (lowindex[i] <= highindex[i]) j += highindex[i] - lowindex[i];
561 		j++;
562 	}
563 	if (!first) xprintf(sim_verfile, x_("\n"));
564 
565 	/* describe power and ground nets */
566 	if (pwrnet != NONETWORK) xprintf(sim_verfile, x_("  supply1 vdd;\n"));
567 	if (gndnet != NONETWORK) xprintf(sim_verfile, x_("  supply0 gnd;\n"));
568 
569 	/* determine whether to use "wire" or "trireg" for networks */
570 	if ((sim_verstate&VERILOGUSETRIREG) != 0) wiretype = x_("trireg"); else
571 		wiretype = x_("wire");
572 
573 	/* write "wire/trireg" declarations for internal single-wide signals */
574 	localwires = 0;
575 	for(wt=0; wt<2; wt++)
576 	{
577 		first = TRUE;
578 		j = 0;
579 		for(i=0; i<namecount; i++)
580 		{
581 			if (tempval[i] <= 1 && lowindex[i] > highindex[i])
582 			{
583 				if (wirelist[j].net->temp2 == 0) estrcpy(impsigname, wiretype); else
584 				{
585 					if (wirelist[j].net->temp2 == 1) estrcpy(impsigname, x_("wire")); else
586 						estrcpy(impsigname, x_("trireg"));
587 				}
588 				if ((wt == 0) ^ (namesame(wiretype, impsigname) == 0))
589 				{
590 					if (first)
591 					{
592 						esnprintf(invsigname, 100, x_("  %s"), impsigname);
593 						sim_verinitdeclaration(invsigname);
594 					}
595 					sim_veradddeclaration(namelist[i]);
596 					localwires++;
597 					first = FALSE;
598 				}
599 			}
600 
601 			/* advance pointer to network information */
602 			if (lowindex[i] <= highindex[i]) j += highindex[i] - lowindex[i];
603 			j++;
604 		}
605 		if (!first) sim_vertermdeclaration();
606 	}
607 
608 	/* write "wire/trireg" declarations for internal busses */
609 	for(i=0; i<namecount; i++)
610 	{
611 		if (tempval[i] > 1) continue;
612 		if (lowindex[i] > highindex[i]) continue;
613 
614 		if ((tempval[i]&1) != 0)
615 		{
616 			xprintf(sim_verfile, x_("  %s [%ld:%ld] %s;\n"), wiretype,
617 				highindex[i], lowindex[i], namelist[i]);
618 		} else
619 		{
620 			xprintf(sim_verfile, x_("  %s [%ld:%ld] %s;\n"), wiretype,
621 				lowindex[i], highindex[i], namelist[i]);
622 		}
623 		localwires++;
624 	}
625 	if (localwires != 0) xprintf(sim_verfile, x_("\n"));
626 
627 	/* add "wire" declarations for implicit inverters */
628 	if (impinv > 1)
629 	{
630 		esnprintf(invsigname, 100, x_("  %s"), wiretype);
631 		sim_verinitdeclaration(invsigname);
632 		for(i=1; i<impinv; i++)
633 		{
634 			esnprintf(impsigname, 100, x_("%s%ld"), IMPLICITINVERTERSIGNAME, i);
635 			sim_veradddeclaration(impsigname);
636 		}
637 		sim_vertermdeclaration();
638 	}
639 
640 	/* add in any user-specified declarations and code */
641 	first = sim_verincludetypedcode(np, sim_verilogdeclarationkey, x_("declarations"));
642 	first |= sim_verincludetypedcode(np, sim_verilogcodekey, x_("code"));
643 	if (!first)
644 		xprintf(sim_verfile, x_("  /* automatically generated Verilog */\n"));
645 
646 	/* load Verilog names onto the networks */
647 	for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
648 		net->temp2 = 0;
649 	j = 0;
650 	for(i=0; i<namecount; i++)
651 	{
652 		if (lowindex[i] > highindex[i])
653 		{
654 			net = wirelist[j++].net;
655 			ptr = (CHAR **)(&net->temp2);
656 			if (net->globalnet > 1 && net->globalnet < np->globalnetcount)
657 			{
658 				gn = sim_verconvertname(np->globalnetnames[net->globalnet]);
659 				*ptr = (CHAR *)emalloc((estrlen(gn)+7) * SIZEOFCHAR, sim_tool->cluster);
660 				estrcpy(*ptr, x_(" glbl."));
661 				estrcat(*ptr, gn);
662 			} else
663 			{
664 				*ptr = (CHAR *)emalloc((estrlen(namelist[i])+2) * SIZEOFCHAR, sim_tool->cluster);
665 				estrcpy(*ptr, x_(" "));
666 				estrcat(*ptr, namelist[i]);
667 			}
668 		} else
669 		{
670 			if ((tempval[i]&1) != 0) dir = x_("D"); else dir = x_("U");
671 			for(k=lowindex[i]; k<=highindex[i]; k++)
672 			{
673 				net = wirelist[j++].net;
674 				infstr = initinfstr();
675 				formatinfstr(infstr, x_("%s%s[%ld]"), dir, namelist[i], k);
676 				ptr = (CHAR **)(&net->temp2);
677 				(void)allocstring(ptr, returninfstr(infstr), sim_tool->cluster);
678 			}
679 		}
680 	}
681 
682 	/* look at every node in this cell */
683 	unconnectednet = 1;
684 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
685 	{
686 		/* not interested in passive nodes (ports electrically connected) */
687 		if (ni->proto->primindex != 0)
688 		{
689 			j = 0;
690 			lastpp = ni->proto->firstportproto;
691 			if (lastpp == NOPORTPROTO) continue;
692 			for(pp = lastpp->nextportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
693 				if (pp->network != lastpp->network) j++;
694 			if (j == 0) continue;
695 		}
696 
697 		nodewidth = ni->arraysize;
698 		if (nodewidth < 1) nodewidth = 1;
699 
700 		nodetype = nodefunction(ni);
701 
702 		/* special case: verilog should ignore R L C etc. */
703 		if (nodetype == NPRESIST || nodetype == NPCAPAC || nodetype == NPECAPAC ||
704 			nodetype == NPINDUCT || nodetype == NPDIODE || nodetype == NPDIODEZ) continue;
705 
706 		/* use "assign" statement if possible */
707 		if ((sim_verstate&VERILOGUSEASSIGN) != 0)
708 		{
709 			if (nodetype == NPGATEAND || nodetype == NPGATEOR ||
710 				nodetype == NPGATEXOR || nodetype == NPBUFFER)
711 			{
712 				/* assign possible: determine operator */
713 				switch (nodetype)
714 				{
715 					case NPGATEAND:  op = x_(" & ");   break;
716 					case NPGATEOR:   op = x_(" | ");   break;
717 					case NPGATEXOR:  op = x_(" ^ ");   break;
718 					case NPBUFFER:   op = x_("");      break;
719 				}
720 				for(nindex=0; nindex<nodewidth; nindex++)
721 				{
722 					/* write a line describing this signal */
723 					infstr = initinfstr();
724 					wholenegated = 0;
725 					first = TRUE;
726 					for(i=0; i<2; i++)
727 					{
728 						for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
729 						{
730 							if (i == 0)
731 							{
732 								if (estrcmp(pi->proto->protoname, x_("y")) != 0) continue;
733 							} else
734 							{
735 								if (estrcmp(pi->proto->protoname, x_("a")) != 0) continue;
736 							}
737 
738 							/* determine the network name at this port */
739 							net = pi->conarcinst->network;
740 							if (nodewidth > 1)
741 							{
742 								(void)net_evalbusname(
743 									(pi->conarcinst->proto->userbits&AFUNCTION)>>AFUNCTIONSH,
744 										networkname(net, 0), &strings, pi->conarcinst, np, 1);
745 								estrcpy(impsigname, strings[nindex]);
746 								signame = impsigname;
747 							} else
748 							{
749 								if (net != NONETWORK && net->namecount > 0)
750 									signame = networkname(net, 0); else
751 										signame = describenetwork(net);
752 								if (net == pwrnet) signame = x_("vdd"); else
753 									if (net == gndnet) signame = x_("gnd");
754 							}
755 
756 							/* see if this end is negated */
757 							isnegated = 0;
758 							ai = pi->conarcinst;
759 							if ((ai->userbits&ISNEGATED) != 0)
760 							{
761 								if ((ai->end[0].nodeinst == ni && (ai->userbits&REVERSEEND) == 0) ||
762 									(ai->end[1].nodeinst == ni && (ai->userbits&REVERSEEND) != 0))
763 								{
764 									isnegated = 1;
765 								}
766 							}
767 
768 							/* write the port name */
769 							if (i == 0)
770 							{
771 								/* got the output port: do the left-side of the "assign" */
772 								addstringtoinfstr(infstr, x_("assign "));
773 								addstringtoinfstr(infstr, signame);
774 								addstringtoinfstr(infstr, x_(" = "));
775 								if (isnegated != 0)
776 								{
777 									addstringtoinfstr(infstr, x_("~("));
778 									wholenegated = 1;
779 								}
780 								break;
781 							} else
782 							{
783 								if (!first)
784 									addstringtoinfstr(infstr, op);
785 								first = FALSE;
786 								if (isnegated != 0) addstringtoinfstr(infstr, x_("~"));
787 								addstringtoinfstr(infstr, signame);
788 							}
789 						}
790 					}
791 					if (wholenegated != 0)
792 						addstringtoinfstr(infstr, x_(")"));
793 					addstringtoinfstr(infstr, x_(";"));
794 					sim_verwritelongline(returninfstr(infstr));
795 				}
796 				continue;
797 			}
798 		}
799 
800 		/* get the name of the node */
801 		implicitports = 0;
802 		dropbias = 0;
803 		if (ni->proto->primindex == 0)
804 		{
805 			/* ignore recursive references (showing icon in contents) */
806 			if (isiconof(ni->proto, np)) continue;
807 			cellname = sim_vercellname(ni->proto);
808 			pname = parameterizedname(ni, cellname);
809 			if (pname == 0) pname = cellname; else
810 				pname = sim_verconvertname(pname);
811 			(void)allocstring(&nodename, pname, sim_tool->cluster);
812 		} else
813 		{
814 			pt = ni->proto->protoname;
815 
816 			/* convert 4-port transistors to 3-port */
817 			switch (nodetype)
818 			{
819 				case NPTRA4NMOS: nodetype = NPTRANMOS;  dropbias = 1;   break;
820 				case NPTRA4PMOS: nodetype = NPTRAPMOS;  dropbias = 1;   break;
821 			}
822 			switch (nodetype)
823 			{
824 				case NPTRANMOS:
825 					implicitports = 2;
826 					pt = x_("tranif1");
827 					var = getvalkey((INTBIG)ni, VNODEINST, -1, sim_weaknodekey);
828 					if (var != NOVARIABLE) pt = x_("rtranif1");
829 					break;
830 				case NPTRAPMOS:
831 					implicitports = 2;
832 					pt = x_("tranif0");
833 					var = getvalkey((INTBIG)ni, VNODEINST, -1, sim_weaknodekey);
834 					if (var != NOVARIABLE) pt = x_("rtranif0");
835 					break;
836 				case NPGATEAND:
837 					implicitports = 1;
838 					pt = x_("and");
839 					for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
840 						if (estrcmp(pi->proto->protoname, x_("y")) == 0) break;
841 					if (pi != NOPORTARCINST && (pi->conarcinst->userbits&ISNEGATED) != 0)
842 						pt = x_("nand");
843 					break;
844 				case NPGATEOR:
845 					implicitports = 1;
846 					pt = x_("or");
847 					for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
848 						if (estrcmp(pi->proto->protoname, x_("y")) == 0) break;
849 					if (pi != NOPORTARCINST && (pi->conarcinst->userbits&ISNEGATED) != 0)
850 						pt = x_("nor");
851 					break;
852 				case NPGATEXOR:
853 					implicitports = 1;
854 					pt = x_("xor");
855 					for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
856 						if (estrcmp(pi->proto->protoname, x_("y")) == 0) break;
857 					if (pi != NOPORTARCINST && (pi->conarcinst->userbits&ISNEGATED) != 0)
858 						pt = x_("xnor");
859 					break;
860 				case NPBUFFER:
861 					implicitports = 1;
862 					pt = x_("buf");
863 					for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
864 						if (estrcmp(pi->proto->protoname, x_("y")) == 0) break;
865 					if (pi != NOPORTARCINST && (pi->conarcinst->userbits&ISNEGATED) != 0)
866 						pt = x_("not");
867 					break;
868 			}
869 			(void)allocstring(&nodename, pt, sim_tool->cluster);
870 		}
871 
872 		if (nodewidth > 1)
873 		{
874 			var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
875 			if (var == NOVARIABLE) nodewidth = 1; else
876 			{
877 				sigcount = net_evalbusname(APBUS, (CHAR *)var->addr, &nodenames,
878 					NOARCINST, NONODEPROTO, 0);
879 				if (sigcount != nodewidth) nodewidth = 1;
880 			}
881 		}
882 
883 		/* write the node (may be arrayed) */
884 		for(nindex=0; nindex<nodewidth; nindex++)
885 		{
886 			/* look for a Verilog template on the prototype */
887 			vartemplate = getvalkey((INTBIG)ni->proto, VNODEPROTO, VSTRING, sim_verilogtemplatekey);
888 			if (vartemplate == NOVARIABLE)
889 			{
890 				cnp = contentsview(ni->proto);
891 				if (cnp != NONODEPROTO)
892 					vartemplate = getvalkey((INTBIG)cnp, VNODEPROTO, VSTRING, sim_verilogtemplatekey);
893 			}
894 
895 			if (vartemplate == NOVARIABLE)
896 			{
897 				/* write the type of the node */
898 				infstr = initinfstr();
899 				addstringtoinfstr(infstr, x_("  "));
900 				addstringtoinfstr(infstr, nodename);
901 
902 				/* write the name of the node */
903 				if (nodewidth > 1)
904 				{
905 					addstringtoinfstr(infstr, x_(" "));
906 					addstringtoinfstr(infstr, sim_vernamenoindices(nodenames[nindex]));
907 				} else
908 				{
909 					var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
910 					if (var != NOVARIABLE)
911 					{
912 						addstringtoinfstr(infstr, x_(" "));
913 						addstringtoinfstr(infstr, sim_vernamenoindices((CHAR *)var->addr));
914 					}
915 				}
916 				addstringtoinfstr(infstr, x_("("));
917 			}
918 
919 			/* write the rest of the ports */
920 			first = TRUE;
921 			switch (implicitports)
922 			{
923 				case 0:		/* explicit ports */
924 					cnp = contentsview(ni->proto);
925 					if (cnp == NONODEPROTO) cnp = ni->proto;
926 					for(net = cnp->firstnetwork; net != NONETWORK; net = net->nextnetwork)
927 						net->temp2 = (INTBIG)NONETWORK;
928 					cpp = NOPORTPROTO;
929 					for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
930 					{
931 						cpp = equivalentport(ni->proto, pp, cnp);
932 						if (cpp == NOPORTPROTO) continue;
933 						net = sim_vergetnetonport(ni, pp);
934 						if (net != NONETWORK && net->buswidth > 1)
935 						{
936 							sigcount = net->buswidth;
937 							if (nodewidth > 1 && cpp->network->buswidth * nodewidth == net->buswidth)
938 							{
939 								/* map wide bus to a particular instantiation of an arrayed node */
940 								if (cpp->network->buswidth == 1)
941 								{
942 									onet = (NETWORK *)cpp->network->temp2;
943 									if (onet == NONETWORK)
944 										cpp->network->temp2 = (INTBIG)net->networklist[nindex];
945 								} else
946 								{
947 									for(i=0; i<cpp->network->buswidth; i++)
948 									{
949 										onet = (NETWORK *)cpp->network->networklist[i]->temp2;
950 										if (onet == NONETWORK)
951 											cpp->network->networklist[i]->temp2 =
952 												(INTBIG)net->networklist[i + nindex*cpp->network->buswidth];
953 									}
954 								}
955 							} else
956 							{
957 								if (cpp->network->buswidth != net->buswidth)
958 								{
959 									ttyputerr(_("***ERROR: port %s on node %s in cell %s is %d wide, but is connected/exported with width %d"),
960 										pp->protoname, describenodeinst(ni), describenodeproto(np),
961 											cpp->network->buswidth, net->buswidth);
962 									sigcount = mini(sigcount, cpp->network->buswidth);
963 									if (sigcount == 1) sigcount = 0;
964 								}
965 								onet = (NETWORK *)cpp->network->temp2;
966 								if (onet == NONETWORK) cpp->network->temp2 = (INTBIG)net;
967 								for(i=0; i<sigcount; i++)
968 								{
969 									onet = (NETWORK *)cpp->network->networklist[i]->temp2;
970 									if (onet == NONETWORK)
971 										cpp->network->networklist[i]->temp2 = (INTBIG)net->networklist[i];
972 								}
973 							}
974 						} else
975 						{
976 							onet = (NETWORK *)cpp->network->temp2;
977 							if (onet == NONETWORK) cpp->network->temp2 = (INTBIG)net;
978 						}
979 					}
980 
981 					/* special case for Verilog templates */
982 					if (vartemplate != NOVARIABLE)
983 					{
984 						infstr = initinfstr();
985 						addstringtoinfstr(infstr, x_("  "));
986 						for(pt = (CHAR *)vartemplate->addr; *pt != 0; pt++)
987 						{
988 							if (pt[0] != '$' || pt[1] != '(')
989 							{
990 								addtoinfstr(infstr, *pt);
991 								continue;
992 							}
993 							startpt = pt + 2;
994 							for(pt = startpt; *pt != 0; pt++)
995 								if (*pt == ')') break;
996 							save = *pt;
997 							*pt = 0;
998 							pp = getportproto(ni->proto, startpt);
999 							if (pp != NOPORTPROTO)
1000 							{
1001 								/* port name found: use its verilog node */
1002 								net = sim_vergetnetonport(ni, pp);
1003 								if (net == NONETWORK)
1004 								{
1005 									formatinfstr(infstr, x_("UNCONNECTED%ld"), unconnectednet++);
1006 								} else
1007 								{
1008 									if (net->buswidth > 1)
1009 									{
1010 										sigcount = net->buswidth;
1011 										if (nodewidth > 1 && pp->network->buswidth * nodewidth == net->buswidth)
1012 										{
1013 											/* map wide bus to a particular instantiation of an arrayed node */
1014 											if (pp->network->buswidth == 1)
1015 											{
1016 												onet = net->networklist[nindex];
1017 												if (onet == pwrnet) addstringtoinfstr(infstr, x_("vdd")); else
1018 													if (onet == gndnet) addstringtoinfstr(infstr, x_("gnd")); else
1019 														addstringtoinfstr(infstr, &((CHAR *)onet->temp2)[1]);
1020 											} else
1021 											{
1022 												outernetlist = (NETWORK **)emalloc(pp->network->buswidth * (sizeof (NETWORK *)),
1023 													sim_tool->cluster);
1024 												for(j=0; j<pp->network->buswidth; j++)
1025 													outernetlist[j] = net->networklist[i + nindex*pp->network->buswidth];
1026 												for(opt = pp->protoname; *opt != 0; opt++)
1027 													if (*opt == '[') break;
1028 												osave = *opt;
1029 												*opt = 0;
1030 												sim_verwritebus(outernetlist, 0, net->buswidth-1, 0,
1031 													&unconnectednet, 0, pwrnet, gndnet, infstr);
1032 												*opt = osave;
1033 												efree((CHAR *)outernetlist);
1034 											}
1035 										} else
1036 										{
1037 											if (pp->network->buswidth != net->buswidth)
1038 											{
1039 												ttyputerr(_("***ERROR: port %s on node %s in cell %s is %d wide, but is connected/exported with width %d"),
1040 													pp->protoname, describenodeinst(ni), describenodeproto(np),
1041 														cpp->network->buswidth, net->buswidth);
1042 												sigcount = mini(sigcount, cpp->network->buswidth);
1043 												if (sigcount == 1) sigcount = 0;
1044 											}
1045 											outernetlist = (NETWORK **)emalloc(net->buswidth * (sizeof (NETWORK *)),
1046 												sim_tool->cluster);
1047 											for(j=0; j<net->buswidth; j++)
1048 												outernetlist[j] = net->networklist[j];
1049 											for(opt = pp->protoname; *opt != 0; opt++)
1050 												if (*opt == '[') break;
1051 											osave = *opt;
1052 											*opt = 0;
1053 											sim_verwritebus(outernetlist, 0, net->buswidth-1, 0,
1054 												&unconnectednet, 0, pwrnet, gndnet, infstr);
1055 											*opt = osave;
1056 											efree((CHAR *)outernetlist);
1057 										}
1058 									} else
1059 									{
1060 										if (net == pwrnet) addstringtoinfstr(infstr, x_("vdd")); else
1061 											if (net == gndnet) addstringtoinfstr(infstr, x_("gnd")); else
1062 												addstringtoinfstr(infstr, &((CHAR *)net->temp2)[1]);
1063 									}
1064 								}
1065 							} else if (namesame(startpt, x_("node_name")) == 0)
1066 							{
1067 								if (nodewidth > 1) opt = nodenames[nindex]; else
1068 								{
1069 									var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
1070 									if (var == NOVARIABLE) opt = x_(""); else
1071 										opt = (CHAR *)var->addr;
1072 								}
1073 								addstringtoinfstr(infstr, sim_vernamenoindices(opt));
1074 							} else
1075 							{
1076 								/* no port name found, look for variable name */
1077 								esnprintf(line, 200, x_("ATTR_%s"), startpt);
1078 								var = getval((INTBIG)ni, VNODEINST, -1, line);
1079 								if (var == NOVARIABLE)
1080 									var = getval((INTBIG)ni, VNODEINST, -1, startpt);
1081 								if (var == NOVARIABLE)
1082 								{
1083 									/* value not found: see if this is a parameter and use default */
1084 									nip = ni->proto;
1085 									nipc = contentsview(nip);
1086 									if (nipc != NONODEPROTO) nip = nipc;
1087 									var = getval((INTBIG)nip, VNODEPROTO, -1, line);
1088 								}
1089 								if (var == NOVARIABLE)
1090 									addstringtoinfstr(infstr, x_("??")); else
1091 								{
1092 									addstringtoinfstr(infstr, describesimplevariable(var));
1093 								}
1094 							}
1095 							*pt = save;
1096 							if (save == 0) break;
1097 						}
1098 						break;
1099 					}
1100 
1101 					/* generate the line the normal way */
1102 					namecount = sim_vergetnetworks(cnp, &namelist, &lowindex, &highindex,
1103 						&tempval, &wirelist, &netcount, &pwrnetdummy, &gndnetdummy, 1);
1104 					l = 0;
1105 					for(i=0; i<namecount; i++)
1106 					{
1107 						/* ignore networks that aren't exported */
1108 						if (tempval[i] <= 1 || tempval[i] >= 6)
1109 						{
1110 							l++;
1111 							if (lowindex[i] <= highindex[i])
1112 								l += highindex[i] - lowindex[i];
1113 							continue;
1114 						}
1115 						if (first) first = FALSE; else
1116 							addstringtoinfstr(infstr, x_(", "));
1117 						if (lowindex[i] > highindex[i])
1118 						{
1119 							/* single signal */
1120 							addstringtoinfstr(infstr, x_("."));
1121 							addstringtoinfstr(infstr, namelist[i]);
1122 							addstringtoinfstr(infstr, x_("("));
1123 							net = (NETWORK *)wirelist[l++].net->temp2;
1124 							if (net == NONETWORK || net->temp2 == 0)
1125 							{
1126 								formatinfstr(infstr, x_("UNCONNECTED%ld"), unconnectednet++);
1127 							} else
1128 							{
1129 								if (net == pwrnet) addstringtoinfstr(infstr, x_("vdd")); else
1130 									if (net == gndnet) addstringtoinfstr(infstr, x_("gnd")); else
1131 										addstringtoinfstr(infstr, &((CHAR *)net->temp2)[1]);
1132 							}
1133 							addstringtoinfstr(infstr, x_(")"));
1134 						} else
1135 						{
1136 							total = highindex[i]-lowindex[i]+1;
1137 							outernetlist = (NETWORK **)emalloc(total * (sizeof (NETWORK *)),
1138 								sim_tool->cluster);
1139 							for(j=lowindex[i]; j<=highindex[i]; j++)
1140 								outernetlist[j-lowindex[i]] = (NETWORK *)wirelist[j-lowindex[i]+l].net->temp2;
1141 
1142 							sim_verwritebus(outernetlist, lowindex[i], highindex[i], tempval[i],
1143 								&unconnectednet, namelist[i], pwrnet, gndnet, infstr);
1144 							l += highindex[i] - lowindex[i] + 1;
1145 							efree((CHAR *)outernetlist);
1146 						}
1147 					}
1148 					addstringtoinfstr(infstr, x_(");"));
1149 					break;
1150 
1151 				case 1:		/* and/or gate: write ports in the proper order */
1152 					for(i=0; i<2; i++)
1153 					{
1154 						for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1155 						{
1156 							if (i == 0)
1157 							{
1158 								if (estrcmp(pi->proto->protoname, x_("y")) != 0) continue;
1159 							} else
1160 							{
1161 								if (estrcmp(pi->proto->protoname, x_("a")) != 0) continue;
1162 							}
1163 							if (first) first = FALSE; else
1164 								addstringtoinfstr(infstr, x_(", "));
1165 							net = pi->conarcinst->network;
1166 							if (nodewidth > 1)
1167 							{
1168 								if (net->buswidth == nodewidth) net = net->networklist[nindex];
1169 							} else
1170 							{
1171 								if (net->buswidth > 1)
1172 								{
1173 									ttyputerr(_("***ERROR: cell %s, node %s is not arrayed but is connected to a bus"),
1174 										describenodeproto(np), describenodeinst(ni));
1175 									net = net->networklist[0];
1176 								}
1177 							}
1178 							signame = &((CHAR *)net->temp2)[1];
1179 							if (net == pwrnet) signame = x_("vdd"); else
1180 								if (net == gndnet) signame = x_("gnd");
1181 							if (i != 0 && pi->conarcinst->temp1 != 0)
1182 							{
1183 								/* this input is negated: write the implicit inverter */
1184 								esnprintf(invsigname, 100, x_("%s%ld"), IMPLICITINVERTERSIGNAME,
1185 									pi->conarcinst->temp1+nindex);
1186 								xprintf(sim_verfile, x_("  inv %s%ld (%s, %s);\n"),
1187 									IMPLICITINVERTERNODENAME, pi->conarcinst->temp1+nindex,
1188 										invsigname, signame);
1189 								signame = invsigname;
1190 							}
1191 							addstringtoinfstr(infstr, signame);
1192 						}
1193 					}
1194 					addstringtoinfstr(infstr, x_(");"));
1195 					break;
1196 
1197 				case 2:		/* transistors: write ports in the proper order */
1198 					/* schem: g/s/d  mos: g/s/g/d */
1199 					gnet = ni->proto->firstportproto->network;
1200 					for(i=0; i<2; i++)
1201 					{
1202 						for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1203 						{
1204 							for(opp = ni->proto->firstportproto; opp != pp; opp = opp->nextportproto)
1205 								if (opp->network == pp->network) break;
1206 							if (opp != pp) continue;
1207 							if (dropbias != 0 && namesame(pp->protoname, x_("b")) == 0) continue;
1208 							if (i == 0)
1209 							{
1210 								if (pp->network == gnet) continue;
1211 							} else
1212 							{
1213 								if (pp->network != gnet) continue;
1214 							}
1215 							net = NONETWORK;
1216 							for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1217 								if (pi->proto->network == pp->network) break;
1218 							if (pi != NOPORTARCINST) net = pi->conarcinst->network; else
1219 							{
1220 								for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
1221 									if (pe->proto == pp) break;
1222 								if (pe != NOPORTEXPINST) net = pe->exportproto->network;
1223 							}
1224 							if (first) first = FALSE; else
1225 								addstringtoinfstr(infstr, x_(", "));
1226 							if (net == NONETWORK)
1227 							{
1228 								ttyputmsg(_("***Warning: cell %s, node %s is not fully connected"),
1229 									describenodeproto(np), describenodeinst(ni));
1230 								esnprintf(impsigname, 100, x_("UNCONNECTED%ld"), unconnectednet++);
1231 								signame = impsigname;
1232 							} else
1233 							{
1234 								if (nodewidth > 1)
1235 								{
1236 									(void)net_evalbusname(APBUS, networkname(net, 0), &strings, pi->conarcinst, np, 1);
1237 									estrcpy(impsigname, strings[nindex]);
1238 									signame = impsigname;
1239 								} else
1240 								{
1241 									signame = &((CHAR *)net->temp2)[1];
1242 									if (net == pwrnet) signame = x_("vdd"); else
1243 										if (net == gndnet) signame = x_("gnd");
1244 								}
1245 								if (i != 0 && pi != NOPORTARCINST && pi->conarcinst->temp1 != 0)
1246 								{
1247 									/* this input is negated: write the implicit inverter */
1248 									esnprintf(invsigname, 100, x_("%s%ld"), IMPLICITINVERTERSIGNAME,
1249 										pi->conarcinst->temp1+nindex);
1250 									xprintf(sim_verfile, x_("  inv %s%ld (%s, %s);\n"),
1251 										IMPLICITINVERTERNODENAME, pi->conarcinst->temp1+nindex,
1252 											invsigname, signame);
1253 									signame = invsigname;
1254 								}
1255 							}
1256 							addstringtoinfstr(infstr, signame);
1257 						}
1258 					}
1259 					addstringtoinfstr(infstr, x_(");"));
1260 					break;
1261 			}
1262 			sim_verwritelongline(returninfstr(infstr));
1263 		}
1264 		efree((CHAR *)nodename);
1265 	}
1266 	if (paramname == 0) modulename = sim_vercellname(np); else
1267 		modulename = sim_verconvertname(paramname);
1268 	xprintf(sim_verfile, x_("endmodule   /* %s */\n"), modulename);
1269 
1270 	/* free net names */
1271 	for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1272 		if (net->temp2 != 0) efree((CHAR *)net->temp2);
1273 
1274 	return(backannotate);
1275 }
1276 
1277 /*
1278  * Routine to add a bus of signals named "name" to the infinite string "infstr".  If "name" is zero,
1279  * do not include the ".NAME()" wrapper.  The signals are in "outernetlist" and range in index from
1280  * "lowindex" to "highindex".  They are described by a bus with characteristic "tempval"
1281  * (low bit is on if the bus descends).  Any unconnected networks can be numbered starting at
1282  * "*unconnectednet".  The power and grounds nets are "pwrnet" and "gndnet".
1283  */
sim_verwritebus(NETWORK ** outernetlist,INTBIG lowindex,INTBIG highindex,INTBIG tempval,INTBIG * unconnectednet,CHAR * name,NETWORK * pwrnet,NETWORK * gndnet,void * infstr)1284 void sim_verwritebus(NETWORK **outernetlist, INTBIG lowindex, INTBIG highindex, INTBIG tempval,
1285 	INTBIG *unconnectednet, CHAR *name, NETWORK *pwrnet, NETWORK *gndnet, void *infstr)
1286 {
1287 	REGISTER INTBIG breakbus, numexported, numinternal, j, k, start, end, order, li;
1288 	REGISTER NETWORK *net, *onet, *lastnet;
1289 	REGISTER CHAR *thisnetname, *lastnetname, *pt, *lastpt;
1290 
1291 	/* array signal: see if it gets split out */
1292 	breakbus = 0;
1293 
1294 	/* bus cannot have pwr/gnd, must be connected */
1295 	numexported = numinternal = 0;
1296 	for(j=lowindex; j<=highindex; j++)
1297 	{
1298 		net = outernetlist[j-lowindex];
1299 		if (net == NONETWORK || net->temp1 == 6) break;
1300 		if (net->temp1 > 1) numexported++; else
1301 			numinternal++;
1302 	}
1303 	if (j <= highindex) breakbus = 1;
1304 
1305 	/* must be all exported or all internal, not a mix */
1306 	if (numexported > 0 && numinternal > 0) breakbus = 1;
1307 
1308 	if (breakbus == 0)
1309 	{
1310 		/* see if all of the nets on this bus are distinct */
1311 		for(j=lowindex+1; j<=highindex; j++)
1312 		{
1313 			net = outernetlist[j-lowindex];
1314 			for(k=lowindex; k<j; k++)
1315 			{
1316 				onet = outernetlist[k-lowindex];
1317 				if (net == onet) break;
1318 			}
1319 			if (k < j) break;
1320 		}
1321 		if (j <= highindex) breakbus = 1; else
1322 		{
1323 			/* bus entries must have the same root name and go in order */
1324 			lastnet = NONETWORK;
1325 			for(j=lowindex; j<=highindex; j++)
1326 			{
1327 				net = outernetlist[j-lowindex];
1328 				thisnetname = (CHAR *)net->temp2;
1329 				if (*thisnetname == 'D')
1330 				{
1331 					if ((tempval&1) == 0) break;
1332 				} else if (*thisnetname == 'U')
1333 				{
1334 					if ((tempval&1) != 0) break;
1335 				}
1336 				thisnetname++;
1337 
1338 				for(pt = thisnetname; *pt != 0; pt++)
1339 					if (*pt == '[') break;
1340 				if (*pt == 0) break;
1341 				if (j > lowindex)
1342 				{
1343 					lastnetname = &((CHAR *)lastnet->temp2)[1];
1344 					for(li = 0; lastnetname[li] != 0; li++)
1345 					{
1346 						if (thisnetname[li] != lastnetname[li]) break;
1347 						if (lastnetname[li] == '[') break;
1348 					}
1349 					if (lastnetname[li] != '[' || thisnetname[li] != '[') break;
1350 					if (myatoi(pt+1) != myatoi(&lastnetname[li+1])+1) break;
1351 				}
1352 				lastnet = net;
1353 			}
1354 			if (j <= highindex) breakbus = 1;
1355 		}
1356 	}
1357 
1358 	if (name != 0) formatinfstr(infstr, x_(".%s("), name);
1359 	if (breakbus != 0)
1360 	{
1361 		addstringtoinfstr(infstr, x_("{"));
1362 		if ((tempval&1) != 0)
1363 		{
1364 			start = highindex;
1365 			end = lowindex;
1366 			order = -1;
1367 		} else
1368 		{
1369 			start = lowindex;
1370 			end = highindex;
1371 			order = 1;
1372 		}
1373 		for(j=start; ; j += order)
1374 		{
1375 			if (j != start)
1376 				addstringtoinfstr(infstr, x_(", "));
1377 			net = outernetlist[j-lowindex];
1378 			if (net == NONETWORK)
1379 			{
1380 				formatinfstr(infstr, x_("UNCONNECTED%ld"), *unconnectednet);
1381 				(*unconnectednet)++;
1382 			} else
1383 			{
1384 				if (net == pwrnet) addstringtoinfstr(infstr, x_("vdd")); else
1385 					if (net == gndnet) addstringtoinfstr(infstr, x_("gnd")); else
1386 						addstringtoinfstr(infstr, &((CHAR *)net->temp2)[1]);
1387 			}
1388 			if (j == end) break;
1389 		}
1390 		addstringtoinfstr(infstr, x_("}"));
1391 	} else
1392 	{
1393 		lastnet = outernetlist[0];
1394 		for(lastpt = &((CHAR *)lastnet->temp2)[1]; *lastpt != 0; lastpt++)
1395 			if (*lastpt == '[') break;
1396 		net = outernetlist[highindex-lowindex];
1397 		for(pt = &((CHAR *)net->temp2)[1]; *pt != 0; pt++)
1398 		{
1399 			if (*pt == '[') break;
1400 			addtoinfstr(infstr, *pt);
1401 		}
1402 		if ((tempval&1) != 0)
1403 		{
1404 			formatinfstr(infstr, x_("[%ld:%ld]"), myatoi(pt+1), myatoi(lastpt+1));
1405 		} else
1406 		{
1407 			formatinfstr(infstr, x_("[%ld:%ld]"), myatoi(lastpt+1), myatoi(pt+1));
1408 		}
1409 	}
1410 	if (name != 0) addstringtoinfstr(infstr, x_(")"));
1411 }
1412 
1413 /*
1414  * Routine to add text from all nodes in cell "np"
1415  * (which have "verilogkey" text on them)
1416  * to that text to the output file.  Returns true if anything
1417  * was found.
1418  */
sim_verincludetypedcode(NODEPROTO * np,INTBIG verilogkey,CHAR * descript)1419 BOOLEAN sim_verincludetypedcode(NODEPROTO *np, INTBIG verilogkey, CHAR *descript)
1420 {
1421 	BOOLEAN first;
1422 	REGISTER INTBIG len, i;
1423 	REGISTER NODEINST *ni;
1424 	REGISTER VARIABLE *var;
1425 
1426 	/* write out any directly-typed Verilog code */
1427 	first = TRUE;
1428 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1429 	{
1430 		if (ni->proto != gen_invispinprim) continue;
1431 		var = getvalkey((INTBIG)ni, VNODEINST, -1, verilogkey);
1432 		if (var == NOVARIABLE) continue;
1433 		if ((var->type&VTYPE) != VSTRING) continue;
1434 		if ((var->type&VDISPLAY) == 0) continue;
1435 		if (first)
1436 		{
1437 			first = FALSE;
1438 			xprintf(sim_verfile, x_("  /* user-specified Verilog %s */\n"),
1439 				descript);
1440 		}
1441 		if ((var->type&VISARRAY) == 0)
1442 		{
1443 			xprintf(sim_verfile, x_("  %s\n"), (CHAR *)var->addr);
1444 		} else
1445 		{
1446 			len = getlength(var);
1447 			for(i=0; i<len; i++)
1448 				xprintf(sim_verfile, x_("  %s\n"), ((CHAR **)var->addr)[i]);
1449 		}
1450 	}
1451 	if (!first) xprintf(sim_verfile, x_("\n"));
1452 	return(first);
1453 }
1454 
1455 /*
1456  * Routine to write a long line to the Verilog file, breaking it where sensible.
1457  */
sim_verwritelongline(CHAR * s)1458 void sim_verwritelongline(CHAR *s)
1459 {
1460 	CHAR *pt, save;
1461 	INTBIG i;
1462 	CHAR *lastspace;
1463 
1464 	lastspace = NULL;
1465 	i = 0;
1466 	for (pt = s; *pt; pt++)
1467 	{
1468 		if (*pt == ' ' || *pt == ',') lastspace = pt;
1469 		++i;
1470 		if (i >= MAXDECLARATIONWIDTH)
1471 		{
1472 			if (lastspace != NULL)
1473 			{
1474 				if (*lastspace != ' ') lastspace++;
1475 				save = *lastspace;   *lastspace = 0;
1476 				xputs(s, sim_verfile);
1477 				*lastspace = save;
1478 				xputs(x_("\n      "), sim_verfile);
1479 				s = lastspace;
1480 				if (*s == ' ') s++;
1481 				i = 6 + pt-s+1;
1482 				lastspace = NULL;
1483 			} else
1484 			{
1485 				xputs(x_("\n      "), sim_verfile);
1486 				i = 6 + 1;
1487 			}
1488 		}
1489 	}
1490 	xputs(s, sim_verfile);
1491 	xputs(x_("\n"), sim_verfile);
1492 }
1493 
1494 /*
1495  * Routine to initialize the collection of signal names in a declaration.
1496  * The declaration starts with the string "header".
1497  */
sim_verinitdeclaration(CHAR * header)1498 void sim_verinitdeclaration(CHAR *header)
1499 {
1500 	estrcpy(sim_verdeclarationline, header);
1501 	sim_verdeclarationprefix = estrlen(sim_verdeclarationline);
1502 }
1503 
1504 /*
1505  * Routine to add "signame" to the collection of signal names in a declaration.
1506  */
sim_veradddeclaration(CHAR * signame)1507 void sim_veradddeclaration(CHAR *signame)
1508 {
1509 	if (estrlen(sim_verdeclarationline) + estrlen(signame) + 3 > MAXDECLARATIONWIDTH)
1510 	{
1511 		xprintf(sim_verfile, x_("%s;\n"), sim_verdeclarationline);
1512 		sim_verdeclarationline[sim_verdeclarationprefix] = 0;
1513 	}
1514 	if ((INTBIG)estrlen(sim_verdeclarationline) != sim_verdeclarationprefix)
1515 		estrcat(sim_verdeclarationline, x_(","));
1516 	estrcat(sim_verdeclarationline, x_(" "));
1517 	estrcat(sim_verdeclarationline, signame);
1518 }
1519 
1520 /*
1521  * Routine to terminate the collection of signal names in a declaration
1522  * and write the declaration to the Verilog file.
1523  */
sim_vertermdeclaration(void)1524 void sim_vertermdeclaration(void)
1525 {
1526 	xprintf(sim_verfile, x_("%s;\n"), sim_verdeclarationline);
1527 }
1528 
1529 /*
1530  * Routine to return the name of cell "c", given that it may be ambiguously used in multiple
1531  * libraries.
1532  */
sim_vercellname(NODEPROTO * np)1533 CHAR *sim_vercellname(NODEPROTO *np)
1534 {
1535 	REGISTER void *infstr;
1536 
1537 
1538 	/* Some other function is messing with temp2 during verilog netlisting
1539 	   so this function is broken.  For now, every instance will be prepended
1540 	   with it's library name
1541 	if (np->temp2 == 0)
1542 		return(sim_verconvertname(np->protoname));
1543 		*/
1544 
1545 	infstr = initinfstr();
1546 	formatinfstr(infstr, x_("%s__%s"), np->lib->libname, sim_vernamenoindices(np->protoname));
1547 	return(returninfstr(infstr));
1548 }
1549 
1550 /*
1551  * routine to adjust name "p" and return the string.
1552  * Verilog does permit a digit in the first location; prepend a "_" if found.
1553  * Verilog only permits the "_" and "$" characters: all others are converted to "_".
1554  * Verilog does not permit nonnumeric indices, so "P[A]" is converted to "P_A_"
1555  * Verilog does not permit multidimensional arrays, so "P[1][2]" is converted to "P_1_[2]"
1556  *   and "P[1][T]" is converted to "P_1_T_"
1557  */
sim_verconvertname(CHAR * p)1558 CHAR *sim_verconvertname(CHAR *p)
1559 {
1560 	REGISTER CHAR *t, *end;
1561 	REGISTER void *infstr;
1562 
1563 	/* simple names are trivially accepted as is */
1564 	for(t = p; *t != 0; t++) if (!isalnum(*t)) break;
1565 	if (*t == 0 && !isdigit(*p)) return(p);
1566 
1567 	infstr = initinfstr();
1568 	end = sim_verstartofindex(p);
1569 	for(t = p; t < end; t++)
1570 	{
1571 		if (*t == '[' || *t == ']')
1572 		{
1573 			addtoinfstr(infstr, '_');
1574 			if (*t == ']' && t[1] == '[') t++;
1575 		} else
1576 		{
1577 			if (isalnum(*t) || *t == '_' || *t == '$')
1578 				addtoinfstr(infstr, *t); else
1579 					addtoinfstr(infstr, '_');
1580 		}
1581 	}
1582 	addstringtoinfstr(infstr, end);
1583 	if (*end != 0) addstringtoinfstr(infstr, x_("_"));
1584 	return(returninfstr(infstr));
1585 }
1586 
1587 /*
1588  * routine to adjust name "p" and return the string.
1589  * This code removes all index indicators and other special characters, turning
1590  * them into "_".
1591  */
sim_vernamenoindices(CHAR * p)1592 CHAR *sim_vernamenoindices(CHAR *p)
1593 {
1594 	REGISTER CHAR *t;
1595 	REGISTER void *infstr;
1596 
1597 	infstr = initinfstr();
1598 	if (isdigit(*p)) addtoinfstr(infstr, '_');
1599 	for(t = p; *t != 0 ; t++)
1600 	{
1601 		if (isalnum(*t) || *t == '_' || *t == '$')
1602 			addtoinfstr(infstr, *t); else
1603 				addtoinfstr(infstr, '_');
1604 	}
1605 	return(returninfstr(infstr));
1606 }
1607 
1608 /*
1609  * Routine to return the character position in network name "name" that is the start of indexing.
1610  * If there is no indexing ("clock"), this will point to the end of the string.
1611  * If there is simple indexing ("dog[12]"), this will point to the "[".
1612  * If the index is nonnumeric ("dog[cat]"), this will point to the end of the string.
1613  *
1614  * If there are multiple indices, ("dog[12][45]") this will point to the last "[" (unless it is nonnumeric).
1615  * NO, if there are multiple indices, ("dog[12][45]") this will point to the end of the string.
1616  */
sim_verstartofindex(CHAR * name)1617 CHAR *sim_verstartofindex(CHAR *name)
1618 {
1619 	REGISTER INTBIG len, i;
1620 
1621 	len = estrlen(name);
1622 	if (name[len-1] != ']') return(name+len);
1623 	for(i = len-2; i > 0; i--)
1624 	{
1625 		if (name[i] == '[') break;
1626 /*		if (name[i] == ':' || name[i] == ',') continue; */
1627 		if (name[i] == ':' || name[i] == ',') break;
1628 		if (!isdigit(name[i])) break;
1629 	}
1630 	if (name[i] != '[') return(name+len);
1631 	if (i > 0 && name[i-1] == ']') return(name+len);
1632 	return(name+i);
1633 }
1634 
1635 /*
1636  * Routine to scan networks in cell "cell".  The "temp1" field is filled in with
1637  *    0: internal network (ascending order when in a bus)
1638  *    1: internal network (descending order when in a bus)
1639  *    2: exported input network (ascending order when in a bus)
1640  *    3: exported input network (descending order when in a bus)
1641  *    4: exported output network (ascending order when in a bus)
1642  *    5: exported output network (descending order when in a bus)
1643  *    6: power or ground network
1644  * All networks are sorted by name within "temp1" and the common array entries are
1645  * reduced to a list of names (in "namelist") and their low/high range of indices
1646  * (in "lowindex" and "highindex", with high < low if no indices apply).  The value
1647  * of "temp1" is returned in the array "tempval".  The list of "netcount" networks
1648  * found (uncombined by index) is returned in "wirelist".  The power and ground nets
1649  * are stored in "pwrnet" and "gndnet".  The total number of names is returned.
1650  */
sim_vergetnetworks(NODEPROTO * cell,CHAR *** namelist,INTBIG ** lowindex,INTBIG ** highindex,INTBIG ** tempval,WIRELIST ** wirelist,INTBIG * netcount,NETWORK ** pwrnet,NETWORK ** gndnet,INTBIG quiet)1651 INTBIG sim_vergetnetworks(NODEPROTO *cell, CHAR ***namelist,
1652 	INTBIG **lowindex, INTBIG **highindex, INTBIG **tempval,
1653 	WIRELIST **wirelist, INTBIG *netcount, NETWORK **pwrnet, NETWORK **gndnet, INTBIG quiet)
1654 {
1655 	REGISTER NETWORK *net, *endnet, *subnet;
1656 	REGISTER PORTPROTO *pp, *widestpp;
1657 	REGISTER BOOLEAN updir, downdir, randomdir, multipwr, multignd, found;
1658 	REGISTER NODEINST *ni;
1659 	REGISTER ARCINST *ai;
1660 	REGISTER PORTARCINST *pi;
1661 	REGISTER INTBIG wirecount, i, j, k, namelistcount, index, newtotal, dirbit,
1662 		*newtemp, *newlow, *newhigh, comp, fun, last, widestfound;
1663 	REGISTER UINTBIG characteristics;
1664 	REGISTER CHAR **newnamelist, save, *pt, *ept, *name, *endname;
1665 	REGISTER void *infstr;
1666 
1667 	/* initialize to describe all nets */
1668 	namelistcount = 0;
1669 	wirecount = 0;
1670 	for(net = cell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1671 	{
1672 		net->temp1 = 0;
1673 		if (net->buswidth > 1) continue;
1674 		wirecount++;
1675 	}
1676 
1677 	/* determine default direction of busses */
1678 	if ((net_options&NETDEFBUSBASEDESC) != 0) dirbit = 1; else
1679 		dirbit = 0;
1680 
1681 	/* mark exported networks */
1682 	for(pp = cell->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1683 	{
1684 		switch (pp->userbits&STATEBITS)
1685 		{
1686 			case OUTPORT:   j = 4+dirbit;  break;
1687 			default:        j = 2+dirbit;  break;
1688 		}
1689 		if (pp->network->buswidth > 1)
1690 		{
1691 			/* bus export: mark individual network entries */
1692 			for(i=0; i<pp->network->buswidth; i++)
1693 			{
1694 				net = pp->network->networklist[i];
1695 				net->temp1 = j;
1696 			}
1697 		} else
1698 		{
1699 			/* single wire export: mark the network */
1700 			net = pp->network;
1701 			net->temp1 = j;
1702 		}
1703 	}
1704 
1705 	/* postprocess to ensure the directionality is correct */
1706 	for(net = cell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1707 	{
1708 		if (net->temp1 == 0) continue;
1709 		if (net->namecount <= 0) continue;
1710 		name = networkname(net, 0);
1711 		for(pp = cell->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1712 		{
1713 			if (pp->network->buswidth > 1) continue;
1714 			if (namesame(pp->protoname, name) != 0) continue;
1715 			switch (pp->userbits&STATEBITS)
1716 			{
1717 				case OUTPORT:   j = 4+dirbit;  break;
1718 				default:        j = 2+dirbit;  break;
1719 			}
1720 			net->temp1 = j;
1721 		}
1722 	}
1723 
1724 	/* make sure all busses go in the same direction */
1725 	for(net = cell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1726 	{
1727 		if (net->buswidth <= 1) continue;
1728 		j = 0;
1729 		for(i=0; i<net->buswidth; i++)
1730 		{
1731 			subnet = net->networklist[i];
1732 			if (subnet->temp1 == 0) continue;
1733 			if (j == 0) j = subnet->temp1;
1734 			if (subnet->temp1 != j) break;
1735 		}
1736 		if (i >= net->buswidth) continue;
1737 
1738 		/* mixed directionality: make it all nonoutput */
1739 		for(i=0; i<net->buswidth; i++)
1740 		{
1741 			subnet = net->networklist[i];
1742 			subnet->temp1 = 2+dirbit;
1743 		}
1744 	}
1745 
1746 	/* scan all networks for those that go in descending order */
1747 	for(net = cell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1748 	{
1749 		if (net->buswidth <= 1) continue;
1750 		updir = downdir = randomdir = FALSE;
1751 		last = 0;
1752 		for(i=0; i<net->buswidth; i++)
1753 		{
1754 			subnet = net->networklist[i];
1755 			if (subnet->namecount == 0) break;
1756 			for(pt = networkname(subnet, 0); *pt != 0; pt++)
1757 				if (*pt == '[') break;
1758 			if (*pt == 0) break;
1759 			if (isdigit(pt[1]) == 0) break;
1760 			index = myatoi(pt+1);
1761 			if (i != 0)
1762 			{
1763 				if (index == last-1) downdir = TRUE; else
1764 					if (index == last+1) updir = TRUE; else
1765 						randomdir = TRUE;
1766 			}
1767 			last = index;
1768 		}
1769 		if (randomdir) continue;
1770 		if (updir && downdir) continue;
1771 		if (!updir && !downdir) continue;
1772 		if (downdir) dirbit = 1; else
1773 			dirbit = 0;
1774 		for(i=0; i<net->buswidth; i++)
1775 		{
1776 			subnet = net->networklist[i];
1777 			subnet->temp1 = (subnet->temp1 & ~1) | dirbit;
1778 		}
1779 	}
1780 
1781 	/* find power and ground */
1782 	*pwrnet = *gndnet = NONETWORK;
1783 	multipwr = multignd = FALSE;
1784 	for(pp = cell->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1785 	{
1786 		if (portispower(pp))
1787 		{
1788 			if (*pwrnet != NONETWORK && *pwrnet != pp->network && !multipwr)
1789 			{
1790 				if (quiet == 0)
1791 					ttyputmsg(_("Warning: multiple power networks in cell %s"),
1792 						describenodeproto(cell));
1793 				multipwr = TRUE;
1794 			}
1795 			*pwrnet = pp->network;
1796 		}
1797 		if (portisground(pp))
1798 		{
1799 			if (*gndnet != NONETWORK && *gndnet != pp->network && !multignd)
1800 			{
1801 				if (quiet == 0)
1802 					ttyputmsg(_("Warning: multiple ground networks in cell %s"),
1803 						describenodeproto(cell));
1804 				multignd = TRUE;
1805 			}
1806 			*gndnet = pp->network;
1807 		}
1808 	}
1809 	for(net = cell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1810 	{
1811 		if (net->globalnet >= 0 && net->globalnet < cell->globalnetcount)
1812 		{
1813 			characteristics = cell->globalnetchar[net->globalnet];
1814 			if (characteristics == PWRPORT)
1815 			{
1816 				if (*pwrnet != NONETWORK && *pwrnet != net && !multipwr)
1817 				{
1818 					if (quiet == 0)
1819 						ttyputmsg(_("Warning: multiple power networks in cell %s"),
1820 							describenodeproto(cell));
1821 					multipwr = TRUE;
1822 				}
1823 				*pwrnet = net;
1824 			} else if (characteristics == GNDPORT)
1825 			{
1826 				if (*gndnet != NONETWORK && *gndnet != net && !multignd)
1827 				{
1828 					if (quiet == 0)
1829 						ttyputmsg(_("Warning: multiple ground networks in cell %s"),
1830 							describenodeproto(cell));
1831 					multignd = TRUE;
1832 				}
1833 				*gndnet = net;
1834 			}
1835 		}
1836 	}
1837 	for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1838 	{
1839 		fun = nodefunction(ni);
1840 		if (fun == NPCONPOWER || fun == NPCONGROUND)
1841 		{
1842 			for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1843 			{
1844 				ai = pi->conarcinst;
1845 				if (fun == NPCONPOWER)
1846 				{
1847 					if (*pwrnet != NONETWORK && *pwrnet != ai->network && !multipwr)
1848 					{
1849 						if (quiet == 0)
1850 							ttyputmsg(_("Warning: multiple power networks in cell %s"),
1851 								describenodeproto(cell));
1852 						multipwr = TRUE;
1853 					}
1854 					*pwrnet = ai->network;
1855 				} else
1856 				{
1857 					if (*gndnet != NONETWORK && *gndnet != ai->network && !multignd)
1858 					{
1859 						if (quiet == 0)
1860 							ttyputmsg(_("Warning: multiple ground networks in cell %s"),
1861 								describenodeproto(cell));
1862 						multignd = TRUE;
1863 					}
1864 					*gndnet = ai->network;
1865 				}
1866 			}
1867 		}
1868 	}
1869 	if (*pwrnet != NONETWORK) (*pwrnet)->temp1 = 6;
1870 	if (*gndnet != NONETWORK) (*gndnet)->temp1 = 6;
1871 
1872 	/* make sure there is room in the array of networks */
1873 	if (wirecount > sim_verilogwirelisttotal)
1874 	{
1875 		if (sim_verilogwirelisttotal > 0)
1876 			efree((CHAR *)sim_verilogwirelist);
1877 		sim_verilogwirelisttotal = 0;
1878 		sim_verilogwirelist = (WIRELIST *)emalloc(wirecount * (sizeof (WIRELIST)),
1879 			sim_tool->cluster);
1880 		if (sim_verilogwirelist == 0) return(0);
1881 		sim_verilogwirelisttotal = wirecount;
1882 	}
1883 
1884 	/* load the array */
1885 	if (wirecount > 0)
1886 	{
1887 		i = 0;
1888 		for(net = cell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1889 		{
1890 			if (net->buswidth > 1) continue;
1891 			sim_verilogwirelist[i].net = net;
1892 			sim_verilogwirelist[i].pp = NOPORTPROTO;
1893 
1894 			/* find the widest export that touches this network */
1895 			widestfound = -1;
1896 			widestpp = NOPORTPROTO;
1897 			for(pp = cell->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1898 			{
1899 				found = FALSE;
1900 				if (pp->network == net) found = TRUE; else
1901 				{
1902 					if (pp->network->buswidth > 1)
1903 					{
1904 						for(j=0; j<pp->network->buswidth; j++)
1905 							if (pp->network->networklist[j] == net) break;
1906 						if (j < pp->network->buswidth) found = TRUE;
1907 					}
1908 				}
1909 				if (found)
1910 				{
1911 					if (pp->network->buswidth > widestfound)
1912 					{
1913 						widestfound = pp->network->buswidth;
1914 						widestpp = pp;
1915 					}
1916 				}
1917 			}
1918 			if (widestpp != NOPORTPROTO) sim_verilogwirelist[i].pp = widestpp;
1919 			i++;
1920 		}
1921 
1922 		/* sort the networks by name */
1923 		esort(sim_verilogwirelist, wirecount, sizeof (WIRELIST), sim_versortwirelistsbyname);
1924 
1925 		/* organize by name and index order */
1926 		for(i=0; i<wirecount; i++)
1927 		{
1928 			net = sim_verilogwirelist[i].net;
1929 
1930 			/* make sure there is room in the list */
1931 			if (namelistcount >= sim_verilognamelisttotal)
1932 			{
1933 				newtotal = sim_verilognamelisttotal * 2;
1934 				if (newtotal <= namelistcount) newtotal = namelistcount + 5;
1935 				newnamelist = (CHAR **)emalloc(newtotal * (sizeof (CHAR *)),
1936 					sim_tool->cluster);
1937 				if (newnamelist == 0) return(0);
1938 				newlow = (INTBIG *)emalloc(newtotal * SIZEOFINTBIG, sim_tool->cluster);
1939 				if (newlow == 0) return(0);
1940 				newhigh = (INTBIG *)emalloc(newtotal * SIZEOFINTBIG, sim_tool->cluster);
1941 				if (newhigh == 0) return(0);
1942 				newtemp = (INTBIG *)emalloc(newtotal * SIZEOFINTBIG, sim_tool->cluster);
1943 				if (newtemp == 0) return(0);
1944 				for(j=0; j<newtotal; j++) newnamelist[j] = 0;
1945 				for(j=0; j<namelistcount; j++)
1946 				{
1947 					newnamelist[j] = sim_verilognamelist[j];
1948 					newlow[j] = sim_verilognamelistlow[j];
1949 					newhigh[j] = sim_verilognamelisthigh[j];
1950 					newtemp[j] = sim_verilognamelisttempval[j];
1951 				}
1952 				if (sim_verilognamelisttotal > 0)
1953 				{
1954 					efree((CHAR *)sim_verilognamelist);
1955 					efree((CHAR *)sim_verilognamelistlow);
1956 					efree((CHAR *)sim_verilognamelisthigh);
1957 					efree((CHAR *)sim_verilognamelisttempval);
1958 				}
1959 				sim_verilognamelist = newnamelist;
1960 				sim_verilognamelistlow = newlow;
1961 				sim_verilognamelisthigh = newhigh;
1962 				sim_verilognamelisttempval = newtemp;
1963 				sim_verilognamelisttotal = newtotal;
1964 			}
1965 
1966 			/* add this name to the list */
1967 			if (net->globalnet > 1 && net->globalnet < net->parent->globalnetcount)
1968 			{
1969 				name = net->parent->globalnetnames[net->globalnet];
1970 			} else
1971 			{
1972 				if (net->namecount == 0) name = describenetwork(net); else
1973 					name = networkname(net, 0);
1974 
1975 				/* if exported, be sure to get the export name */
1976 				if (net->temp1 > 1 && net->temp1 < 6)
1977 				{
1978 					for(pp = cell->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1979 						if (pp->network == net) break;
1980 					if (pp != NOPORTPROTO) name = pp->protoname;
1981 				}
1982 			}
1983 
1984 			pt = sim_verstartofindex(name);
1985 			save = *pt;
1986 			*pt = 0;
1987 			if (sim_verilognamelist[namelistcount] != 0)
1988 				efree(sim_verilognamelist[namelistcount]);
1989 			(void)allocstring(&sim_verilognamelist[namelistcount],
1990 				sim_verconvertname(name), sim_tool->cluster);
1991 			sim_verilognamelisttempval[namelistcount] = net->temp1;
1992 			if (save == 0)
1993 			{
1994 				/* single wire: set range to show that */
1995 				sim_verilognamelistlow[namelistcount] = 1;
1996 				sim_verilognamelisthigh[namelistcount] = 0;
1997 			} else
1998 			{
1999 				sim_verilognamelistlow[namelistcount] =
2000 					sim_verilognamelisthigh[namelistcount] = myatoi(pt+1);
2001 				for(j=i+1; j<wirecount; j++)
2002 				{
2003 					endnet = sim_verilogwirelist[j].net;
2004 					if (endnet == NONETWORK) break;
2005 					if (endnet->temp1 != net->temp1) break;
2006 					if (sim_verilogwirelist[j].pp != sim_verilogwirelist[i].pp) break;
2007 					if (endnet->globalnet != net->globalnet) break;
2008 					if (endnet->namecount == 0) break;
2009 					endname = networkname(endnet, 0);
2010 					ept = sim_verstartofindex(endname);
2011 					if (*ept != '[') break;
2012 					*ept = 0;
2013 					comp = namesame(name, endname);
2014 					*ept = '[';
2015 					if (comp != 0) break;
2016 					index = myatoi(ept+1);
2017 
2018 					/* make sure export indices go in order */
2019 					if (index != sim_verilognamelisthigh[namelistcount]+1)
2020 						break;
2021 					if (index > sim_verilognamelisthigh[namelistcount])
2022 						sim_verilognamelisthigh[namelistcount] = index;
2023 					i = j;
2024 				}
2025 			}
2026 			*pt = save;
2027 			namelistcount++;
2028 		}
2029 	}
2030 
2031 	/* make sure all names are unique */
2032 	for(i=1; i<namelistcount; i++)
2033 	{
2034 		/* single signal: give it that name */
2035 		if (sim_verilognamelistlow[i] == sim_verilognamelisthigh[i])
2036 		{
2037 			infstr = initinfstr();
2038 			formatinfstr(infstr, x_("%s_%ld_"), sim_verilognamelist[i], sim_verilognamelistlow[i]);
2039 			(void)reallocstring(&sim_verilognamelist[i], returninfstr(infstr), sim_tool->cluster);
2040 		}
2041 
2042 		/* see if it clashes */
2043 		for(j=0; j<i; j++)
2044 			if (namesame(sim_verilognamelist[i], sim_verilognamelist[j]) == 0) break;
2045 		if (j < i)
2046 		{
2047 			/* name the same: rename */
2048 			pt = 0;
2049 			for(k=1; k<1000; k++)
2050 			{
2051 				infstr = initinfstr();
2052 				formatinfstr(infstr, x_("%s_%ld"), sim_verilognamelist[i], k);
2053 				pt = returninfstr(infstr);
2054 				for(j=0; j<namelistcount; j++)
2055 					if (namesame(pt, sim_verilognamelist[j]) == 0) break;
2056 				if (j >= namelistcount) break;
2057 			}
2058 			(void)reallocstring(&sim_verilognamelist[i], pt, sim_tool->cluster);
2059 		}
2060 	}
2061 
2062 	*namelist = sim_verilognamelist;
2063 	*lowindex = sim_verilognamelistlow;
2064 	*highindex = sim_verilognamelisthigh;
2065 	*tempval = sim_verilognamelisttempval;
2066 	*wirelist = sim_verilogwirelist;
2067 	*netcount = wirecount;
2068 	return(namelistcount);
2069 }
2070 
2071 /*
2072  * Helper routine for "esort" that makes networks with names go in ascending name order.
2073  */
sim_versortwirelistsbyname(const void * e1,const void * e2)2074 int sim_versortwirelistsbyname(const void *e1, const void *e2)
2075 {
2076 	REGISTER WIRELIST *w1, *w2;
2077 	REGISTER NETWORK *net1, *net2;
2078 	REGISTER CHAR *pt1, *pt2;
2079 	CHAR empty[1];
2080 
2081 	w1 = (WIRELIST *)e1;
2082 	w2 = (WIRELIST *)e2;
2083 	net1 = w1->net;
2084 	net2 = w2->net;
2085 	if (net1->temp1 != net2->temp1) return(net1->temp1 - net2->temp1);
2086 	empty[0] = 0;
2087 	if (net1->globalnet > 1 && net1->globalnet < net1->parent->globalnetcount)
2088 	{
2089 		pt1 = net1->parent->globalnetnames[net1->globalnet];
2090 	} else
2091 	{
2092 		if (net1->namecount == 0) pt1 = empty; else pt1 = networkname(net1, 0);
2093 	}
2094 	if (net2->globalnet > 1 && net2->globalnet < net2->parent->globalnetcount)
2095 	{
2096 		pt2 = net2->parent->globalnetnames[net2->globalnet];
2097 	} else
2098 	{
2099 		if (net2->namecount == 0) pt2 = empty; else pt2 = networkname(net2, 0);
2100 	}
2101 	return(namesamenumeric(pt1, pt2));
2102 }
2103 
2104 /*
2105  * Routine to return the network connected to node "ni", port "pp".
2106  */
sim_vergetnetonport(NODEINST * ni,PORTPROTO * pp)2107 NETWORK *sim_vergetnetonport(NODEINST *ni, PORTPROTO *pp)
2108 {
2109 	REGISTER PORTARCINST *pi;
2110 	REGISTER PORTEXPINST *pe;
2111 
2112 	for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
2113 		if (pi->proto == pp) return(pi->conarcinst->network);
2114 	for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
2115 		if (pe->proto == pp) return(pe->exportproto->network);
2116 	return(NONETWORK);
2117 }
2118 
2119 /*
2120  * Routine to recursively examine cells and gather global network names.
2121  */
sim_vergatherglobals(NODEPROTO * np)2122 void sim_vergatherglobals(NODEPROTO *np)
2123 {
2124 	REGISTER INTBIG i, newtotal, globalnet;
2125 	REGISTER UINTBIG *newchars;
2126 	NETWORK *net;
2127 	REGISTER CHAR *gname, **newlist;
2128 	REGISTER NODEPROTO *onp, *cnp;
2129 	REGISTER NODEINST *ni;
2130 	REGISTER PORTARCINST *pi;
2131 
2132 	if (np->temp1 != 0) return;
2133 	np->temp1 = 1;
2134 
2135 	/* mark all exported nets */
2136 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2137 	{
2138 		if (ni->proto != sch_globalprim) continue;
2139 		pi = ni->firstportarcinst;
2140 		if (pi == NOPORTARCINST) continue;
2141 		net = pi->conarcinst->network;
2142 		if (net == NONETWORK) continue;
2143 		globalnet = net->globalnet;
2144 		if (globalnet < 2) continue;
2145 
2146 		/* global net found: see if it is already in the list */
2147 		gname = sim_verconvertname(np->globalnetnames[globalnet]);
2148 		for(i=0; i<sim_verilogglobalnetcount; i++)
2149 			if (namesame(gname, sim_verilogglobalnets[i]) == 0) break;
2150 		if (i < sim_verilogglobalnetcount) continue;
2151 
2152 		/* add the global net name */
2153 		if (sim_verilogglobalnetcount >= sim_verilogglobalnettotal)
2154 		{
2155 			newtotal = sim_verilogglobalnettotal * 2;
2156 			if (sim_verilogglobalnetcount >= newtotal)
2157 				newtotal = sim_verilogglobalnetcount + 5;
2158 			newlist = (CHAR **)emalloc(newtotal * (sizeof (CHAR *)), sim_tool->cluster);
2159 			if (newlist == 0) return;
2160 			newchars = (UINTBIG *)emalloc(newtotal * SIZEOFINTBIG, sim_tool->cluster);
2161 			if (newchars == 0) return;
2162 			for(i=0; i<sim_verilogglobalnettotal; i++)
2163 			{
2164 				newlist[i] = sim_verilogglobalnets[i];
2165 				newchars[i] = sim_verilogglobalchars[i];
2166 			}
2167 			for(i=sim_verilogglobalnettotal; i<newtotal; i++)
2168 				newlist[i] = 0;
2169 			if (sim_verilogglobalnettotal > 0)
2170 			{
2171 				efree((CHAR *)sim_verilogglobalnets);
2172 				efree((CHAR *)sim_verilogglobalchars);
2173 			}
2174 			sim_verilogglobalnets = newlist;
2175 			sim_verilogglobalchars = newchars;
2176 			sim_verilogglobalnettotal = newtotal;
2177 		}
2178 		if (sim_verilogglobalnets[sim_verilogglobalnetcount] != 0)
2179 			efree((CHAR *)sim_verilogglobalnets[sim_verilogglobalnetcount]);
2180 		(void)allocstring(&sim_verilogglobalnets[sim_verilogglobalnetcount], gname,
2181 			sim_tool->cluster);
2182 
2183 		/* should figure out the characteristics of this global!!! */
2184 		sim_verilogglobalchars[sim_verilogglobalnetcount] =
2185 			((ni->userbits&NTECHBITS) >> NTECHBITSSH) << STATEBITSSH;
2186 		sim_verilogglobalnetcount++;
2187 	}
2188 
2189 	for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2190 	{
2191 		onp = ni->proto;
2192 		if (onp->primindex != 0) continue;
2193 
2194 		/* ignore recursive references (showing icon in contents) */
2195 		if (isiconof(onp, np)) continue;
2196 
2197 		if (onp->cellview == el_iconview)
2198 		{
2199 			cnp = contentsview(onp);
2200 			if (cnp != NONODEPROTO) onp = cnp;
2201 		}
2202 
2203 		sim_vergatherglobals(onp);
2204 	}
2205 }
2206 
2207 /*************************************** READING VCD DUMPS INTO WAVEFORM ***************************************/
2208 
sim_verfreesimdata(void)2209 void sim_verfreesimdata(void)
2210 {
2211 	REGISTER VERSIGNAL *vs;
2212 
2213 	while (sim_verfirstsignal != NOVERSIGNAL)
2214 	{
2215 		vs = sim_verfirstsignal;
2216 		sim_verfirstsignal = vs->nextversignal;
2217 		if (vs->total > 0)
2218 		{
2219 			efree((CHAR *)vs->stimtime);
2220 			efree((CHAR *)vs->stimstate);
2221 		}
2222 		if (vs->width > 1) efree((CHAR *)vs->signals);
2223 		efree((CHAR *)vs);
2224 	}
2225 }
2226 
sim_verparsefile(CHAR * file,NODEPROTO * cell)2227 void sim_verparsefile(CHAR *file, NODEPROTO *cell)
2228 {
2229 	REGISTER INTBIG i, len, numsignals, curposition, hashtablesize, hashcode, units, width,
2230 		namelen, symbollen, contextlen, structlen, structsize;
2231 	REGISTER INTSML state=0;
2232 	REGISTER double curtime;
2233 	REGISTER NODEINST *ni;
2234 	REGISTER BOOLEAN foundlevel, foundend;
2235 	REGISTER VARIABLE *var;
2236 	REGISTER CHAR *keyword, *symname, *nodename, *symbol, *name, *context;
2237 	REGISTER VERSIGNAL *vs, *vslast, **verhash, **vslist, *subvs;
2238 	NODEPROTO *np;
2239 	REGISTER STRINGOBJ *sosymbol, *soname, *socontext;
2240 	REGISTER void *infstr;
2241 	double min, max;
2242 	REGISTER UCHAR1 *onestruct;
2243 	CHAR *filename, *pt, *pars[10];
2244 	extern COMCOMP us_showdp;
2245 
2246 	sim_verfd = xopen(file, el_filetypetext, 0, &filename);
2247 	if (sim_verfd == 0) return;
2248 
2249 	/* show the progress dialog */
2250 	sim_verfilesize = filesize(sim_verfd);
2251 	if (sim_verfilesize > 0)
2252 	{
2253 		sim_verprogressdialog = DiaInitProgress(x_(""), _("Reading dump file..."));
2254 		if (sim_verprogressdialog == 0)
2255 		{
2256 			xclose(sim_verfd);
2257 			return;
2258 		}
2259 	}
2260 	DiaSetProgress(sim_verprogressdialog, 0, sim_verfilesize);
2261 
2262 	sim_timescale = 1.0;
2263 	sim_vercurscope[0] = 0;
2264 	sim_verlineno = 0;
2265 	sim_vercurlevel = 0;
2266 	numsignals = 0;
2267 	verhash = 0;
2268 	hashtablesize = 1;
2269 	vslast = NOVERSIGNAL;
2270 	sim_verfreesimdata();
2271 	sosymbol = newstringobj(sim_tool->cluster);
2272 	soname = newstringobj(sim_tool->cluster);
2273 	socontext = newstringobj(sim_tool->cluster);
2274 	for(;;)
2275 	{
2276 		if (xfgets(sim_verline, 300, sim_verfd)) break;
2277 		sim_verlineno++;
2278 		if ((sim_verlineno%100) == 0)
2279 		{
2280 			if (stopping(STOPREASONSIMULATE)) break;
2281 			curposition = xtell(sim_verfd);
2282 			DiaSetProgress(sim_verprogressdialog, curposition, sim_verfilesize);
2283 		}
2284 
2285 		/* accumulate the scope name */
2286 		pt = sim_verline;
2287 		keyword = getkeyword(&pt, x_(" "));
2288 		if (keyword == NOSTRING) continue;
2289 
2290 		/* ignore "$date", "$version" or "$timescale" */
2291 		if (namesame(keyword, x_("$date")) == 0 ||
2292 			namesame(keyword, x_("$version")) == 0)
2293 		{
2294 			sim_verparsetoend(&pt);
2295 			continue;
2296 		}
2297 		if (namesame(keyword, x_("$timescale")) == 0)
2298 		{
2299 			if (xfgets(sim_verline, 300, sim_verfd)) break;
2300 			sim_verlineno++;
2301 			units = -1;
2302 			pt = sim_verline;
2303 			keyword = getkeyword(&pt, x_(" "));
2304 			for(pt = keyword; *pt != 0; pt++)
2305 				if (!isdigit(*pt)) break;
2306 			if (*pt == 0)
2307 			{
2308 				ttyputerr(_("No time units on line %ld"), pt, sim_verlineno);
2309 			} else
2310 			{
2311 				if (namesame(pt, "ps") == 0) units = INTTIMEUNITPSEC; else
2312 				if (namesame(pt, "s") == 0) units = INTTIMEUNITSEC; else
2313 					ttyputerr(_("Unknown time units: '%s' on line %ld"), pt, sim_verlineno);
2314 			}
2315 			if (units >= 0)
2316 			{
2317 				*pt = 0;
2318 				sim_timescale = figureunits(keyword, VTUNITSTIME, units);
2319 			}
2320 			sim_verparsetoend(&pt);
2321 			continue;
2322 		}
2323 		if (namesame(keyword, x_("$scope")) == 0)
2324 		{
2325 			keyword = getkeyword(&pt, x_(" "));
2326 			if (keyword != NOSTRING)
2327 			{
2328 				if (namesame(keyword, x_("module")) == 0 || namesame(keyword, x_("task")) == 0 ||
2329 					namesame(keyword, x_("function")) == 0)
2330 				{
2331 					keyword = getkeyword(&pt, x_(" "));
2332 					if (keyword != NOSTRING)
2333 					{
2334 						if (sim_vercurscope[0] != 0) strcat(sim_vercurscope, x_("."));
2335 						strcat(sim_vercurscope, keyword);
2336 						sim_vercurlevel++;
2337 					}
2338 				}
2339 				sim_verparsetoend(&pt);
2340 			}
2341 			continue;
2342 		}
2343 
2344 		if (namesame(keyword, x_("$upscope")) == 0)
2345 		{
2346 			if (sim_vercurlevel <= 0 || sim_vercurscope[0] == 0)
2347 			{
2348 				ttyputerr(_("Unbalanced $upscope on line %ld"), sim_verlineno);
2349 				continue;
2350 			} else
2351 			{
2352 				len = strlen(sim_vercurscope);
2353 				for(i=len-1; i>0; i--) if (sim_vercurscope[i] == '.') break;
2354 				if (sim_vercurscope[i] == '.') sim_vercurscope[i] = 0;
2355 				sim_vercurlevel--;
2356 			}
2357 			sim_verparsetoend(&pt);
2358 			continue;
2359 		}
2360 
2361 		if (namesame(keyword, x_("$var")) == 0)
2362 		{
2363 			keyword = getkeyword(&pt, x_(" "));
2364 			if (keyword != NOSTRING)
2365 			{
2366 				if (namesame(keyword, x_("wire")) == 0 ||
2367 					namesame(keyword, x_("supply0")) == 0 ||
2368 					namesame(keyword, x_("supply1")) == 0 ||
2369 					namesame(keyword, x_("reg")) == 0 ||
2370 					namesame(keyword, x_("parameter")) == 0 ||
2371 					namesame(keyword, x_("trireg")) == 0)
2372 				{
2373 					/* get the bus width */
2374 					keyword = getkeyword(&pt, x_(" "));
2375 					if (keyword == NOSTRING) continue;
2376 					width = myatoi(keyword);
2377 
2378 					/* get the symbol name for this signal */
2379 					keyword = getkeyword(&pt, x_(" "));
2380 					if (keyword == NOSTRING) continue;
2381 					clearstringobj(sosymbol);
2382 					addstringtostringobj(keyword, sosymbol);
2383 
2384 					/* get the signal name */
2385 					keyword = getkeyword(&pt, x_(" "));
2386 					if (keyword == NOSTRING) continue;
2387 					clearstringobj(soname);
2388 					addstringtostringobj(keyword, soname);
2389 
2390 					/* see if there is an index */
2391 					keyword = getkeyword(&pt, x_(" "));
2392 					if (keyword == NOSTRING) continue;
2393 					foundend = FALSE;
2394 					if (namesame(keyword, x_("$end")) == 0) foundend = TRUE; else
2395 						addstringtostringobj(keyword, soname);
2396 
2397 					/* set the context */
2398 					clearstringobj(socontext);
2399 					addstringtostringobj(sim_vercurscope, socontext);
2400 
2401 					/* allocate one big object with structure and names */
2402 					structlen = sizeof (VERSIGNAL);
2403 					symbol = getstringobj(sosymbol);   symbollen = (estrlen(symbol)+1) * SIZEOFCHAR;
2404 					name = getstringobj(soname);       namelen = (estrlen(name)+1) * SIZEOFCHAR;
2405 					context = getstringobj(socontext); contextlen = (estrlen(context)+1) * SIZEOFCHAR;
2406 					structsize = structlen + symbollen + namelen + contextlen;
2407 					onestruct = (UCHAR1 *)emalloc(structsize, sim_tool->cluster);
2408 					if (onestruct == 0) continue;
2409 					vs = (VERSIGNAL *)onestruct;
2410 					vs->symbol = (CHAR *)&onestruct[structlen];
2411 					vs->signalname = (CHAR *)&onestruct[structlen+symbollen];
2412 					vs->signalcontext = (CHAR *)&onestruct[structlen+symbollen+namelen];
2413 					strcpy(vs->symbol, symbol);
2414 					strcpy(vs->signalname, name);
2415 					strcpy(vs->signalcontext, context);
2416 					vs->nextversignal = NOVERSIGNAL;
2417 					if (vslast == NOVERSIGNAL) sim_verfirstsignal = vs; else
2418 						vslast->nextversignal = vs;
2419 					vslast = vs;
2420 					vs->level = sim_vercurlevel;
2421 					vs->flags = 0;
2422 					vs->signal = 0;
2423 					vs->total = 0;
2424 					vs->count = 0;
2425 					vs->width = width;
2426 					vs->realversignal = NOVERSIGNAL;
2427 					numsignals++;
2428 
2429 					if (width > 1)
2430 					{
2431 						/* create fake signals for the individual entries */
2432 						vslist = (VERSIGNAL **)emalloc(width * (sizeof (VERSIGNAL *)), sim_tool->cluster);
2433 						if (vslist == 0) continue;
2434 						vs->signals = vslist;
2435 						for(i=0; i<width; i++)
2436 						{
2437 							structlen = sizeof (VERSIGNAL);
2438 							infstr = initinfstr();
2439 							formatinfstr(infstr, x_("%s[%ld]"), vs->signalname, i);
2440 							name = returninfstr(infstr);       namelen = (estrlen(name)+1) * SIZEOFCHAR;
2441 							context = sim_vercurscope;         contextlen = (estrlen(context)+1) * SIZEOFCHAR;
2442 							structsize = structlen + namelen + contextlen;
2443 							onestruct = (UCHAR1 *)emalloc(structsize, sim_tool->cluster);
2444 							if (onestruct == 0) break;
2445 							subvs = (VERSIGNAL *)onestruct;
2446 							subvs->symbol = 0;
2447 							subvs->signalname = (CHAR *)&onestruct[structlen];
2448 							subvs->signalcontext = (CHAR *)&onestruct[structlen+namelen];
2449 							strcpy(subvs->signalname, name);
2450 							strcpy(subvs->signalcontext, context);
2451 							subvs->nextversignal = NOVERSIGNAL;
2452 							if (vslast == NOVERSIGNAL) sim_verfirstsignal = subvs; else
2453 								vslast->nextversignal = subvs;
2454 							vslast = subvs;
2455 							subvs->level = sim_vercurlevel;
2456 							subvs->flags = 0;
2457 							subvs->signal = 0;
2458 							subvs->total = 0;
2459 							subvs->count = 0;
2460 							subvs->width = 1;
2461 							subvs->realversignal = NOVERSIGNAL;
2462 							vslist[i] = subvs;
2463 							numsignals++;
2464 						}
2465 					}
2466 					if (foundend) continue;
2467 				} else
2468 				{
2469 					ttyputerr(_("Invalid $var on line %ld: %s"), sim_verlineno, sim_verline);
2470 					continue;
2471 				}
2472 			}
2473 			sim_verparsetoend(&pt);
2474 			continue;
2475 		}
2476 
2477 		if (namesame(keyword, x_("$enddefinitions")) == 0)
2478 		{
2479 			sim_verparsetoend(&pt);
2480 			infstr = initinfstr();
2481 			formatinfstr(infstr, _("Found %ld signal names"), numsignals);
2482 			DiaSetTextProgress(sim_verprogressdialog, _("Building signal table..."));
2483 			DiaSetCaptionProgress(sim_verprogressdialog, returninfstr(infstr));
2484 
2485 			/* build a table for finding signal names */
2486 			for(i=0; i<256; i++) sim_charused[i] = -1;
2487 			sim_numcharsused = 0;
2488 			for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
2489 			{
2490 				if (vs->symbol == 0) continue;
2491 				for(pt = vs->symbol; *pt != 0; pt++)
2492 				{
2493 					i = *pt & 0xFF;
2494 					if (sim_charused[i] < 0)
2495 						sim_charused[i] = ++sim_numcharsused;
2496 				}
2497 			}
2498 
2499 			hashtablesize = pickprime(numsignals*2);
2500 			verhash = (VERSIGNAL **)emalloc(hashtablesize * (sizeof (VERSIGNAL *)), sim_tool->cluster);
2501 			if (verhash == 0) return;
2502 			for(i=0; i<hashtablesize; i++) verhash[i] = NOVERSIGNAL;
2503 
2504 			/* insert the signals */
2505 			for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
2506 			{
2507 				if (vs->symbol == 0) continue;
2508 				hashcode = sim_vergetsignalhash(vs->symbol) % hashtablesize;
2509 				for(i=0; i<hashtablesize; i++)
2510 				{
2511 					if (verhash[hashcode] == NOVERSIGNAL)
2512 					{
2513 						verhash[hashcode] = vs;
2514 						break;
2515 					}
2516 					if (strcmp(vs->symbol, verhash[hashcode]->symbol) == 0)
2517 					{
2518 						/* same symbol name: merge the signals */
2519 						vs->realversignal = verhash[hashcode];
2520 						break;
2521 					}
2522 					hashcode++;
2523 					if (hashcode >= hashtablesize) hashcode = 0;
2524 				}
2525 			}
2526 			DiaSetTextProgress(sim_verprogressdialog, _("Reading stimulus..."));
2527 			continue;
2528 		}
2529 		if (namesame(keyword, x_("$dumpvars")) == 0)
2530 		{
2531 			curtime = 0.0;
2532 			for(;;)
2533 			{
2534 				if (xfgets(sim_verline, 300, sim_verfd)) break;
2535 				sim_verlineno++;
2536 				if ((sim_verlineno%1000) == 0)
2537 				{
2538 					if (stopping(STOPREASONSIMULATE)) break;
2539 					curposition = xtell(sim_verfd);
2540 					DiaSetProgress(sim_verprogressdialog, curposition, sim_verfilesize);
2541 				}
2542 				if (sim_verline[0] == '0' || sim_verline[0] == '1' ||
2543 					sim_verline[0] == 'x' || sim_verline[0] == 'z')
2544 				{
2545 					symname = &sim_verline[1];
2546 					hashcode = sim_vergetsignalhash(symname) % hashtablesize;
2547 					vs = NOVERSIGNAL;
2548 					for(i=0; i<hashtablesize; i++)
2549 					{
2550 						vs = verhash[hashcode];
2551 						if (vs == NOVERSIGNAL) break;
2552 						if (strcmp(symname, vs->symbol) == 0) break;
2553 						hashcode++;
2554 						if (hashcode >= hashtablesize) hashcode = 0;
2555 					}
2556 					if (vs == NOVERSIGNAL)
2557 					{
2558 						ttyputmsg(_("Unknown symbol '%s' on line %ld"), symname, sim_verlineno);
2559 						continue;
2560 					}
2561 
2562 					/* insert the stimuli */
2563 					switch (sim_verline[0])
2564 					{
2565 						case '0': state = (LOGIC_LOW << 8) | GATE_STRENGTH;   break;
2566 						case '1': state = (LOGIC_HIGH << 8) | GATE_STRENGTH;  break;
2567 						case 'x': state = (LOGIC_X << 8) | GATE_STRENGTH;     break;
2568 						case 'z': state = (LOGIC_Z << 8) | GATE_STRENGTH;     break;
2569 					}
2570 					sim_versetvalue(vs, curtime, state);
2571 					continue;
2572 				}
2573 				if (sim_verline[0] == '$')
2574 				{
2575 					if (namesame(&sim_verline[0], x_("$end")) == 0) continue;
2576 					ttyputmsg(_("Unknown directive on line %ld: %s"), sim_verlineno, sim_verline);
2577 					continue;
2578 				}
2579 				if (sim_verline[0] == '#')
2580 				{
2581 					curtime = myatoi(&sim_verline[1]) * sim_timescale;
2582 					continue;
2583 				}
2584 				if (sim_verline[0] == 'b')
2585 				{
2586 					for(pt = &sim_verline[1]; *pt != 0; pt++)
2587 						if (*pt == ' ') break;
2588 					if (*pt == 0)
2589 					{
2590 						ttyputmsg(_("Bus has missing signal name on line %ld: %s"), sim_verlineno, sim_verline);
2591 						continue;
2592 					}
2593 					symname = &pt[1];
2594 					hashcode = sim_vergetsignalhash(symname) % hashtablesize;
2595 					vs = NOVERSIGNAL;
2596 					for(i=0; i<hashtablesize; i++)
2597 					{
2598 						vs = verhash[hashcode];
2599 						if (vs == NOVERSIGNAL) break;
2600 						if (strcmp(symname, vs->symbol) == 0) break;
2601 						hashcode++;
2602 						if (hashcode >= hashtablesize) hashcode = 0;
2603 					}
2604 					if (vs == NOVERSIGNAL)
2605 					{
2606 						ttyputmsg(_("Unknown symbol '%s' on line %ld"), symname, sim_verlineno);
2607 						continue;
2608 					}
2609 					for(i=0; i<vs->width; i++)
2610 					{
2611 						switch (sim_verline[i+1])
2612 						{
2613 							case '0': state = (LOGIC_LOW << 8) | GATE_STRENGTH;   break;
2614 							case '1': state = (LOGIC_HIGH << 8) | GATE_STRENGTH;  break;
2615 							case 'x': state = (LOGIC_X << 8) | GATE_STRENGTH;     break;
2616 							case 'z': state = (LOGIC_Z << 8) | GATE_STRENGTH;     break;
2617 						}
2618 						sim_versetvalue(vs->signals[i], curtime, state);
2619 					}
2620 					continue;
2621 				}
2622 				ttyputmsg(_("Unknown stimulus on line %ld: %s"), sim_verlineno, sim_verline);
2623 			}
2624 		}
2625 	}
2626 	DiaDoneProgress(sim_verprogressdialog);
2627 	xclose(sim_verfd);
2628 	if (verhash != 0) efree((CHAR *)verhash);
2629 	killstringobj(sosymbol);
2630 	killstringobj(soname);
2631 	killstringobj(socontext);
2632 
2633 	/* pick an associated cell */
2634 	if (cell == NONODEPROTO)
2635 	{
2636 		i = ttygetparam(_("Please select a cell to associate with this dump file: "),
2637 			&us_showdp, 3, pars);
2638 		if (i > 0) cell = getnodeproto(pars[0]);
2639 		if (cell == NONODEPROTO) return;
2640 	}
2641 
2642 	/* remember signal list stored on this cell */
2643 	sim_window_grabcachedsignalsoncell(cell);
2644 
2645 	/* display the waveform window */
2646 	i = sim_window_isactive(&np);
2647 	if ((i&SIMWINDOWWAVEFORM) == 0)
2648 	{
2649 		if (i != 0 && np != cell)
2650 		{
2651 			/* stop simulation of cell "np" */
2652 			sim_window_stopsimulation();
2653 		}
2654 		if (sim_window_create(0, cell,
2655 			((sim_window_state&SHOWWAVEFORM) != 0 ? sim_vercharhandlerwave : 0),
2656 				us_charhandler, IRSIM)) return;
2657 		sim_window_state = (sim_window_state & ~SIMENGINECUR) | SIMENGINECURVERILOG;
2658 		sim_window_settimerange(0, 0.0, DEFIRSIMTIMERANGE);
2659 		sim_window_setmaincursor(DEFIRSIMTIMERANGE/5.0*2.0);
2660 		sim_window_setextensioncursor(DEFIRSIMTIMERANGE/5.0*3.0);
2661 	}
2662 
2663 	/* find a subcell and set the initial simulation level from it */
2664 	sim_vercurlevel = -1;
2665 	for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2666 	{
2667 		if (ni->proto->primindex != 0) continue;
2668 		if (isiconof(ni->proto, cell)) continue;
2669 		var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
2670 		if (var != NOVARIABLE)
2671 		{
2672 			nodename = (CHAR *)var->addr;
2673 			for(sim_vercurlevel=2; sim_vercurlevel<4; sim_vercurlevel++)
2674 			{
2675 				foundlevel = FALSE;
2676 				for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
2677 				{
2678 					if (vs->level != sim_vercurlevel) continue;
2679 					foundlevel = TRUE;
2680 					estrcpy(sim_vercurscope, vs->signalcontext);
2681 					len = estrlen(sim_vercurscope);
2682 					for(i=len-1; i>0; i--) if (sim_vercurscope[i] == '.') break;
2683 					if (i < 0) continue;
2684 					if (namesame(&sim_vercurscope[i+1], nodename) == 0) break;
2685 				}
2686 				if (!foundlevel)
2687 				{
2688 					sim_vercurlevel = -1;
2689 					break;
2690 				}
2691 				if (vs != NOVERSIGNAL)
2692 				{
2693 					sim_vercurlevel--;
2694 					sim_vercurscope[i] = 0;
2695 					break;
2696 				}
2697 			}
2698 			if (sim_vercurlevel >= 0 && sim_vercurlevel < 4) break;
2699 		}
2700 	}
2701 	if (sim_vercurlevel < 0)
2702 	{
2703 		/* no subcell found: just start at the top level */
2704 		sim_vercurlevel = 1;
2705 		for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
2706 		{
2707 			if (vs->level != sim_vercurlevel) continue;
2708 			estrcpy(sim_vercurscope, vs->signalcontext);
2709 			break;
2710 		}
2711 	}
2712 	sim_verignoresigname = sim_vercurlevel - 1;
2713 
2714 	/* show current level */
2715 	sim_vershowcurrentlevel(cell);
2716 	sim_window_gettimeextents(&min, &max);
2717 	sim_window_settimerange(0, min, max);
2718 	sim_window_redraw();
2719 }
2720 
sim_versetvalue(VERSIGNAL * vs,double curtime,INTSML state)2721 void sim_versetvalue(VERSIGNAL *vs, double curtime, INTSML state)
2722 {
2723 	REGISTER INTBIG newtotal, i;
2724 	REGISTER INTSML *newstate;
2725 	REGISTER double *newtime;
2726 
2727 	if (vs->count >= vs->total)
2728 	{
2729 		newtotal = vs->total * 2;
2730 		if (vs->count >= newtotal) newtotal = vs->count + 50;
2731 		newtime = (double *)emalloc(newtotal * (sizeof (double)), sim_tool->cluster);
2732 		newstate = (INTSML *)emalloc(newtotal * SIZEOFINTSML, sim_tool->cluster);
2733 		if (newtime == 0 || newstate == 0) return;
2734 		for(i=0; i<vs->count; i++)
2735 		{
2736 			newtime[i] = vs->stimtime[i];
2737 			newstate[i] = vs->stimstate[i];
2738 		}
2739 		if (vs->total > 0)
2740 		{
2741 			efree((CHAR *)vs->stimtime);
2742 			efree((CHAR *)vs->stimstate);
2743 		}
2744 		vs->total = newtotal;
2745 		vs->stimtime = newtime;
2746 		vs->stimstate = newstate;
2747 	}
2748 	vs->stimtime[vs->count] = curtime;
2749 	vs->stimstate[vs->count] = state;
2750 	vs->count++;
2751 }
2752 
sim_vergetsignalhash(CHAR * name)2753 INTBIG sim_vergetsignalhash(CHAR *name)
2754 {
2755 	REGISTER INTBIG value, index, i, len;
2756 
2757 	value = 0;
2758 	len = estrlen(name);
2759 	for(i=len-1; i>=0; i--)
2760 	{
2761 		index = sim_charused[name[i] & 0xFF];
2762 		value = (value * sim_numcharsused) + index;
2763 	}
2764 	return(value);
2765 }
2766 
sim_vershowcurrentlevel(NODEPROTO * cell)2767 void sim_vershowcurrentlevel(NODEPROTO *cell)
2768 {
2769 	REGISTER INTBIG tot, i, j, buscount, plainnet, numnets, namednet, shownsignals,
2770 		busprefixlen, oldsigcount;
2771 	REGISTER CHAR *pt, *opt, *start, save, *name, *busprefix;
2772 	CHAR **oldsignames;
2773 	REGISTER void *infstr;
2774 	REGISTER VERSIGNAL *vs, **netlist, *realvs, *subvs;
2775 	INTBIG *bussignals;
2776 	Q_UNUSED( cell );
2777 
2778 	/* show the waveform window */
2779 	sim_window_cleartracehighlight();
2780 	sim_window_killalltraces(FALSE);
2781 	infstr = initinfstr();
2782 	formatinfstr(infstr, _("level=%s"), sim_vercurscope);
2783 	pt = returninfstr(infstr);
2784 	for(j=0; j<sim_verignoresigname; j++)
2785 	{
2786 		while (*pt != 0 && *pt != '.') pt++;
2787 		if (*pt == '.') pt++;
2788 	}
2789 	sim_window_titleinfo(pt);
2790 	for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
2791 	{
2792 		vs->flags &= ~VERSIGNALSHOWN;
2793 		vs->signal = 0;
2794 	}
2795 	/* first show the signals saved from last time */
2796 	oldsigcount = sim_window_getcachedsignals(&oldsignames);
2797 	shownsignals = 0;
2798 	for(j=0; j<oldsigcount; j++)
2799 	{
2800 		/* see if the name is a bus */
2801 		for(pt = oldsignames[j]; *pt != 0; pt++) if (*pt == '\t') break;
2802 		if (*pt == '\t')
2803 		{
2804 			/* a bus */
2805 			pt++;
2806 			sim_initbussignals();
2807 			for(;;)
2808 			{
2809 				for(start = pt; *pt != 0; pt++) if (*pt == '\t') break;
2810 				save = *pt;
2811 				*pt = 0;
2812 				opt = start;
2813 				if (*opt == '-') opt++;
2814 				for( ; *opt != 0; opt++)
2815 					if (!isdigit(*opt) || *opt == ':') break;
2816 				if (*opt == ':') start = opt+1;
2817 				for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
2818 				{
2819 					name = vs->signalname;
2820 					if (namesame(name, start) != 0) continue;
2821 					realvs = vs;
2822 					if (vs->realversignal != NOVERSIGNAL) realvs = vs->realversignal;
2823 					if ((realvs->flags&VERSIGNALSHOWN) != 0) continue;
2824 
2825 					realvs->signal = sim_window_newtrace(-1, name, (INTBIG)realvs);
2826 					sim_window_loaddigtrace(realvs->signal, realvs->count, realvs->stimtime, realvs->stimstate);
2827 					realvs->flags |= VERSIGNALSHOWN;
2828 					sim_addbussignal(realvs->signal);
2829 					shownsignals++;
2830 					break;
2831 				}
2832 				*pt++ = save;
2833 				if (save == 0) break;
2834 			}
2835 
2836 			/* create the bus */
2837 			infstr = initinfstr();
2838 			for(pt = oldsignames[j]; *pt != 0; pt++)
2839 			{
2840 				if (*pt == '\t') break;
2841 				addtoinfstr(infstr, *pt);
2842 			}
2843 			pt = returninfstr(infstr);
2844 			buscount = sim_getbussignals(&bussignals);
2845 			(void)sim_window_makebus(buscount, bussignals, pt);
2846 		} else
2847 		{
2848 			/* a single signal */
2849 			pt = oldsignames[j];
2850 			if (*pt == '-') pt++;
2851 			for( ; *pt != 0; pt++)
2852 				if (!isdigit(*pt) || *pt == ':') break;
2853 			if (*pt == ':') pt++; else pt = oldsignames[j];
2854 			for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
2855 			{
2856 				name = vs->signalname;
2857 				if (namesame(name, pt) != 0) continue;
2858 				realvs = vs;
2859 				if (vs->realversignal != NOVERSIGNAL) realvs = vs->realversignal;
2860 				if ((realvs->flags&VERSIGNALSHOWN) != 0) continue;
2861 
2862 				realvs->signal = sim_window_newtrace(-1, name, (INTBIG)realvs);
2863 				sim_window_loaddigtrace(realvs->signal, realvs->count, realvs->stimtime, realvs->stimstate);
2864 				realvs->flags |= VERSIGNALSHOWN;
2865 				shownsignals++;
2866 				break;
2867 			}
2868 		}
2869 	}
2870 
2871 	/* show default signals if none are cached */
2872 	if (oldsigcount == 0)
2873 	{
2874 		/* see how many signals of each type are left */
2875 		plainnet = namednet = 0;
2876 		for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
2877 		{
2878 			if (vs->symbol == 0) continue;
2879 			if (vs->level != sim_vercurlevel) continue;
2880 			if (estrcmp(sim_vercurscope, vs->signalcontext) != 0) continue;
2881 			realvs = vs;
2882 			if (vs->realversignal != NOVERSIGNAL) realvs = vs->realversignal;
2883 			if ((realvs->flags&VERSIGNALSHOWN) != 0) continue;
2884 			if (namesamen(vs->signalname, x_("net"), 3) == 0) plainnet++; else
2885 				namednet++;
2886 		}
2887 		numnets = namednet;
2888 		if (numnets == 0 && shownsignals == 0)
2889 			numnets = plainnet;
2890 		if (numnets > 0)
2891 		{
2892 			netlist = (VERSIGNAL **)emalloc(numnets * (sizeof (VERSIGNAL *)), sim_tool->cluster);
2893 			if (netlist == 0) return;
2894 			tot = 0;
2895 			for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
2896 			{
2897 				if (vs->symbol == 0) continue;
2898 				if (vs->level != sim_vercurlevel) continue;
2899 				if (estrcmp(sim_vercurscope, vs->signalcontext) != 0) continue;
2900 				realvs = vs;
2901 				if (vs->realversignal != NOVERSIGNAL) realvs = vs->realversignal;
2902 				if ((realvs->flags&VERSIGNALSHOWN) != 0) continue;
2903 				if (namednet > 0)
2904 				{
2905 					if (namesamen(vs->signalname, x_("net"), 3) == 0) continue;
2906 				}
2907 				netlist[tot++] = vs;
2908 			}
2909 			esort(netlist, tot, sizeof (VERSIGNAL *), sim_versortsignalnames);
2910 			busprefixlen = 0;
2911 			busprefix = 0;
2912 			sim_initbussignals();
2913 			for(j=0; j<tot; j++)
2914 			{
2915 				vs = netlist[j];
2916 				realvs = vs;
2917 				if (vs->realversignal != NOVERSIGNAL) realvs = vs->realversignal;
2918 
2919 				/* if in a bus, see if it is done */
2920 				if (busprefixlen > 0 && (namesamen(vs->signalname, busprefix, busprefixlen) != 0 ||
2921 					vs->signalname[busprefixlen] != '[' || realvs->width > 1))
2922 				{
2923 					buscount = sim_getbussignals(&bussignals);
2924 					save = busprefix[busprefixlen];
2925 					busprefix[busprefixlen] = 0;
2926 					(void)sim_window_makebus(buscount, bussignals, busprefix);
2927 					busprefix[busprefixlen] = save;
2928 					busprefixlen = 0;
2929 					sim_initbussignals();
2930 				}
2931 				if (realvs->width > 1)
2932 				{
2933 					/* show a bus */
2934 					sim_initbussignals();
2935 					for(i=0; i<realvs->width; i++)
2936 					{
2937 						subvs = realvs->signals[i];
2938 						subvs->signal = sim_window_newtrace(-1, subvs->signalname, (INTBIG)subvs);
2939 						sim_window_loaddigtrace(subvs->signal, subvs->count, subvs->stimtime, subvs->stimstate);
2940 						subvs->flags |= VERSIGNALSHOWN;
2941 						sim_addbussignal(subvs->signal);
2942 					}
2943 					buscount = sim_getbussignals(&bussignals);
2944 					(void)sim_window_makebus(buscount, bussignals, vs->signalname);
2945 					sim_initbussignals();
2946 				} else
2947 				{
2948 					realvs->signal = sim_window_newtrace(-1, vs->signalname, (INTBIG)realvs);
2949 					sim_window_loaddigtrace(realvs->signal, realvs->count, realvs->stimtime, realvs->stimstate);
2950 					realvs->flags |= VERSIGNALSHOWN;
2951 					if (busprefixlen == 0)
2952 					{
2953 						for(i=0; vs->signalname[i] != 0; i++)
2954 							if (vs->signalname[i] == '[') break;
2955 						if (vs->signalname[i] == '[')
2956 						{
2957 							busprefix = vs->signalname;
2958 							busprefixlen = i;
2959 							sim_addbussignal(realvs->signal);
2960 						}
2961 					} else sim_addbussignal(realvs->signal);
2962 				}
2963 			}
2964 			if (busprefixlen > 0)
2965 			{
2966 				buscount = sim_getbussignals(&bussignals);
2967 				save = busprefix[busprefixlen];
2968 				busprefix[busprefixlen] = 0;
2969 				(void)sim_window_makebus(buscount, bussignals, busprefix);
2970 				busprefix[busprefixlen] = save;
2971 			}
2972 			efree((CHAR *)netlist);
2973 		}
2974 	}
2975 
2976 	sim_window_redraw();
2977 }
2978 
sim_versortsignalnames(const void * e1,const void * e2)2979 int sim_versortsignalnames(const void *e1, const void *e2)
2980 {
2981 	VERSIGNAL *vs1, *vs2;
2982 
2983 	vs1 = *((VERSIGNAL **)e1);
2984 	vs2 = *((VERSIGNAL **)e2);
2985 	return(namesamenumeric(vs1->signalname, vs2->signalname));
2986 }
2987 
sim_verparsetoend(CHAR ** pt)2988 void sim_verparsetoend(CHAR **pt)
2989 {
2990 	REGISTER CHAR *keyword;
2991 
2992 	for(;;)
2993 	{
2994 		keyword = getkeyword(pt, x_(" "));
2995 		if (keyword == NOSTRING) return;
2996 		if (*keyword == 0)
2997 		{
2998 			if (stopping(STOPREASONSIMULATE)) break;
2999 			if (xfgets(sim_verline, 300, sim_verfd)) break;
3000 			sim_verlineno++;
3001 			*pt = sim_verline;
3002 			continue;
3003 		}
3004 		if (namesame(keyword, x_("$end")) == 0) return;
3005 	}
3006 }
3007 
3008 /*
3009  * The character handler for the waveform window of ALS simulation
3010  */
sim_vercharhandlerwave(WINDOWPART * w,INTSML chr,INTBIG special)3011 BOOLEAN sim_vercharhandlerwave(WINDOWPART *w, INTSML chr, INTBIG special)
3012 {
3013 	NODEPROTO *np;
3014 	REGISTER INTBIG *highsigs, highsig, i, j, thispos, *bussigs,
3015 		trl, nexttr, prevtr, pos, buscount;
3016 	REGISTER VERSIGNAL *vs;
3017 
3018 	ttynewcommand();
3019 
3020 	/* special characters are not handled here */
3021 	if (special != 0)
3022 		return(us_charhandler(w, chr, special));
3023 
3024 	/* can always preserve snapshot */
3025 	if (chr == 'p')
3026 	{
3027 		sim_window_savegraph();
3028 		return(FALSE);
3029 	}
3030 
3031 	/* can always do help */
3032 	if (chr == '?')
3033 	{
3034 		sim_verhelpwindow();
3035 		return(FALSE);
3036 	}
3037 
3038 	/* if not simulating, don't handle any simulation commands */
3039 	if (sim_window_isactive(&np) == 0)
3040 		return(us_charhandler(w, chr, special));
3041 	switch (chr)
3042 	{
3043 		/* convert busses */
3044 		case 'b':
3045 			if (sim_window_buscommand()) return(FALSE);
3046 			highsigs = sim_window_gethighlighttraces();
3047 			return(FALSE);
3048 
3049 		/* add trace */
3050 		case 'a':
3051 			sim_veraddsignals();
3052 			return(FALSE);
3053 
3054 		case 'i':
3055 		case 'r':
3056 		case DELETEKEY:
3057 			break;
3058 		default:
3059 			return(FALSE);
3060 	}
3061 
3062 	/* the following commands demand a current trace...get it */
3063 	highsigs = sim_window_gethighlighttraces();
3064 	if (highsigs[0] == 0)
3065 	{
3066 		ttyputerr(_("Select a signal name first"));
3067 		return(FALSE);
3068 	}
3069 	if (chr == 'i')
3070 	{
3071 		for(j=0; highsigs[j] != 0; j++)
3072 		{
3073 			highsig = highsigs[j];
3074 			vs = (VERSIGNAL *)sim_window_gettracedata(highsig);
3075 			ttyputmsg("Signal %s has %d stimuli on it:", vs->signalname, vs->count);
3076 			for(i=0; i<vs->count; i++)
3077 			{
3078 				ttyputmsg("  %d at time %s (%g)", vs->stimstate[i],
3079 					sim_windowconvertengineeringnotation(vs->stimtime[i]), vs->stimtime[i]);
3080 			}
3081 		}
3082 		return(FALSE);
3083 	}
3084 	if (chr == 'r' || chr == DELETEKEY)		/* remove trace(s) */
3085 	{
3086 		sim_window_cleartracehighlight();
3087 
3088 		/* delete them */
3089 		nexttr = prevtr = 0;
3090 		for(j=0; highsigs[j] != 0; j++)
3091 		{
3092 			highsig = highsigs[j];
3093 			thispos = sim_window_gettraceframe(highsig);
3094 			bussigs = sim_window_getbustraces(highsig);
3095 			for(buscount=0; bussigs[buscount] != 0; buscount++) ;
3096 			sim_window_inittraceloop();
3097 			nexttr = prevtr = 0;
3098 			for(;;)
3099 			{
3100 				trl = sim_window_nexttraceloop();
3101 				if (trl == 0) break;
3102 				pos = sim_window_gettraceframe(trl);
3103 				if (pos > thispos)
3104 				{
3105 					if (pos-1 == thispos) nexttr = trl;
3106 					pos = pos - 1 + buscount;
3107 					sim_window_settraceframe(trl, pos);
3108 				} else if (pos == thispos-1) prevtr = trl;
3109 			}
3110 			if (buscount > 0)
3111 			{
3112 				for(i=0; i<buscount; i++)
3113 					sim_window_settraceframe(bussigs[i], thispos+i);
3114 			}
3115 
3116 			/* remove from the simulator's list */
3117 			for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
3118 			{
3119 				if (vs->signal == highsig)
3120 				{
3121 					vs->signal = 0;
3122 					break;
3123 				}
3124 			}
3125 
3126 			/* kill trace */
3127 			sim_window_killtrace(highsig);
3128 		}
3129 
3130 		/* redraw */
3131 		if (nexttr != 0)
3132 		{
3133 			sim_window_addhighlighttrace(nexttr);
3134 		} else if (prevtr != 0)
3135 		{
3136 			sim_window_addhighlighttrace(prevtr);
3137 		}
3138 		sim_window_redraw();
3139 		return(FALSE);
3140 	}
3141 
3142 	return(FALSE);
3143 }
3144 
3145 /* Simulation Signal Selection */
3146 static DIALOGITEM sim_sigselectdialogitems[] =
3147 {
3148  /*  1 */ {0, {344,276,368,356}, BUTTON, N_("OK")},
3149  /*  2 */ {0, {344,184,368,264}, BUTTON, N_("Cancel")},
3150  /*  3 */ {0, {4,4,336,356}, SCROLLMULTI, x_("")},
3151  /*  4 */ {0, {348,4,364,176}, CHECK, N_("Show lower levels")}
3152 };
3153 static DIALOG sim_sigselectdialog = {{75,75,452,441}, N_("Select Signal for Simulation"), 0, 4, sim_sigselectdialogitems, 0, 0};
3154 
3155 /* special items for the "Simulation Signal Selection" dialog: */
3156 #define DSSS_LIST            3		/* list of signals (scroll) */
3157 #define DSSS_SHOWLOWER       4		/* show lower levels (check) */
3158 
3159 BOOLEAN sim_signalshowlower = FALSE;
3160 
3161 /*
3162  * Routine to prompt the user for signal names and add them to the waveform window.
3163  */
sim_veraddsignals(void)3164 void sim_veraddsignals(void)
3165 {
3166 	REGISTER void *infstr, *dia;
3167 	CHAR *pt;
3168 	REGISTER INTBIG i, traces, itemHit, *list;
3169 	REGISTER VERSIGNAL *vs;
3170 
3171 	dia = DiaInitDialog(&sim_sigselectdialog);
3172 	if (dia == 0) return;
3173 	DiaInitTextDialog(dia, DSSS_LIST, sim_vertopofsignals, sim_vernextsignals, DiaNullDlogDone, 0,
3174 		SCSELMOUSE|SCSELKEY|SCHORIZBAR);
3175 	if (sim_signalshowlower) DiaSetControl(dia, DSSS_SHOWLOWER, 1);
3176 	infstr = initinfstr();
3177 	formatinfstr(infstr, "Signal in %s", sim_vercurscope);
3178 	ttyputmsg("%s", returninfstr(infstr));
3179 	for(;;)
3180 	{
3181 		itemHit = DiaNextHit(dia);
3182 		if (itemHit == OK || itemHit == CANCEL) break;
3183 		if (itemHit == DSSS_SHOWLOWER)
3184 		{
3185 			sim_signalshowlower = !sim_signalshowlower;
3186 			if (sim_signalshowlower) DiaSetControl(dia, DSSS_SHOWLOWER, 1); else
3187 				DiaSetControl(dia, DSSS_SHOWLOWER, 0);
3188 			DiaLoadTextDialog(dia, DSSS_LIST, sim_vertopofsignals, sim_vernextsignals, DiaNullDlogDone, 0);
3189 			continue;
3190 		}
3191 	}
3192 
3193 	if (itemHit == OK)
3194 	{
3195 		list = DiaGetCurLines(dia, DSSS_LIST);
3196 		for(i=0; list[i] >= 0; i++)
3197 		{
3198 			pt = DiaGetScrollLine(dia, DSSS_LIST, list[i]);
3199 
3200 			/* find the signal */
3201 			for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
3202 			{
3203 				if (vs->signal != 0) continue;
3204 				if (namesame(vs->signalcontext, sim_vercurscope) != 0) continue;
3205 				if (namesame(vs->signalname, pt) == 0) break;
3206 			}
3207 			if (vs == NOVERSIGNAL)
3208 			{
3209 				for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
3210 				{
3211 					if (vs->signal != 0) continue;
3212 					infstr = initinfstr();
3213 					formatinfstr(infstr, x_("%s.%s"), vs->signalcontext, vs->signalname);
3214 					if (namesame(pt, returninfstr(infstr)) == 0) break;
3215 				}
3216 			}
3217 			if (vs == NOVERSIGNAL) continue;
3218 
3219 			/* ready to add: remove highlighting */
3220 			sim_window_cleartracehighlight();
3221 
3222 			/* count the number of traces */
3223 			sim_window_inittraceloop();
3224 			for(traces=0; ; traces++) if (sim_window_nexttraceloop() == 0) break;
3225 
3226 			/* create a new trace in the last slot */
3227 			vs->signal = sim_window_newtrace(-1, vs->signalname, (INTBIG)vs);
3228 			sim_window_addhighlighttrace(vs->signal);
3229 			sim_window_setnumframes(sim_window_getnumframes()+1);
3230 			sim_window_loaddigtrace(vs->signal, vs->count, vs->stimtime, vs->stimstate);
3231 		}
3232 	}
3233 	sim_window_redraw();
3234 	DiaDoneDialog(dia);
3235 }
3236 
sim_vertopofsignals(CHAR ** c)3237 BOOLEAN sim_vertopofsignals(CHAR **c)
3238 {
3239 	Q_UNUSED( c );
3240 	sim_verwindow_iter = sim_verfirstsignal;
3241 	return(TRUE);
3242 }
3243 
sim_vernextsignals(void)3244 CHAR *sim_vernextsignals(void)
3245 {
3246 	VERSIGNAL *vs;
3247 	REGISTER void *infstr;
3248 
3249 	for(;;)
3250 	{
3251 		vs = sim_verwindow_iter;
3252 		if (vs == NOVERSIGNAL) break;
3253 		sim_verwindow_iter = vs->nextversignal;
3254 		if (vs->signal != 0) continue;
3255 		if (vs->count <= 0) continue;
3256 		if (sim_signalshowlower)
3257 		{
3258 			if (vs->level < sim_vercurlevel) continue;
3259 			if (vs->level == sim_vercurlevel)
3260 			{
3261 				if (estrcmp(vs->signalcontext, sim_vercurscope) != 0) continue;
3262 				return(vs->signalname);
3263 			}
3264 			infstr = initinfstr();
3265 			formatinfstr(infstr, x_("%s.%s"), vs->signalcontext, vs->signalname);
3266 			return(returninfstr(infstr));
3267 		}
3268 		if (vs->level != sim_vercurlevel) continue;
3269 		if (estrcmp(vs->signalcontext, sim_vercurscope) != 0) continue;
3270 		return(vs->signalname);
3271 	}
3272 	return(0);
3273 }
3274 
sim_vertopofinstances(CHAR ** c)3275 BOOLEAN sim_vertopofinstances(CHAR **c)
3276 {
3277 	Q_UNUSED( c );
3278 	sim_verwindow_iter = sim_verfirstsignal;
3279 	sim_verwindow_lastiter = NOVERSIGNAL;
3280 	return(TRUE);
3281 }
3282 
sim_vernextinstance(void)3283 CHAR *sim_vernextinstance(void)
3284 {
3285 	VERSIGNAL *vs;
3286 	REGISTER INTBIG len, curlen, i;
3287 
3288 	curlen = estrlen(sim_vercurscope);
3289 	for(;;)
3290 	{
3291 		vs = sim_verwindow_iter;
3292 		if (vs == NOVERSIGNAL) break;
3293 		sim_verwindow_iter = vs->nextversignal;
3294 		if (vs->level != sim_vercurlevel+1) continue;
3295 		if (estrncmp(vs->signalcontext, sim_vercurscope, curlen) != 0) continue;
3296 		if (vs->signalcontext[curlen] != '.') continue;
3297 		if (sim_verwindow_lastiter != NOVERSIGNAL &&
3298 			strcmp(vs->signalcontext, sim_verwindow_lastiter->signalcontext) == 0) continue;
3299 		sim_verwindow_lastiter = vs;
3300 		len = estrlen(vs->signalcontext);
3301 		for(i=len-1; i>0; i--)
3302 			if (vs->signalcontext[i] == '.') break;
3303 		if (i > 0) i++;
3304 		return(&vs->signalcontext[i]);
3305 	}
3306 	return(0);
3307 }
3308 
sim_verhelpwindow(void)3309 void sim_verhelpwindow(void)
3310 {
3311 	NODEPROTO *np;
3312 	INTBIG active;
3313 
3314 	active = sim_window_isactive(&np);
3315 	if (active == 0)
3316 	{
3317 		ttyputmsg(_("There is no current simulation"));
3318 		return;
3319 	}
3320 
3321 	ttyputmsg(_("These keys may be typed in the Verilog Waveform window:"));
3322 	ttyputinstruction(x_(" a"), 5, _("Add signal to simulation window"));
3323 	ttyputinstruction(x_(" r"), 5, _("Remove signal from the window"));
3324 	ttyputinstruction(x_(" b"), 5, _("Combine selected signals into a bus"));
3325 	ttyputinstruction(x_(" p"), 5, _("Preserve snapshot of simulation window in database"));
3326 }
3327 
3328 /*
3329  * Routine to move down the hierarchy into instance "level" and show
3330  * signals at that level.
3331  */
sim_verlevel_set(CHAR * level,NODEPROTO * cell)3332 void sim_verlevel_set(CHAR *level, NODEPROTO *cell)
3333 {
3334 	REGISTER VERSIGNAL *vs;
3335 	REGISTER INTBIG len;
3336 	REGISTER BOOLEAN foundlowerlevel;
3337 	REGISTER CHAR *lowerlevel;
3338 
3339 	/* see if this name is in the data */
3340 	if (level != 0)
3341 	{
3342 		foundlowerlevel = FALSE;
3343 		lowerlevel = 0;
3344 		len = estrlen(sim_vercurscope);
3345 		for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
3346 		{
3347 			if (vs->level != sim_vercurlevel+1) continue;
3348 			if (namesamen(vs->signalcontext, sim_vercurscope, len) != 0) continue;
3349 			if (vs->signalcontext[len] != '.') continue;
3350 
3351 			/* check the lower level */
3352 			if (namesame(&vs->signalcontext[len+1], level) == 0) break;
3353 			if (foundlowerlevel)
3354 			{
3355 				if (lowerlevel != 0)
3356 				{
3357 					if (namesame(lowerlevel, &vs->signalcontext[len+1]) != 0)
3358 						lowerlevel = 0;
3359 				}
3360 			} else
3361 			{
3362 				lowerlevel = &vs->signalcontext[len+1];
3363 				foundlowerlevel = TRUE;
3364 			}
3365 		}
3366 
3367 		if (vs == NOVERSIGNAL)
3368 		{
3369 			/* did not find the lower level */
3370 			if (lowerlevel != 0)
3371 			{
3372 				estrcat(sim_vercurscope, x_("."));
3373 				estrcat(sim_vercurscope, lowerlevel);
3374 				sim_vercurlevel++;
3375 			}
3376 		}
3377 
3378 		estrcat(sim_vercurscope, x_("."));
3379 		estrcat(sim_vercurscope, level);
3380 		sim_vercurlevel++;
3381 	}
3382 
3383 	sim_window_grabcachedsignalsoncell(cell);
3384 	sim_vershowcurrentlevel(cell);
3385 }
3386 
3387 /*
3388  * Routine to move up one level of hierarchy in the display of signal names.
3389  */
sim_verlevel_up(NODEPROTO * cell)3390 void sim_verlevel_up(NODEPROTO *cell)
3391 {
3392 	REGISTER INTBIG i;
3393 
3394 	if (sim_vercurlevel <= 0)
3395 	{
3396 		ttyputerr(_("At the top level of the hierarchy"));
3397 		return;
3398 	}
3399 	sim_vercurlevel--;
3400 	for(i=estrlen(sim_vercurscope)-1; i>0; i--)
3401 		if (sim_vercurscope[i] == '.') break;
3402 	sim_vercurscope[i] = 0;
3403 	sim_window_grabcachedsignalsoncell(cell);
3404 	sim_vershowcurrentlevel(cell);
3405 }
3406 
sim_verlevel_cur(void)3407 CHAR *sim_verlevel_cur(void)
3408 {
3409 	return(sim_vercurscope);
3410 }
3411 
3412 /*
3413  * Routine to add the signal called "signame" to the waveform window.
3414  */
sim_veraddhighlightednet(CHAR * signame)3415 void sim_veraddhighlightednet(CHAR *signame)
3416 {
3417 	REGISTER VERSIGNAL *vs;
3418 	REGISTER INTBIG traces;
3419 	REGISTER void *infstr;
3420 
3421 	for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
3422 	{
3423 		if (vs->signal != 0) continue;
3424 		infstr = initinfstr();
3425 		formatinfstr(infstr, x_("%s.%s"), vs->signalcontext, vs->signalname);
3426 		if (namesame(signame, returninfstr(infstr)) == 0) break;
3427 	}
3428 	if (vs == NOVERSIGNAL) return;
3429 
3430 	/* ready to add: remove highlighting */
3431 	sim_window_cleartracehighlight();
3432 
3433 	/* count the number of traces */
3434 	sim_window_inittraceloop();
3435 	for(traces=0; ; traces++) if (sim_window_nexttraceloop() == 0) break;
3436 
3437 	/* create a new trace in the last slot */
3438 	vs->signal = sim_window_newtrace(-1, vs->signalname, (INTBIG)vs);
3439 	sim_window_addhighlighttrace(vs->signal);
3440 	sim_window_setnumframes(sim_window_getnumframes()+1);
3441 	sim_window_loaddigtrace(vs->signal, vs->count, vs->stimtime, vs->stimstate);
3442 }
3443 
3444 /*
3445  * Routine that feeds the current signals into the explorer window.
3446  */
sim_verreportsignals(WINDOWPART * simwin,void * (* addbranch)(CHAR *,void *),void * (* findbranch)(CHAR *,void *),void * (* addleaf)(CHAR *,void *),CHAR * (* nodename)(void *))3447 void sim_verreportsignals(WINDOWPART *simwin, void *(*addbranch)(CHAR*, void*),
3448 	void *(*findbranch)(CHAR*, void*), void *(*addleaf)(CHAR*, void*), CHAR *(*nodename)(void*))
3449 {
3450 	REGISTER INTBIG j, k, len;
3451 	REGISTER CHAR *pt, save;
3452 	REGISTER void *curlevel, *nextlevel;
3453 	REGISTER VERSIGNAL *vs;
3454 	CHAR signame[500];
3455 
3456 	for(vs = sim_verfirstsignal; vs != NOVERSIGNAL; vs = vs->nextversignal)
3457 	{
3458 		if (vs->level < 1) continue;
3459 		esnprintf(signame, 500, x_("%s.%s"), vs->signalcontext, vs->signalname);
3460 		len = strlen(signame);
3461 		for(j=len-2; j>0; j--)
3462 			if (signame[j] == '.') break;
3463 		if (j <= 0)
3464 		{
3465 			/* no "." qualifiers */
3466 			(*addleaf)(signame, 0);
3467 		} else
3468 		{
3469 			/* is down the hierarchy */
3470 			signame[j] = 0;
3471 
3472 			/* now find the location for this branch */
3473 			curlevel = 0;
3474 			pt = signame;
3475 			for(;;)
3476 			{
3477 				for(k=0; pt[k] != 0; k++) if (pt[k] == '.') break;
3478 				save = pt[k];
3479 				pt[k] = 0;
3480 				nextlevel = (*findbranch)(pt, curlevel);
3481 				if (nextlevel == 0)
3482 					nextlevel = (*addbranch)(pt, curlevel);
3483 				curlevel = nextlevel;
3484 				if (save == 0) break;
3485 				pt[k] = save;
3486 				pt = &pt[k+1];
3487 			}
3488 			(*addleaf)(&signame[j+1], curlevel);
3489 			signame[j] = '.';
3490 		}
3491 	}
3492 }
3493 
3494 #endif  /* SIMTOOL - at top */
3495