1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: simalsgraph.c
6  * Asynchronous Logic Simulator graphics interface
7  * From algorithms by: Brent Serbin and Peter J. Gallant
8  * Last maintained by: Steven M. Rubin
9  *
10  * Copyright (c) 2000 Static Free Software.
11  *
12  * Electric(tm) is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * Electric(tm) is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with Electric(tm); see the file COPYING.  If not, write to
24  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
25  * Boston, Mass 02111-1307, USA.
26  *
27  * Static Free Software
28  * 4119 Alpine Road
29  * Portola Valley, California 94028
30  * info@staticfreesoft.com
31  */
32 
33 #include "config.h"
34 #if SIMTOOL
35 
36 #include "global.h"
37 #include "sim.h"
38 #include "simals.h"
39 #include "usr.h"
40 #include "network.h"
41 #include "edialogs.h"
42 
43 static INTBIG  sim_window_iter;
44 static BOOLEAN sim_als_wantweak = FALSE, sim_als_wantstrong = FALSE, sim_als_wantfull = FALSE;
45 
46 /* prototypes for local routines */
47 static BOOLEAN  simals_topofsignals(CHAR**);
48 static CHAR    *simals_nextsignals(void);
49 static INTBIG   simals_count_channels(CONPTR);
50 static void     simals_helpwindow(BOOLEAN waveform);
51 static int      simals_sortbusnames(const void *e1, const void *e2);
52 
simals_topofsignals(CHAR ** c)53 BOOLEAN simals_topofsignals(CHAR **c)
54 {
55 	Q_UNUSED( c );
56 	sim_window_iter = 0;
57 	return(TRUE);
58 }
59 
simals_nextsignals(void)60 CHAR *simals_nextsignals(void)
61 {
62 	CHAR *nextname;
63 
64 	for(; ; sim_window_iter++)
65 	{
66 		if (sim_window_iter >= simals_levelptr->num_chn) return(0);
67 		if (simals_levelptr->display_page[sim_window_iter+1].nodeptr == 0) continue;
68 		if (simals_levelptr->display_page[sim_window_iter+1].displayptr == 0) break;
69 	}
70 	nextname = simals_levelptr->display_page[sim_window_iter+1].name;
71 	sim_window_iter++;
72 	return(nextname);
73 }
74 
75 static COMCOMP sim_window_pickalstrace = {NOKEYWORD, simals_topofsignals,
76 	simals_nextsignals, NOPARAMS, 0, x_(" \t"), N_("pick a signal to display"), x_("")};
77 
78 /*
79  * Routine to start ALS simulation of cell "np".
80  */
simals_startsimulation(NODEPROTO * np)81 BOOLEAN simals_startsimulation(NODEPROTO *np)
82 {
83 	extern TOOL *vhdl_tool;
84 	REGISTER INTBIG error;
85 
86 	/* initialize memory */
87 	simals_init();
88 
89 	/* demand an ALS netlist */
90 	error = asktool(vhdl_tool, x_("want-netlist-input"), (INTBIG)np, sim_filetypeals);
91 	if (error != 0) return(TRUE);
92 
93 	/* read netlist */
94 	simals_erase_model();
95 	if (simals_read_net_desc(np)) return(TRUE);
96 	if (simals_flatten_network()) return(TRUE);
97 
98 	if (simals_title != 0)
99 	{
100 		efree((CHAR *)simals_title);
101 		simals_title = 0;
102 	}
103 
104 	/* initialize display */
105 	simals_init_display();
106 	return(FALSE);
107 }
108 
109 /*
110  * The character handler for the waveform window of ALS simulation
111  */
simals_charhandlerwave(WINDOWPART * w,INTSML chr,INTBIG special)112 BOOLEAN simals_charhandlerwave(WINDOWPART *w, INTSML chr, INTBIG special)
113 {
114 	REGISTER INTBIG i, j, traces, pos, thispos, strength, *tracelist,
115 		tr, trl, nexttr, prevtr, highsig, *highsigs, numbits, bitoffset;
116 	INTBIG state, *theBits;
117 	CHAR *par[30], *name;
118 	NODEPTR node, nodehead;
119 	NODEPROTO *np;
120 	double endtime;
121 	LINKPTR sethead;
122 
123 	ttynewcommand();
124 
125 	/* special characters are not handled here */
126 	if (special != 0)
127 		return(us_charhandler(w, chr, special));
128 
129 	/* can always preserve snapshot */
130 	if (chr == 'p')
131 	{
132 		sim_window_savegraph();
133 		sim_als_wantweak = sim_als_wantstrong = sim_als_wantfull = FALSE;
134 		return(FALSE);
135 	}
136 
137 	/* can always do help */
138 	if (chr == '?')
139 	{
140 		simals_helpwindow(TRUE);
141 		sim_als_wantweak = sim_als_wantstrong = sim_als_wantfull = FALSE;
142 		return(FALSE);
143 	}
144 
145 	/* if not simulating, don't handle any simulation commands */
146 	if (sim_window_isactive(&np) == 0)
147 		return(us_charhandler(w, chr, special));
148 
149 	numbits = 0;
150 	switch (chr)
151 	{
152 		/* update display */
153 		case 'u':
154 			endtime = simals_initialize_simulator(TRUE);
155 			if ((sim_window_state&ADVANCETIME) != 0) sim_window_setmaincursor(endtime);
156 			return(FALSE);
157 
158 		/* convert busses */
159 		case 'b':
160 			(void)sim_window_buscommand();
161 			return(FALSE);
162 
163 		/* add trace */
164 		case 'a':
165 			i = ttygetparam(_("Signal to add"), &sim_window_pickalstrace, 3, par);
166 			if (i == 0) return(FALSE);
167 
168 			/* find the signal */
169 			for(i=0; i<simals_levelptr->num_chn; i++)
170 			{
171 				node = simals_levelptr->display_page[i+1].nodeptr;
172 				if (node == 0) continue;
173 				if (simals_levelptr->display_page[i+1].displayptr != 0) continue;
174 				name = simals_levelptr->display_page[i+1].name;
175 				if (namesame(name, par[0]) == 0) break;
176 			}
177 			if (i >= simals_levelptr->num_chn) return(FALSE);
178 
179 			/* ready to add: remove highlighting */
180 			sim_window_cleartracehighlight();
181 
182 			/* count the number of traces */
183 			sim_window_inittraceloop();
184 			for(traces=0; ; traces++) if (sim_window_nexttraceloop() == 0) break;
185 
186 			/* if there are no traces, put new trace on line zero */
187 			if (traces == 0) j = 0; else
188 			{
189 				/* other traces exist, make a new line in the plot */
190 				j = sim_window_getnumframes();
191 				sim_window_setnumframes(j+1);
192 			}
193 
194 			/* create a new trace in the last slot */
195 			tr = sim_window_newtrace(j, simals_levelptr->display_page[i+1].name,
196 				(INTBIG)simals_levelptr->display_page[i+1].nodeptr);
197 			simals_levelptr->display_page[i+1].displayptr = tr;
198 			simals_fill_display_arrays();
199 			sim_window_redraw();
200 			sim_window_addhighlighttrace(tr);
201 			sim_als_wantweak = sim_als_wantstrong = sim_als_wantfull = FALSE;
202 			return(FALSE);
203 
204 		/* handle weak and strong prefixes */
205 		case 'w':
206 			if (sim_als_wantweak || sim_als_wantstrong) ttybeep(SOUNDBEEP, FALSE);
207 			sim_als_wantweak = TRUE;
208 			return(FALSE);
209 		case 's':
210 			if (sim_als_wantweak || sim_als_wantstrong) ttybeep(SOUNDBEEP, FALSE);
211 			sim_als_wantstrong = TRUE;
212 			return(FALSE);
213 		case 'f':
214 			if (sim_als_wantfull) ttybeep(SOUNDBEEP, FALSE);
215 			sim_als_wantfull = TRUE;
216 			return(FALSE);
217 
218 		/* different flavors of low values */
219 		case '0':
220 		case 'l':
221 			state = LOGIC_LOW;    strength = GATE_STRENGTH;
222 			if (sim_als_wantweak) strength = NODE_STRENGTH; else
223 				if (sim_als_wantstrong) strength = VDD_STRENGTH;
224 			break;
225 
226 		/* different flavors of high values */
227 		case '1':
228 		case 'h':
229 			state = LOGIC_HIGH;   strength = GATE_STRENGTH;
230 			if (sim_als_wantweak) strength = NODE_STRENGTH; else
231 				if (sim_als_wantstrong) strength = VDD_STRENGTH;
232 			break;
233 
234 		/* different flavors of undefined values */
235 		case 'x':
236 			state = LOGIC_X;      strength = GATE_STRENGTH;
237 			if (sim_als_wantweak) strength = NODE_STRENGTH; else
238 				if (sim_als_wantstrong) strength = VDD_STRENGTH;
239 			break;
240 
241 		/* different flavors of wide numeric values */
242 		case 'v':
243 			numbits = sim_window_getwidevalue(&theBits);
244 			if (numbits < 0) return(FALSE);
245 			strength = GATE_STRENGTH;
246 			if (sim_als_wantweak) strength = NODE_STRENGTH; else
247 				if (sim_als_wantstrong) strength = VDD_STRENGTH;
248 			break;
249 
250 		/* signal tracing */
251 		case 't':
252 			if (sim_als_wantfull)
253 			{
254 				simals_trace_all_nodes = TRUE;
255 				(void)simals_initialize_simulator(TRUE);
256 				simals_trace_all_nodes = FALSE;
257 			} else
258 			{
259 				highsigs = sim_window_gethighlighttraces();
260 				if (highsigs[0] == 0)
261 				{
262 					ttyputerr(_("Select signal names first"));
263 					return(FALSE);
264 				}
265 				for(i=0; highsigs[i] != 0; i++)
266 					((NODEPTR)sim_window_gettracedata(highsigs[i]))->tracenode = TRUE;
267 				(void)simals_initialize_simulator(TRUE);
268 				for(i=0; highsigs[i] != 0; i++)
269 					((NODEPTR)sim_window_gettracedata(highsigs[i]))->tracenode = FALSE;
270 			}
271 			return(FALSE);
272 
273 		/* signal clock setting, info, erasing, removing (all handled later) */
274 		case 'c':
275 		case 'i':
276 		case 'e':
277 		case 'r':
278 		case DELETEKEY:
279 			strength = OFF_STRENGTH;
280 			break;
281 
282 		default:
283 			sim_als_wantweak = sim_als_wantstrong = sim_als_wantfull = FALSE;
284 			return(us_charhandler(w, chr, special));
285 	}
286 	sim_als_wantweak = sim_als_wantstrong = sim_als_wantfull = FALSE;
287 
288 	/* the following commands demand a current trace...get it */
289 	highsigs = sim_window_gethighlighttraces();
290 	if (highsigs[0] == 0)
291 	{
292 		ttyputerr(_("Select a signal name first"));
293 		return(FALSE);
294 	}
295 	if (chr == 'r' || chr == DELETEKEY)		/* remove trace */
296 	{
297 		sim_window_cleartracehighlight();
298 
299 		/* delete them */
300 		nexttr = prevtr = 0;
301 		for(j=0; highsigs[j] != 0; j++)
302 		{
303 			highsig = highsigs[j];
304 			thispos = sim_window_gettraceframe(highsig);
305 			sim_window_inittraceloop();
306 			nexttr = prevtr = 0;
307 			for(;;)
308 			{
309 				trl = sim_window_nexttraceloop();
310 				if (trl == 0) break;
311 				pos = sim_window_gettraceframe(trl);
312 				if (pos > thispos)
313 				{
314 					pos--;
315 					if (pos == thispos) nexttr = trl;
316 					sim_window_settraceframe(trl, pos);
317 				} else if (pos == thispos-1) prevtr = trl;
318 			}
319 
320 			/* remove from the simulator's list */
321 			for(i=0; i<simals_levelptr->num_chn; i++)
322 			{
323 				node = simals_levelptr->display_page[i+1].nodeptr;
324 				if (node == 0) continue;
325 				if (simals_levelptr->display_page[i+1].displayptr == highsig)
326 				{
327 					simals_levelptr->display_page[i+1].displayptr = 0;
328 					break;
329 				}
330 			}
331 
332 			/* kill trace */
333 			sim_window_killtrace(highsig);
334 		}
335 		if (nexttr != 0) sim_window_addhighlighttrace(nexttr); else
336 			if (prevtr != 0) sim_window_addhighlighttrace(prevtr);
337 		sim_window_redraw();
338 		return(FALSE);
339 	}
340 
341 	if (highsigs[1] != 0)
342 	{
343 		ttyputerr(_("Select just one signal name first"));
344 		return(FALSE);
345 	}
346 	highsig = highsigs[0];
347 
348 	if (chr == 'c')		/* set clock waveform */
349 	{
350 		tracelist = sim_window_getbustraces(highsig);
351 		if (tracelist != 0 && tracelist[0] != 0)
352 		{
353 			ttyputerr(_("Cannot set clock waveform on a bus signal"));
354 			return(FALSE);
355 		}
356 		par[0] = sim_window_gettracename(highsig);
357 		simals_clock_command(1, par);
358 		return(FALSE);
359 	}
360 	if (chr == 'i')		/* print signal info */
361 	{
362 		par[0] = x_("state");
363 		par[1] = sim_window_gettracename(highsig);
364 		simals_print_command(2, par);
365 		return(FALSE);
366 	}
367 	if (chr == 'e')		/* clear signal vectors */
368 	{
369 		tracelist = sim_window_getbustraces(highsig);
370 		if (tracelist != 0 && tracelist[0] != 0)
371 		{
372 			for(i=0; tracelist[i] != 0; i++)
373 			{
374 				par[0] = x_("delete");
375 				par[1] = sim_window_gettracename(tracelist[i]);
376 				par[2] = x_("all");
377 				simals_vector_command(3, par);
378 			}
379 		} else
380 		{
381 			par[0] = x_("delete");
382 			par[1] = sim_window_gettracename(highsig);
383 			par[2] = x_("all");
384 			simals_vector_command(3, par);
385 		}
386 		return(FALSE);
387 	}
388 
389 	/* handle setting of values on signals */
390 	if (chr == 'v')
391 	{
392 		tracelist = sim_window_getbustraces(highsig);
393 		if (tracelist == 0 || tracelist[0] == 0)
394 		{
395 			ttyputerr(_("Select a bus signal before setting numeric values on it"));
396 			return(FALSE);
397 		}
398 		for(i=0; tracelist[i] != 0; i++) ;
399 		bitoffset = numbits - i;
400 		for(i=0; tracelist[i] != 0; i++)
401 		{
402 			nodehead = simals_find_node(sim_window_gettracename(tracelist[i]));
403 			if (! nodehead) return(FALSE);
404 			sethead = simals_alloc_link_mem();
405 			if (sethead == 0) return(FALSE);
406 			sethead->type = 'N';
407 			sethead->ptr = (CHAR *)nodehead;
408 			if (i+bitoffset < 0 || theBits[i+bitoffset] == 0) sethead->state = LOGIC_LOW; else
409 				sethead->state = LOGIC_HIGH;
410 			sethead->strength = (INTSML)strength;
411 			sethead->priority = 2;
412 			sethead->time = sim_window_getmaincursor();
413 			sethead->right = 0;
414 			simals_insert_set_list(sethead);
415 		}
416 	} else
417 	{
418 		nodehead = simals_find_node(sim_window_gettracename(highsig));
419 		if (! nodehead) return(FALSE);
420 		sethead = simals_alloc_link_mem();
421 		if (sethead == 0) return(FALSE);
422 		sethead->type = 'N';
423 		sethead->ptr = (CHAR *)nodehead;
424 		sethead->state = state;
425 		sethead->strength = (INTSML)strength;
426 		sethead->priority = 2;
427 		sethead->time = sim_window_getmaincursor();
428 		sethead->right = 0;
429 		simals_insert_set_list(sethead);
430 	}
431 
432 	endtime = simals_initialize_simulator(FALSE);
433 	if ((sim_window_state&ADVANCETIME) != 0) sim_window_setmaincursor(endtime);
434 	return(FALSE);
435 }
436 
437 /*
438  * The character handler for the schematic/layout window of ALS simulation
439  */
simals_charhandlerschem(WINDOWPART * w,INTSML chr,INTBIG special)440 BOOLEAN simals_charhandlerschem(WINDOWPART *w, INTSML chr, INTBIG special)
441 {
442 	INTBIG state, i, highsigcount, *highsiglist;
443 	REGISTER INTSML strength;
444 	REGISTER NETWORK *net, **netlist;
445 	CHAR *par[30], *pt;
446 	double endtime;
447 	NODEPTR nodehead;
448 	LINKPTR sethead;
449 
450 	ttynewcommand();
451 
452 	/* special characters are not handled here */
453 	if (special != 0)
454 		return(us_charhandler(w, chr, special));
455 
456 	switch (chr)
457 	{
458 		case '?':
459 			simals_helpwindow(FALSE);
460 			sim_als_wantweak = sim_als_wantstrong = FALSE;
461 			return(FALSE);
462 		case 'u':
463 			endtime = simals_initialize_simulator(TRUE);
464 			if ((sim_window_state&ADVANCETIME) != 0) sim_window_setmaincursor(endtime);
465 			return(FALSE);
466 		case 'w':
467 			if (sim_als_wantweak || sim_als_wantstrong) ttybeep(SOUNDBEEP, FALSE);
468 			sim_als_wantweak = TRUE;
469 			return(FALSE);
470 		case 's':
471 			if (sim_als_wantweak || sim_als_wantstrong) ttybeep(SOUNDBEEP, FALSE);
472 			sim_als_wantstrong = TRUE;
473 			return(FALSE);
474 		case '0':
475 		case 'l':
476 			state = LOGIC_LOW;    strength = GATE_STRENGTH;
477 			if (sim_als_wantweak) strength = NODE_STRENGTH; else
478 				if (sim_als_wantstrong) strength = VDD_STRENGTH;
479 			break;
480 		case '1':
481 		case 'h':
482 			state = LOGIC_HIGH;   strength = GATE_STRENGTH;
483 			if (sim_als_wantweak) strength = NODE_STRENGTH; else
484 				if (sim_als_wantstrong) strength = VDD_STRENGTH;
485 			break;
486 		case 'x':
487 			state = LOGIC_X;      strength = GATE_STRENGTH;
488 			if (sim_als_wantweak) strength = NODE_STRENGTH; else
489 				if (sim_als_wantstrong) strength = VDD_STRENGTH;
490 			break;
491 		case 'c':
492 		case 'i':
493 		case 't':
494 		case 'e':
495 			strength = OFF_STRENGTH;
496 			break;
497 		default:
498 			sim_als_wantweak = sim_als_wantstrong = FALSE;
499 			return(us_charhandler(w, chr, special));
500 	}
501 	sim_als_wantweak = sim_als_wantstrong = FALSE;
502 
503 	/* find the net in the waveform window */
504 	netlist = net_gethighlightednets(FALSE);
505 	net = netlist[0];
506 	if (net == NONETWORK) return(FALSE);
507 	if (net->namecount > 0) pt = networkname(net, 0); else
508 		pt = describenetwork(net);
509 	highsiglist = sim_window_findtrace(pt, &highsigcount);
510 	if (highsigcount == 0)
511 	{
512 		ttyputerr(_("Cannot find network %s in simulation"), pt);
513 		return(FALSE);
514 	}
515 	sim_window_cleartracehighlight();
516 	for(i=0; i<highsigcount; i++)
517 		sim_window_addhighlighttrace(highsiglist[i]);
518 
519 	if (chr == 'c')
520 	{
521 		par[0] = sim_window_gettracename(highsiglist[0]);
522 		simals_clock_command(1, par);
523 		return(FALSE);
524 	}
525 	if (chr == 'i')
526 	{
527 		par[0] = x_("state");
528 		par[1] = sim_window_gettracename(highsiglist[0]);
529 		simals_print_command(2, par);
530 		return(FALSE);
531 	}
532 	if (chr == 't')
533 	{
534 		nodehead = (NODEPTR)sim_window_gettracedata(highsiglist[0]);
535 		nodehead->tracenode = TRUE;
536 		(void)simals_initialize_simulator(TRUE);
537 		nodehead->tracenode = FALSE;
538 		return(FALSE);
539 	}
540 	if (chr == 'e')
541 	{
542 		par[0] = x_("delete");
543 		par[1] = sim_window_gettracename(highsiglist[0]);
544 		par[2] = x_("all");
545 		simals_vector_command(3, par);
546 		simals_fill_display_arrays();
547 		sim_window_redraw();
548 		return(FALSE);
549 	}
550 
551 	nodehead = simals_find_node(sim_window_gettracename(highsiglist[0]));
552 	if (nodehead == 0) return(FALSE);
553 
554 	sethead = simals_alloc_link_mem();
555 	if (sethead == 0) return(FALSE);
556 	sethead->type = 'N';
557 	sethead->ptr = (CHAR *)nodehead;
558 	sethead->state = state;
559 	sethead->strength = strength;
560 	sethead->priority = 2;
561 	sethead->time = sim_window_getmaincursor();
562 	sethead->right = 0;
563 	simals_insert_set_list(sethead);
564 	endtime = simals_initialize_simulator(FALSE);
565 
566 	if ((sim_window_state&ADVANCETIME) != 0) sim_window_setmaincursor(endtime);
567 	return(FALSE);
568 }
569 
simals_helpwindow(BOOLEAN waveform)570 void simals_helpwindow(BOOLEAN waveform)
571 {
572 	REGISTER INTBIG active;
573 	NODEPROTO *np;
574 
575 	active = sim_window_isactive(&np);
576 	if (active == 0)
577 	{
578 		ttyputmsg(_("There is no current simulation"));
579 		return;
580 	}
581 
582 	if (waveform)
583 		ttyputmsg(_("These keys may be typed in the ALS Waveform window:")); else
584 			ttyputmsg(_("These keys may be typed in the ALS Schematic window:"));
585 	ttyputinstruction(x_(";,0"), 4, _("Set signal low (normal strength)"));
586 	ttyputinstruction(x_("wl"),  4, _("Set signal low (weak strength)"));
587 	ttyputinstruction(x_("sl"),  4, _("Set signal low (strong strength)"));
588 	ttyputinstruction(x_("h,1"), 4, _("Set signal high (normal strength)"));
589 	ttyputinstruction(x_("wh"),  4, _("Set signal high (weak strength)"));
590 	ttyputinstruction(x_("sh"),  4, _("Set signal high (strong strength)"));
591 	ttyputinstruction(x_(" x"),  4, _("Set signal undefined (normal strength)"));
592 	ttyputinstruction(x_("wx"),  4, _("Set signal undefined (weak strength)"));
593 	ttyputinstruction(x_("sx"),  4, _("Set signal undefined (strong strength)"));
594 	if (waveform)
595 	{
596 		ttyputinstruction(x_(" v"),  4, _("Set bus to wide value (normal strength)"));
597 		ttyputinstruction(x_("wv"),  4, _("Set bus to wide value (weak strength)"));
598 		ttyputinstruction(x_("sv"),  4, _("Set bus to wide value (strong strength)"));
599 	}
600 	ttyputinstruction(x_(" c"),  4, _("Set signal to be a clock"));
601 	ttyputinstruction(x_(" e"),  4, _("Delete all vectors on signal"));
602 	ttyputinstruction(x_(" i"),  4, _("Print information about signal"));
603 	ttyputinstruction(x_(" t"),  4, _("Trace events on signal(s)"));
604 	ttyputinstruction(x_(" u"),  4, _("Update display (resimulate)"));
605 
606 	if (waveform)
607 	{
608 		ttyputinstruction(x_(" a"), 4, _("Add signal to simulation window"));
609 		ttyputinstruction(x_(" r"), 4, _("Remove signal from the window"));
610 		ttyputinstruction(x_(" b"), 4, _("Combine selected signals into a bus"));
611 		ttyputinstruction(x_("ft"), 4, _("Full Trace of all events"));
612 		ttyputinstruction(x_(" p"), 4, _("Preserve snapshot of simulation window in database"));
613 	}
614 }
615 
616 /*
617  * Name: simals_count_channels
618  *
619  * Description:
620  *	This function returns the number of exported channels in a given level.
621  *
622  * Calling Argument:
623  *	level_pointer : pointer to a level
624  */
simals_count_channels(CONPTR level_pointer)625 INTBIG simals_count_channels(CONPTR level_pointer)
626 {
627 	INTBIG count=0;
628 	EXPTR exhead;
629 
630 	for (exhead = level_pointer->exptr; exhead; exhead = exhead->next) count++;
631 	return(count);
632 }
633 
634 /*
635  * Name: simals_set_current_level
636  *
637  * Description:
638  *	This procedure is used to initialize the display channels to the current
639  * level of the database hierarchy.  Returns true on error.
640  */
simals_set_current_level(void)641 BOOLEAN simals_set_current_level(void)
642 {
643 	INTBIG i, j, k, buscount, oldsigcount, chn, bussignals[MAXSIMWINDOWBUSWIDTH],
644 		len, olen;
645 	CHAR **oldsignames;
646 	REGISTER VARIABLE *var;
647 	NODEPTR nodehead;
648 	NODE *node, *subnode;
649 	EXPTR exhead;
650 	CHAR *name, *subname, *pt, *opt, *start, save;
651 	void *sa;
652 	NODEPROTO *np;
653 	REGISTER void *infstr;
654 
655 	for (nodehead = simals_noderoot; nodehead; nodehead = nodehead->next)
656 		nodehead->plot_node = 0;
657 
658 	if (simals_levelptr->display_page)
659 	{
660 		exhead = simals_levelptr->exptr;
661 		for (i = 1; i <= simals_levelptr->num_chn; i++)
662 		{
663 			if (exhead)
664 			{
665 				exhead->nodeptr->plot_node = 1;
666 				exhead = exhead->next;
667 			}
668 		}
669 	} else
670 	{
671 		simals_levelptr->num_chn = simals_count_channels(simals_levelptr);
672 		chn = simals_levelptr->num_chn + 1;
673 		simals_levelptr->display_page = (CHNPTR)simals_alloc_mem((INTBIG)(chn * sizeof(CHANNEL)));
674 		if (simals_levelptr->display_page == 0) return(TRUE);
675 
676 		exhead = simals_levelptr->exptr;
677 		for (i = 1; i < chn; i++)
678 		{
679 			if (exhead)
680 			{
681 				name = exhead->node_name;
682 				simals_levelptr->display_page[i].nodeptr = exhead->nodeptr;
683 				exhead->nodeptr->plot_node = 1;
684 				exhead = exhead->next;
685 			} else
686 			{
687 				name = x_("");
688 				simals_levelptr->display_page[i].nodeptr = 0;
689 			}
690 			(void)allocstring(&simals_levelptr->display_page[i].name, name, sim_tool->cluster);
691 
692 			/* convert names to proper bracketed form */
693 			name = simals_levelptr->display_page[i].name;
694 			len = estrlen(name) - 1;
695 			if (name[len] == '_')
696 			{
697 				olen = len;
698 				while (len > 0 && isdigit(name[len-1])) len--;
699 				if (len != olen && name[len-1] == '_')
700 				{
701 					/* found the form "name_INDEX_" */
702 					name[len-1] = '[';
703 					name[olen] = ']';
704 				}
705 			}
706 		}
707 	}
708 
709 	/* prepare the simulation window */
710 	oldsigcount = 0;
711 	i = sim_window_isactive(&np);
712 	if ((i&SIMWINDOWWAVEFORM) == 0)
713 	{
714 		if (i != 0 && np != simals_mainproto)
715 		{
716 			/* stop simulation of cell "np" */
717 			sim_window_stopsimulation();
718 		}
719 
720 		/* no simulation running: start it up */
721 		if (simals_levelptr->num_chn <= 0) return(TRUE);
722 
723 		var = getvalkey((INTBIG)simals_mainproto, VNODEPROTO, VSTRING|VISARRAY,
724 			sim_window_signalorder_key);
725 		if (var != NOVARIABLE)
726 		{
727 			oldsigcount = getlength(var);
728 			if (oldsigcount > 0)
729 			{
730 				sa = newstringarray(sim_tool->cluster);
731 				for(i=0; i<oldsigcount; i++)
732 					addtostringarray(sa, ((CHAR **)var->addr)[i]);
733 				oldsignames = getstringarray(sa, &oldsigcount);
734 			}
735 		}
736 		if (sim_window_create(simals_levelptr->num_chn, simals_mainproto,
737 			((sim_window_state&SHOWWAVEFORM) != 0 ? simals_charhandlerwave : 0),
738 				simals_charhandlerschem, ALS))
739 		{
740 			if (oldsigcount > 0) killstringarray(sa);
741 			return(TRUE);
742 		}
743 		sim_window_state = (sim_window_state & ~SIMENGINECUR) | SIMENGINECURALS;
744 	}
745 
746 	/* set the window title */
747 	if (simals_title == 0) sim_window_titleinfo(_("Top Level")); else
748 	{
749 		sim_window_titleinfo(simals_title);
750 	}
751 
752 	/* load the traces */
753 	sim_window_killalltraces(TRUE);
754 	for(i=0; i<simals_levelptr->num_chn; i++)
755 		simals_levelptr->display_page[i+1].displayptr = 0;
756 
757 	/* add in saved signals */
758 	for(j=0; j<oldsigcount; j++)
759 	{
760 		/* see if the name is a bus */
761 		for(pt = oldsignames[j]; *pt != 0; pt++) if (*pt == '\t') break;
762 		if (*pt == '\t')
763 		{
764 			/* a bus */
765 			pt++;
766 			for(buscount = 0; ; )
767 			{
768 				for(start = pt; *pt != 0; pt++) if (*pt == '\t') break;
769 				save = *pt;
770 				*pt = 0;
771 				opt = start;
772 				if (*opt == '-') opt++;
773 				for( ; *opt != 0; opt++)
774 					if (!isdigit(*opt) || *opt == ':') break;
775 				if (*opt == ':') start = opt+1;
776 				for(i=0; i<simals_levelptr->num_chn; i++)
777 				{
778 					node = simals_levelptr->display_page[i+1].nodeptr;
779 					if (node == 0) continue;
780 					name = simals_levelptr->display_page[i+1].name;
781 					if (namesame(name, start) != 0) continue;
782 					bussignals[buscount] = sim_window_newtrace(-1, name, (INTBIG)node);
783 					simals_levelptr->display_page[i+1].displayptr = bussignals[buscount];
784 					buscount++;
785 					break;
786 				}
787 				*pt++ = save;
788 				if (save == 0) break;
789 			}
790 
791 			/* create the bus */
792 			infstr = initinfstr();
793 			for(pt = oldsignames[j]; *pt != 0; pt++)
794 			{
795 				if (*pt == '\t') break;
796 				addtoinfstr(infstr, *pt);
797 			}
798 			(void)sim_window_makebus(buscount, bussignals, returninfstr(infstr));
799 		} else
800 		{
801 			/* a single signal */
802 			pt = oldsignames[j];
803 			if (*pt == '-') pt++;
804 			for( ; *pt != 0; pt++)
805 				if (!isdigit(*pt) || *pt == ':') break;
806 			if (*pt == ':') pt++; else pt = oldsignames[j];
807 			for(i=0; i<simals_levelptr->num_chn; i++)
808 			{
809 				node = simals_levelptr->display_page[i+1].nodeptr;
810 				if (node == 0) continue;
811 				name = simals_levelptr->display_page[i+1].name;
812 				if (namesame(name, pt) != 0) continue;
813 				simals_levelptr->display_page[i+1].displayptr = sim_window_newtrace(-1, name,
814 					(INTBIG)node);
815 				break;
816 			}
817 		}
818 	}
819 
820 	/* add in other signals not in the saved list */
821 	for(i=0; i<simals_levelptr->num_chn; i++)
822 	{
823 		if (simals_levelptr->display_page[i+1].displayptr != 0) continue;
824 		node = simals_levelptr->display_page[i+1].nodeptr;
825 		if (node == 0) continue;
826 		name = simals_levelptr->display_page[i+1].name;
827 		for(k=0; name[k] != 0; k++) if (name[k] == '[') break;
828 		if (name[k] == '[')
829 		{
830 			/* found an arrayed signal: gather it into a bus */
831 			buscount = 0;
832 			for(j=0; j<simals_levelptr->num_chn; j++)
833 			{
834 				if (simals_levelptr->display_page[j+1].displayptr != 0) continue;
835 				if (simals_levelptr->display_page[j+1].nodeptr == 0) continue;
836 				subname = simals_levelptr->display_page[j+1].name;
837 				if (namesamen(subname, name, k) != 0) continue;
838 				if (buscount >= MAXSIMWINDOWBUSWIDTH) break;
839 				bussignals[buscount++] = j;
840 			}
841 			esort(bussignals, buscount, SIZEOFINTBIG, simals_sortbusnames);
842 			for(j=0; j<buscount; j++)
843 			{
844 				k = bussignals[j];
845 				subnode = simals_levelptr->display_page[k+1].nodeptr;
846 				subname = simals_levelptr->display_page[k+1].name;
847 				bussignals[j] = sim_window_newtrace(-1, subname, (INTBIG)subnode);
848 				simals_levelptr->display_page[k+1].displayptr = bussignals[j];
849 			}
850 
851 			/* create the bus */
852 			if (buscount > 1)
853 			{
854 				(void)sim_window_makebus(buscount, bussignals, 0);
855 			}
856 		} else
857 		{
858 			simals_levelptr->display_page[i+1].displayptr = sim_window_newtrace(-1, name,
859 				(INTBIG)node);
860 		}
861 	}
862 	sim_window_cleartracehighlight();
863 	sim_window_settimerange(0, 0.0, 0.0000005f);
864 	sim_window_setmaincursor(0.0000002f);
865 	sim_window_setextensioncursor(0.0000003f);
866 	if (oldsigcount > 0) killstringarray(sa);
867 	return(FALSE);
868 }
869 
870 /*
871  * Helper routine for "esort" that makes bus signals be numerically ordered
872  */
simals_sortbusnames(const void * e1,const void * e2)873 int simals_sortbusnames(const void *e1, const void *e2)
874 {
875 	REGISTER CHAR *n1, *n2;
876 	REGISTER INTBIG i1, i2;
877 
878 	i1 = *((INTBIG *)e1);
879 	i2 = *((INTBIG *)e2);
880 	n1 = simals_levelptr->display_page[i1+1].name;
881 	n2 = simals_levelptr->display_page[i2+1].name;
882 	if ((net_options&NETDEFBUSBASEDESC) != 0)
883 		return(namesamenumeric(n2, n1));
884 	return(namesamenumeric(n1, n2));
885 }
886 
simals_fill_display_arrays(void)887 void simals_fill_display_arrays(void)
888 {
889 	INTBIG *numsteps, i, j, pos, num_chan;
890 	INTSML **statearrays;
891 	INTBIG *nodelist, displayobj;
892 	TRAKPTR trakhead;
893 	double min, max, **timearrays;
894 
895 	/* determine size needed for waveform arrays */
896 	num_chan = simals_levelptr->num_chn;
897 	numsteps = (INTBIG *)emalloc(num_chan * SIZEOFINTBIG, el_tempcluster);
898 	if (numsteps == 0) return;
899 	nodelist = (INTBIG *)emalloc(num_chan * SIZEOFINTBIG, el_tempcluster);
900 	if (nodelist == 0) return;
901 	timearrays = (double **)emalloc(num_chan * (sizeof (double *)), el_tempcluster);
902 	if (timearrays == 0) return;
903 	statearrays = (INTSML **)emalloc(num_chan * (sizeof (INTSML *)), el_tempcluster);
904 	if (statearrays == 0) return;
905 	for(i=0; i<num_chan; i++)
906 	{
907 		numsteps[i] = 1;
908 		displayobj = simals_levelptr->display_page[i+1].displayptr;
909 		if (displayobj == 0) nodelist[i] = 0; else
910 			nodelist[i] = sim_window_gettracedata(displayobj);
911 	}
912 
913 	sim_window_gettimeextents(&min, &max);
914 	if (simals_trakfull == 0) i = 0; else i = simals_trakptr;
915 	for( ; i < simals_trakptr && i < simals_trace_size; i++)
916 	{
917 		trakhead = &(simals_trakroot[i]);
918 		if (trakhead->time > max) break;
919 		for (j=0; j<num_chan; j++)
920 		{
921 			if (nodelist[j] == 0) continue;
922 			if (nodelist[j] != (INTBIG)trakhead->ptr) continue;
923 			numsteps[j]++;
924 		}
925 	}
926 
927 	/* allocate space for the waveform arrays */
928 	for (j=0; j<num_chan; j++)
929 	{
930 		if (nodelist[j] == 0) continue;
931 		timearrays[j] = (double *)emalloc(numsteps[j] * (sizeof (double)), sim_tool->cluster);
932 		statearrays[j] = (INTSML *)emalloc(numsteps[j] * SIZEOFINTSML, sim_tool->cluster);
933 		if (timearrays[j] == 0 || statearrays[j] == 0) return;
934 	}
935 
936 	/* fill the arrays */
937 	for (i=0; i<num_chan; i++)
938 	{
939 		if (nodelist[i] == 0) continue;
940 		numsteps[i] = 1;
941 		timearrays[i][0] = min;
942 		statearrays[i][0] = (LOGIC_LOW << 8) | OFF_STRENGTH;
943 	}
944 	if (simals_trakfull == 0) i = 0; else i = simals_trakptr;
945 	for( ; i < simals_trakptr && i < simals_trace_size; i++)
946 	{
947 		trakhead = &(simals_trakroot[i]);
948 		if (trakhead->time > max) break;
949 		for (j=0; j<num_chan; j++)
950 		{
951 			if (nodelist[j] == 0) continue;
952 			if (nodelist[j] != (INTBIG)trakhead->ptr) continue;
953 			pos = numsteps[j]++;
954 			timearrays[j][pos] = trakhead->time;
955 			statearrays[j][pos] = (INTSML)((trakhead->state << 8) | trakhead->strength);
956 		}
957 	}
958 
959 	/* give the data to the simulation window system */
960 	for (j=0; j<num_chan; j++)
961 	{
962 		if (nodelist[j] == 0) continue;
963 		displayobj = simals_levelptr->display_page[j+1].displayptr;
964 		sim_window_loaddigtrace(displayobj, numsteps[j], timearrays[j], statearrays[j]);
965 		efree((CHAR *)timearrays[j]);
966 		efree((CHAR *)statearrays[j]);
967 	}
968 	efree((CHAR *)nodelist);
969 	efree((CHAR *)numsteps);
970 	efree((CHAR *)timearrays);
971 	efree((CHAR *)statearrays);
972 }
973 
974 /*
975  * Routine that feeds the current signals into the explorer window.
976  */
simals_reportsignals(WINDOWPART * simwin,void * (* addbranch)(CHAR *,void *),void * (* findbranch)(CHAR *,void *),void * (* addleaf)(CHAR *,void *),CHAR * (* nodename)(void *))977 void simals_reportsignals(WINDOWPART *simwin, void *(*addbranch)(CHAR*, void*),
978 	void *(*findbranch)(CHAR*, void*), void *(*addleaf)(CHAR*, void*), CHAR *(*nodename)(void*))
979 {
980 	(*addleaf)("NO SIGNALS YET", 0);
981 }
982 
983 #endif  /* SIMTOOL - at top */
984