From f11ba81202c0d44377204024de8d66f21e888433 Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 21 May 2010 15:04:17 -0700 Subject: [PATCH] Add initial fst support. This patch is a slight modification to files Tony Bybell (the author of GTKWave) send to me. We still have a few more changes we plan to make, but this should be functional enough for initial testing. Multi-treading and speed/size flags will be added shortly. --- vpi/Makefile.in | 1 + vpi/fastlz.c | 547 +++++++ vpi/fastlz.h | 107 ++ vpi/fstapi.c | 4186 +++++++++++++++++++++++++++++++++++++++++++++++ vpi/fstapi.h | 219 +++ vpi/sys_fst.c | 868 ++++++++++ vpi/sys_table.c | 18 +- vvp/vvp.man.in | 13 +- 8 files changed, 5953 insertions(+), 6 deletions(-) create mode 100644 vpi/fastlz.c create mode 100644 vpi/fastlz.h create mode 100644 vpi/fstapi.c create mode 100644 vpi/fstapi.h create mode 100644 vpi/sys_fst.c diff --git a/vpi/Makefile.in b/vpi/Makefile.in index 371d5c8da..383e12d43 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -73,6 +73,7 @@ ifeq (@HAVE_LIBBZ2@,yes) O += sys_lxt.o lxt_write.o endif O += sys_lxt2.o lxt2_write.o +O += sys_fst.o fstapi.o fastlz.o endif # Object files for v2005_math.vpi diff --git a/vpi/fastlz.c b/vpi/fastlz.c new file mode 100644 index 000000000..8e14ecfc0 --- /dev/null +++ b/vpi/fastlz.c @@ -0,0 +1,547 @@ +/* + FastLZ - lightning-fast lossless compression library + + Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) + Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) + Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "fastlz.h" + +#if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) + +/* + * Always check for bound when decompressing. + * Generally it is best to leave it defined. + */ +#define FASTLZ_SAFE + + +/* + * Give hints to the compiler for branch prediction optimization. + */ +#if defined(__GNUC__) && (__GNUC__ > 2) +#define FASTLZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1)) +#define FASTLZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0)) +#else +#define FASTLZ_EXPECT_CONDITIONAL(c) (c) +#define FASTLZ_UNEXPECT_CONDITIONAL(c) (c) +#endif + +/* + * Use inlined functions for supported systems. + */ +#if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) || defined(__WATCOMC__) || defined(__SUNPRO_C) +#define FASTLZ_INLINE inline +#elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__) +#define FASTLZ_INLINE __inline +#else +#define FASTLZ_INLINE +#endif + +/* + * Prevent accessing more than 8-bit at once, except on x86 architectures. + */ +#if !defined(FASTLZ_STRICT_ALIGN) +#define FASTLZ_STRICT_ALIGN +#if defined(__i386__) || defined(__386) /* GNU C, Sun Studio */ +#undef FASTLZ_STRICT_ALIGN +#elif defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__amd64) /* GNU C */ +#undef FASTLZ_STRICT_ALIGN +#elif defined(_M_IX86) /* Intel, MSVC */ +#undef FASTLZ_STRICT_ALIGN +#elif defined(__386) +#undef FASTLZ_STRICT_ALIGN +#elif defined(_X86_) /* MinGW */ +#undef FASTLZ_STRICT_ALIGN +#elif defined(__I86__) /* Digital Mars */ +#undef FASTLZ_STRICT_ALIGN +#endif +#endif + +/* prototypes */ +int fastlz_compress(const void* input, int length, void* output); +int fastlz_compress_level(int level, const void* input, int length, void* output); +int fastlz_decompress(const void* input, int length, void* output, int maxout); + +#define MAX_COPY 32 +#define MAX_LEN 264 /* 256 + 8 */ +#define MAX_DISTANCE 8192 + +#if !defined(FASTLZ_STRICT_ALIGN) +#define FASTLZ_READU16(p) *((const flzuint16*)(p)) +#else +#define FASTLZ_READU16(p) ((p)[0] | (p)[1]<<8) +#endif + +#define HASH_LOG 13 +#define HASH_SIZE (1<< HASH_LOG) +#define HASH_MASK (HASH_SIZE-1) +#define HASH_FUNCTION(v,p) { v = FASTLZ_READU16(p); v ^= FASTLZ_READU16(p+1)^(v>>(16-HASH_LOG));v &= HASH_MASK; } + +#undef FASTLZ_LEVEL +#define FASTLZ_LEVEL 1 + +#undef FASTLZ_COMPRESSOR +#undef FASTLZ_DECOMPRESSOR +#define FASTLZ_COMPRESSOR fastlz1_compress +#define FASTLZ_DECOMPRESSOR fastlz1_decompress +static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); +static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); +#include "fastlz.c" + +#undef FASTLZ_LEVEL +#define FASTLZ_LEVEL 2 + +#undef MAX_DISTANCE +#define MAX_DISTANCE 8191 +#define MAX_FARDISTANCE (65535+MAX_DISTANCE-1) + +#undef FASTLZ_COMPRESSOR +#undef FASTLZ_DECOMPRESSOR +#define FASTLZ_COMPRESSOR fastlz2_compress +#define FASTLZ_DECOMPRESSOR fastlz2_decompress +static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); +static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); +#include "fastlz.c" + +int fastlz_compress(const void* input, int length, void* output) +{ + /* for short block, choose fastlz1 */ + if(length < 65536) + return fastlz1_compress(input, length, output); + + /* else... */ + return fastlz2_compress(input, length, output); +} + +int fastlz_decompress(const void* input, int length, void* output, int maxout) +{ + /* magic identifier for compression level */ + int level = ((*(const flzuint8*)input) >> 5) + 1; + + if(level == 1) + return fastlz1_decompress(input, length, output, maxout); + if(level == 2) + return fastlz2_decompress(input, length, output, maxout); + + /* unknown level, trigger error */ + return 0; +} + +int fastlz_compress_level(int level, const void* input, int length, void* output) +{ + if(level == 1) + return fastlz1_compress(input, length, output); + if(level == 2) + return fastlz2_compress(input, length, output); + + return 0; +} + +#else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ + +static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output) +{ + const flzuint8* ip = (const flzuint8*) input; + const flzuint8* ip_bound = ip + length - 2; + const flzuint8* ip_limit = ip + length - 12; + flzuint8* op = (flzuint8*) output; + + const flzuint8* htab[HASH_SIZE]; + const flzuint8** hslot; + flzuint32 hval; + + flzuint32 copy; + + /* sanity check */ + if(FASTLZ_UNEXPECT_CONDITIONAL(length < 4)) + { + if(length) + { + /* create literal copy only */ + *op++ = length-1; + ip_bound++; + while(ip <= ip_bound) + *op++ = *ip++; + return length+1; + } + else + return 0; + } + + /* initializes hash table */ + for (hslot = htab; hslot < htab + HASH_SIZE; hslot++) + *hslot = ip; + + /* we start with literal copy */ + copy = 2; + *op++ = MAX_COPY-1; + *op++ = *ip++; + *op++ = *ip++; + + /* main loop */ + while(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) + { + const flzuint8* ref; + flzuint32 distance; + + /* minimum match length */ + flzuint32 len = 3; + + /* comparison starting-point */ + const flzuint8* anchor = ip; + + /* check for a run */ +#if FASTLZ_LEVEL==2 + if(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1)) + { + distance = 1; + ip += 3; + ref = anchor - 1 + 3; + goto match; + } +#endif + + /* find potential match */ + HASH_FUNCTION(hval,ip); + hslot = htab + hval; + ref = htab[hval]; + + /* calculate distance to the match */ + distance = anchor - ref; + + /* update hash table */ + *hslot = anchor; + + /* is this a match? check the first 3 bytes */ + if(distance==0 || +#if FASTLZ_LEVEL==1 + (distance >= MAX_DISTANCE) || +#else + (distance >= MAX_FARDISTANCE) || +#endif + *ref++ != *ip++ || *ref++!=*ip++ || *ref++!=*ip++) + goto literal; + +#if FASTLZ_LEVEL==2 + /* far, needs at least 5-byte match */ + if(distance >= MAX_DISTANCE) + { + if(*ip++ != *ref++ || *ip++!= *ref++) + goto literal; + len += 2; + } + + match: +#endif + + /* last matched byte */ + ip = anchor + len; + + /* distance is biased */ + distance--; + + if(!distance) + { + /* zero distance means a run */ + flzuint8 x = ip[-1]; + while(ip < ip_bound) + if(*ref++ != x) break; else ip++; + } + else + for(;;) + { + /* safe because the outer check against ip limit */ + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + while(ip < ip_bound) + if(*ref++ != *ip++) break; + break; + } + + /* if we have copied something, adjust the copy count */ + if(copy) + /* copy is biased, '0' means 1 byte copy */ + *(op-copy-1) = copy-1; + else + /* back, to overwrite the copy count */ + op--; + + /* reset literal counter */ + copy = 0; + + /* length is biased, '1' means a match of 3 bytes */ + ip -= 3; + len = ip - anchor; + + /* encode the match */ +#if FASTLZ_LEVEL==2 + if(distance < MAX_DISTANCE) + { + if(len < 7) + { + *op++ = (len << 5) + (distance >> 8); + *op++ = (distance & 255); + } + else + { + *op++ = (7 << 5) + (distance >> 8); + for(len-=7; len >= 255; len-= 255) + *op++ = 255; + *op++ = len; + *op++ = (distance & 255); + } + } + else + { + /* far away, but not yet in the another galaxy... */ + if(len < 7) + { + distance -= MAX_DISTANCE; + *op++ = (len << 5) + 31; + *op++ = 255; + *op++ = distance >> 8; + *op++ = distance & 255; + } + else + { + distance -= MAX_DISTANCE; + *op++ = (7 << 5) + 31; + for(len-=7; len >= 255; len-= 255) + *op++ = 255; + *op++ = len; + *op++ = 255; + *op++ = distance >> 8; + *op++ = distance & 255; + } + } +#else + + if(FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN-2)) + while(len > MAX_LEN-2) + { + *op++ = (7 << 5) + (distance >> 8); + *op++ = MAX_LEN - 2 - 7 -2; + *op++ = (distance & 255); + len -= MAX_LEN-2; + } + + if(len < 7) + { + *op++ = (len << 5) + (distance >> 8); + *op++ = (distance & 255); + } + else + { + *op++ = (7 << 5) + (distance >> 8); + *op++ = len - 7; + *op++ = (distance & 255); + } +#endif + + /* update the hash at match boundary */ + HASH_FUNCTION(hval,ip); + htab[hval] = ip++; + HASH_FUNCTION(hval,ip); + htab[hval] = ip++; + + /* assuming literal copy */ + *op++ = MAX_COPY-1; + + continue; + + literal: + *op++ = *anchor++; + ip = anchor; + copy++; + if(FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY)) + { + copy = 0; + *op++ = MAX_COPY-1; + } + } + + /* left-over as literal copy */ + ip_bound++; + while(ip <= ip_bound) + { + *op++ = *ip++; + copy++; + if(copy == MAX_COPY) + { + copy = 0; + *op++ = MAX_COPY-1; + } + } + + /* if we have copied something, adjust the copy length */ + if(copy) + *(op-copy-1) = copy-1; + else + op--; + +#if FASTLZ_LEVEL==2 + /* marker for fastlz2 */ + *(flzuint8*)output |= (1 << 5); +#endif + + return op - (flzuint8*)output; +} + +static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout) +{ + const flzuint8* ip = (const flzuint8*) input; + const flzuint8* ip_limit = ip + length; + flzuint8* op = (flzuint8*) output; + flzuint8* op_limit = op + maxout; + flzuint32 ctrl = (*ip++) & 31; + int loop = 1; + + do + { + const flzuint8* ref = op; + flzuint32 len = ctrl >> 5; + flzuint32 ofs = (ctrl & 31) << 8; + + if(ctrl >= 32) + { +#if FASTLZ_LEVEL==2 + flzuint8 code; +#endif + len--; + ref -= ofs; + if (len == 7-1) +#if FASTLZ_LEVEL==1 + len += *ip++; + ref -= *ip++; +#else + do + { + code = *ip++; + len += code; + } while (code==255); + code = *ip++; + ref -= code; + + /* match from 16-bit distance */ + if(FASTLZ_UNEXPECT_CONDITIONAL(code==255)) + if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8))) + { + ofs = (*ip++) << 8; + ofs += *ip++; + ref = op - ofs - MAX_DISTANCE; + } +#endif + +#ifdef FASTLZ_SAFE + if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit)) + return 0; + + if (FASTLZ_UNEXPECT_CONDITIONAL(ref-1 < (flzuint8 *)output)) + return 0; +#endif + + if(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) + ctrl = *ip++; + else + loop = 0; + + if(ref == op) + { + /* optimize copy for a run */ + flzuint8 b = ref[-1]; + *op++ = b; + *op++ = b; + *op++ = b; + for(; len; --len) + *op++ = b; + } + else + { +#if !defined(FASTLZ_STRICT_ALIGN) + const flzuint16* p; + flzuint16* q; +#endif + /* copy from reference */ + ref--; + *op++ = *ref++; + *op++ = *ref++; + *op++ = *ref++; + +#if !defined(FASTLZ_STRICT_ALIGN) + /* copy a byte, so that now it's word aligned */ + if(len & 1) + { + *op++ = *ref++; + len--; + } + + /* copy 16-bit at once */ + q = (flzuint16*) op; + op += len; + p = (const flzuint16*) ref; + for(len>>=1; len > 4; len-=4) + { + *q++ = *p++; + *q++ = *p++; + *q++ = *p++; + *q++ = *p++; + } + for(; len; --len) + *q++ = *p++; +#else + for(; len; --len) + *op++ = *ref++; +#endif + } + } + else + { + ctrl++; +#ifdef FASTLZ_SAFE + if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit)) + return 0; + if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit)) + return 0; +#endif + + *op++ = *ip++; + for(--ctrl; ctrl; ctrl--) + *op++ = *ip++; + + loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit); + if(loop) + ctrl = *ip++; + } + } + while(FASTLZ_EXPECT_CONDITIONAL(loop)); + + return op - (flzuint8*)output; +} + +#endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ diff --git a/vpi/fastlz.h b/vpi/fastlz.h new file mode 100644 index 000000000..e0512c190 --- /dev/null +++ b/vpi/fastlz.h @@ -0,0 +1,107 @@ +/* + FastLZ - lightning-fast lossless compression library + + Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) + Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) + Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef FASTLZ_H +#define FASTLZ_H + +#include + +#define flzuint8 uint8_t +#define flzuint16 uint16_t +#define flzuint32 uint32_t + + +#define FASTLZ_VERSION 0x000100 + +#define FASTLZ_VERSION_MAJOR 0 +#define FASTLZ_VERSION_MINOR 0 +#define FASTLZ_VERSION_REVISION 0 + +#define FASTLZ_VERSION_STRING "0.1.0" + +#if defined (__cplusplus) +extern "C" { +#endif + +/** + Compress a block of data in the input buffer and returns the size of + compressed block. The size of input buffer is specified by length. The + minimum input buffer size is 16. + + The output buffer must be at least 5% larger than the input buffer + and can not be smaller than 66 bytes. + + If the input is not compressible, the return value might be larger than + length (input buffer size). + + The input buffer and the output buffer can not overlap. +*/ + +int fastlz_compress(const void* input, int length, void* output); + +/** + Decompress a block of compressed data and returns the size of the + decompressed block. If error occurs, e.g. the compressed data is + corrupted or the output buffer is not large enough, then 0 (zero) + will be returned instead. + + The input buffer and the output buffer can not overlap. + + Decompression is memory safe and guaranteed not to write the output buffer + more than what is specified in maxout. + */ + +int fastlz_decompress(const void* input, int length, void* output, int maxout); + +/** + Compress a block of data in the input buffer and returns the size of + compressed block. The size of input buffer is specified by length. The + minimum input buffer size is 16. + + The output buffer must be at least 5% larger than the input buffer + and can not be smaller than 66 bytes. + + If the input is not compressible, the return value might be larger than + length (input buffer size). + + The input buffer and the output buffer can not overlap. + + Compression level can be specified in parameter level. At the moment, + only level 1 and level 2 are supported. + Level 1 is the fastest compression and generally useful for short data. + Level 2 is slightly slower but it gives better compression ratio. + + Note that the compressed data, regardless of the level, can always be + decompressed using the function fastlz_decompress above. +*/ + +int fastlz_compress_level(int level, const void* input, int length, void* output); + +#if defined (__cplusplus) +} +#endif + +#endif /* FASTLZ_H */ diff --git a/vpi/fstapi.c b/vpi/fstapi.c new file mode 100644 index 000000000..ea23d6b35 --- /dev/null +++ b/vpi/fstapi.c @@ -0,0 +1,4186 @@ +/* + * Copyright (c) 2009-2010 Tony Bybell. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "fstapi.h" +#include "fastlz.h" + +#undef FST_DEBUG + +#define FST_BREAK_SIZE (32 * 1024 * 1024) +#define FST_WRITER_STR "fstWriter" +#define FST_ID_NAM_SIZ (512) +#define FST_DOUBLE_ENDTEST (2.7182818284590452354) +#define FST_HDR_SIM_VERSION_SIZE (128) +#define FST_HDR_DATE_SIZE (128) +#define FST_GZIO_LEN (32768) + + +#if defined(__i386__) || defined(__x86_64__) || defined(_AIX) +#define FST_DO_MISALIGNED_OPS +#endif + + +/***********************/ +/*** ***/ +/*** common function ***/ +/*** ***/ +/***********************/ + +#ifdef __MINGW32__ +#include +#define ftello ftell +#define fseeko fseek +#endif + + +/* the recoded "extra" values... */ +#define FST_RCV_X (1 | (0<<1)) +#define FST_RCV_Z (1 | (1<<1)) +#define FST_RCV_H (1 | (2<<1)) +#define FST_RCV_U (1 | (3<<1)) +#define FST_RCV_W (1 | (4<<1)) +#define FST_RCV_L (1 | (5<<1)) +#define FST_RCV_D (1 | (6<<1)) + +#define FST_RCV_STR "xzhuwl-?" +/* 01234567 */ + + +/* + * to remove warn_unused_result compile time messages + * (in the future there needs to be results checking) + */ +static size_t fstFread(void *buf, size_t siz, size_t cnt, FILE *fp) +{ +return(fread(buf, siz, cnt, fp)); +} + +static size_t fstFwrite(const void *buf, size_t siz, size_t cnt, FILE *fp) +{ +return(fwrite(buf, siz, cnt, fp)); +} + +static int fstFtruncate(int fd, off_t length) +{ +return(ftruncate(fd, length)); +} + + +/* + * mmap compatibility + */ +#if defined __CYGWIN__ || defined __MINGW32__ +#include +#define fstMmap(__addr,__len,__prot,__flags,__fd,__off) fstMmap2((__len), (__fd), (__off)) +#define fstMunmap(__addr,__len) free(__addr) + +static void *fstMmap2(size_t __len, int __fd, off_t __off) +{ +unsigned char *pnt = malloc(__len); +off_t cur_offs = lseek(__fd, 0, SEEK_CUR); +size_t i; + +lseek(__fd, 0, SEEK_SET); +for(i=0;i<__len;i+=SSIZE_MAX) + { + read(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i)); + } +lseek(__fd, cur_offs, SEEK_SET); +return(pnt); +} +#else +#include +#define fstMmap(__addr,__len,__prot,__flags,__fd,__off) mmap((__addr),(__len),(__prot),(__flags),(__fd),(__off)) +#define fstMunmap(__addr,__len) munmap((__addr),(__len)) +#endif + + +/* + * regular and variable-length integer access functions + */ +#ifdef FST_DO_MISALIGNED_OPS +#define fstGetUint32(x) (*(uint32_t *)(x)) +#define fstWriterSetUint32(x,y) (*(uint32_t *)(x)) = (y) +#else +static uint32_t fstGetUint32(unsigned char *mem) +{ +uint32_t u32; +unsigned char *buf = (unsigned char *)(&u32); + +buf[0] = mem[0]; +buf[1] = mem[1]; +buf[2] = mem[2]; +buf[3] = mem[3]; + +return(*(uint32_t *)buf); +} + + +static void fstWriterSetUint32(unsigned char *mem, uint32_t u32) +{ +unsigned char *buf = (unsigned char *)(&u32); + +mem[0] = buf[0]; +mem[1] = buf[1]; +mem[2] = buf[2]; +mem[3] = buf[3]; +} +#endif + + +static int fstWriterUint64(FILE *handle, uint64_t v) +{ +unsigned char buf[8]; +int i; + +for(i=7;i>=0;i--) + { + buf[i] = v & 0xff; + v >>= 8; + } + +fstFwrite(buf, 8, 1, handle); +return(8); +} + + +static uint64_t fstReaderUint64(FILE *f) +{ +uint64_t val = 0; +unsigned char buf[sizeof(uint64_t)]; +int i; + +fstFread(buf, sizeof(uint64_t), 1, f); +for(i=0;i>7)) + { + *(spnt++) = (v&0x7f) | 0x80; + v = nxt; + } +*(spnt++) = (v&0x7f); + +do { + *(--pnt) = *(--spnt); + } while(spnt != buf); + +return(pnt); +} + + +static uint64_t fstGetVarint64(unsigned char *mem, int *skiplen) +{ +unsigned char *mem_orig = mem; +uint64_t rc = 0; +while(*mem & 0x80) + { + mem++; + } + +*skiplen = mem - mem_orig + 1; +for(;;) + { + rc <<= 7; + rc |= (uint64_t)(*mem & 0x7f); + if(mem == mem_orig) + { + break; + } + mem--; + } + +return(rc); +} + + +static uint32_t fstReaderVarint32(FILE *f) +{ +unsigned char buf[5]; +unsigned char *mem = buf; +uint32_t rc = 0; +int ch; + +do + { + ch = fgetc(f); + *(mem++) = ch; + } while(ch & 0x80); +mem--; + +for(;;) + { + rc <<= 7; + rc |= (uint32_t)(*mem & 0x7f); + if(mem == buf) + { + break; + } + mem--; + } + +return(rc); +} + + +static uint32_t fstReaderVarint32WithSkip(FILE *f, uint32_t *skiplen) +{ +unsigned char buf[5]; +unsigned char *mem = buf; +uint32_t rc = 0; +int ch; + +do + { + ch = fgetc(f); + *(mem++) = ch; + } while(ch & 0x80); +*skiplen = mem - buf; +mem--; + +for(;;) + { + rc <<= 7; + rc |= (uint32_t)(*mem & 0x7f); + if(mem == buf) + { + break; + } + mem--; + } + +return(rc); +} + + +static uint64_t fstReaderVarint64(FILE *f) +{ +unsigned char buf[16]; +unsigned char *mem = buf; +uint64_t rc = 0; +int ch; + +do + { + ch = fgetc(f); + *(mem++) = ch; + } while(ch & 0x80); +mem--; + +for(;;) + { + rc <<= 7; + rc |= (uint64_t)(*mem & 0x7f); + if(mem == buf) + { + break; + } + mem--; + } + +return(rc); +} + + +static int fstWriterVarint(FILE *handle, uint64_t v) +{ +uint64_t nxt; +unsigned char buf[32]; +unsigned char *pnt = buf; +int len; + +while((nxt = v>>7)) + { + *(pnt++) = (v&0x7f) | 0x80; + v = nxt; + } +*(pnt++) = (v&0x7f); + +len = pnt-buf; +fstFwrite(buf, len, 1, handle); +return(len); +} + + +/***********************/ +/*** ***/ +/*** writer function ***/ +/*** ***/ +/***********************/ + +/* + * private structs + */ +struct fstBlackoutChain +{ +struct fstBlackoutChain *next; +uint64_t tim; +unsigned active : 1; +}; + + +struct fstWriterContext +{ +FILE *handle; +FILE *hier_handle; +FILE *geom_handle; +FILE *valpos_handle; +FILE *curval_handle; +FILE *vchn_handle; +FILE *tchn_handle; + +off_t hier_file_len; + +uint32_t *valpos_mem; +unsigned char *curval_mem; + +char *filename; + +fstHandle maxhandle; +fstHandle numsigs; +uint32_t maxvalpos; + +unsigned vc_emitted : 1; +unsigned is_initial_time : 1; +unsigned fastpack : 1; + +off_t section_header_truncpos; +uint32_t tchn_cnt, tchn_idx; +uint64_t curtime; +uint64_t firsttime; +off_t vchn_siz; + +uint32_t secnum; +off_t section_start; + +uint32_t numscopes; +double nan; /* nan value for uninitialized doubles */ + +struct fstBlackoutChain *blackout_head; +struct fstBlackoutChain *blackout_curr; +uint32_t num_blackouts; + +uint64_t dump_size_limit; + +unsigned compress_hier : 1; +unsigned repack_on_close : 1; +unsigned skip_writing_section_hdr : 1; +unsigned size_limit_locked : 1; + +/* should really be semaphores, but are bytes to cut down on read-modify-write window size */ +unsigned char already_in_flush; /* in case control-c handlers interrupt */ +unsigned char already_in_close; /* in case control-c handlers interrupt */ +}; + + +/* + * header bytes, write here so defines are set up before anything else + * that needs to use them + */ +static void fstWriterEmitHdrBytes(struct fstWriterContext *xc) +{ +char vbuf[FST_HDR_SIM_VERSION_SIZE]; +char dbuf[FST_HDR_DATE_SIZE]; +double endtest = FST_DOUBLE_ENDTEST; +time_t walltime; + +#define FST_HDR_OFFS_TAG (0) +fputc(FST_BL_HDR, xc->handle); /* +0 tag */ + +#define FST_HDR_OFFS_SECLEN (FST_HDR_OFFS_TAG + 1) +fstWriterUint64(xc->handle, 329); /* +1 section length */ + +#define FST_HDR_OFFS_START_TIME (FST_HDR_OFFS_SECLEN + 8) +fstWriterUint64(xc->handle, 0); /* +9 start time */ + +#define FST_HDR_OFFS_END_TIME (FST_HDR_OFFS_START_TIME + 8) +fstWriterUint64(xc->handle, 0); /* +17 end time */ + +#define FST_HDR_OFFS_ENDIAN_TEST (FST_HDR_OFFS_END_TIME + 8) +fstFwrite(&endtest, 8, 1, xc->handle); /* +25 endian test for reals */ + +#define FST_HDR_OFFS_MEM_USED (FST_HDR_OFFS_ENDIAN_TEST + 8) +fstWriterUint64(xc->handle, FST_BREAK_SIZE); /* +33 memory used by writer */ + +#define FST_HDR_OFFS_NUM_SCOPES (FST_HDR_OFFS_MEM_USED + 8) +fstWriterUint64(xc->handle, 0); /* +41 scope creation count */ + +#define FST_HDR_OFFS_NUM_VARS (FST_HDR_OFFS_NUM_SCOPES + 8) +fstWriterUint64(xc->handle, 0); /* +49 var creation count */ + +#define FST_HDR_OFFS_MAXHANDLE (FST_HDR_OFFS_NUM_VARS + 8) +fstWriterUint64(xc->handle, 0); /* +57 max var idcode */ + +#define FST_HDR_OFFS_SECTION_CNT (FST_HDR_OFFS_MAXHANDLE + 8) +fstWriterUint64(xc->handle, 0); /* +65 vc section count */ + +#define FST_HDR_OFFS_TIMESCALE (FST_HDR_OFFS_SECTION_CNT + 8) +fputc((-9)&255, xc->handle); /* +73 timescale 1ns */ + +#define FST_HDR_OFFS_SIM_VERSION (FST_HDR_OFFS_TIMESCALE + 1) +memset(vbuf, 0, FST_HDR_SIM_VERSION_SIZE); +strcpy(vbuf, FST_WRITER_STR); +fstFwrite(vbuf, FST_HDR_SIM_VERSION_SIZE, 1, xc->handle); /* +74 version */ + +#define FST_HDR_OFFS_DATE (FST_HDR_OFFS_SIM_VERSION + FST_HDR_SIM_VERSION_SIZE) +memset(dbuf, 0, FST_HDR_DATE_SIZE); +time(&walltime); +strcpy(dbuf, asctime(localtime(&walltime))); +fstFwrite(dbuf, FST_HDR_DATE_SIZE, 1, xc->handle); /* +202 date */ + +#define FST_HDR_LENGTH (FST_HDR_OFFS_DATE + FST_HDR_DATE_SIZE) + /* +330 next section starts here */ +fflush(xc->handle); +} + + +/* + * mmap functions + */ +static void fstWriterCreateMmaps(struct fstWriterContext *xc) +{ +off_t curpos = ftello(xc->handle); + +fflush(xc->hier_handle); + +/* write out intermediate header */ +fseeko(xc->handle, FST_HDR_OFFS_START_TIME, SEEK_SET); +fstWriterUint64(xc->handle, xc->firsttime); +fstWriterUint64(xc->handle, xc->curtime); +fseeko(xc->handle, FST_HDR_OFFS_NUM_SCOPES, SEEK_SET); +fstWriterUint64(xc->handle, xc->numscopes); +fstWriterUint64(xc->handle, xc->numsigs); +fstWriterUint64(xc->handle, xc->maxhandle); +fstWriterUint64(xc->handle, xc->secnum); +fseeko(xc->handle, curpos, SEEK_SET); +fflush(xc->handle); + +/* do mappings */ +if(!xc->valpos_mem) + { + fflush(xc->valpos_handle); + xc->valpos_mem = fstMmap(NULL, xc->maxhandle * 4 * sizeof(uint32_t), PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->valpos_handle), 0); + } +if(!xc->curval_mem) + { + fflush(xc->curval_handle); + xc->curval_mem = fstMmap(NULL, xc->maxvalpos, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->curval_handle), 0); + } +} + + +static void fstDestroyMmaps(struct fstWriterContext *xc) +{ +if(xc->valpos_mem) + { + fstMunmap(xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t)); + xc->valpos_mem = NULL; + } +if(xc->curval_mem) + { + fstMunmap(xc->curval_mem, xc->maxvalpos); + xc->curval_mem = NULL; + } +} + + +/* + * file creation and close + */ +void *fstWriterCreate(const char *nam, int use_compressed_hier) +{ +struct fstWriterContext *xc = calloc(1, sizeof(struct fstWriterContext)); + +xc->compress_hier = use_compressed_hier; + +if((!nam)||(!(xc->handle=fopen(nam, "w+b")))) + { + free(xc); + xc=NULL; + } + else + { + int flen = strlen(nam); + char *hf = calloc(1, flen + 6); + + memcpy(hf, nam, flen); + strcpy(hf + flen, ".hier"); + xc->hier_handle = fopen(hf, "w+b"); + + xc->geom_handle = tmpfile(); /* .geom */ + xc->valpos_handle = tmpfile(); /* .offs */ + xc->curval_handle = tmpfile(); /* .bits */ + xc->vchn_handle = tmpfile(); /* .vchn */ + xc->tchn_handle = tmpfile(); /* .tchn */ + + free(hf); + if(xc->hier_handle && xc->geom_handle && xc->valpos_handle && xc->curval_handle && xc->vchn_handle && xc->tchn_handle) + { + xc->filename = strdup(nam); + xc->is_initial_time = 1; + + fstWriterEmitHdrBytes(xc); + xc->nan = strtod("NaN", NULL); + } + else + { + if(xc->hier_handle) fclose(xc->hier_handle); + if(xc->geom_handle) fclose(xc->geom_handle); + if(xc->valpos_handle) fclose(xc->valpos_handle); + if(xc->curval_handle) fclose(xc->curval_handle); + if(xc->vchn_handle) fclose(xc->vchn_handle); + if(xc->tchn_handle) fclose(xc->tchn_handle); + free(xc); + xc=NULL; + } + } + +return(xc); +} + + +void fstWriterClose(void *ctx) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc && !xc->already_in_close && !xc->already_in_flush) + { + unsigned char *tmem; + off_t fixup_offs, tlen, hlen; + + xc->already_in_close = 1; /* never need to zero this out as it is freed at bottom */ + + xc->skip_writing_section_hdr = 1; + if(!xc->size_limit_locked) + { + if(xc->is_initial_time) /* simulation time never advanced so mock up the changes as time zero ones */ + { + fstHandle dupe_idx; + + fstWriterEmitTimeChange(xc, 0); /* emit some time change just to have one */ + for(dupe_idx = 0; dupe_idx < xc->maxhandle; dupe_idx++) /* now clone the values */ + { + fstWriterEmitValueChange(xc, dupe_idx+1, xc->curval_mem + xc->valpos_mem[4*dupe_idx]); + } + } + fstWriterFlushContext(xc); + } + fstDestroyMmaps(xc); + + /* write out geom section */ + fflush(xc->geom_handle); + tlen = ftello(xc->geom_handle); + tmem = fstMmap(NULL, tlen, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->geom_handle), 0); + if(tmem) + { + unsigned long destlen = tlen; + unsigned char *dmem = malloc(destlen); + int rc = compress2(dmem, &destlen, tmem, tlen, 9); + + if((rc != Z_OK) || (destlen > tlen)) + { + destlen = tlen; + } + + fixup_offs = ftello(xc->handle); + fputc(FST_BL_SKIP, xc->handle); /* temporary tag */ + fstWriterUint64(xc->handle, destlen + 24); /* section length */ + fstWriterUint64(xc->handle, tlen); /* uncompressed */ + /* compressed len is section length - 24 */ + fstWriterUint64(xc->handle, xc->maxhandle); /* maxhandle */ + fstFwrite((destlen != tlen) ? dmem : tmem, destlen, 1, xc->handle); + fflush(xc->handle); + + fseeko(xc->handle, fixup_offs, SEEK_SET); + fputc(FST_BL_GEOM, xc->handle); /* actual tag */ + + fseeko(xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */ + fflush(xc->handle); + + free(dmem); + fstMunmap(tmem, tlen); + } + + if(xc->num_blackouts) + { + uint64_t cur_bl = 0; + off_t bpos, eos; + uint32_t i; + + fixup_offs = ftello(xc->handle); + fputc(FST_BL_SKIP, xc->handle); /* temporary tag */ + bpos = fixup_offs + 1; + fstWriterUint64(xc->handle, 0); /* section length */ + fstWriterVarint(xc->handle, xc->num_blackouts); + + for(i=0;inum_blackouts;i++) + { + fputc(xc->blackout_head->active, xc->handle); + fstWriterVarint(xc->handle, xc->blackout_head->tim - cur_bl); + cur_bl = xc->blackout_head->tim; + xc->blackout_curr = xc->blackout_head->next; + free(xc->blackout_head); + xc->blackout_head = xc->blackout_curr; + } + + eos = ftello(xc->handle); + fseeko(xc->handle, bpos, SEEK_SET); + fstWriterUint64(xc->handle, eos - bpos); + fflush(xc->handle); + + fseeko(xc->handle, fixup_offs, SEEK_SET); + fputc(FST_BL_BLACKOUT, xc->handle); /* actual tag */ + + fseeko(xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */ + fflush(xc->handle); + } + + if(xc->compress_hier) + { + unsigned char *mem = malloc(FST_GZIO_LEN); + off_t hl, eos; + gzFile zhandle; +#ifndef __MINGW32__ + char *fnam = malloc(strlen(xc->filename) + 5 + 1); +#endif + + fixup_offs = ftello(xc->handle); + fputc(FST_BL_SKIP, xc->handle); /* temporary tag */ + hlen = ftello(xc->handle); + fstWriterUint64(xc->handle, 0); /* section length */ + fstWriterUint64(xc->handle, xc->hier_file_len); /* uncompressed length */ + + fflush(xc->handle); + zhandle = gzdopen(dup(fileno(xc->handle)), "wb4"); + fseeko(xc->hier_handle, 0, SEEK_SET); + for(hl = 0; hl < xc->hier_file_len; hl += FST_GZIO_LEN) + { + unsigned len = ((xc->hier_file_len - hl) > FST_GZIO_LEN) ? FST_GZIO_LEN : (xc->hier_file_len - hl); + fstFread(mem, len, 1, xc->hier_handle); + gzwrite(zhandle, mem, len); + } + gzclose(zhandle); + free(mem); + + fseeko(xc->handle, 0, SEEK_END); + eos = ftello(xc->handle); + fseeko(xc->handle, hlen, SEEK_SET); + fstWriterUint64(xc->handle, eos - hlen); + fflush(xc->handle); + + fseeko(xc->handle, fixup_offs, SEEK_SET); + fputc(FST_BL_HIER, xc->handle); /* actual tag */ + + fseeko(xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */ + fflush(xc->handle); + +#ifndef __MINGW32__ + sprintf(fnam, "%s.hier", xc->filename); + unlink(fnam); + free(fnam); +#endif + } + + /* finalize out header */ + fseeko(xc->handle, FST_HDR_OFFS_START_TIME, SEEK_SET); + fstWriterUint64(xc->handle, xc->firsttime); + fstWriterUint64(xc->handle, xc->curtime); + fseeko(xc->handle, FST_HDR_OFFS_NUM_SCOPES, SEEK_SET); + fstWriterUint64(xc->handle, xc->numscopes); + fstWriterUint64(xc->handle, xc->numsigs); + fstWriterUint64(xc->handle, xc->maxhandle); + fstWriterUint64(xc->handle, xc->secnum); + fflush(xc->handle); + + if(xc->tchn_handle) { fclose(xc->tchn_handle); xc->tchn_handle = NULL; } + if(xc->vchn_handle) { fclose(xc->vchn_handle); xc->vchn_handle = NULL; } + if(xc->curval_handle) { fclose(xc->curval_handle); xc->curval_handle = NULL; } + if(xc->valpos_handle) { fclose(xc->valpos_handle); xc->valpos_handle = NULL; } + if(xc->geom_handle) { fclose(xc->geom_handle); xc->geom_handle = NULL; } + if(xc->hier_handle) { fclose(xc->hier_handle); xc->hier_handle = NULL; } + if(xc->handle) + { + if(xc->repack_on_close) + { + FILE *fp; + off_t offpnt, uclen; + int flen = strlen(xc->filename); + char *hf = calloc(1, flen + 5); + + strcpy(hf, xc->filename); + strcpy(hf+flen, ".pak"); + fp = fopen(hf, "wb"); + + if(fp) + { + void *dsth; + int rc; + char gz_membuf[FST_GZIO_LEN]; + + fseeko(xc->handle, 0, SEEK_END); + uclen = ftello(xc->handle); + + fputc(FST_BL_ZWRAPPER, fp); + fstWriterUint64(fp, 0); + fstWriterUint64(fp, uclen); + fflush(fp); + + fseeko(xc->handle, 0, SEEK_SET); + dsth = gzdopen(dup(fileno(fp)), "wb4"); + + for(offpnt = 0; offpnt < uclen; offpnt += FST_GZIO_LEN) + { + size_t this_len = ((uclen - offpnt) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - offpnt); + rc = fstFread(gz_membuf, this_len, 1, xc->handle); + gzwrite(dsth, gz_membuf, this_len); + } + gzclose(dsth); + fseeko(fp, 0, SEEK_END); + offpnt = ftello(fp); + fseeko(fp, 1, SEEK_SET); + fstWriterUint64(fp, offpnt - 1); + fclose(fp); + fclose(xc->handle); xc->handle = NULL; + + unlink(xc->filename); + rename(hf, xc->filename); + } + else + { + xc->repack_on_close = 0; + fclose(xc->handle); xc->handle = NULL; + } + + free(hf); + } + else + { + fclose(xc->handle); xc->handle = NULL; + } + } + +#ifdef __MINGW32__ + { + int flen = strlen(xc->filename); + char *hf = calloc(1, flen + 6); + strcpy(hf, xc->filename); + + if(xc->compress_hier) + { + strcpy(hf + flen, ".hier"); + unlink(hf); /* no longer needed as a section now exists for this */ + } + + free(hf); + } +#endif + + if(xc->filename) { free(xc->filename); xc->filename = NULL; } + + free(xc); + } +} + + +/* + * generation and writing out of value change data sections + */ +static void fstWriterEmitSectionHeader(void *ctx) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; + +if(xc) + { + unsigned long destlen; + unsigned char *dmem; + int rc; + + destlen = xc->maxvalpos; + dmem = malloc(destlen); + rc = compress2(dmem, &destlen, xc->curval_mem, xc->maxvalpos, 9); + + fputc(FST_BL_SKIP, xc->handle); /* temporarily tag the section, use FST_BL_VCDATA on finalize */ + xc->section_start = ftello(xc->handle); + fstWriterUint64(xc->handle, 0); /* placeholder = section length */ + fstWriterUint64(xc->handle, xc->is_initial_time ? xc->firsttime : xc->curtime); /* begin time of section */ + fstWriterUint64(xc->handle, xc->curtime); /* end time of section (placeholder) */ + fstWriterUint64(xc->handle, 0); /* placeholder = amount of buffer memory required in reader for full vc traversal */ + fstWriterVarint(xc->handle, xc->maxvalpos); /* maxvalpos = length of uncompressed data */ + + if((rc == Z_OK) && (destlen < xc->maxvalpos)) + { + fstWriterVarint(xc->handle, destlen); /* length of compressed data */ + } + else + { + fstWriterVarint(xc->handle, xc->maxvalpos); /* length of (unable to be) compressed data */ + } + fstWriterVarint(xc->handle, xc->maxhandle); /* max handle associated with this data (in case of dynamic facility adds) */ + + if((rc == Z_OK) && (destlen < xc->maxvalpos)) + { + fstFwrite(dmem, destlen, 1, xc->handle); + } + else /* comparison between compressed / decompressed len tells if compressed */ + { + fstFwrite(xc->curval_mem, xc->maxvalpos, 1, xc->handle); + } + + free(dmem); + } +} + + +void fstWriterFlushContext(void *ctx) +{ +#ifdef FST_DEBUG +int cnt = 0; +#endif +int i; +unsigned char *vchg_mem; +FILE *f; +off_t fpos, indxpos, endpos; +uint32_t prevpos; +int zerocnt; +unsigned char *scratchpad; +unsigned char *scratchpnt; +unsigned char *tmem; +off_t tlen; +off_t unc_memreq = 0; /* for reader */ +unsigned char *packmem; +unsigned int packmemlen; +uint32_t *vm4ip; + +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; + +if((!xc)||(xc->vchn_siz <= 1)||(xc->already_in_flush)) return; +xc->already_in_flush = 1; /* should really do this with a semaphore */ + +scratchpad = malloc(xc->vchn_siz); + +fflush(xc->vchn_handle); +vchg_mem = fstMmap(NULL, xc->vchn_siz, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->vchn_handle), 0); + +f = xc->handle; +fstWriterVarint(f, xc->maxhandle); /* emit current number of handles */ +fputc(xc->fastpack ? 'F' : 'Z', f); +fpos = 1; + +packmemlen = 1024; /* maintain a running "longest" allocation to */ +packmem = malloc(packmemlen); /* prevent continual malloc...free every loop iter */ + +for(i=0;imaxhandle;i++) + { + vm4ip = &(xc->valpos_mem[4*i]); + + if(vm4ip[2]) + { + uint32_t offs = vm4ip[2]; + uint32_t next_offs; + int wrlen; + + vm4ip[2] = fpos; + + scratchpnt = scratchpad + xc->vchn_siz; /* build this buffer backwards */ + if(vm4ip[1] == 1) + { + while(offs) + { + unsigned char val; + uint32_t time_delta, rcv; + next_offs = fstGetUint32(vchg_mem + offs); + offs += 4; + + time_delta = fstGetVarint32(vchg_mem + offs, &wrlen); + val = vchg_mem[offs+wrlen]; + offs = next_offs; + + switch(val) + { + case '0': + case '1': rcv = ((val&1)<<1) | (time_delta<<2); + break; /* pack more delta bits in for 0/1 vchs */ + + case 'x': case 'X': rcv = FST_RCV_X | (time_delta<<4); break; + case 'z': case 'Z': rcv = FST_RCV_Z | (time_delta<<4); break; + case 'h': case 'H': rcv = FST_RCV_H | (time_delta<<4); break; + case 'u': case 'U': rcv = FST_RCV_U | (time_delta<<4); break; + case 'w': case 'W': rcv = FST_RCV_W | (time_delta<<4); break; + case 'l': case 'L': rcv = FST_RCV_L | (time_delta<<4); break; + default: rcv = FST_RCV_D | (time_delta<<4); break; + } + + scratchpnt = fstCopyVarint32ToLeft(scratchpnt, rcv); + } + } + else + { + while(offs) + { + int idx; + char is_binary = 1; + unsigned char *pnt; + uint32_t time_delta; + + next_offs = fstGetUint32(vchg_mem + offs); + offs += 4; + + time_delta = fstGetVarint32(vchg_mem + offs, &wrlen); + + pnt = vchg_mem+offs+wrlen; + offs = next_offs; + + for(idx=0;idx=0;idx--) + { + acc |= (pnt[idx] & 1) << shift; + shift++; + if(shift == 8) + { + *(--scratchpnt) = acc; + shift = 0; + acc = 0; + } + } + + scratchpnt = fstCopyVarint32ToLeft(scratchpnt, (time_delta << 1)); + } + else + { + scratchpnt -= vm4ip[1]; + memcpy(scratchpnt, pnt, vm4ip[1]); + + scratchpnt = fstCopyVarint32ToLeft(scratchpnt, (time_delta << 1) | 1); + } + } + } + + wrlen = scratchpad + xc->vchn_siz - scratchpnt; + unc_memreq += wrlen; + if(wrlen > 32) + { + unsigned long destlen = wrlen; + unsigned char *dmem; + int rc; + + if(!xc->fastpack) + { + if(wrlen <= packmemlen) + { + dmem = packmem; + } + else + { + free(packmem); + dmem = packmem = malloc(packmemlen = wrlen); + } + + rc = compress2(dmem, &destlen, scratchpnt, wrlen, 4); + if(rc == Z_OK) + { + fpos += fstWriterVarint(f, wrlen); + fpos += destlen; + fstFwrite(dmem, destlen, 1, f); + } + else + { + fpos += fstWriterVarint(f, 0); + fpos += wrlen; + fstFwrite(scratchpnt, wrlen, 1, f); + } + } + else + { + if(((wrlen * 2) + 2) <= packmemlen) + { + dmem = packmem; + } + else + { + free(packmem); + dmem = packmem = malloc(packmemlen = (wrlen * 2) + 2); + } + + rc = fastlz_compress(scratchpnt, wrlen, dmem); + if(rc < destlen) + { + fpos += fstWriterVarint(f, wrlen); + fpos += rc; + fstFwrite(dmem, rc, 1, f); + } + else + { + fpos += fstWriterVarint(f, 0); + fpos += wrlen; + fstFwrite(scratchpnt, wrlen, 1, f); + } + } + } + else + { + fpos += fstWriterVarint(f, 0); + fpos += wrlen; + fstFwrite(scratchpnt, wrlen, 1, f); + } + + vm4ip[3] = 0; +#ifdef FST_DEBUG + cnt++; +#endif + } + } + +free(packmem); packmem = NULL; packmemlen = 0; + +prevpos = 0; zerocnt = 0; +free(scratchpad); scratchpad = NULL; + +indxpos = ftello(f); +xc->secnum++; + +for(i=0;imaxhandle;i++) + { + vm4ip = &(xc->valpos_mem[4*i]); + + if(vm4ip[2]) + { + if(zerocnt) + { + fpos += fstWriterVarint(f, (zerocnt << 1)); + zerocnt = 0; + } + + fpos += fstWriterVarint(f, ((vm4ip[2] - prevpos) << 1) | 1); + prevpos = vm4ip[2]; + vm4ip[2] = 0; + vm4ip[3] = 0; /* clear out tchn idx */ + } + else + { + zerocnt++; + } + } +if(zerocnt) + { + fpos += fstWriterVarint(f, (zerocnt << 1)); + } +#ifdef FST_DEBUG +printf("value chains: %d\n", cnt); +#endif + +fstMunmap(vchg_mem, xc->vchn_siz); + +fseeko(xc->vchn_handle, 0, SEEK_SET); +fstFtruncate(fileno(xc->vchn_handle), 0); +fputc('!', xc->vchn_handle); +xc->vchn_siz = 1; + +endpos = ftello(xc->handle); +fstWriterUint64(xc->handle, endpos-indxpos); /* write delta index position at very end of block */ + +/*emit time changes for block */ +fflush(xc->tchn_handle); +tlen = ftello(xc->tchn_handle); +fseeko(xc->tchn_handle, 0, SEEK_SET); + +tmem = fstMmap(NULL, tlen, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->tchn_handle), 0); +if(tmem) + { + unsigned long destlen = tlen; + unsigned char *dmem = malloc(destlen); + int rc = compress2(dmem, &destlen, tmem, tlen, 9); + + if((rc == Z_OK) && (destlen < tlen)) + { + fstFwrite(dmem, destlen, 1, xc->handle); + } + else /* comparison between compressed / decompressed len tells if compressed */ + { + fstFwrite(tmem, tlen, 1, xc->handle); + destlen = tlen; + } + free(dmem); + fstMunmap(tmem, tlen); + fstWriterUint64(xc->handle, tlen); /* uncompressed */ + fstWriterUint64(xc->handle, destlen); /* compressed */ + fstWriterUint64(xc->handle, xc->tchn_cnt); /* number of time items */ + } + +xc->tchn_cnt = xc->tchn_idx = 0; +fseeko(xc->tchn_handle, 0, SEEK_SET); +fstFtruncate(fileno(xc->tchn_handle), 0); + +/* write block trailer */ +endpos = ftello(xc->handle); +fseeko(xc->handle, xc->section_start, SEEK_SET); +fstWriterUint64(xc->handle, endpos - xc->section_start); /* write block length */ +fseeko(xc->handle, 8, SEEK_CUR); /* skip begin time */ +fstWriterUint64(xc->handle, xc->curtime); /* write end time for section */ +fstWriterUint64(xc->handle, unc_memreq); /* amount of buffer memory required in reader for full traversal */ +fflush(xc->handle); + +fseeko(xc->handle, xc->section_start-1, SEEK_SET); /* write out FST_BL_VCDATA over FST_BL_SKIP */ +fputc(FST_BL_VCDATA, xc->handle); +fflush(xc->handle); + +fseeko(xc->handle, endpos, SEEK_SET); /* seek to end of file */ + +xc->section_header_truncpos = endpos; /* cache in case of need to truncate */ +if(xc->dump_size_limit) + { + if(endpos >= xc->dump_size_limit) + { + xc->skip_writing_section_hdr = 1; + xc->size_limit_locked = 1; + xc->is_initial_time = 1; /* to trick emit value and emit time change */ +#ifdef FST_DEBUG + printf("<< dump file size limit reached, stopping dumping >>\n"); +#endif + } + } + + +if(!xc->skip_writing_section_hdr) + { + fstWriterEmitSectionHeader(xc); /* emit next section header */ + } +fflush(xc->handle); + +xc->already_in_flush = 0; +} + + +/* + * functions to set miscellaneous header/block information + */ +void fstWriterSetDate(void *ctx, const char *dat) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc) + { + char s[FST_HDR_DATE_SIZE]; + off_t fpos = ftello(xc->handle); + int len = strlen(dat); + + fseeko(xc->handle, FST_HDR_OFFS_DATE, SEEK_SET); + memset(s, 0, FST_HDR_DATE_SIZE); + memcpy(s, dat, (len < FST_HDR_DATE_SIZE) ? len : FST_HDR_DATE_SIZE); + fstFwrite(s, FST_HDR_DATE_SIZE, 1, xc->handle); + fflush(xc->handle); + fseeko(xc->handle, fpos, SEEK_SET); + } +} + + +void fstWriterSetVersion(void *ctx, const char *vers) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc && vers) + { + char s[FST_HDR_SIM_VERSION_SIZE]; + off_t fpos = ftello(xc->handle); + int len = strlen(vers); + + fseeko(xc->handle, FST_HDR_OFFS_SIM_VERSION, SEEK_SET); + memset(s, 0, FST_HDR_SIM_VERSION_SIZE); + memcpy(s, vers, (len < FST_HDR_SIM_VERSION_SIZE) ? len : FST_HDR_SIM_VERSION_SIZE); + fstFwrite(s, FST_HDR_SIM_VERSION_SIZE, 1, xc->handle); + fflush(xc->handle); + fseeko(xc->handle, fpos, SEEK_SET); + } +} + + +void fstWriterSetTimescale(void *ctx, int ts) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc) + { + off_t fpos = ftello(xc->handle); + fseeko(xc->handle, FST_HDR_OFFS_TIMESCALE, SEEK_SET); + fputc(ts & 255, xc->handle); + fflush(xc->handle); + fseeko(xc->handle, fpos, SEEK_SET); + } +} + + +void fstWriterSetTimescaleFromString(void *ctx, const char *s) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc && s) + { + int mat = 0; + int exp = -9; + int tv = atoi(s); + const char *pnt = s; + + while(*pnt) + { + switch(*pnt) + { + case 'm': exp = -3; mat = 1; break; + case 'u': exp = -6; mat = 1; break; + case 'n': exp = -9; mat = 1; break; + case 'p': exp = -12; mat = 1; break; + case 'f': exp = -15; mat = 1; break; + case 'a': exp = -18; mat = 1; break; + case 'z': exp = -21; mat = 1; break; + case 's': exp = -0; mat = 1; break; + default: break; + } + + if(mat) break; + pnt++; + } + + if(tv == 10) + { + exp++; + } + else + if(tv == 100) + { + exp+=2; + } + + fstWriterSetTimescale(ctx, exp); + } +} + + +void fstWriterSetPackType(void *ctx, int typ) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc) + { + xc->fastpack = (typ != 0); + } +} + + +void fstWriterSetRepackOnClose(void *ctx, int enable) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc) + { + xc->repack_on_close = (enable != 0); + } +} + + +void fstWriterSetDumpSizeLimit(void *ctx, uint64_t numbytes) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc) + { + xc->dump_size_limit = numbytes; + } +} + + +int fstWriterGetDumpSizeLimitReached(void *ctx) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc) + { + return(xc->size_limit_locked != 0); + } + +return(0); +} + + +/* + * writer scope/var creation + */ +fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir vd, + uint32_t len, const char *nam, fstHandle aliasHandle) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +int i, nlen, is_real; + +if(xc && nam) + { + if(xc->valpos_mem) + { + fstDestroyMmaps(xc); + } + + fputc(vt, xc->hier_handle); + fputc(vd, xc->hier_handle); + nlen = strlen(nam); + fstFwrite(nam, nlen, 1, xc->hier_handle); + fputc(0, xc->hier_handle); + xc->hier_file_len += (nlen+3); + + if((vt == FST_VT_VCD_REAL) || (vt == FST_VT_VCD_REAL_PARAMETER) || (vt == FST_VT_VCD_REALTIME)) + { + is_real = 1; + len = 8; /* recast number of bytes to that of what a double is */ + } + else + { + is_real = 0; + } + + xc->hier_file_len += fstWriterVarint(xc->hier_handle, len); + + if(aliasHandle > xc->maxhandle) aliasHandle = 0; + xc->hier_file_len += fstWriterVarint(xc->hier_handle, aliasHandle); + xc->numsigs++; + if(!aliasHandle) + { + uint32_t zero = 0; + + fstWriterVarint(xc->geom_handle, !is_real ? len : 0); /* geom section encodes reals as zero byte */ + + fstFwrite(&xc->maxvalpos, sizeof(uint32_t), 1, xc->valpos_handle); + fstFwrite(&len, sizeof(uint32_t), 1, xc->valpos_handle); + fstFwrite(&zero, sizeof(uint32_t), 1, xc->valpos_handle); + fstFwrite(&zero, sizeof(uint32_t), 1, xc->valpos_handle); + + if(!is_real) + { + for(i=0;icurval_handle); + } + } + else + { + fstFwrite(&xc->nan, 8, 1, xc->curval_handle); /* initialize doubles to NaN rather than x */ + } + + xc->maxvalpos+=len; + xc->maxhandle++; + return(xc->maxhandle); + } + else + { + return(aliasHandle); + } + } + +return(0); +} + + +void fstWriterSetScope(void *ctx, enum fstScopeType scopetype, + const char *scopename, const char *scopecomp) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; + +if(xc && scopename) + { + fputc(FST_ST_VCD_SCOPE, xc->hier_handle); + if((scopetype < FST_ST_VCD_MODULE) || (scopetype > FST_ST_MAX)) { scopetype = FST_ST_VCD_MODULE; } + fputc(scopetype, xc->hier_handle); + fprintf(xc->hier_handle, "%s%c%s%c", + scopename ? scopename : "", 0, + scopecomp ? scopecomp : "", 0); + + if(scopename) + { + xc->hier_file_len += strlen(scopename); + } + if(scopecomp) + { + xc->hier_file_len += strlen(scopecomp); + } + + xc->hier_file_len += 4; /* FST_ST_VCD_SCOPE + scopetype + two string terminating zeros */ + xc->numscopes++; + } +} + + +void fstWriterSetUpscope(void *ctx) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; + +if(xc) + { + fputc(FST_ST_VCD_UPSCOPE, xc->hier_handle); + xc->hier_file_len++; + } +} + + +/* + * value and time change emission + */ +void fstWriterEmitValueChange(void *ctx, fstHandle handle, void *val) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +unsigned char *buf = (unsigned char *)val; +uint32_t offs; +size_t len; + +if((xc) && (handle <= xc->maxhandle)) + { + uint32_t prev_chg; + uint32_t fpos; + uint32_t *vm4ip; + + if(!xc->valpos_mem) + { + xc->vc_emitted = 1; + fstWriterCreateMmaps(xc); + } + + handle--; /* move starting at 1 index to starting at 0 */ + vm4ip = &(xc->valpos_mem[4*handle]); + offs = vm4ip[0]; + len = vm4ip[1]; + memcpy(xc->curval_mem + offs, buf, len); + + if(!xc->is_initial_time) + { + prev_chg = vm4ip[2]; + fpos = xc->vchn_siz; + + fstFwrite(&prev_chg, 1, sizeof(uint32_t), xc->vchn_handle); + xc->vchn_siz += 4; + xc->vchn_siz += fstWriterVarint(xc->vchn_handle, xc->tchn_idx - vm4ip[3]); + fstFwrite(buf, len, 1, xc->vchn_handle); + xc->vchn_siz += len; + vm4ip[3] = xc->tchn_idx; + vm4ip[2] = fpos; + } + } +} + + +void fstWriterEmitTimeChange(void *ctx, uint64_t tim) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +int i; +int skip = 0; +if(xc) + { + if(xc->is_initial_time) + { + if(xc->size_limit_locked) /* this resets xc->is_initial_time to one */ + { + return; + } + + if(!xc->valpos_mem) + { + fstWriterCreateMmaps(xc); + } + + skip = 1; + + xc->firsttime = (xc->vc_emitted) ? 0: tim; + xc->curtime = 0; + fseeko(xc->vchn_handle, 0, SEEK_SET); + fstFtruncate(fileno(xc->vchn_handle), 0); + fputc('!', xc->vchn_handle); + xc->vchn_siz = 1; + fstWriterEmitSectionHeader(xc); + for(i=0;imaxhandle;i++) + { + xc->valpos_mem[4*i+2] = 0; /* zero out offset val */ + xc->valpos_mem[4*i+3] = 0; /* zero out last time change val */ + } + xc->is_initial_time = 0; + } + else + { + if(xc->vchn_siz >= FST_BREAK_SIZE) + { + fstWriterFlushContext(xc); + xc->tchn_cnt++; + fstWriterVarint(xc->tchn_handle, xc->curtime); + } + } + + if(!skip) + { + xc->tchn_idx++; + } + fstWriterVarint(xc->tchn_handle, tim - xc->curtime); + xc->tchn_cnt++; + xc->curtime = tim; + } +} + + +void fstWriterEmitDumpActive(void *ctx, int enable) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; + +if(xc) + { + struct fstBlackoutChain *b = calloc(1, sizeof(struct fstBlackoutChain)); + + b->tim = xc->curtime; + b->active = (enable != 0); + + xc->num_blackouts++; + if(xc->blackout_curr) + { + xc->blackout_curr->next = b; + xc->blackout_curr = b; + } + else + { + xc->blackout_head = b; + xc->blackout_curr = b; + } + } +} + + +/***********************/ +/*** ***/ +/*** reader function ***/ +/*** ***/ +/***********************/ + +/* + * private structs + */ +static const char *vartypes[] = { + "event", "integer", "parameter", "real", "real_parameter", + "reg", "supply0", "supply1", "time", "tri", + "triand", "trior", "trireg", "tri0", "tri1", + "wand", "wire", "wor", "port", "array", "realtime" + }; + +static const char *modtypes[] = { + "module", "task", "function", "begin", "fork" + }; + +struct fstCurrHier +{ +struct fstCurrHier *prev; +void *user_info; +int len; +}; + + +struct fstReaderContext +{ +/* common entries */ + +FILE *f, *fh; +#ifdef __MINGW32__ +char *fh_name; +#endif + +uint64_t start_time, end_time; +uint64_t mem_used_by_writer; +uint64_t scope_count; +uint64_t var_count; +fstHandle maxhandle; +uint64_t num_alias; +uint64_t vc_section_count; + +uint32_t *signal_lens; /* maxhandle sized */ +unsigned char *signal_typs; /* maxhandle sized */ +unsigned char *process_mask; /* maxhandle-based, bitwise sized */ +uint32_t longest_signal_value_len; /* longest len value encountered */ +unsigned char *temp_signal_value_buf; /* malloced for len in longest_signal_value_len */ + +signed char timescale; +unsigned double_endian_match : 1; +unsigned native_doubles_for_cb : 1; +unsigned contains_geom_section : 1; +unsigned contains_hier_section : 1; /* valid for hier_pos */ +unsigned limit_range_valid : 1; /* valid for limit_range_start, limit_range_end */ + +char version[FST_HDR_SIM_VERSION_SIZE + 1]; +char date[FST_HDR_DATE_SIZE + 1]; + +char *filename, *filename_unpacked; +off_t hier_pos; + +uint32_t num_blackouts; +uint64_t *blackout_times; +unsigned char *blackout_activity; + +uint64_t limit_range_start, limit_range_end; + +/* entries specific to read value at time functions */ + +unsigned rvat_data_valid : 1; +uint64_t *rvat_time_table; +uint64_t rvat_beg_tim, rvat_end_tim; +unsigned char *rvat_frame_data; +uint64_t rvat_frame_maxhandle; +off_t *rvat_chain_table; +uint32_t *rvat_chain_table_lengths; +uint64_t rvat_vc_maxhandle; +off_t rvat_vc_start; +uint32_t *rvat_sig_offs; + +uint32_t rvat_chain_len; +unsigned char *rvat_chain_mem; +fstHandle rvat_chain_facidx; + +uint32_t rvat_chain_pos_tidx; +uint32_t rvat_chain_pos_idx; +uint64_t rvat_chain_pos_time; +unsigned rvat_chain_pos_valid : 1; + +/* entries specific to hierarchy traversal */ + +struct fstHier hier; +struct fstCurrHier *curr_hier; +fstHandle current_handle; +char *curr_flat_hier_nam; +int flat_hier_alloc_len; +unsigned do_rewind : 1; +char str_scope_nam[FST_ID_NAM_SIZ+1]; +char str_scope_comp[FST_ID_NAM_SIZ+1]; + +}; + + +/* + * scope -> flat name handling + */ +static void fstReaderDeallocateScopeData(struct fstReaderContext *xc) +{ +struct fstCurrHier *chp; + +if(xc->curr_flat_hier_nam) { free(xc->curr_flat_hier_nam); xc->curr_flat_hier_nam = NULL; } +while(xc->curr_hier) + { + chp = xc->curr_hier->prev; + free(xc->curr_hier); + xc->curr_hier = chp; + } +} + + +const char *fstReaderGetCurrentFlatScope(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +if(xc) + { + return(xc->curr_flat_hier_nam ? xc->curr_flat_hier_nam : ""); + } + else + { + return(NULL); + } +} + + +void *fstReaderGetCurrentScopeUserInfo(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +if(xc) + { + return(xc->curr_hier ? xc->curr_hier->user_info : NULL); + } + else + { + return(NULL); + } +} + + +const char *fstReaderPopScope(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +if(xc && xc->curr_hier) + { + struct fstCurrHier *ch = xc->curr_hier; + if(xc->curr_hier->prev) + { + xc->curr_flat_hier_nam[xc->curr_hier->prev->len] = 0; + } + else + { + *xc->curr_flat_hier_nam = 0; + } + xc->curr_hier = xc->curr_hier->prev; + free(ch); + return(xc->curr_flat_hier_nam ? xc->curr_flat_hier_nam : ""); + } + +return(NULL); +} + + +void fstReaderResetScope(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; + +if(xc) + { + while(fstReaderPopScope(xc)); /* remove any already-built scoping info */ + } +} + + +const char *fstReaderPushScope(void *ctx, const char *nam, void *user_info) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +if(xc) + { + struct fstCurrHier *ch = malloc(sizeof(struct fstCurrHier)); + int chl = xc->curr_hier ? xc->curr_hier->len : 0; + int len = chl + 1 + strlen(nam); + if(len >= xc->flat_hier_alloc_len) + { + xc->curr_flat_hier_nam = xc->curr_flat_hier_nam ? realloc(xc->curr_flat_hier_nam, len+1) : malloc(len+1); + } + + if(chl) + { + xc->curr_flat_hier_nam[chl] = '.'; + strcpy(xc->curr_flat_hier_nam + chl + 1, nam); + } + else + { + strcpy(xc->curr_flat_hier_nam, nam); + len--; + } + + ch->len = len; + ch->prev = xc->curr_hier; + ch->user_info = user_info; + xc->curr_hier = ch; + return(xc->curr_flat_hier_nam); + } + +return(NULL); +} + + +/* + * iter mask manipulation util functions + */ +int fstReaderGetFacProcessMask(void *ctx, fstHandle facidx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; + +if(xc) + { + facidx--; + if(facidxmaxhandle) + { + int process_idx = facidx/8; + int process_bit = facidx&7; + + return( (xc->process_mask[process_idx]&(1<maxhandle) + { + int idx = facidx/8; + int bitpos = facidx&7; + + xc->process_mask[idx] |= (1<maxhandle) + { + int idx = facidx/8; + int bitpos = facidx&7; + + xc->process_mask[idx] &= (~(1<process_mask, 0xff, (xc->maxhandle+7)/8); + } +} + + +void fstReaderClrFacProcessMaskAll(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; + +if(xc) + { + memset(xc->process_mask, 0x00, (xc->maxhandle+7)/8); + } +} + + +/* + * various utility read/write functions + */ +signed char fstReaderGetTimescale(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +return(xc ? xc->timescale : 0); +} + + +uint64_t fstReaderGetStartTime(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +return(xc ? xc->start_time : 0); +} + + +uint64_t fstReaderGetEndTime(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +return(xc ? xc->end_time : 0); +} + + +uint64_t fstReaderGetMemoryUsedByWriter(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +return(xc ? xc->mem_used_by_writer : 0); +} + + +uint64_t fstReaderGetScopeCount(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +return(xc ? xc->scope_count : 0); +} + + +uint64_t fstReaderGetVarCount(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +return(xc ? xc->var_count : 0); +} + + +fstHandle fstReaderGetMaxHandle(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +return(xc ? xc->maxhandle : 0); +} + + +uint64_t fstReaderGetAliasCount(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +return(xc ? xc->num_alias : 0); +} + + +uint64_t fstReaderGetValueChangeSectionCount(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +return(xc ? xc->vc_section_count : 0); +} + + +int fstReaderGetDoubleEndianMatchState(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +return(xc ? xc->double_endian_match : 0); +} + + +const char *fstReaderGetVersionString(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +return(xc ? xc->version : NULL); +} + + +const char *fstReaderGetDateString(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +return(xc ? xc->date : NULL); +} + + +uint32_t fstReaderGetNumberDumpActivityChanges(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +return(xc ? xc->num_blackouts : 0); +} + + +uint64_t fstReaderGetDumpActivityChangeTime(void *ctx, uint32_t idx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; + +if(xc && (idx < xc->num_blackouts) && (xc->blackout_times)) + { + return(xc->blackout_times[idx]); + } + else + { + return(0); + } +} + + +unsigned char fstReaderGetDumpActivityChangeValue(void *ctx, uint32_t idx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; + +if(xc && (idx < xc->num_blackouts) && (xc->blackout_activity)) + { + return(xc->blackout_activity[idx]); + } + else + { + return(0); + } +} + + +void fstReaderSetLimitTimeRange(void *ctx, uint64_t start_time, uint64_t end_time) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; + +if(xc) + { + xc->limit_range_valid = 1; + xc->limit_range_start = start_time; + xc->limit_range_end = end_time; + } +} + + +void fstReaderSetUnlimitedTimeRange(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; + +if(xc) + { + xc->limit_range_valid = 0; + } +} + + +void fstReaderIterBlocksSetNativeDoublesOnCallback(void *ctx, int enable) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +if(xc) + { + xc->native_doubles_for_cb = (enable != 0); + } +} + +/* + * hierarchy processing + */ +static char *fstVcdID(int value) +{ +static char buf[16]; +char *pnt = buf; +int vmod; + +/* zero is illegal for a value...it is assumed they start at one */ +for(;;) + { + if((vmod = (value % 94))) + { + *(pnt++) = (char)(vmod + 32); + } + else + { + *(pnt++) = '~'; value -= 94; + } + value = value / 94; + if(!value) { break; } + } + +*pnt = 0; +return(buf); +} + +static char *fstVcdIDForFwrite(int value, int *len) +{ +static char buf[16]; +char *pnt = buf; +int vmod; + +/* zero is illegal for a value...it is assumed they start at one */ +for(;;) + { + if((vmod = (value % 94))) + { + *(pnt++) = (char)(vmod + 32); + } + else + { + *(pnt++) = '~'; value -= 94; + } + value = value / 94; + if(!value) { break; } + } + +*len = pnt-buf; +return(buf); +} + + +static void fstReaderRecreateHierFile(struct fstReaderContext *xc) +{ +if(!xc->fh) + { + off_t offs_cache = ftello(xc->f); + char *fnam = malloc(strlen(xc->filename) + 6 + 16 + 32 + 1); + unsigned char *mem = malloc(FST_GZIO_LEN); + off_t hl; + uint64_t uclen; + gzFile zhandle; + + sprintf(fnam, "%s.hier_%d_%p", xc->filename, getpid(), (void *)xc); + fseeko(xc->f, xc->hier_pos, SEEK_SET); + uclen = fstReaderUint64(xc->f); + fflush(xc->f); + zhandle = gzdopen(dup(fileno(xc->f)), "rb"); + xc->fh = fopen(fnam, "w+b"); +#ifndef __MINGW32__ + unlink(fnam); +#endif + + for(hl = 0; hl < uclen; hl += FST_GZIO_LEN) + { + unsigned len = ((uclen - hl) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - hl); + gzread(zhandle, mem, len); /* rc should equal len... */ + fstFwrite(mem, len, 1, xc->fh); + } + gzclose(zhandle); + free(mem); + +#ifndef __MINGW32__ + free(fnam); +#else + xc->fh_name = fnam; +#endif + + fseeko(xc->f, offs_cache, SEEK_SET); + } +} + + +void fstReaderIterateHierRewind(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; + +if(xc) + { + if(!xc->fh) + { + fstReaderRecreateHierFile(xc); + } + + xc->do_rewind = 1; + } +} + + +struct fstHier *fstReaderIterateHier(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +int isfeof; +fstHandle alias; +char *pnt; +int ch; + +if(!xc) return(NULL); + +if(!xc->fh) + { + fstReaderRecreateHierFile(xc); + } + +if(xc->do_rewind) + { + xc->do_rewind = 0; + xc->current_handle = 0; + fseeko(xc->fh, 0, SEEK_SET); + clearerr(xc->fh); + } + +if(!(isfeof=feof(xc->fh))) + { + int tag = fgetc(xc->fh); + switch(tag) + { + case FST_ST_VCD_SCOPE: + xc->hier.htyp = FST_HT_SCOPE; + xc->hier.u.scope.typ = fgetc(xc->fh); + xc->hier.u.scope.name = pnt = xc->str_scope_nam; + while((ch = fgetc(xc->fh))) + { + *(pnt++) = ch; + }; /* scopename */ + *pnt = 0; + + xc->hier.u.scope.component = pnt = xc->str_scope_comp; + while((ch = fgetc(xc->fh))) + { + *(pnt++) = ch; + }; /* scopecomp */ + *pnt = 0; + break; + + case FST_ST_VCD_UPSCOPE: + xc->hier.htyp = FST_HT_UPSCOPE; + break; + + case FST_VT_VCD_EVENT: + case FST_VT_VCD_INTEGER: + case FST_VT_VCD_PARAMETER: + case FST_VT_VCD_REAL: + case FST_VT_VCD_REAL_PARAMETER: + case FST_VT_VCD_REG: + case FST_VT_VCD_SUPPLY0: + case FST_VT_VCD_SUPPLY1: + case FST_VT_VCD_TIME: + case FST_VT_VCD_TRI: + case FST_VT_VCD_TRIAND: + case FST_VT_VCD_TRIOR: + case FST_VT_VCD_TRIREG: + case FST_VT_VCD_TRI0: + case FST_VT_VCD_TRI1: + case FST_VT_VCD_WAND: + case FST_VT_VCD_WIRE: + case FST_VT_VCD_WOR: + case FST_VT_VCD_PORT: + case FST_VT_VCD_ARRAY: + case FST_VT_VCD_REALTIME: + xc->hier.htyp = FST_HT_VAR; + + xc->hier.u.var.typ = tag; + xc->hier.u.var.direction = fgetc(xc->fh); + xc->hier.u.var.name = pnt = xc->str_scope_nam; + while((ch = fgetc(xc->fh))) + { + *(pnt++) = ch; + }; /* varname */ + *pnt = 0; + xc->hier.u.var.length = fstReaderVarint32(xc->fh); + if(tag == FST_VT_VCD_PORT) + { + xc->hier.u.var.length -= 2; /* removal of delimiting spaces */ + xc->hier.u.var.length /= 3; /* port -> signal size adjust */ + } + + alias = fstReaderVarint32(xc->fh); + + if(!alias) + { + xc->current_handle++; + xc->hier.u.var.handle = xc->current_handle; + xc->hier.u.var.is_alias = 0; + } + else + { + xc->hier.u.var.handle = alias; + xc->hier.u.var.is_alias = 1; + } + + break; + + default: + isfeof = 1; + break; + } + } + +return(!isfeof ? &xc->hier : NULL); +} + + +void fstReaderProcessHier(void *ctx, FILE *fv) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +char str[FST_ID_NAM_SIZ+1]; +char *pnt; +int ch, scopetype; +int vartype, vardir; +uint32_t len, alias; +uint32_t maxvalpos=0; +int num_signal_dyn = 65536; + +if(!xc) return; + +xc->longest_signal_value_len = 32; /* arbitrarily set at 32...this is much longer than an expanded double */ + +if(!xc->fh) + { + fstReaderRecreateHierFile(xc); + } + +if(fv) + { + char time_dimension[2] = {0, 0}; + int time_scale = 1; + + fprintf(fv, "$date\n\t%s\n$end\n", xc->date); + fprintf(fv, "$version\n\t%s\n$end\n", xc->version); + + switch(xc->timescale) + { + case 0: break; + + case -1: time_scale = 100; time_dimension[0] = 'm'; break; + case -2: time_scale = 10; + case -3: time_dimension[0] = 'm'; break; + + case -4: time_scale = 100; time_dimension[0] = 'u'; break; + case -5: time_scale = 10; + case -6: time_dimension[0] = 'u'; break; + + case -10: time_scale = 100; time_dimension[0] = 'p'; break; + case -11: time_scale = 10; + case -12: time_dimension[0] = 'p'; break; + + case -13: time_scale = 100; time_dimension[0] = 'f'; break; + case -14: time_scale = 10; + case -15: time_dimension[0] = 'f'; break; + + case -16: time_scale = 100; time_dimension[0] = 'a'; break; + case -17: time_scale = 10; + case -18: time_dimension[0] = 'a'; break; + + case -19: time_scale = 100; time_dimension[0] = 'z'; break; + case -20: time_scale = 10; + case -21: time_dimension[0] = 'z'; break; + + case -7: time_scale = 100; time_dimension[0] = 'n'; break; + case -8: time_scale = 10; + case -9: + default: time_dimension[0] = 'n'; break; + } + + if(fv) fprintf(fv, "$timescale\n\t%d%ss\n$end\n", time_scale, time_dimension); + } + +xc->maxhandle = 0; +xc->num_alias = 0; + +if(xc->signal_lens) free(xc->signal_lens); +xc->signal_lens = malloc(num_signal_dyn*sizeof(uint32_t)); + +if(xc->signal_typs) free(xc->signal_typs); +xc->signal_typs = malloc(num_signal_dyn*sizeof(unsigned char)); + +fseeko(xc->fh, 0, SEEK_SET); +while(!feof(xc->fh)) + { + int tag = fgetc(xc->fh); + switch(tag) + { + case FST_ST_VCD_SCOPE: + scopetype = fgetc(xc->fh); + pnt = str; + while((ch = fgetc(xc->fh))) + { + *(pnt++) = ch; + }; /* scopename */ + *pnt = 0; + while(fgetc(xc->fh)) { }; /* scopecomp */ + + if(fv) fprintf(fv, "$scope %s %s $end\n", modtypes[scopetype], str); + break; + + case FST_ST_VCD_UPSCOPE: + if(fv) fprintf(fv, "$upscope $end\n"); + break; + + case FST_VT_VCD_EVENT: + case FST_VT_VCD_INTEGER: + case FST_VT_VCD_PARAMETER: + case FST_VT_VCD_REAL: + case FST_VT_VCD_REAL_PARAMETER: + case FST_VT_VCD_REG: + case FST_VT_VCD_SUPPLY0: + case FST_VT_VCD_SUPPLY1: + case FST_VT_VCD_TIME: + case FST_VT_VCD_TRI: + case FST_VT_VCD_TRIAND: + case FST_VT_VCD_TRIOR: + case FST_VT_VCD_TRIREG: + case FST_VT_VCD_TRI0: + case FST_VT_VCD_TRI1: + case FST_VT_VCD_WAND: + case FST_VT_VCD_WIRE: + case FST_VT_VCD_WOR: + case FST_VT_VCD_PORT: + case FST_VT_VCD_ARRAY: + case FST_VT_VCD_REALTIME: + vartype = tag; + vardir = fgetc(xc->fh); /* unused in VCD reader */ + pnt = str; + while((ch = fgetc(xc->fh))) + { + *(pnt++) = ch; + }; /* varname */ + *pnt = 0; + len = fstReaderVarint32(xc->fh); + alias = fstReaderVarint32(xc->fh); + + if(!alias) + { + if(xc->maxhandle == num_signal_dyn) + { + num_signal_dyn *= 2; + xc->signal_lens = realloc(xc->signal_lens, num_signal_dyn*sizeof(uint32_t)); + xc->signal_typs = realloc(xc->signal_typs, num_signal_dyn*sizeof(unsigned char)); + } + xc->signal_lens[xc->maxhandle] = len; + xc->signal_typs[xc->maxhandle] = vartype; + + maxvalpos+=len; + if(len > xc->longest_signal_value_len) + { + xc->longest_signal_value_len = len; + } + + if((vartype == FST_VT_VCD_REAL) || (vartype == FST_VT_VCD_REAL_PARAMETER) || (vartype == FST_VT_VCD_REALTIME)) + { + len = 64; + xc->signal_typs[xc->maxhandle] = FST_VT_VCD_REAL; + } + if(fv) + { + uint32_t modlen = (vartype != FST_VT_VCD_PORT) ? len : ((len - 2) / 3); + fprintf(fv, "$var %s %"PRIu32" %s %s $end\n", vartypes[vartype], modlen, fstVcdID(xc->maxhandle+1), str); + } + xc->maxhandle++; + } + else + { + if((vartype == FST_VT_VCD_REAL) || (vartype == FST_VT_VCD_REAL_PARAMETER) || (vartype == FST_VT_VCD_REALTIME)) + { + len = 64; + xc->signal_typs[xc->maxhandle] = FST_VT_VCD_REAL; + } + if(fv) + { + uint32_t modlen = (vartype != FST_VT_VCD_PORT) ? len : ((len - 2) / 3); + fprintf(fv, "$var %s %"PRIu32" %s %s $end\n", vartypes[vartype], modlen, fstVcdID(alias), str); + } + xc->num_alias++; + } + + break; + + default: + break; + } + } +if(fv) fprintf(fv, "$enddefinitions $end\n"); + +xc->signal_lens = realloc(xc->signal_lens, xc->maxhandle*sizeof(uint32_t)); +xc->signal_typs = realloc(xc->signal_typs, xc->maxhandle*sizeof(unsigned char)); + +if(xc->process_mask) { free(xc->process_mask); } +xc->process_mask = calloc(1, (xc->maxhandle+7)/8); + +if(xc->temp_signal_value_buf) free(xc->temp_signal_value_buf); +xc->temp_signal_value_buf = malloc(xc->longest_signal_value_len + 1); + +xc->var_count = xc->maxhandle + xc->num_alias; +} + + +/* + * reader file open/close functions + */ +int fstReaderInit(struct fstReaderContext *xc) +{ +off_t blkpos = 0; +off_t endfile; +uint64_t seclen; +int sectype; +uint64_t vc_section_count_actual = 0; +int hdr_incomplete = 0; +int hdr_seen = 0; + +sectype = fgetc(xc->f); +if(sectype == FST_BL_ZWRAPPER) + { + FILE *fcomp; + off_t offpnt, uclen; + char gz_membuf[FST_GZIO_LEN]; + void *zhandle; + int flen = strlen(xc->filename); + char *hf = calloc(1, flen + 16 + 32 + 1); + + sprintf(hf, "%s.upk_%d_%p", xc->filename, getpid(), (void *)xc); + fcomp = fopen(hf, "w+b"); + +#ifdef __MINGW32__ + setvbuf(fcomp, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */ + xc->filename_unpacked = hf; +#else + unlink(hf); + free(hf); +#endif + + seclen = fstReaderUint64(xc->f); + uclen = fstReaderUint64(xc->f); + + if(!seclen) return(0); /* not finished compressing, this is a failed read */ + + fseeko(xc->f, 1+8+8, SEEK_SET); + fflush(xc->f); + + zhandle = gzdopen(dup(fileno(xc->f)), "rb"); + for(offpnt = 0; offpnt < uclen; offpnt += FST_GZIO_LEN) + { + size_t this_len = ((uclen - offpnt) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - offpnt); + gzread(zhandle, gz_membuf, this_len); + fstFwrite(gz_membuf, this_len, 1, fcomp); + } + fflush(fcomp); + fclose(xc->f); + xc->f = fcomp; + } + +fseeko(xc->f, 0, SEEK_END); +endfile = ftello(xc->f); + +while(blkpos < endfile) + { + fseeko(xc->f, blkpos, SEEK_SET); + + sectype = fgetc(xc->f); + seclen = fstReaderUint64(xc->f); + + if(sectype == EOF) + { + break; + } + + if(!hdr_seen && (sectype != FST_BL_HDR)) + { + break; + } + + blkpos++; + if(sectype == FST_BL_HDR) + { + if(!hdr_seen) + { + int ch; + double dcheck; + + xc->start_time = fstReaderUint64(xc->f); + xc->end_time = fstReaderUint64(xc->f); + + hdr_incomplete = (xc->start_time == 0) && (xc->end_time == 0); + + fstFread(&dcheck, 8, 1, xc->f); + xc->double_endian_match = (dcheck == FST_DOUBLE_ENDTEST); + if(!xc->double_endian_match) + { + unsigned char rvs_buf[8]; + unsigned char *dcheck_alias = (unsigned char *)&dcheck; + int rvs_idx; + + for(rvs_idx=0;rvs_idx<8;rvs_idx++) + { + rvs_buf[rvs_idx] = dcheck_alias[7-rvs_idx]; + } + if(*((double *)rvs_buf) != FST_DOUBLE_ENDTEST) + { + break; /* either corrupt file or wrong architecture (offset +33 also functions as matchword) */ + } + } + + hdr_seen = 1; + + xc->mem_used_by_writer = fstReaderUint64(xc->f); + xc->scope_count = fstReaderUint64(xc->f); + xc->var_count = fstReaderUint64(xc->f); + xc->maxhandle = fstReaderUint64(xc->f); + xc->num_alias = xc->var_count - xc->maxhandle; + xc->vc_section_count = fstReaderUint64(xc->f); + ch = fgetc(xc->f); + xc->timescale = (signed char)ch; + fstFread(xc->version, FST_HDR_SIM_VERSION_SIZE, 1, xc->f); + xc->version[FST_HDR_SIM_VERSION_SIZE] = 0; + fstFread(xc->date, FST_HDR_DATE_SIZE, 1, xc->f); + xc->date[FST_HDR_DATE_SIZE] = 0; + } + } + else if(sectype == FST_BL_VCDATA) + { + if(hdr_incomplete) + { + uint64_t bt = fstReaderUint64(xc->f); + xc->end_time = fstReaderUint64(xc->f); + + if(!vc_section_count_actual) { xc->start_time = bt; } + } + + vc_section_count_actual++; + } + else if(sectype == FST_BL_GEOM) + { + if(!hdr_incomplete) + { + uint64_t clen = seclen - 24; + uint64_t uclen = fstReaderUint64(xc->f); + unsigned char *ucdata = malloc(uclen); + unsigned char *pnt = ucdata; + int i; + + xc->contains_geom_section = 1; + xc->maxhandle = fstReaderUint64(xc->f); + xc->longest_signal_value_len = 32; /* arbitrarily set at 32...this is much longer than an expanded double */ + + if(xc->process_mask) { free(xc->process_mask); } + xc->process_mask = calloc(1, (xc->maxhandle+7)/8); + + if(clen != uclen) + { + unsigned char *cdata = malloc(clen); + unsigned long destlen = uclen; + unsigned long sourcelen = clen; + int rc; + + fstFread(cdata, clen, 1, xc->f); + rc = uncompress(ucdata, &destlen, cdata, sourcelen); + + if(rc != Z_OK) + { + printf("geom uncompress rc = %d\n", rc); + exit(255); + } + + free(cdata); + } + else + { + fstFread(ucdata, uclen, 1, xc->f); + } + + if(xc->signal_lens) free(xc->signal_lens); + xc->signal_lens = malloc(sizeof(uint32_t) * xc->maxhandle); + if(xc->signal_typs) free(xc->signal_typs); + xc->signal_typs = malloc(sizeof(unsigned char) * xc->maxhandle); + + for(i=0;imaxhandle;i++) + { + int skiplen; + uint64_t val = fstGetVarint32(pnt, &skiplen); + + pnt += skiplen; + + if(val) + { + xc->signal_lens[i] = val; + xc->signal_typs[i] = FST_VT_VCD_WIRE; + if(val > xc->longest_signal_value_len) + { + xc->longest_signal_value_len = val; + } + } + else + { + xc->signal_lens[i] = 8; /* backpatch in real */ + xc->signal_typs[i] = FST_VT_VCD_REAL; + /* xc->longest_signal_value_len handled above by overly large init size */ + } + } + + if(xc->temp_signal_value_buf) free(xc->temp_signal_value_buf); + xc->temp_signal_value_buf = malloc(xc->longest_signal_value_len + 1); + + free(ucdata); + } + } + else if(sectype == FST_BL_HIER) + { + xc->contains_hier_section = 1; + xc->hier_pos = ftello(xc->f); + } + else if(sectype == FST_BL_BLACKOUT) + { + uint32_t i; + uint64_t cur_bl = 0; + uint64_t delta; + + xc->num_blackouts = fstReaderVarint32(xc->f); + if(xc->blackout_times) free(xc->blackout_times); + xc->blackout_times = calloc(xc->num_blackouts, sizeof(uint64_t)); + if(xc->blackout_activity) free(xc->blackout_activity); + xc->blackout_activity = calloc(xc->num_blackouts, sizeof(unsigned char)); + + for(i=0;inum_blackouts;i++) + { + xc->blackout_activity[i] = fgetc(xc->f) != 0; + delta = fstReaderVarint64(xc->f); + cur_bl += delta; + xc->blackout_times[i] = cur_bl; + } + } + + blkpos += seclen; + if(!hdr_seen) break; + } + +if(hdr_seen) + { + if(xc->vc_section_count != vc_section_count_actual) + { + xc->vc_section_count = vc_section_count_actual; + } + + if(!xc->contains_geom_section) + { + fstReaderProcessHier(xc, NULL); /* recreate signal_lens/signal_typs info */ + } + } + +return(hdr_seen); +} + + +void *fstReaderOpen(const char *nam) +{ +struct fstReaderContext *xc = calloc(1, sizeof(struct fstReaderContext)); + +if((!nam)||(!(xc->f=fopen(nam, "rb")))) + { + free(xc); + xc=NULL; + } + else + { + int flen = strlen(nam); + char *hf = calloc(1, flen + 6); + int rc; + +#ifdef __MINGW32__ + setvbuf(xc->f, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */ +#endif + + memcpy(hf, nam, flen); + strcpy(hf + flen, ".hier"); + xc->fh = fopen(hf, "rb"); + + free(hf); + xc->filename = strdup(nam); + rc = fstReaderInit(xc); + + if((rc) && (xc->vc_section_count) && (xc->maxhandle) && ((xc->fh)||(xc->contains_hier_section))) + { + /* more init */ + xc->do_rewind = 1; + } + else + { + fstReaderClose(xc); + xc = NULL; + } + } + +return(xc); +} + + +static void fstReaderDeallocateRvatData(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +if(xc) + { + if(xc->rvat_chain_mem) { free(xc->rvat_chain_mem); xc->rvat_chain_mem = NULL; } + if(xc->rvat_frame_data) { free(xc->rvat_frame_data); xc->rvat_frame_data = NULL; } + if(xc->rvat_time_table) { free(xc->rvat_time_table); xc->rvat_time_table = NULL; } + if(xc->rvat_chain_table) { free(xc->rvat_chain_table); xc->rvat_chain_table = NULL; } + if(xc->rvat_chain_table_lengths) { free(xc->rvat_chain_table_lengths); xc->rvat_chain_table_lengths = NULL; } + + xc->rvat_data_valid = 0; + } +} + + +void fstReaderClose(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; + +if(xc) + { + fstReaderDeallocateScopeData(xc); + fstReaderDeallocateRvatData(xc); + if(xc->rvat_sig_offs) { free(xc->rvat_sig_offs); xc->rvat_sig_offs = NULL; } + + if(xc->process_mask) { free(xc->process_mask); xc->process_mask = NULL; } + if(xc->blackout_times) { free(xc->blackout_times); xc->blackout_times = NULL; } + if(xc->blackout_activity) { free(xc->blackout_activity); xc->blackout_activity = NULL; } + if(xc->temp_signal_value_buf) { free(xc->temp_signal_value_buf); xc->temp_signal_value_buf = NULL; } + if(xc->signal_typs) { free(xc->signal_typs); xc->signal_typs = NULL; } + if(xc->signal_lens) { free(xc->signal_lens); xc->signal_lens = NULL; } + if(xc->filename) { free(xc->filename); xc->filename = NULL; } + + if(xc->fh) + { + fclose(xc->fh); xc->fh = NULL; +#ifdef __MINGW32__ + if(xc->fh_name) + { + unlink(xc->fh_name); + free(xc->fh_name); xc->fh_name = NULL; + } +#endif + } + + if(xc->f) + { + fclose(xc->f); xc->f = NULL; + if(xc->filename_unpacked) + { + unlink(xc->filename_unpacked); + free(xc->filename_unpacked); + } + } + + free(xc); + } +} + + +/* + * read processing + */ + +/* normal read which re-interleaves the value change data */ +int 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) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; + +uint64_t previous_time = ~0; +uint64_t *time_table = NULL; +uint64_t tsec_nitems; +int secnum = 0; +off_t blkpos = 0; +uint64_t seclen, beg_tim, end_tim; +uint64_t frame_uclen, frame_clen, frame_maxhandle, vc_maxhandle; +off_t vc_start; +off_t indx_pntr, indx_pos; +off_t *chain_table = NULL; +uint32_t *chain_table_lengths = NULL; +unsigned char *chain_cmem; +unsigned char *pnt; +long chain_clen; +fstHandle idx, pidx=0, i; +uint64_t pval; +uint64_t vc_maxhandle_largest = 0; +uint64_t tsec_uclen = 0, tsec_clen = 0; +int sectype; +uint64_t mem_required_for_traversal; +unsigned char *mem_for_traversal = NULL; +uint32_t traversal_mem_offs; +uint32_t *scatterptr, *headptr, *length_remaining; +uint32_t cur_blackout = 0; +int packtype; + +if(!xc) return(0); + +scatterptr = calloc(xc->maxhandle, sizeof(uint32_t)); +headptr = calloc(xc->maxhandle, sizeof(uint32_t)); +length_remaining = calloc(xc->maxhandle, sizeof(uint32_t)); + +for(;;) + { + uint32_t *tc_head = NULL; + traversal_mem_offs = 0; + + fseeko(xc->f, blkpos, SEEK_SET); + + sectype = fgetc(xc->f); + seclen = fstReaderUint64(xc->f); + + if((sectype == EOF) || (sectype == FST_BL_SKIP)) + { +#ifdef FST_DEBUG + printf("<< EOF >>\n"); +#endif + break; + } + + blkpos++; + if(sectype != FST_BL_VCDATA) + { + blkpos += seclen; + continue; + } + + if(!seclen) break; + + beg_tim = fstReaderUint64(xc->f); + end_tim = fstReaderUint64(xc->f); + + if(xc->limit_range_valid) + { + if(beg_tim < xc->limit_range_start) + { + blkpos += seclen; + continue; + } + + if(beg_tim > xc->limit_range_end) /* likely the compare in for(i=0;if); + mem_for_traversal = malloc(mem_required_for_traversal + 66); /* add in potential fastlz overhead */ +#ifdef FST_DEBUG + printf("sec: %d seclen: %d begtim: %d endtim: %d\n", + secnum, (int)seclen, (int)beg_tim, (int)end_tim); + printf("\tmem_required_for_traversal: %d\n", (int)mem_required_for_traversal); +#endif + /* process time block */ + { + unsigned char *ucdata; + unsigned char *cdata; + unsigned long destlen = tsec_uclen; + unsigned long sourcelen = tsec_clen; + int rc; + unsigned char *tpnt; + uint64_t tpval; + int ti; + + fseeko(xc->f, blkpos + seclen - 24, SEEK_SET); + tsec_uclen = fstReaderUint64(xc->f); + tsec_clen = fstReaderUint64(xc->f); + tsec_nitems = fstReaderUint64(xc->f); +#ifdef FST_DEBUG + printf("\ttime section unc: %d, com: %d (%d items)\n", + (int)tsec_uclen, (int)tsec_clen, (int)tsec_nitems); +#endif + ucdata = malloc(tsec_uclen); + destlen = tsec_uclen; + sourcelen = tsec_clen; + + fseeko(xc->f, -24 - ((off_t)tsec_clen), SEEK_CUR); + + if(tsec_uclen != tsec_clen) + { + cdata = malloc(tsec_clen); + fstFread(cdata, tsec_clen, 1, xc->f); + + rc = uncompress(ucdata, &destlen, cdata, sourcelen); + + if(rc != Z_OK) + { + printf("tsec uncompress rc = %d\n", rc); + exit(255); + } + + free(cdata); + } + else + { + fstFread(ucdata, tsec_uclen, 1, xc->f); + } + + if(time_table) free(time_table); + time_table = calloc(tsec_nitems, sizeof(uint64_t)); + tpnt = ucdata; + tpval = 0; + for(ti=0;tif, blkpos+32, SEEK_SET); + + frame_uclen = fstReaderVarint64(xc->f); + frame_clen = fstReaderVarint64(xc->f); + frame_maxhandle = fstReaderVarint64(xc->f); + + if(secnum == 0) + { + if(beg_tim != time_table[0]) + { + unsigned char *mu = malloc(frame_uclen); + uint32_t sig_offs = 0; + + if(fv) + { + if(beg_tim) { fprintf(fv, "#%"PRIu64"\n", beg_tim); } + if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts)) + { + if(beg_tim == xc->blackout_times[cur_blackout]) + { + fprintf(fv, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off"); + } + } + } + + if(frame_uclen == frame_clen) + { + fstFread(mu, frame_uclen, 1, xc->f); + } + else + { + unsigned char *mc = malloc(frame_clen); + int rc; + + unsigned long destlen = frame_uclen; + unsigned long sourcelen = frame_clen; + + fstFread(mc, sourcelen, 1, xc->f); + rc = uncompress(mu, &destlen, mc, sourcelen); + if(rc != Z_OK) + { + printf("rc: %d\n", rc); + exit(255); + } + free(mc); + } + + + for(idx=0;idxprocess_mask[process_idx]&(1<signal_lens[idx] == 1) + { + unsigned char val = mu[sig_offs]; + if(value_change_callback) + { + xc->temp_signal_value_buf[0] = val; + xc->temp_signal_value_buf[1] = 0; + value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf); + } + else + { + if(fv) + { + int vcdid_len; + const char *vcd_id = fstVcdIDForFwrite(idx+1, &vcdid_len); + fputc(val, fv); + fstFwrite(vcd_id, vcdid_len, 1, fv); + fputc('\n', fv); + } + } + } + else + { + if(xc->signal_typs[idx] != FST_VT_VCD_REAL) + { + if(value_change_callback) + { + memcpy(xc->temp_signal_value_buf, mu+sig_offs, xc->signal_lens[idx]); + xc->temp_signal_value_buf[xc->signal_lens[idx]] = 0; + value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf); + } + else + { + if(fv) + { + int vcdid_len; + const char *vcd_id = fstVcdIDForFwrite(idx+1, &vcdid_len); + fputc((xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p', fv); + fstFwrite(mu+sig_offs, xc->signal_lens[idx], 1, fv); + fputc(' ', fv); + fstFwrite(vcd_id, vcdid_len, 1, fv); + fputc('\n', fv); + } + } + } + else + { + double d; + unsigned char *clone_d; + unsigned char *srcdata = mu+sig_offs; + + if(value_change_callback) + { + if(xc->native_doubles_for_cb) + { + if(xc->double_endian_match) + { + clone_d = srcdata; + } + else + { + int j; + + clone_d = (unsigned char *)&d; + for(j=0;j<8;j++) + { + clone_d[j] = srcdata[7-j]; + } + } + value_change_callback(user_callback_data_pointer, beg_tim, idx+1, clone_d); + } + else + { + clone_d = (unsigned char *)&d; + if(xc->double_endian_match) + { + memcpy(clone_d, srcdata, 8); + } + else + { + int j; + + for(j=0;j<8;j++) + { + clone_d[j] = srcdata[7-j]; + } + } + sprintf((char *)xc->temp_signal_value_buf, "%.16g", d); + value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf); + } + } + else + { + if(fv) + { + clone_d = (unsigned char *)&d; + if(xc->double_endian_match) + { + memcpy(clone_d, srcdata, 8); + } + else + { + int j; + + for(j=0;j<8;j++) + { + clone_d[j] = srcdata[7-j]; + } + } + + fprintf(fv, "r%.16g %s\n", d, fstVcdID(idx+1)); + } + } + } + } + } + + sig_offs += xc->signal_lens[idx]; + } + + free(mu); + fseeko(xc->f, -((off_t)frame_clen), SEEK_CUR); + } + } + + fseeko(xc->f, (off_t)frame_clen, SEEK_CUR); /* skip past compressed data */ + + vc_maxhandle = fstReaderVarint64(xc->f); + vc_start = ftello(xc->f); /* points to '!' character */ + packtype = fgetc(xc->f); + +#ifdef FST_DEBUG + printf("\tframe_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n", + (int)frame_uclen, (int)frame_clen, (int)frame_maxhandle); + printf("\tvc_maxhandle: %d, packtype: %c\n", (int)vc_maxhandle, packtype); +#endif + + indx_pntr = blkpos + seclen - 24 -tsec_clen -8; + fseeko(xc->f, indx_pntr, SEEK_SET); + chain_clen = fstReaderUint64(xc->f); + indx_pos = indx_pntr - chain_clen; +#ifdef FST_DEBUG + printf("\tindx_pos: %d (%d bytes)\n", (int)indx_pos, (int)chain_clen); +#endif + chain_cmem = malloc(chain_clen); + fseeko(xc->f, indx_pos, SEEK_SET); + fstFread(chain_cmem, chain_clen, 1, xc->f); + + if(vc_maxhandle > vc_maxhandle_largest) + { + free(chain_table); + free(chain_table_lengths); + + vc_maxhandle_largest = vc_maxhandle; + chain_table = malloc((vc_maxhandle+1) * sizeof(off_t)); + chain_table_lengths = malloc((vc_maxhandle+1) * sizeof(uint32_t)); + } + + pnt = chain_cmem; + idx = 0; + pval = 0; + do + { + int skiplen; + uint64_t val = fstGetVarint32(pnt, &skiplen); + + if(val&1) + { + pval = chain_table[idx] = pval + (val >> 1); + if(idx) { chain_table_lengths[pidx] = pval - chain_table[pidx]; } + pidx = idx++; + } + else + { + int loopcnt = val >> 1; + for(i=0;i xc->maxhandle) idx = xc->maxhandle; + for(i=0;iprocess_mask[process_idx]&(1<f, vc_start + chain_table[i], SEEK_SET); + val = fstReaderVarint32WithSkip(xc->f, &skiplen); + if(val) + { + unsigned char *mu = mem_for_traversal + traversal_mem_offs; + unsigned char *mc = malloc(chain_table_lengths[i]); + unsigned long destlen = val; + unsigned long sourcelen = chain_table_lengths[i]; + + fstFread(mc, chain_table_lengths[i], 1, xc->f); + if(packtype == 'F') + { + rc = fastlz_decompress(mc, sourcelen, mu, destlen); + } + else + { + rc = uncompress(mu, &destlen, mc, sourcelen); + } + free(mc); + /* data to process is for(j=0;jf); + /* data to process is for(j=0;jsignal_lens[i] == 1) + { + uint32_t vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[i]); + uint32_t shcnt = 2 << (vli & 1); + tdelta = vli >> shcnt; + } + else + { + uint32_t vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[i]); + tdelta = vli >> 1; + } + + scatterptr[i] = tc_head[tdelta]; + tc_head[tdelta] = i+1; + } + } + } + + for(i=0;ilimit_range_valid) + { + if(time_table[i] > xc->limit_range_end) + { + break; + } + } + + fprintf(fv, "#%"PRIu64"\n", time_table[i]); + if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts)) + { + if(time_table[i] == xc->blackout_times[cur_blackout]) + { + fprintf(fv, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off"); + } + } + previous_time = time_table[i]; + } + } + + while(tc_head[i]) + { + idx = tc_head[i] - 1; + vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen); + + if(xc->signal_lens[idx] == 1) + { + unsigned char val; + if(!(vli & 1)) + { + tdelta = vli >> 2; + val = ((vli >> 1) & 1) | '0'; + } + else + { + tdelta = vli >> 4; + val = FST_RCV_STR[((vli >> 1) & 7)]; + } + + if(value_change_callback) + { + xc->temp_signal_value_buf[0] = val; + xc->temp_signal_value_buf[1] = 0; + value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf); + } + else + { + if(fv) + { + int vcdid_len; + const char *vcd_id = fstVcdIDForFwrite(idx+1, &vcdid_len); + fputc(val, fv); + fstFwrite(vcd_id, vcdid_len, 1, fv); + fputc('\n', fv); + } + } + headptr[idx] += skiplen; + length_remaining[idx] -= skiplen; + + tc_head[i] = scatterptr[idx]; + scatterptr[idx] = 0; + + if(length_remaining[idx]) + { + int shamt; + vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]); + shamt = 2 << (vli & 1); + tdelta = vli >> shamt; + + scatterptr[idx] = tc_head[i+tdelta]; + tc_head[i+tdelta] = idx+1; + } + } + else + { + uint32_t len = xc->signal_lens[idx]; + unsigned char *vdata; + + vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen); + tdelta = vli >> 1; + vdata = mem_for_traversal + headptr[idx] + skiplen; + + if(xc->signal_typs[idx] != FST_VT_VCD_REAL) + { + if(!(vli & 1)) + { + int byte = 0; + int bit; + int j; + + for(j=0;j> bit) & 1) | '0'; + xc->temp_signal_value_buf[j] = ch; + } + xc->temp_signal_value_buf[j] = 0; + + if(value_change_callback) + { + value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf); + } + else + { + if(fv) { + fputc((xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p', fv); + fstFwrite(xc->temp_signal_value_buf, len, 1, fv); + } + } + + len = byte+1; + } + else + { + if(value_change_callback) + { + memcpy(xc->temp_signal_value_buf, vdata, len); + xc->temp_signal_value_buf[len] = 0; + value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf); + } + else + { + if(fv) + { + fputc((xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p', fv); + fstFwrite(vdata, len, 1, fv); + } + } + } + } + else + { + double d; + unsigned char *clone_d = (unsigned char *)&d; + unsigned char buf[8]; + unsigned char *srcdata; + + if(!(vli & 1)) /* very rare case, but possible */ + { + int bit; + int j; + + for(j=0;j<8;j++) + { + unsigned char ch; + bit = 7 - (j & 7); + ch = ((vdata[0] >> bit) & 1) | '0'; + buf[j] = ch; + } + + len = 1; + srcdata = buf; + } + else + { + srcdata = vdata; + } + + if(value_change_callback) + { + if(xc->native_doubles_for_cb) + { + if(xc->double_endian_match) + { + clone_d = srcdata; + } + else + { + int j; + + clone_d = (unsigned char *)&d; + for(j=0;j<8;j++) + { + clone_d[j] = srcdata[7-j]; + } + } + value_change_callback(user_callback_data_pointer, time_table[i], idx+1, clone_d); + } + else + { + clone_d = (unsigned char *)&d; + if(xc->double_endian_match) + { + memcpy(clone_d, srcdata, 8); + } + else + { + int j; + + for(j=0;j<8;j++) + { + clone_d[j] = srcdata[7-j]; + } + } + sprintf((char *)xc->temp_signal_value_buf, "%.16g", d); + value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf); + } + } + else + { + if(fv) + { + clone_d = (unsigned char *)&d; + if(xc->double_endian_match) + { + memcpy(clone_d, srcdata, 8); + } + else + { + int j; + + for(j=0;j<8;j++) + { + clone_d[j] = srcdata[7-j]; + } + } + + fprintf(fv, "r%.16g", d); + } + } + } + + if(fv) + { + int vcdid_len; + const char *vcd_id = fstVcdIDForFwrite(idx+1, &vcdid_len); + fputc(' ', fv); + fstFwrite(vcd_id, vcdid_len, 1, fv); + fputc('\n', fv); + } + + skiplen += len; + headptr[idx] += skiplen; + length_remaining[idx] -= skiplen; + + tc_head[i] = scatterptr[idx]; + scatterptr[idx] = 0; + + if(length_remaining[idx]) + { + vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]); + tdelta = vli >> 1; + + scatterptr[idx] = tc_head[i+tdelta]; + tc_head[i+tdelta] = idx+1; + } + } + } + } + + free(tc_head); + free(chain_cmem); + free(mem_for_traversal); + + secnum++; + if(secnum == xc->vc_section_count) break; /* in case file is growing, keep with original block count */ + blkpos += seclen; + } + +free(length_remaining); +free(headptr); +free(scatterptr); + +if(chain_table) + { + free(chain_table); + free(chain_table_lengths); + } + +if(time_table) free(time_table); + +return(1); +} + + +/* rvat functions */ + +static char *fstExtractRvatDataFromFrame(struct fstReaderContext *xc, fstHandle facidx, char *buf) +{ +if(facidx >= xc->rvat_frame_maxhandle) + { + return(NULL); + } + +if(xc->signal_lens[facidx] == 1) + { + buf[0] = (char)xc->rvat_frame_data[xc->rvat_sig_offs[facidx]]; + buf[1] = 0; + } + else + { + if(xc->signal_typs[facidx] != FST_VT_VCD_REAL) + { + memcpy(buf, xc->rvat_frame_data + xc->rvat_sig_offs[facidx], xc->signal_lens[facidx]); + buf[xc->signal_lens[facidx]] = 0; + } + else + { + double d; + unsigned char *clone_d = (unsigned char *)&d; + unsigned char *srcdata = xc->rvat_frame_data + xc->rvat_sig_offs[facidx]; + + if(xc->double_endian_match) + { + memcpy(clone_d, srcdata, 8); + } + else + { + int j; + + for(j=0;j<8;j++) + { + clone_d[j] = srcdata[7-j]; + } + } + + sprintf((char *)buf, "%.16g", d); + } + } + +return(buf); +} + + +char *fstReaderGetValueFromHandleAtTime(void *ctx, uint64_t tim, fstHandle facidx, char *buf) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +off_t blkpos = 0, prev_blkpos; +uint64_t beg_tim, end_tim, beg_tim2, end_tim2; +int sectype; +int secnum = 0; +uint64_t seclen; +uint64_t tsec_uclen = 0, tsec_clen = 0; +uint64_t tsec_nitems; +uint64_t frame_uclen, frame_clen; +uint64_t mem_required_for_traversal; +off_t indx_pntr, indx_pos; +long chain_clen; +unsigned char *chain_cmem; +unsigned char *pnt; +fstHandle idx, pidx=0, i; +uint64_t pval; + +if((!xc) || (!facidx) || (facidx > xc->maxhandle) || (!buf)) + { + return(NULL); + } + +if(!xc->rvat_sig_offs) + { + uint32_t cur_offs = 0; + + xc->rvat_sig_offs = calloc(xc->maxhandle, sizeof(uint32_t)); + for(i=0;imaxhandle;i++) + { + xc->rvat_sig_offs[i] = cur_offs; + cur_offs += xc->signal_lens[i]; + } + } + +if(xc->rvat_data_valid) + { + if((xc->rvat_beg_tim <= tim) && (tim <= xc->rvat_end_tim)) + { + goto process_value; + } + + fstReaderDeallocateRvatData(xc); + } + +xc->rvat_chain_pos_valid = 0; + +for(;;) + { + fseeko(xc->f, (prev_blkpos = blkpos), SEEK_SET); + + sectype = fgetc(xc->f); + seclen = fstReaderUint64(xc->f); + + if((sectype == EOF) || (sectype == FST_BL_SKIP) || (!seclen)) + { + return(NULL); /* if this loop exits on break, it's successful */ + } + + blkpos++; + if(sectype != FST_BL_VCDATA) + { + blkpos += seclen; + continue; + } + + beg_tim = fstReaderUint64(xc->f); + end_tim = fstReaderUint64(xc->f); + + if((beg_tim <= tim) && (tim <= end_tim)) + { + if((tim == end_tim) && (tim != xc->end_time)) + { + off_t cached_pos = ftello(xc->f); + fseeko(xc->f, blkpos, SEEK_SET); + + sectype = fgetc(xc->f); + seclen = fstReaderUint64(xc->f); + + beg_tim2 = fstReaderUint64(xc->f); + end_tim2 = fstReaderUint64(xc->f); + + if((sectype != FST_BL_VCDATA) || (!seclen) || (beg_tim2 != tim)) + { + blkpos = prev_blkpos; + break; + } + beg_tim = beg_tim2; + end_tim = end_tim2; + fseeko(xc->f, cached_pos, SEEK_SET); + } + break; + } + + blkpos += seclen; + secnum++; + } + +xc->rvat_beg_tim = beg_tim; +xc->rvat_end_tim = end_tim; + +mem_required_for_traversal = fstReaderUint64(xc->f); +#ifdef FST_DEBUG +printf("rvat sec: %d seclen: %d begtim: %d endtim: %d\n", + secnum, (int)seclen, (int)beg_tim, (int)end_tim); +printf("\tmem_required_for_traversal: %d\n", (int)mem_required_for_traversal); +#endif + +/* process time block */ +{ +unsigned char *ucdata; +unsigned char *cdata; +unsigned long destlen = tsec_uclen; +unsigned long sourcelen = tsec_clen; +int rc; +unsigned char *tpnt; +uint64_t tpval; +int ti; + +fseeko(xc->f, blkpos + seclen - 24, SEEK_SET); +tsec_uclen = fstReaderUint64(xc->f); +tsec_clen = fstReaderUint64(xc->f); +tsec_nitems = fstReaderUint64(xc->f); +#ifdef FST_DEBUG +printf("\ttime section unc: %d, com: %d (%d items)\n", + (int)tsec_uclen, (int)tsec_clen, (int)tsec_nitems); +#endif +ucdata = malloc(tsec_uclen); +destlen = tsec_uclen; +sourcelen = tsec_clen; + +fseeko(xc->f, -24 - ((off_t)tsec_clen), SEEK_CUR); +if(tsec_uclen != tsec_clen) + { + cdata = malloc(tsec_clen); + fstFread(cdata, tsec_clen, 1, xc->f); + + rc = uncompress(ucdata, &destlen, cdata, sourcelen); + + if(rc != Z_OK) + { + printf("tsec uncompress rc = %d\n", rc); + exit(255); + } + + free(cdata); + } + else + { + fstFread(ucdata, tsec_uclen, 1, xc->f); + } + +xc->rvat_time_table = calloc(tsec_nitems, sizeof(uint64_t)); +tpnt = ucdata; +tpval = 0; +for(ti=0;tirvat_time_table[ti] = tpval + val; + tpnt += skiplen; + } + +free(ucdata); +} + +fseeko(xc->f, blkpos+32, SEEK_SET); + +frame_uclen = fstReaderVarint64(xc->f); +frame_clen = fstReaderVarint64(xc->f); +xc->rvat_frame_maxhandle = fstReaderVarint64(xc->f); +xc->rvat_frame_data = malloc(frame_uclen); + +if(frame_uclen == frame_clen) + { + fstFread(xc->rvat_frame_data, frame_uclen, 1, xc->f); + } + else + { + unsigned char *mc = malloc(frame_clen); + int rc; + + unsigned long destlen = frame_uclen; + unsigned long sourcelen = frame_clen; + + fstFread(mc, sourcelen, 1, xc->f); + rc = uncompress(xc->rvat_frame_data, &destlen, mc, sourcelen); + if(rc != Z_OK) + { + printf("decompress rc: %d\n", rc); + exit(255); + } + free(mc); + } + +xc->rvat_vc_maxhandle = fstReaderVarint64(xc->f); +xc->rvat_vc_start = ftello(xc->f); /* points to '!' character */ + +#ifdef FST_DEBUG +printf("\tframe_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n", + (int)frame_uclen, (int)frame_clen, (int)xc->rvat_frame_maxhandle); +printf("\tvc_maxhandle: %d\n", (int)xc->rvat_vc_maxhandle); +#endif + +indx_pntr = blkpos + seclen - 24 -tsec_clen -8; +fseeko(xc->f, indx_pntr, SEEK_SET); +chain_clen = fstReaderUint64(xc->f); +indx_pos = indx_pntr - chain_clen; +#ifdef FST_DEBUG +printf("\tindx_pos: %d (%d bytes)\n", (int)indx_pos, (int)chain_clen); +#endif +chain_cmem = malloc(chain_clen); +fseeko(xc->f, indx_pos, SEEK_SET); +fstFread(chain_cmem, chain_clen, 1, xc->f); + +xc->rvat_chain_table = malloc((xc->rvat_vc_maxhandle+1) * sizeof(off_t)); +xc->rvat_chain_table_lengths = malloc((xc->rvat_vc_maxhandle+1) * sizeof(uint32_t)); + +pnt = chain_cmem; +idx = 0; +pval = 0; +do + { + int skiplen; + uint64_t val = fstGetVarint32(pnt, &skiplen); + + if(val&1) + { + pval = xc->rvat_chain_table[idx] = pval + (val >> 1); + if(idx) { xc->rvat_chain_table_lengths[pidx] = pval - xc->rvat_chain_table[pidx]; } + pidx = idx++; + } + else + { + int loopcnt = val >> 1; + for(i=0;irvat_chain_table[idx++] = 0; + } + } + + pnt += skiplen; + } while (pnt != (chain_cmem + chain_clen)); + +free(chain_cmem); +xc->rvat_chain_table[idx] = indx_pos - xc->rvat_vc_start; +xc->rvat_chain_table_lengths[pidx] = xc->rvat_chain_table[idx] - xc->rvat_chain_table[pidx]; + +#ifdef FST_DEBUG +printf("\tdecompressed chain idx len: %"PRIu32"\n", idx); +#endif + +xc->rvat_data_valid = 1; + +/* all data at this point is loaded or resident in fst cache, process and return appropriate value */ +process_value: +if(facidx > xc->rvat_vc_maxhandle) + { + return(NULL); + } + +facidx--; /* scale down for array which starts at zero */ + + +if(((tim == xc->rvat_beg_tim)&&(!xc->rvat_chain_table[facidx])) || (!xc->rvat_chain_table[facidx])) + { + return(fstExtractRvatDataFromFrame(xc, facidx, buf)); + } + +if(facidx != xc->rvat_chain_facidx) + { + if(xc->rvat_chain_mem) + { + free(xc->rvat_chain_mem); + xc->rvat_chain_mem = NULL; + + xc->rvat_chain_pos_valid = 0; + } + } + +if(!xc->rvat_chain_mem) + { + uint32_t skiplen; + fseeko(xc->f, xc->rvat_vc_start + xc->rvat_chain_table[facidx], SEEK_SET); + xc->rvat_chain_len = fstReaderVarint32WithSkip(xc->f, &skiplen); + if(xc->rvat_chain_len) + { + unsigned char *mu = malloc(xc->rvat_chain_len); + unsigned char *mc = malloc(xc->rvat_chain_table_lengths[facidx]); + unsigned long destlen = xc->rvat_chain_len; + unsigned long sourcelen = xc->rvat_chain_table_lengths[facidx]; + int rc; + + fstFread(mc, xc->rvat_chain_table_lengths[facidx], 1, xc->f); + rc = uncompress(mu, &destlen, mc, sourcelen); + free(mc); + + if(rc != Z_OK) + { + printf("\tclen: %d (rc=%d)\n", (int)xc->rvat_chain_len, rc); + exit(255); + } + + /* data to process is for(j=0;jrvat_chain_mem = mu; + } + else + { + int destlen = xc->rvat_chain_table_lengths[facidx] - skiplen; + unsigned char *mu = malloc(xc->rvat_chain_len = destlen); + fstFread(mu, destlen, 1, xc->f); + /* data to process is for(j=0;jrvat_chain_mem = mu; + } + + xc->rvat_chain_facidx = facidx; + } + +/* process value chain here */ + +{ +uint32_t tidx = 0, ptidx = 0; +uint32_t tdelta; +int skiplen; +int iprev = xc->rvat_chain_len; +uint32_t pvli = 0; +int pskip = 0; + +if((xc->rvat_chain_pos_valid)&&(tim >= xc->rvat_chain_pos_time)) + { + i = xc->rvat_chain_pos_idx; + tidx = xc->rvat_chain_pos_tidx; + } + else + { + i = 0; + tidx = 0; + xc->rvat_chain_pos_time = xc->rvat_beg_tim; + } + +if(xc->signal_lens[facidx] == 1) + { + while(irvat_chain_len) + { + uint32_t vli = fstGetVarint32(xc->rvat_chain_mem + i, &skiplen); + uint32_t shcnt = 2 << (vli & 1); + tdelta = vli >> shcnt; + + if(xc->rvat_time_table[tidx + tdelta] <= tim) + { + iprev = i; + pvli = vli; + ptidx = tidx; + pskip = skiplen; + + tidx += tdelta; + i+=skiplen; + } + else + { + break; + } + } + if(iprev != xc->rvat_chain_len) + { + xc->rvat_chain_pos_tidx = ptidx; + xc->rvat_chain_pos_idx = iprev; + xc->rvat_chain_pos_time = tim; + xc->rvat_chain_pos_valid = 1; + + if(!(pvli & 1)) + { + buf[0] = ((pvli >> 1) & 1) | '0'; + } + else + { + buf[0] = FST_RCV_STR[((pvli >> 1) & 7)]; + } + buf[1] = 0; + return(buf); + } + else + { + return(fstExtractRvatDataFromFrame(xc, facidx, buf)); + } + } + else + { + while(irvat_chain_len) + { + uint32_t vli = fstGetVarint32(xc->rvat_chain_mem + i, &skiplen); + tdelta = vli >> 1; + + if(xc->rvat_time_table[tidx + tdelta] <= tim) + { + iprev = i; + pvli = vli; + ptidx = tidx; + pskip = skiplen; + + tidx += tdelta; + i+=skiplen; + + if(!(pvli & 1)) + { + i+=((xc->signal_lens[facidx]+7)/8); + } + else + { + i+=xc->signal_lens[facidx]; + } + } + else + { + break; + } + } + + if(iprev != xc->rvat_chain_len) + { + unsigned char *vdata = xc->rvat_chain_mem + iprev + pskip; + + xc->rvat_chain_pos_tidx = ptidx; + xc->rvat_chain_pos_idx = iprev; + xc->rvat_chain_pos_time = tim; + xc->rvat_chain_pos_valid = 1; + + if(xc->signal_typs[facidx] != FST_VT_VCD_REAL) + { + if(!(pvli & 1)) + { + int byte = 0; + int bit; + int j; + + for(j=0;jsignal_lens[facidx];j++) + { + unsigned char ch; + byte = j/8; + bit = 7 - (j & 7); + ch = ((vdata[byte] >> bit) & 1) | '0'; + buf[j] = ch; + } + buf[j] = 0; + + return(buf); + } + else + { + memcpy(buf, vdata, xc->signal_lens[facidx]); + buf[xc->signal_lens[facidx]] = 0; + return(buf); + } + } + else + { + double d; + unsigned char *clone_d = (unsigned char *)&d; + unsigned char bufd[8]; + unsigned char *srcdata; + + if(!(pvli & 1)) /* very rare case, but possible */ + { + int bit; + int j; + + for(j=0;j<8;j++) + { + unsigned char ch; + bit = 7 - (j & 7); + ch = ((vdata[0] >> bit) & 1) | '0'; + bufd[j] = ch; + } + + srcdata = bufd; + } + else + { + srcdata = vdata; + } + + if(xc->double_endian_match) + { + memcpy(clone_d, srcdata, 8); + } + else + { + int j; + + for(j=0;j<8;j++) + { + clone_d[j] = srcdata[7-j]; + } + } + + sprintf(buf, "r%.16g", d); + return(buf); + } + } + else + { + return(fstExtractRvatDataFromFrame(xc, facidx, buf)); + } + } +} + +return(NULL); +} diff --git a/vpi/fstapi.h b/vpi/fstapi.h new file mode 100644 index 000000000..6e6bc3614 --- /dev/null +++ b/vpi/fstapi.h @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2009-2010 Tony Bybell. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef FST_API_H +#define FST_API_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#define FST_RDLOAD "FSTLOAD | " + +typedef uint32_t fstHandle; + +enum fstBlockType { + FST_BL_HDR = 0, + FST_BL_VCDATA = 1, + FST_BL_BLACKOUT = 2, + FST_BL_GEOM = 3, + FST_BL_HIER = 4, + + FST_BL_ZWRAPPER = 254, /* indicates that whole trace is gz wrapped */ + FST_BL_SKIP = 255 /* used while block is being written */ +}; + +enum fstScopeType { + FST_ST_VCD_MIN = 0, + FST_ST_VCD_MODULE = 0, + FST_ST_VCD_TASK = 1, + FST_ST_VCD_FUNCTION = 2, + FST_ST_VCD_BEGIN = 3, + FST_ST_VCD_FORK = 4, + FST_ST_VCD_MAX = 4, + + FST_ST_MAX = 4, + + FST_ST_VCD_SCOPE = 254, + FST_ST_VCD_UPSCOPE = 255 +}; + +enum fstVarType { + FST_VT_VCD_MIN = 0, /* start of VCD datatypes */ + FST_VT_VCD_EVENT = 0, + FST_VT_VCD_INTEGER = 1, + FST_VT_VCD_PARAMETER = 2, + FST_VT_VCD_REAL = 3, + FST_VT_VCD_REAL_PARAMETER = 4, + FST_VT_VCD_REG = 5, + FST_VT_VCD_SUPPLY0 = 6, + FST_VT_VCD_SUPPLY1 = 7, + FST_VT_VCD_TIME = 8, + FST_VT_VCD_TRI = 9, + FST_VT_VCD_TRIAND = 10, + FST_VT_VCD_TRIOR = 11, + FST_VT_VCD_TRIREG = 12, + FST_VT_VCD_TRI0 = 13, + FST_VT_VCD_TRI1 = 14, + FST_VT_VCD_WAND = 15, + FST_VT_VCD_WIRE = 16, + FST_VT_VCD_WOR = 17, + FST_VT_VCD_PORT = 18, + FST_VT_VCD_ARRAY = 19, /* used to define the rownum (index) port on the array */ + FST_VT_VCD_REALTIME = 20, + FST_VT_VCD_MAX = 20, /* end of VCD datatypes */ + + FST_VT_GEN_STRING = 254, /* generic string type (max len is defined as the len in fstWriterCreateVar() */ + FST_VT_GEN_MEMBLOCK = 255 /* generic memblock type (max len is defined as the len in fstWriterCreateVar() */ +}; + +enum fstVarDir { + FST_VD_IMPLICIT = 0, + FST_VD_INPUT = 1, + FST_VD_OUTPUT = 2, + FST_VD_INOUT = 3, + + FST_VD_MAX = 3 +}; + +enum fstHierType { + FST_HT_SCOPE = 0, + FST_HT_UPSCOPE = 1, + FST_HT_VAR = 2, + + FST_HT_MAX = 2 +}; + +struct fstHier +{ +unsigned char htyp; + +union { + /* if htyp == FST_HT_SCOPE */ + struct fstHierScope { + unsigned char typ; /* FST_ST_VCD_MODULE ... FST_ST_VCD_FORK */ + const char *name; + const char *component; + } scope; + + /* if htyp == FST_HT_VAR */ + struct fstHierVar { + unsigned char typ; /* FST_VT_VCD_EVENT ... FST_VT_VCD_WOR */ + unsigned char direction; /* FST_VD_IMPLICIT ... FST_VD_INOUT */ + const char *name; + uint32_t length; + fstHandle handle; + unsigned is_alias : 1; + } var; + } u; +}; + + +/* + * writer functions + */ +fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir vd, + uint32_t len, const char *nam, fstHandle aliasHandle); + +void fstWriterSetPackType(void *ctx, int typ); /* type = 0 (libz), 1 (fastlz) */ +void fstWriterSetRepackOnClose(void *ctx, int enable); /* type = 0 (none), 1 (libz) */ +void fstWriterSetDumpSizeLimit(void *ctx, uint64_t numbytes); +int fstWriterGetDumpSizeLimitReached(void *ctx); + +void *fstWriterCreate(const char *nam, int use_compressed_hier); +void fstWriterClose(void *ctx); +void fstWriterSetDate(void *ctx, const char *dat); +void fstWriterSetVersion(void *ctx, const char *vers); +void fstWriterSetTimescale(void *ctx, int ts); +void fstWriterSetTimescaleFromString(void *ctx, const char *s); +void fstWriterSetScope(void *ctx, enum fstScopeType scopetype, + const char *scopename, const char *scopecomp); +void fstWriterSetUpscope(void *ctx); +void fstWriterEmitValueChange(void *ctx, fstHandle handle, void *val); +void fstWriterEmitDumpActive(void *ctx, int enable); +void fstWriterEmitTimeChange(void *ctx, uint64_t tim); +void fstWriterFlushContext(void *ctx); + +/* + * reader functions + */ +void *fstReaderOpen(const char *nam); +void fstReaderClose(void *ctx); + +void fstReaderProcessHier(void *ctx, FILE *vcdhandle); +void fstReaderIterateHierRewind(void *ctx); +struct fstHier *fstReaderIterateHier(void *ctx); + +void fstReaderResetScope(void *ctx); +const char *fstReaderPopScope(void *ctx); +const char *fstReaderPushScope(void *ctx, const char *nam, void *user_info); +const char *fstReaderGetCurrentFlatScope(void *ctx); +void *fstReaderGetCurrentScopeUserInfo(void *ctx); + +signed char fstReaderGetTimescale(void *ctx); +uint64_t fstReaderGetStartTime(void *ctx); +uint64_t fstReaderGetEndTime(void *ctx); +uint64_t fstReaderGetMemoryUsedByWriter(void *ctx); +uint64_t fstReaderGetScopeCount(void *ctx); +uint64_t fstReaderGetVarCount(void *ctx); +fstHandle fstReaderGetMaxHandle(void *ctx); +uint64_t fstReaderGetAliasCount(void *ctx); +uint64_t fstReaderGetValueChangeSectionCount(void *ctx); +int fstReaderGetDoubleEndianMatchState(void *ctx); +const char *fstReaderGetVersionString(void *ctx); +const char *fstReaderGetDateString(void *ctx); + +void fstReaderSetLimitTimeRange(void *ctx, uint64_t start_time, uint64_t end_time); +void fstReaderSetUnlimitedTimeRange(void *ctx); + +uint32_t fstReaderGetNumberDumpActivityChanges(void *ctx); +uint64_t fstReaderGetDumpActivityChangeTime(void *ctx, uint32_t idx); +unsigned char fstReaderGetDumpActivityChangeValue(void *ctx, uint32_t idx); + +int fstReaderGetFacProcessMask(void *ctx, fstHandle facidx); +void fstReaderSetFacProcessMask(void *ctx, fstHandle facidx); +void fstReaderClrFacProcessMask(void *ctx, fstHandle facidx); +void fstReaderSetFacProcessMaskAll(void *ctx); +void fstReaderClrFacProcessMaskAll(void *ctx); + +void fstReaderIterBlocksSetNativeDoublesOnCallback(void *ctx, int enable); + +int 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 *vcdhandle); + +char *fstReaderGetValueFromHandleAtTime(void *ctx, uint64_t tim, fstHandle facidx, char *buf); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vpi/sys_fst.c b/vpi/sys_fst.c new file mode 100644 index 000000000..ca838a8fb --- /dev/null +++ b/vpi/sys_fst.c @@ -0,0 +1,868 @@ +/* + * Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "sys_priv.h" +# include "vcd_priv.h" +# include "fstapi.h" + +/* + * This file contains the implementations of the VCD related + * funcitons. + */ + +# include +# include +# include +# include +# include +#ifdef HAVE_MALLOC_H +# include +#endif + +static char *dump_path = NULL; +static struct fstContext *dump_file = NULL; + +struct vcd_info { + vpiHandle item; + vpiHandle cb; + struct t_vpi_time time; + struct vcd_info *next; + struct vcd_info *dmp_next; + fstHandle handle; + int scheduled; +}; + + +static struct vcd_info *vcd_list = NULL; +static struct vcd_info *vcd_dmp_list = NULL; +static PLI_UINT64 vcd_cur_time = 0; +static int dump_is_off = 0; +static long dump_limit = 0; +static int dump_is_full = 0; +static int finish_status = 0; + + +static const char*units_names[] = { + "s", + "ms", + "us", + "ns", + "ps", + "fs" +}; + +static void show_this_item(struct vcd_info*info) +{ + s_vpi_value value; + PLI_INT32 type = vpi_get(vpiType, info->item); + + if (type == vpiRealVar) { + value.format = vpiRealVal; + vpi_get_value(info->item, &value); + fstWriterEmitValueChange(dump_file, info->handle, &value.value.real); + } else { + value.format = vpiBinStrVal; + vpi_get_value(info->item, &value); + fstWriterEmitValueChange(dump_file, info->handle, value.value.str); + } +} + +/* Dump values for a $dumpoff. */ +static void show_this_item_x(struct vcd_info*info) +{ + PLI_INT32 type = vpi_get(vpiType, info->item); + + if (type == vpiRealVar) { + /* Some tools dump nothing here...? */ + double mynan = strtod("NaN", NULL); + fstWriterEmitValueChange(dump_file, info->handle, &mynan); + } else if (type == vpiNamedEvent) { + /* Do nothing for named events. */ + } else { + int siz = vpi_get(vpiSize, info->item); + char *xmem = malloc(siz); + memset(xmem, 'x', siz); + fstWriterEmitValueChange(dump_file, info->handle, xmem); + free(xmem); + } +} + + +/* + * managed qsorted list of scope names/variables for duplicates bsearching + */ + +struct vcd_names_list_s fst_tab = { 0 }; +struct vcd_names_list_s fst_var = { 0 }; + + +static int dumpvars_status = 0; /* 0:fresh 1:cb installed, 2:callback done */ +static PLI_UINT64 dumpvars_time; +__inline__ static int dump_header_pending(void) +{ + return dumpvars_status != 2; +} + +/* + * This function writes out all the traced variables, whether they + * changed or not. + */ +static void vcd_checkpoint() +{ + struct vcd_info*cur; + + for (cur = vcd_list ; cur ; cur = cur->next) + show_this_item(cur); +} + +static void vcd_checkpoint_x() +{ + struct vcd_info*cur; + + for (cur = vcd_list ; cur ; cur = cur->next) + show_this_item_x(cur); +} + +static PLI_INT32 variable_cb_2(p_cb_data cause) +{ + struct vcd_info* info = vcd_dmp_list; + PLI_UINT64 now = timerec_to_time64(cause->time); + + if (now != vcd_cur_time) { + fstWriterEmitTimeChange(dump_file, now); + vcd_cur_time = now; + } + + do { + show_this_item(info); + info->scheduled = 0; + } while ((info = info->dmp_next) != 0); + + vcd_dmp_list = 0; + + return 0; +} + +static PLI_INT32 variable_cb_1(p_cb_data cause) +{ + struct t_cb_data cb; + struct vcd_info*info = (struct vcd_info*)cause->user_data; + + if (dump_is_full) return 0; + if (dump_is_off) return 0; + if (dump_header_pending()) return 0; + if (info->scheduled) return 0; + + if ((dump_limit > 0) && fstWriterGetDumpSizeLimitReached(dump_file)) { + dump_is_full = 1; + vpi_printf("WARNING: Dump file limit (%ld bytes) " + "exceeded.\n", dump_limit); + return 0; + } + + if (!vcd_dmp_list) { + cb = *cause; + cb.reason = cbReadOnlySynch; + cb.cb_rtn = variable_cb_2; + vpi_register_cb(&cb); + } + + info->scheduled = 1; + info->dmp_next = vcd_dmp_list; + vcd_dmp_list = info; + + return 0; +} + +static PLI_INT32 dumpvars_cb(p_cb_data cause) +{ + if (dumpvars_status != 1) return 0; + + dumpvars_status = 2; + + dumpvars_time = timerec_to_time64(cause->time); + vcd_cur_time = dumpvars_time; + + /* nothing to do for $enddefinitions $end */ + + if (!dump_is_off) { + fstWriterEmitTimeChange(dump_file, dumpvars_time); + /* nothing to do for $dumpvars... */ + vcd_checkpoint(); + /* ...nothing to do for $end */ + } + + return 0; +} + +static PLI_INT32 finish_cb(p_cb_data cause) +{ + struct vcd_info *cur, *next; + + if (finish_status != 0) return 0; + + finish_status = 1; + + dumpvars_time = timerec_to_time64(cause->time); + + if (!dump_is_off && !dump_is_full && dumpvars_time != vcd_cur_time) { + fstWriterEmitTimeChange(dump_file, dumpvars_time); + } + + fstWriterClose(dump_file); + + for (cur = vcd_list ; cur ; cur = next) { + next = cur->next; + free(cur); + } + vcd_list = 0; + vcd_names_delete(&fst_tab); + vcd_names_delete(&fst_var); + nexus_ident_delete(); + free(dump_path); + dump_path = 0; + + return 0; +} + +__inline__ static int install_dumpvars_callback(void) +{ + struct t_cb_data cb; + static struct t_vpi_time now; + + if (dumpvars_status == 1) return 0; + + if (dumpvars_status == 2) { + vpi_printf("FST warning: $dumpvars ignored, previously" + " called at simtime %" PLI_UINT64_FMT "\n", + dumpvars_time); + return 1; + } + + now.type = vpiSimTime; + cb.time = &now; + cb.reason = cbReadOnlySynch; + cb.cb_rtn = dumpvars_cb; + cb.user_data = 0x0; + cb.obj = 0x0; + + vpi_register_cb(&cb); + + cb.reason = cbEndOfSimulation; + cb.cb_rtn = finish_cb; + + vpi_register_cb(&cb); + + dumpvars_status = 1; + return 0; +} + +static PLI_INT32 sys_dumpoff_calltf(PLI_BYTE8*name) +{ + s_vpi_time now; + PLI_UINT64 now64; + + if (dump_is_off) return 0; + + dump_is_off = 1; + + if (dump_file == 0) return 0; + if (dump_header_pending()) return 0; + + now.type = vpiSimTime; + vpi_get_time(0, &now); + now64 = timerec_to_time64(&now); + + if (now64 > vcd_cur_time) { + fstWriterEmitTimeChange(dump_file, now64); + vcd_cur_time = now64; + } + + fstWriterEmitDumpActive(dump_file, 0); /* $dumpoff */ + vcd_checkpoint_x(); + + return 0; +} + +static PLI_INT32 sys_dumpon_calltf(PLI_BYTE8*name) +{ + s_vpi_time now; + PLI_UINT64 now64; + + if (!dump_is_off) return 0; + + dump_is_off = 0; + + if (dump_file == 0) return 0; + if (dump_header_pending()) return 0; + + now.type = vpiSimTime; + vpi_get_time(0, &now); + now64 = timerec_to_time64(&now); + + if (now64 > vcd_cur_time) { + fstWriterEmitTimeChange(dump_file, now64); + vcd_cur_time = now64; + } + + fstWriterEmitDumpActive(dump_file, 1); /* $dumpon */ + vcd_checkpoint(); + + return 0; +} + +static PLI_INT32 sys_dumpall_calltf(PLI_BYTE8*name) +{ + s_vpi_time now; + PLI_UINT64 now64; + + if (dump_is_off) return 0; + if (dump_file == 0) return 0; + if (dump_header_pending()) return 0; + + now.type = vpiSimTime; + vpi_get_time(0, &now); + now64 = timerec_to_time64(&now); + + if (now64 > vcd_cur_time) { + fstWriterEmitTimeChange(dump_file, now64); + vcd_cur_time = now64; + } + + /* nothing to do for $dumpall... */ + vcd_checkpoint(); + + return 0; +} + +static void open_dumpfile(vpiHandle callh) +{ + if (dump_path == 0) dump_path = strdup("dump.fst"); + + dump_file = fstWriterCreate(dump_path, 1); + + if (dump_file == 0) { + vpi_printf("FST Error: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("Unable to open %s for output.\n", dump_path); + vpi_control(vpiFinish, 1); + return; + } else { + int prec = vpi_get(vpiTimePrecision, 0); + unsigned scale = 1; + unsigned udx = 0; + time_t walltime; + char scale_buf[65]; + + vpi_printf("FST info: dumpfile %s opened for output.\n", + dump_path); + + time(&walltime); + + assert(prec >= -15); + while (prec < 0) { + udx += 1; + prec += 3; + } + while (prec > 0) { + scale *= 10; + prec -= 1; + } + + fstWriterSetDate(dump_file, asctime(localtime(&walltime))); + fstWriterSetVersion(dump_file, "Icarus Verilog"); + sprintf(scale_buf, "\t%u%s\n", scale, units_names[udx]); + fstWriterSetTimescaleFromString(dump_file, scale_buf); + } +} + +static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + char *path; + + /* $dumpfile must be called before $dumpvars starts! */ + if (dumpvars_status != 0) { + char msg [64]; + snprintf(msg, 64, "FST warning: %s:%d:", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s %s called after $dumpvars started,\n", msg, name); + vpi_printf("%*s using existing file (%s).\n", + (int) strlen(msg), " ", dump_path); + vpi_free_object(argv); + return 0; + } + + path = get_filename(callh, name, vpi_scan(argv)); + vpi_free_object(argv); + if (! path) return 0; + + if (dump_path) { + vpi_printf("FST warning: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("Overriding dump file %s with %s.\n", dump_path, path); + free(dump_path); + } + dump_path = path; + + return 0; +} + +static PLI_INT32 sys_dumpflush_calltf(PLI_BYTE8*name) +{ + if (dump_file) fstWriterFlushContext(dump_file); + + return 0; +} + +static PLI_INT32 sys_dumplimit_calltf(PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + s_vpi_value val; + + /* Get the value and set the dump limit. */ + val.format = vpiIntVal; + vpi_get_value(vpi_scan(argv), &val); + dump_limit = val.value.integer; + fstWriterSetDumpSizeLimit(dump_file, dump_limit); + + vpi_free_object(argv); + return 0; +} + +static void scan_item(unsigned depth, vpiHandle item, int skip) +{ + struct t_cb_data cb; + struct vcd_info* info; + + PLI_INT32 type; + const char* name; + const char* fullname; + const char* prefix; + const char *ident; + fstHandle new_ident; + int nexus_id; + unsigned size; + PLI_INT32 item_type; + + /* list of types to iterate upon */ + int i; + static int types[] = { + /* Value */ + vpiNamedEvent, + vpiNet, +// vpiParameter, + vpiReg, + vpiVariables, + /* Scope */ + vpiFunction, + vpiModule, + vpiNamedBegin, + vpiNamedFork, + vpiTask, + -1 + }; + + /* Get the displayed type for the various $var and $scope types. */ + /* Not all of these are supported now, but they should be in a + * future development version. */ + item_type = vpi_get(vpiType, item); + switch (item_type) { + case vpiNamedEvent: type = FST_VT_VCD_EVENT; break; + case vpiIntegerVar: type = FST_VT_VCD_INTEGER; break; + case vpiParameter: type = FST_VT_VCD_PARAMETER; break; + /* Icarus converts realtime to real. */ + case vpiRealVar: type = FST_VT_VCD_REAL; break; + case vpiMemoryWord: + case vpiReg: type = FST_VT_VCD_REG; break; + /* Icarus converts a time to a plain register. */ + case vpiTimeVar: type = FST_VT_VCD_TIME; break; + case vpiNet: + switch (vpi_get(vpiNetType, item)) { + case vpiWand: type = FST_VT_VCD_WAND; break; + case vpiWor: type = FST_VT_VCD_WOR; break; + case vpiTri: type = FST_VT_VCD_TRI; break; + case vpiTri0: type = FST_VT_VCD_TRI0; break; + case vpiTri1: type = FST_VT_VCD_TRI1; break; + case vpiTriReg: type = FST_VT_VCD_TRIREG; break; + case vpiTriAnd: type = FST_VT_VCD_TRIAND; break; + case vpiTriOr: type = FST_VT_VCD_TRIOR; break; + case vpiSupply1: type = FST_VT_VCD_SUPPLY1; break; + case vpiSupply0: type = FST_VT_VCD_SUPPLY0; break; + default: type = FST_VT_VCD_WIRE; break; + } + break; + + case vpiNamedBegin: type = FST_ST_VCD_BEGIN; break; + case vpiNamedFork: type = FST_ST_VCD_FORK; break; + case vpiFunction: type = FST_ST_VCD_FUNCTION; break; + case vpiModule: type = FST_ST_VCD_MODULE; break; + case vpiTask: type = FST_ST_VCD_TASK; break; + + default: + vpi_printf("FST warning: $dumpvars: Unsupported argument " + "type (%s)\n", vpi_get_str(vpiType, item)); + return; + } + + /* Do some special processing/checking on array words. Dumping + * array words is an Icarus extension. */ + if (item_type == vpiMemoryWord) { + /* Turn a non-constant array word select into a constant + * word select. */ + if (vpi_get(vpiConstantSelect, item) == 0) { + vpiHandle array = vpi_handle(vpiParent, item); + PLI_INT32 idx = vpi_get(vpiIndex, item); + item = vpi_handle_by_index(array, idx); + } + + /* An array word is implicitly escaped so look for an + * escaped identifier that this could conflict with. */ + /* This does not work as expected since we always find at + * least the array word. We likely need a custom routine. */ + if (vpi_get(vpiType, item) == vpiMemoryWord && + vpi_handle_by_name(vpi_get_str(vpiFullName, item), 0)) { + vpi_printf("FST warning: array word %s will conflict " + "with an escaped identifier.\n", + vpi_get_str(vpiFullName, item)); + } + } + + fullname = vpi_get_str(vpiFullName, item); + + /* Generate the $var or $scope commands. */ + switch (item_type) { + case vpiParameter: + vpi_printf("VCD sorry: $dumpvars: can not dump parameters.\n"); + break; + + case vpiNamedEvent: + case vpiIntegerVar: +// case vpiParameter: + case vpiRealVar: + case vpiMemoryWord: + case vpiReg: + case vpiTimeVar: + case vpiNet: + + /* If we are skipping all signal or this is in an automatic + * scope then just return. */ + if (skip || vpi_get(vpiAutomatic, item)) return; + + /* Skip this signal if it has already been included. + * This can only happen for implicitly given signals. */ + if (vcd_names_search(&fst_var, fullname)) return; + + /* Declare the variable in the VCD file. */ + name = vpi_get_str(vpiName, item); + prefix = is_escaped_id(name) ? "\\" : ""; + + /* Some signals can have an alias so handle that. */ + nexus_id = vpi_get(_vpiNexusId, item); + + ident = 0; + if (nexus_id) ident = find_nexus_ident(nexus_id); + + /* Named events do not have a size, but other tools use + * a size of 1 and some viewers do not accept a width of + * zero so we will also use a width of one for events. */ + if (item_type == vpiNamedEvent) size = 1; + else size = vpi_get(vpiSize, item); + + + if (vpi_get(vpiSize, item) > 1 + || vpi_get(vpiLeftRange, item) != 0) + { + int slen = strlen(name); + char *buf = malloc(slen + 65); + sprintf(buf, "%s [%i:%i]", name, + (int)vpi_get(vpiLeftRange, item), + (int)vpi_get(vpiRightRange, item)); + + + new_ident = fstWriterCreateVar(dump_file, type, FST_VD_IMPLICIT, size, buf, (fstHandle)ident); + free(buf); + } + else + { + new_ident = fstWriterCreateVar(dump_file, type, FST_VD_IMPLICIT, size, name, (fstHandle)ident); + } + + if (!ident) { + if (nexus_id) set_nexus_ident(nexus_id, (const char *)new_ident); + + /* Add a callback for the signal. */ + info = malloc(sizeof(*info)); + + info->time.type = vpiSimTime; + info->item = item; + info->handle = new_ident; + info->scheduled = 0; + + cb.time = &info->time; + cb.user_data = (char*)info; + cb.value = NULL; + cb.obj = item; + cb.reason = cbValueChange; + cb.cb_rtn = variable_cb_1; + + info->dmp_next = 0; + info->next = vcd_list; + vcd_list = info; + + info->cb = vpi_register_cb(&cb); + } + + break; + + case vpiModule: + case vpiNamedBegin: + case vpiTask: + case vpiFunction: + case vpiNamedFork: + + if (depth > 0) { + int nskip = (vcd_names_search(&fst_tab, fullname) != 0); + + /* We have to always scan the scope because the + * depth could be different for this call. */ + if (nskip) { + vpi_printf("FST warning: ignoring signals in " + "previously scanned scope %s.\n", fullname); + } else { + vcd_names_add(&fst_tab, fullname); + vcd_names_sort(&fst_tab); + } + + name = vpi_get_str(vpiName, item); + fstWriterSetScope(dump_file, type, name, NULL); + + for (i=0; types[i]>0; i++) { + vpiHandle hand; + vpiHandle argv = vpi_iterate(types[i], item); + while (argv && (hand = vpi_scan(argv))) { + scan_item(depth-1, hand, nskip); + } + } + + /* Sort any signals that we added above. */ + fstWriterSetUpscope(dump_file); + } + break; + } +} + +static int draw_scope(vpiHandle item, vpiHandle callh) +{ + int depth; + const char *name; + PLI_INT32 type; + + vpiHandle scope = vpi_handle(vpiScope, item); + if (!scope) return 0; + + depth = 1 + draw_scope(scope, callh); + name = vpi_get_str(vpiName, scope); + + switch (vpi_get(vpiType, scope)) { + case vpiNamedBegin: type = FST_ST_VCD_BEGIN; break; + case vpiTask: type = FST_ST_VCD_TASK; break; + case vpiFunction: type = FST_ST_VCD_FUNCTION; break; + case vpiNamedFork: type = FST_ST_VCD_FORK; break; + case vpiModule: type = FST_ST_VCD_MODULE; break; + default: + type = FST_ST_VCD_MODULE; + vpi_printf("FST Error: %s:%d: $dumpvars: Unsupported scope " + "type (%d)\n", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh), + (int)vpi_get(vpiType, item)); + assert(0); + } + + fstWriterSetScope(dump_file, type, name, NULL); + + return depth; +} + +static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle item; + s_vpi_value value; + unsigned depth = 0; + + if (dump_file == 0) { + open_dumpfile(callh); + if (dump_file == 0) { + if (argv) vpi_free_object(argv); + return 0; + } + } + + if (install_dumpvars_callback()) { + if (argv) vpi_free_object(argv); + return 0; + } + + /* Get the depth if it exists. */ + if (argv) { + value.format = vpiIntVal; + vpi_get_value(vpi_scan(argv), &value); + depth = value.value.integer; + } + if (!depth) depth = 10000; + + /* This dumps all the modules in the design if none are given. */ + if (!argv || !(item = vpi_scan(argv))) { + argv = vpi_iterate(vpiModule, 0x0); + assert(argv); /* There must be at least one top level module. */ + item = vpi_scan(argv); + } + + for ( ; item; item = vpi_scan(argv)) { + char *scname; + const char *fullname; + int add_var = 0; + int dep; + PLI_INT32 item_type = vpi_get(vpiType, item); + + /* If this is a signal make sure it has not already + * been included. */ + switch (item_type) { + case vpiIntegerVar: + case vpiMemoryWord: + case vpiNamedEvent: + case vpiNet: + case vpiParameter: + case vpiRealVar: + case vpiReg: + case vpiTimeVar: + /* Warn if the variables scope (which includes the + * variable) or the variable itself was already + * included. A scope does not automatically include + * memory words so do not check the scope for them. */ + scname = strdup(vpi_get_str(vpiFullName, + vpi_handle(vpiScope, item))); + fullname = vpi_get_str(vpiFullName, item); + if (((item_type != vpiMemoryWord) && + vcd_names_search(&fst_tab, scname)) || + vcd_names_search(&fst_var, fullname)) { + vpi_printf("FST warning: skipping signal %s, " + "it was previously included.\n", + fullname); + free(scname); + continue; + } else { + add_var = 1; + } + free(scname); + } + + dep = draw_scope(item, callh); + + scan_item(depth, item, 0); + + while (dep--) fstWriterSetUpscope(dump_file); + + /* Add this signal to the variable list so we can verify it + * is not included twice. This must be done after it has + * been added */ + if (add_var) { + vcd_names_add(&fst_var, vpi_get_str(vpiFullName, item)); + vcd_names_sort(&fst_var); + } + } + + return 0; +} + +void sys_fst_register() +{ + s_vpi_systf_data tf_data; + vpiHandle res; + + /* All the compiletf routines are located in vcd_priv.c. */ + + tf_data.type = vpiSysTask; + tf_data.tfname = "$dumpall"; + tf_data.calltf = sys_dumpall_calltf; + tf_data.compiletf = sys_no_arg_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$dumpall"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); + + tf_data.type = vpiSysTask; + tf_data.tfname = "$dumpfile"; + tf_data.calltf = sys_dumpfile_calltf; + tf_data.compiletf = sys_one_string_arg_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$dumpfile"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); + + tf_data.type = vpiSysTask; + tf_data.tfname = "$dumpflush"; + tf_data.calltf = sys_dumpflush_calltf; + tf_data.compiletf = sys_no_arg_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$dumpflush"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); + + tf_data.type = vpiSysTask; + tf_data.tfname = "$dumplimit"; + tf_data.calltf = sys_dumplimit_calltf; + tf_data.compiletf = sys_one_numeric_arg_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$dumplimit"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); + + tf_data.type = vpiSysTask; + tf_data.tfname = "$dumpoff"; + tf_data.calltf = sys_dumpoff_calltf; + tf_data.compiletf = sys_no_arg_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$dumpoff"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); + + tf_data.type = vpiSysTask; + tf_data.tfname = "$dumpon"; + tf_data.calltf = sys_dumpon_calltf; + tf_data.compiletf = sys_no_arg_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$dumpon"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); + + tf_data.type = vpiSysTask; + tf_data.tfname = "$dumpvars"; + tf_data.calltf = sys_dumpvars_calltf; + tf_data.compiletf = sys_dumpvars_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$dumpvars"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); +} diff --git a/vpi/sys_table.c b/vpi/sys_table.c index 4560744e7..6500a7fac 100644 --- a/vpi/sys_table.c +++ b/vpi/sys_table.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -47,9 +47,11 @@ extern void sys_lxt_register(); static void sys_lxt_register() { fputs("LXT support disabled since libbzip2 not available\n",stderr); exit(1); } #endif extern void sys_lxt2_register(); +extern void sys_fst_register(); #else static void sys_lxt_register() { fputs("LXT support disabled since zlib not available\n",stderr); exit(1); } static void sys_lxt2_register() { fputs("LXT2 support disabled since zlib not available\n",stderr); exit(1); } +static void sys_fst_register() { fputs("FST support disabled since zlib not available\n",stderr); exit(1); } #endif static void sys_lxt_or_vcd_register() @@ -78,7 +80,13 @@ static void sys_lxt_or_vcd_register() for (idx = 0 ; idx < vlog_info.argc ; idx += 1) { - if (strcmp(vlog_info.argv[idx],"-lxt") == 0) { + if (strcmp(vlog_info.argv[idx],"-fst") == 0) { + dumper = "fst"; + + } else if (strcmp(vlog_info.argv[idx],"-fst-none") == 0) { + dumper = "none"; + + } else if (strcmp(vlog_info.argv[idx],"-lxt") == 0) { dumper = "lxt"; } else if (strcmp(vlog_info.argv[idx],"-lxt-space") == 0) { @@ -135,6 +143,12 @@ static void sys_lxt_or_vcd_register() else if (strcmp(dumper, "VCD") == 0) sys_vcd_register(); + else if (strcmp(dumper, "fst") == 0) + sys_fst_register(); + + else if (strcmp(dumper, "FST") == 0) + sys_fst_register(); + else if (strcmp(dumper, "lxt") == 0) sys_lxt_register(); diff --git a/vvp/vvp.man.in b/vvp/vvp.man.in index 02ab5b6d7..5d65d2bdb 100644 --- a/vvp/vvp.man.in +++ b/vvp/vvp.man.in @@ -1,4 +1,4 @@ -.TH vvp 1 "April 17th, 2009" "" "Version %M.%m.%n %E" +.TH vvp 1 "May 21st, 2010" "" "Version %M.%m.%n %E" .SH NAME vvp - Icarus Verilog vvp runtime engine @@ -102,10 +102,15 @@ space, and is written out incrementally. Thus, you can view lxt2 files while a simulation is still running (or paused) or if your simulation crashes or is killed, you still have a useful dump. +.TP 8 +.B -fst +A modern dumping format this is both faster and more compact than the +other dumping formats. + .TP 8 .B -none This flag can be used by itself or appended to the end of the above -dumpers (vcd/lxt/lxt2/lx2) to suppress all waveform output. This can +dumpers (vcd/lxt/lxt2/lx2/fst) to suppress all waveform output. This can make long simulations run faster. .TP 8 @@ -128,7 +133,7 @@ The vvp command also accepts some environment variables that control its behavior. These can be used to make semi-permanent changes. .TP 8 -.B IVERILOG_DUMPER=\fIlxt|lxt2|lx2|vcd|none\fP +.B IVERILOG_DUMPER=\fIfst|lxt|lxt2|lx2|vcd|none\fP This selects the output format for the waveform output. Normally, waveforms are dumped in vcd format, but this variable can be used to select lxt format, which is far more compact, though limited to @@ -158,7 +163,7 @@ iverilog\-vpi(1), .SH COPYRIGHT .nf -Copyright \(co 2001\-2009 Stephen Williams +Copyright \(co 2001\-2010 Stephen Williams This document can be freely redistributed according to the terms of the GNU General Public License version 2.0