1 /*
2 to compile:
3 g++ -o fsdb2vcd_fast -O2 fsdb2vcd_fast.cc -I /pub/FsdbReader/ /pub/FsdbReader/libnffr.a /pub/FsdbReader/libnsys.a -ldl -lpthread -lz
4
5 Much faster version of fsdb2vcd as compared to one bundled with Verdi.
6 Requires libs and headers for FsdbReader.
7 */
8
9 #ifdef NOVAS_FSDB
10 #undef NOVAS_FSDB
11 #endif
12
13 #include "ffrAPI.h"
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include <unistd.h>
19 #include <stdarg.h>
20 #include <errno.h>
21 #include <map>
22
23 #ifdef __GNUC__
24 /* non-portable trick that caches the ->second value of a RB tree entry for a given ->first key */
25 /* provides about 20% overall speedup */
26 #define BYPASS_RB_TREE_IF_POSSIBLE
27 #endif
28
29 #define __STDC_FORMAT_MACROS
30 #include <inttypes.h>
31
32 #define WRITEX_FILE_BUFFER_SIZE (64 * 1024)
33
34 #define T2U64(t) (((uint64_t)(t).H << 32) | ((uint64_t)(t).L))
35 #define XT2U64(xt) (((uint64_t)(xt).t64.H << 32) | ((uint64_t)(xt).t64.L))
36 #define FXT2U64(xt) (((uint64_t)(xt).hltag.H << 32) | ((uint64_t)(xt).hltag.L))
37
38 #ifndef FALSE
39 #define FALSE 0
40 #endif
41
42 #ifndef TRUE
43 #define TRUE 1
44 #endif
45
46 enum VcdVcTypes { VCD_VC_TYPE_BIT, VCD_VC_TYPE_BITVEC, VCD_VC_TYPE_REAL, VCD_VC_TYPE_PORT, VCD_VC_TYPE_IGNORE };
47
48 struct fsdbReaderBlackoutChain
49 {
50 uint64_t tim;
51 unsigned active : 1;
52 };
53
54
writex(int fd,char * s,int len)55 static void writex(int fd, char *s, int len)
56 {
57 const int mx = WRITEX_FILE_BUFFER_SIZE;
58 static char buf[mx];
59 static int pos = 0;
60
61 if(len)
62 {
63 if(len < mx)
64 {
65 if(pos + len >= mx)
66 {
67 writex(fd, NULL, 0);
68 }
69
70 memcpy(buf + pos, s, len);
71 pos += len;
72 }
73 else
74 {
75 writex(fd, NULL, 0);
76 write(fd, s, len);
77 }
78 }
79 else
80 {
81 if(pos)
82 {
83 write(fd, buf, pos);
84 pos = 0;
85 }
86 }
87 }
88
89
makeVcdID(unsigned int value,int * idlen)90 static char *makeVcdID(unsigned int value, int *idlen)
91 {
92 static char buf[16];
93 char *pnt = buf;
94
95 /* zero is illegal for a value...it is assumed they start at one */
96 while (value)
97 {
98 value--;
99 *(pnt++) = (char)('!' + value % 94);
100 value = value / 94;
101 }
102
103 *pnt = 0;
104 *idlen = pnt - buf;
105 return(buf);
106 }
107
108
__TreeCB(fsdbTreeCBType cb_type,void * client_data,void * tree_cb_data)109 static bool_T __TreeCB(fsdbTreeCBType cb_type, void *client_data, void *tree_cb_data)
110 {
111 return(TRUE);
112 }
113
114
115 static bool_T __MyTreeCB(fsdbTreeCBType cb_type, void *client_data, void *tree_cb_data);
116
117
fsdbReaderOpenFile(char * nam)118 static void *fsdbReaderOpenFile(char *nam)
119 {
120 fsdbFileType ft;
121 uint_T blk_idx = 0;
122
123 if(!ffrObject::ffrIsFSDB(nam))
124 {
125 return(NULL);
126 }
127
128 ffrFSDBInfo fsdb_info;
129 ffrObject::ffrGetFSDBInfo(nam, fsdb_info);
130 if((fsdb_info.file_type != FSDB_FT_VERILOG) && (fsdb_info.file_type != FSDB_FT_VERILOG_VHDL) && (fsdb_info.file_type != FSDB_FT_VHDL))
131 {
132 return(NULL);
133 }
134
135 ffrObject *fsdb_obj = ffrObject::ffrOpen3(nam);
136 if(!fsdb_obj)
137 {
138 return(NULL);
139 }
140
141 fsdb_obj->ffrSetTreeCBFunc(__TreeCB, NULL);
142
143 ft = fsdb_obj->ffrGetFileType();
144 if((ft != FSDB_FT_VERILOG) && (ft != FSDB_FT_VERILOG_VHDL) && (ft != FSDB_FT_VHDL))
145 {
146 fsdb_obj->ffrClose();
147 return(NULL);
148 }
149
150 fsdb_obj->ffrReadDataTypeDefByBlkIdx(blk_idx); /* necessary if FSDB file has transaction data ... we don't process this but it prevents possible crashes */
151
152 return((void *)fsdb_obj);
153 }
154
155
fsdbReaderReadScopeVarTree(void * ctx,FILE * cb)156 static void fsdbReaderReadScopeVarTree(void *ctx, FILE *cb)
157 {
158 ffrObject *fsdb_obj = (ffrObject *)ctx;
159
160 fsdb_obj->ffrSetTreeCBFunc(__MyTreeCB, (void *) cb);
161 fsdb_obj->ffrReadScopeVarTree();
162 }
163
164
fsdbReaderGetMaxVarIdcode(void * ctx)165 static int fsdbReaderGetMaxVarIdcode(void *ctx)
166 {
167 ffrObject *fsdb_obj = (ffrObject *)ctx;
168 fsdbVarIdcode max_var_idcode = fsdb_obj->ffrGetMaxVarIdcode();
169 return(max_var_idcode);
170 }
171
172
fsdbReaderAddToSignalList(void * ctx,int i)173 static void fsdbReaderAddToSignalList(void *ctx, int i)
174 {
175 ffrObject *fsdb_obj = (ffrObject *)ctx;
176 fsdb_obj->ffrAddToSignalList(i);
177 }
178
179
fsdbReaderLoadSignals(void * ctx)180 static void fsdbReaderLoadSignals(void *ctx)
181 {
182 ffrObject *fsdb_obj = (ffrObject *)ctx;
183 fsdb_obj->ffrLoadSignals();
184 }
185
186
fsdbReaderCreateVCTraverseHandle(void * ctx,int i)187 static void *fsdbReaderCreateVCTraverseHandle(void *ctx, int i)
188 {
189 ffrObject *fsdb_obj = (ffrObject *)ctx;
190 ffrVCTrvsHdl hdl = fsdb_obj->ffrCreateVCTraverseHandle(i);
191 return((void *)hdl);
192 }
193
194
fsdbReaderHasIncoreVC(void * ctx,void * hdl)195 static int fsdbReaderHasIncoreVC(void *ctx, void *hdl)
196 {
197 ffrObject *fsdb_obj = (ffrObject *)ctx;
198 ffrVCTrvsHdl fsdb_hdl = (ffrVCTrvsHdl)hdl;
199 return(fsdb_hdl->ffrHasIncoreVC() == TRUE);
200 }
201
202
fsdbReaderFree(void * ctx,void * hdl)203 static void fsdbReaderFree(void *ctx, void *hdl)
204 {
205 ffrObject *fsdb_obj = (ffrObject *)ctx;
206 ffrVCTrvsHdl fsdb_hdl = (ffrVCTrvsHdl)hdl;
207
208 fsdb_hdl->ffrFree();
209 }
210
211
fsdbReaderGetMinXTag(void * ctx,void * hdl)212 static uint64_t fsdbReaderGetMinXTag(void *ctx, void *hdl)
213 {
214 ffrObject *fsdb_obj = (ffrObject *)ctx;
215 ffrVCTrvsHdl fsdb_hdl = (ffrVCTrvsHdl)hdl;
216 fsdbTag64 timetag;
217
218 fsdb_hdl->ffrGetMinXTag((void*)&timetag);
219 uint64_t rv = T2U64(timetag);
220 return(rv);
221 }
222
223
fsdbReaderGetMaxXTag(void * ctx,void * hdl)224 static uint64_t fsdbReaderGetMaxXTag(void *ctx, void *hdl)
225 {
226 ffrObject *fsdb_obj = (ffrObject *)ctx;
227 ffrVCTrvsHdl fsdb_hdl = (ffrVCTrvsHdl)hdl;
228 fsdbTag64 timetag;
229
230 fsdb_hdl->ffrGetMaxXTag((void*)&timetag);
231 uint64_t rv = T2U64(timetag);
232 return(rv);
233 }
234
235
fsdbReaderGotoXTag(void * ctx,void * hdl,uint64_t tim)236 static void fsdbReaderGotoXTag(void *ctx, void *hdl, uint64_t tim)
237 {
238 ffrObject *fsdb_obj = (ffrObject *)ctx;
239 ffrVCTrvsHdl fsdb_hdl = (ffrVCTrvsHdl)hdl;
240 fsdbTag64 timetag;
241
242 timetag.H = (uint32_t)(tim >> 32);
243 timetag.L = (uint32_t)(tim & 0xFFFFFFFFUL);
244
245 fsdb_hdl->ffrGotoXTag((void*)&timetag);
246 }
247
248
fsdbReaderGetXTag(void * ctx,void * hdl)249 static uint64_t fsdbReaderGetXTag(void *ctx, void *hdl)
250 {
251 ffrObject *fsdb_obj = (ffrObject *)ctx;
252 ffrVCTrvsHdl fsdb_hdl = (ffrVCTrvsHdl)hdl;
253 fsdbTag64 timetag;
254
255 fsdb_hdl->ffrGetXTag((void*)&timetag);
256 uint64_t rv = T2U64(timetag);
257 return(rv);
258 }
259
260
fsdbReaderGetVC(void * ctx,void * hdl,void ** val_ptr)261 static int fsdbReaderGetVC(void *ctx, void *hdl, void **val_ptr)
262 {
263 ffrObject *fsdb_obj = (ffrObject *)ctx;
264 ffrVCTrvsHdl fsdb_hdl = (ffrVCTrvsHdl)hdl;
265
266 return(fsdb_hdl->ffrGetVC((byte_T**)val_ptr) == FSDB_RC_SUCCESS);
267 }
268
269
fsdbReaderGotoNextVC(void * ctx,void * hdl)270 static int fsdbReaderGotoNextVC(void *ctx, void *hdl)
271 {
272 ffrObject *fsdb_obj = (ffrObject *)ctx;
273 ffrVCTrvsHdl fsdb_hdl = (ffrVCTrvsHdl)hdl;
274
275 return(fsdb_hdl->ffrGotoNextVC() == FSDB_RC_SUCCESS);
276 }
277
278
fsdbReaderUnloadSignals(void * ctx)279 static void fsdbReaderUnloadSignals(void *ctx)
280 {
281 ffrObject *fsdb_obj = (ffrObject *)ctx;
282 fsdb_obj->ffrUnloadSignals();
283 }
284
285
fsdbReaderClose(void * ctx)286 static void fsdbReaderClose(void *ctx)
287 {
288 ffrObject *fsdb_obj = (ffrObject *)ctx;
289 fsdb_obj->ffrClose();
290 }
291
292
fsdbReaderGetBytesPerBit(void * hdl)293 static int fsdbReaderGetBytesPerBit(void *hdl)
294 {
295 ffrVCTrvsHdl fsdb_hdl = (ffrVCTrvsHdl)hdl;
296
297 return(fsdb_hdl->ffrGetBytesPerBit());
298 }
299
300
fsdbReaderGetBitSize(void * hdl)301 static int fsdbReaderGetBitSize(void *hdl)
302 {
303 ffrVCTrvsHdl fsdb_hdl = (ffrVCTrvsHdl)hdl;
304
305 return(fsdb_hdl->ffrGetBitSize());
306 }
307
308
fsdbReaderGetVarType(void * hdl)309 static int fsdbReaderGetVarType(void *hdl)
310 {
311 ffrVCTrvsHdl fsdb_hdl = (ffrVCTrvsHdl)hdl;
312
313 return(fsdb_hdl->ffrGetVarType());
314 }
315
316
fsdbReaderTranslateVC(void * hdl,void * val_ptr,int * vtype,int * vlen)317 static char *fsdbReaderTranslateVC(void *hdl, void *val_ptr, int *vtype, int *vlen)
318 {
319 ffrVCTrvsHdl vc_trvs_hdl = (ffrVCTrvsHdl)hdl;
320 byte_T *vc_ptr = (byte_T *)val_ptr;
321 byte_T *bufferp;
322 uint_T i;
323 fsdbVarType var_type;
324 int bs;
325 static byte_T buffer[FSDB_MAX_BIT_SIZE+1+32];
326
327 bufferp = buffer + 1;
328
329 switch (vc_trvs_hdl->ffrGetBytesPerBit())
330 {
331 case FSDB_BYTES_PER_BIT_1B:
332 *vlen = bs = vc_trvs_hdl->ffrGetBitSize();
333 for (i = 0; i < bs; i++)
334 {
335 switch(vc_ptr[i])
336 {
337 case FSDB_BT_VCD_0:
338 bufferp[i] = '0';
339 break;
340
341 case FSDB_BT_VCD_1:
342 bufferp[i] = '1';
343 break;
344
345 case FSDB_BT_VCD_X:
346 bufferp[i] = 'x';
347 break;
348
349 case FSDB_BT_VCD_Z:
350 bufferp[i] = 'z';
351 break;
352
353 default:
354 bufferp[i] = 'x';
355 break;
356 }
357 }
358 *vtype = (i>1) ? VCD_VC_TYPE_BITVEC : VCD_VC_TYPE_BIT;
359 break;
360
361 case FSDB_BYTES_PER_BIT_2B:
362 {
363 bs = vc_trvs_hdl->ffrGetBitSize();
364 fsdbBitType *bt = (fsdbBitType *)bufferp;
365 byte_T *buffers0 = bufferp + bs*1+1;
366 byte_T *buffers1 = bufferp + bs*2+2;
367
368 fsdbStrengthType *s0 = (fsdbStrengthType *)buffers0;
369 fsdbStrengthType *s1 = (fsdbStrengthType *)buffers1;
370
371 ffrObject::ffrGetEvcdPortStrength((byte_T *)val_ptr, bt, s0, s1);
372 for (i = 0; i < bs; i++)
373 {
374 /* normally use ffrObject::ffrGetEvcdPortStrength() */
375 bufferp[i] = ((byte_T *)val_ptr)[i*2];
376 buffers0[i] = ((byte_T *)val_ptr)[i*2+1] & 15;
377 buffers1[i] = (((byte_T *)val_ptr)[i*2+1] >> 4) & 15;
378
379 if((bufferp[i] >= FSDB_BT_EVCD_L) && (bufferp[i] <= FSDB_BT_EVCD_f))
380 {
381 bufferp[i] = "LlHhXxTDdUuNnZ?01AaBbCcFf"[bufferp[i]];
382 }
383 else
384 {
385 bufferp[i] = '?';
386 }
387
388 if((buffers0[i] >= FSDB_ST_HIGHZ) && (buffers0[i] <= FSDB_ST_SUPPLY))
389 {
390 buffers0[i] += '0';
391 }
392 else
393 {
394 buffers0[i] = FSDB_ST_HIGHZ + '0';
395 }
396
397 if((buffers1[i] >= FSDB_ST_HIGHZ) && (buffers1[i] <= FSDB_ST_SUPPLY))
398 {
399 buffers1[i] += '0';
400 }
401 else
402 {
403 buffers1[i] = FSDB_ST_HIGHZ + '0';
404 }
405 }
406
407 bufferp[bs] = ' ';
408 bufferp[bs*2+1] = ' ';
409 bufferp[*vlen = bs*3+2] = 0;
410 *vtype = VCD_VC_TYPE_PORT;
411 }
412 break;
413
414 case FSDB_BYTES_PER_BIT_4B:
415 var_type = vc_trvs_hdl->ffrGetVarType();
416 switch(var_type)
417 {
418 case FSDB_VT_VCD_MEMORY_DEPTH:
419 case FSDB_VT_VHDL_MEMORY_DEPTH:
420 break;
421
422 default:
423 vc_trvs_hdl->ffrGetVC(&vc_ptr);
424 *vlen = sprintf((char *)bufferp, "%f", *((float*)vc_ptr));
425 break;
426 }
427 *vtype = VCD_VC_TYPE_IGNORE;
428 break;
429
430 case FSDB_BYTES_PER_BIT_8B:
431 var_type = vc_trvs_hdl->ffrGetVarType();
432 switch(var_type)
433 {
434 case FSDB_VT_VCD_REAL:
435 *vlen = sprintf((char *)bufferp, "%.16g", *((double*)vc_ptr));
436 *vtype = VCD_VC_TYPE_REAL;
437 break;
438
439 case FSDB_VT_STREAM:
440 default:
441 *vlen = 0;
442 *vtype = VCD_VC_TYPE_IGNORE;
443 break;
444 }
445 break;
446
447 default:
448 *vlen = 0;
449 *vtype = VCD_VC_TYPE_IGNORE;
450 break;
451 }
452
453 return((char *)bufferp);
454 }
455
456
fsdbReaderExtractScaleUnit(void * ctx,int * mult,char * scale)457 static int fsdbReaderExtractScaleUnit(void *ctx, int *mult, char *scale)
458 {
459 ffrObject *fsdb_obj = (ffrObject *)ctx;
460 uint_T digit;
461 char *unit;
462
463 str_T su = fsdb_obj->ffrGetScaleUnit();
464 fsdbRC rc = fsdb_obj->ffrExtractScaleUnit(su, digit, unit);
465
466 if(rc == FSDB_RC_SUCCESS)
467 {
468 *mult = digit ? ((int)digit) : 1; /* in case digit is zero */
469 *scale = unit[0];
470 }
471
472 return(rc == FSDB_RC_SUCCESS);
473 }
474
475
fsdbReaderGetMinFsdbTag64(void * ctx,uint64_t * tim)476 static int fsdbReaderGetMinFsdbTag64(void *ctx, uint64_t *tim)
477 {
478 ffrObject *fsdb_obj = (ffrObject *)ctx;
479 fsdbTag64 tag64;
480 fsdbRC rc = fsdb_obj->ffrGetMinFsdbTag64(&tag64);
481
482 if(rc == FSDB_RC_SUCCESS)
483 {
484 *tim = T2U64(tag64);
485 }
486
487 return(rc == FSDB_RC_SUCCESS);
488 }
489
490
fsdbReaderGetMaxFsdbTag64(void * ctx,uint64_t * tim)491 static int fsdbReaderGetMaxFsdbTag64(void *ctx, uint64_t *tim)
492 {
493 ffrObject *fsdb_obj = (ffrObject *)ctx;
494 fsdbTag64 tag64;
495 fsdbRC rc = fsdb_obj->ffrGetMaxFsdbTag64(&tag64);
496
497 if(rc == FSDB_RC_SUCCESS)
498 {
499 *tim = T2U64(tag64);
500 }
501
502 return(rc == FSDB_RC_SUCCESS);
503 }
504
505
fsdbReaderGetDumpOffRange(void * ctx,struct fsdbReaderBlackoutChain ** r)506 static unsigned int fsdbReaderGetDumpOffRange(void *ctx, struct fsdbReaderBlackoutChain **r)
507 {
508 ffrObject *fsdb_obj = (ffrObject *)ctx;
509
510 if(fsdb_obj->ffrHasDumpOffRange())
511 {
512 uint_T count;
513 fsdbDumpOffRange *fdr = NULL;
514
515 if(FSDB_RC_SUCCESS == fsdb_obj->ffrGetDumpOffRange(count, fdr))
516 {
517 uint_T i;
518 *r = (struct fsdbReaderBlackoutChain *)calloc(count * 2, sizeof(struct fsdbReaderBlackoutChain));
519
520 for(i=0;i<count;i++)
521 {
522 (*r)[i*2 ].tim = FXT2U64(fdr[i].begin); (*r)[i*2 ].active = 0;
523 (*r)[i*2+1].tim = FXT2U64(fdr[i].end); (*r)[i*2+1].active = 1;
524 }
525
526 uint64_t max_t;
527 if(fsdbReaderGetMaxFsdbTag64(ctx, &max_t))
528 {
529 if((count == 1) && (max_t == (*r)[0].tim))
530 {
531 free(*r);
532 *r = NULL;
533 count = 0;
534 }
535 }
536
537 return(count*2);
538 }
539 }
540
541 if(*r) { *r = NULL; }
542 return(0);
543 }
544
545
__DumpStruct(fsdbTreeCBDataStructBegin * struc,FILE * cb)546 static void __DumpStruct(fsdbTreeCBDataStructBegin* struc, FILE *cb)
547 {
548 str_T type;
549
550 fprintf(cb, "$scope %s %s $end\n", "fork", struc->name);
551 /* sprintf(bf, "Scope: %s %s %s", type, scope->name, scope->module ? scope->module : "NULL"); */
552 }
553
554
__DumpScope(fsdbTreeCBDataScope * scope,FILE * cb)555 static void __DumpScope(fsdbTreeCBDataScope* scope, FILE *cb)
556 {
557 str_T type;
558
559 switch (scope->type)
560 {
561 case FSDB_ST_SV_INTERFACE:
562 case FSDB_ST_VCD_MODULE:
563 type = (str_T) "module";
564 break;
565
566 case FSDB_ST_VCD_TASK:
567 type = (str_T) "task";
568 break;
569
570 case FSDB_ST_VCD_FUNCTION:
571 type = (str_T) "function";
572 break;
573
574 case FSDB_ST_VCD_BEGIN:
575 type = (str_T) "begin";
576 break;
577
578 case FSDB_ST_VCD_FORK:
579 type = (str_T) "fork";
580 break;
581
582 case FSDB_ST_VCD_GENERATE:
583 case FSDB_ST_VHDL_ARCHITECTURE:
584 case FSDB_ST_VHDL_PROCEDURE:
585 case FSDB_ST_VHDL_FUNCTION:
586 case FSDB_ST_VHDL_RECORD:
587 case FSDB_ST_VHDL_PROCESS:
588 case FSDB_ST_VHDL_BLOCK:
589 case FSDB_ST_VHDL_FOR_GENERATE:
590 case FSDB_ST_VHDL_IF_GENERATE:
591 case FSDB_ST_VHDL_GENERATE:
592 default:
593 type = (str_T) "begin";
594 break;
595 }
596
597 fprintf(cb, "$scope %s %s $end\n", type, scope->name);
598 /* sprintf(bf, "Scope: %s %s %s", type, scope->name, scope->module ? scope->module : "NULL"); */
599 }
600
601
__DumpVar(fsdbTreeCBDataVar * var,FILE * cb)602 static void __DumpVar(fsdbTreeCBDataVar *var, FILE *cb)
603 {
604 str_T type;
605 int vcdid_len;
606 int siz = 0;
607
608 switch (var->type)
609 {
610 case FSDB_VT_VCD_EVENT:
611 type = (str_T) "event";
612 break;
613
614 case FSDB_VT_VCD_INTEGER:
615 type = (str_T) "integer";
616 break;
617
618 case FSDB_VT_VCD_PARAMETER:
619 type = (str_T) "parameter";
620 break;
621
622 case FSDB_VT_VCD_REAL:
623 type = (str_T) "real";
624 siz = 64;
625 break;
626
627 case FSDB_VT_VCD_REG:
628 type = (str_T) "reg";
629 break;
630
631 case FSDB_VT_VCD_SUPPLY0:
632 type = (str_T) "supply0";
633 break;
634
635 case FSDB_VT_VCD_SUPPLY1:
636 type = (str_T) "supply1";
637 break;
638
639 case FSDB_VT_VCD_TIME:
640 type = (str_T) "time";
641 break;
642
643 case FSDB_VT_VCD_TRI:
644 type = (str_T) "tri";
645 break;
646
647 case FSDB_VT_VCD_TRIAND:
648 type = (str_T) "triand";
649 break;
650
651 case FSDB_VT_VCD_TRIOR:
652 type = (str_T) "trior";
653 break;
654
655 case FSDB_VT_VCD_TRIREG:
656 type = (str_T) "trireg";
657 break;
658
659 case FSDB_VT_VCD_TRI0:
660 type = (str_T) "tri0";
661 break;
662
663 case FSDB_VT_VCD_TRI1:
664 type = (str_T) "tri1";
665 break;
666
667 case FSDB_VT_VCD_WAND:
668 type = (str_T) "wand";
669 break;
670
671 case FSDB_VT_VCD_WIRE:
672 type = (str_T) "wire";
673 break;
674
675 case FSDB_VT_VCD_WOR:
676 type = (str_T) "wor";
677 break;
678
679 case FSDB_VT_VHDL_SIGNAL:
680 case FSDB_VT_VHDL_VARIABLE:
681 case FSDB_VT_VHDL_CONSTANT:
682 case FSDB_VT_VHDL_FILE:
683 case FSDB_VT_VCD_MEMORY:
684 case FSDB_VT_VHDL_MEMORY:
685 case FSDB_VT_VCD_MEMORY_DEPTH:
686 case FSDB_VT_VHDL_MEMORY_DEPTH:
687 switch(var->vc_dt)
688 {
689 case FSDB_VC_DT_FLOAT:
690 case FSDB_VC_DT_DOUBLE:
691 type = (str_T) "real";
692 break;
693
694 case FSDB_VC_DT_UNKNOWN:
695 case FSDB_VC_DT_BYTE:
696 case FSDB_VC_DT_SHORT:
697 case FSDB_VC_DT_INT:
698 case FSDB_VC_DT_LONG:
699 case FSDB_VC_DT_HL_INT:
700 case FSDB_VC_DT_PHYSICAL:
701 default:
702 if(var->type == FSDB_VT_VHDL_SIGNAL)
703 {
704 type = (str_T) "wire";
705 }
706 else
707 {
708 type = (str_T) "reg";
709 }
710 break;
711 }
712 break;
713
714 case FSDB_VT_VCD_PORT:
715 type = (str_T) "port";
716 break;
717
718 case FSDB_VT_STREAM: /* these hold transactions: not yet supported so do not emit */
719 return;
720 /* type = (str_T) "stream"; */
721 break;
722
723 default:
724 type = (str_T) "wire";
725 break;
726 }
727
728 if(!siz)
729 {
730 if(var->lbitnum >= var->rbitnum)
731 {
732 siz = var->lbitnum - var->rbitnum + 1;
733 }
734 else
735 {
736 siz = var->rbitnum - var->lbitnum + 1;
737 }
738 }
739
740 char *lb = strchr(var->name, '[');
741
742 if(!lb || strchr(var->name, ' '))
743 {
744 fprintf(cb, "$var %s %d %s %s $end\n", type, siz, makeVcdID(var->u.idcode, &vcdid_len), var->name);
745 }
746 else
747 {
748 fprintf(cb, "$var %s %d %s ", type, siz, makeVcdID(var->u.idcode, &vcdid_len)); /* add space, VCS-style */
749 fwrite(var->name, lb - var->name, 1, cb);
750 fprintf(cb, " %s $end\n", lb);
751 }
752 }
753
754
__MyTreeCB(fsdbTreeCBType cb_type,void * client_data,void * tree_cb_data)755 static bool_T __MyTreeCB(fsdbTreeCBType cb_type,
756 void *client_data, void *tree_cb_data)
757 {
758 FILE *cb = (FILE *)client_data;
759
760 switch (cb_type)
761 {
762 case FSDB_TREE_CBT_BEGIN_TREE:
763 /* fprintf(stderr, "Begin Tree:\n"); */
764 break;
765
766 case FSDB_TREE_CBT_SCOPE:
767 __DumpScope((fsdbTreeCBDataScope *)tree_cb_data, cb);
768 break;
769
770 case FSDB_TREE_CBT_STRUCT_BEGIN:
771 __DumpStruct((fsdbTreeCBDataStructBegin *)tree_cb_data, cb);
772 break;
773
774 case FSDB_TREE_CBT_VAR:
775 __DumpVar((fsdbTreeCBDataVar*)tree_cb_data, cb);
776 break;
777
778 case FSDB_TREE_CBT_UPSCOPE:
779 case FSDB_TREE_CBT_STRUCT_END:
780 fprintf(cb, "$upscope $end\n");
781 break;
782
783 case FSDB_TREE_CBT_END_TREE:
784 /* fprintf(stderr, "End Tree:\n"); */
785 break;
786
787 case FSDB_TREE_CBT_ARRAY_BEGIN:
788 case FSDB_TREE_CBT_ARRAY_END:
789 break;
790
791 case FSDB_TREE_CBT_FILE_TYPE:
792 case FSDB_TREE_CBT_SIMULATOR_VERSION:
793 case FSDB_TREE_CBT_SIMULATION_DATE:
794 case FSDB_TREE_CBT_X_AXIS_SCALE:
795 case FSDB_TREE_CBT_END_ALL_TREE:
796 case FSDB_TREE_CBT_RECORD_BEGIN:
797 case FSDB_TREE_CBT_RECORD_END:
798 break;
799
800 default:
801 return(FALSE);
802 }
803
804 return(TRUE);
805 }
806
807
main(int argc,char ** argv)808 int main(int argc, char **argv)
809 {
810 void *ctx;
811 FILE *fh;
812 int i;
813 ffrVCTrvsHdl *hdl;
814 int mx_id;
815 uint64_t key = 0;
816 uint64_t max_tim;
817 ffrFSDBInfo fsdb_info;
818 int mult;
819 char scale[3];
820 std::map <uint64_t, fsdbVarIdcode> time_map;
821 fsdbVarIdcode *time_autosort;
822 char timestring[32];
823 FILE *stdout_cache = stdout;
824 unsigned int dumpoff_count = 0;
825 unsigned int dumpoff_idx = 0;
826 struct fsdbReaderBlackoutChain *dumpoff_ranges = NULL;
827 uint64_t prev_dumponoff_tim = 0;
828 int dumptime_emitted = 0;
829 uint64_t time_serial_number = 0;
830
831 stdout_cache = stdout;
832 stdout = tmpfile(); /* redirects useless log file messages that would mess up VCD output for piped execution */
833
834 if((argc != 2) && (argc != 3))
835 {
836 fprintf(stderr, "Usage:\n------\n%s filename.fsdb [filename.vcd]\n\n", argv[0]);
837 exit(0);
838 }
839
840
841 ctx = fsdbReaderOpenFile(argv[1]);
842 if(!ctx)
843 {
844 fprintf(stderr, "Could not open '%s', exiting.\n", argv[1]);
845 exit(255);
846 }
847
848 if(argc == 3)
849 {
850 fh = fopen(argv[2], "wb");
851 if(!fh)
852 {
853 fprintf(stderr, "Could not open '%s', exiting.\n", argv[2]);
854 perror("Why");
855 exit(255);
856 }
857 }
858 else
859 {
860 fh = stdout_cache;
861 if(!fh)
862 {
863 fprintf(stderr, "stdin is NULL, exiting.\n");
864 exit(255);
865 }
866 }
867
868 dumpoff_count = fsdbReaderGetDumpOffRange(ctx, &dumpoff_ranges);
869
870 if(FSDB_RC_SUCCESS == ((ffrObject *)ctx)->ffrGetFSDBInfo(argv[1], fsdb_info))
871 {
872 fprintf(fh, "$date\n\t%s\n$end\n", fsdb_info.simulation_date);
873 fprintf(fh, "$version\n\t%s\n$end\n", fsdb_info.simulator_version);
874 }
875
876 if(fsdbReaderExtractScaleUnit(ctx, &mult, &scale[0]))
877 {
878 scale[0] = tolower(scale[0]);
879 switch(scale[0])
880 {
881 case 'm':
882 case 'u':
883 case 'n':
884 case 'p':
885 case 'f':
886 case 'a':
887 case 'z': scale[1] = 's'; scale[2] = 0; break;
888
889 default : scale[0] = 's'; scale[1] = 0; break;
890 }
891 fprintf(fh, "$timescale\n\t%d%s\n$end\n", mult, scale);
892 }
893
894
895 fsdbReaderReadScopeVarTree(ctx, fh);
896 fprintf(fh, "$enddefinitions $end\n$dumpvars\n");
897
898 mx_id = fsdbReaderGetMaxVarIdcode(ctx);
899 for(i=1;i<=mx_id;i++)
900 {
901 fsdbReaderAddToSignalList(ctx, i);
902 }
903
904 fsdbReaderLoadSignals(ctx);
905
906 hdl = (ffrVCTrvsHdl *)calloc(i+1, sizeof(ffrVCTrvsHdl));
907 for(i=1;i<=mx_id;i++)
908 {
909 hdl[i] = (ffrVCTrvsHdl)fsdbReaderCreateVCTraverseHandle(ctx, i);
910 }
911
912 time_autosort = (fsdbVarIdcode *)calloc(mx_id + 1, sizeof(fsdbVarIdcode));
913
914 for(i=mx_id;i>0;i--)
915 {
916 ffrXTag xt;
917 fsdbRC gf = hdl[i]->ffrGotoTheFirstVC();
918 if(gf == FSDB_RC_SUCCESS)
919 {
920 fsdbRC gx = hdl[i]->ffrGetXTag(&xt);
921
922 if(gx == FSDB_RC_SUCCESS)
923 {
924 uint64_t x64 = XT2U64(xt);
925 fsdbVarIdcode t_prev = time_map[x64];
926 time_autosort[i] = t_prev;
927 time_map[x64] = i;
928 }
929 }
930 }
931
932 fflush(fh);
933 setvbuf(fh, (char *) NULL, _IONBF, 0); /* even buffered IO is slow so disable it and use our own routines that don't need seeking */
934 int fd = fileno(fh);
935
936 while(!time_map.empty())
937 {
938 key = time_map.begin()->first;
939
940 while(dumpoff_idx < dumpoff_count)
941 {
942 uint64_t top_tim = dumpoff_ranges[dumpoff_idx].tim;
943
944 if(key >= top_tim)
945 {
946 uint64_t active = dumpoff_ranges[dumpoff_idx].active;
947
948 if(top_tim >= prev_dumponoff_tim)
949 {
950 if((top_tim != prev_dumponoff_tim) || (!dumptime_emitted))
951 {
952 if(time_serial_number++ == 1)
953 {
954 writex(fd, (char *)"$end\n", 5);
955 }
956 if(top_tim) { writex(fd, timestring, sprintf(timestring, "#%"PRIu64"\n", top_tim)); }
957 prev_dumponoff_tim = top_tim;
958 dumptime_emitted = 1;
959 }
960
961 if(active)
962 {
963 writex(fd, timestring, sprintf(timestring, "$dumpon\n"));
964 }
965 else
966 {
967 writex(fd, timestring, sprintf(timestring, "$dumpoff\n"));
968 }
969 }
970
971 dumpoff_idx++;
972 }
973 else
974 {
975 break;
976 }
977 }
978
979 if((!dumptime_emitted) || (key != prev_dumponoff_tim))
980 {
981 if(time_serial_number++ == 1)
982 {
983 writex(fd, (char *)"$end\n", 5);
984 }
985 if(key) { writex(fd, timestring, sprintf(timestring, "#%"PRIu64"\n", key)); }
986 }
987
988 fsdbVarIdcode idx = time_map.begin()->second;
989 #ifdef BYPASS_RB_TREE_IF_POSSIBLE
990 fsdbVarIdcode *tms = NULL;
991 uint64_t prev_x64 = key - 1;
992 #endif
993 while(idx)
994 {
995 fsdbVarIdcode idxn = time_autosort[idx];
996 byte_T *ret_vc;
997 fsdbRC gvc = hdl[idx]->ffrGetVC(&ret_vc);
998 if(gvc == FSDB_RC_SUCCESS)
999 {
1000 int vtype, vlen;
1001 char *vcdid;
1002 int vcdid_len;
1003 char *vdata = fsdbReaderTranslateVC(hdl[idx], ret_vc, &vtype, &vlen);
1004
1005 vcdid = makeVcdID(idx, &vcdid_len);
1006
1007 switch(vtype)
1008 {
1009 case VCD_VC_TYPE_BIT:
1010 {
1011 writex(fd, vdata, 1);
1012 vcdid[vcdid_len++] = '\n';
1013 writex(fd, vcdid, vcdid_len);
1014 }
1015 break;
1016
1017 case VCD_VC_TYPE_BITVEC:
1018 case VCD_VC_TYPE_REAL:
1019 case VCD_VC_TYPE_PORT:
1020 {
1021 vdata--; /* buffer was specially allocated in fsdbReaderTranslateVC() so we can do this */
1022 vdata[0] = (vtype == VCD_VC_TYPE_BITVEC) ? 'b' : ((vtype == VCD_VC_TYPE_REAL) ? 'r' : 'p'); vlen++;
1023 vdata[vlen] = ' '; vlen++;
1024 writex(fd, vdata, vlen);
1025
1026 vcdid[vcdid_len++] = '\n';
1027 writex(fd, vcdid, vcdid_len);
1028 }
1029 break;
1030
1031 case VCD_VC_TYPE_IGNORE:
1032 default:
1033 1;
1034 }
1035
1036 if(FSDB_RC_SUCCESS == hdl[idx]->ffrGotoNextVC())
1037 {
1038 ffrXTag xt;
1039 fsdbRC gx = hdl[idx]->ffrGetXTag(&xt);
1040 if(gx == FSDB_RC_SUCCESS)
1041 {
1042 uint64_t x64 = XT2U64(xt);
1043
1044 #ifdef BYPASS_RB_TREE_IF_POSSIBLE
1045 if(x64 == prev_x64)
1046 {
1047 }
1048 else
1049 {
1050 tms = & time_map[prev_x64 = x64];
1051 }
1052
1053 fsdbVarIdcode t_prev = *tms;
1054 time_autosort[idx] = t_prev;
1055 *tms = idx;
1056 #else
1057 fsdbVarIdcode t_prev = time_map[x64];
1058 time_autosort[idx] = t_prev;
1059 time_map[x64] = idx;
1060 #endif
1061 }
1062 }
1063 }
1064 idx = idxn;
1065 }
1066
1067 time_map.erase(key);
1068 }
1069
1070 if(fsdbReaderGetMaxFsdbTag64(ctx, &max_tim))
1071 {
1072 if(key != max_tim)
1073 {
1074 if(time_serial_number++ == 1)
1075 {
1076 writex(fd, (char *)"$end\n", 5);
1077 }
1078 if(max_tim) { writex(fd, timestring, sprintf(timestring, "#%"PRIu64"\n", max_tim)); }
1079 }
1080 }
1081
1082 writex(fd, NULL, 0);
1083
1084 free(dumpoff_ranges);
1085 free(time_autosort);
1086 free(hdl);
1087 if(fh != stdout_cache) fclose(fh);
1088 fsdbReaderClose(ctx);
1089 fclose(stdout);
1090
1091 return(0);
1092 }
1093