1 /*
2  * Copyright (c) Tony Bybell 2005-2014.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  */
9 
10 #include <config.h>
11 #include "globals.h"
12 #include "vcd_saver.h"
13 #include "helpers/lxt_write.h"
14 #include "ghw.h"
15 #include "hierpack.h"
16 #include <time.h>
17 
18 WAVE_NODEVARTYPE_STR
19 
w32redirect_fprintf(int is_trans,FILE * sfd,const char * format,...)20 static void w32redirect_fprintf(int is_trans, FILE *sfd, const char *format, ...)
21 {
22 #if defined _MSC_VER || defined __MINGW32__
23 if(is_trans)
24 	{
25 	char buf[16385];
26 	BOOL bSuccess;
27 	DWORD dwWritten;
28 
29 	va_list ap;
30 	va_start(ap, format);
31 	buf[0] = 0;
32 	vsprintf(buf, format, ap);
33 	bSuccess = WriteFile((HANDLE)sfd, buf, strlen(buf), &dwWritten, NULL);
34 	va_end(ap);
35 	}
36 	else
37 #else
38 (void) is_trans;
39 #endif
40 	{
41 	va_list ap;
42 	va_start(ap, format);
43 	vfprintf(sfd, format, ap);
44 	va_end(ap);
45 	}
46 }
47 
48 
49 /*
50  * unconvert trace data back to VCD representation...use strict mode for LXT
51  */
analyzer_demang(int strict,unsigned char ch)52 static unsigned char analyzer_demang(int strict, unsigned char ch)
53 {
54 if(!strict)
55 	{
56 	if(ch < AN_COUNT)
57 		{
58 		return(AN_STR[ch]);
59 		}
60 		else
61 		{
62 		return(ch);
63 		}
64 	}
65 else
66 	{
67 	if(ch < AN_COUNT)
68 		{
69 		return(AN_STR4ST[ch]);
70 		}
71 		else
72 		{
73 		return(ch);
74 		}
75 	}
76 }
77 
78 
79 /*
80  * generate a vcd identifier for a given facindx
81  */
vcdid(unsigned int value,int export_typ)82 static char *vcdid(unsigned int value, int export_typ)
83 {
84 char *pnt = GLOBALS->buf_vcd_saver_c_3;
85 unsigned int vmod;
86 
87 if(export_typ != WAVE_EXPORT_TRANS)
88 	{
89 	value++;
90 	for(;;)
91 	        {
92 	        if((vmod = (value % 94)))
93 	                {
94 	                *(pnt++) = (char)(vmod + 32);
95 	                }
96 	                else
97 	                {
98 	                *(pnt++) = '~'; value -= 94;
99 	                }
100 	        value = value / 94;
101 	        if(!value) { break; }
102 	        }
103 
104 	*pnt = 0;
105 	}
106 	else
107 	{
108 	sprintf(pnt, "%d", value);
109 	}
110 
111 return(GLOBALS->buf_vcd_saver_c_3);
112 }
113 
114 
vcd_truncate_bitvec(char * s)115 static char *vcd_truncate_bitvec(char *s)
116 {
117 char l, r;
118 
119 r=*s;
120 if(r=='1')
121         {
122         return s;
123         }
124         else
125         {
126         s++;
127         }
128 
129 for(;;s++)
130         {
131         l=r; r=*s;
132         if(!r) return (s-1);
133 
134         if(l!=r)
135                 {
136                 return(((l=='0')&&(r=='1'))?s:s-1);
137                 }
138         }
139 }
140 
141 
142 /************************ splay ************************/
143 
144 /*
145  * integer splay
146  */
147 typedef struct vcdsav_tree_node vcdsav_Tree;
148 struct vcdsav_tree_node {
149     vcdsav_Tree * left, * right;
150     nptr item;
151     int val;
152     hptr hist;
153     int len;
154 
155     union
156 	{
157 	void *p;
158 	long l;
159 	int i;
160 	} handle;	/* future expansion for adding other writers that need pnt/handle info */
161 
162     unsigned char flags;
163 };
164 
165 
vcdsav_cmp_l(void * i,void * j)166 static long vcdsav_cmp_l(void *i, void *j)
167 {
168 intptr_t il = (intptr_t)i, jl = (intptr_t)j;
169 return(il - jl);
170 }
171 
vcdsav_splay(void * i,vcdsav_Tree * t)172 static vcdsav_Tree * vcdsav_splay (void *i, vcdsav_Tree * t) {
173 /* Simple top down splay, not requiring i to be in the tree t.  */
174 /* What it does is described above.                             */
175     vcdsav_Tree N, *l, *r, *y;
176     int dir;
177 
178     if (t == NULL) return t;
179     N.left = N.right = NULL;
180     l = r = &N;
181 
182     for (;;) {
183 	dir = vcdsav_cmp_l(i, t->item);
184 	if (dir < 0) {
185 	    if (t->left == NULL) break;
186 	    if (vcdsav_cmp_l(i, t->left->item)<0) {
187 		y = t->left;                           /* rotate right */
188 		t->left = y->right;
189 		y->right = t;
190 		t = y;
191 		if (t->left == NULL) break;
192 	    }
193 	    r->left = t;                               /* link right */
194 	    r = t;
195 	    t = t->left;
196 	} else if (dir > 0) {
197 	    if (t->right == NULL) break;
198 	    if (vcdsav_cmp_l(i, t->right->item)>0) {
199 		y = t->right;                          /* rotate left */
200 		t->right = y->left;
201 		y->left = t;
202 		t = y;
203 		if (t->right == NULL) break;
204 	    }
205 	    l->right = t;                              /* link left */
206 	    l = t;
207 	    t = t->right;
208 	} else {
209 	    break;
210 	}
211     }
212     l->right = t->left;                                /* assemble */
213     r->left = t->right;
214     t->left = N.right;
215     t->right = N.left;
216     return t;
217 }
218 
219 
vcdsav_insert(void * i,vcdsav_Tree * t,int val,unsigned char flags,hptr h)220 static vcdsav_Tree * vcdsav_insert(void *i, vcdsav_Tree * t, int val, unsigned char flags, hptr h) {
221 /* Insert i into the tree t, unless it's already there.    */
222 /* Return a pointer to the resulting tree.                 */
223     vcdsav_Tree * n;
224     int dir;
225 
226     n = (vcdsav_Tree *) calloc_2(1, sizeof (vcdsav_Tree));
227     if (n == NULL) {
228 	fprintf(stderr, "vcdsav_insert: ran out of memory, exiting.\n");
229 	exit(255);
230     }
231     n->item = i;
232     n->val = val;
233     n->flags = flags;
234     n->hist = h;
235     if (t == NULL) {
236 	n->left = n->right = NULL;
237 	return n;
238     }
239     t = vcdsav_splay(i,t);
240     dir = vcdsav_cmp_l(i,t->item);
241     if (dir<0) {
242 	n->left = t->left;
243 	n->right = t;
244 	t->left = NULL;
245 	return n;
246     } else if (dir>0) {
247 	n->right = t->right;
248 	n->left = t;
249 	t->right = NULL;
250 	return n;
251     } else { /* We get here if it's already in the tree */
252              /* Don't add it again                      */
253 	free_2(n);
254 	return t;
255     }
256 }
257 
258 /************************ heap ************************/
259 
hpcmp(vcdsav_Tree * hp1,vcdsav_Tree * hp2)260 static int hpcmp(vcdsav_Tree *hp1, vcdsav_Tree *hp2)
261 {
262 hptr n1 = hp1->hist;
263 hptr n2 = hp2->hist;
264 TimeType t1, t2;
265 
266 if(n1)  t1 = n1->time; else t1 = MAX_HISTENT_TIME;
267 if(n2)  t2 = n2->time; else t2 = MAX_HISTENT_TIME;
268 
269 if(t1 == t2)
270 	{
271 	return(0);
272 	}
273 else
274 if(t1 > t2)
275 	{
276 	return(-1);
277 	}
278 else
279 	{
280 	return(1);
281 	}
282 }
283 
284 
recurse_build(vcdsav_Tree * vt,vcdsav_Tree *** hp)285 static void recurse_build(vcdsav_Tree *vt, vcdsav_Tree ***hp)
286 {
287 if(vt->left) recurse_build(vt->left, hp);
288 
289 **hp = vt;
290 *hp = (*hp) + 1;
291 
292 if(vt->right) recurse_build(vt->right, hp);
293 }
294 
295 
296 /*
297  * heapify algorithm...used to grab the next value change
298  */
heapify(int i,int heap_size)299 static void heapify(int i, int heap_size)
300 {
301 int l, r;
302 int largest;
303 vcdsav_Tree *t;
304 int maxele=heap_size/2-1;	/* points to where heapswaps don't matter anymore */
305 
306 for(;;)
307         {
308         l=2*i+1;
309         r=l+1;
310 
311         if((l<heap_size)&&(hpcmp(GLOBALS->hp_vcd_saver_c_1[l],GLOBALS->hp_vcd_saver_c_1[i])>0))
312                 {
313                 largest=l;
314                 }
315                 else
316                 {
317                 largest=i;
318                 }
319         if((r<heap_size)&&(hpcmp(GLOBALS->hp_vcd_saver_c_1[r],GLOBALS->hp_vcd_saver_c_1[largest])>0))
320                 {
321                 largest=r;
322                 }
323 
324         if(i!=largest)
325                 {
326                 t=GLOBALS->hp_vcd_saver_c_1[i];
327                 GLOBALS->hp_vcd_saver_c_1[i]=GLOBALS->hp_vcd_saver_c_1[largest];
328                 GLOBALS->hp_vcd_saver_c_1[largest]=t;
329 
330                 if(largest<=maxele)
331                         {
332                         i=largest;
333                         }
334                         else
335                         {
336                         break;
337                         }
338                 }
339                 else
340                 {
341                 break;
342                 }
343         }
344 }
345 
346 
347 /*
348  * mainline
349  */
save_nodes_to_export_generic(FILE * trans_file,Trptr trans_head,const char * fname,int export_typ)350 int save_nodes_to_export_generic(FILE *trans_file, Trptr trans_head, const char *fname, int export_typ)
351 {
352 Trptr t = trans_head ? trans_head : GLOBALS->traces.first;
353 int nodecnt = 0;
354 vcdsav_Tree *vt = NULL;
355 vcdsav_Tree **hp_clone = GLOBALS->hp_vcd_saver_c_1;
356 nptr n;
357 /* ExtNode *e; */
358 /* int msi, lsi; */
359 int i;
360 TimeType prevtime = LLDescriptor(-1);
361 time_t walltime;
362 struct strace *st = NULL;
363 int strace_append = 0;
364 int max_len = 1;
365 char *row_data = NULL;
366 struct lt_trace *lt = NULL;
367 int lxt = (export_typ == WAVE_EXPORT_LXT);
368 int is_trans = (export_typ == WAVE_EXPORT_TRANS);
369 int dumpvars_state = 0;
370 
371 if(export_typ == WAVE_EXPORT_TIM)
372 	{
373 	return(do_timfile_save(fname));
374 	}
375 
376 errno = 0;
377 if(lxt)
378 	{
379 	lt = lt_init(fname);
380 	if(!lt)
381 		{
382 		return(VCDSAV_FILE_ERROR);
383 		}
384 	}
385 	else
386 	{
387 	if(export_typ != WAVE_EXPORT_TRANS)
388 		{
389 		GLOBALS->f_vcd_saver_c_1 = fopen(fname, "wb");
390 		}
391 		else
392 		{
393 		if(!trans_head) /* scan-build : is programming error to get here */
394 			{
395 			return(VCDSAV_FILE_ERROR);
396 			}
397 		GLOBALS->f_vcd_saver_c_1 = trans_file;
398 		}
399 
400 	if(!GLOBALS->f_vcd_saver_c_1)
401 		{
402 		return(VCDSAV_FILE_ERROR);
403 		}
404 	}
405 
406 while(t)
407 	{
408 	if(!t->vector)
409 		{
410 		if(t->n.nd)
411 			{
412 			n = t->n.nd;
413 			if(n->expansion) n = n->expansion->parent;
414 			vt = vcdsav_splay(n, vt);
415 			if(!vt || vt->item != n)
416 				{
417 				unsigned char flags = 0;
418 
419 				if(n->head.next)
420 				if(n->head.next->next)
421 					{
422 					flags = n->head.next->next->flags;
423 					}
424 
425 				vt = vcdsav_insert(n, vt, ++nodecnt, flags, &n->head);
426 				}
427 			}
428 		}
429 		else
430 		{
431 		bvptr b = t->n.vec;
432 		if(b)
433 			{
434 			bptr bt = b->bits;
435 			if(bt)
436 				{
437 				for(i=0;i<bt->nnbits;i++)
438 					{
439 					if(bt->nodes[i])
440 						{
441 						n = bt->nodes[i];
442 
443 						if(n->expansion) n = n->expansion->parent;
444 						vt = vcdsav_splay(n, vt);
445 						if(!vt || vt->item != n)
446 							{
447 							unsigned char flags = 0;
448 
449 							if(n->head.next)
450 							if(n->head.next->next)
451 								{
452 								flags = n->head.next->next->flags;
453 								}
454 
455 							vt = vcdsav_insert(n, vt, ++nodecnt, flags, &n->head);
456 							}
457 						}
458 					}
459 				}
460 			}
461 		}
462 
463 
464 	if(export_typ == WAVE_EXPORT_TRANS)
465 		{
466 		break;
467 		}
468 
469 	if(!strace_append)
470 		{
471 		t=t->t_next;
472 		if(t) continue;
473 		}
474 		else
475 		{
476 		st = st->next;
477 		t = st ? st->trace : NULL;
478 		if(t)
479 			{
480 			continue;
481 			}
482 			else
483 			{
484 			swap_strace_contexts();
485 			}
486 		}
487 
488 strace_concat:
489 	GLOBALS->strace_ctx = &GLOBALS->strace_windows[GLOBALS->strace_current_window = strace_append];
490 	strace_append++;
491 	if(strace_append == WAVE_NUM_STRACE_WINDOWS) break;
492 
493 	if(!GLOBALS->strace_ctx->shadow_straces)
494 		{
495 		goto strace_concat;
496 		}
497 
498 	swap_strace_contexts();
499 	st = GLOBALS->strace_ctx->straces;
500 	t = st ? st->trace : NULL;
501 	if(!t) {swap_strace_contexts(); goto strace_concat; }
502 	}
503 
504 if(!nodecnt) return(VCDSAV_EMPTY);
505 
506 
507 /* header */
508 if(lxt)
509 	{
510 	int dim;
511 
512 	lt_set_chg_compress(lt);
513 	lt_set_clock_compress(lt);
514 	lt_set_initial_value(lt, 'x');
515 	lt_set_time64(lt, 0);
516 	lt_symbol_bracket_stripping(lt, 1);
517 
518 	switch(GLOBALS->time_dimension)
519 		{
520 		case 'm':	dim = -3; break;
521 		case 'u':	dim = -6; break;
522 		case 'n':	dim = -9; break;
523 		case 'p':	dim = -12; break;
524 		case 'f':	dim = -15; break;
525 		default: 	dim = 0; break;
526 		}
527 
528 	lt_set_timescale(lt, dim);
529 	}
530 	else
531 	{
532 	if(export_typ != WAVE_EXPORT_TRANS)
533 		{
534 		time(&walltime);
535 		w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$date\n");
536 		w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "\t%s",asctime(localtime(&walltime)));
537 		w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$end\n");
538 		w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$version\n\t"WAVE_VERSION_INFO"\n$end\n");
539 		w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$timescale\n\t%d%c%s\n$end\n", (int)GLOBALS->time_scale, GLOBALS->time_dimension, (GLOBALS->time_dimension=='s') ? "" : "s");
540 		if(GLOBALS->global_time_offset) { w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$timezero\n\t"TTFormat"\n$end\n",GLOBALS->global_time_offset); }
541 		}
542 		else
543 		{
544 		w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$comment data_start %p $end\n", (void *)trans_head); /* arbitrary hex identifier */
545 		w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$comment name %s $end\n", trans_head->name ? trans_head->name : "UNKNOWN");
546 		w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$timescale %d%c%s $end\n", (int)GLOBALS->time_scale, GLOBALS->time_dimension, (GLOBALS->time_dimension=='s') ? "" : "s");
547 		if(GLOBALS->global_time_offset) { w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$timezero "TTFormat" $end\n",GLOBALS->global_time_offset); }
548 		w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$comment min_time "TTFormat" $end\n", GLOBALS->min_time / GLOBALS->time_scale);
549 		w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$comment max_time "TTFormat" $end\n", GLOBALS->max_time / GLOBALS->time_scale);
550 		}
551 	}
552 
553 if(export_typ == WAVE_EXPORT_TRANS)
554 	{
555         w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$comment max_seqn %d $end\n", nodecnt);
556 	if(t && t->transaction_args)
557 		{
558 		w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$comment args \"%s\" $end\n", t->transaction_args);
559 		}
560         }
561 
562 /* write out netnames here ... */
563 hp_clone = GLOBALS->hp_vcd_saver_c_1 = calloc_2(nodecnt, sizeof(vcdsav_Tree *));
564 recurse_build(vt, &hp_clone);
565 
566 for(i=0;i<nodecnt;i++)
567 	{
568 	int was_packed = HIER_DEPACK_STATIC;
569 	char *hname = hier_decompress_flagged(GLOBALS->hp_vcd_saver_c_1[i]->item->nname, &was_packed);
570 	char *netname = lxt ? hname : output_hier(is_trans, hname);
571 
572 	if(export_typ == WAVE_EXPORT_TRANS)
573 		{
574 	        w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$comment seqn %d %s $end\n", GLOBALS->hp_vcd_saver_c_1[i]->val, hname);
575 	        }
576 
577 	if(GLOBALS->hp_vcd_saver_c_1[i]->flags & (HIST_REAL|HIST_STRING))
578 		{
579 		if(lxt)
580 			{
581 			GLOBALS->hp_vcd_saver_c_1[i]->handle.p = lt_symbol_add(lt, netname, 0, 0, 0, GLOBALS->hp_vcd_saver_c_1[i]->flags & HIST_STRING ? LT_SYM_F_STRING : LT_SYM_F_DOUBLE);
582 			}
583 			else
584 			{
585 			const char *typ = (GLOBALS->hp_vcd_saver_c_1[i]->flags & HIST_STRING) ? "string" : "real";
586 			int tlen = (GLOBALS->hp_vcd_saver_c_1[i]->flags & HIST_STRING) ? 0 : 1;
587 			w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$var %s %d %s %s $end\n", typ, tlen, vcdid(GLOBALS->hp_vcd_saver_c_1[i]->val, export_typ), netname);
588 			}
589 		}
590 		else
591 		{
592 		int msi = -1, lsi = -1;
593 
594 		if(GLOBALS->hp_vcd_saver_c_1[i]->item->extvals)
595 			{
596 			msi = GLOBALS->hp_vcd_saver_c_1[i]->item->msi;
597 			lsi = GLOBALS->hp_vcd_saver_c_1[i]->item->lsi;
598 			}
599 
600 		if(msi==lsi)
601 			{
602 			if(lxt)
603 				{
604 				int strand_idx = strand_pnt(netname);
605 				if(strand_idx >= 0)
606 					{
607 					msi = lsi = atoi(netname + strand_idx + 1);
608 					}
609 				GLOBALS->hp_vcd_saver_c_1[i]->handle.p = lt_symbol_add(lt, netname, 0, msi, lsi, LT_SYM_F_BITS);
610 				}
611 				else
612 				{
613 				w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$var %s 1 %s %s $end\n", vartype_strings[GLOBALS->hp_vcd_saver_c_1[i]->item->vartype], vcdid(GLOBALS->hp_vcd_saver_c_1[i]->val, export_typ), netname);
614 				}
615 			}
616 			else
617 			{
618 			int len = (msi < lsi) ? (lsi - msi + 1) : (msi - lsi + 1);
619 			if(lxt)
620 				{
621 				GLOBALS->hp_vcd_saver_c_1[i]->handle.p = lt_symbol_add(lt, netname, 0, msi, lsi, LT_SYM_F_BITS);
622 				}
623 				else
624 				{
625 				w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$var %s %d %s %s $end\n", vartype_strings[GLOBALS->hp_vcd_saver_c_1[i]->item->vartype], len, vcdid(GLOBALS->hp_vcd_saver_c_1[i]->val, export_typ), netname);
626 				}
627 			GLOBALS->hp_vcd_saver_c_1[i]->len = len;
628 			if(len > max_len) max_len = len;
629 			}
630 		}
631 
632 	/* if(was_packed) { free_2(hname); } ...not needed for HIER_DEPACK_STATIC */
633 	}
634 
635 row_data = malloc_2(max_len + 1);
636 
637 if(!lxt)
638 	{
639 	output_hier(is_trans, "");
640 	free_hier();
641 
642 	w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$enddefinitions $end\n");
643 	}
644 
645 /* value changes */
646 
647 for(i=(nodecnt/2-1);i>0;i--)        /* build nodes into having heap property */
648         {
649         heapify(i,nodecnt);
650         }
651 
652 for(;;)
653 	{
654 	heapify(0, nodecnt);
655 
656 	if(!GLOBALS->hp_vcd_saver_c_1[0]->hist) break;
657 	if(GLOBALS->hp_vcd_saver_c_1[0]->hist->time > GLOBALS->max_time) break;
658 
659 	if((GLOBALS->hp_vcd_saver_c_1[0]->hist->time != prevtime) && (GLOBALS->hp_vcd_saver_c_1[0]->hist->time >= LLDescriptor(0)))
660 		{
661 		TimeType tnorm = GLOBALS->hp_vcd_saver_c_1[0]->hist->time;
662 		if(GLOBALS->time_scale != 1)
663 			{
664 			tnorm /= GLOBALS->time_scale;
665 			}
666 
667 		if(lxt)
668 			{
669 			lt_set_time64(lt, tnorm);
670 			}
671 			else
672 			{
673 			if(dumpvars_state == 1) { w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$end\n"); dumpvars_state = 2; }
674 			w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "#"TTFormat"\n", tnorm);
675 			if(!dumpvars_state) { w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$dumpvars\n"); dumpvars_state = 1; }
676 			}
677 		prevtime = GLOBALS->hp_vcd_saver_c_1[0]->hist->time;
678 		}
679 
680 	if(GLOBALS->hp_vcd_saver_c_1[0]->hist->time >= LLDescriptor(0))
681 		{
682 		if(GLOBALS->hp_vcd_saver_c_1[0]->flags & (HIST_REAL|HIST_STRING))
683 			{
684 			if(GLOBALS->hp_vcd_saver_c_1[0]->flags & HIST_STRING)
685 				{
686 				char *vec = GLOBALS->hp_vcd_saver_c_1[0]->hist->v.h_vector ? GLOBALS->hp_vcd_saver_c_1[0]->hist->v.h_vector : "UNDEF";
687 
688 				if(lxt)
689 					{
690 					lt_emit_value_string(lt, GLOBALS->hp_vcd_saver_c_1[0]->handle.p, 0, vec);
691 					}
692 					else
693 					{
694 					int vec_slen = strlen(vec);
695 					char *vec_escaped = malloc_2(vec_slen*4 + 1); /* worst case */
696 					int vlen = fstUtilityBinToEsc((unsigned char *)vec_escaped, (unsigned char *)vec, vec_slen);
697 
698 					vec_escaped[vlen] = 0;
699 					if(vlen)
700 						{
701 						w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "s%s %s\n", vec_escaped, vcdid(GLOBALS->hp_vcd_saver_c_1[0]->val, export_typ));
702 						}
703 						else
704 						{
705 						w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "s\\000 %s\n", vcdid(GLOBALS->hp_vcd_saver_c_1[0]->val, export_typ));
706 						}
707 					free_2(vec_escaped);
708 					}
709 				}
710 				else
711 				{
712 #ifdef WAVE_HAS_H_DOUBLE
713 				double *d = &GLOBALS->hp_vcd_saver_c_1[0]->hist->v.h_double;
714 #else
715 				double *d = (double *)GLOBALS->hp_vcd_saver_c_1[0]->hist->v.h_vector;
716 #endif
717                                 double value;
718 
719 				if(!d)
720 					{
721 	                                sscanf("NaN", "%lg", &value);
722 					}
723 					else
724 					{
725 					value = *d;
726 					}
727 
728 				if(lxt)
729 					{
730 					lt_emit_value_double(lt, GLOBALS->hp_vcd_saver_c_1[0]->handle.p, 0, value);
731 					}
732 					else
733 					{
734 					w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "r%.16g %s\n", value, vcdid(GLOBALS->hp_vcd_saver_c_1[0]->val, export_typ));
735 					}
736 				}
737 			}
738 		else
739 		if(GLOBALS->hp_vcd_saver_c_1[0]->len)
740 			{
741 			if(GLOBALS->hp_vcd_saver_c_1[0]->hist->v.h_vector)
742 				{
743 				for(i=0;i<GLOBALS->hp_vcd_saver_c_1[0]->len;i++)
744 					{
745 					row_data[i] = analyzer_demang(lxt, GLOBALS->hp_vcd_saver_c_1[0]->hist->v.h_vector[i]);
746 					}
747 				}
748 				else
749 				{
750 				for(i=0;i<GLOBALS->hp_vcd_saver_c_1[0]->len;i++)
751 					{
752 					row_data[i] = 'x';
753 					}
754 				}
755 			row_data[i] = 0;
756 
757 			if(lxt)
758 				{
759 				lt_emit_value_bit_string(lt, GLOBALS->hp_vcd_saver_c_1[0]->handle.p, 0, row_data);
760 				}
761 				else
762 				{
763 				w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "b%s %s\n", vcd_truncate_bitvec(row_data), vcdid(GLOBALS->hp_vcd_saver_c_1[0]->val, export_typ));
764 				}
765 			}
766 		else
767 			{
768 			if(lxt)
769 				{
770 				row_data[0] = analyzer_demang(lxt, GLOBALS->hp_vcd_saver_c_1[0]->hist->v.h_val);
771 				row_data[1] = 0;
772 
773 				lt_emit_value_bit_string(lt, GLOBALS->hp_vcd_saver_c_1[0]->handle.p, 0, row_data);
774 				}
775 				else
776 				{
777 				w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "%c%s\n", analyzer_demang(lxt, GLOBALS->hp_vcd_saver_c_1[0]->hist->v.h_val), vcdid(GLOBALS->hp_vcd_saver_c_1[0]->val, export_typ));
778 				}
779 			}
780 		}
781 
782 	GLOBALS->hp_vcd_saver_c_1[0]->hist = GLOBALS->hp_vcd_saver_c_1[0]->hist->next;
783 	}
784 
785 if(prevtime < GLOBALS->max_time)
786 	{
787 	if(lxt)
788 		{
789 		lt_set_time64(lt, GLOBALS->max_time / GLOBALS->time_scale);
790 		}
791 		else
792 		{
793 		if(dumpvars_state == 1) { w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$end\n"); dumpvars_state = 2; }
794 		w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "#"TTFormat"\n", GLOBALS->max_time / GLOBALS->time_scale);
795 		}
796 	}
797 
798 
799 for(i=0;i<nodecnt;i++)
800 	{
801 	free_2(GLOBALS->hp_vcd_saver_c_1[i]);
802 	}
803 
804 free_2(GLOBALS->hp_vcd_saver_c_1); GLOBALS->hp_vcd_saver_c_1 = NULL;
805 free_2(row_data); row_data = NULL;
806 
807 if(lxt)
808 	{
809 	lt_close(lt); lt = NULL;
810 	}
811 	else
812 	{
813 	if(export_typ != WAVE_EXPORT_TRANS)
814 		{
815 		fclose(GLOBALS->f_vcd_saver_c_1);
816 		}
817 		else
818 		{
819 		w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$comment data_end %p $end\n", (void *)trans_head); /* arbitrary hex identifier */
820 #if !defined _MSC_VER && !defined __MINGW32__
821 		fflush(GLOBALS->f_vcd_saver_c_1);
822 #endif
823 		}
824 
825 	GLOBALS->f_vcd_saver_c_1 = NULL;
826 	}
827 
828 return(VCDSAV_OK);
829 }
830 
831 
832 
save_nodes_to_export(const char * fname,int export_typ)833 int save_nodes_to_export(const char *fname, int export_typ)
834 {
835 return(save_nodes_to_export_generic(NULL, NULL, fname, export_typ));
836 }
837 
save_nodes_to_trans(FILE * trans,Trptr t)838 int save_nodes_to_trans(FILE *trans, Trptr t)
839 {
840 return(save_nodes_to_export_generic(trans, t, NULL, WAVE_EXPORT_TRANS));
841 }
842 
843 
844 /************************ scopenav ************************/
845 
846 struct namehier
847 {
848 struct namehier *next;
849 char *name;
850 char not_final;
851 };
852 
853 
854 
free_hier(void)855 void free_hier(void)
856 {
857 struct namehier *nhtemp;
858 
859 while(GLOBALS->nhold_vcd_saver_c_1)
860 	{
861 	nhtemp=GLOBALS->nhold_vcd_saver_c_1->next;
862 	free_2(GLOBALS->nhold_vcd_saver_c_1->name);
863 	free_2(GLOBALS->nhold_vcd_saver_c_1);
864 	GLOBALS->nhold_vcd_saver_c_1=nhtemp;
865 	}
866 }
867 
868 /*
869  * navigate up and down the scope hierarchy and
870  * emit the appropriate vcd scope primitives
871  */
diff_hier(int is_trans,struct namehier * nh1,struct namehier * nh2)872 static void diff_hier(int is_trans, struct namehier *nh1, struct namehier *nh2)
873 {
874 /* struct namehier *nhtemp; */ /* scan-build */
875 
876 if(!nh2)
877 	{
878 	while((nh1)&&(nh1->not_final))
879 		{
880 		w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$scope module %s $end\n", nh1->name);
881 		nh1=nh1->next;
882 		}
883 	return;
884 	}
885 
886 for(;;)
887 	{
888 	if((nh1->not_final==0)&&(nh2->not_final==0)) /* both are equal */
889 		{
890 		break;
891 		}
892 
893 	if(nh2->not_final==0)	/* old hier is shorter */
894 		{
895 		/* nhtemp=nh1; */ /* scan-build */
896 		while((nh1)&&(nh1->not_final))
897 			{
898 			w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$scope module %s $end\n", nh1->name);
899 			nh1=nh1->next;
900 			}
901 		break;
902 		}
903 
904 	if(nh1->not_final==0)	/* new hier is shorter */
905 		{
906 		/* nhtemp=nh2; */ /* scan-build */
907 		while((nh2)&&(nh2->not_final))
908 			{
909 			w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$upscope $end\n");
910 			nh2=nh2->next;
911 			}
912 		break;
913 		}
914 
915 	if(strcmp(nh1->name, nh2->name))
916 		{
917 		/* nhtemp=nh2; */ /* prune old hier */ /* scan-build */
918 		while((nh2)&&(nh2->not_final))
919 			{
920 			w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$upscope $end\n");
921 			nh2=nh2->next;
922 			}
923 
924 		/* nhtemp=nh1; */ /* add new hier */ /* scan-build */
925 		while((nh1)&&(nh1->not_final))
926 			{
927 			w32redirect_fprintf(is_trans, GLOBALS->f_vcd_saver_c_1, "$scope module %s $end\n", nh1->name);
928 			nh1=nh1->next;
929 			}
930 		break;
931 		}
932 
933 	nh1=nh1->next;
934 	nh2=nh2->next;
935 	}
936 }
937 
938 
939 /*
940  * output scopedata for a given name if needed, return pointer to name string
941  */
output_hier(int is_trans,char * name)942 char *output_hier(int is_trans, char *name)
943 {
944 char *pnt, *pnt2;
945 char *s;
946 int len;
947 struct namehier *nh_head=NULL, *nh_curr=NULL, *nhtemp;
948 
949 pnt=pnt2=name;
950 
951 for(;;)
952 {
953 if(*pnt2 == '\\')
954 	{
955 	while(*pnt2) pnt2++;
956 	}
957 	else
958 	{
959 	/* while((*pnt2!='.')&&(*pnt2)) pnt2++; ... does not handle dot at end of name */
960 
961 	while(*pnt2)
962 		{
963 		if(*pnt2!='.')
964 			{
965 			pnt2++;
966 			continue;
967 			}
968 			else
969 			{
970 			if(!*(pnt2+1))	/* if dot is at end of name */
971 				{
972 				pnt2++;
973 				continue;
974 				}
975 				else
976 				{
977 				break;
978 				}
979 			}
980 		}
981 	}
982 
983 s=(char *)calloc_2(1,(len=pnt2-pnt)+1);
984 memcpy(s, pnt, len);
985 nhtemp=(struct namehier *)calloc_2(1,sizeof(struct namehier));
986 nhtemp->name=s;
987 
988 if(!nh_curr)
989 	{
990 	nh_head=nh_curr=nhtemp;
991 	}
992 	else
993 	{
994 	nh_curr->next=nhtemp;
995 	nh_curr->not_final=1;
996 	nh_curr=nhtemp;
997 	}
998 
999 if(!*pnt2) break;
1000 pnt=(++pnt2);
1001 }
1002 
1003 diff_hier(is_trans, nh_head, GLOBALS->nhold_vcd_saver_c_1);
1004 free_hier();
1005 GLOBALS->nhold_vcd_saver_c_1=nh_head;
1006 
1007 	{
1008 	char *mti_sv_patch = strstr(nh_curr->name, "]["); 	/* case is: #implicit-var###VarElem:ram_di[0.0] [63:0] */
1009 	if(mti_sv_patch)
1010 		{
1011 		char *t = calloc_2(1, strlen(nh_curr->name) + 1 + 1);
1012 
1013 		*mti_sv_patch = 0;
1014 		sprintf(t, "%s] %s", nh_curr->name, mti_sv_patch+1);
1015 
1016 		free_2(nh_curr->name);
1017 		nh_curr->name = t;
1018 		}
1019 
1020 	if((nh_curr->name[0] == '\\') && (nh_curr->name[1] == '#'))
1021 		{
1022 		return(nh_curr->name+1);
1023 		}
1024 	}
1025 
1026 return(nh_curr->name);
1027 }
1028 
1029 
1030 /****************************************/
1031 /***                                  ***/
1032 /*** output in timing analyzer format ***/
1033 /***                                  ***/
1034 /****************************************/
1035 
write_hptr_trace(Trptr t,int * whichptr,TimeType tmin,TimeType tmax)1036 static void write_hptr_trace(Trptr t, int *whichptr, TimeType tmin, TimeType tmax)
1037 {
1038 nptr n = t->n.nd;
1039 hptr *ha = n->harray;
1040 int numhist = n->numhist;
1041 int i;
1042 unsigned char h_val = AN_X;
1043 gboolean first;
1044 gboolean invert = ((t->flags&TR_INVERT) != 0);
1045 int edges = 0;
1046 
1047 first = TRUE;
1048 for(i=0;i<numhist;i++)
1049 	{
1050 	if(ha[i]->time < tmin)
1051 		{
1052 		}
1053 	else
1054 	if(ha[i]->time > tmax)
1055 		{
1056 		break;
1057 		}
1058 	else
1059 		{
1060 		if((ha[i]->time != tmin) || (!first))
1061 			{
1062 			edges++;
1063 			}
1064 
1065 		first = FALSE;
1066 		}
1067 	}
1068 
1069 
1070 first = TRUE;
1071 for(i=0;i<numhist;i++)
1072 	{
1073 	if(ha[i]->time < tmin)
1074 		{
1075 		h_val = invert ? AN_USTR_INV[ha[i]->v.h_val] : AN_USTR[ha[i]->v.h_val];
1076 		}
1077 	else
1078 	if(ha[i]->time > tmax)
1079 		{
1080 		break;
1081 		}
1082 	else
1083 		{
1084 		if(first)
1085 			{
1086 			gboolean skip_this = (ha[i]->time == tmin);
1087 
1088 			if(skip_this)
1089 				{
1090 				h_val = invert ? AN_USTR_INV[ha[i]->v.h_val] : AN_USTR[ha[i]->v.h_val];
1091 				}
1092 
1093 			w32redirect_fprintf(0, GLOBALS->f_vcd_saver_c_1,
1094 				"Digital_Signal\n"
1095 				"     Position:          %d\n"
1096 				"     Height:            24\n"
1097 				"     Space_Above:       24\n"
1098 				"     Name:              %s\n"
1099 				"     Start_State:       %c\n"
1100 				"     Number_Edges:      %d\n"
1101 				"     Rise_Time:         0.2\n"
1102 				"     Fall_Time:         0.2\n",
1103 					*whichptr,
1104 					t->name,
1105 					h_val,
1106 					edges);
1107 			first = FALSE;
1108 
1109 			if(skip_this)
1110 				{
1111 				continue;
1112 				}
1113 			}
1114 
1115 		h_val = invert ? AN_USTR_INV[ha[i]->v.h_val] : AN_USTR[ha[i]->v.h_val];
1116 		w32redirect_fprintf(0, GLOBALS->f_vcd_saver_c_1, "          Edge:               "TTFormat".0 %c\n", ha[i]->time, h_val);
1117 		}
1118 	}
1119 
1120 if(first)
1121 	{
1122 	/* need to emit blank trace */
1123 	w32redirect_fprintf(0, GLOBALS->f_vcd_saver_c_1,
1124 		"Digital_Signal\n"
1125 		"     Position:          %d\n"
1126 		"     Height:            24\n"
1127 		"     Space_Above:       24\n"
1128 		"     Name:              %s\n"
1129 		"     Start_State:       %c\n"
1130 		"     Number_Edges:      %d\n"
1131 		"     Rise_Time:         10.0\n"
1132 		"     Fall_Time:         10.0\n",
1133 			*whichptr,
1134 			t->name,
1135 			h_val,
1136 			edges);
1137 	}
1138 
1139 (*whichptr)++;
1140 }
1141 
1142 /***/
1143 
format_value_string(char * s)1144 static void format_value_string(char *s)
1145 {
1146 char *s_orig = s;
1147 
1148 if((s)&&(*s))
1149 	{
1150 	gboolean is_all_z = TRUE;
1151 	gboolean is_all_x = TRUE;
1152 
1153 	while(*s)
1154 		{
1155 		if((*s != 'z') && (*s != 'Z'))
1156 			{
1157 			is_all_z = FALSE;
1158 			}
1159 		if((*s != 'x') && (*s != 'X'))
1160 			{
1161 			is_all_x = FALSE;
1162 			}
1163 
1164 		/* if(isspace(*s)) *s='_'; ...not needed */
1165 		s++;
1166 		}
1167 
1168 	if(is_all_z)
1169 		{
1170 		*(s_orig++) = 'Z';
1171 		*(s_orig) = 0;
1172 		}
1173 	else
1174 	if(is_all_x)
1175 		{
1176 		*(s_orig++) = 'X';
1177 		*(s_orig) = 0;
1178 		}
1179 	}
1180 }
1181 
get_hptr_vector_val(Trptr t,hptr h)1182 static char *get_hptr_vector_val(Trptr t, hptr h)
1183 {
1184 char *ascii = NULL;
1185 
1186 if(h->time < LLDescriptor(0))
1187 	{
1188 	ascii=strdup_2("X");
1189 	}
1190 else
1191 if(h->flags&HIST_REAL)
1192 	{
1193         if(!(h->flags&HIST_STRING))
1194         	{
1195 #ifdef WAVE_HAS_H_DOUBLE
1196                 ascii=convert_ascii_real(t, &h->v.h_double);
1197 #else
1198                 ascii=convert_ascii_real(t, (double *)h->v.h_vector);
1199 #endif
1200                 }
1201                 else
1202                 {
1203                 ascii=convert_ascii_string((char *)h->v.h_vector);
1204                 }
1205 	}
1206         else
1207         {
1208         ascii=convert_ascii_vec(t,h->v.h_vector);
1209         }
1210 
1211 format_value_string(ascii);
1212 return(ascii);
1213 }
1214 
1215 static const char *vcdsav_dtypes[] = { "Bin", "Hex", "Text" };
1216 
determine_trace_data_type(char * s,int curtype)1217 static int determine_trace_data_type(char *s, int curtype)
1218 {
1219 int i;
1220 
1221 if((s) && (curtype != VCDSAV_IS_TEXT))
1222 	{
1223 	int len = strlen(s);
1224 	for(i=0;i<len;i++)
1225 		{
1226 		int ch = (int)((unsigned char)s[i]);
1227 
1228 		if(strchr("01xXzZhHuUwWlL-?_", ch))
1229 			{
1230 			/* nothing */
1231 			}
1232 		else if(strchr("23456789aAbBcCdDeEfF", ch))
1233 			{
1234 			curtype = VCDSAV_IS_HEX;
1235 			}
1236 		else
1237 			{
1238 			curtype = VCDSAV_IS_TEXT;
1239 			break;
1240 			}
1241 		}
1242 	}
1243 
1244 return(curtype);
1245 }
1246 
1247 
write_hptr_trace_vector(Trptr t,int * whichptr,TimeType tmin,TimeType tmax)1248 static void write_hptr_trace_vector(Trptr t, int *whichptr, TimeType tmin, TimeType tmax)
1249 {
1250 nptr n = t->n.nd;
1251 hptr *ha = n->harray;
1252 int numhist = n->numhist;
1253 int i;
1254 char *h_val = NULL;
1255 gboolean first;
1256 int edges = 0;
1257 int curtype = VCDSAV_IS_BIN;
1258 
1259 first = TRUE;
1260 for(i=0;i<numhist;i++)
1261 	{
1262 	if(ha[i]->time < tmin)
1263 		{
1264 		}
1265 	else
1266 	if(ha[i]->time > tmax)
1267 		{
1268 		break;
1269 		}
1270 	else
1271 		{
1272 		char *s = get_hptr_vector_val(t, ha[i]);
1273 		if(s)
1274 			{
1275 			curtype = determine_trace_data_type(s, curtype);
1276 			free_2(s);
1277 			}
1278 
1279 		if((ha[i]->time != tmin) || (!first))
1280 			{
1281 			edges++;
1282 			}
1283 
1284 		first = FALSE;
1285 		}
1286 	}
1287 
1288 
1289 first = TRUE;
1290 for(i=0;i<numhist;i++)
1291 	{
1292 	if(ha[i]->time < tmin)
1293 		{
1294 		if(h_val) free_2(h_val);
1295 		h_val = get_hptr_vector_val(t, ha[i]);
1296 		}
1297 	else
1298 	if(ha[i]->time > tmax)
1299 		{
1300 		break;
1301 		}
1302 	else
1303 		{
1304 		if(first)
1305 			{
1306 			gboolean skip_this = (ha[i]->time == tmin);
1307 
1308 			if(skip_this)
1309 				{
1310 				if(h_val) free_2(h_val);
1311 				h_val = get_hptr_vector_val(t, ha[i]);
1312 				}
1313 
1314 			w32redirect_fprintf(0, GLOBALS->f_vcd_saver_c_1,
1315 				"Digital_Bus\n"
1316 				"     Position:          %d\n"
1317 				"     Height:            24\n"
1318 				"     Space_Above:       24\n"
1319 				"     Name:              %s\n"
1320 				"     Start_State:       %s\n"
1321 				"     State_Format:      %s\n"
1322 				"     Number_Edges:      %d\n"
1323 				"     Rise_Time:         0.2\n"
1324 				"     Fall_Time:         0.2\n",
1325 					*whichptr,
1326 					t->name,
1327 					h_val,
1328 					vcdsav_dtypes[curtype],
1329 					edges);
1330 			first = FALSE;
1331 
1332 			if(skip_this)
1333 				{
1334 				continue;
1335 				}
1336 			}
1337 
1338 		if(h_val) free_2(h_val);
1339 		h_val = get_hptr_vector_val(t, ha[i]);
1340 		w32redirect_fprintf(0, GLOBALS->f_vcd_saver_c_1, "          Edge:               "TTFormat".0 %s\n", ha[i]->time, h_val);
1341 		}
1342 	}
1343 
1344 if(first)
1345 	{
1346 	/* need to emit blank trace */
1347 	w32redirect_fprintf(0, GLOBALS->f_vcd_saver_c_1,
1348 		"Digital_Bus\n"
1349 		"     Position:          %d\n"
1350 		"     Height:            24\n"
1351 		"     Space_Above:       24\n"
1352 		"     Name:              %s\n"
1353 		"     Start_State:       %s\n"
1354 		"     State_Format:      %s\n"
1355 		"     Number_Edges:      %d\n"
1356 		"     Rise_Time:         10.0\n"
1357 		"     Fall_Time:         10.0\n",
1358 			*whichptr,
1359 			t->name,
1360 			h_val,
1361 			vcdsav_dtypes[curtype],
1362 			edges);
1363 	}
1364 
1365 if(h_val) free_2(h_val);
1366 (*whichptr)++;
1367 }
1368 
1369 /***/
1370 
get_vptr_vector_val(Trptr t,vptr v)1371 static char *get_vptr_vector_val(Trptr t, vptr v)
1372 {
1373 char *ascii = NULL;
1374 
1375 if(v->time < LLDescriptor(0))
1376 	{
1377 	ascii=strdup_2("X");
1378 	}
1379 else
1380         {
1381         ascii=convert_ascii(t,v);
1382         }
1383 
1384 if(!ascii)
1385 	{
1386 	ascii=strdup_2("X");
1387 	}
1388 
1389 format_value_string(ascii);
1390 return(ascii);
1391 }
1392 
1393 
write_vptr_trace(Trptr t,int * whichptr,TimeType tmin,TimeType tmax)1394 static void write_vptr_trace(Trptr t, int *whichptr, TimeType tmin, TimeType tmax)
1395 {
1396 vptr *ha = t->n.vec->vectors;
1397 int numhist = t->n.vec->numregions;
1398 int i;
1399 char *h_val = NULL;
1400 gboolean first;
1401 int edges = 0;
1402 int curtype = VCDSAV_IS_BIN;
1403 
1404 first = TRUE;
1405 for(i=0;i<numhist;i++)
1406 	{
1407 	if(ha[i]->time < tmin)
1408 		{
1409 		}
1410 	else
1411 	if(ha[i]->time > tmax)
1412 		{
1413 		break;
1414 		}
1415 	else
1416 		{
1417 		char *s = get_vptr_vector_val(t, ha[i]);
1418 		if(s)
1419 			{
1420 			curtype = determine_trace_data_type(s, curtype);
1421 			free_2(s);
1422 			}
1423 
1424 		if((ha[i]->time != tmin) || (!first))
1425 			{
1426 			edges++;
1427 			}
1428 
1429 		first = FALSE;
1430 		}
1431 	}
1432 
1433 
1434 first = TRUE;
1435 for(i=0;i<numhist;i++)
1436 	{
1437 	if(ha[i]->time < tmin)
1438 		{
1439 		if(h_val) free_2(h_val);
1440 		h_val = get_vptr_vector_val(t, ha[i]);
1441 		}
1442 	else
1443 	if(ha[i]->time > tmax)
1444 		{
1445 		break;
1446 		}
1447 	else
1448 		{
1449 		if(first)
1450 			{
1451 			gboolean skip_this = (ha[i]->time == tmin);
1452 
1453 			if(skip_this)
1454 				{
1455 				if(h_val) free_2(h_val);
1456 				h_val = get_vptr_vector_val(t, ha[i]);
1457 				}
1458 
1459 			w32redirect_fprintf(0, GLOBALS->f_vcd_saver_c_1,
1460 				"Digital_Bus\n"
1461 				"     Position:          %d\n"
1462 				"     Height:            24\n"
1463 				"     Space_Above:       24\n"
1464 				"     Name:              %s\n"
1465 				"     Start_State:       %s\n"
1466 				"     State_Format:      %s\n"
1467 				"     Number_Edges:      %d\n"
1468 				"     Rise_Time:         0.2\n"
1469 				"     Fall_Time:         0.2\n",
1470 					*whichptr,
1471 					t->name,
1472 					h_val,
1473 					vcdsav_dtypes[curtype],
1474 					edges);
1475 			first = FALSE;
1476 
1477 			if(skip_this)
1478 				{
1479 				continue;
1480 				}
1481 			}
1482 
1483 		if(h_val) free_2(h_val);
1484 		h_val = get_vptr_vector_val(t, ha[i]);
1485 		w32redirect_fprintf(0, GLOBALS->f_vcd_saver_c_1, "          Edge:               "TTFormat".0 %s\n", ha[i]->time, h_val);
1486 		}
1487 	}
1488 
1489 if(first)
1490 	{
1491 	/* need to emit blank trace */
1492 	w32redirect_fprintf(0, GLOBALS->f_vcd_saver_c_1,
1493 		"Digital_Bus\n"
1494 		"     Position:          %d\n"
1495 		"     Height:            24\n"
1496 		"     Space_Above:       24\n"
1497 		"     Name:              %s\n"
1498 		"     Start_State:       %s\n"
1499 		"     State_Format:      %s\n"
1500 		"     Number_Edges:      %d\n"
1501 		"     Rise_Time:         10.0\n"
1502 		"     Fall_Time:         10.0\n",
1503 			*whichptr,
1504 			t->name,
1505 			h_val,
1506 			vcdsav_dtypes[curtype],
1507 			edges);
1508 	}
1509 
1510 if(h_val) free_2(h_val);
1511 (*whichptr)++;
1512 }
1513 
1514 
write_tim_tracedata(Trptr t,int * whichptr,TimeType tmin,TimeType tmax)1515 static void write_tim_tracedata(Trptr t, int *whichptr, TimeType tmin, TimeType tmax)
1516 {
1517 if(!(t->flags&(TR_EXCLUDE|TR_BLANK|TR_ANALOG_BLANK_STRETCH)))
1518 	{
1519         GLOBALS->shift_timebase=t->shift;
1520         if(!t->vector)
1521         	{
1522                 if(!t->n.nd->extvals)
1523                 	{
1524 			write_hptr_trace(t, whichptr, tmin, tmax); /* single-bit */
1525                         }
1526                         else
1527                         {
1528 			write_hptr_trace_vector(t, whichptr, tmin, tmax); /* multi-bit */
1529                         }
1530 		}
1531                 else
1532                 {
1533 		write_vptr_trace(t, whichptr, tmin, tmax); /* synthesized/concatenated vector */
1534                 }
1535 	}
1536 }
1537 
1538 
do_timfile_save(const char * fname)1539 int do_timfile_save(const char *fname)
1540 {
1541 const char *time_prefix=WAVE_SI_UNITS;
1542 const double negpow[] = { 1.0, 1.0e-3, 1.0e-6, 1.0e-9, 1.0e-12, 1.0e-15, 1.0e-18, 1.0e-21 };
1543 char *pnt;
1544 int offset;
1545 Trptr t = GLOBALS->traces.first;
1546 int i = 1; /* trace index in the .tim file */
1547 TimeType tmin, tmax;
1548 
1549 errno = 0;
1550 
1551 if((GLOBALS->tims.marker > LLDescriptor(0)) && (GLOBALS->tims.baseline > LLDescriptor(0)))
1552 	{
1553 	if(GLOBALS->tims.marker < GLOBALS->tims.baseline)
1554 		{
1555 	        tmin = GLOBALS->tims.marker;
1556 	        tmax = GLOBALS->tims.baseline;
1557 		}
1558 		else
1559 		{
1560 	        tmax = GLOBALS->tims.marker;
1561 	        tmin = GLOBALS->tims.baseline;
1562 		}
1563 	}
1564 	else
1565 	{
1566         tmin = GLOBALS->min_time;
1567         tmax = GLOBALS->max_time;
1568 	}
1569 
1570 GLOBALS->f_vcd_saver_c_1 = fopen(fname, "wb");
1571 if(!GLOBALS->f_vcd_saver_c_1)
1572 	{
1573         return(VCDSAV_FILE_ERROR);
1574         }
1575 
1576 pnt=strchr(time_prefix, (int)GLOBALS->time_dimension);
1577 if(pnt) { offset=pnt-time_prefix; } else offset=0;
1578 
1579 w32redirect_fprintf(0, GLOBALS->f_vcd_saver_c_1,
1580 	"Timing Analyzer Settings\n"
1581 	"     Time_Scale:        %E\n"
1582 	"     Time_Per_Division: %E\n"
1583 	"     NumberDivisions:   10\n"
1584 	"     Start_Time:        "TTFormat".0\n"
1585 	"     End_Time:          "TTFormat".0\n",
1586 
1587 	negpow[offset],
1588 	(tmax-tmin) / 10.0,
1589 	tmin,
1590 	tmax
1591 	);
1592 
1593 while(t)
1594 	{
1595 	write_tim_tracedata(t, &i, tmin, tmax);
1596         t = GiveNextTrace(t);
1597 	}
1598 
1599 fclose(GLOBALS->f_vcd_saver_c_1);
1600 GLOBALS->f_vcd_saver_c_1 = NULL;
1601 
1602 return(errno ? VCDSAV_FILE_ERROR : VCDSAV_OK);
1603 }
1604 
1605