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