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