1 /*
2 * Copyright (c) 2009-2018 Tony Bybell.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 *
22 * SPDX-License-Identifier: MIT
23 */
24
25 /*
26 * possible disables:
27 *
28 * FST_DYNAMIC_ALIAS_DISABLE : dynamic aliases are not processed
29 * FST_DYNAMIC_ALIAS2_DISABLE : new encoding for dynamic aliases is not generated
30 * FST_WRITEX_DISABLE : fast write I/O routines are disabled
31 *
32 * possible enables:
33 *
34 * FST_DEBUG : not for production use, only enable for development
35 * FST_REMOVE_DUPLICATE_VC : glitch removal (has writer performance impact)
36 * HAVE_LIBPTHREAD -> FST_WRITER_PARALLEL : enables inclusion of parallel writer code
37 * FST_DO_MISALIGNED_OPS (defined automatically for x86 and some others) : CPU architecture can handle misaligned loads/stores
38 * _WAVE_HAVE_JUDY : use Judy arrays instead of Jenkins (undefine if LGPL is not acceptable)
39 *
40 */
41
42 #ifndef FST_CONFIG_INCLUDE
43 # define FST_CONFIG_INCLUDE <config.h>
44 #endif
45 #include FST_CONFIG_INCLUDE
46
47 #include "fstapi.h"
48 #include "fastlz.h"
49 #include "lz4.h"
50 #include <errno.h>
51
52 #ifndef HAVE_LIBPTHREAD
53 #undef FST_WRITER_PARALLEL
54 #endif
55
56 #ifdef FST_WRITER_PARALLEL
57 #include <pthread.h>
58 #endif
59
60 #ifdef __MINGW32__
61 #include <windows.h>
62 #endif
63
64 #ifdef HAVE_ALLOCA_H
65 #include <alloca.h>
66 #elif defined(__GNUC__)
67 #ifndef __MINGW32__
68 #ifndef alloca
69 #define alloca __builtin_alloca
70 #endif
71 #else
72 #include <malloc.h>
73 #endif
74 #elif defined(_MSC_VER)
75 #include <malloc.h>
76 #define alloca _alloca
77 #endif
78
79 #ifndef PATH_MAX
80 #define PATH_MAX (4096)
81 #endif
82
83 #if defined(_MSC_VER)
84 typedef int64_t fst_off_t;
85 #else
86 typedef off_t fst_off_t;
87 #endif
88
89 /* note that Judy versus Jenkins requires more experimentation: they are */
90 /* functionally equivalent though it appears Jenkins is slightly faster. */
91 /* in addition, Jenkins is not bound by the LGPL. */
92 #ifdef _WAVE_HAVE_JUDY
93 #include <Judy.h>
94 #else
95 /* should be more than enough for fstWriterSetSourceStem() */
96 #define FST_PATH_HASHMASK ((1UL << 16) - 1)
97 typedef const void *Pcvoid_t;
98 typedef void *Pvoid_t;
99 typedef void **PPvoid_t;
100 #define JudyHSIns(a,b,c,d) JenkinsIns((a),(b),(c),(hashmask))
101 #define JudyHSFreeArray(a,b) JenkinsFree((a),(hashmask))
102 void JenkinsFree(void *base_i, uint32_t hashmask);
103 void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint32_t hashmask);
104 #endif
105
106
107 #ifndef FST_WRITEX_DISABLE
108 #define FST_WRITEX_MAX (64 * 1024)
109 #else
110 #define fstWritex(a,b,c) fstFwrite((b), (c), 1, fv)
111 #endif
112
113
114 /* these defines have a large impact on writer speed when a model has a */
115 /* huge number of symbols. as a default, use 128MB and increment when */
116 /* every 1M signals are defined. */
117 #define FST_BREAK_SIZE (1UL << 27)
118 #define FST_BREAK_ADD_SIZE (1UL << 22)
119 #define FST_BREAK_SIZE_MAX (1UL << 31)
120 #define FST_ACTIVATE_HUGE_BREAK (1000000)
121 #define FST_ACTIVATE_HUGE_INC (1000000)
122
123 #define FST_WRITER_STR "fstWriter"
124 #define FST_ID_NAM_SIZ (512)
125 #define FST_ID_NAM_ATTR_SIZ (65536+4096)
126 #define FST_DOUBLE_ENDTEST (2.7182818284590452354)
127 #define FST_HDR_SIM_VERSION_SIZE (128)
128 #define FST_HDR_DATE_SIZE (119)
129 #define FST_HDR_FILETYPE_SIZE (1)
130 #define FST_HDR_TIMEZERO_SIZE (8)
131 #define FST_GZIO_LEN (32768)
132 #define FST_HDR_FOURPACK_DUO_SIZE (4*1024*1024)
133
134 #if defined(__i386__) || defined(__x86_64__) || defined(_AIX)
135 #define FST_DO_MISALIGNED_OPS
136 #endif
137
138 #if defined(__APPLE__) && defined(__MACH__)
139 #define FST_MACOSX
140 #include <sys/sysctl.h>
141 #endif
142
143 #ifdef __GNUC__
144 /* Boolean expression more often true than false */
145 #define FST_LIKELY(x) __builtin_expect(!!(x), 1)
146 /* Boolean expression more often false than true */
147 #define FST_UNLIKELY(x) __builtin_expect(!!(x), 0)
148 #else
149 #define FST_LIKELY(x) (!!(x))
150 #define FST_UNLIKELY(x) (!!(x))
151 #endif
152
153 #define FST_APIMESS "FSTAPI | "
154
155 /***********************/
156 /*** ***/
157 /*** common function ***/
158 /*** ***/
159 /***********************/
160
161 #ifdef __MINGW32__
162 #include <io.h>
163 #ifndef HAVE_FSEEKO
164 #define ftello _ftelli64
165 #define fseeko _fseeki64
166 #endif
167 #endif
168
169 /*
170 * the recoded "extra" values...
171 * note that FST_RCV_Q is currently unused and is for future expansion.
172 * its intended use is as another level of escape such that any arbitrary
173 * value can be stored as the value: { time_delta, 8 bits, FST_RCV_Q }.
174 * this is currently not implemented so that the branchless decode is:
175 * uint32_t shcnt = 2 << (vli & 1); tdelta = vli >> shcnt;
176 */
177 #define FST_RCV_X (1 | (0<<1))
178 #define FST_RCV_Z (1 | (1<<1))
179 #define FST_RCV_H (1 | (2<<1))
180 #define FST_RCV_U (1 | (3<<1))
181 #define FST_RCV_W (1 | (4<<1))
182 #define FST_RCV_L (1 | (5<<1))
183 #define FST_RCV_D (1 | (6<<1))
184 #define FST_RCV_Q (1 | (7<<1))
185
186 #define FST_RCV_STR "xzhuwl-?"
187 /* 01234567 */
188
189
190 /*
191 * prevent old file overwrite when currently being read
192 */
unlink_fopen(const char * nam,const char * mode)193 static FILE *unlink_fopen(const char *nam, const char *mode)
194 {
195 unlink(nam);
196 return(fopen(nam, mode));
197 }
198
199
200 /*
201 * system-specific temp file handling
202 */
203 #ifdef __MINGW32__
204
tmpfile_open(char ** nam)205 static FILE* tmpfile_open(char **nam)
206 {
207 char *fname = NULL;
208 TCHAR szTempFileName[MAX_PATH];
209 TCHAR lpTempPathBuffer[MAX_PATH];
210 DWORD dwRetVal = 0;
211 UINT uRetVal = 0;
212 FILE *fh = NULL;
213
214 if(nam) /* cppcheck warning fix: nam is always defined, so this is not needed */
215 {
216 dwRetVal = GetTempPath(MAX_PATH, lpTempPathBuffer);
217 if((dwRetVal > MAX_PATH) || (dwRetVal == 0))
218 {
219 fprintf(stderr, FST_APIMESS "GetTempPath() failed in " __FILE__ " line %d, exiting.\n", __LINE__);
220 exit(255);
221 }
222 else
223 {
224 uRetVal = GetTempFileName(lpTempPathBuffer, TEXT("FSTW"), 0, szTempFileName);
225 if (uRetVal == 0)
226 {
227 fprintf(stderr, FST_APIMESS "GetTempFileName() failed in " __FILE__ " line %d, exiting.\n", __LINE__);
228 exit(255);
229 }
230 else
231 {
232 fname = strdup(szTempFileName);
233 }
234 }
235
236 if(fname)
237 {
238 *nam = fname;
239 fh = unlink_fopen(fname, "w+b");
240 }
241 }
242
243 return(fh);
244 }
245
246 #else
247
tmpfile_open(char ** nam)248 static FILE* tmpfile_open(char **nam)
249 {
250 FILE *f = tmpfile(); /* replace with mkstemp() + fopen(), etc if this is not good enough */
251 if(nam) { *nam = NULL; }
252 return(f);
253 }
254
255 #endif
256
257
tmpfile_close(FILE ** f,char ** nam)258 static void tmpfile_close(FILE **f, char **nam)
259 {
260 if(f)
261 {
262 if(*f) { fclose(*f); *f = NULL; }
263 }
264
265 if(nam)
266 {
267 if(*nam)
268 {
269 unlink(*nam);
270 free(*nam);
271 *nam = NULL;
272 }
273 }
274 }
275
276 /*****************************************/
277
278
279 /*
280 * to remove warn_unused_result compile time messages
281 * (in the future there needs to be results checking)
282 */
fstFread(void * buf,size_t siz,size_t cnt,FILE * fp)283 static size_t fstFread(void *buf, size_t siz, size_t cnt, FILE *fp)
284 {
285 return(fread(buf, siz, cnt, fp));
286 }
287
fstFwrite(const void * buf,size_t siz,size_t cnt,FILE * fp)288 static size_t fstFwrite(const void *buf, size_t siz, size_t cnt, FILE *fp)
289 {
290 return(fwrite(buf, siz, cnt, fp));
291 }
292
fstFtruncate(int fd,fst_off_t length)293 static int fstFtruncate(int fd, fst_off_t length)
294 {
295 return(ftruncate(fd, length));
296 }
297
298
299 /*
300 * realpath compatibility
301 */
fstRealpath(const char * path,char * resolved_path)302 static char *fstRealpath(const char *path, char *resolved_path)
303 {
304 #if defined __USE_BSD || defined __USE_XOPEN_EXTENDED || defined __CYGWIN__ || defined HAVE_REALPATH
305 #if (defined(__MACH__) && defined(__APPLE__))
306 if(!resolved_path)
307 {
308 resolved_path = (char *)malloc(PATH_MAX+1); /* fixes bug on Leopard when resolved_path == NULL */
309 }
310 #endif
311
312 return(realpath(path, resolved_path));
313
314 #else
315 #ifdef __MINGW32__
316 if(!resolved_path)
317 {
318 resolved_path = (char *)malloc(PATH_MAX+1);
319 }
320 return(_fullpath(resolved_path, path, PATH_MAX));
321 #else
322 (void)path;
323 (void)resolved_path;
324 return(NULL);
325 #endif
326 #endif
327 }
328
329
330 /*
331 * mmap compatibility
332 */
333 #if defined __CYGWIN__ || defined __MINGW32__
334 #include <limits.h>
335 #define fstMmap(__addr,__len,__prot,__flags,__fd,__off) fstMmap2((__len), (__fd), (__off))
336 #define fstMunmap(__addr,__len) free(__addr)
337
fstMmap2(size_t __len,int __fd,fst_off_t __off)338 static void *fstMmap2(size_t __len, int __fd, fst_off_t __off)
339 {
340 (void)__off;
341
342 unsigned char *pnt = (unsigned char *)malloc(__len);
343 fst_off_t cur_offs = lseek(__fd, 0, SEEK_CUR);
344 size_t i;
345
346 lseek(__fd, 0, SEEK_SET);
347 for(i=0;i<__len;i+=SSIZE_MAX)
348 {
349 read(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i));
350 }
351 lseek(__fd, cur_offs, SEEK_SET);
352 return(pnt);
353 }
354 #else
355 #include <sys/mman.h>
356 #if defined(__SUNPRO_C)
357 #define FST_CADDR_T_CAST (caddr_t)
358 #else
359 #define FST_CADDR_T_CAST
360 #endif
361 #define fstMmap(__addr,__len,__prot,__flags,__fd,__off) (void*)mmap(FST_CADDR_T_CAST (__addr),(__len),(__prot),(__flags),(__fd),(__off))
362 #define fstMunmap(__addr,__len) { if(__addr) munmap(FST_CADDR_T_CAST (__addr),(__len)); }
363 #endif
364
365
366 /*
367 * regular and variable-length integer access functions
368 */
369 #ifdef FST_DO_MISALIGNED_OPS
370 #define fstGetUint32(x) (*(uint32_t *)(x))
371 #else
fstGetUint32(unsigned char * mem)372 static uint32_t fstGetUint32(unsigned char *mem)
373 {
374 uint32_t u32;
375 unsigned char *buf = (unsigned char *)(&u32);
376
377 buf[0] = mem[0];
378 buf[1] = mem[1];
379 buf[2] = mem[2];
380 buf[3] = mem[3];
381
382 return(*(uint32_t *)buf);
383 }
384 #endif
385
386
fstWriterUint64(FILE * handle,uint64_t v)387 static int fstWriterUint64(FILE *handle, uint64_t v)
388 {
389 unsigned char buf[8];
390 int i;
391
392 for(i=7;i>=0;i--)
393 {
394 buf[i] = v & 0xff;
395 v >>= 8;
396 }
397
398 fstFwrite(buf, 8, 1, handle);
399 return(8);
400 }
401
402
fstReaderUint64(FILE * f)403 static uint64_t fstReaderUint64(FILE *f)
404 {
405 uint64_t val = 0;
406 unsigned char buf[sizeof(uint64_t)];
407 unsigned int i;
408
409 fstFread(buf, sizeof(uint64_t), 1, f);
410 for(i=0;i<sizeof(uint64_t);i++)
411 {
412 val <<= 8;
413 val |= buf[i];
414 }
415
416 return(val);
417 }
418
419
fstGetVarint32(unsigned char * mem,int * skiplen)420 static uint32_t fstGetVarint32(unsigned char *mem, int *skiplen)
421 {
422 unsigned char *mem_orig = mem;
423 uint32_t rc = 0;
424 while(*mem & 0x80)
425 {
426 mem++;
427 }
428
429 *skiplen = mem - mem_orig + 1;
430 for(;;)
431 {
432 rc <<= 7;
433 rc |= (uint32_t)(*mem & 0x7f);
434 if(mem == mem_orig)
435 {
436 break;
437 }
438 mem--;
439 }
440
441 return(rc);
442 }
443
444
fstGetVarint32Length(unsigned char * mem)445 static uint32_t fstGetVarint32Length(unsigned char *mem)
446 {
447 unsigned char *mem_orig = mem;
448
449 while(*mem & 0x80)
450 {
451 mem++;
452 }
453
454 return(mem - mem_orig + 1);
455 }
456
457
fstGetVarint32NoSkip(unsigned char * mem)458 static uint32_t fstGetVarint32NoSkip(unsigned char *mem)
459 {
460 unsigned char *mem_orig = mem;
461 uint32_t rc = 0;
462 while(*mem & 0x80)
463 {
464 mem++;
465 }
466
467 for(;;)
468 {
469 rc <<= 7;
470 rc |= (uint32_t)(*mem & 0x7f);
471 if(mem == mem_orig)
472 {
473 break;
474 }
475 mem--;
476 }
477
478 return(rc);
479 }
480
481
fstCopyVarint32ToLeft(unsigned char * pnt,uint32_t v)482 static unsigned char *fstCopyVarint32ToLeft(unsigned char *pnt, uint32_t v)
483 {
484 unsigned char *spnt;
485 uint32_t nxt = v;
486 int cnt = 1;
487 int i;
488
489 while((nxt = nxt>>7)) /* determine len to avoid temp buffer copying to cut down on load-hit-store */
490 {
491 cnt++;
492 }
493
494 pnt -= cnt;
495 spnt = pnt;
496 cnt--;
497
498 for(i=0;i<cnt;i++) /* now generate left to right as normal */
499 {
500 nxt = v>>7;
501 *(spnt++) = ((unsigned char)v) | 0x80;
502 v = nxt;
503 }
504 *spnt = (unsigned char)v;
505
506 return(pnt);
507 }
508
509
fstCopyVarint64ToRight(unsigned char * pnt,uint64_t v)510 static unsigned char *fstCopyVarint64ToRight(unsigned char *pnt, uint64_t v)
511 {
512 uint64_t nxt;
513
514 while((nxt = v>>7))
515 {
516 *(pnt++) = ((unsigned char)v) | 0x80;
517 v = nxt;
518 }
519 *(pnt++) = (unsigned char)v;
520
521 return(pnt);
522 }
523
524
fstGetVarint64(unsigned char * mem,int * skiplen)525 static uint64_t fstGetVarint64(unsigned char *mem, int *skiplen)
526 {
527 unsigned char *mem_orig = mem;
528 uint64_t rc = 0;
529 while(*mem & 0x80)
530 {
531 mem++;
532 }
533
534 *skiplen = mem - mem_orig + 1;
535 for(;;)
536 {
537 rc <<= 7;
538 rc |= (uint64_t)(*mem & 0x7f);
539 if(mem == mem_orig)
540 {
541 break;
542 }
543 mem--;
544 }
545
546 return(rc);
547 }
548
549
fstReaderVarint32(FILE * f)550 static uint32_t fstReaderVarint32(FILE *f)
551 {
552 unsigned char buf[5];
553 unsigned char *mem = buf;
554 uint32_t rc = 0;
555 int ch;
556
557 do
558 {
559 ch = fgetc(f);
560 *(mem++) = ch;
561 } while(ch & 0x80);
562 mem--;
563
564 for(;;)
565 {
566 rc <<= 7;
567 rc |= (uint32_t)(*mem & 0x7f);
568 if(mem == buf)
569 {
570 break;
571 }
572 mem--;
573 }
574
575 return(rc);
576 }
577
578
fstReaderVarint32WithSkip(FILE * f,uint32_t * skiplen)579 static uint32_t fstReaderVarint32WithSkip(FILE *f, uint32_t *skiplen)
580 {
581 unsigned char buf[5];
582 unsigned char *mem = buf;
583 uint32_t rc = 0;
584 int ch;
585
586 do
587 {
588 ch = fgetc(f);
589 *(mem++) = ch;
590 } while(ch & 0x80);
591 *skiplen = mem - buf;
592 mem--;
593
594 for(;;)
595 {
596 rc <<= 7;
597 rc |= (uint32_t)(*mem & 0x7f);
598 if(mem == buf)
599 {
600 break;
601 }
602 mem--;
603 }
604
605 return(rc);
606 }
607
608
fstReaderVarint64(FILE * f)609 static uint64_t fstReaderVarint64(FILE *f)
610 {
611 unsigned char buf[16];
612 unsigned char *mem = buf;
613 uint64_t rc = 0;
614 int ch;
615
616 do
617 {
618 ch = fgetc(f);
619 *(mem++) = ch;
620 } while(ch & 0x80);
621 mem--;
622
623 for(;;)
624 {
625 rc <<= 7;
626 rc |= (uint64_t)(*mem & 0x7f);
627 if(mem == buf)
628 {
629 break;
630 }
631 mem--;
632 }
633
634 return(rc);
635 }
636
637
fstWriterVarint(FILE * handle,uint64_t v)638 static int fstWriterVarint(FILE *handle, uint64_t v)
639 {
640 uint64_t nxt;
641 unsigned char buf[10]; /* ceil(64/7) = 10 */
642 unsigned char *pnt = buf;
643 int len;
644
645 while((nxt = v>>7))
646 {
647 *(pnt++) = ((unsigned char)v) | 0x80;
648 v = nxt;
649 }
650 *(pnt++) = (unsigned char)v;
651
652 len = pnt-buf;
653 fstFwrite(buf, len, 1, handle);
654 return(len);
655 }
656
657
658 /* signed integer read/write routines are currently unused */
fstGetSVarint64(unsigned char * mem,int * skiplen)659 static int64_t fstGetSVarint64(unsigned char *mem, int *skiplen)
660 {
661 unsigned char *mem_orig = mem;
662 int64_t rc = 0;
663 const int64_t one = 1;
664 const int siz = sizeof(int64_t) * 8;
665 int shift = 0;
666 unsigned char byt;
667
668 do {
669 byt = *(mem++);
670 rc |= ((int64_t)(byt & 0x7f)) << shift;
671 shift += 7;
672
673 } while(byt & 0x80);
674
675 if((shift<siz) && (byt & 0x40))
676 {
677 rc |= -(one << shift); /* sign extend */
678 }
679
680 *skiplen = mem - mem_orig;
681
682 return(rc);
683 }
684
685
686 #ifndef FST_DYNAMIC_ALIAS2_DISABLE
fstWriterSVarint(FILE * handle,int64_t v)687 static int fstWriterSVarint(FILE *handle, int64_t v)
688 {
689 unsigned char buf[15]; /* ceil(64/7) = 10 + sign byte padded way up */
690 unsigned char byt;
691 unsigned char *pnt = buf;
692 int more = 1;
693 int len;
694
695 do {
696 byt = v | 0x80;
697 v >>= 7;
698
699 if (((!v) && (!(byt & 0x40))) || ((v == -1) && (byt & 0x40)))
700 {
701 more = 0;
702 byt &= 0x7f;
703 }
704
705 *(pnt++) = byt;
706 } while(more);
707
708 len = pnt-buf;
709 fstFwrite(buf, len, 1, handle);
710 return(len);
711 }
712 #endif
713
714
715 /***********************/
716 /*** ***/
717 /*** writer function ***/
718 /*** ***/
719 /***********************/
720
721 /*
722 * private structs
723 */
724 struct fstBlackoutChain
725 {
726 struct fstBlackoutChain *next;
727 uint64_t tim;
728 unsigned active : 1;
729 };
730
731
732 struct fstWriterContext
733 {
734 FILE *handle;
735 FILE *hier_handle;
736 FILE *geom_handle;
737 FILE *valpos_handle;
738 FILE *curval_handle;
739 FILE *tchn_handle;
740
741 unsigned char *vchg_mem;
742
743 fst_off_t hier_file_len;
744
745 uint32_t *valpos_mem;
746 unsigned char *curval_mem;
747
748 unsigned char *outval_mem; /* for two-state / Verilator-style value changes */
749 uint32_t outval_alloc_siz;
750
751 char *filename;
752
753 fstHandle maxhandle;
754 fstHandle numsigs;
755 uint32_t maxvalpos;
756
757 unsigned vc_emitted : 1;
758 unsigned is_initial_time : 1;
759 unsigned fourpack : 1;
760 unsigned fastpack : 1;
761
762 int64_t timezero;
763 fst_off_t section_header_truncpos;
764 uint32_t tchn_cnt, tchn_idx;
765 uint64_t curtime;
766 uint64_t firsttime;
767 uint32_t vchg_siz;
768 uint32_t vchg_alloc_siz;
769
770 uint32_t secnum;
771 fst_off_t section_start;
772
773 uint32_t numscopes;
774 double nan; /* nan value for uninitialized doubles */
775
776 struct fstBlackoutChain *blackout_head;
777 struct fstBlackoutChain *blackout_curr;
778 uint32_t num_blackouts;
779
780 uint64_t dump_size_limit;
781
782 unsigned char filetype; /* default is 0, FST_FT_VERILOG */
783
784 unsigned compress_hier : 1;
785 unsigned repack_on_close : 1;
786 unsigned skip_writing_section_hdr : 1;
787 unsigned size_limit_locked : 1;
788 unsigned section_header_only : 1;
789 unsigned flush_context_pending : 1;
790 unsigned parallel_enabled : 1;
791 unsigned parallel_was_enabled : 1;
792
793 /* should really be semaphores, but are bytes to cut down on read-modify-write window size */
794 unsigned char already_in_flush; /* in case control-c handlers interrupt */
795 unsigned char already_in_close; /* in case control-c handlers interrupt */
796
797 #ifdef FST_WRITER_PARALLEL
798 pthread_mutex_t mutex;
799 pthread_t thread;
800 pthread_attr_t thread_attr;
801 struct fstWriterContext *xc_parent;
802 #endif
803 unsigned in_pthread : 1;
804
805 size_t fst_orig_break_size;
806 size_t fst_orig_break_add_size;
807
808 size_t fst_break_size;
809 size_t fst_break_add_size;
810
811 size_t fst_huge_break_size;
812
813 fstHandle next_huge_break;
814
815 Pvoid_t path_array;
816 uint32_t path_array_count;
817
818 unsigned fseek_failed : 1;
819
820 char *geom_handle_nam;
821 char *valpos_handle_nam;
822 char *curval_handle_nam;
823 char *tchn_handle_nam;
824
825 fstEnumHandle max_enumhandle;
826 };
827
828
fstWriterFseeko(struct fstWriterContext * xc,FILE * stream,fst_off_t offset,int whence)829 static int fstWriterFseeko(struct fstWriterContext *xc, FILE *stream, fst_off_t offset, int whence)
830 {
831 int rc = fseeko(stream, offset, whence);
832
833 if(rc<0)
834 {
835 xc->fseek_failed = 1;
836 #ifdef FST_DEBUG
837 fprintf(stderr, FST_APIMESS "Seek to #%" PRId64 " (whence = %d) failed!\n", offset, whence);
838 perror("Why");
839 #endif
840 }
841
842 return(rc);
843 }
844
845
fstWriterUint32WithVarint32(struct fstWriterContext * xc,uint32_t * u,uint32_t v,const void * dbuf,uint32_t siz)846 static uint32_t fstWriterUint32WithVarint32(struct fstWriterContext *xc, uint32_t *u, uint32_t v, const void *dbuf, uint32_t siz)
847 {
848 unsigned char *buf = xc->vchg_mem + xc->vchg_siz;
849 unsigned char *pnt = buf;
850 uint32_t nxt;
851 uint32_t len;
852
853 #ifdef FST_DO_MISALIGNED_OPS
854 (*(uint32_t *)(pnt)) = (*(uint32_t *)(u));
855 #else
856 memcpy(pnt, u, sizeof(uint32_t));
857 #endif
858 pnt += 4;
859
860 while((nxt = v>>7))
861 {
862 *(pnt++) = ((unsigned char)v) | 0x80;
863 v = nxt;
864 }
865 *(pnt++) = (unsigned char)v;
866 memcpy(pnt, dbuf, siz);
867
868 len = pnt-buf + siz;
869 return(len);
870 }
871
872
fstWriterUint32WithVarint32AndLength(struct fstWriterContext * xc,uint32_t * u,uint32_t v,const void * dbuf,uint32_t siz)873 static uint32_t fstWriterUint32WithVarint32AndLength(struct fstWriterContext *xc, uint32_t *u, uint32_t v, const void *dbuf, uint32_t siz)
874 {
875 unsigned char *buf = xc->vchg_mem + xc->vchg_siz;
876 unsigned char *pnt = buf;
877 uint32_t nxt;
878 uint32_t len;
879
880 #ifdef FST_DO_MISALIGNED_OPS
881 (*(uint32_t *)(pnt)) = (*(uint32_t *)(u));
882 #else
883 memcpy(pnt, u, sizeof(uint32_t));
884 #endif
885 pnt += 4;
886
887 while((nxt = v>>7))
888 {
889 *(pnt++) = ((unsigned char)v) | 0x80;
890 v = nxt;
891 }
892 *(pnt++) = (unsigned char)v;
893
894 v = siz;
895 while((nxt = v>>7))
896 {
897 *(pnt++) = ((unsigned char)v) | 0x80;
898 v = nxt;
899 }
900 *(pnt++) = (unsigned char)v;
901
902 memcpy(pnt, dbuf, siz);
903
904 len = pnt-buf + siz;
905 return(len);
906 }
907
908
909 /*
910 * header bytes, write here so defines are set up before anything else
911 * that needs to use them
912 */
fstWriterEmitHdrBytes(struct fstWriterContext * xc)913 static void fstWriterEmitHdrBytes(struct fstWriterContext *xc)
914 {
915 char vbuf[FST_HDR_SIM_VERSION_SIZE];
916 char dbuf[FST_HDR_DATE_SIZE];
917 double endtest = FST_DOUBLE_ENDTEST;
918 time_t walltime;
919
920 #define FST_HDR_OFFS_TAG (0)
921 fputc(FST_BL_HDR, xc->handle); /* +0 tag */
922
923 #define FST_HDR_OFFS_SECLEN (FST_HDR_OFFS_TAG + 1)
924 fstWriterUint64(xc->handle, 329); /* +1 section length */
925
926 #define FST_HDR_OFFS_START_TIME (FST_HDR_OFFS_SECLEN + 8)
927 fstWriterUint64(xc->handle, 0); /* +9 start time */
928
929 #define FST_HDR_OFFS_END_TIME (FST_HDR_OFFS_START_TIME + 8)
930 fstWriterUint64(xc->handle, 0); /* +17 end time */
931
932 #define FST_HDR_OFFS_ENDIAN_TEST (FST_HDR_OFFS_END_TIME + 8)
933 fstFwrite(&endtest, 8, 1, xc->handle); /* +25 endian test for reals */
934
935 #define FST_HDR_OFFS_MEM_USED (FST_HDR_OFFS_ENDIAN_TEST + 8)
936 fstWriterUint64(xc->handle, xc->fst_break_size);/* +33 memory used by writer */
937
938 #define FST_HDR_OFFS_NUM_SCOPES (FST_HDR_OFFS_MEM_USED + 8)
939 fstWriterUint64(xc->handle, 0); /* +41 scope creation count */
940
941 #define FST_HDR_OFFS_NUM_VARS (FST_HDR_OFFS_NUM_SCOPES + 8)
942 fstWriterUint64(xc->handle, 0); /* +49 var creation count */
943
944 #define FST_HDR_OFFS_MAXHANDLE (FST_HDR_OFFS_NUM_VARS + 8)
945 fstWriterUint64(xc->handle, 0); /* +57 max var idcode */
946
947 #define FST_HDR_OFFS_SECTION_CNT (FST_HDR_OFFS_MAXHANDLE + 8)
948 fstWriterUint64(xc->handle, 0); /* +65 vc section count */
949
950 #define FST_HDR_OFFS_TIMESCALE (FST_HDR_OFFS_SECTION_CNT + 8)
951 fputc((-9)&255, xc->handle); /* +73 timescale 1ns */
952
953 #define FST_HDR_OFFS_SIM_VERSION (FST_HDR_OFFS_TIMESCALE + 1)
954 memset(vbuf, 0, FST_HDR_SIM_VERSION_SIZE);
955 strcpy(vbuf, FST_WRITER_STR);
956 fstFwrite(vbuf, FST_HDR_SIM_VERSION_SIZE, 1, xc->handle); /* +74 version */
957
958 #define FST_HDR_OFFS_DATE (FST_HDR_OFFS_SIM_VERSION + FST_HDR_SIM_VERSION_SIZE)
959 memset(dbuf, 0, FST_HDR_DATE_SIZE);
960 time(&walltime);
961 strcpy(dbuf, asctime(localtime(&walltime)));
962 fstFwrite(dbuf, FST_HDR_DATE_SIZE, 1, xc->handle); /* +202 date */
963
964 /* date size is deliberately overspecified at 119 bytes (originally 128) in order to provide backfill for new args */
965
966 #define FST_HDR_OFFS_FILETYPE (FST_HDR_OFFS_DATE + FST_HDR_DATE_SIZE)
967 fputc(xc->filetype, xc->handle); /* +321 filetype */
968
969 #define FST_HDR_OFFS_TIMEZERO (FST_HDR_OFFS_FILETYPE + FST_HDR_FILETYPE_SIZE)
970 fstWriterUint64(xc->handle, xc->timezero); /* +322 timezero */
971
972 #define FST_HDR_LENGTH (FST_HDR_OFFS_TIMEZERO + FST_HDR_TIMEZERO_SIZE)
973 /* +330 next section starts here */
974 fflush(xc->handle);
975 }
976
977
978 /*
979 * mmap functions
980 */
fstWriterMmapSanity(void * pnt,const char * file,int line,const char * usage)981 static void fstWriterMmapSanity(void *pnt, const char *file, int line, const char *usage)
982 {
983 #if !defined(__CYGWIN__) && !defined(__MINGW32__)
984 if(pnt == MAP_FAILED)
985 {
986 fprintf(stderr, "fstMmap() assigned to %s failed: errno: %d, file %s, line %d.\n", usage, errno, file, line);
987 perror("Why");
988 pnt = NULL;
989 }
990 #endif
991 }
992
993
fstWriterCreateMmaps(struct fstWriterContext * xc)994 static void fstWriterCreateMmaps(struct fstWriterContext *xc)
995 {
996 fst_off_t curpos = ftello(xc->handle);
997
998 fflush(xc->hier_handle);
999
1000 /* write out intermediate header */
1001 fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_START_TIME, SEEK_SET);
1002 fstWriterUint64(xc->handle, xc->firsttime);
1003 fstWriterUint64(xc->handle, xc->curtime);
1004 fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_NUM_SCOPES, SEEK_SET);
1005 fstWriterUint64(xc->handle, xc->numscopes);
1006 fstWriterUint64(xc->handle, xc->numsigs);
1007 fstWriterUint64(xc->handle, xc->maxhandle);
1008 fstWriterUint64(xc->handle, xc->secnum);
1009 fstWriterFseeko(xc, xc->handle, curpos, SEEK_SET);
1010 fflush(xc->handle);
1011
1012 /* do mappings */
1013 if(!xc->valpos_mem)
1014 {
1015 fflush(xc->valpos_handle);
1016 errno = 0;
1017 if(xc->maxhandle)
1018 {
1019 fstWriterMmapSanity(xc->valpos_mem = (uint32_t *)fstMmap(NULL, xc->maxhandle * 4 * sizeof(uint32_t), PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->valpos_handle), 0), __FILE__, __LINE__, "xc->valpos_mem");
1020 }
1021 }
1022 if(!xc->curval_mem)
1023 {
1024 fflush(xc->curval_handle);
1025 errno = 0;
1026 if(xc->maxvalpos)
1027 {
1028 fstWriterMmapSanity(xc->curval_mem = (unsigned char *)fstMmap(NULL, xc->maxvalpos, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->curval_handle), 0), __FILE__, __LINE__, "xc->curval_handle");
1029 }
1030 }
1031 }
1032
1033
fstDestroyMmaps(struct fstWriterContext * xc,int is_closing)1034 static void fstDestroyMmaps(struct fstWriterContext *xc, int is_closing)
1035 {
1036 #if !defined __CYGWIN__ && !defined __MINGW32__
1037 (void)is_closing;
1038 #endif
1039
1040 fstMunmap(xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t));
1041 xc->valpos_mem = NULL;
1042
1043 #if defined __CYGWIN__ || defined __MINGW32__
1044 if(xc->curval_mem)
1045 {
1046 if(!is_closing) /* need to flush out for next emulated mmap() read */
1047 {
1048 unsigned char *pnt = xc->curval_mem;
1049 int __fd = fileno(xc->curval_handle);
1050 fst_off_t cur_offs = lseek(__fd, 0, SEEK_CUR);
1051 size_t i;
1052 size_t __len = xc->maxvalpos;
1053
1054 lseek(__fd, 0, SEEK_SET);
1055 for(i=0;i<__len;i+=SSIZE_MAX)
1056 {
1057 write(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i));
1058 }
1059 lseek(__fd, cur_offs, SEEK_SET);
1060 }
1061 }
1062 #endif
1063
1064 fstMunmap(xc->curval_mem, xc->maxvalpos);
1065 xc->curval_mem = NULL;
1066 }
1067
1068
1069 /*
1070 * set up large and small memory usages
1071 * crossover point in model is FST_ACTIVATE_HUGE_BREAK number of signals
1072 */
fstDetermineBreakSize(struct fstWriterContext * xc)1073 static void fstDetermineBreakSize(struct fstWriterContext *xc)
1074 {
1075 #if defined(__linux__) || defined(FST_MACOSX)
1076 int was_set = 0;
1077
1078 #ifdef __linux__
1079 FILE *f = fopen("/proc/meminfo", "rb");
1080
1081 if(f)
1082 {
1083 char buf[257];
1084 char *s;
1085 while(!feof(f))
1086 {
1087 buf[0] = 0;
1088 s = fgets(buf, 256, f);
1089 if(s && *s)
1090 {
1091 if(!strncmp(s, "MemTotal:", 9))
1092 {
1093 size_t v = atol(s+10);
1094 v *= 1024; /* convert to bytes */
1095 v /= 8; /* chop down to 1/8 physical memory */
1096 if(v > FST_BREAK_SIZE)
1097 {
1098 if(v > FST_BREAK_SIZE_MAX)
1099 {
1100 v = FST_BREAK_SIZE_MAX;
1101 }
1102
1103 xc->fst_huge_break_size = v;
1104 was_set = 1;
1105 break;
1106 }
1107 }
1108 }
1109 }
1110
1111 fclose(f);
1112 }
1113
1114 if(!was_set)
1115 {
1116 xc->fst_huge_break_size = FST_BREAK_SIZE;
1117 }
1118 #else
1119 int mib[2];
1120 int64_t v;
1121 size_t length;
1122
1123 mib[0] = CTL_HW;
1124 mib[1] = HW_MEMSIZE;
1125 length = sizeof(int64_t);
1126 if(!sysctl(mib, 2, &v, &length, NULL, 0))
1127 {
1128 v /= 8;
1129
1130 if(v > (int64_t)FST_BREAK_SIZE)
1131 {
1132 if(v > (int64_t)FST_BREAK_SIZE_MAX)
1133 {
1134 v = FST_BREAK_SIZE_MAX;
1135 }
1136
1137 xc->fst_huge_break_size = v;
1138 was_set = 1;
1139 }
1140 }
1141
1142 if(!was_set)
1143 {
1144 xc->fst_huge_break_size = FST_BREAK_SIZE;
1145 }
1146 #endif
1147 #else
1148 xc->fst_huge_break_size = FST_BREAK_SIZE;
1149 #endif
1150
1151 xc->fst_break_size = xc->fst_orig_break_size = FST_BREAK_SIZE;
1152 xc->fst_break_add_size = xc->fst_orig_break_add_size = FST_BREAK_ADD_SIZE;
1153 xc->next_huge_break = FST_ACTIVATE_HUGE_BREAK;
1154 }
1155
1156
1157 /*
1158 * file creation and close
1159 */
fstWriterCreate(const char * nam,int use_compressed_hier)1160 void *fstWriterCreate(const char *nam, int use_compressed_hier)
1161 {
1162 struct fstWriterContext *xc = (struct fstWriterContext *)calloc(1, sizeof(struct fstWriterContext));
1163
1164 xc->compress_hier = use_compressed_hier;
1165 fstDetermineBreakSize(xc);
1166
1167 if((!nam)||
1168 (!(xc->handle=unlink_fopen(nam, "w+b"))))
1169 {
1170 free(xc);
1171 xc=NULL;
1172 }
1173 else
1174 {
1175 int flen = strlen(nam);
1176 char *hf = (char *)calloc(1, flen + 6);
1177
1178 memcpy(hf, nam, flen);
1179 strcpy(hf + flen, ".hier");
1180 xc->hier_handle = unlink_fopen(hf, "w+b");
1181
1182 xc->geom_handle = tmpfile_open(&xc->geom_handle_nam); /* .geom */
1183 xc->valpos_handle = tmpfile_open(&xc->valpos_handle_nam); /* .offs */
1184 xc->curval_handle = tmpfile_open(&xc->curval_handle_nam); /* .bits */
1185 xc->tchn_handle = tmpfile_open(&xc->tchn_handle_nam); /* .tchn */
1186 xc->vchg_alloc_siz = xc->fst_break_size + xc->fst_break_add_size;
1187 xc->vchg_mem = (unsigned char *)malloc(xc->vchg_alloc_siz);
1188
1189 if(xc->hier_handle && xc->geom_handle && xc->valpos_handle && xc->curval_handle && xc->vchg_mem && xc->tchn_handle)
1190 {
1191 xc->filename = strdup(nam);
1192 xc->is_initial_time = 1;
1193
1194 fstWriterEmitHdrBytes(xc);
1195 xc->nan = strtod("NaN", NULL);
1196 #ifdef FST_WRITER_PARALLEL
1197 pthread_mutex_init(&xc->mutex, NULL);
1198 pthread_attr_init(&xc->thread_attr);
1199 pthread_attr_setdetachstate(&xc->thread_attr, PTHREAD_CREATE_DETACHED);
1200 #endif
1201 }
1202 else
1203 {
1204 fclose(xc->handle);
1205 if(xc->hier_handle) { fclose(xc->hier_handle); unlink(hf); }
1206 tmpfile_close(&xc->geom_handle, &xc->geom_handle_nam);
1207 tmpfile_close(&xc->valpos_handle, &xc->valpos_handle_nam);
1208 tmpfile_close(&xc->curval_handle, &xc->curval_handle_nam);
1209 tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam);
1210 free(xc->vchg_mem);
1211 free(xc);
1212 xc=NULL;
1213 }
1214
1215 free(hf);
1216 }
1217
1218 return(xc);
1219 }
1220
1221
1222 /*
1223 * generation and writing out of value change data sections
1224 */
fstWriterEmitSectionHeader(void * ctx)1225 static void fstWriterEmitSectionHeader(void *ctx)
1226 {
1227 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
1228
1229 if(xc)
1230 {
1231 unsigned long destlen;
1232 unsigned char *dmem;
1233 int rc;
1234
1235 destlen = xc->maxvalpos;
1236 dmem = (unsigned char *)malloc(compressBound(destlen));
1237 rc = compress2(dmem, &destlen, xc->curval_mem, xc->maxvalpos, 4); /* was 9...which caused performance drag on traces with many signals */
1238
1239 fputc(FST_BL_SKIP, xc->handle); /* temporarily tag the section, use FST_BL_VCDATA on finalize */
1240 xc->section_start = ftello(xc->handle);
1241 #ifdef FST_WRITER_PARALLEL
1242 if(xc->xc_parent) xc->xc_parent->section_start = xc->section_start;
1243 #endif
1244 xc->section_header_only = 1; /* indicates truncate might be needed */
1245 fstWriterUint64(xc->handle, 0); /* placeholder = section length */
1246 fstWriterUint64(xc->handle, xc->is_initial_time ? xc->firsttime : xc->curtime); /* begin time of section */
1247 fstWriterUint64(xc->handle, xc->curtime); /* end time of section (placeholder) */
1248 fstWriterUint64(xc->handle, 0); /* placeholder = amount of buffer memory required in reader for full vc traversal */
1249 fstWriterVarint(xc->handle, xc->maxvalpos); /* maxvalpos = length of uncompressed data */
1250
1251 if((rc == Z_OK) && (destlen < xc->maxvalpos))
1252 {
1253 fstWriterVarint(xc->handle, destlen); /* length of compressed data */
1254 }
1255 else
1256 {
1257 fstWriterVarint(xc->handle, xc->maxvalpos); /* length of (unable to be) compressed data */
1258 }
1259 fstWriterVarint(xc->handle, xc->maxhandle); /* max handle associated with this data (in case of dynamic facility adds) */
1260
1261 if((rc == Z_OK) && (destlen < xc->maxvalpos))
1262 {
1263 fstFwrite(dmem, destlen, 1, xc->handle);
1264 }
1265 else /* comparison between compressed / decompressed len tells if compressed */
1266 {
1267 fstFwrite(xc->curval_mem, xc->maxvalpos, 1, xc->handle);
1268 }
1269
1270 free(dmem);
1271 }
1272 }
1273
1274
1275 /*
1276 * only to be called directly by fst code...otherwise must
1277 * be synced up with time changes
1278 */
1279 #ifdef FST_WRITER_PARALLEL
fstWriterFlushContextPrivate2(void * ctx)1280 static void fstWriterFlushContextPrivate2(void *ctx)
1281 #else
1282 static void fstWriterFlushContextPrivate(void *ctx)
1283 #endif
1284 {
1285 #ifdef FST_DEBUG
1286 int cnt = 0;
1287 #endif
1288 unsigned int i;
1289 unsigned char *vchg_mem;
1290 FILE *f;
1291 fst_off_t fpos, indxpos, endpos;
1292 uint32_t prevpos;
1293 int zerocnt;
1294 unsigned char *scratchpad;
1295 unsigned char *scratchpnt;
1296 unsigned char *tmem;
1297 fst_off_t tlen;
1298 fst_off_t unc_memreq = 0; /* for reader */
1299 unsigned char *packmem;
1300 unsigned int packmemlen;
1301 uint32_t *vm4ip;
1302 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
1303 #ifdef FST_WRITER_PARALLEL
1304 struct fstWriterContext *xc2 = xc->xc_parent;
1305 #else
1306 struct fstWriterContext *xc2 = xc;
1307 #endif
1308
1309 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1310 Pvoid_t PJHSArray = (Pvoid_t) NULL;
1311 #ifndef _WAVE_HAVE_JUDY
1312 uint32_t hashmask = xc->maxhandle;
1313 hashmask |= hashmask >> 1;
1314 hashmask |= hashmask >> 2;
1315 hashmask |= hashmask >> 4;
1316 hashmask |= hashmask >> 8;
1317 hashmask |= hashmask >> 16;
1318 #endif
1319 #endif
1320
1321 if((xc->vchg_siz <= 1)||(xc->already_in_flush)) return;
1322 xc->already_in_flush = 1; /* should really do this with a semaphore */
1323
1324 xc->section_header_only = 0;
1325 scratchpad = (unsigned char *)malloc(xc->vchg_siz);
1326
1327 vchg_mem = xc->vchg_mem;
1328
1329 f = xc->handle;
1330 fstWriterVarint(f, xc->maxhandle); /* emit current number of handles */
1331 fputc(xc->fourpack ? '4' : (xc->fastpack ? 'F' : 'Z'), f);
1332 fpos = 1;
1333
1334 packmemlen = 1024; /* maintain a running "longest" allocation to */
1335 packmem = (unsigned char *)malloc(packmemlen); /* prevent continual malloc...free every loop iter */
1336
1337 for(i=0;i<xc->maxhandle;i++)
1338 {
1339 vm4ip = &(xc->valpos_mem[4*i]);
1340
1341 if(vm4ip[2])
1342 {
1343 uint32_t offs = vm4ip[2];
1344 uint32_t next_offs;
1345 unsigned int wrlen;
1346
1347 vm4ip[2] = fpos;
1348
1349 scratchpnt = scratchpad + xc->vchg_siz; /* build this buffer backwards */
1350 if(vm4ip[1] <= 1)
1351 {
1352 if(vm4ip[1] == 1)
1353 {
1354 wrlen = fstGetVarint32Length(vchg_mem + offs + 4); /* used to advance and determine wrlen */
1355 #ifndef FST_REMOVE_DUPLICATE_VC
1356 xc->curval_mem[vm4ip[0]] = vchg_mem[offs + 4 + wrlen]; /* checkpoint variable */
1357 #endif
1358 while(offs)
1359 {
1360 unsigned char val;
1361 uint32_t time_delta, rcv;
1362 next_offs = fstGetUint32(vchg_mem + offs);
1363 offs += 4;
1364
1365 time_delta = fstGetVarint32(vchg_mem + offs, (int *)&wrlen);
1366 val = vchg_mem[offs+wrlen];
1367 offs = next_offs;
1368
1369 switch(val)
1370 {
1371 case '0':
1372 case '1': rcv = ((val&1)<<1) | (time_delta<<2);
1373 break; /* pack more delta bits in for 0/1 vchs */
1374
1375 case 'x': case 'X': rcv = FST_RCV_X | (time_delta<<4); break;
1376 case 'z': case 'Z': rcv = FST_RCV_Z | (time_delta<<4); break;
1377 case 'h': case 'H': rcv = FST_RCV_H | (time_delta<<4); break;
1378 case 'u': case 'U': rcv = FST_RCV_U | (time_delta<<4); break;
1379 case 'w': case 'W': rcv = FST_RCV_W | (time_delta<<4); break;
1380 case 'l': case 'L': rcv = FST_RCV_L | (time_delta<<4); break;
1381 default: rcv = FST_RCV_D | (time_delta<<4); break;
1382 }
1383
1384 scratchpnt = fstCopyVarint32ToLeft(scratchpnt, rcv);
1385 }
1386 }
1387 else
1388 {
1389 /* variable length */
1390 /* fstGetUint32 (next_offs) + fstGetVarint32 (time_delta) + fstGetVarint32 (len) + payload */
1391 unsigned char *pnt;
1392 uint32_t record_len;
1393 uint32_t time_delta;
1394
1395 while(offs)
1396 {
1397 next_offs = fstGetUint32(vchg_mem + offs);
1398 offs += 4;
1399 pnt = vchg_mem + offs;
1400 offs = next_offs;
1401 time_delta = fstGetVarint32(pnt, (int *)&wrlen);
1402 pnt += wrlen;
1403 record_len = fstGetVarint32(pnt, (int *)&wrlen);
1404 pnt += wrlen;
1405
1406 scratchpnt -= record_len;
1407 memcpy(scratchpnt, pnt, record_len);
1408
1409 scratchpnt = fstCopyVarint32ToLeft(scratchpnt, record_len);
1410 scratchpnt = fstCopyVarint32ToLeft(scratchpnt, (time_delta << 1)); /* reserve | 1 case for future expansion */
1411 }
1412 }
1413 }
1414 else
1415 {
1416 wrlen = fstGetVarint32Length(vchg_mem + offs + 4); /* used to advance and determine wrlen */
1417 #ifndef FST_REMOVE_DUPLICATE_VC
1418 memcpy(xc->curval_mem + vm4ip[0], vchg_mem + offs + 4 + wrlen, vm4ip[1]); /* checkpoint variable */
1419 #endif
1420 while(offs)
1421 {
1422 unsigned int idx;
1423 char is_binary = 1;
1424 unsigned char *pnt;
1425 uint32_t time_delta;
1426
1427 next_offs = fstGetUint32(vchg_mem + offs);
1428 offs += 4;
1429
1430 time_delta = fstGetVarint32(vchg_mem + offs, (int *)&wrlen);
1431
1432 pnt = vchg_mem+offs+wrlen;
1433 offs = next_offs;
1434
1435 for(idx=0;idx<vm4ip[1];idx++)
1436 {
1437 if((pnt[idx] == '0') || (pnt[idx] == '1'))
1438 {
1439 continue;
1440 }
1441 else
1442 {
1443 is_binary = 0;
1444 break;
1445 }
1446 }
1447
1448 if(is_binary)
1449 {
1450 unsigned char acc = 0;
1451 /* new algorithm */
1452 idx = ((vm4ip[1]+7) & ~7);
1453 switch(vm4ip[1] & 7)
1454 {
1455 case 0: do { acc = (pnt[idx+7-8] & 1) << 0; /* fallthrough */
1456 case 7: acc |= (pnt[idx+6-8] & 1) << 1; /* fallthrough */
1457 case 6: acc |= (pnt[idx+5-8] & 1) << 2; /* fallthrough */
1458 case 5: acc |= (pnt[idx+4-8] & 1) << 3; /* fallthrough */
1459 case 4: acc |= (pnt[idx+3-8] & 1) << 4; /* fallthrough */
1460 case 3: acc |= (pnt[idx+2-8] & 1) << 5; /* fallthrough */
1461 case 2: acc |= (pnt[idx+1-8] & 1) << 6; /* fallthrough */
1462 case 1: acc |= (pnt[idx+0-8] & 1) << 7;
1463 *(--scratchpnt) = acc;
1464 idx -= 8;
1465 } while(idx);
1466 }
1467
1468 scratchpnt = fstCopyVarint32ToLeft(scratchpnt, (time_delta << 1));
1469 }
1470 else
1471 {
1472 scratchpnt -= vm4ip[1];
1473 memcpy(scratchpnt, pnt, vm4ip[1]);
1474
1475 scratchpnt = fstCopyVarint32ToLeft(scratchpnt, (time_delta << 1) | 1);
1476 }
1477 }
1478 }
1479
1480 wrlen = scratchpad + xc->vchg_siz - scratchpnt;
1481 unc_memreq += wrlen;
1482 if(wrlen > 32)
1483 {
1484 unsigned long destlen = wrlen;
1485 unsigned char *dmem;
1486 unsigned int rc;
1487
1488 if(!xc->fastpack)
1489 {
1490 if(wrlen <= packmemlen)
1491 {
1492 dmem = packmem;
1493 }
1494 else
1495 {
1496 free(packmem);
1497 dmem = packmem = (unsigned char *)malloc(compressBound(packmemlen = wrlen));
1498 }
1499
1500 rc = compress2(dmem, &destlen, scratchpnt, wrlen, 4);
1501 if(rc == Z_OK)
1502 {
1503 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1504 PPvoid_t pv = JudyHSIns(&PJHSArray, dmem, destlen, NULL);
1505 if(*pv)
1506 {
1507 uint32_t pvi = (intptr_t)(*pv);
1508 vm4ip[2] = -pvi;
1509 }
1510 else
1511 {
1512 *pv = (void *)(intptr_t)(i+1);
1513 #endif
1514 fpos += fstWriterVarint(f, wrlen);
1515 fpos += destlen;
1516 fstFwrite(dmem, destlen, 1, f);
1517 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1518 }
1519 #endif
1520 }
1521 else
1522 {
1523 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1524 PPvoid_t pv = JudyHSIns(&PJHSArray, scratchpnt, wrlen, NULL);
1525 if(*pv)
1526 {
1527 uint32_t pvi = (intptr_t)(*pv);
1528 vm4ip[2] = -pvi;
1529 }
1530 else
1531 {
1532 *pv = (void *)(intptr_t)(i+1);
1533 #endif
1534 fpos += fstWriterVarint(f, 0);
1535 fpos += wrlen;
1536 fstFwrite(scratchpnt, wrlen, 1, f);
1537 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1538 }
1539 #endif
1540 }
1541 }
1542 else
1543 {
1544 /* this is extremely conservative: fastlz needs +5% for worst case, lz4 needs siz+(siz/255)+16 */
1545 if(((wrlen * 2) + 2) <= packmemlen)
1546 {
1547 dmem = packmem;
1548 }
1549 else
1550 {
1551 free(packmem);
1552 dmem = packmem = (unsigned char *)malloc(packmemlen = (wrlen * 2) + 2);
1553 }
1554
1555 rc = (xc->fourpack) ? LZ4_compress((char *)scratchpnt, (char *)dmem, wrlen) : fastlz_compress(scratchpnt, wrlen, dmem);
1556 if(rc < destlen)
1557 {
1558 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1559 PPvoid_t pv = JudyHSIns(&PJHSArray, dmem, rc, NULL);
1560 if(*pv)
1561 {
1562 uint32_t pvi = (intptr_t)(*pv);
1563 vm4ip[2] = -pvi;
1564 }
1565 else
1566 {
1567 *pv = (void *)(intptr_t)(i+1);
1568 #endif
1569 fpos += fstWriterVarint(f, wrlen);
1570 fpos += rc;
1571 fstFwrite(dmem, rc, 1, f);
1572 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1573 }
1574 #endif
1575 }
1576 else
1577 {
1578 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1579 PPvoid_t pv = JudyHSIns(&PJHSArray, scratchpnt, wrlen, NULL);
1580 if(*pv)
1581 {
1582 uint32_t pvi = (intptr_t)(*pv);
1583 vm4ip[2] = -pvi;
1584 }
1585 else
1586 {
1587 *pv = (void *)(intptr_t)(i+1);
1588 #endif
1589 fpos += fstWriterVarint(f, 0);
1590 fpos += wrlen;
1591 fstFwrite(scratchpnt, wrlen, 1, f);
1592 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1593 }
1594 #endif
1595 }
1596 }
1597 }
1598 else
1599 {
1600 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1601 PPvoid_t pv = JudyHSIns(&PJHSArray, scratchpnt, wrlen, NULL);
1602 if(*pv)
1603 {
1604 uint32_t pvi = (intptr_t)(*pv);
1605 vm4ip[2] = -pvi;
1606 }
1607 else
1608 {
1609 *pv = (void *)(intptr_t)(i+1);
1610 #endif
1611 fpos += fstWriterVarint(f, 0);
1612 fpos += wrlen;
1613 fstFwrite(scratchpnt, wrlen, 1, f);
1614 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1615 }
1616 #endif
1617 }
1618
1619 /* vm4ip[3] = 0; ...redundant with clearing below */
1620 #ifdef FST_DEBUG
1621 cnt++;
1622 #endif
1623 }
1624 }
1625
1626 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1627 JudyHSFreeArray(&PJHSArray, NULL);
1628 #endif
1629
1630 free(packmem); packmem = NULL; /* packmemlen = 0; */ /* scan-build */
1631
1632 prevpos = 0; zerocnt = 0;
1633 free(scratchpad); scratchpad = NULL;
1634
1635 indxpos = ftello(f);
1636 xc->secnum++;
1637
1638 #ifndef FST_DYNAMIC_ALIAS2_DISABLE
1639 if(1)
1640 {
1641 uint32_t prev_alias = 0;
1642
1643 for(i=0;i<xc->maxhandle;i++)
1644 {
1645 vm4ip = &(xc->valpos_mem[4*i]);
1646
1647 if(vm4ip[2])
1648 {
1649 if(zerocnt)
1650 {
1651 fpos += fstWriterVarint(f, (zerocnt << 1));
1652 zerocnt = 0;
1653 }
1654
1655 if(vm4ip[2] & 0x80000000)
1656 {
1657 if(vm4ip[2] != prev_alias)
1658 {
1659 fpos += fstWriterSVarint(f, (((int64_t)((int32_t)(prev_alias = vm4ip[2]))) << 1) | 1);
1660 }
1661 else
1662 {
1663 fpos += fstWriterSVarint(f, (0 << 1) | 1);
1664 }
1665 }
1666 else
1667 {
1668 fpos += fstWriterSVarint(f, ((vm4ip[2] - prevpos) << 1) | 1);
1669 prevpos = vm4ip[2];
1670 }
1671 vm4ip[2] = 0;
1672 vm4ip[3] = 0; /* clear out tchn idx */
1673 }
1674 else
1675 {
1676 zerocnt++;
1677 }
1678 }
1679 }
1680 else
1681 #endif
1682 {
1683 for(i=0;i<xc->maxhandle;i++)
1684 {
1685 vm4ip = &(xc->valpos_mem[4*i]);
1686
1687 if(vm4ip[2])
1688 {
1689 if(zerocnt)
1690 {
1691 fpos += fstWriterVarint(f, (zerocnt << 1));
1692 zerocnt = 0;
1693 }
1694
1695 if(vm4ip[2] & 0x80000000)
1696 {
1697 fpos += fstWriterVarint(f, 0); /* signal, note that using a *signed* varint would be more efficient than this byte escape! */
1698 fpos += fstWriterVarint(f, (-(int32_t)vm4ip[2]));
1699 }
1700 else
1701 {
1702 fpos += fstWriterVarint(f, ((vm4ip[2] - prevpos) << 1) | 1);
1703 prevpos = vm4ip[2];
1704 }
1705 vm4ip[2] = 0;
1706 vm4ip[3] = 0; /* clear out tchn idx */
1707 }
1708 else
1709 {
1710 zerocnt++;
1711 }
1712 }
1713 }
1714
1715 if(zerocnt)
1716 {
1717 /* fpos += */ fstWriterVarint(f, (zerocnt << 1)); /* scan-build */
1718 }
1719 #ifdef FST_DEBUG
1720 fprintf(stderr, FST_APIMESS "value chains: %d\n", cnt);
1721 #endif
1722
1723 xc->vchg_mem[0] = '!';
1724 xc->vchg_siz = 1;
1725
1726 endpos = ftello(xc->handle);
1727 fstWriterUint64(xc->handle, endpos-indxpos); /* write delta index position at very end of block */
1728
1729 /*emit time changes for block */
1730 fflush(xc->tchn_handle);
1731 tlen = ftello(xc->tchn_handle);
1732 fstWriterFseeko(xc, xc->tchn_handle, 0, SEEK_SET);
1733
1734 errno = 0;
1735 fstWriterMmapSanity(tmem = (unsigned char *)fstMmap(NULL, tlen, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->tchn_handle), 0), __FILE__, __LINE__, "tmem");
1736 if(tmem)
1737 {
1738 unsigned long destlen = tlen;
1739 unsigned char *dmem = (unsigned char *)malloc(compressBound(destlen));
1740 int rc = compress2(dmem, &destlen, tmem, tlen, 9);
1741
1742 if((rc == Z_OK) && (((fst_off_t)destlen) < tlen))
1743 {
1744 fstFwrite(dmem, destlen, 1, xc->handle);
1745 }
1746 else /* comparison between compressed / decompressed len tells if compressed */
1747 {
1748 fstFwrite(tmem, tlen, 1, xc->handle);
1749 destlen = tlen;
1750 }
1751 free(dmem);
1752 fstMunmap(tmem, tlen);
1753 fstWriterUint64(xc->handle, tlen); /* uncompressed */
1754 fstWriterUint64(xc->handle, destlen); /* compressed */
1755 fstWriterUint64(xc->handle, xc->tchn_cnt); /* number of time items */
1756 }
1757
1758 xc->tchn_cnt = xc->tchn_idx = 0;
1759 fstWriterFseeko(xc, xc->tchn_handle, 0, SEEK_SET);
1760 fstFtruncate(fileno(xc->tchn_handle), 0);
1761
1762 /* write block trailer */
1763 endpos = ftello(xc->handle);
1764 fstWriterFseeko(xc, xc->handle, xc->section_start, SEEK_SET);
1765 fstWriterUint64(xc->handle, endpos - xc->section_start); /* write block length */
1766 fstWriterFseeko(xc, xc->handle, 8, SEEK_CUR); /* skip begin time */
1767 fstWriterUint64(xc->handle, xc->curtime); /* write end time for section */
1768 fstWriterUint64(xc->handle, unc_memreq); /* amount of buffer memory required in reader for full traversal */
1769 fflush(xc->handle);
1770
1771 fstWriterFseeko(xc, xc->handle, xc->section_start-1, SEEK_SET); /* write out FST_BL_VCDATA over FST_BL_SKIP */
1772
1773 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1774 #ifndef FST_DYNAMIC_ALIAS2_DISABLE
1775 fputc(FST_BL_VCDATA_DYN_ALIAS2, xc->handle);
1776 #else
1777 fputc(FST_BL_VCDATA_DYN_ALIAS, xc->handle);
1778 #endif
1779 #else
1780 fputc(FST_BL_VCDATA, xc->handle);
1781 #endif
1782
1783 fflush(xc->handle);
1784
1785 fstWriterFseeko(xc, xc->handle, endpos, SEEK_SET); /* seek to end of file */
1786
1787 xc2->section_header_truncpos = endpos; /* cache in case of need to truncate */
1788 if(xc->dump_size_limit)
1789 {
1790 if(endpos >= ((fst_off_t)xc->dump_size_limit))
1791 {
1792 xc2->skip_writing_section_hdr = 1;
1793 xc2->size_limit_locked = 1;
1794 xc2->is_initial_time = 1; /* to trick emit value and emit time change */
1795 #ifdef FST_DEBUG
1796 fprintf(stderr, FST_APIMESS "<< dump file size limit reached, stopping dumping >>\n");
1797 #endif
1798 }
1799 }
1800
1801 if(!xc2->skip_writing_section_hdr)
1802 {
1803 fstWriterEmitSectionHeader(xc); /* emit next section header */
1804 }
1805 fflush(xc->handle);
1806
1807 xc->already_in_flush = 0;
1808 }
1809
1810
1811 #ifdef FST_WRITER_PARALLEL
fstWriterFlushContextPrivate1(void * ctx)1812 static void *fstWriterFlushContextPrivate1(void *ctx)
1813 {
1814 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
1815 struct fstWriterContext *xc_parent;
1816
1817 pthread_mutex_lock(&(xc->xc_parent->mutex));
1818 fstWriterFlushContextPrivate2(xc);
1819
1820 #ifdef FST_REMOVE_DUPLICATE_VC
1821 free(xc->curval_mem);
1822 #endif
1823 free(xc->valpos_mem);
1824 free(xc->vchg_mem);
1825 tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam);
1826 xc_parent = xc->xc_parent;
1827 free(xc);
1828
1829 xc_parent->in_pthread = 0;
1830 pthread_mutex_unlock(&(xc_parent->mutex));
1831
1832 return(NULL);
1833 }
1834
1835
fstWriterFlushContextPrivate(void * ctx)1836 static void fstWriterFlushContextPrivate(void *ctx)
1837 {
1838 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
1839
1840 if(xc->parallel_enabled)
1841 {
1842 struct fstWriterContext *xc2 = (struct fstWriterContext *)malloc(sizeof(struct fstWriterContext));
1843 unsigned int i;
1844
1845 pthread_mutex_lock(&xc->mutex);
1846 pthread_mutex_unlock(&xc->mutex);
1847
1848 xc->xc_parent = xc;
1849 memcpy(xc2, xc, sizeof(struct fstWriterContext));
1850
1851 xc2->valpos_mem = (uint32_t *)malloc(xc->maxhandle * 4 * sizeof(uint32_t));
1852 memcpy(xc2->valpos_mem, xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t));
1853
1854 /* curval mem is updated in the thread */
1855 #ifdef FST_REMOVE_DUPLICATE_VC
1856 xc2->curval_mem = (unsigned char *)malloc(xc->maxvalpos);
1857 memcpy(xc2->curval_mem, xc->curval_mem, xc->maxvalpos);
1858 #endif
1859
1860 xc->vchg_mem = (unsigned char *)malloc(xc->vchg_alloc_siz);
1861 xc->vchg_mem[0] = '!';
1862 xc->vchg_siz = 1;
1863
1864 for(i=0;i<xc->maxhandle;i++)
1865 {
1866 uint32_t *vm4ip = &(xc->valpos_mem[4*i]);
1867 vm4ip[2] = 0; /* zero out offset val */
1868 vm4ip[3] = 0; /* zero out last time change val */
1869 }
1870
1871 xc->tchn_cnt = xc->tchn_idx = 0;
1872 xc->tchn_handle = tmpfile_open(&xc->tchn_handle_nam); /* child thread will deallocate file/name */
1873 fstWriterFseeko(xc, xc->tchn_handle, 0, SEEK_SET);
1874 fstFtruncate(fileno(xc->tchn_handle), 0);
1875
1876 xc->section_header_only = 0;
1877 xc->secnum++;
1878
1879 while (xc->in_pthread)
1880 {
1881 pthread_mutex_lock(&xc->mutex);
1882 pthread_mutex_unlock(&xc->mutex);
1883 };
1884
1885 pthread_mutex_lock(&xc->mutex);
1886 xc->in_pthread = 1;
1887 pthread_mutex_unlock(&xc->mutex);
1888
1889 pthread_create(&xc->thread, &xc->thread_attr, fstWriterFlushContextPrivate1, xc2);
1890 }
1891 else
1892 {
1893 if(xc->parallel_was_enabled) /* conservatively block */
1894 {
1895 pthread_mutex_lock(&xc->mutex);
1896 pthread_mutex_unlock(&xc->mutex);
1897 }
1898
1899 xc->xc_parent = xc;
1900 fstWriterFlushContextPrivate2(xc);
1901 }
1902 }
1903 #endif
1904
1905
1906 /*
1907 * queues up a flush context operation
1908 */
fstWriterFlushContext(void * ctx)1909 void fstWriterFlushContext(void *ctx)
1910 {
1911 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
1912 if(xc)
1913 {
1914 if(xc->tchn_idx > 1)
1915 {
1916 xc->flush_context_pending = 1;
1917 }
1918 }
1919 }
1920
1921
1922 /*
1923 * close out FST file
1924 */
fstWriterClose(void * ctx)1925 void fstWriterClose(void *ctx)
1926 {
1927 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
1928
1929 #ifdef FST_WRITER_PARALLEL
1930 if(xc)
1931 {
1932 pthread_mutex_lock(&xc->mutex);
1933 pthread_mutex_unlock(&xc->mutex);
1934 }
1935 #endif
1936
1937 if(xc && !xc->already_in_close && !xc->already_in_flush)
1938 {
1939 unsigned char *tmem = NULL;
1940 fst_off_t fixup_offs, tlen, hlen;
1941
1942 xc->already_in_close = 1; /* never need to zero this out as it is freed at bottom */
1943
1944 if(xc->section_header_only && xc->section_header_truncpos && (xc->vchg_siz <= 1) && (!xc->is_initial_time))
1945 {
1946 fstFtruncate(fileno(xc->handle), xc->section_header_truncpos);
1947 fstWriterFseeko(xc, xc->handle, xc->section_header_truncpos, SEEK_SET);
1948 xc->section_header_only = 0;
1949 }
1950 else
1951 {
1952 xc->skip_writing_section_hdr = 1;
1953 if(!xc->size_limit_locked)
1954 {
1955 if(FST_UNLIKELY(xc->is_initial_time)) /* simulation time never advanced so mock up the changes as time zero ones */
1956 {
1957 fstHandle dupe_idx;
1958
1959 fstWriterEmitTimeChange(xc, 0); /* emit some time change just to have one */
1960 for(dupe_idx = 0; dupe_idx < xc->maxhandle; dupe_idx++) /* now clone the values */
1961 {
1962 fstWriterEmitValueChange(xc, dupe_idx+1, xc->curval_mem + xc->valpos_mem[4*dupe_idx]);
1963 }
1964 }
1965 fstWriterFlushContextPrivate(xc);
1966 #ifdef FST_WRITER_PARALLEL
1967 pthread_mutex_lock(&xc->mutex);
1968 pthread_mutex_unlock(&xc->mutex);
1969
1970 while (xc->in_pthread)
1971 {
1972 pthread_mutex_lock(&xc->mutex);
1973 pthread_mutex_unlock(&xc->mutex);
1974 };
1975 #endif
1976 }
1977 }
1978 fstDestroyMmaps(xc, 1);
1979 if(xc->outval_mem)
1980 {
1981 free(xc->outval_mem); xc->outval_mem = NULL;
1982 xc->outval_alloc_siz = 0;
1983 }
1984
1985 /* write out geom section */
1986 fflush(xc->geom_handle);
1987 tlen = ftello(xc->geom_handle);
1988 errno = 0;
1989 if(tlen)
1990 {
1991 fstWriterMmapSanity(tmem = (unsigned char *)fstMmap(NULL, tlen, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->geom_handle), 0), __FILE__, __LINE__, "tmem");
1992 }
1993
1994 if(tmem)
1995 {
1996 unsigned long destlen = tlen;
1997 unsigned char *dmem = (unsigned char *)malloc(compressBound(destlen));
1998 int rc = compress2(dmem, &destlen, tmem, tlen, 9);
1999
2000 if((rc != Z_OK) || (((fst_off_t)destlen) > tlen))
2001 {
2002 destlen = tlen;
2003 }
2004
2005 fixup_offs = ftello(xc->handle);
2006 fputc(FST_BL_SKIP, xc->handle); /* temporary tag */
2007 fstWriterUint64(xc->handle, destlen + 24); /* section length */
2008 fstWriterUint64(xc->handle, tlen); /* uncompressed */
2009 /* compressed len is section length - 24 */
2010 fstWriterUint64(xc->handle, xc->maxhandle); /* maxhandle */
2011 fstFwrite((((fst_off_t)destlen) != tlen) ? dmem : tmem, destlen, 1, xc->handle);
2012 fflush(xc->handle);
2013
2014 fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET);
2015 fputc(FST_BL_GEOM, xc->handle); /* actual tag */
2016
2017 fstWriterFseeko(xc, xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */
2018 fflush(xc->handle);
2019
2020 free(dmem);
2021 fstMunmap(tmem, tlen);
2022 }
2023
2024 if(xc->num_blackouts)
2025 {
2026 uint64_t cur_bl = 0;
2027 fst_off_t bpos, eos;
2028 uint32_t i;
2029
2030 fixup_offs = ftello(xc->handle);
2031 fputc(FST_BL_SKIP, xc->handle); /* temporary tag */
2032 bpos = fixup_offs + 1;
2033 fstWriterUint64(xc->handle, 0); /* section length */
2034 fstWriterVarint(xc->handle, xc->num_blackouts);
2035
2036 for(i=0;i<xc->num_blackouts;i++)
2037 {
2038 fputc(xc->blackout_head->active, xc->handle);
2039 fstWriterVarint(xc->handle, xc->blackout_head->tim - cur_bl);
2040 cur_bl = xc->blackout_head->tim;
2041 xc->blackout_curr = xc->blackout_head->next;
2042 free(xc->blackout_head);
2043 xc->blackout_head = xc->blackout_curr;
2044 }
2045
2046 eos = ftello(xc->handle);
2047 fstWriterFseeko(xc, xc->handle, bpos, SEEK_SET);
2048 fstWriterUint64(xc->handle, eos - bpos);
2049 fflush(xc->handle);
2050
2051 fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET);
2052 fputc(FST_BL_BLACKOUT, xc->handle); /* actual tag */
2053
2054 fstWriterFseeko(xc, xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */
2055 fflush(xc->handle);
2056 }
2057
2058 if(xc->compress_hier)
2059 {
2060 fst_off_t hl, eos;
2061 gzFile zhandle;
2062 int zfd;
2063 int fourpack_duo = 0;
2064 #ifndef __MINGW32__
2065 char *fnam = (char *)malloc(strlen(xc->filename) + 5 + 1);
2066 #endif
2067
2068 fixup_offs = ftello(xc->handle);
2069 fputc(FST_BL_SKIP, xc->handle); /* temporary tag */
2070 hlen = ftello(xc->handle);
2071 fstWriterUint64(xc->handle, 0); /* section length */
2072 fstWriterUint64(xc->handle, xc->hier_file_len); /* uncompressed length */
2073
2074 if(!xc->fourpack)
2075 {
2076 unsigned char *mem = (unsigned char *)malloc(FST_GZIO_LEN);
2077 zfd = dup(fileno(xc->handle));
2078 fflush(xc->handle);
2079 zhandle = gzdopen(zfd, "wb4");
2080 if(zhandle)
2081 {
2082 fstWriterFseeko(xc, xc->hier_handle, 0, SEEK_SET);
2083 for(hl = 0; hl < xc->hier_file_len; hl += FST_GZIO_LEN)
2084 {
2085 unsigned len = ((xc->hier_file_len - hl) > FST_GZIO_LEN) ? FST_GZIO_LEN : (xc->hier_file_len - hl);
2086 fstFread(mem, len, 1, xc->hier_handle);
2087 gzwrite(zhandle, mem, len);
2088 }
2089 gzclose(zhandle);
2090 }
2091 else
2092 {
2093 close(zfd);
2094 }
2095 free(mem);
2096 }
2097 else
2098 {
2099 int lz4_maxlen;
2100 unsigned char *mem;
2101 unsigned char *hmem = NULL;
2102 int packed_len;
2103
2104 fflush(xc->handle);
2105
2106 lz4_maxlen = LZ4_compressBound(xc->hier_file_len);
2107 mem = (unsigned char *)malloc(lz4_maxlen);
2108 errno = 0;
2109 if(xc->hier_file_len)
2110 {
2111 fstWriterMmapSanity(hmem = (unsigned char *)fstMmap(NULL, xc->hier_file_len, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->hier_handle), 0), __FILE__, __LINE__, "hmem");
2112 }
2113 packed_len = LZ4_compress((char *)hmem, (char *)mem, xc->hier_file_len);
2114 fstMunmap(hmem, xc->hier_file_len);
2115
2116 fourpack_duo = (!xc->repack_on_close) && (xc->hier_file_len > FST_HDR_FOURPACK_DUO_SIZE); /* double pack when hierarchy is large */
2117
2118 if(fourpack_duo) /* double packing with LZ4 is faster than gzip */
2119 {
2120 unsigned char *mem_duo;
2121 int lz4_maxlen_duo;
2122 int packed_len_duo;
2123
2124 lz4_maxlen_duo = LZ4_compressBound(packed_len);
2125 mem_duo = (unsigned char *)malloc(lz4_maxlen_duo);
2126 packed_len_duo = LZ4_compress((char *)mem, (char *)mem_duo, packed_len);
2127
2128 fstWriterVarint(xc->handle, packed_len); /* 1st round compressed length */
2129 fstFwrite(mem_duo, packed_len_duo, 1, xc->handle);
2130 free(mem_duo);
2131 }
2132 else
2133 {
2134 fstFwrite(mem, packed_len, 1, xc->handle);
2135 }
2136
2137 free(mem);
2138 }
2139
2140 fstWriterFseeko(xc, xc->handle, 0, SEEK_END);
2141 eos = ftello(xc->handle);
2142 fstWriterFseeko(xc, xc->handle, hlen, SEEK_SET);
2143 fstWriterUint64(xc->handle, eos - hlen);
2144 fflush(xc->handle);
2145
2146 fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET);
2147 fputc(xc->fourpack ?
2148 ( fourpack_duo ? FST_BL_HIER_LZ4DUO : FST_BL_HIER_LZ4) :
2149 FST_BL_HIER, xc->handle); /* actual tag now also == compression type */
2150
2151 fstWriterFseeko(xc, xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */
2152 fflush(xc->handle);
2153
2154 #ifndef __MINGW32__
2155 sprintf(fnam, "%s.hier", xc->filename);
2156 unlink(fnam);
2157 free(fnam);
2158 #endif
2159 }
2160
2161 /* finalize out header */
2162 fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_START_TIME, SEEK_SET);
2163 fstWriterUint64(xc->handle, xc->firsttime);
2164 fstWriterUint64(xc->handle, xc->curtime);
2165 fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_NUM_SCOPES, SEEK_SET);
2166 fstWriterUint64(xc->handle, xc->numscopes);
2167 fstWriterUint64(xc->handle, xc->numsigs);
2168 fstWriterUint64(xc->handle, xc->maxhandle);
2169 fstWriterUint64(xc->handle, xc->secnum);
2170 fflush(xc->handle);
2171
2172 tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam);
2173 free(xc->vchg_mem); xc->vchg_mem = NULL;
2174 tmpfile_close(&xc->curval_handle, &xc->curval_handle_nam);
2175 tmpfile_close(&xc->valpos_handle, &xc->valpos_handle_nam);
2176 tmpfile_close(&xc->geom_handle, &xc->geom_handle_nam);
2177 if(xc->hier_handle) { fclose(xc->hier_handle); xc->hier_handle = NULL; }
2178 if(xc->handle)
2179 {
2180 if(xc->repack_on_close)
2181 {
2182 FILE *fp;
2183 fst_off_t offpnt, uclen;
2184 int flen = strlen(xc->filename);
2185 char *hf = (char *)calloc(1, flen + 5);
2186
2187 strcpy(hf, xc->filename);
2188 strcpy(hf+flen, ".pak");
2189 fp = fopen(hf, "wb");
2190
2191 if(fp)
2192 {
2193 gzFile dsth;
2194 int zfd;
2195 char gz_membuf[FST_GZIO_LEN];
2196
2197 fstWriterFseeko(xc, xc->handle, 0, SEEK_END);
2198 uclen = ftello(xc->handle);
2199
2200 fputc(FST_BL_ZWRAPPER, fp);
2201 fstWriterUint64(fp, 0);
2202 fstWriterUint64(fp, uclen);
2203 fflush(fp);
2204
2205 fstWriterFseeko(xc, xc->handle, 0, SEEK_SET);
2206 zfd = dup(fileno(fp));
2207 dsth = gzdopen(zfd, "wb4");
2208 if(dsth)
2209 {
2210 for(offpnt = 0; offpnt < uclen; offpnt += FST_GZIO_LEN)
2211 {
2212 size_t this_len = ((uclen - offpnt) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - offpnt);
2213 fstFread(gz_membuf, this_len, 1, xc->handle);
2214 gzwrite(dsth, gz_membuf, this_len);
2215 }
2216 gzclose(dsth);
2217 }
2218 else
2219 {
2220 close(zfd);
2221 }
2222 fstWriterFseeko(xc, fp, 0, SEEK_END);
2223 offpnt = ftello(fp);
2224 fstWriterFseeko(xc, fp, 1, SEEK_SET);
2225 fstWriterUint64(fp, offpnt - 1);
2226 fclose(fp);
2227 fclose(xc->handle); xc->handle = NULL;
2228
2229 unlink(xc->filename);
2230 rename(hf, xc->filename);
2231 }
2232 else
2233 {
2234 xc->repack_on_close = 0;
2235 fclose(xc->handle); xc->handle = NULL;
2236 }
2237
2238 free(hf);
2239 }
2240 else
2241 {
2242 fclose(xc->handle); xc->handle = NULL;
2243 }
2244 }
2245
2246 #ifdef __MINGW32__
2247 {
2248 int flen = strlen(xc->filename);
2249 char *hf = (char *)calloc(1, flen + 6);
2250 strcpy(hf, xc->filename);
2251
2252 if(xc->compress_hier)
2253 {
2254 strcpy(hf + flen, ".hier");
2255 unlink(hf); /* no longer needed as a section now exists for this */
2256 }
2257
2258 free(hf);
2259 }
2260 #endif
2261
2262 #ifdef FST_WRITER_PARALLEL
2263 pthread_mutex_destroy(&xc->mutex);
2264 pthread_attr_destroy(&xc->thread_attr);
2265 #endif
2266
2267 if(xc->path_array)
2268 {
2269 #ifndef _WAVE_HAVE_JUDY
2270 const uint32_t hashmask = FST_PATH_HASHMASK;
2271 #endif
2272 JudyHSFreeArray(&(xc->path_array), NULL);
2273 }
2274
2275 free(xc->filename); xc->filename = NULL;
2276 free(xc);
2277 }
2278 }
2279
2280
2281 /*
2282 * functions to set miscellaneous header/block information
2283 */
fstWriterSetDate(void * ctx,const char * dat)2284 void fstWriterSetDate(void *ctx, const char *dat)
2285 {
2286 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2287 if(xc)
2288 {
2289 char s[FST_HDR_DATE_SIZE];
2290 fst_off_t fpos = ftello(xc->handle);
2291 int len = strlen(dat);
2292
2293 fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_DATE, SEEK_SET);
2294 memset(s, 0, FST_HDR_DATE_SIZE);
2295 memcpy(s, dat, (len < FST_HDR_DATE_SIZE) ? len : FST_HDR_DATE_SIZE);
2296 fstFwrite(s, FST_HDR_DATE_SIZE, 1, xc->handle);
2297 fflush(xc->handle);
2298 fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET);
2299 }
2300 }
2301
2302
fstWriterSetVersion(void * ctx,const char * vers)2303 void fstWriterSetVersion(void *ctx, const char *vers)
2304 {
2305 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2306 if(xc && vers)
2307 {
2308 char s[FST_HDR_SIM_VERSION_SIZE];
2309 fst_off_t fpos = ftello(xc->handle);
2310 int len = strlen(vers);
2311
2312 fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_SIM_VERSION, SEEK_SET);
2313 memset(s, 0, FST_HDR_SIM_VERSION_SIZE);
2314 memcpy(s, vers, (len < FST_HDR_SIM_VERSION_SIZE) ? len : FST_HDR_SIM_VERSION_SIZE);
2315 fstFwrite(s, FST_HDR_SIM_VERSION_SIZE, 1, xc->handle);
2316 fflush(xc->handle);
2317 fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET);
2318 }
2319 }
2320
2321
fstWriterSetFileType(void * ctx,enum fstFileType filetype)2322 void fstWriterSetFileType(void *ctx, enum fstFileType filetype)
2323 {
2324 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2325 if(xc)
2326 {
2327 if(/*(filetype >= FST_FT_MIN) &&*/ (filetype <= FST_FT_MAX))
2328 {
2329 fst_off_t fpos = ftello(xc->handle);
2330
2331 xc->filetype = filetype;
2332
2333 fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_FILETYPE, SEEK_SET);
2334 fputc(xc->filetype, xc->handle);
2335 fflush(xc->handle);
2336 fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET);
2337 }
2338 }
2339 }
2340
2341
fstWriterSetAttrDoubleArgGeneric(void * ctx,int typ,uint64_t arg1,uint64_t arg2)2342 static void fstWriterSetAttrDoubleArgGeneric(void *ctx, int typ, uint64_t arg1, uint64_t arg2)
2343 {
2344 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2345 if(xc)
2346 {
2347 unsigned char buf[11]; /* ceil(64/7) = 10 + null term */
2348 unsigned char *pnt = fstCopyVarint64ToRight(buf, arg1);
2349 if(arg1)
2350 {
2351 *pnt = 0; /* this converts any *nonzero* arg1 when made a varint into a null-term string */
2352 }
2353
2354 fstWriterSetAttrBegin(xc, FST_AT_MISC, typ, (char *)buf, arg2);
2355 }
2356 }
2357
2358
fstWriterSetAttrGeneric(void * ctx,const char * comm,int typ,uint64_t arg)2359 static void fstWriterSetAttrGeneric(void *ctx, const char *comm, int typ, uint64_t arg)
2360 {
2361 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2362 if(xc && comm)
2363 {
2364 char *s = strdup(comm);
2365 char *sf = s;
2366
2367 while(*s)
2368 {
2369 if((*s == '\n') || (*s == '\r')) *s = ' ';
2370 s++;
2371 }
2372
2373 fstWriterSetAttrBegin(xc, FST_AT_MISC, typ, sf, arg);
2374 free(sf);
2375 }
2376 }
2377
2378
fstWriterSetSourceStem_2(void * ctx,const char * path,unsigned int line,unsigned int use_realpath,int typ)2379 static void fstWriterSetSourceStem_2(void *ctx, const char *path, unsigned int line, unsigned int use_realpath, int typ)
2380 {
2381 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2382
2383 if(xc && path && path[0])
2384 {
2385 uint64_t sidx = 0;
2386 int slen = strlen(path);
2387 #ifndef _WAVE_HAVE_JUDY
2388 const uint32_t hashmask = FST_PATH_HASHMASK;
2389 const unsigned char *path2 = (const unsigned char *)path;
2390 PPvoid_t pv;
2391 #else
2392 char *path2 = (char *)alloca(slen + 1); /* judy lacks const qualifier in its JudyHSIns definition */
2393 PPvoid_t pv;
2394 strcpy(path2, path);
2395 #endif
2396
2397 pv = JudyHSIns(&(xc->path_array), path2, slen, NULL);
2398 if(*pv)
2399 {
2400 sidx = (intptr_t)(*pv);
2401 }
2402 else
2403 {
2404 char *rp = NULL;
2405
2406 sidx = ++xc->path_array_count;
2407 *pv = (void *)(intptr_t)(xc->path_array_count);
2408
2409 if(use_realpath)
2410 {
2411 rp = fstRealpath(
2412 #ifndef _WAVE_HAVE_JUDY
2413 (const char *)
2414 #endif
2415 path2, NULL);
2416 }
2417
2418 fstWriterSetAttrGeneric(xc, rp ? rp :
2419 #ifndef _WAVE_HAVE_JUDY
2420 (const char *)
2421 #endif
2422 path2, FST_MT_PATHNAME, sidx);
2423
2424 if(rp)
2425 {
2426 free(rp);
2427 }
2428 }
2429
2430 fstWriterSetAttrDoubleArgGeneric(xc, typ, sidx, line);
2431 }
2432 }
2433
2434
fstWriterSetSourceStem(void * ctx,const char * path,unsigned int line,unsigned int use_realpath)2435 void fstWriterSetSourceStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath)
2436 {
2437 fstWriterSetSourceStem_2(ctx, path, line, use_realpath, FST_MT_SOURCESTEM);
2438 }
2439
2440
fstWriterSetSourceInstantiationStem(void * ctx,const char * path,unsigned int line,unsigned int use_realpath)2441 void fstWriterSetSourceInstantiationStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath)
2442 {
2443 fstWriterSetSourceStem_2(ctx, path, line, use_realpath, FST_MT_SOURCEISTEM);
2444 }
2445
2446
fstWriterSetComment(void * ctx,const char * comm)2447 void fstWriterSetComment(void *ctx, const char *comm)
2448 {
2449 fstWriterSetAttrGeneric(ctx, comm, FST_MT_COMMENT, 0);
2450 }
2451
2452
fstWriterSetValueList(void * ctx,const char * vl)2453 void fstWriterSetValueList(void *ctx, const char *vl)
2454 {
2455 fstWriterSetAttrGeneric(ctx, vl, FST_MT_VALUELIST, 0);
2456 }
2457
2458
fstWriterSetEnvVar(void * ctx,const char * envvar)2459 void fstWriterSetEnvVar(void *ctx, const char *envvar)
2460 {
2461 fstWriterSetAttrGeneric(ctx, envvar, FST_MT_ENVVAR, 0);
2462 }
2463
2464
fstWriterSetTimescale(void * ctx,int ts)2465 void fstWriterSetTimescale(void *ctx, int ts)
2466 {
2467 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2468 if(xc)
2469 {
2470 fst_off_t fpos = ftello(xc->handle);
2471 fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_TIMESCALE, SEEK_SET);
2472 fputc(ts & 255, xc->handle);
2473 fflush(xc->handle);
2474 fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET);
2475 }
2476 }
2477
2478
fstWriterSetTimescaleFromString(void * ctx,const char * s)2479 void fstWriterSetTimescaleFromString(void *ctx, const char *s)
2480 {
2481 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2482 if(xc && s)
2483 {
2484 int mat = 0;
2485 int seconds_exp = -9;
2486 int tv = atoi(s);
2487 const char *pnt = s;
2488
2489 while(*pnt)
2490 {
2491 switch(*pnt)
2492 {
2493 case 'm': seconds_exp = -3; mat = 1; break;
2494 case 'u': seconds_exp = -6; mat = 1; break;
2495 case 'n': seconds_exp = -9; mat = 1; break;
2496 case 'p': seconds_exp = -12; mat = 1; break;
2497 case 'f': seconds_exp = -15; mat = 1; break;
2498 case 'a': seconds_exp = -18; mat = 1; break;
2499 case 'z': seconds_exp = -21; mat = 1; break;
2500 case 's': seconds_exp = 0; mat = 1; break;
2501 default: break;
2502 }
2503
2504 if(mat) break;
2505 pnt++;
2506 }
2507
2508 if(tv == 10)
2509 {
2510 seconds_exp++;
2511 }
2512 else
2513 if(tv == 100)
2514 {
2515 seconds_exp+=2;
2516 }
2517
2518 fstWriterSetTimescale(ctx, seconds_exp);
2519 }
2520 }
2521
2522
fstWriterSetTimezero(void * ctx,int64_t tim)2523 void fstWriterSetTimezero(void *ctx, int64_t tim)
2524 {
2525 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2526 if(xc)
2527 {
2528 fst_off_t fpos = ftello(xc->handle);
2529 fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_TIMEZERO, SEEK_SET);
2530 fstWriterUint64(xc->handle, (xc->timezero = tim));
2531 fflush(xc->handle);
2532 fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET);
2533 }
2534 }
2535
2536
fstWriterSetPackType(void * ctx,enum fstWriterPackType typ)2537 void fstWriterSetPackType(void *ctx, enum fstWriterPackType typ)
2538 {
2539 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2540 if(xc)
2541 {
2542 xc->fastpack = (typ != FST_WR_PT_ZLIB);
2543 xc->fourpack = (typ == FST_WR_PT_LZ4);
2544 }
2545 }
2546
2547
fstWriterSetRepackOnClose(void * ctx,int enable)2548 void fstWriterSetRepackOnClose(void *ctx, int enable)
2549 {
2550 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2551 if(xc)
2552 {
2553 xc->repack_on_close = (enable != 0);
2554 }
2555 }
2556
2557
fstWriterSetParallelMode(void * ctx,int enable)2558 void fstWriterSetParallelMode(void *ctx, int enable)
2559 {
2560 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2561 if(xc)
2562 {
2563 xc->parallel_was_enabled |= xc->parallel_enabled; /* make sticky */
2564 xc->parallel_enabled = (enable != 0);
2565 #ifndef FST_WRITER_PARALLEL
2566 if(xc->parallel_enabled)
2567 {
2568 fprintf(stderr, FST_APIMESS "fstWriterSetParallelMode(), FST_WRITER_PARALLEL not enabled during compile, exiting.\n");
2569 exit(255);
2570 }
2571 #endif
2572 }
2573 }
2574
2575
fstWriterSetDumpSizeLimit(void * ctx,uint64_t numbytes)2576 void fstWriterSetDumpSizeLimit(void *ctx, uint64_t numbytes)
2577 {
2578 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2579 if(xc)
2580 {
2581 xc->dump_size_limit = numbytes;
2582 }
2583 }
2584
2585
fstWriterGetDumpSizeLimitReached(void * ctx)2586 int fstWriterGetDumpSizeLimitReached(void *ctx)
2587 {
2588 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2589 if(xc)
2590 {
2591 return(xc->size_limit_locked != 0);
2592 }
2593
2594 return(0);
2595 }
2596
2597
fstWriterGetFseekFailed(void * ctx)2598 int fstWriterGetFseekFailed(void *ctx)
2599 {
2600 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2601 if(xc)
2602 {
2603 return(xc->fseek_failed != 0);
2604 }
2605
2606 return(0);
2607 }
2608
2609
2610 /*
2611 * writer attr/scope/var creation:
2612 * fstWriterCreateVar2() is used to dump VHDL or other languages, but the
2613 * underlying variable needs to map to Verilog/SV via the proper fstVarType vt
2614 */
fstWriterCreateVar2(void * ctx,enum fstVarType vt,enum fstVarDir vd,uint32_t len,const char * nam,fstHandle aliasHandle,const char * type,enum fstSupplementalVarType svt,enum fstSupplementalDataType sdt)2615 fstHandle fstWriterCreateVar2(void *ctx, enum fstVarType vt, enum fstVarDir vd,
2616 uint32_t len, const char *nam, fstHandle aliasHandle,
2617 const char *type, enum fstSupplementalVarType svt, enum fstSupplementalDataType sdt)
2618 {
2619 fstWriterSetAttrGeneric(ctx, type ? type : "", FST_MT_SUPVAR, (svt<<FST_SDT_SVT_SHIFT_COUNT) | (sdt & FST_SDT_ABS_MAX));
2620 return(fstWriterCreateVar(ctx, vt, vd, len, nam, aliasHandle));
2621 }
2622
2623
fstWriterCreateVar(void * ctx,enum fstVarType vt,enum fstVarDir vd,uint32_t len,const char * nam,fstHandle aliasHandle)2624 fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir vd,
2625 uint32_t len, const char *nam, fstHandle aliasHandle)
2626 {
2627 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2628 unsigned int i;
2629 int nlen, is_real;
2630
2631 if(xc && nam)
2632 {
2633 if(xc->valpos_mem)
2634 {
2635 fstDestroyMmaps(xc, 0);
2636 }
2637
2638 fputc(vt, xc->hier_handle);
2639 fputc(vd, xc->hier_handle);
2640 nlen = strlen(nam);
2641 fstFwrite(nam, nlen, 1, xc->hier_handle);
2642 fputc(0, xc->hier_handle);
2643 xc->hier_file_len += (nlen+3);
2644
2645 if((vt == FST_VT_VCD_REAL) || (vt == FST_VT_VCD_REAL_PARAMETER) || (vt == FST_VT_VCD_REALTIME) || (vt == FST_VT_SV_SHORTREAL))
2646 {
2647 is_real = 1;
2648 len = 8; /* recast number of bytes to that of what a double is */
2649 }
2650 else
2651 {
2652 is_real = 0;
2653 if(vt == FST_VT_GEN_STRING)
2654 {
2655 len = 0;
2656 }
2657 }
2658
2659 xc->hier_file_len += fstWriterVarint(xc->hier_handle, len);
2660
2661 if(aliasHandle > xc->maxhandle) aliasHandle = 0;
2662 xc->hier_file_len += fstWriterVarint(xc->hier_handle, aliasHandle);
2663 xc->numsigs++;
2664 if(xc->numsigs == xc->next_huge_break)
2665 {
2666 if(xc->fst_break_size < xc->fst_huge_break_size)
2667 {
2668 xc->next_huge_break += FST_ACTIVATE_HUGE_INC;
2669 xc->fst_break_size += xc->fst_orig_break_size;
2670 xc->fst_break_add_size += xc->fst_orig_break_add_size;
2671
2672 xc->vchg_alloc_siz = xc->fst_break_size + xc->fst_break_add_size;
2673 if(xc->vchg_mem)
2674 {
2675 xc->vchg_mem = (unsigned char *)realloc(xc->vchg_mem, xc->vchg_alloc_siz);
2676 }
2677 }
2678 }
2679
2680 if(!aliasHandle)
2681 {
2682 uint32_t zero = 0;
2683
2684 if(len)
2685 {
2686 fstWriterVarint(xc->geom_handle, !is_real ? len : 0); /* geom section encodes reals as zero byte */
2687 }
2688 else
2689 {
2690 fstWriterVarint(xc->geom_handle, 0xFFFFFFFF); /* geom section encodes zero len as 32b -1 */
2691 }
2692
2693 fstFwrite(&xc->maxvalpos, sizeof(uint32_t), 1, xc->valpos_handle);
2694 fstFwrite(&len, sizeof(uint32_t), 1, xc->valpos_handle);
2695 fstFwrite(&zero, sizeof(uint32_t), 1, xc->valpos_handle);
2696 fstFwrite(&zero, sizeof(uint32_t), 1, xc->valpos_handle);
2697
2698 if(!is_real)
2699 {
2700 for(i=0;i<len;i++)
2701 {
2702 fputc('x', xc->curval_handle);
2703 }
2704 }
2705 else
2706 {
2707 fstFwrite(&xc->nan, 8, 1, xc->curval_handle); /* initialize doubles to NaN rather than x */
2708 }
2709
2710 xc->maxvalpos+=len;
2711 xc->maxhandle++;
2712 return(xc->maxhandle);
2713 }
2714 else
2715 {
2716 return(aliasHandle);
2717 }
2718 }
2719
2720 return(0);
2721 }
2722
2723
fstWriterSetScope(void * ctx,enum fstScopeType scopetype,const char * scopename,const char * scopecomp)2724 void fstWriterSetScope(void *ctx, enum fstScopeType scopetype,
2725 const char *scopename, const char *scopecomp)
2726 {
2727 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2728
2729 if(xc)
2730 {
2731 fputc(FST_ST_VCD_SCOPE, xc->hier_handle);
2732 if(/*(scopetype < FST_ST_VCD_MODULE) ||*/ (scopetype > FST_ST_MAX)) { scopetype = FST_ST_VCD_MODULE; }
2733 fputc(scopetype, xc->hier_handle);
2734 fprintf(xc->hier_handle, "%s%c%s%c",
2735 scopename ? scopename : "", 0,
2736 scopecomp ? scopecomp : "", 0);
2737
2738 if(scopename)
2739 {
2740 xc->hier_file_len += strlen(scopename);
2741 }
2742 if(scopecomp)
2743 {
2744 xc->hier_file_len += strlen(scopecomp);
2745 }
2746
2747 xc->hier_file_len += 4; /* FST_ST_VCD_SCOPE + scopetype + two string terminating zeros */
2748 xc->numscopes++;
2749 }
2750 }
2751
2752
fstWriterSetUpscope(void * ctx)2753 void fstWriterSetUpscope(void *ctx)
2754 {
2755 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2756
2757 if(xc)
2758 {
2759 fputc(FST_ST_VCD_UPSCOPE, xc->hier_handle);
2760 xc->hier_file_len++;
2761 }
2762 }
2763
2764
fstWriterSetAttrBegin(void * ctx,enum fstAttrType attrtype,int subtype,const char * attrname,uint64_t arg)2765 void fstWriterSetAttrBegin(void *ctx, enum fstAttrType attrtype, int subtype,
2766 const char *attrname, uint64_t arg)
2767 {
2768 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2769
2770 if(xc)
2771 {
2772 fputc(FST_ST_GEN_ATTRBEGIN, xc->hier_handle);
2773 if(/*(attrtype < FST_AT_MISC) ||*/ (attrtype > FST_AT_MAX)) { attrtype = FST_AT_MISC; subtype = FST_MT_UNKNOWN; }
2774 fputc(attrtype, xc->hier_handle);
2775
2776 switch(attrtype)
2777 {
2778 case FST_AT_ARRAY: if((subtype < FST_AR_NONE) || (subtype > FST_AR_MAX)) subtype = FST_AR_NONE; break;
2779 case FST_AT_ENUM: if((subtype < FST_EV_SV_INTEGER) || (subtype > FST_EV_MAX)) subtype = FST_EV_SV_INTEGER; break;
2780 case FST_AT_PACK: if((subtype < FST_PT_NONE) || (subtype > FST_PT_MAX)) subtype = FST_PT_NONE; break;
2781
2782 case FST_AT_MISC:
2783 default: break;
2784 }
2785
2786 fputc(subtype, xc->hier_handle);
2787 fprintf(xc->hier_handle, "%s%c",
2788 attrname ? attrname : "", 0);
2789
2790 if(attrname)
2791 {
2792 xc->hier_file_len += strlen(attrname);
2793 }
2794
2795 xc->hier_file_len += 4; /* FST_ST_GEN_ATTRBEGIN + type + subtype + string terminating zero */
2796 xc->hier_file_len += fstWriterVarint(xc->hier_handle, arg);
2797 }
2798 }
2799
2800
fstWriterSetAttrEnd(void * ctx)2801 void fstWriterSetAttrEnd(void *ctx)
2802 {
2803 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2804
2805 if(xc)
2806 {
2807 fputc(FST_ST_GEN_ATTREND, xc->hier_handle);
2808 xc->hier_file_len++;
2809 }
2810 }
2811
2812
fstWriterCreateEnumTable(void * ctx,const char * name,uint32_t elem_count,unsigned int min_valbits,const char ** literal_arr,const char ** val_arr)2813 fstEnumHandle fstWriterCreateEnumTable(void *ctx, const char *name, uint32_t elem_count, unsigned int min_valbits, const char **literal_arr, const char **val_arr)
2814 {
2815 fstEnumHandle handle = 0;
2816 unsigned int *literal_lens = NULL;
2817 unsigned int *val_lens = NULL;
2818 int lit_len_tot = 0;
2819 int val_len_tot = 0;
2820 int name_len;
2821 char elem_count_buf[16];
2822 int elem_count_len;
2823 int total_len;
2824 int pos = 0;
2825 char *attr_str = NULL;
2826
2827 if(ctx && name && literal_arr && val_arr && (elem_count != 0))
2828 {
2829 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2830
2831 uint32_t i;
2832
2833 name_len = strlen(name);
2834 elem_count_len = sprintf(elem_count_buf, "%" PRIu32, elem_count);
2835
2836 literal_lens = (unsigned int *)calloc(elem_count, sizeof(unsigned int));
2837 val_lens = (unsigned int *)calloc(elem_count, sizeof(unsigned int));
2838
2839 for(i=0;i<elem_count;i++)
2840 {
2841 literal_lens[i] = strlen(literal_arr[i]);
2842 lit_len_tot += fstUtilityBinToEscConvertedLen((unsigned char*)literal_arr[i], literal_lens[i]);
2843
2844 val_lens[i] = strlen(val_arr[i]);
2845 val_len_tot += fstUtilityBinToEscConvertedLen((unsigned char*)val_arr[i], val_lens[i]);
2846
2847 if(min_valbits > 0)
2848 {
2849 if(val_lens[i] < min_valbits)
2850 {
2851 val_len_tot += (min_valbits - val_lens[i]); /* additional converted len is same for '0' character */
2852 }
2853 }
2854 }
2855
2856 total_len = name_len + 1 + elem_count_len + 1 + lit_len_tot + elem_count + val_len_tot + elem_count;
2857
2858 attr_str = (char*)malloc(total_len);
2859 pos = 0;
2860
2861 memcpy(attr_str+pos, name, name_len);
2862 pos += name_len;
2863 attr_str[pos++] = ' ';
2864
2865 memcpy(attr_str+pos, elem_count_buf, elem_count_len);
2866 pos += elem_count_len;
2867 attr_str[pos++] = ' ';
2868
2869 for(i=0;i<elem_count;i++)
2870 {
2871 pos += fstUtilityBinToEsc((unsigned char*)attr_str+pos, (unsigned char*)literal_arr[i], literal_lens[i]);
2872 attr_str[pos++] = ' ';
2873 }
2874
2875 for(i=0;i<elem_count;i++)
2876 {
2877 if(min_valbits > 0)
2878 {
2879 if(val_lens[i] < min_valbits)
2880 {
2881 memset(attr_str+pos, '0', min_valbits - val_lens[i]);
2882 pos += (min_valbits - val_lens[i]);
2883 }
2884 }
2885
2886 pos += fstUtilityBinToEsc((unsigned char*)attr_str+pos, (unsigned char*)val_arr[i], val_lens[i]);
2887 attr_str[pos++] = ' ';
2888 }
2889
2890 attr_str[pos-1] = 0;
2891
2892 #ifdef FST_DEBUG
2893 fprintf(stderr, FST_APIMESS "fstWriterCreateEnumTable() total_len: %d, pos: %d\n", total_len, pos);
2894 fprintf(stderr, FST_APIMESS "*%s*\n", attr_str);
2895 #endif
2896
2897 fstWriterSetAttrBegin(xc, FST_AT_MISC, FST_MT_ENUMTABLE, attr_str, handle = ++xc->max_enumhandle);
2898
2899 free(attr_str);
2900 free(val_lens);
2901 free(literal_lens);
2902 }
2903
2904 return(handle);
2905 }
2906
2907
fstWriterEmitEnumTableRef(void * ctx,fstEnumHandle handle)2908 void fstWriterEmitEnumTableRef(void *ctx, fstEnumHandle handle)
2909 {
2910 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2911 if(xc && handle)
2912 {
2913 fstWriterSetAttrBegin(xc, FST_AT_MISC, FST_MT_ENUMTABLE, NULL, handle);
2914 }
2915 }
2916
2917
2918 /*
2919 * value and time change emission
2920 */
fstWriterEmitValueChange(void * ctx,fstHandle handle,const void * val)2921 void fstWriterEmitValueChange(void *ctx, fstHandle handle, const void *val)
2922 {
2923 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2924 const unsigned char *buf = (const unsigned char *)val;
2925 uint32_t offs;
2926 int len;
2927
2928 if(FST_LIKELY((xc) && (handle <= xc->maxhandle)))
2929 {
2930 uint32_t fpos;
2931 uint32_t *vm4ip;
2932
2933 if(FST_UNLIKELY(!xc->valpos_mem))
2934 {
2935 xc->vc_emitted = 1;
2936 fstWriterCreateMmaps(xc);
2937 }
2938
2939 handle--; /* move starting at 1 index to starting at 0 */
2940 vm4ip = &(xc->valpos_mem[4*handle]);
2941
2942 len = vm4ip[1];
2943 if(FST_LIKELY(len)) /* len of zero = variable length, use fstWriterEmitVariableLengthValueChange */
2944 {
2945 if(FST_LIKELY(!xc->is_initial_time))
2946 {
2947 fpos = xc->vchg_siz;
2948
2949 if(FST_UNLIKELY((fpos + len + 10) > xc->vchg_alloc_siz))
2950 {
2951 xc->vchg_alloc_siz += (xc->fst_break_add_size + len); /* +len added in the case of extremely long vectors and small break add sizes */
2952 xc->vchg_mem = (unsigned char *)realloc(xc->vchg_mem, xc->vchg_alloc_siz);
2953 if(FST_UNLIKELY(!xc->vchg_mem))
2954 {
2955 fprintf(stderr, FST_APIMESS "Could not realloc() in fstWriterEmitValueChange, exiting.\n");
2956 exit(255);
2957 }
2958 }
2959 #ifdef FST_REMOVE_DUPLICATE_VC
2960 offs = vm4ip[0];
2961
2962 if(len != 1)
2963 {
2964 if((vm4ip[3]==xc->tchn_idx)&&(vm4ip[2]))
2965 {
2966 unsigned char *old_value = xc->vchg_mem + vm4ip[2] + 4; /* the +4 skips old vm4ip[2] value */
2967 while(*(old_value++) & 0x80) { /* skips over varint encoded "xc->tchn_idx - vm4ip[3]" */ }
2968 memcpy(old_value, buf, len); /* overlay new value */
2969
2970 memcpy(xc->curval_mem + offs, buf, len);
2971 return;
2972 }
2973 else
2974 {
2975 if(!memcmp(xc->curval_mem + offs, buf, len))
2976 {
2977 if(!xc->curtime)
2978 {
2979 int i;
2980 for(i=0;i<len;i++)
2981 {
2982 if(buf[i]!='x') break;
2983 }
2984
2985 if(i<len) return;
2986 }
2987 else
2988 {
2989 return;
2990 }
2991 }
2992 }
2993
2994 memcpy(xc->curval_mem + offs, buf, len);
2995 }
2996 else
2997 {
2998 if((vm4ip[3]==xc->tchn_idx)&&(vm4ip[2]))
2999 {
3000 unsigned char *old_value = xc->vchg_mem + vm4ip[2] + 4; /* the +4 skips old vm4ip[2] value */
3001 while(*(old_value++) & 0x80) { /* skips over varint encoded "xc->tchn_idx - vm4ip[3]" */ }
3002 *old_value = *buf; /* overlay new value */
3003
3004 *(xc->curval_mem + offs) = *buf;
3005 return;
3006 }
3007 else
3008 {
3009 if((*(xc->curval_mem + offs)) == (*buf))
3010 {
3011 if(!xc->curtime)
3012 {
3013 if(*buf != 'x') return;
3014 }
3015 else
3016 {
3017 return;
3018 }
3019 }
3020 }
3021
3022 *(xc->curval_mem + offs) = *buf;
3023 }
3024 #endif
3025 xc->vchg_siz += fstWriterUint32WithVarint32(xc, &vm4ip[2], xc->tchn_idx - vm4ip[3], buf, len); /* do one fwrite op only */
3026 vm4ip[3] = xc->tchn_idx;
3027 vm4ip[2] = fpos;
3028 }
3029 else
3030 {
3031 offs = vm4ip[0];
3032 memcpy(xc->curval_mem + offs, buf, len);
3033 }
3034 }
3035 }
3036 }
3037
fstWriterEmitValueChange32(void * ctx,fstHandle handle,uint32_t bits,uint32_t val)3038 void fstWriterEmitValueChange32(void *ctx, fstHandle handle,
3039 uint32_t bits, uint32_t val) {
3040 char buf[32];
3041 char *s = buf;
3042 uint32_t i;
3043 for (i = 0; i < bits; ++i)
3044 {
3045 *s++ = '0' + ((val >> (bits - i - 1)) & 1);
3046 }
3047 fstWriterEmitValueChange(ctx, handle, buf);
3048 }
fstWriterEmitValueChange64(void * ctx,fstHandle handle,uint32_t bits,uint64_t val)3049 void fstWriterEmitValueChange64(void *ctx, fstHandle handle,
3050 uint32_t bits, uint64_t val) {
3051 char buf[64];
3052 char *s = buf;
3053 uint32_t i;
3054 for (i = 0; i < bits; ++i)
3055 {
3056 *s++ = '0' + ((val >> (bits - i - 1)) & 1);
3057 }
3058 fstWriterEmitValueChange(ctx, handle, buf);
3059 }
fstWriterEmitValueChangeVec32(void * ctx,fstHandle handle,uint32_t bits,const uint32_t * val)3060 void fstWriterEmitValueChangeVec32(void *ctx, fstHandle handle,
3061 uint32_t bits, const uint32_t *val) {
3062 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
3063 if (FST_UNLIKELY(bits <= 32))
3064 {
3065 fstWriterEmitValueChange32(ctx, handle, bits, val[0]);
3066 }
3067 else if(FST_LIKELY(xc))
3068 {
3069 int bq = bits / 32;
3070 int br = bits & 31;
3071 int i;
3072 int w;
3073 uint32_t v;
3074 unsigned char* s;
3075 if (FST_UNLIKELY(bits > xc->outval_alloc_siz))
3076 {
3077 xc->outval_alloc_siz = bits*2 + 1;
3078 xc->outval_mem = (unsigned char*)realloc(xc->outval_mem, xc->outval_alloc_siz);
3079 if (FST_UNLIKELY(!xc->outval_mem))
3080 {
3081 fprintf(stderr,
3082 FST_APIMESS "Could not realloc() in fstWriterEmitValueChangeVec32, exiting.\n");
3083 exit(255);
3084 }
3085 }
3086 s = xc->outval_mem;
3087 {
3088 w = bq;
3089 v = val[w];
3090 for (i = 0; i < br; ++i)
3091 {
3092 *s++ = '0' + ((v >> (br - i - 1)) & 1);
3093 }
3094 }
3095 for (w = bq - 1; w >= 0; --w)
3096 {
3097 v = val[w];
3098 for (i = (32 - 4); i >= 0; i -= 4) {
3099 s[0] = '0' + ((v >> (i + 3)) & 1);
3100 s[1] = '0' + ((v >> (i + 2)) & 1);
3101 s[2] = '0' + ((v >> (i + 1)) & 1);
3102 s[3] = '0' + ((v >> (i + 0)) & 1);
3103 s += 4;
3104 }
3105 }
3106 fstWriterEmitValueChange(ctx, handle, xc->outval_mem);
3107 }
3108 }
fstWriterEmitValueChangeVec64(void * ctx,fstHandle handle,uint32_t bits,const uint64_t * val)3109 void fstWriterEmitValueChangeVec64(void *ctx, fstHandle handle,
3110 uint32_t bits, const uint64_t *val) {
3111 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
3112 if (FST_UNLIKELY(bits <= 64))
3113 {
3114 fstWriterEmitValueChange64(ctx, handle, bits, val[0]);
3115 }
3116 else if(FST_LIKELY(xc))
3117 {
3118 int bq = bits / 64;
3119 int br = bits & 63;
3120 int i;
3121 int w;
3122 uint32_t v;
3123 unsigned char* s;
3124 if (FST_UNLIKELY(bits > xc->outval_alloc_siz))
3125 {
3126 xc->outval_alloc_siz = bits*2 + 1;
3127 xc->outval_mem = (unsigned char*)realloc(xc->outval_mem, xc->outval_alloc_siz);
3128 if (FST_UNLIKELY(!xc->outval_mem))
3129 {
3130 fprintf(stderr,
3131 FST_APIMESS "Could not realloc() in fstWriterEmitValueChangeVec64, exiting.\n");
3132 exit(255);
3133 }
3134 }
3135 s = xc->outval_mem;
3136 {
3137 w = bq;
3138 v = val[w];
3139 for (i = 0; i < br; ++i)
3140 {
3141 *s++ = '0' + ((v >> (br - i - 1)) & 1);
3142 }
3143 }
3144 for (w = bq - 1; w >= 0; --w) {
3145 v = val[w];
3146 for (i = (64 - 4); i >= 0; i -= 4)
3147 {
3148 s[0] = '0' + ((v >> (i + 3)) & 1);
3149 s[1] = '0' + ((v >> (i + 2)) & 1);
3150 s[2] = '0' + ((v >> (i + 1)) & 1);
3151 s[3] = '0' + ((v >> (i + 0)) & 1);
3152 s += 4;
3153 }
3154 }
3155 fstWriterEmitValueChange(ctx, handle, xc->outval_mem);
3156 }
3157 }
3158
3159
fstWriterEmitVariableLengthValueChange(void * ctx,fstHandle handle,const void * val,uint32_t len)3160 void fstWriterEmitVariableLengthValueChange(void *ctx, fstHandle handle, const void *val, uint32_t len)
3161 {
3162 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
3163 const unsigned char *buf = (const unsigned char *)val;
3164
3165 if(FST_LIKELY((xc) && (handle <= xc->maxhandle)))
3166 {
3167 uint32_t fpos;
3168 uint32_t *vm4ip;
3169
3170 if(FST_UNLIKELY(!xc->valpos_mem))
3171 {
3172 xc->vc_emitted = 1;
3173 fstWriterCreateMmaps(xc);
3174 }
3175
3176 handle--; /* move starting at 1 index to starting at 0 */
3177 vm4ip = &(xc->valpos_mem[4*handle]);
3178
3179 /* there is no initial time dump for variable length value changes */
3180 if(FST_LIKELY(!vm4ip[1])) /* len of zero = variable length */
3181 {
3182 fpos = xc->vchg_siz;
3183
3184 if(FST_UNLIKELY((fpos + len + 10 + 5) > xc->vchg_alloc_siz))
3185 {
3186 xc->vchg_alloc_siz += (xc->fst_break_add_size + len + 5); /* +len added in the case of extremely long vectors and small break add sizes */
3187 xc->vchg_mem = (unsigned char *)realloc(xc->vchg_mem, xc->vchg_alloc_siz);
3188 if(FST_UNLIKELY(!xc->vchg_mem))
3189 {
3190 fprintf(stderr, FST_APIMESS "Could not realloc() in fstWriterEmitVariableLengthValueChange, exiting.\n");
3191 exit(255);
3192 }
3193 }
3194
3195 xc->vchg_siz += fstWriterUint32WithVarint32AndLength(xc, &vm4ip[2], xc->tchn_idx - vm4ip[3], buf, len); /* do one fwrite op only */
3196 vm4ip[3] = xc->tchn_idx;
3197 vm4ip[2] = fpos;
3198 }
3199 }
3200 }
3201
3202
fstWriterEmitTimeChange(void * ctx,uint64_t tim)3203 void fstWriterEmitTimeChange(void *ctx, uint64_t tim)
3204 {
3205 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
3206 unsigned int i;
3207 int skip = 0;
3208 if(xc)
3209 {
3210 if(FST_UNLIKELY(xc->is_initial_time))
3211 {
3212 if(xc->size_limit_locked) /* this resets xc->is_initial_time to one */
3213 {
3214 return;
3215 }
3216
3217 if(!xc->valpos_mem)
3218 {
3219 fstWriterCreateMmaps(xc);
3220 }
3221
3222 skip = 1;
3223
3224 xc->firsttime = (xc->vc_emitted) ? 0: tim;
3225 xc->curtime = 0;
3226 xc->vchg_mem[0] = '!';
3227 xc->vchg_siz = 1;
3228 fstWriterEmitSectionHeader(xc);
3229 for(i=0;i<xc->maxhandle;i++)
3230 {
3231 xc->valpos_mem[4*i+2] = 0; /* zero out offset val */
3232 xc->valpos_mem[4*i+3] = 0; /* zero out last time change val */
3233 }
3234 xc->is_initial_time = 0;
3235 }
3236 else
3237 {
3238 if((xc->vchg_siz >= xc->fst_break_size) || (xc->flush_context_pending))
3239 {
3240 xc->flush_context_pending = 0;
3241 fstWriterFlushContextPrivate(xc);
3242 xc->tchn_cnt++;
3243 fstWriterVarint(xc->tchn_handle, xc->curtime);
3244 }
3245 }
3246
3247 if(!skip)
3248 {
3249 xc->tchn_idx++;
3250 }
3251 fstWriterVarint(xc->tchn_handle, tim - xc->curtime);
3252 xc->tchn_cnt++;
3253 xc->curtime = tim;
3254 }
3255 }
3256
3257
fstWriterEmitDumpActive(void * ctx,int enable)3258 void fstWriterEmitDumpActive(void *ctx, int enable)
3259 {
3260 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
3261
3262 if(xc)
3263 {
3264 struct fstBlackoutChain *b = (struct fstBlackoutChain *)calloc(1, sizeof(struct fstBlackoutChain));
3265
3266 b->tim = xc->curtime;
3267 b->active = (enable != 0);
3268
3269 xc->num_blackouts++;
3270 if(xc->blackout_curr)
3271 {
3272 xc->blackout_curr->next = b;
3273 xc->blackout_curr = b;
3274 }
3275 else
3276 {
3277 xc->blackout_head = b;
3278 xc->blackout_curr = b;
3279 }
3280 }
3281 }
3282
3283
3284 /***********************/
3285 /*** ***/
3286 /*** reader function ***/
3287 /*** ***/
3288 /***********************/
3289
3290 /*
3291 * private structs
3292 */
3293 static const char *vartypes[] = {
3294 "event", "integer", "parameter", "real", "real_parameter",
3295 "reg", "supply0", "supply1", "time", "tri",
3296 "triand", "trior", "trireg", "tri0", "tri1",
3297 "wand", "wire", "wor", "port", "sparray", "realtime",
3298 "string",
3299 "bit", "logic", "int", "shortint", "longint", "byte", "enum", "shortreal"
3300 };
3301
3302 static const char *modtypes[] = {
3303 "module", "task", "function", "begin", "fork", "generate", "struct", "union", "class", "interface", "package", "program",
3304 "vhdl_architecture", "vhdl_procedure", "vhdl_function", "vhdl_record", "vhdl_process", "vhdl_block", "vhdl_for_generate", "vhdl_if_generate", "vhdl_generate", "vhdl_package"
3305 };
3306
3307 static const char *attrtypes[] = {
3308 "misc", "array", "enum", "class"
3309 };
3310
3311 static const char *arraytypes[] = {
3312 "none", "unpacked", "packed", "sparse"
3313 };
3314
3315 static const char *enumvaluetypes[] = {
3316 "integer", "bit", "logic", "int", "shortint", "longint", "byte",
3317 "unsigned_integer", "unsigned_bit", "unsigned_logic", "unsigned_int", "unsigned_shortint", "unsigned_longint", "unsigned_byte"
3318 };
3319
3320 static const char *packtypes[] = {
3321 "none", "unpacked", "packed", "tagged_packed"
3322 };
3323
3324
3325 struct fstCurrHier
3326 {
3327 struct fstCurrHier *prev;
3328 void *user_info;
3329 int len;
3330 };
3331
3332
3333 struct fstReaderContext
3334 {
3335 /* common entries */
3336
3337 FILE *f, *fh;
3338
3339 uint64_t start_time, end_time;
3340 uint64_t mem_used_by_writer;
3341 uint64_t scope_count;
3342 uint64_t var_count;
3343 fstHandle maxhandle;
3344 uint64_t num_alias;
3345 uint64_t vc_section_count;
3346
3347 uint32_t *signal_lens; /* maxhandle sized */
3348 unsigned char *signal_typs; /* maxhandle sized */
3349 unsigned char *process_mask; /* maxhandle-based, bitwise sized */
3350 uint32_t longest_signal_value_len; /* longest len value encountered */
3351 unsigned char *temp_signal_value_buf; /* malloced for len in longest_signal_value_len */
3352
3353 signed char timescale;
3354 unsigned char filetype;
3355
3356 unsigned use_vcd_extensions : 1;
3357 unsigned double_endian_match : 1;
3358 unsigned native_doubles_for_cb : 1;
3359 unsigned contains_geom_section : 1;
3360 unsigned contains_hier_section : 1; /* valid for hier_pos */
3361 unsigned contains_hier_section_lz4duo : 1; /* valid for hier_pos (contains_hier_section_lz4 always also set) */
3362 unsigned contains_hier_section_lz4 : 1; /* valid for hier_pos */
3363 unsigned limit_range_valid : 1; /* valid for limit_range_start, limit_range_end */
3364
3365 char version[FST_HDR_SIM_VERSION_SIZE + 1];
3366 char date[FST_HDR_DATE_SIZE + 1];
3367 int64_t timezero;
3368
3369 char *filename, *filename_unpacked;
3370 fst_off_t hier_pos;
3371
3372 uint32_t num_blackouts;
3373 uint64_t *blackout_times;
3374 unsigned char *blackout_activity;
3375
3376 uint64_t limit_range_start, limit_range_end;
3377
3378 /* entries specific to read value at time functions */
3379
3380 unsigned rvat_data_valid : 1;
3381 uint64_t *rvat_time_table;
3382 uint64_t rvat_beg_tim, rvat_end_tim;
3383 unsigned char *rvat_frame_data;
3384 uint64_t rvat_frame_maxhandle;
3385 fst_off_t *rvat_chain_table;
3386 uint32_t *rvat_chain_table_lengths;
3387 uint64_t rvat_vc_maxhandle;
3388 fst_off_t rvat_vc_start;
3389 uint32_t *rvat_sig_offs;
3390 int rvat_packtype;
3391
3392 uint32_t rvat_chain_len;
3393 unsigned char *rvat_chain_mem;
3394 fstHandle rvat_chain_facidx;
3395
3396 uint32_t rvat_chain_pos_tidx;
3397 uint32_t rvat_chain_pos_idx;
3398 uint64_t rvat_chain_pos_time;
3399 unsigned rvat_chain_pos_valid : 1;
3400
3401 /* entries specific to hierarchy traversal */
3402
3403 struct fstHier hier;
3404 struct fstCurrHier *curr_hier;
3405 fstHandle current_handle;
3406 char *curr_flat_hier_nam;
3407 int flat_hier_alloc_len;
3408 unsigned do_rewind : 1;
3409 char str_scope_nam[FST_ID_NAM_SIZ+1];
3410 char str_scope_comp[FST_ID_NAM_SIZ+1];
3411
3412 unsigned fseek_failed : 1;
3413
3414 /* self-buffered I/O for writes */
3415
3416 #ifndef FST_WRITEX_DISABLE
3417 int writex_pos;
3418 int writex_fd;
3419 unsigned char writex_buf[FST_WRITEX_MAX];
3420 #endif
3421
3422 char *f_nam;
3423 char *fh_nam;
3424 };
3425
3426
fstReaderFseeko(struct fstReaderContext * xc,FILE * stream,fst_off_t offset,int whence)3427 int fstReaderFseeko(struct fstReaderContext *xc, FILE *stream, fst_off_t offset, int whence)
3428 {
3429 int rc = fseeko(stream, offset, whence);
3430
3431 if(rc<0)
3432 {
3433 xc->fseek_failed = 1;
3434 #ifdef FST_DEBUG
3435 fprintf(stderr, FST_APIMESS "Seek to #%" PRId64 " (whence = %d) failed!\n", offset, whence);
3436 perror("Why");
3437 #endif
3438 }
3439
3440 return(rc);
3441 }
3442
3443
3444 #ifndef FST_WRITEX_DISABLE
fstWritex(struct fstReaderContext * xc,void * v,int len)3445 static void fstWritex(struct fstReaderContext *xc, void *v, int len)
3446 {
3447 unsigned char *s = (unsigned char *)v;
3448
3449 if(len)
3450 {
3451 if(len < FST_WRITEX_MAX)
3452 {
3453 if(xc->writex_pos + len >= FST_WRITEX_MAX)
3454 {
3455 fstWritex(xc, NULL, 0);
3456 }
3457
3458 memcpy(xc->writex_buf + xc->writex_pos, s, len);
3459 xc->writex_pos += len;
3460 }
3461 else
3462 {
3463 fstWritex(xc, NULL, 0);
3464 if (write(xc->writex_fd, s, len)) { };
3465 }
3466 }
3467 else
3468 {
3469 if(xc->writex_pos)
3470 {
3471 if(write(xc->writex_fd, xc->writex_buf, xc->writex_pos)) { };
3472 xc->writex_pos = 0;
3473 }
3474 }
3475 }
3476 #endif
3477
3478
3479 /*
3480 * scope -> flat name handling
3481 */
fstReaderDeallocateScopeData(struct fstReaderContext * xc)3482 static void fstReaderDeallocateScopeData(struct fstReaderContext *xc)
3483 {
3484 struct fstCurrHier *chp;
3485
3486 free(xc->curr_flat_hier_nam); xc->curr_flat_hier_nam = NULL;
3487 while(xc->curr_hier)
3488 {
3489 chp = xc->curr_hier->prev;
3490 free(xc->curr_hier);
3491 xc->curr_hier = chp;
3492 }
3493 }
3494
3495
fstReaderGetCurrentFlatScope(void * ctx)3496 const char *fstReaderGetCurrentFlatScope(void *ctx)
3497 {
3498 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3499 if(xc)
3500 {
3501 return(xc->curr_flat_hier_nam ? xc->curr_flat_hier_nam : "");
3502 }
3503 else
3504 {
3505 return(NULL);
3506 }
3507 }
3508
3509
fstReaderGetCurrentScopeUserInfo(void * ctx)3510 void *fstReaderGetCurrentScopeUserInfo(void *ctx)
3511 {
3512 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3513 if(xc)
3514 {
3515 return(xc->curr_hier ? xc->curr_hier->user_info : NULL);
3516 }
3517 else
3518 {
3519 return(NULL);
3520 }
3521 }
3522
3523
fstReaderPopScope(void * ctx)3524 const char *fstReaderPopScope(void *ctx)
3525 {
3526 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3527 if(xc && xc->curr_hier)
3528 {
3529 struct fstCurrHier *ch = xc->curr_hier;
3530 if(xc->curr_hier->prev)
3531 {
3532 xc->curr_flat_hier_nam[xc->curr_hier->prev->len] = 0;
3533 }
3534 else
3535 {
3536 *xc->curr_flat_hier_nam = 0;
3537 }
3538 xc->curr_hier = xc->curr_hier->prev;
3539 free(ch);
3540 return(xc->curr_flat_hier_nam ? xc->curr_flat_hier_nam : "");
3541 }
3542
3543 return(NULL);
3544 }
3545
3546
fstReaderResetScope(void * ctx)3547 void fstReaderResetScope(void *ctx)
3548 {
3549 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3550
3551 if(xc)
3552 {
3553 while(fstReaderPopScope(xc)); /* remove any already-built scoping info */
3554 }
3555 }
3556
3557
fstReaderPushScope(void * ctx,const char * nam,void * user_info)3558 const char *fstReaderPushScope(void *ctx, const char *nam, void *user_info)
3559 {
3560 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3561 if(xc)
3562 {
3563 struct fstCurrHier *ch = (struct fstCurrHier *)malloc(sizeof(struct fstCurrHier));
3564 int chl = xc->curr_hier ? xc->curr_hier->len : 0;
3565 int len = chl + 1 + strlen(nam);
3566 if(len >= xc->flat_hier_alloc_len)
3567 {
3568 xc->curr_flat_hier_nam = xc->curr_flat_hier_nam ? (char *)realloc(xc->curr_flat_hier_nam, len+1) : (char *)malloc(len+1);
3569 }
3570
3571 if(chl)
3572 {
3573 xc->curr_flat_hier_nam[chl] = '.';
3574 strcpy(xc->curr_flat_hier_nam + chl + 1, nam);
3575 }
3576 else
3577 {
3578 strcpy(xc->curr_flat_hier_nam, nam);
3579 len--;
3580 }
3581
3582 ch->len = len;
3583 ch->prev = xc->curr_hier;
3584 ch->user_info = user_info;
3585 xc->curr_hier = ch;
3586 return(xc->curr_flat_hier_nam);
3587 }
3588
3589 return(NULL);
3590 }
3591
3592
fstReaderGetCurrentScopeLen(void * ctx)3593 int fstReaderGetCurrentScopeLen(void *ctx)
3594 {
3595 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3596
3597 if(xc && xc->curr_hier)
3598 {
3599 return(xc->curr_hier->len);
3600 }
3601
3602 return(0);
3603 }
3604
3605
fstReaderGetFseekFailed(void * ctx)3606 int fstReaderGetFseekFailed(void *ctx)
3607 {
3608 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3609 if(xc)
3610 {
3611 return(xc->fseek_failed != 0);
3612 }
3613
3614 return(0);
3615 }
3616
3617
3618 /*
3619 * iter mask manipulation util functions
3620 */
fstReaderGetFacProcessMask(void * ctx,fstHandle facidx)3621 int fstReaderGetFacProcessMask(void *ctx, fstHandle facidx)
3622 {
3623 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3624
3625 if(xc)
3626 {
3627 facidx--;
3628 if(facidx<xc->maxhandle)
3629 {
3630 int process_idx = facidx/8;
3631 int process_bit = facidx&7;
3632
3633 return( (xc->process_mask[process_idx]&(1<<process_bit)) != 0 );
3634 }
3635 }
3636 return(0);
3637 }
3638
3639
fstReaderSetFacProcessMask(void * ctx,fstHandle facidx)3640 void fstReaderSetFacProcessMask(void *ctx, fstHandle facidx)
3641 {
3642 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3643
3644 if(xc)
3645 {
3646 facidx--;
3647 if(facidx<xc->maxhandle)
3648 {
3649 int idx = facidx/8;
3650 int bitpos = facidx&7;
3651
3652 xc->process_mask[idx] |= (1<<bitpos);
3653 }
3654 }
3655 }
3656
3657
fstReaderClrFacProcessMask(void * ctx,fstHandle facidx)3658 void fstReaderClrFacProcessMask(void *ctx, fstHandle facidx)
3659 {
3660 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3661
3662 if(xc)
3663 {
3664 facidx--;
3665 if(facidx<xc->maxhandle)
3666 {
3667 int idx = facidx/8;
3668 int bitpos = facidx&7;
3669
3670 xc->process_mask[idx] &= (~(1<<bitpos));
3671 }
3672 }
3673 }
3674
3675
fstReaderSetFacProcessMaskAll(void * ctx)3676 void fstReaderSetFacProcessMaskAll(void *ctx)
3677 {
3678 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3679
3680 if(xc)
3681 {
3682 memset(xc->process_mask, 0xff, (xc->maxhandle+7)/8);
3683 }
3684 }
3685
3686
fstReaderClrFacProcessMaskAll(void * ctx)3687 void fstReaderClrFacProcessMaskAll(void *ctx)
3688 {
3689 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3690
3691 if(xc)
3692 {
3693 memset(xc->process_mask, 0x00, (xc->maxhandle+7)/8);
3694 }
3695 }
3696
3697
3698 /*
3699 * various utility read/write functions
3700 */
fstReaderGetTimescale(void * ctx)3701 signed char fstReaderGetTimescale(void *ctx)
3702 {
3703 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3704 return(xc ? xc->timescale : 0);
3705 }
3706
3707
fstReaderGetStartTime(void * ctx)3708 uint64_t fstReaderGetStartTime(void *ctx)
3709 {
3710 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3711 return(xc ? xc->start_time : 0);
3712 }
3713
3714
fstReaderGetEndTime(void * ctx)3715 uint64_t fstReaderGetEndTime(void *ctx)
3716 {
3717 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3718 return(xc ? xc->end_time : 0);
3719 }
3720
3721
fstReaderGetMemoryUsedByWriter(void * ctx)3722 uint64_t fstReaderGetMemoryUsedByWriter(void *ctx)
3723 {
3724 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3725 return(xc ? xc->mem_used_by_writer : 0);
3726 }
3727
3728
fstReaderGetScopeCount(void * ctx)3729 uint64_t fstReaderGetScopeCount(void *ctx)
3730 {
3731 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3732 return(xc ? xc->scope_count : 0);
3733 }
3734
3735
fstReaderGetVarCount(void * ctx)3736 uint64_t fstReaderGetVarCount(void *ctx)
3737 {
3738 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3739 return(xc ? xc->var_count : 0);
3740 }
3741
3742
fstReaderGetMaxHandle(void * ctx)3743 fstHandle fstReaderGetMaxHandle(void *ctx)
3744 {
3745 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3746 return(xc ? xc->maxhandle : 0);
3747 }
3748
3749
fstReaderGetAliasCount(void * ctx)3750 uint64_t fstReaderGetAliasCount(void *ctx)
3751 {
3752 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3753 return(xc ? xc->num_alias : 0);
3754 }
3755
3756
fstReaderGetValueChangeSectionCount(void * ctx)3757 uint64_t fstReaderGetValueChangeSectionCount(void *ctx)
3758 {
3759 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3760 return(xc ? xc->vc_section_count : 0);
3761 }
3762
3763
fstReaderGetDoubleEndianMatchState(void * ctx)3764 int fstReaderGetDoubleEndianMatchState(void *ctx)
3765 {
3766 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3767 return(xc ? xc->double_endian_match : 0);
3768 }
3769
3770
fstReaderGetVersionString(void * ctx)3771 const char *fstReaderGetVersionString(void *ctx)
3772 {
3773 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3774 return(xc ? xc->version : NULL);
3775 }
3776
3777
fstReaderGetDateString(void * ctx)3778 const char *fstReaderGetDateString(void *ctx)
3779 {
3780 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3781 return(xc ? xc->date : NULL);
3782 }
3783
3784
fstReaderGetFileType(void * ctx)3785 int fstReaderGetFileType(void *ctx)
3786 {
3787 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3788 return(xc ? (int)xc->filetype : (int)FST_FT_VERILOG);
3789 }
3790
3791
fstReaderGetTimezero(void * ctx)3792 int64_t fstReaderGetTimezero(void *ctx)
3793 {
3794 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3795 return(xc ? xc->timezero : 0);
3796 }
3797
3798
fstReaderGetNumberDumpActivityChanges(void * ctx)3799 uint32_t fstReaderGetNumberDumpActivityChanges(void *ctx)
3800 {
3801 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3802 return(xc ? xc->num_blackouts : 0);
3803 }
3804
3805
fstReaderGetDumpActivityChangeTime(void * ctx,uint32_t idx)3806 uint64_t fstReaderGetDumpActivityChangeTime(void *ctx, uint32_t idx)
3807 {
3808 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3809
3810 if(xc && (idx < xc->num_blackouts) && (xc->blackout_times))
3811 {
3812 return(xc->blackout_times[idx]);
3813 }
3814 else
3815 {
3816 return(0);
3817 }
3818 }
3819
3820
fstReaderGetDumpActivityChangeValue(void * ctx,uint32_t idx)3821 unsigned char fstReaderGetDumpActivityChangeValue(void *ctx, uint32_t idx)
3822 {
3823 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3824
3825 if(xc && (idx < xc->num_blackouts) && (xc->blackout_activity))
3826 {
3827 return(xc->blackout_activity[idx]);
3828 }
3829 else
3830 {
3831 return(0);
3832 }
3833 }
3834
3835
fstReaderSetLimitTimeRange(void * ctx,uint64_t start_time,uint64_t end_time)3836 void fstReaderSetLimitTimeRange(void *ctx, uint64_t start_time, uint64_t end_time)
3837 {
3838 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3839
3840 if(xc)
3841 {
3842 xc->limit_range_valid = 1;
3843 xc->limit_range_start = start_time;
3844 xc->limit_range_end = end_time;
3845 }
3846 }
3847
3848
fstReaderSetUnlimitedTimeRange(void * ctx)3849 void fstReaderSetUnlimitedTimeRange(void *ctx)
3850 {
3851 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3852
3853 if(xc)
3854 {
3855 xc->limit_range_valid = 0;
3856 }
3857 }
3858
3859
fstReaderSetVcdExtensions(void * ctx,int enable)3860 void fstReaderSetVcdExtensions(void *ctx, int enable)
3861 {
3862 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3863
3864 if(xc)
3865 {
3866 xc->use_vcd_extensions = (enable != 0);
3867 }
3868 }
3869
3870
fstReaderIterBlocksSetNativeDoublesOnCallback(void * ctx,int enable)3871 void fstReaderIterBlocksSetNativeDoublesOnCallback(void *ctx, int enable)
3872 {
3873 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3874 if(xc)
3875 {
3876 xc->native_doubles_for_cb = (enable != 0);
3877 }
3878 }
3879
3880 /*
3881 * hierarchy processing
3882 */
fstVcdID(char * buf,unsigned int value)3883 static void fstVcdID(char *buf, unsigned int value)
3884 {
3885 char *pnt = buf;
3886
3887 /* zero is illegal for a value...it is assumed they start at one */
3888 while (value)
3889 {
3890 value--;
3891 *(pnt++) = (char)('!' + value % 94);
3892 value = value / 94;
3893 }
3894
3895 *pnt = 0;
3896 }
3897
fstVcdIDForFwrite(char * buf,unsigned int value)3898 static int fstVcdIDForFwrite(char *buf, unsigned int value)
3899 {
3900 char *pnt = buf;
3901
3902 /* zero is illegal for a value...it is assumed they start at one */
3903 while (value)
3904 {
3905 value--;
3906 *(pnt++) = (char)('!' + value % 94);
3907 value = value / 94;
3908 }
3909
3910 return(pnt - buf);
3911 }
3912
3913
fstReaderRecreateHierFile(struct fstReaderContext * xc)3914 static int fstReaderRecreateHierFile(struct fstReaderContext *xc)
3915 {
3916 int pass_status = 1;
3917
3918 if(!xc->fh)
3919 {
3920 fst_off_t offs_cache = ftello(xc->f);
3921 char *fnam = (char *)malloc(strlen(xc->filename) + 6 + 16 + 32 + 1);
3922 unsigned char *mem = (unsigned char *)malloc(FST_GZIO_LEN);
3923 fst_off_t hl, uclen;
3924 fst_off_t clen = 0;
3925 gzFile zhandle = NULL;
3926 int zfd;
3927 int htyp = FST_BL_SKIP;
3928
3929 /* can't handle both set at once should never happen in a real file */
3930 if(!xc->contains_hier_section_lz4 && xc->contains_hier_section)
3931 {
3932 htyp = FST_BL_HIER;
3933 }
3934 else
3935 if(xc->contains_hier_section_lz4 && !xc->contains_hier_section)
3936 {
3937 htyp = xc->contains_hier_section_lz4duo ? FST_BL_HIER_LZ4DUO : FST_BL_HIER_LZ4;
3938 }
3939
3940 sprintf(fnam, "%s.hier_%d_%p", xc->filename, getpid(), (void *)xc);
3941 fstReaderFseeko(xc, xc->f, xc->hier_pos, SEEK_SET);
3942 uclen = fstReaderUint64(xc->f);
3943 #ifndef __MINGW32__
3944 fflush(xc->f);
3945 #endif
3946 if(htyp == FST_BL_HIER)
3947 {
3948 fstReaderFseeko(xc, xc->f, xc->hier_pos, SEEK_SET);
3949 uclen = fstReaderUint64(xc->f);
3950 #ifndef __MINGW32__
3951 fflush(xc->f);
3952 #endif
3953 zfd = dup(fileno(xc->f));
3954 zhandle = gzdopen(zfd, "rb");
3955 if(!zhandle)
3956 {
3957 close(zfd);
3958 free(mem);
3959 free(fnam);
3960 return(0);
3961 }
3962 }
3963 else
3964 if((htyp == FST_BL_HIER_LZ4) || (htyp == FST_BL_HIER_LZ4DUO))
3965 {
3966 fstReaderFseeko(xc, xc->f, xc->hier_pos - 8, SEEK_SET); /* get section len */
3967 clen = fstReaderUint64(xc->f) - 16;
3968 uclen = fstReaderUint64(xc->f);
3969 #ifndef __MINGW32__
3970 fflush(xc->f);
3971 #endif
3972 }
3973
3974 #ifndef __MINGW32__
3975 xc->fh = fopen(fnam, "w+b");
3976 if(!xc->fh)
3977 #endif
3978 {
3979 xc->fh = tmpfile_open(&xc->fh_nam);
3980 free(fnam); fnam = NULL;
3981 if(!xc->fh)
3982 {
3983 tmpfile_close(&xc->fh, &xc->fh_nam);
3984 free(mem);
3985 return(0);
3986 }
3987 }
3988
3989 #ifndef __MINGW32__
3990 if(fnam) unlink(fnam);
3991 #endif
3992
3993 if(htyp == FST_BL_HIER)
3994 {
3995 for(hl = 0; hl < uclen; hl += FST_GZIO_LEN)
3996 {
3997 size_t len = ((uclen - hl) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - hl);
3998 size_t gzreadlen = gzread(zhandle, mem, len); /* rc should equal len... */
3999 size_t fwlen;
4000
4001 if(gzreadlen != len)
4002 {
4003 pass_status = 0;
4004 break;
4005 }
4006
4007 fwlen = fstFwrite(mem, len, 1, xc->fh);
4008 if(fwlen != 1)
4009 {
4010 pass_status = 0;
4011 break;
4012 }
4013 }
4014 gzclose(zhandle);
4015 }
4016 else
4017 if(htyp == FST_BL_HIER_LZ4DUO)
4018 {
4019 unsigned char *lz4_cmem = (unsigned char *)malloc(clen);
4020 unsigned char *lz4_ucmem = (unsigned char *)malloc(uclen);
4021 unsigned char *lz4_ucmem2;
4022 uint64_t uclen2;
4023 int skiplen2 = 0;
4024
4025 fstFread(lz4_cmem, clen, 1, xc->f);
4026
4027 uclen2 = fstGetVarint64(lz4_cmem, &skiplen2);
4028 lz4_ucmem2 = (unsigned char *)malloc(uclen2);
4029 pass_status = (uclen2 == (uint64_t)LZ4_decompress_safe_partial ((char *)lz4_cmem + skiplen2, (char *)lz4_ucmem2, clen - skiplen2, uclen2, uclen2));
4030 if(pass_status)
4031 {
4032 pass_status = (uclen == LZ4_decompress_safe_partial ((char *)lz4_ucmem2, (char *)lz4_ucmem, uclen2, uclen, uclen));
4033
4034 if(fstFwrite(lz4_ucmem, uclen, 1, xc->fh) != 1)
4035 {
4036 pass_status = 0;
4037 }
4038 }
4039
4040 free(lz4_ucmem2);
4041 free(lz4_ucmem);
4042 free(lz4_cmem);
4043 }
4044 else
4045 if(htyp == FST_BL_HIER_LZ4)
4046 {
4047 unsigned char *lz4_cmem = (unsigned char *)malloc(clen);
4048 unsigned char *lz4_ucmem = (unsigned char *)malloc(uclen);
4049
4050 fstFread(lz4_cmem, clen, 1, xc->f);
4051 pass_status = (uclen == LZ4_decompress_safe_partial ((char *)lz4_cmem, (char *)lz4_ucmem, clen, uclen, uclen));
4052
4053 if(fstFwrite(lz4_ucmem, uclen, 1, xc->fh) != 1)
4054 {
4055 pass_status = 0;
4056 }
4057
4058 free(lz4_ucmem);
4059 free(lz4_cmem);
4060 }
4061 else /* FST_BL_SKIP */
4062 {
4063 pass_status = 0;
4064 if(xc->fh)
4065 {
4066 fclose(xc->fh); xc->fh = NULL; /* needed in case .hier file is missing and there are no hier sections */
4067 }
4068 }
4069
4070 free(mem);
4071 free(fnam);
4072
4073 fstReaderFseeko(xc, xc->f, offs_cache, SEEK_SET);
4074 }
4075
4076 return(pass_status);
4077 }
4078
4079
fstReaderIterateHierRewind(void * ctx)4080 int fstReaderIterateHierRewind(void *ctx)
4081 {
4082 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
4083 int pass_status = 0;
4084
4085 if(xc)
4086 {
4087 pass_status = 1;
4088 if(!xc->fh)
4089 {
4090 pass_status = fstReaderRecreateHierFile(xc);
4091 }
4092
4093 xc->do_rewind = 1;
4094 }
4095
4096 return(pass_status);
4097 }
4098
4099
fstReaderIterateHier(void * ctx)4100 struct fstHier *fstReaderIterateHier(void *ctx)
4101 {
4102 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
4103 int isfeof;
4104 fstHandle alias;
4105 char *pnt;
4106 int ch;
4107
4108 if(!xc) return(NULL);
4109
4110 if(!xc->fh)
4111 {
4112 if(!fstReaderRecreateHierFile(xc))
4113 {
4114 return(NULL);
4115 }
4116 }
4117
4118 if(xc->do_rewind)
4119 {
4120 xc->do_rewind = 0;
4121 xc->current_handle = 0;
4122 fstReaderFseeko(xc, xc->fh, 0, SEEK_SET);
4123 clearerr(xc->fh);
4124 }
4125
4126 if(!(isfeof=feof(xc->fh)))
4127 {
4128 int tag = fgetc(xc->fh);
4129 switch(tag)
4130 {
4131 case FST_ST_VCD_SCOPE:
4132 xc->hier.htyp = FST_HT_SCOPE;
4133 xc->hier.u.scope.typ = fgetc(xc->fh);
4134 xc->hier.u.scope.name = pnt = xc->str_scope_nam;
4135 while((ch = fgetc(xc->fh)))
4136 {
4137 *(pnt++) = ch;
4138 }; /* scopename */
4139 *pnt = 0;
4140 xc->hier.u.scope.name_length = pnt - xc->hier.u.scope.name;
4141
4142 xc->hier.u.scope.component = pnt = xc->str_scope_comp;
4143 while((ch = fgetc(xc->fh)))
4144 {
4145 *(pnt++) = ch;
4146 }; /* scopecomp */
4147 *pnt = 0;
4148 xc->hier.u.scope.component_length = pnt - xc->hier.u.scope.component;
4149 break;
4150
4151 case FST_ST_VCD_UPSCOPE:
4152 xc->hier.htyp = FST_HT_UPSCOPE;
4153 break;
4154
4155 case FST_ST_GEN_ATTRBEGIN:
4156 xc->hier.htyp = FST_HT_ATTRBEGIN;
4157 xc->hier.u.attr.typ = fgetc(xc->fh);
4158 xc->hier.u.attr.subtype = fgetc(xc->fh);
4159 xc->hier.u.attr.name = pnt = xc->str_scope_nam;
4160 while((ch = fgetc(xc->fh)))
4161 {
4162 *(pnt++) = ch;
4163 }; /* scopename */
4164 *pnt = 0;
4165 xc->hier.u.attr.name_length = pnt - xc->hier.u.scope.name;
4166
4167 xc->hier.u.attr.arg = fstReaderVarint64(xc->fh);
4168
4169 if(xc->hier.u.attr.typ == FST_AT_MISC)
4170 {
4171 if((xc->hier.u.attr.subtype == FST_MT_SOURCESTEM)||(xc->hier.u.attr.subtype == FST_MT_SOURCEISTEM))
4172 {
4173 int sidx_skiplen_dummy = 0;
4174 xc->hier.u.attr.arg_from_name = fstGetVarint64((unsigned char *)xc->str_scope_nam, &sidx_skiplen_dummy);
4175 }
4176 }
4177 break;
4178
4179 case FST_ST_GEN_ATTREND:
4180 xc->hier.htyp = FST_HT_ATTREND;
4181 break;
4182
4183 case FST_VT_VCD_EVENT:
4184 case FST_VT_VCD_INTEGER:
4185 case FST_VT_VCD_PARAMETER:
4186 case FST_VT_VCD_REAL:
4187 case FST_VT_VCD_REAL_PARAMETER:
4188 case FST_VT_VCD_REG:
4189 case FST_VT_VCD_SUPPLY0:
4190 case FST_VT_VCD_SUPPLY1:
4191 case FST_VT_VCD_TIME:
4192 case FST_VT_VCD_TRI:
4193 case FST_VT_VCD_TRIAND:
4194 case FST_VT_VCD_TRIOR:
4195 case FST_VT_VCD_TRIREG:
4196 case FST_VT_VCD_TRI0:
4197 case FST_VT_VCD_TRI1:
4198 case FST_VT_VCD_WAND:
4199 case FST_VT_VCD_WIRE:
4200 case FST_VT_VCD_WOR:
4201 case FST_VT_VCD_PORT:
4202 case FST_VT_VCD_SPARRAY:
4203 case FST_VT_VCD_REALTIME:
4204 case FST_VT_GEN_STRING:
4205 case FST_VT_SV_BIT:
4206 case FST_VT_SV_LOGIC:
4207 case FST_VT_SV_INT:
4208 case FST_VT_SV_SHORTINT:
4209 case FST_VT_SV_LONGINT:
4210 case FST_VT_SV_BYTE:
4211 case FST_VT_SV_ENUM:
4212 case FST_VT_SV_SHORTREAL:
4213 xc->hier.htyp = FST_HT_VAR;
4214 xc->hier.u.var.svt_workspace = FST_SVT_NONE;
4215 xc->hier.u.var.sdt_workspace = FST_SDT_NONE;
4216 xc->hier.u.var.sxt_workspace = 0;
4217 xc->hier.u.var.typ = tag;
4218 xc->hier.u.var.direction = fgetc(xc->fh);
4219 xc->hier.u.var.name = pnt = xc->str_scope_nam;
4220 while((ch = fgetc(xc->fh)))
4221 {
4222 *(pnt++) = ch;
4223 }; /* varname */
4224 *pnt = 0;
4225 xc->hier.u.var.name_length = pnt - xc->hier.u.var.name;
4226 xc->hier.u.var.length = fstReaderVarint32(xc->fh);
4227 if(tag == FST_VT_VCD_PORT)
4228 {
4229 xc->hier.u.var.length -= 2; /* removal of delimiting spaces */
4230 xc->hier.u.var.length /= 3; /* port -> signal size adjust */
4231 }
4232
4233 alias = fstReaderVarint32(xc->fh);
4234
4235 if(!alias)
4236 {
4237 xc->current_handle++;
4238 xc->hier.u.var.handle = xc->current_handle;
4239 xc->hier.u.var.is_alias = 0;
4240 }
4241 else
4242 {
4243 xc->hier.u.var.handle = alias;
4244 xc->hier.u.var.is_alias = 1;
4245 }
4246
4247 break;
4248
4249 default:
4250 isfeof = 1;
4251 break;
4252 }
4253 }
4254
4255 return(!isfeof ? &xc->hier : NULL);
4256 }
4257
4258
fstReaderProcessHier(void * ctx,FILE * fv)4259 int fstReaderProcessHier(void *ctx, FILE *fv)
4260 {
4261 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
4262 char *str;
4263 char *pnt;
4264 int ch, scopetype;
4265 int vartype;
4266 uint32_t len, alias;
4267 /* uint32_t maxvalpos=0; */
4268 unsigned int num_signal_dyn = 65536;
4269 int attrtype, subtype;
4270 uint64_t attrarg;
4271 fstHandle maxhandle_scanbuild;
4272
4273 if(!xc) return(0);
4274
4275 xc->longest_signal_value_len = 32; /* arbitrarily set at 32...this is much longer than an expanded double */
4276
4277 if(!xc->fh)
4278 {
4279 if(!fstReaderRecreateHierFile(xc))
4280 {
4281 return(0);
4282 }
4283 }
4284
4285 str = (char *)malloc(FST_ID_NAM_ATTR_SIZ+1);
4286
4287 if(fv)
4288 {
4289 char time_dimension[2] = {0, 0};
4290 int time_scale = 1;
4291
4292 fprintf(fv, "$date\n\t%s\n$end\n", xc->date);
4293 fprintf(fv, "$version\n\t%s\n$end\n", xc->version);
4294 if(xc->timezero) fprintf(fv, "$timezero\n\t%" PRId64 "\n$end\n", xc->timezero);
4295
4296 switch(xc->timescale)
4297 {
4298 case 2: time_scale = 100; time_dimension[0] = 0; break;
4299 case 1: time_scale = 10; /* fallthrough */
4300 case 0: time_dimension[0] = 0; break;
4301
4302 case -1: time_scale = 100; time_dimension[0] = 'm'; break;
4303 case -2: time_scale = 10; /* fallthrough */
4304 case -3: time_dimension[0] = 'm'; break;
4305
4306 case -4: time_scale = 100; time_dimension[0] = 'u'; break;
4307 case -5: time_scale = 10; /* fallthrough */
4308 case -6: time_dimension[0] = 'u'; break;
4309
4310 case -10: time_scale = 100; time_dimension[0] = 'p'; break;
4311 case -11: time_scale = 10; /* fallthrough */
4312 case -12: time_dimension[0] = 'p'; break;
4313
4314 case -13: time_scale = 100; time_dimension[0] = 'f'; break;
4315 case -14: time_scale = 10; /* fallthrough */
4316 case -15: time_dimension[0] = 'f'; break;
4317
4318 case -16: time_scale = 100; time_dimension[0] = 'a'; break;
4319 case -17: time_scale = 10; /* fallthrough */
4320 case -18: time_dimension[0] = 'a'; break;
4321
4322 case -19: time_scale = 100; time_dimension[0] = 'z'; break;
4323 case -20: time_scale = 10; /* fallthrough */
4324 case -21: time_dimension[0] = 'z'; break;
4325
4326 case -7: time_scale = 100; time_dimension[0] = 'n'; break;
4327 case -8: time_scale = 10; /* fallthrough */
4328 case -9:
4329 default: time_dimension[0] = 'n'; break;
4330 }
4331
4332 if(fv) fprintf(fv, "$timescale\n\t%d%ss\n$end\n", time_scale, time_dimension);
4333 }
4334
4335 xc->maxhandle = 0;
4336 xc->num_alias = 0;
4337
4338 free(xc->signal_lens);
4339 xc->signal_lens = (uint32_t *)malloc(num_signal_dyn*sizeof(uint32_t));
4340
4341 free(xc->signal_typs);
4342 xc->signal_typs = (unsigned char *)malloc(num_signal_dyn*sizeof(unsigned char));
4343
4344 fstReaderFseeko(xc, xc->fh, 0, SEEK_SET);
4345 while(!feof(xc->fh))
4346 {
4347 int tag = fgetc(xc->fh);
4348 switch(tag)
4349 {
4350 case FST_ST_VCD_SCOPE:
4351 scopetype = fgetc(xc->fh);
4352 if((scopetype < FST_ST_MIN) || (scopetype > FST_ST_MAX)) scopetype = FST_ST_VCD_MODULE;
4353 pnt = str;
4354 while((ch = fgetc(xc->fh)))
4355 {
4356 *(pnt++) = ch;
4357 }; /* scopename */
4358 *pnt = 0;
4359 while(fgetc(xc->fh)) { }; /* scopecomp */
4360
4361 if(fv) fprintf(fv, "$scope %s %s $end\n", modtypes[scopetype], str);
4362 break;
4363
4364 case FST_ST_VCD_UPSCOPE:
4365 if(fv) fprintf(fv, "$upscope $end\n");
4366 break;
4367
4368 case FST_ST_GEN_ATTRBEGIN:
4369 attrtype = fgetc(xc->fh);
4370 subtype = fgetc(xc->fh);
4371 pnt = str;
4372 while((ch = fgetc(xc->fh)))
4373 {
4374 *(pnt++) = ch;
4375 }; /* attrname */
4376 *pnt = 0;
4377
4378 if(!str[0]) { strcpy(str, "\"\""); }
4379
4380 attrarg = fstReaderVarint64(xc->fh);
4381
4382 if(fv && xc->use_vcd_extensions)
4383 {
4384 switch(attrtype)
4385 {
4386 case FST_AT_ARRAY: if((subtype < FST_AR_NONE) || (subtype > FST_AR_MAX)) subtype = FST_AR_NONE;
4387 fprintf(fv, "$attrbegin %s %s %s %" PRId64 " $end\n", attrtypes[attrtype], arraytypes[subtype], str, attrarg);
4388 break;
4389 case FST_AT_ENUM: if((subtype < FST_EV_SV_INTEGER) || (subtype > FST_EV_MAX)) subtype = FST_EV_SV_INTEGER;
4390 fprintf(fv, "$attrbegin %s %s %s %" PRId64 " $end\n", attrtypes[attrtype], enumvaluetypes[subtype], str, attrarg);
4391 break;
4392 case FST_AT_PACK: if((subtype < FST_PT_NONE) || (subtype > FST_PT_MAX)) subtype = FST_PT_NONE;
4393 fprintf(fv, "$attrbegin %s %s %s %" PRId64 " $end\n", attrtypes[attrtype], packtypes[subtype], str, attrarg);
4394 break;
4395 case FST_AT_MISC:
4396 default: attrtype = FST_AT_MISC;
4397 if(subtype == FST_MT_COMMENT)
4398 {
4399 fprintf(fv, "$comment\n\t%s\n$end\n", str);
4400 }
4401 else
4402 {
4403 if((subtype == FST_MT_SOURCESTEM)||(subtype == FST_MT_SOURCEISTEM))
4404 {
4405 int sidx_skiplen_dummy = 0;
4406 uint64_t sidx = fstGetVarint64((unsigned char *)str, &sidx_skiplen_dummy);
4407
4408 fprintf(fv, "$attrbegin %s %02x %" PRId64 " %" PRId64 " $end\n", attrtypes[attrtype], subtype, sidx, attrarg);
4409 }
4410 else
4411 {
4412 fprintf(fv, "$attrbegin %s %02x %s %" PRId64 " $end\n", attrtypes[attrtype], subtype, str, attrarg);
4413 }
4414 }
4415 break;
4416 }
4417 }
4418 break;
4419
4420 case FST_ST_GEN_ATTREND:
4421 if(fv && xc->use_vcd_extensions) fprintf(fv, "$attrend $end\n");
4422 break;
4423
4424 case FST_VT_VCD_EVENT:
4425 case FST_VT_VCD_INTEGER:
4426 case FST_VT_VCD_PARAMETER:
4427 case FST_VT_VCD_REAL:
4428 case FST_VT_VCD_REAL_PARAMETER:
4429 case FST_VT_VCD_REG:
4430 case FST_VT_VCD_SUPPLY0:
4431 case FST_VT_VCD_SUPPLY1:
4432 case FST_VT_VCD_TIME:
4433 case FST_VT_VCD_TRI:
4434 case FST_VT_VCD_TRIAND:
4435 case FST_VT_VCD_TRIOR:
4436 case FST_VT_VCD_TRIREG:
4437 case FST_VT_VCD_TRI0:
4438 case FST_VT_VCD_TRI1:
4439 case FST_VT_VCD_WAND:
4440 case FST_VT_VCD_WIRE:
4441 case FST_VT_VCD_WOR:
4442 case FST_VT_VCD_PORT:
4443 case FST_VT_VCD_SPARRAY:
4444 case FST_VT_VCD_REALTIME:
4445 case FST_VT_GEN_STRING:
4446 case FST_VT_SV_BIT:
4447 case FST_VT_SV_LOGIC:
4448 case FST_VT_SV_INT:
4449 case FST_VT_SV_SHORTINT:
4450 case FST_VT_SV_LONGINT:
4451 case FST_VT_SV_BYTE:
4452 case FST_VT_SV_ENUM:
4453 case FST_VT_SV_SHORTREAL:
4454 vartype = tag;
4455 /* vardir = */ fgetc(xc->fh); /* unused in VCD reader, but need to advance read pointer */
4456 pnt = str;
4457 while((ch = fgetc(xc->fh)))
4458 {
4459 *(pnt++) = ch;
4460 }; /* varname */
4461 *pnt = 0;
4462 len = fstReaderVarint32(xc->fh);
4463 alias = fstReaderVarint32(xc->fh);
4464
4465 if(!alias)
4466 {
4467 if(xc->maxhandle == num_signal_dyn)
4468 {
4469 num_signal_dyn *= 2;
4470 xc->signal_lens = (uint32_t *)realloc(xc->signal_lens, num_signal_dyn*sizeof(uint32_t));
4471 xc->signal_typs = (unsigned char *)realloc(xc->signal_typs, num_signal_dyn*sizeof(unsigned char));
4472 }
4473 xc->signal_lens[xc->maxhandle] = len;
4474 xc->signal_typs[xc->maxhandle] = vartype;
4475
4476 /* maxvalpos+=len; */
4477 if(len > xc->longest_signal_value_len)
4478 {
4479 xc->longest_signal_value_len = len;
4480 }
4481
4482 if((vartype == FST_VT_VCD_REAL) || (vartype == FST_VT_VCD_REAL_PARAMETER) || (vartype == FST_VT_VCD_REALTIME) || (vartype == FST_VT_SV_SHORTREAL))
4483 {
4484 len = (vartype != FST_VT_SV_SHORTREAL) ? 64 : 32;
4485 xc->signal_typs[xc->maxhandle] = FST_VT_VCD_REAL;
4486 }
4487 if(fv)
4488 {
4489 char vcdid_buf[16];
4490 uint32_t modlen = (vartype != FST_VT_VCD_PORT) ? len : ((len - 2) / 3);
4491 fstVcdID(vcdid_buf, xc->maxhandle+1);
4492 fprintf(fv, "$var %s %" PRIu32 " %s %s $end\n", vartypes[vartype], modlen, vcdid_buf, str);
4493 }
4494 xc->maxhandle++;
4495 }
4496 else
4497 {
4498 if((vartype == FST_VT_VCD_REAL) || (vartype == FST_VT_VCD_REAL_PARAMETER) || (vartype == FST_VT_VCD_REALTIME) || (vartype == FST_VT_SV_SHORTREAL))
4499 {
4500 len = (vartype != FST_VT_SV_SHORTREAL) ? 64 : 32;
4501 xc->signal_typs[xc->maxhandle] = FST_VT_VCD_REAL;
4502 }
4503 if(fv)
4504 {
4505 char vcdid_buf[16];
4506 uint32_t modlen = (vartype != FST_VT_VCD_PORT) ? len : ((len - 2) / 3);
4507 fstVcdID(vcdid_buf, alias);
4508 fprintf(fv, "$var %s %" PRIu32 " %s %s $end\n", vartypes[vartype], modlen, vcdid_buf, str);
4509 }
4510 xc->num_alias++;
4511 }
4512
4513 break;
4514
4515 default:
4516 break;
4517 }
4518 }
4519 if(fv) fprintf(fv, "$enddefinitions $end\n");
4520
4521 maxhandle_scanbuild = xc->maxhandle ? xc->maxhandle : 1; /*scan-build warning suppression, in reality we have at least one signal */
4522
4523 xc->signal_lens = (uint32_t *)realloc(xc->signal_lens, maxhandle_scanbuild*sizeof(uint32_t));
4524 xc->signal_typs = (unsigned char *)realloc(xc->signal_typs, maxhandle_scanbuild*sizeof(unsigned char));
4525
4526 free(xc->process_mask);
4527 xc->process_mask = (unsigned char *)calloc(1, (maxhandle_scanbuild+7)/8);
4528
4529 free(xc->temp_signal_value_buf);
4530 xc->temp_signal_value_buf = (unsigned char *)malloc(xc->longest_signal_value_len + 1);
4531
4532 xc->var_count = xc->maxhandle + xc->num_alias;
4533
4534 free(str);
4535 return(1);
4536 }
4537
4538
4539 /*
4540 * reader file open/close functions
4541 */
fstReaderInit(struct fstReaderContext * xc)4542 int fstReaderInit(struct fstReaderContext *xc)
4543 {
4544 fst_off_t blkpos = 0;
4545 fst_off_t endfile;
4546 uint64_t seclen;
4547 int sectype;
4548 uint64_t vc_section_count_actual = 0;
4549 int hdr_incomplete = 0;
4550 int hdr_seen = 0;
4551 int gzread_pass_status = 1;
4552
4553 sectype = fgetc(xc->f);
4554 if(sectype == FST_BL_ZWRAPPER)
4555 {
4556 FILE *fcomp;
4557 fst_off_t offpnt, uclen;
4558 char gz_membuf[FST_GZIO_LEN];
4559 gzFile zhandle;
4560 int zfd;
4561 int flen = strlen(xc->filename);
4562 char *hf;
4563
4564 seclen = fstReaderUint64(xc->f);
4565 uclen = fstReaderUint64(xc->f);
4566
4567 if(!seclen) return(0); /* not finished compressing, this is a failed read */
4568
4569 hf = (char *)calloc(1, flen + 16 + 32 + 1);
4570
4571 sprintf(hf, "%s.upk_%d_%p", xc->filename, getpid(), (void *)xc);
4572 fcomp = fopen(hf, "w+b");
4573 if(!fcomp)
4574 {
4575 fcomp = tmpfile_open(&xc->f_nam);
4576 free(hf); hf = NULL;
4577 if(!fcomp) { tmpfile_close(&fcomp, &xc->f_nam); return(0); }
4578 }
4579
4580 #if defined(FST_MACOSX)
4581 setvbuf(fcomp, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */
4582 #endif
4583
4584 #ifdef __MINGW32__
4585 setvbuf(fcomp, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */
4586 xc->filename_unpacked = hf;
4587 #else
4588 if(hf)
4589 {
4590 unlink(hf);
4591 free(hf);
4592 }
4593 #endif
4594
4595 fstReaderFseeko(xc, xc->f, 1+8+8, SEEK_SET);
4596 #ifndef __MINGW32__
4597 fflush(xc->f);
4598 #endif
4599
4600 zfd = dup(fileno(xc->f));
4601 zhandle = gzdopen(zfd, "rb");
4602 if(zhandle)
4603 {
4604 for(offpnt = 0; offpnt < uclen; offpnt += FST_GZIO_LEN)
4605 {
4606 size_t this_len = ((uclen - offpnt) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - offpnt);
4607 size_t gzreadlen = gzread(zhandle, gz_membuf, this_len);
4608 size_t fwlen;
4609
4610 if(gzreadlen != this_len)
4611 {
4612 gzread_pass_status = 0;
4613 break;
4614 }
4615 fwlen = fstFwrite(gz_membuf, this_len, 1, fcomp);
4616 if(fwlen != 1)
4617 {
4618 gzread_pass_status = 0;
4619 break;
4620 }
4621 }
4622 gzclose(zhandle);
4623 }
4624 else
4625 {
4626 close(zfd);
4627 }
4628 fflush(fcomp);
4629 fclose(xc->f);
4630 xc->f = fcomp;
4631 }
4632
4633 if(gzread_pass_status)
4634 {
4635 fstReaderFseeko(xc, xc->f, 0, SEEK_END);
4636 endfile = ftello(xc->f);
4637
4638 while(blkpos < endfile)
4639 {
4640 fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET);
4641
4642 sectype = fgetc(xc->f);
4643 seclen = fstReaderUint64(xc->f);
4644
4645 if(sectype == EOF)
4646 {
4647 break;
4648 }
4649
4650 if((hdr_incomplete) && (!seclen))
4651 {
4652 break;
4653 }
4654
4655 if(!hdr_seen && (sectype != FST_BL_HDR))
4656 {
4657 break;
4658 }
4659
4660 blkpos++;
4661 if(sectype == FST_BL_HDR)
4662 {
4663 if(!hdr_seen)
4664 {
4665 int ch;
4666 double dcheck;
4667
4668 xc->start_time = fstReaderUint64(xc->f);
4669 xc->end_time = fstReaderUint64(xc->f);
4670
4671 hdr_incomplete = (xc->start_time == 0) && (xc->end_time == 0);
4672
4673 fstFread(&dcheck, 8, 1, xc->f);
4674 xc->double_endian_match = (dcheck == FST_DOUBLE_ENDTEST);
4675 if(!xc->double_endian_match)
4676 {
4677 union {
4678 unsigned char rvs_buf[8];
4679 double d;
4680 } vu;
4681
4682 unsigned char *dcheck_alias = (unsigned char *)&dcheck;
4683 int rvs_idx;
4684
4685 for(rvs_idx=0;rvs_idx<8;rvs_idx++)
4686 {
4687 vu.rvs_buf[rvs_idx] = dcheck_alias[7-rvs_idx];
4688 }
4689 if(vu.d != FST_DOUBLE_ENDTEST)
4690 {
4691 break; /* either corrupt file or wrong architecture (offset +33 also functions as matchword) */
4692 }
4693 }
4694
4695 hdr_seen = 1;
4696
4697 xc->mem_used_by_writer = fstReaderUint64(xc->f);
4698 xc->scope_count = fstReaderUint64(xc->f);
4699 xc->var_count = fstReaderUint64(xc->f);
4700 xc->maxhandle = fstReaderUint64(xc->f);
4701 xc->num_alias = xc->var_count - xc->maxhandle;
4702 xc->vc_section_count = fstReaderUint64(xc->f);
4703 ch = fgetc(xc->f);
4704 xc->timescale = (signed char)ch;
4705 fstFread(xc->version, FST_HDR_SIM_VERSION_SIZE, 1, xc->f);
4706 xc->version[FST_HDR_SIM_VERSION_SIZE] = 0;
4707 fstFread(xc->date, FST_HDR_DATE_SIZE, 1, xc->f);
4708 xc->date[FST_HDR_DATE_SIZE] = 0;
4709 ch = fgetc(xc->f);
4710 xc->filetype = (unsigned char)ch;
4711 xc->timezero = fstReaderUint64(xc->f);
4712 }
4713 }
4714 else if((sectype == FST_BL_VCDATA) || (sectype == FST_BL_VCDATA_DYN_ALIAS) || (sectype == FST_BL_VCDATA_DYN_ALIAS2))
4715 {
4716 if(hdr_incomplete)
4717 {
4718 uint64_t bt = fstReaderUint64(xc->f);
4719 xc->end_time = fstReaderUint64(xc->f);
4720
4721 if(!vc_section_count_actual) { xc->start_time = bt; }
4722 }
4723
4724 vc_section_count_actual++;
4725 }
4726 else if(sectype == FST_BL_GEOM)
4727 {
4728 if(!hdr_incomplete)
4729 {
4730 uint64_t clen = seclen - 24;
4731 uint64_t uclen = fstReaderUint64(xc->f);
4732 unsigned char *ucdata = (unsigned char *)malloc(uclen);
4733 unsigned char *pnt = ucdata;
4734 unsigned int i;
4735
4736 xc->contains_geom_section = 1;
4737 xc->maxhandle = fstReaderUint64(xc->f);
4738 xc->longest_signal_value_len = 32; /* arbitrarily set at 32...this is much longer than an expanded double */
4739
4740 free(xc->process_mask);
4741 xc->process_mask = (unsigned char *)calloc(1, (xc->maxhandle+7)/8);
4742
4743 if(clen != uclen)
4744 {
4745 unsigned char *cdata = (unsigned char *)malloc(clen);
4746 unsigned long destlen = uclen;
4747 unsigned long sourcelen = clen;
4748 int rc;
4749
4750 fstFread(cdata, clen, 1, xc->f);
4751 rc = uncompress(ucdata, &destlen, cdata, sourcelen);
4752
4753 if(rc != Z_OK)
4754 {
4755 fprintf(stderr, FST_APIMESS "fstReaderInit(), geom uncompress rc = %d, exiting.\n", rc);
4756 exit(255);
4757 }
4758
4759 free(cdata);
4760 }
4761 else
4762 {
4763 fstFread(ucdata, uclen, 1, xc->f);
4764 }
4765
4766 free(xc->signal_lens);
4767 xc->signal_lens = (uint32_t *)malloc(sizeof(uint32_t) * xc->maxhandle);
4768 free(xc->signal_typs);
4769 xc->signal_typs = (unsigned char *)malloc(sizeof(unsigned char) * xc->maxhandle);
4770
4771 for(i=0;i<xc->maxhandle;i++)
4772 {
4773 int skiplen;
4774 uint64_t val = fstGetVarint32(pnt, &skiplen);
4775
4776 pnt += skiplen;
4777
4778 if(val)
4779 {
4780 xc->signal_lens[i] = (val != 0xFFFFFFFF) ? val : 0;
4781 xc->signal_typs[i] = FST_VT_VCD_WIRE;
4782 if(xc->signal_lens[i] > xc->longest_signal_value_len)
4783 {
4784 xc->longest_signal_value_len = xc->signal_lens[i];
4785 }
4786 }
4787 else
4788 {
4789 xc->signal_lens[i] = 8; /* backpatch in real */
4790 xc->signal_typs[i] = FST_VT_VCD_REAL;
4791 /* xc->longest_signal_value_len handled above by overly large init size */
4792 }
4793 }
4794
4795 free(xc->temp_signal_value_buf);
4796 xc->temp_signal_value_buf = (unsigned char *)malloc(xc->longest_signal_value_len + 1);
4797
4798 free(ucdata);
4799 }
4800 }
4801 else if(sectype == FST_BL_HIER)
4802 {
4803 xc->contains_hier_section = 1;
4804 xc->hier_pos = ftello(xc->f);
4805 }
4806 else if(sectype == FST_BL_HIER_LZ4DUO)
4807 {
4808 xc->contains_hier_section_lz4 = 1;
4809 xc->contains_hier_section_lz4duo = 1;
4810 xc->hier_pos = ftello(xc->f);
4811 }
4812 else if(sectype == FST_BL_HIER_LZ4)
4813 {
4814 xc->contains_hier_section_lz4 = 1;
4815 xc->hier_pos = ftello(xc->f);
4816 }
4817 else if(sectype == FST_BL_BLACKOUT)
4818 {
4819 uint32_t i;
4820 uint64_t cur_bl = 0;
4821 uint64_t delta;
4822
4823 xc->num_blackouts = fstReaderVarint32(xc->f);
4824 free(xc->blackout_times);
4825 xc->blackout_times = (uint64_t *)calloc(xc->num_blackouts, sizeof(uint64_t));
4826 free(xc->blackout_activity);
4827 xc->blackout_activity = (unsigned char *)calloc(xc->num_blackouts, sizeof(unsigned char));
4828
4829 for(i=0;i<xc->num_blackouts;i++)
4830 {
4831 xc->blackout_activity[i] = fgetc(xc->f) != 0;
4832 delta = fstReaderVarint64(xc->f);
4833 cur_bl += delta;
4834 xc->blackout_times[i] = cur_bl;
4835 }
4836 }
4837
4838 blkpos += seclen;
4839 if(!hdr_seen) break;
4840 }
4841
4842 if(hdr_seen)
4843 {
4844 if(xc->vc_section_count != vc_section_count_actual)
4845 {
4846 xc->vc_section_count = vc_section_count_actual;
4847 }
4848
4849 if(!xc->contains_geom_section)
4850 {
4851 fstReaderProcessHier(xc, NULL); /* recreate signal_lens/signal_typs info */
4852 }
4853 }
4854 }
4855
4856 return(hdr_seen);
4857 }
4858
4859
fstReaderOpenForUtilitiesOnly(void)4860 void *fstReaderOpenForUtilitiesOnly(void)
4861 {
4862 struct fstReaderContext *xc = (struct fstReaderContext *)calloc(1, sizeof(struct fstReaderContext));
4863
4864 return(xc);
4865 }
4866
4867
fstReaderOpen(const char * nam)4868 void *fstReaderOpen(const char *nam)
4869 {
4870 struct fstReaderContext *xc = (struct fstReaderContext *)calloc(1, sizeof(struct fstReaderContext));
4871
4872 if((!nam)||(!(xc->f=fopen(nam, "rb"))))
4873 {
4874 free(xc);
4875 xc=NULL;
4876 }
4877 else
4878 {
4879 int flen = strlen(nam);
4880 char *hf = (char *)calloc(1, flen + 6);
4881 int rc;
4882
4883 #if defined(__MINGW32__) || defined(FST_MACOSX)
4884 setvbuf(xc->f, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */
4885 #endif
4886
4887 memcpy(hf, nam, flen);
4888 strcpy(hf + flen, ".hier");
4889 xc->fh = fopen(hf, "rb");
4890
4891 free(hf);
4892 xc->filename = strdup(nam);
4893 rc = fstReaderInit(xc);
4894
4895 if((rc) && (xc->vc_section_count) && (xc->maxhandle) && ((xc->fh)||(xc->contains_hier_section||(xc->contains_hier_section_lz4))))
4896 {
4897 /* more init */
4898 xc->do_rewind = 1;
4899 }
4900 else
4901 {
4902 fstReaderClose(xc);
4903 xc = NULL;
4904 }
4905 }
4906
4907 return(xc);
4908 }
4909
4910
fstReaderDeallocateRvatData(void * ctx)4911 static void fstReaderDeallocateRvatData(void *ctx)
4912 {
4913 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
4914 if(xc)
4915 {
4916 free(xc->rvat_chain_mem); xc->rvat_chain_mem = NULL;
4917 free(xc->rvat_frame_data); xc->rvat_frame_data = NULL;
4918 free(xc->rvat_time_table); xc->rvat_time_table = NULL;
4919 free(xc->rvat_chain_table); xc->rvat_chain_table = NULL;
4920 free(xc->rvat_chain_table_lengths); xc->rvat_chain_table_lengths = NULL;
4921
4922 xc->rvat_data_valid = 0;
4923 }
4924 }
4925
4926
fstReaderClose(void * ctx)4927 void fstReaderClose(void *ctx)
4928 {
4929 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
4930
4931 if(xc)
4932 {
4933 fstReaderDeallocateScopeData(xc);
4934 fstReaderDeallocateRvatData(xc);
4935 free(xc->rvat_sig_offs); xc->rvat_sig_offs = NULL;
4936
4937 free(xc->process_mask); xc->process_mask = NULL;
4938 free(xc->blackout_times); xc->blackout_times = NULL;
4939 free(xc->blackout_activity); xc->blackout_activity = NULL;
4940 free(xc->temp_signal_value_buf); xc->temp_signal_value_buf = NULL;
4941 free(xc->signal_typs); xc->signal_typs = NULL;
4942 free(xc->signal_lens); xc->signal_lens = NULL;
4943 free(xc->filename); xc->filename = NULL;
4944
4945 if(xc->fh)
4946 {
4947 tmpfile_close(&xc->fh, &xc->fh_nam);
4948 }
4949
4950 if(xc->f)
4951 {
4952 tmpfile_close(&xc->f, &xc->f_nam);
4953 if(xc->filename_unpacked)
4954 {
4955 unlink(xc->filename_unpacked);
4956 free(xc->filename_unpacked);
4957 }
4958 }
4959
4960 free(xc);
4961 }
4962 }
4963
4964
4965 /*
4966 * read processing
4967 */
4968
4969 /* normal read which re-interleaves the value change data */
fstReaderIterBlocks(void * ctx,void (* value_change_callback)(void * user_callback_data_pointer,uint64_t time,fstHandle facidx,const unsigned char * value),void * user_callback_data_pointer,FILE * fv)4970 int fstReaderIterBlocks(void *ctx,
4971 void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value),
4972 void *user_callback_data_pointer, FILE *fv)
4973 {
4974 return(fstReaderIterBlocks2(ctx, value_change_callback, NULL, user_callback_data_pointer, fv));
4975 }
4976
4977
fstReaderIterBlocks2(void * ctx,void (* value_change_callback)(void * user_callback_data_pointer,uint64_t time,fstHandle facidx,const unsigned char * value),void (* value_change_callback_varlen)(void * user_callback_data_pointer,uint64_t time,fstHandle facidx,const unsigned char * value,uint32_t len),void * user_callback_data_pointer,FILE * fv)4978 int fstReaderIterBlocks2(void *ctx,
4979 void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value),
4980 void (*value_change_callback_varlen)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value, uint32_t len),
4981 void *user_callback_data_pointer, FILE *fv)
4982 {
4983 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
4984
4985 uint64_t previous_time = UINT64_MAX;
4986 uint64_t *time_table = NULL;
4987 uint64_t tsec_nitems;
4988 unsigned int secnum = 0;
4989 int blocks_skipped = 0;
4990 fst_off_t blkpos = 0;
4991 uint64_t seclen, beg_tim;
4992 uint64_t end_tim;
4993 uint64_t frame_uclen, frame_clen, frame_maxhandle, vc_maxhandle;
4994 fst_off_t vc_start;
4995 fst_off_t indx_pntr, indx_pos;
4996 fst_off_t *chain_table = NULL;
4997 uint32_t *chain_table_lengths = NULL;
4998 unsigned char *chain_cmem;
4999 unsigned char *pnt;
5000 long chain_clen;
5001 fstHandle idx, pidx=0, i;
5002 uint64_t pval;
5003 uint64_t vc_maxhandle_largest = 0;
5004 uint64_t tsec_uclen = 0, tsec_clen = 0;
5005 int sectype;
5006 uint64_t mem_required_for_traversal;
5007 unsigned char *mem_for_traversal = NULL;
5008 uint32_t traversal_mem_offs;
5009 uint32_t *scatterptr, *headptr, *length_remaining;
5010 uint32_t cur_blackout = 0;
5011 int packtype;
5012 unsigned char *mc_mem = NULL;
5013 uint32_t mc_mem_len; /* corresponds to largest value encountered in chain_table_lengths[i] */
5014 int dumpvars_state = 0;
5015
5016 if(!xc) return(0);
5017
5018 scatterptr = (uint32_t *)calloc(xc->maxhandle, sizeof(uint32_t));
5019 headptr = (uint32_t *)calloc(xc->maxhandle, sizeof(uint32_t));
5020 length_remaining = (uint32_t *)calloc(xc->maxhandle, sizeof(uint32_t));
5021
5022 if(fv)
5023 {
5024 #ifndef FST_WRITEX_DISABLE
5025 fflush(fv);
5026 setvbuf(fv, (char *) NULL, _IONBF, 0); /* even buffered IO is slow so disable it and use our own routines that don't need seeking */
5027 xc->writex_fd = fileno(fv);
5028 #endif
5029 }
5030
5031 for(;;)
5032 {
5033 uint32_t *tc_head = NULL;
5034 traversal_mem_offs = 0;
5035
5036 fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET);
5037
5038 sectype = fgetc(xc->f);
5039 seclen = fstReaderUint64(xc->f);
5040
5041 if((sectype == EOF) || (sectype == FST_BL_SKIP))
5042 {
5043 #ifdef FST_DEBUG
5044 fprintf(stderr, FST_APIMESS "<< EOF >>\n");
5045 #endif
5046 break;
5047 }
5048
5049 blkpos++;
5050 if((sectype != FST_BL_VCDATA) && (sectype != FST_BL_VCDATA_DYN_ALIAS) && (sectype != FST_BL_VCDATA_DYN_ALIAS2))
5051 {
5052 blkpos += seclen;
5053 continue;
5054 }
5055
5056 if(!seclen) break;
5057
5058 beg_tim = fstReaderUint64(xc->f);
5059 end_tim = fstReaderUint64(xc->f);
5060
5061 if(xc->limit_range_valid)
5062 {
5063 if(end_tim < xc->limit_range_start)
5064 {
5065 blocks_skipped++;
5066 blkpos += seclen;
5067 continue;
5068 }
5069
5070 if(beg_tim > xc->limit_range_end) /* likely the compare in for(i=0;i<tsec_nitems;i++) below would do this earlier */
5071 {
5072 break;
5073 }
5074 }
5075
5076
5077 mem_required_for_traversal = fstReaderUint64(xc->f);
5078 mem_for_traversal = (unsigned char *)malloc(mem_required_for_traversal + 66); /* add in potential fastlz overhead */
5079 #ifdef FST_DEBUG
5080 fprintf(stderr, FST_APIMESS "sec: %u seclen: %d begtim: %d endtim: %d\n",
5081 secnum, (int)seclen, (int)beg_tim, (int)end_tim);
5082 fprintf(stderr, FST_APIMESS "mem_required_for_traversal: %d\n", (int)mem_required_for_traversal);
5083 #endif
5084 /* process time block */
5085 {
5086 unsigned char *ucdata;
5087 unsigned char *cdata;
5088 unsigned long destlen /* = tsec_uclen */; /* scan-build */
5089 unsigned long sourcelen /*= tsec_clen */; /* scan-build */
5090 int rc;
5091 unsigned char *tpnt;
5092 uint64_t tpval;
5093 unsigned int ti;
5094
5095 if(fstReaderFseeko(xc, xc->f, blkpos + seclen - 24, SEEK_SET) != 0) break;
5096 tsec_uclen = fstReaderUint64(xc->f);
5097 tsec_clen = fstReaderUint64(xc->f);
5098 tsec_nitems = fstReaderUint64(xc->f);
5099 #ifdef FST_DEBUG
5100 fprintf(stderr, FST_APIMESS "time section unc: %d, com: %d (%d items)\n",
5101 (int)tsec_uclen, (int)tsec_clen, (int)tsec_nitems);
5102 #endif
5103 if(tsec_clen > seclen) break; /* corrupted tsec_clen: by definition it can't be larger than size of section */
5104 ucdata = (unsigned char *)malloc(tsec_uclen);
5105 if(!ucdata) break; /* malloc fail as tsec_uclen out of range from corrupted file */
5106 destlen = tsec_uclen;
5107 sourcelen = tsec_clen;
5108
5109 fstReaderFseeko(xc, xc->f, -24 - ((fst_off_t)tsec_clen), SEEK_CUR);
5110
5111 if(tsec_uclen != tsec_clen)
5112 {
5113 cdata = (unsigned char *)malloc(tsec_clen);
5114 fstFread(cdata, tsec_clen, 1, xc->f);
5115
5116 rc = uncompress(ucdata, &destlen, cdata, sourcelen);
5117
5118 if(rc != Z_OK)
5119 {
5120 fprintf(stderr, FST_APIMESS "fstReaderIterBlocks2(), tsec uncompress rc = %d, exiting.\n", rc);
5121 exit(255);
5122 }
5123
5124 free(cdata);
5125 }
5126 else
5127 {
5128 fstFread(ucdata, tsec_uclen, 1, xc->f);
5129 }
5130
5131 free(time_table);
5132 time_table = (uint64_t *)calloc(tsec_nitems, sizeof(uint64_t));
5133 tpnt = ucdata;
5134 tpval = 0;
5135 for(ti=0;ti<tsec_nitems;ti++)
5136 {
5137 int skiplen;
5138 uint64_t val = fstGetVarint64(tpnt, &skiplen);
5139 tpval = time_table[ti] = tpval + val;
5140 tpnt += skiplen;
5141 }
5142
5143 tc_head = (uint32_t *)calloc(tsec_nitems /* scan-build */ ? tsec_nitems : 1, sizeof(uint32_t));
5144 free(ucdata);
5145 }
5146
5147 fstReaderFseeko(xc, xc->f, blkpos+32, SEEK_SET);
5148
5149 frame_uclen = fstReaderVarint64(xc->f);
5150 frame_clen = fstReaderVarint64(xc->f);
5151 frame_maxhandle = fstReaderVarint64(xc->f);
5152
5153 if(secnum == 0)
5154 {
5155 if((beg_tim != time_table[0]) || (blocks_skipped))
5156 {
5157 unsigned char *mu = (unsigned char *)malloc(frame_uclen);
5158 uint32_t sig_offs = 0;
5159
5160 if(fv)
5161 {
5162 char wx_buf[32];
5163 int wx_len;
5164
5165 if(beg_tim)
5166 {
5167 if(dumpvars_state == 1) { wx_len = sprintf(wx_buf, "$end\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 2; }
5168 wx_len = sprintf(wx_buf, "#%" PRIu64 "\n", beg_tim);
5169 fstWritex(xc, wx_buf, wx_len);
5170 if(!dumpvars_state) { wx_len = sprintf(wx_buf, "$dumpvars\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 1; }
5171 }
5172 if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts))
5173 {
5174 if(beg_tim == xc->blackout_times[cur_blackout])
5175 {
5176 wx_len = sprintf(wx_buf, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off");
5177 fstWritex(xc, wx_buf, wx_len);
5178 }
5179 }
5180 }
5181
5182 if(frame_uclen == frame_clen)
5183 {
5184 fstFread(mu, frame_uclen, 1, xc->f);
5185 }
5186 else
5187 {
5188 unsigned char *mc = (unsigned char *)malloc(frame_clen);
5189 int rc;
5190
5191 unsigned long destlen = frame_uclen;
5192 unsigned long sourcelen = frame_clen;
5193
5194 fstFread(mc, sourcelen, 1, xc->f);
5195 rc = uncompress(mu, &destlen, mc, sourcelen);
5196 if(rc != Z_OK)
5197 {
5198 fprintf(stderr, FST_APIMESS "fstReaderIterBlocks2(), frame uncompress rc: %d, exiting.\n", rc);
5199 exit(255);
5200 }
5201 free(mc);
5202 }
5203
5204
5205 for(idx=0;idx<frame_maxhandle;idx++)
5206 {
5207 int process_idx = idx/8;
5208 int process_bit = idx&7;
5209
5210 if(xc->process_mask[process_idx]&(1<<process_bit))
5211 {
5212 if(xc->signal_lens[idx] <= 1)
5213 {
5214 if(xc->signal_lens[idx] == 1)
5215 {
5216 unsigned char val = mu[sig_offs];
5217 if(value_change_callback)
5218 {
5219 xc->temp_signal_value_buf[0] = val;
5220 xc->temp_signal_value_buf[1] = 0;
5221 value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf);
5222 }
5223 else
5224 {
5225 if(fv)
5226 {
5227 char vcd_id[16];
5228
5229 int vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1);
5230 vcd_id[0] = val; /* collapse 3 writes into one I/O call */
5231 vcd_id[vcdid_len + 1] = '\n';
5232 fstWritex(xc, vcd_id, vcdid_len + 2);
5233 }
5234 }
5235 }
5236 else
5237 {
5238 /* variable-length ("0" length) records have no initial state */
5239 }
5240 }
5241 else
5242 {
5243 if(xc->signal_typs[idx] != FST_VT_VCD_REAL)
5244 {
5245 if(value_change_callback)
5246 {
5247 memcpy(xc->temp_signal_value_buf, mu+sig_offs, xc->signal_lens[idx]);
5248 xc->temp_signal_value_buf[xc->signal_lens[idx]] = 0;
5249 value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf);
5250 }
5251 else
5252 {
5253 if(fv)
5254 {
5255 char vcd_id[16];
5256 int vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1);
5257
5258 vcd_id[0] = (xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p';
5259 fstWritex(xc, vcd_id, 1);
5260 fstWritex(xc,mu+sig_offs, xc->signal_lens[idx]);
5261
5262 vcd_id[0] = ' '; /* collapse 3 writes into one I/O call */
5263 vcd_id[vcdid_len + 1] = '\n';
5264 fstWritex(xc, vcd_id, vcdid_len + 2);
5265 }
5266 }
5267 }
5268 else
5269 {
5270 double d;
5271 unsigned char *clone_d;
5272 unsigned char *srcdata = mu+sig_offs;
5273
5274 if(value_change_callback)
5275 {
5276 if(xc->native_doubles_for_cb)
5277 {
5278 if(xc->double_endian_match)
5279 {
5280 clone_d = srcdata;
5281 }
5282 else
5283 {
5284 int j;
5285
5286 clone_d = (unsigned char *)&d;
5287 for(j=0;j<8;j++)
5288 {
5289 clone_d[j] = srcdata[7-j];
5290 }
5291 }
5292 value_change_callback(user_callback_data_pointer, beg_tim, idx+1, clone_d);
5293 }
5294 else
5295 {
5296 clone_d = (unsigned char *)&d;
5297 if(xc->double_endian_match)
5298 {
5299 memcpy(clone_d, srcdata, 8);
5300 }
5301 else
5302 {
5303 int j;
5304
5305 for(j=0;j<8;j++)
5306 {
5307 clone_d[j] = srcdata[7-j];
5308 }
5309 }
5310 sprintf((char *)xc->temp_signal_value_buf, "%.16g", d);
5311 value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf);
5312 }
5313 }
5314 else
5315 {
5316 if(fv)
5317 {
5318 char vcdid_buf[16];
5319 char wx_buf[64];
5320 int wx_len;
5321
5322 clone_d = (unsigned char *)&d;
5323 if(xc->double_endian_match)
5324 {
5325 memcpy(clone_d, srcdata, 8);
5326 }
5327 else
5328 {
5329 int j;
5330
5331 for(j=0;j<8;j++)
5332 {
5333 clone_d[j] = srcdata[7-j];
5334 }
5335 }
5336
5337 fstVcdID(vcdid_buf, idx+1);
5338 wx_len = sprintf(wx_buf, "r%.16g %s\n", d, vcdid_buf);
5339 fstWritex(xc, wx_buf, wx_len);
5340 }
5341 }
5342 }
5343 }
5344 }
5345
5346 sig_offs += xc->signal_lens[idx];
5347 }
5348
5349 free(mu);
5350 fstReaderFseeko(xc, xc->f, -((fst_off_t)frame_clen), SEEK_CUR);
5351 }
5352 }
5353
5354 fstReaderFseeko(xc, xc->f, (fst_off_t)frame_clen, SEEK_CUR); /* skip past compressed data */
5355
5356 vc_maxhandle = fstReaderVarint64(xc->f);
5357 vc_start = ftello(xc->f); /* points to '!' character */
5358 packtype = fgetc(xc->f);
5359
5360 #ifdef FST_DEBUG
5361 fprintf(stderr, FST_APIMESS "frame_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n",
5362 (int)frame_uclen, (int)frame_clen, (int)frame_maxhandle);
5363 fprintf(stderr, FST_APIMESS "vc_maxhandle: %d, packtype: %c\n", (int)vc_maxhandle, packtype);
5364 #endif
5365
5366 indx_pntr = blkpos + seclen - 24 -tsec_clen -8;
5367 fstReaderFseeko(xc, xc->f, indx_pntr, SEEK_SET);
5368 chain_clen = fstReaderUint64(xc->f);
5369 indx_pos = indx_pntr - chain_clen;
5370 #ifdef FST_DEBUG
5371 fprintf(stderr, FST_APIMESS "indx_pos: %d (%d bytes)\n", (int)indx_pos, (int)chain_clen);
5372 #endif
5373 chain_cmem = (unsigned char *)malloc(chain_clen);
5374 if(!chain_cmem) goto block_err;
5375 fstReaderFseeko(xc, xc->f, indx_pos, SEEK_SET);
5376 fstFread(chain_cmem, chain_clen, 1, xc->f);
5377
5378 if(vc_maxhandle > vc_maxhandle_largest)
5379 {
5380 free(chain_table);
5381 free(chain_table_lengths);
5382
5383 vc_maxhandle_largest = vc_maxhandle;
5384 chain_table = (fst_off_t *)calloc((vc_maxhandle+1), sizeof(fst_off_t));
5385 chain_table_lengths = (uint32_t *)calloc((vc_maxhandle+1), sizeof(uint32_t));
5386 }
5387
5388 if(!chain_table || !chain_table_lengths) goto block_err;
5389
5390 pnt = chain_cmem;
5391 idx = 0;
5392 pval = 0;
5393
5394 if(sectype == FST_BL_VCDATA_DYN_ALIAS2)
5395 {
5396 uint32_t prev_alias = 0;
5397
5398 do {
5399 int skiplen;
5400
5401 if(*pnt & 0x01)
5402 {
5403 int64_t shval = fstGetSVarint64(pnt, &skiplen) >> 1;
5404 if(shval > 0)
5405 {
5406 pval = chain_table[idx] = pval + shval;
5407 if(idx) { chain_table_lengths[pidx] = pval - chain_table[pidx]; }
5408 pidx = idx++;
5409 }
5410 else if(shval < 0)
5411 {
5412 chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */
5413 chain_table_lengths[idx] = prev_alias = shval; /* because during this loop iter would give stale data! */
5414 idx++;
5415 }
5416 else
5417 {
5418 chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */
5419 chain_table_lengths[idx] = prev_alias; /* because during this loop iter would give stale data! */
5420 idx++;
5421 }
5422 }
5423 else
5424 {
5425 uint64_t val = fstGetVarint32(pnt, &skiplen);
5426
5427 fstHandle loopcnt = val >> 1;
5428 for(i=0;i<loopcnt;i++)
5429 {
5430 chain_table[idx++] = 0;
5431 }
5432 }
5433
5434 pnt += skiplen;
5435 } while (pnt != (chain_cmem + chain_clen));
5436 }
5437 else
5438 {
5439 do {
5440 int skiplen;
5441 uint64_t val = fstGetVarint32(pnt, &skiplen);
5442
5443 if(!val)
5444 {
5445 pnt += skiplen;
5446 val = fstGetVarint32(pnt, &skiplen);
5447 chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */
5448 chain_table_lengths[idx] = -val; /* because during this loop iter would give stale data! */
5449 idx++;
5450 }
5451 else
5452 if(val&1)
5453 {
5454 pval = chain_table[idx] = pval + (val >> 1);
5455 if(idx) { chain_table_lengths[pidx] = pval - chain_table[pidx]; }
5456 pidx = idx++;
5457 }
5458 else
5459 {
5460 fstHandle loopcnt = val >> 1;
5461 for(i=0;i<loopcnt;i++)
5462 {
5463 chain_table[idx++] = 0;
5464 }
5465 }
5466
5467 pnt += skiplen;
5468 } while (pnt != (chain_cmem + chain_clen));
5469 }
5470
5471 chain_table[idx] = indx_pos - vc_start;
5472 chain_table_lengths[pidx] = chain_table[idx] - chain_table[pidx];
5473
5474 for(i=0;i<idx;i++)
5475 {
5476 int32_t v32 = chain_table_lengths[i];
5477 if((v32 < 0) && (!chain_table[i]))
5478 {
5479 v32 = -v32;
5480 v32--;
5481 if(((uint32_t)v32) < i) /* sanity check */
5482 {
5483 chain_table[i] = chain_table[v32];
5484 chain_table_lengths[i] = chain_table_lengths[v32];
5485 }
5486 }
5487 }
5488
5489 #ifdef FST_DEBUG
5490 fprintf(stderr, FST_APIMESS "decompressed chain idx len: %" PRIu32 "\n", idx);
5491 #endif
5492
5493 mc_mem_len = 16384;
5494 mc_mem = (unsigned char *)malloc(mc_mem_len); /* buffer for compressed reads */
5495
5496 /* check compressed VC data */
5497 if(idx > xc->maxhandle) idx = xc->maxhandle;
5498 for(i=0;i<idx;i++)
5499 {
5500 if(chain_table[i])
5501 {
5502 int process_idx = i/8;
5503 int process_bit = i&7;
5504
5505 if(xc->process_mask[process_idx]&(1<<process_bit))
5506 {
5507 int rc = Z_OK;
5508 uint32_t val;
5509 uint32_t skiplen;
5510 uint32_t tdelta;
5511
5512 fstReaderFseeko(xc, xc->f, vc_start + chain_table[i], SEEK_SET);
5513 val = fstReaderVarint32WithSkip(xc->f, &skiplen);
5514 if(val)
5515 {
5516 unsigned char *mu = mem_for_traversal + traversal_mem_offs; /* uncomp: dst */
5517 unsigned char *mc; /* comp: src */
5518 unsigned long destlen = val;
5519 unsigned long sourcelen = chain_table_lengths[i];
5520
5521 if(mc_mem_len < chain_table_lengths[i])
5522 {
5523 free(mc_mem);
5524 mc_mem = (unsigned char *)malloc(mc_mem_len = chain_table_lengths[i]);
5525 }
5526 mc = mc_mem;
5527
5528 fstFread(mc, chain_table_lengths[i], 1, xc->f);
5529
5530 switch(packtype)
5531 {
5532 case '4': rc = (destlen == (unsigned long)LZ4_decompress_safe_partial((char *)mc, (char *)mu, sourcelen, destlen, destlen)) ? Z_OK : Z_DATA_ERROR;
5533 break;
5534 case 'F': fastlz_decompress(mc, sourcelen, mu, destlen); /* rc appears unreliable */
5535 break;
5536 default: rc = uncompress(mu, &destlen, mc, sourcelen);
5537 break;
5538 }
5539
5540 /* data to process is for(j=0;j<destlen;j++) in mu[j] */
5541 headptr[i] = traversal_mem_offs;
5542 length_remaining[i] = val;
5543 traversal_mem_offs += val;
5544 }
5545 else
5546 {
5547 int destlen = chain_table_lengths[i] - skiplen;
5548 unsigned char *mu = mem_for_traversal + traversal_mem_offs;
5549 fstFread(mu, destlen, 1, xc->f);
5550 /* data to process is for(j=0;j<destlen;j++) in mu[j] */
5551 headptr[i] = traversal_mem_offs;
5552 length_remaining[i] = destlen;
5553 traversal_mem_offs += destlen;
5554 }
5555
5556 if(rc != Z_OK)
5557 {
5558 fprintf(stderr, FST_APIMESS "fstReaderIterBlocks2(), fac: %d clen: %d (rc=%d), exiting.\n", (int)i, (int)val, rc);
5559 exit(255);
5560 }
5561
5562 if(xc->signal_lens[i] == 1)
5563 {
5564 uint32_t vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[i]);
5565 uint32_t shcnt = 2 << (vli & 1);
5566 tdelta = vli >> shcnt;
5567 }
5568 else
5569 {
5570 uint32_t vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[i]);
5571 tdelta = vli >> 1;
5572 }
5573
5574 scatterptr[i] = tc_head[tdelta];
5575 tc_head[tdelta] = i+1;
5576 }
5577 }
5578 }
5579
5580 free(mc_mem); /* there is no usage below for this, no real need to clear out mc_mem or mc_mem_len */
5581
5582 for(i=0;i<tsec_nitems;i++)
5583 {
5584 uint32_t tdelta;
5585 int skiplen, skiplen2;
5586 uint32_t vli;
5587
5588 if(fv)
5589 {
5590 char wx_buf[32];
5591 int wx_len;
5592
5593 if(time_table[i] != previous_time)
5594 {
5595 if(xc->limit_range_valid)
5596 {
5597 if(time_table[i] > xc->limit_range_end)
5598 {
5599 break;
5600 }
5601 }
5602
5603 if(dumpvars_state == 1) { wx_len = sprintf(wx_buf, "$end\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 2; }
5604 wx_len = sprintf(wx_buf, "#%" PRIu64 "\n", time_table[i]);
5605 fstWritex(xc, wx_buf, wx_len);
5606 if(!dumpvars_state) { wx_len = sprintf(wx_buf, "$dumpvars\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 1; }
5607
5608 if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts))
5609 {
5610 if(time_table[i] == xc->blackout_times[cur_blackout])
5611 {
5612 wx_len = sprintf(wx_buf, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off");
5613 fstWritex(xc, wx_buf, wx_len);
5614 }
5615 }
5616 previous_time = time_table[i];
5617 }
5618 }
5619
5620 while(tc_head[i])
5621 {
5622 idx = tc_head[i] - 1;
5623 vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen);
5624
5625 if(xc->signal_lens[idx] <= 1)
5626 {
5627 if(xc->signal_lens[idx] == 1)
5628 {
5629 unsigned char val;
5630 if(!(vli & 1))
5631 {
5632 /* tdelta = vli >> 2; */ /* scan-build */
5633 val = ((vli >> 1) & 1) | '0';
5634 }
5635 else
5636 {
5637 /* tdelta = vli >> 4; */ /* scan-build */
5638 val = FST_RCV_STR[((vli >> 1) & 7)];
5639 }
5640
5641 if(value_change_callback)
5642 {
5643 xc->temp_signal_value_buf[0] = val;
5644 xc->temp_signal_value_buf[1] = 0;
5645 value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf);
5646 }
5647 else
5648 {
5649 if(fv)
5650 {
5651 char vcd_id[16];
5652 int vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1);
5653
5654 vcd_id[0] = val;
5655 vcd_id[vcdid_len+1] = '\n';
5656 fstWritex(xc, vcd_id, vcdid_len+2);
5657 }
5658 }
5659 headptr[idx] += skiplen;
5660 length_remaining[idx] -= skiplen;
5661
5662 tc_head[i] = scatterptr[idx];
5663 scatterptr[idx] = 0;
5664
5665 if(length_remaining[idx])
5666 {
5667 int shamt;
5668 vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]);
5669 shamt = 2 << (vli & 1);
5670 tdelta = vli >> shamt;
5671
5672 scatterptr[idx] = tc_head[i+tdelta];
5673 tc_head[i+tdelta] = idx+1;
5674 }
5675 }
5676 else
5677 {
5678 unsigned char *vdata;
5679 uint32_t len;
5680
5681 vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen);
5682 len = fstGetVarint32(mem_for_traversal + headptr[idx] + skiplen, &skiplen2);
5683 /* tdelta = vli >> 1; */ /* scan-build */
5684 skiplen += skiplen2;
5685 vdata = mem_for_traversal + headptr[idx] + skiplen;
5686
5687 if(!(vli & 1))
5688 {
5689 if(value_change_callback_varlen)
5690 {
5691 value_change_callback_varlen(user_callback_data_pointer, time_table[i], idx+1, vdata, len);
5692 }
5693 else
5694 {
5695 if(fv)
5696 {
5697 char vcd_id[16];
5698 int vcdid_len;
5699
5700 vcd_id[0] = 's';
5701 fstWritex(xc, vcd_id, 1);
5702
5703 vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1);
5704 {
5705 unsigned char *vesc = (unsigned char *)malloc(len*4 + 1);
5706 int vlen = fstUtilityBinToEsc(vesc, vdata, len);
5707 fstWritex(xc, vesc, vlen);
5708 free(vesc);
5709 }
5710
5711 vcd_id[0] = ' ';
5712 vcd_id[vcdid_len + 1] = '\n';
5713 fstWritex(xc, vcd_id, vcdid_len+2);
5714 }
5715 }
5716 }
5717
5718 skiplen += len;
5719 headptr[idx] += skiplen;
5720 length_remaining[idx] -= skiplen;
5721
5722 tc_head[i] = scatterptr[idx];
5723 scatterptr[idx] = 0;
5724
5725 if(length_remaining[idx])
5726 {
5727 vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]);
5728 tdelta = vli >> 1;
5729
5730 scatterptr[idx] = tc_head[i+tdelta];
5731 tc_head[i+tdelta] = idx+1;
5732 }
5733 }
5734 }
5735 else
5736 {
5737 uint32_t len = xc->signal_lens[idx];
5738 unsigned char *vdata;
5739
5740 vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen);
5741 /* tdelta = vli >> 1; */ /* scan-build */
5742 vdata = mem_for_traversal + headptr[idx] + skiplen;
5743
5744 if(xc->signal_typs[idx] != FST_VT_VCD_REAL)
5745 {
5746 if(!(vli & 1))
5747 {
5748 int byte = 0;
5749 int bit;
5750 unsigned int j;
5751
5752 for(j=0;j<len;j++)
5753 {
5754 unsigned char ch;
5755 byte = j/8;
5756 bit = 7 - (j & 7);
5757 ch = ((vdata[byte] >> bit) & 1) | '0';
5758 xc->temp_signal_value_buf[j] = ch;
5759 }
5760 xc->temp_signal_value_buf[j] = 0;
5761
5762 if(value_change_callback)
5763 {
5764 value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf);
5765 }
5766 else
5767 {
5768 if(fv) {
5769 unsigned char ch_bp = (xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p';
5770
5771 fstWritex(xc, &ch_bp, 1);
5772 fstWritex(xc, xc->temp_signal_value_buf, len);
5773 }
5774 }
5775
5776 len = byte+1;
5777 }
5778 else
5779 {
5780 if(value_change_callback)
5781 {
5782 memcpy(xc->temp_signal_value_buf, vdata, len);
5783 xc->temp_signal_value_buf[len] = 0;
5784 value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf);
5785 }
5786 else
5787 {
5788 if(fv)
5789 {
5790 unsigned char ch_bp = (xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p';
5791
5792 fstWritex(xc, &ch_bp, 1);
5793 fstWritex(xc, vdata, len);
5794 }
5795 }
5796 }
5797 }
5798 else
5799 {
5800 double d;
5801 unsigned char *clone_d /*= (unsigned char *)&d */; /* scan-build */
5802 unsigned char buf[8];
5803 unsigned char *srcdata;
5804
5805 if(!(vli & 1)) /* very rare case, but possible */
5806 {
5807 int bit;
5808 int j;
5809
5810 for(j=0;j<8;j++)
5811 {
5812 unsigned char ch;
5813 bit = 7 - (j & 7);
5814 ch = ((vdata[0] >> bit) & 1) | '0';
5815 buf[j] = ch;
5816 }
5817
5818 len = 1;
5819 srcdata = buf;
5820 }
5821 else
5822 {
5823 srcdata = vdata;
5824 }
5825
5826 if(value_change_callback)
5827 {
5828 if(xc->native_doubles_for_cb)
5829 {
5830 if(xc->double_endian_match)
5831 {
5832 clone_d = srcdata;
5833 }
5834 else
5835 {
5836 int j;
5837
5838 clone_d = (unsigned char *)&d;
5839 for(j=0;j<8;j++)
5840 {
5841 clone_d[j] = srcdata[7-j];
5842 }
5843 }
5844 value_change_callback(user_callback_data_pointer, time_table[i], idx+1, clone_d);
5845 }
5846 else
5847 {
5848 clone_d = (unsigned char *)&d;
5849 if(xc->double_endian_match)
5850 {
5851 memcpy(clone_d, srcdata, 8);
5852 }
5853 else
5854 {
5855 int j;
5856
5857 for(j=0;j<8;j++)
5858 {
5859 clone_d[j] = srcdata[7-j];
5860 }
5861 }
5862 sprintf((char *)xc->temp_signal_value_buf, "%.16g", d);
5863 value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf);
5864 }
5865 }
5866 else
5867 {
5868 if(fv)
5869 {
5870 char wx_buf[32];
5871 int wx_len;
5872
5873 clone_d = (unsigned char *)&d;
5874 if(xc->double_endian_match)
5875 {
5876 memcpy(clone_d, srcdata, 8);
5877 }
5878 else
5879 {
5880 int j;
5881
5882 for(j=0;j<8;j++)
5883 {
5884 clone_d[j] = srcdata[7-j];
5885 }
5886 }
5887
5888 wx_len = sprintf(wx_buf, "r%.16g", d);
5889 fstWritex(xc, wx_buf, wx_len);
5890 }
5891 }
5892 }
5893
5894 if(fv)
5895 {
5896 char vcd_id[16];
5897 int vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1);
5898 vcd_id[0] = ' ';
5899 vcd_id[vcdid_len+1] = '\n';
5900 fstWritex(xc, vcd_id, vcdid_len+2);
5901 }
5902
5903 skiplen += len;
5904 headptr[idx] += skiplen;
5905 length_remaining[idx] -= skiplen;
5906
5907 tc_head[i] = scatterptr[idx];
5908 scatterptr[idx] = 0;
5909
5910 if(length_remaining[idx])
5911 {
5912 vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]);
5913 tdelta = vli >> 1;
5914
5915 scatterptr[idx] = tc_head[i+tdelta];
5916 tc_head[i+tdelta] = idx+1;
5917 }
5918 }
5919 }
5920 }
5921
5922 block_err:
5923 free(tc_head);
5924 free(chain_cmem);
5925 free(mem_for_traversal); mem_for_traversal = NULL;
5926
5927 secnum++;
5928 if(secnum == xc->vc_section_count) break; /* in case file is growing, keep with original block count */
5929 blkpos += seclen;
5930 }
5931
5932 if(mem_for_traversal) free(mem_for_traversal); /* scan-build */
5933 free(length_remaining);
5934 free(headptr);
5935 free(scatterptr);
5936
5937 if(chain_table) free(chain_table);
5938 if(chain_table_lengths) free(chain_table_lengths);
5939
5940 free(time_table);
5941
5942 #ifndef FST_WRITEX_DISABLE
5943 if(fv)
5944 {
5945 fstWritex(xc, NULL, 0);
5946 }
5947 #endif
5948
5949 return(1);
5950 }
5951
5952
5953 /* rvat functions */
5954
fstExtractRvatDataFromFrame(struct fstReaderContext * xc,fstHandle facidx,char * buf)5955 static char *fstExtractRvatDataFromFrame(struct fstReaderContext *xc, fstHandle facidx, char *buf)
5956 {
5957 if(facidx >= xc->rvat_frame_maxhandle)
5958 {
5959 return(NULL);
5960 }
5961
5962 if(xc->signal_lens[facidx] == 1)
5963 {
5964 buf[0] = (char)xc->rvat_frame_data[xc->rvat_sig_offs[facidx]];
5965 buf[1] = 0;
5966 }
5967 else
5968 {
5969 if(xc->signal_typs[facidx] != FST_VT_VCD_REAL)
5970 {
5971 memcpy(buf, xc->rvat_frame_data + xc->rvat_sig_offs[facidx], xc->signal_lens[facidx]);
5972 buf[xc->signal_lens[facidx]] = 0;
5973 }
5974 else
5975 {
5976 double d;
5977 unsigned char *clone_d = (unsigned char *)&d;
5978 unsigned char *srcdata = xc->rvat_frame_data + xc->rvat_sig_offs[facidx];
5979
5980 if(xc->double_endian_match)
5981 {
5982 memcpy(clone_d, srcdata, 8);
5983 }
5984 else
5985 {
5986 int j;
5987
5988 for(j=0;j<8;j++)
5989 {
5990 clone_d[j] = srcdata[7-j];
5991 }
5992 }
5993
5994 sprintf((char *)buf, "%.16g", d);
5995 }
5996 }
5997
5998 return(buf);
5999 }
6000
6001
fstReaderGetValueFromHandleAtTime(void * ctx,uint64_t tim,fstHandle facidx,char * buf)6002 char *fstReaderGetValueFromHandleAtTime(void *ctx, uint64_t tim, fstHandle facidx, char *buf)
6003 {
6004 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
6005 fst_off_t blkpos = 0, prev_blkpos;
6006 uint64_t beg_tim, end_tim, beg_tim2, end_tim2;
6007 int sectype;
6008 unsigned int secnum = 0;
6009 uint64_t seclen;
6010 uint64_t tsec_uclen = 0, tsec_clen = 0;
6011 uint64_t tsec_nitems;
6012 uint64_t frame_uclen, frame_clen;
6013 #ifdef FST_DEBUG
6014 uint64_t mem_required_for_traversal;
6015 #endif
6016 fst_off_t indx_pntr, indx_pos;
6017 long chain_clen;
6018 unsigned char *chain_cmem;
6019 unsigned char *pnt;
6020 fstHandle idx, pidx=0, i;
6021 uint64_t pval;
6022
6023 if((!xc) || (!facidx) || (facidx > xc->maxhandle) || (!buf) || (!xc->signal_lens[facidx-1]))
6024 {
6025 return(NULL);
6026 }
6027
6028 if(!xc->rvat_sig_offs)
6029 {
6030 uint32_t cur_offs = 0;
6031
6032 xc->rvat_sig_offs = (uint32_t *)calloc(xc->maxhandle, sizeof(uint32_t));
6033 for(i=0;i<xc->maxhandle;i++)
6034 {
6035 xc->rvat_sig_offs[i] = cur_offs;
6036 cur_offs += xc->signal_lens[i];
6037 }
6038 }
6039
6040 if(xc->rvat_data_valid)
6041 {
6042 if((xc->rvat_beg_tim <= tim) && (tim <= xc->rvat_end_tim))
6043 {
6044 goto process_value;
6045 }
6046
6047 fstReaderDeallocateRvatData(xc);
6048 }
6049
6050 xc->rvat_chain_pos_valid = 0;
6051
6052 for(;;)
6053 {
6054 fstReaderFseeko(xc, xc->f, (prev_blkpos = blkpos), SEEK_SET);
6055
6056 sectype = fgetc(xc->f);
6057 seclen = fstReaderUint64(xc->f);
6058
6059 if((sectype == EOF) || (sectype == FST_BL_SKIP) || (!seclen))
6060 {
6061 return(NULL); /* if this loop exits on break, it's successful */
6062 }
6063
6064 blkpos++;
6065 if((sectype != FST_BL_VCDATA) && (sectype != FST_BL_VCDATA_DYN_ALIAS) && (sectype != FST_BL_VCDATA_DYN_ALIAS2))
6066 {
6067 blkpos += seclen;
6068 continue;
6069 }
6070
6071 beg_tim = fstReaderUint64(xc->f);
6072 end_tim = fstReaderUint64(xc->f);
6073
6074 if((beg_tim <= tim) && (tim <= end_tim))
6075 {
6076 if((tim == end_tim) && (tim != xc->end_time))
6077 {
6078 fst_off_t cached_pos = ftello(xc->f);
6079 fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET);
6080
6081 sectype = fgetc(xc->f);
6082 seclen = fstReaderUint64(xc->f);
6083
6084 beg_tim2 = fstReaderUint64(xc->f);
6085 end_tim2 = fstReaderUint64(xc->f);
6086
6087 if(((sectype != FST_BL_VCDATA)&&(sectype != FST_BL_VCDATA_DYN_ALIAS)&&(sectype != FST_BL_VCDATA_DYN_ALIAS2)) || (!seclen) || (beg_tim2 != tim))
6088 {
6089 blkpos = prev_blkpos;
6090 break;
6091 }
6092 beg_tim = beg_tim2;
6093 end_tim = end_tim2;
6094 fstReaderFseeko(xc, xc->f, cached_pos, SEEK_SET);
6095 }
6096 break;
6097 }
6098
6099 blkpos += seclen;
6100 secnum++;
6101 }
6102
6103 xc->rvat_beg_tim = beg_tim;
6104 xc->rvat_end_tim = end_tim;
6105
6106 #ifdef FST_DEBUG
6107 mem_required_for_traversal =
6108 #endif
6109 fstReaderUint64(xc->f);
6110
6111 #ifdef FST_DEBUG
6112 fprintf(stderr, FST_APIMESS "rvat sec: %u seclen: %d begtim: %d endtim: %d\n",
6113 secnum, (int)seclen, (int)beg_tim, (int)end_tim);
6114 fprintf(stderr, FST_APIMESS "mem_required_for_traversal: %d\n", (int)mem_required_for_traversal);
6115 #endif
6116
6117 /* process time block */
6118 {
6119 unsigned char *ucdata;
6120 unsigned char *cdata;
6121 unsigned long destlen /* = tsec_uclen */; /* scan-build */
6122 unsigned long sourcelen /* = tsec_clen */; /* scan-build */
6123 int rc;
6124 unsigned char *tpnt;
6125 uint64_t tpval;
6126 unsigned int ti;
6127
6128 fstReaderFseeko(xc, xc->f, blkpos + seclen - 24, SEEK_SET);
6129 tsec_uclen = fstReaderUint64(xc->f);
6130 tsec_clen = fstReaderUint64(xc->f);
6131 tsec_nitems = fstReaderUint64(xc->f);
6132 #ifdef FST_DEBUG
6133 fprintf(stderr, FST_APIMESS "time section unc: %d, com: %d (%d items)\n",
6134 (int)tsec_uclen, (int)tsec_clen, (int)tsec_nitems);
6135 #endif
6136 ucdata = (unsigned char *)malloc(tsec_uclen);
6137 destlen = tsec_uclen;
6138 sourcelen = tsec_clen;
6139
6140 fstReaderFseeko(xc, xc->f, -24 - ((fst_off_t)tsec_clen), SEEK_CUR);
6141 if(tsec_uclen != tsec_clen)
6142 {
6143 cdata = (unsigned char *)malloc(tsec_clen);
6144 fstFread(cdata, tsec_clen, 1, xc->f);
6145
6146 rc = uncompress(ucdata, &destlen, cdata, sourcelen);
6147
6148 if(rc != Z_OK)
6149 {
6150 fprintf(stderr, FST_APIMESS "fstReaderGetValueFromHandleAtTime(), tsec uncompress rc = %d, exiting.\n", rc);
6151 exit(255);
6152 }
6153
6154 free(cdata);
6155 }
6156 else
6157 {
6158 fstFread(ucdata, tsec_uclen, 1, xc->f);
6159 }
6160
6161 xc->rvat_time_table = (uint64_t *)calloc(tsec_nitems, sizeof(uint64_t));
6162 tpnt = ucdata;
6163 tpval = 0;
6164 for(ti=0;ti<tsec_nitems;ti++)
6165 {
6166 int skiplen;
6167 uint64_t val = fstGetVarint64(tpnt, &skiplen);
6168 tpval = xc->rvat_time_table[ti] = tpval + val;
6169 tpnt += skiplen;
6170 }
6171
6172 free(ucdata);
6173 }
6174
6175 fstReaderFseeko(xc, xc->f, blkpos+32, SEEK_SET);
6176
6177 frame_uclen = fstReaderVarint64(xc->f);
6178 frame_clen = fstReaderVarint64(xc->f);
6179 xc->rvat_frame_maxhandle = fstReaderVarint64(xc->f);
6180 xc->rvat_frame_data = (unsigned char *)malloc(frame_uclen);
6181
6182 if(frame_uclen == frame_clen)
6183 {
6184 fstFread(xc->rvat_frame_data, frame_uclen, 1, xc->f);
6185 }
6186 else
6187 {
6188 unsigned char *mc = (unsigned char *)malloc(frame_clen);
6189 int rc;
6190
6191 unsigned long destlen = frame_uclen;
6192 unsigned long sourcelen = frame_clen;
6193
6194 fstFread(mc, sourcelen, 1, xc->f);
6195 rc = uncompress(xc->rvat_frame_data, &destlen, mc, sourcelen);
6196 if(rc != Z_OK)
6197 {
6198 fprintf(stderr, FST_APIMESS "fstReaderGetValueFromHandleAtTime(), frame decompress rc: %d, exiting.\n", rc);
6199 exit(255);
6200 }
6201 free(mc);
6202 }
6203
6204 xc->rvat_vc_maxhandle = fstReaderVarint64(xc->f);
6205 xc->rvat_vc_start = ftello(xc->f); /* points to '!' character */
6206 xc->rvat_packtype = fgetc(xc->f);
6207
6208 #ifdef FST_DEBUG
6209 fprintf(stderr, FST_APIMESS "frame_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n",
6210 (int)frame_uclen, (int)frame_clen, (int)xc->rvat_frame_maxhandle);
6211 fprintf(stderr, FST_APIMESS "vc_maxhandle: %d\n", (int)xc->rvat_vc_maxhandle);
6212 #endif
6213
6214 indx_pntr = blkpos + seclen - 24 -tsec_clen -8;
6215 fstReaderFseeko(xc, xc->f, indx_pntr, SEEK_SET);
6216 chain_clen = fstReaderUint64(xc->f);
6217 indx_pos = indx_pntr - chain_clen;
6218 #ifdef FST_DEBUG
6219 fprintf(stderr, FST_APIMESS "indx_pos: %d (%d bytes)\n", (int)indx_pos, (int)chain_clen);
6220 #endif
6221 chain_cmem = (unsigned char *)malloc(chain_clen);
6222 fstReaderFseeko(xc, xc->f, indx_pos, SEEK_SET);
6223 fstFread(chain_cmem, chain_clen, 1, xc->f);
6224
6225 xc->rvat_chain_table = (fst_off_t *)calloc((xc->rvat_vc_maxhandle+1), sizeof(fst_off_t));
6226 xc->rvat_chain_table_lengths = (uint32_t *)calloc((xc->rvat_vc_maxhandle+1), sizeof(uint32_t));
6227
6228 pnt = chain_cmem;
6229 idx = 0;
6230 pval = 0;
6231
6232 if(sectype == FST_BL_VCDATA_DYN_ALIAS2)
6233 {
6234 uint32_t prev_alias = 0;
6235
6236 do {
6237 int skiplen;
6238
6239 if(*pnt & 0x01)
6240 {
6241 int64_t shval = fstGetSVarint64(pnt, &skiplen) >> 1;
6242 if(shval > 0)
6243 {
6244 pval = xc->rvat_chain_table[idx] = pval + shval;
6245 if(idx) { xc->rvat_chain_table_lengths[pidx] = pval - xc->rvat_chain_table[pidx]; }
6246 pidx = idx++;
6247 }
6248 else if(shval < 0)
6249 {
6250 xc->rvat_chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */
6251 xc->rvat_chain_table_lengths[idx] = prev_alias = shval; /* because during this loop iter would give stale data! */
6252 idx++;
6253 }
6254 else
6255 {
6256 xc->rvat_chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */
6257 xc->rvat_chain_table_lengths[idx] = prev_alias; /* because during this loop iter would give stale data! */
6258 idx++;
6259 }
6260 }
6261 else
6262 {
6263 uint64_t val = fstGetVarint32(pnt, &skiplen);
6264
6265 fstHandle loopcnt = val >> 1;
6266 for(i=0;i<loopcnt;i++)
6267 {
6268 xc->rvat_chain_table[idx++] = 0;
6269 }
6270 }
6271
6272 pnt += skiplen;
6273 } while (pnt != (chain_cmem + chain_clen));
6274 }
6275 else
6276 {
6277 do
6278 {
6279 int skiplen;
6280 uint64_t val = fstGetVarint32(pnt, &skiplen);
6281
6282 if(!val)
6283 {
6284 pnt += skiplen;
6285 val = fstGetVarint32(pnt, &skiplen);
6286 xc->rvat_chain_table[idx] = 0;
6287 xc->rvat_chain_table_lengths[idx] = -val;
6288 idx++;
6289 }
6290 else
6291 if(val&1)
6292 {
6293 pval = xc->rvat_chain_table[idx] = pval + (val >> 1);
6294 if(idx) { xc->rvat_chain_table_lengths[pidx] = pval - xc->rvat_chain_table[pidx]; }
6295 pidx = idx++;
6296 }
6297 else
6298 {
6299 fstHandle loopcnt = val >> 1;
6300 for(i=0;i<loopcnt;i++)
6301 {
6302 xc->rvat_chain_table[idx++] = 0;
6303 }
6304 }
6305
6306 pnt += skiplen;
6307 } while (pnt != (chain_cmem + chain_clen));
6308 }
6309
6310 free(chain_cmem);
6311 xc->rvat_chain_table[idx] = indx_pos - xc->rvat_vc_start;
6312 xc->rvat_chain_table_lengths[pidx] = xc->rvat_chain_table[idx] - xc->rvat_chain_table[pidx];
6313
6314 for(i=0;i<idx;i++)
6315 {
6316 int32_t v32 = xc->rvat_chain_table_lengths[i];
6317 if((v32 < 0) && (!xc->rvat_chain_table[i]))
6318 {
6319 v32 = -v32;
6320 v32--;
6321 if(((uint32_t)v32) < i) /* sanity check */
6322 {
6323 xc->rvat_chain_table[i] = xc->rvat_chain_table[v32];
6324 xc->rvat_chain_table_lengths[i] = xc->rvat_chain_table_lengths[v32];
6325 }
6326 }
6327 }
6328
6329 #ifdef FST_DEBUG
6330 fprintf(stderr, FST_APIMESS "decompressed chain idx len: %" PRIu32 "\n", idx);
6331 #endif
6332
6333 xc->rvat_data_valid = 1;
6334
6335 /* all data at this point is loaded or resident in fst cache, process and return appropriate value */
6336 process_value:
6337 if(facidx > xc->rvat_vc_maxhandle)
6338 {
6339 return(NULL);
6340 }
6341
6342 facidx--; /* scale down for array which starts at zero */
6343
6344
6345 if(((tim == xc->rvat_beg_tim)&&(!xc->rvat_chain_table[facidx])) || (!xc->rvat_chain_table[facidx]))
6346 {
6347 return(fstExtractRvatDataFromFrame(xc, facidx, buf));
6348 }
6349
6350 if(facidx != xc->rvat_chain_facidx)
6351 {
6352 if(xc->rvat_chain_mem)
6353 {
6354 free(xc->rvat_chain_mem);
6355 xc->rvat_chain_mem = NULL;
6356
6357 xc->rvat_chain_pos_valid = 0;
6358 }
6359 }
6360
6361 if(!xc->rvat_chain_mem)
6362 {
6363 uint32_t skiplen;
6364 fstReaderFseeko(xc, xc->f, xc->rvat_vc_start + xc->rvat_chain_table[facidx], SEEK_SET);
6365 xc->rvat_chain_len = fstReaderVarint32WithSkip(xc->f, &skiplen);
6366 if(xc->rvat_chain_len)
6367 {
6368 unsigned char *mu = (unsigned char *)malloc(xc->rvat_chain_len);
6369 unsigned char *mc = (unsigned char *)malloc(xc->rvat_chain_table_lengths[facidx]);
6370 unsigned long destlen = xc->rvat_chain_len;
6371 unsigned long sourcelen = xc->rvat_chain_table_lengths[facidx];
6372 int rc = Z_OK;
6373
6374 fstFread(mc, xc->rvat_chain_table_lengths[facidx], 1, xc->f);
6375
6376 switch(xc->rvat_packtype)
6377 {
6378 case '4': rc = (destlen == (unsigned long)LZ4_decompress_safe_partial((char *)mc, (char *)mu, sourcelen, destlen, destlen)) ? Z_OK : Z_DATA_ERROR;
6379 break;
6380 case 'F': fastlz_decompress(mc, sourcelen, mu, destlen); /* rc appears unreliable */
6381 break;
6382 default: rc = uncompress(mu, &destlen, mc, sourcelen);
6383 break;
6384 }
6385
6386 free(mc);
6387
6388 if(rc != Z_OK)
6389 {
6390 fprintf(stderr, FST_APIMESS "fstReaderGetValueFromHandleAtTime(), rvat decompress clen: %d (rc=%d), exiting.\n", (int)xc->rvat_chain_len, rc);
6391 exit(255);
6392 }
6393
6394 /* data to process is for(j=0;j<destlen;j++) in mu[j] */
6395 xc->rvat_chain_mem = mu;
6396 }
6397 else
6398 {
6399 int destlen = xc->rvat_chain_table_lengths[facidx] - skiplen;
6400 unsigned char *mu = (unsigned char *)malloc(xc->rvat_chain_len = destlen);
6401 fstFread(mu, destlen, 1, xc->f);
6402 /* data to process is for(j=0;j<destlen;j++) in mu[j] */
6403 xc->rvat_chain_mem = mu;
6404 }
6405
6406 xc->rvat_chain_facidx = facidx;
6407 }
6408
6409 /* process value chain here */
6410
6411 {
6412 uint32_t tidx = 0, ptidx = 0;
6413 uint32_t tdelta;
6414 int skiplen;
6415 unsigned int iprev = xc->rvat_chain_len;
6416 uint32_t pvli = 0;
6417 int pskip = 0;
6418
6419 if((xc->rvat_chain_pos_valid)&&(tim >= xc->rvat_chain_pos_time))
6420 {
6421 i = xc->rvat_chain_pos_idx;
6422 tidx = xc->rvat_chain_pos_tidx;
6423 }
6424 else
6425 {
6426 i = 0;
6427 tidx = 0;
6428 xc->rvat_chain_pos_time = xc->rvat_beg_tim;
6429 }
6430
6431 if(xc->signal_lens[facidx] == 1)
6432 {
6433 while(i<xc->rvat_chain_len)
6434 {
6435 uint32_t vli = fstGetVarint32(xc->rvat_chain_mem + i, &skiplen);
6436 uint32_t shcnt = 2 << (vli & 1);
6437 tdelta = vli >> shcnt;
6438
6439 if(xc->rvat_time_table[tidx + tdelta] <= tim)
6440 {
6441 iprev = i;
6442 pvli = vli;
6443 ptidx = tidx;
6444 /* pskip = skiplen; */ /* scan-build */
6445
6446 tidx += tdelta;
6447 i+=skiplen;
6448 }
6449 else
6450 {
6451 break;
6452 }
6453 }
6454 if(iprev != xc->rvat_chain_len)
6455 {
6456 xc->rvat_chain_pos_tidx = ptidx;
6457 xc->rvat_chain_pos_idx = iprev;
6458 xc->rvat_chain_pos_time = tim;
6459 xc->rvat_chain_pos_valid = 1;
6460
6461 if(!(pvli & 1))
6462 {
6463 buf[0] = ((pvli >> 1) & 1) | '0';
6464 }
6465 else
6466 {
6467 buf[0] = FST_RCV_STR[((pvli >> 1) & 7)];
6468 }
6469 buf[1] = 0;
6470 return(buf);
6471 }
6472 else
6473 {
6474 return(fstExtractRvatDataFromFrame(xc, facidx, buf));
6475 }
6476 }
6477 else
6478 {
6479 while(i<xc->rvat_chain_len)
6480 {
6481 uint32_t vli = fstGetVarint32(xc->rvat_chain_mem + i, &skiplen);
6482 tdelta = vli >> 1;
6483
6484 if(xc->rvat_time_table[tidx + tdelta] <= tim)
6485 {
6486 iprev = i;
6487 pvli = vli;
6488 ptidx = tidx;
6489 pskip = skiplen;
6490
6491 tidx += tdelta;
6492 i+=skiplen;
6493
6494 if(!(pvli & 1))
6495 {
6496 i+=((xc->signal_lens[facidx]+7)/8);
6497 }
6498 else
6499 {
6500 i+=xc->signal_lens[facidx];
6501 }
6502 }
6503 else
6504 {
6505 break;
6506 }
6507 }
6508
6509 if(iprev != xc->rvat_chain_len)
6510 {
6511 unsigned char *vdata = xc->rvat_chain_mem + iprev + pskip;
6512
6513 xc->rvat_chain_pos_tidx = ptidx;
6514 xc->rvat_chain_pos_idx = iprev;
6515 xc->rvat_chain_pos_time = tim;
6516 xc->rvat_chain_pos_valid = 1;
6517
6518 if(xc->signal_typs[facidx] != FST_VT_VCD_REAL)
6519 {
6520 if(!(pvli & 1))
6521 {
6522 int byte = 0;
6523 int bit;
6524 unsigned int j;
6525
6526 for(j=0;j<xc->signal_lens[facidx];j++)
6527 {
6528 unsigned char ch;
6529 byte = j/8;
6530 bit = 7 - (j & 7);
6531 ch = ((vdata[byte] >> bit) & 1) | '0';
6532 buf[j] = ch;
6533 }
6534 buf[j] = 0;
6535
6536 return(buf);
6537 }
6538 else
6539 {
6540 memcpy(buf, vdata, xc->signal_lens[facidx]);
6541 buf[xc->signal_lens[facidx]] = 0;
6542 return(buf);
6543 }
6544 }
6545 else
6546 {
6547 double d;
6548 unsigned char *clone_d = (unsigned char *)&d;
6549 unsigned char bufd[8];
6550 unsigned char *srcdata;
6551
6552 if(!(pvli & 1)) /* very rare case, but possible */
6553 {
6554 int bit;
6555 int j;
6556
6557 for(j=0;j<8;j++)
6558 {
6559 unsigned char ch;
6560 bit = 7 - (j & 7);
6561 ch = ((vdata[0] >> bit) & 1) | '0';
6562 bufd[j] = ch;
6563 }
6564
6565 srcdata = bufd;
6566 }
6567 else
6568 {
6569 srcdata = vdata;
6570 }
6571
6572 if(xc->double_endian_match)
6573 {
6574 memcpy(clone_d, srcdata, 8);
6575 }
6576 else
6577 {
6578 int j;
6579
6580 for(j=0;j<8;j++)
6581 {
6582 clone_d[j] = srcdata[7-j];
6583 }
6584 }
6585
6586 sprintf(buf, "r%.16g", d);
6587 return(buf);
6588 }
6589 }
6590 else
6591 {
6592 return(fstExtractRvatDataFromFrame(xc, facidx, buf));
6593 }
6594 }
6595 }
6596
6597 /* return(NULL); */
6598 }
6599
6600
6601
6602 /**********************************************************************/
6603 #ifndef _WAVE_HAVE_JUDY
6604
6605 /***********************/
6606 /*** ***/
6607 /*** jenkins hash ***/
6608 /*** ***/
6609 /***********************/
6610
6611 /*
6612 --------------------------------------------------------------------
6613 mix -- mix 3 32-bit values reversibly.
6614 For every delta with one or two bits set, and the deltas of all three
6615 high bits or all three low bits, whether the original value of a,b,c
6616 is almost all zero or is uniformly distributed,
6617 * If mix() is run forward or backward, at least 32 bits in a,b,c
6618 have at least 1/4 probability of changing.
6619 * If mix() is run forward, every bit of c will change between 1/3 and
6620 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.)
6621 mix() was built out of 36 single-cycle latency instructions in a
6622 structure that could supported 2x parallelism, like so:
6623 a -= b;
6624 a -= c; x = (c>>13);
6625 b -= c; a ^= x;
6626 b -= a; x = (a<<8);
6627 c -= a; b ^= x;
6628 c -= b; x = (b>>13);
6629 ...
6630 Unfortunately, superscalar Pentiums and Sparcs can't take advantage
6631 of that parallelism. They've also turned some of those single-cycle
6632 latency instructions into multi-cycle latency instructions. Still,
6633 this is the fastest good hash I could find. There were about 2^^68
6634 to choose from. I only looked at a billion or so.
6635 --------------------------------------------------------------------
6636 */
6637 #define mix(a,b,c) \
6638 { \
6639 a -= b; a -= c; a ^= (c>>13); \
6640 b -= c; b -= a; b ^= (a<<8); \
6641 c -= a; c -= b; c ^= (b>>13); \
6642 a -= b; a -= c; a ^= (c>>12); \
6643 b -= c; b -= a; b ^= (a<<16); \
6644 c -= a; c -= b; c ^= (b>>5); \
6645 a -= b; a -= c; a ^= (c>>3); \
6646 b -= c; b -= a; b ^= (a<<10); \
6647 c -= a; c -= b; c ^= (b>>15); \
6648 }
6649
6650 /*
6651 --------------------------------------------------------------------
6652 j_hash() -- hash a variable-length key into a 32-bit value
6653 k : the key (the unaligned variable-length array of bytes)
6654 len : the length of the key, counting by bytes
6655 initval : can be any 4-byte value
6656 Returns a 32-bit value. Every bit of the key affects every bit of
6657 the return value. Every 1-bit and 2-bit delta achieves avalanche.
6658 About 6*len+35 instructions.
6659
6660 The best hash table sizes are powers of 2. There is no need to do
6661 mod a prime (mod is sooo slow!). If you need less than 32 bits,
6662 use a bitmask. For example, if you need only 10 bits, do
6663 h = (h & hashmask(10));
6664 In which case, the hash table should have hashsize(10) elements.
6665
6666 If you are hashing n strings (uint8_t **)k, do it like this:
6667 for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h);
6668
6669 By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this
6670 code any way you wish, private, educational, or commercial. It's free.
6671
6672 See http://burtleburtle.net/bob/hash/evahash.html
6673 Use for hash table lookup, or anything where one collision in 2^^32 is
6674 acceptable. Do NOT use for cryptographic purposes.
6675 --------------------------------------------------------------------
6676 */
6677
j_hash(const uint8_t * k,uint32_t length,uint32_t initval)6678 static uint32_t j_hash(const uint8_t *k, uint32_t length, uint32_t initval)
6679 {
6680 uint32_t a,b,c,len;
6681
6682 /* Set up the internal state */
6683 len = length;
6684 a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
6685 c = initval; /* the previous hash value */
6686
6687 /*---------------------------------------- handle most of the key */
6688 while (len >= 12)
6689 {
6690 a += (k[0] +((uint32_t)k[1]<<8) +((uint32_t)k[2]<<16) +((uint32_t)k[3]<<24));
6691 b += (k[4] +((uint32_t)k[5]<<8) +((uint32_t)k[6]<<16) +((uint32_t)k[7]<<24));
6692 c += (k[8] +((uint32_t)k[9]<<8) +((uint32_t)k[10]<<16)+((uint32_t)k[11]<<24));
6693 mix(a,b,c);
6694 k += 12; len -= 12;
6695 }
6696
6697 /*------------------------------------- handle the last 11 bytes */
6698 c += length;
6699 switch(len) /* all the case statements fall through */
6700 {
6701 case 11: c+=((uint32_t)k[10]<<24); /* fallthrough */
6702 case 10: c+=((uint32_t)k[9]<<16); /* fallthrough */
6703 case 9 : c+=((uint32_t)k[8]<<8); /* fallthrough */
6704 /* the first byte of c is reserved for the length */
6705 case 8 : b+=((uint32_t)k[7]<<24); /* fallthrough */
6706 case 7 : b+=((uint32_t)k[6]<<16); /* fallthrough */
6707 case 6 : b+=((uint32_t)k[5]<<8); /* fallthrough */
6708 case 5 : b+=k[4]; /* fallthrough */
6709 case 4 : a+=((uint32_t)k[3]<<24); /* fallthrough */
6710 case 3 : a+=((uint32_t)k[2]<<16); /* fallthrough */
6711 case 2 : a+=((uint32_t)k[1]<<8); /* fallthrough */
6712 case 1 : a+=k[0];
6713 /* case 0: nothing left to add */
6714 }
6715 mix(a,b,c);
6716 /*-------------------------------------------- report the result */
6717 return(c);
6718 }
6719
6720 /********************************************************************/
6721
6722 /***************************/
6723 /*** ***/
6724 /*** judy HS emulation ***/
6725 /*** ***/
6726 /***************************/
6727
6728 struct collchain_t
6729 {
6730 struct collchain_t *next;
6731 void *payload;
6732 uint32_t fullhash, length;
6733 unsigned char mem[1];
6734 };
6735
6736
JenkinsIns(void * base_i,const unsigned char * mem,uint32_t length,uint32_t hashmask)6737 void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint32_t hashmask)
6738 {
6739 struct collchain_t ***base = (struct collchain_t ***)base_i;
6740 uint32_t hf, h;
6741 struct collchain_t **ar;
6742 struct collchain_t *chain, *pchain;
6743
6744 if(!*base)
6745 {
6746 *base = (struct collchain_t **)calloc(1, (hashmask + 1) * sizeof(void *));
6747 }
6748 ar = *base;
6749
6750 h = (hf = j_hash(mem, length, length)) & hashmask;
6751 pchain = chain = ar[h];
6752 while(chain)
6753 {
6754 if((chain->fullhash == hf) && (chain->length == length) && !memcmp(chain->mem, mem, length))
6755 {
6756 if(pchain != chain) /* move hit to front */
6757 {
6758 pchain->next = chain->next;
6759 chain->next = ar[h];
6760 ar[h] = chain;
6761 }
6762 return(&(chain->payload));
6763 }
6764
6765 pchain = chain;
6766 chain = chain->next;
6767 }
6768
6769 chain = (struct collchain_t *)calloc(1, sizeof(struct collchain_t) + length - 1);
6770 memcpy(chain->mem, mem, length);
6771 chain->fullhash = hf;
6772 chain->length = length;
6773 chain->next = ar[h];
6774 ar[h] = chain;
6775 return(&(chain->payload));
6776 }
6777
6778
JenkinsFree(void * base_i,uint32_t hashmask)6779 void JenkinsFree(void *base_i, uint32_t hashmask)
6780 {
6781 struct collchain_t ***base = (struct collchain_t ***)base_i;
6782 uint32_t h;
6783 struct collchain_t **ar;
6784 struct collchain_t *chain, *chain_next;
6785
6786 if(base && *base)
6787 {
6788 ar = *base;
6789 for(h=0;h<=hashmask;h++)
6790 {
6791 chain = ar[h];
6792 while(chain)
6793 {
6794 chain_next = chain->next;
6795 free(chain);
6796 chain = chain_next;
6797 }
6798 }
6799
6800 free(*base);
6801 *base = NULL;
6802 }
6803 }
6804
6805 #endif
6806
6807 /**********************************************************************/
6808
6809 /************************/
6810 /*** ***/
6811 /*** utility function ***/
6812 /*** ***/
6813 /************************/
6814
fstUtilityBinToEscConvertedLen(const unsigned char * s,int len)6815 int fstUtilityBinToEscConvertedLen(const unsigned char *s, int len)
6816 {
6817 const unsigned char *src = s;
6818 int dlen = 0;
6819 int i;
6820
6821 for(i=0;i<len;i++)
6822 {
6823 switch(src[i])
6824 {
6825 case '\a': /* fallthrough */
6826 case '\b': /* fallthrough */
6827 case '\f': /* fallthrough */
6828 case '\n': /* fallthrough */
6829 case '\r': /* fallthrough */
6830 case '\t': /* fallthrough */
6831 case '\v': /* fallthrough */
6832 case '\'': /* fallthrough */
6833 case '\"': /* fallthrough */
6834 case '\\': /* fallthrough */
6835 case '\?': dlen += 2; break;
6836 default: if((src[i] > ' ') && (src[i] <= '~')) /* no white spaces in output */
6837 {
6838 dlen++;
6839 }
6840 else
6841 {
6842 dlen += 4;
6843 }
6844 break;
6845 }
6846 }
6847
6848 return(dlen);
6849 }
6850
6851
fstUtilityBinToEsc(unsigned char * d,const unsigned char * s,int len)6852 int fstUtilityBinToEsc(unsigned char *d, const unsigned char *s, int len)
6853 {
6854 const unsigned char *src = s;
6855 unsigned char *dst = d;
6856 unsigned char val;
6857 int i;
6858
6859 for(i=0;i<len;i++)
6860 {
6861 switch(src[i])
6862 {
6863 case '\a': *(dst++) = '\\'; *(dst++) = 'a'; break;
6864 case '\b': *(dst++) = '\\'; *(dst++) = 'b'; break;
6865 case '\f': *(dst++) = '\\'; *(dst++) = 'f'; break;
6866 case '\n': *(dst++) = '\\'; *(dst++) = 'n'; break;
6867 case '\r': *(dst++) = '\\'; *(dst++) = 'r'; break;
6868 case '\t': *(dst++) = '\\'; *(dst++) = 't'; break;
6869 case '\v': *(dst++) = '\\'; *(dst++) = 'v'; break;
6870 case '\'': *(dst++) = '\\'; *(dst++) = '\''; break;
6871 case '\"': *(dst++) = '\\'; *(dst++) = '\"'; break;
6872 case '\\': *(dst++) = '\\'; *(dst++) = '\\'; break;
6873 case '\?': *(dst++) = '\\'; *(dst++) = '\?'; break;
6874 default: if((src[i] > ' ') && (src[i] <= '~')) /* no white spaces in output */
6875 {
6876 *(dst++) = src[i];
6877 }
6878 else
6879 {
6880 val = src[i];
6881 *(dst++) = '\\';
6882 *(dst++) = (val/64) + '0'; val = val & 63;
6883 *(dst++) = (val/8) + '0'; val = val & 7;
6884 *(dst++) = (val) + '0';
6885 }
6886 break;
6887 }
6888 }
6889
6890 return(dst - d);
6891 }
6892
6893
6894 /*
6895 * this overwrites the original string if the destination pointer is NULL
6896 */
fstUtilityEscToBin(unsigned char * d,unsigned char * s,int len)6897 int fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len)
6898 {
6899 unsigned char *src = s;
6900 unsigned char *dst = (!d) ? s : (s = d);
6901 unsigned char val[3];
6902 int i;
6903
6904 for(i=0;i<len;i++)
6905 {
6906 if(src[i] != '\\')
6907 {
6908 *(dst++) = src[i];
6909 }
6910 else
6911 {
6912 switch(src[++i])
6913 {
6914 case 'a': *(dst++) = '\a'; break;
6915 case 'b': *(dst++) = '\b'; break;
6916 case 'f': *(dst++) = '\f'; break;
6917 case 'n': *(dst++) = '\n'; break;
6918 case 'r': *(dst++) = '\r'; break;
6919 case 't': *(dst++) = '\t'; break;
6920 case 'v': *(dst++) = '\v'; break;
6921 case '\'': *(dst++) = '\''; break;
6922 case '\"': *(dst++) = '\"'; break;
6923 case '\\': *(dst++) = '\\'; break;
6924 case '\?': *(dst++) = '\?'; break;
6925
6926 case 'x': val[0] = toupper(src[++i]);
6927 val[1] = toupper(src[++i]);
6928 val[0] = ((val[0]>='A')&&(val[0]<='F')) ? (val[0] - 'A' + 10) : (val[0] - '0');
6929 val[1] = ((val[1]>='A')&&(val[1]<='F')) ? (val[1] - 'A' + 10) : (val[1] - '0');
6930 *(dst++) = val[0] * 16 + val[1];
6931 break;
6932
6933 case '0':
6934 case '1':
6935 case '2':
6936 case '3':
6937 case '4':
6938 case '5':
6939 case '6':
6940 case '7': val[0] = src[ i] - '0';
6941 val[1] = src[++i] - '0';
6942 val[2] = src[++i] - '0';
6943 *(dst++) = val[0] * 64 + val[1] * 8 + val[2];
6944 break;
6945
6946 default: *(dst++) = src[i]; break;
6947 }
6948 }
6949 }
6950
6951 return(dst - s);
6952 }
6953
6954
fstUtilityExtractEnumTableFromString(const char * s)6955 struct fstETab *fstUtilityExtractEnumTableFromString(const char *s)
6956 {
6957 struct fstETab *et = NULL;
6958 int num_spaces = 0;
6959 int i;
6960 int newlen;
6961
6962 if(s)
6963 {
6964 const char *csp = strchr(s, ' ');
6965 int cnt = atoi(csp+1);
6966
6967 for(;;)
6968 {
6969 csp = strchr(csp+1, ' ');
6970 if(csp) { num_spaces++; } else { break; }
6971 }
6972
6973 if(num_spaces == (2*cnt))
6974 {
6975 char *sp, *sp2;
6976
6977 et = (struct fstETab*)calloc(1, sizeof(struct fstETab));
6978 et->elem_count = cnt;
6979 et->name = strdup(s);
6980 et->literal_arr = (char**)calloc(cnt, sizeof(char *));
6981 et->val_arr = (char**)calloc(cnt, sizeof(char *));
6982
6983 sp = strchr(et->name, ' ');
6984 *sp = 0;
6985
6986 sp = strchr(sp+1, ' ');
6987
6988 for(i=0;i<cnt;i++)
6989 {
6990 sp2 = strchr(sp+1, ' ');
6991 *(char*)sp2 = 0;
6992 et->literal_arr[i] = sp+1;
6993 sp = sp2;
6994
6995 newlen = fstUtilityEscToBin(NULL, (unsigned char*)et->literal_arr[i], strlen(et->literal_arr[i]));
6996 et->literal_arr[i][newlen] = 0;
6997 }
6998
6999 for(i=0;i<cnt;i++)
7000 {
7001 sp2 = strchr(sp+1, ' ');
7002 if(sp2) { *sp2 = 0; }
7003 et->val_arr[i] = sp+1;
7004 sp = sp2;
7005
7006 newlen = fstUtilityEscToBin(NULL, (unsigned char*)et->val_arr[i], strlen(et->val_arr[i]));
7007 et->val_arr[i][newlen] = 0;
7008 }
7009 }
7010 }
7011
7012 return(et);
7013 }
7014
7015
fstUtilityFreeEnumTable(struct fstETab * etab)7016 void fstUtilityFreeEnumTable(struct fstETab *etab)
7017 {
7018 if(etab)
7019 {
7020 free(etab->literal_arr);
7021 free(etab->val_arr);
7022 free(etab->name);
7023 free(etab);
7024 }
7025 }
7026