diff --git a/vpi/Makefile.in b/vpi/Makefile.in index d3cd4226f..a7c85bace 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -67,6 +67,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..4c2203a6b --- /dev/null +++ b/vpi/fstapi.c @@ -0,0 +1,4211 @@ +/* + * 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 +#if defined(__SUNPRO_C) +#define FST_CADDR_T_CAST (caddr_t) +#else +#define FST_CADDR_T_CAST +#endif +#define fstMmap(__addr,__len,__prot,__flags,__fd,__off) (void*)mmap(FST_CADDR_T_CAST (__addr),(__len),(__prot),(__flags),(__fd),(__off)) +#define fstMunmap(__addr,__len) { if(__addr) munmap(FST_CADDR_T_CAST (__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, int is_closing) +{ +fstMunmap(xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t)); +xc->valpos_mem = NULL; + +#if defined __CYGWIN__ || defined __MINGW32__ +if(xc->curval_mem) + { + if(!is_closing) /* need to flush out for next emulated mmap() read */ + { + unsigned char *pnt = xc->curval_mem; + int __fd = fileno(xc->curval_handle); + off_t cur_offs = lseek(__fd, 0, SEEK_CUR); + size_t i; + size_t __len = xc->maxvalpos; + + lseek(__fd, 0, SEEK_SET); + for(i=0;i<__len;i+=SSIZE_MAX) + { + write(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i)); + } + lseek(__fd, cur_offs, SEEK_SET); + } + } +#endif + +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, 1); + + /* 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; + 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); + 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 + + 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 seconds_exp = -9; + int tv = atoi(s); + const char *pnt = s; + + while(*pnt) + { + switch(*pnt) + { + case 'm': seconds_exp = -3; mat = 1; break; + case 'u': seconds_exp = -6; mat = 1; break; + case 'n': seconds_exp = -9; mat = 1; break; + case 'p': seconds_exp = -12; mat = 1; break; + case 'f': seconds_exp = -15; mat = 1; break; + case 'a': seconds_exp = -18; mat = 1; break; + case 'z': seconds_exp = -21; mat = 1; break; + case 's': seconds_exp = -0; mat = 1; break; + default: break; + } + + if(mat) break; + pnt++; + } + + if(tv == 10) + { + seconds_exp++; + } + else + if(tv == 100) + { + seconds_exp+=2; + } + + fstWriterSetTimescale(ctx, seconds_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, 0); + } + + 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; + +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; +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; + +free(xc->signal_lens); +xc->signal_lens = malloc(num_signal_dyn*sizeof(uint32_t)); + +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, but need to advance read pointer */ + 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)); + +free(xc->process_mask); +xc->process_mask = calloc(1, (xc->maxhandle+7)/8); + +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; + + seclen = fstReaderUint64(xc->f); + uclen = fstReaderUint64(xc->f); + + if(!seclen) return(0); /* not finished compressing, this is a failed read */ + + 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 + + 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) + { + union { + unsigned char rvs_buf[8]; + double d; + } vu; + + unsigned char *dcheck_alias = (unsigned char *)&dcheck; + int rvs_idx; + + for(rvs_idx=0;rvs_idx<8;rvs_idx++) + { + vu.rvs_buf[rvs_idx] = dcheck_alias[7-rvs_idx]; + } + if(vu.d != 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 */ + + 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); + } + + free(xc->signal_lens); + xc->signal_lens = malloc(sizeof(uint32_t) * xc->maxhandle); + 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 */ + } + } + + 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); + free(xc->blackout_times); + xc->blackout_times = calloc(xc->num_blackouts, sizeof(uint64_t)); + 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) + { + free(xc->rvat_chain_mem); xc->rvat_chain_mem = NULL; + free(xc->rvat_frame_data); xc->rvat_frame_data = NULL; + free(xc->rvat_time_table); xc->rvat_time_table = NULL; + free(xc->rvat_chain_table); xc->rvat_chain_table = NULL; + 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); + free(xc->rvat_sig_offs); xc->rvat_sig_offs = NULL; + + free(xc->process_mask); xc->process_mask = NULL; + free(xc->blackout_times); xc->blackout_times = NULL; + free(xc->blackout_activity); xc->blackout_activity = NULL; + free(xc->temp_signal_value_buf); xc->temp_signal_value_buf = NULL; + free(xc->signal_typs); xc->signal_typs = NULL; + free(xc->signal_lens); xc->signal_lens = NULL; + 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 = UINT64_MAX; +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); + } + + 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); + } + +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..bbac88663 --- /dev/null +++ b/vpi/sys_fst.c @@ -0,0 +1,899 @@ +/* + * 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 enum lxm_optimum_mode_e { + LXM_NONE = 0, + LXM_SPACE = 1, + LXM_SPEED = 2, + LXM_BOTH = 3 +} lxm_optimum_mode = LXM_NONE; + +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); + /* Set the faster dump type when requested. */ + if ((lxm_optimum_mode == LXM_SPEED) || + (lxm_optimum_mode == LXM_BOTH)) { + fstWriterSetPackType(dump_file, 1); + } + /* Set the most effective compression when requested. */ + if ((lxm_optimum_mode == LXM_SPACE) || + (lxm_optimum_mode == LXM_BOTH)) { + fstWriterSetRepackOnClose(dump_file, 1); + } + } +} + +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)(long)ident); + free(buf); + } else { + new_ident = fstWriterCreateVar(dump_file, type, + FST_VD_IMPLICIT, size, name, + (fstHandle)(long)ident); + } + + if (!ident) { + if (nexus_id) set_nexus_ident(nexus_id, + (const char *)(long)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); + } + + 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); + /* The scope list must be sorted after we scan an item. */ + vcd_names_sort(&fst_tab); + + 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() +{ + int idx; + struct t_vpi_vlog_info vlog_info; + s_vpi_systf_data tf_data; + + /* Scan the extended arguments, looking for fst optimization flags. */ + vpi_get_vlog_info(&vlog_info); + + /* The "speed" option is not used in this dumper. */ + for (idx = 0 ; idx < vlog_info.argc ; idx += 1) { + if (strcmp(vlog_info.argv[idx],"-fst-space") == 0) { + lxm_optimum_mode = LXM_SPACE; + + } else if (strcmp(vlog_info.argv[idx],"-fst-speed") == 0) { + lxm_optimum_mode = LXM_SPEED; + + } else if (strcmp(vlog_info.argv[idx],"-fst-space-speed") == 0) { + lxm_optimum_mode = LXM_BOTH; + } else if (strcmp(vlog_info.argv[idx],"-fst-speed-space") == 0) { + lxm_optimum_mode = LXM_BOTH; + } + } + + /* 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"; + vpi_register_systf(&tf_data); + + 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"; + vpi_register_systf(&tf_data); + + 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"; + vpi_register_systf(&tf_data); + + 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"; + vpi_register_systf(&tf_data); + + 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"; + vpi_register_systf(&tf_data); + + 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"; + vpi_register_systf(&tf_data); + + 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"; + vpi_register_systf(&tf_data); +} diff --git a/vpi/sys_table.c b/vpi/sys_table.c index 4560744e7..f7b1ad2be 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,24 @@ 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-space") == 0) { + dumper = "fst"; + + } else if (strcmp(vlog_info.argv[idx],"-fst-speed") == 0) { + dumper = "fst"; + + } else if (strcmp(vlog_info.argv[idx],"-fst-space-speed") == 0) { + dumper = "fst"; + } else if (strcmp(vlog_info.argv[idx],"-fst-speed-space") == 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 +154,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();