diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/grt/Makefile.inc | 13 | ||||
| -rw-r--r-- | src/grt/fst/block_format.txt | 130 | ||||
| -rw-r--r-- | src/grt/fst/config.h | 2 | ||||
| -rw-r--r-- | src/grt/fst/fastlz.c | 547 | ||||
| -rw-r--r-- | src/grt/fst/fastlz.h | 107 | ||||
| -rw-r--r-- | src/grt/fst/fstapi.c | 6531 | ||||
| -rw-r--r-- | src/grt/fst/fstapi.h | 426 | ||||
| -rw-r--r-- | src/grt/fst/lz4.c | 1267 | ||||
| -rw-r--r-- | src/grt/fst/lz4.h | 323 | ||||
| -rw-r--r-- | src/grt/grt-fst.adb | 474 | ||||
| -rw-r--r-- | src/grt/grt-fst.ads | 28 | ||||
| -rw-r--r-- | src/grt/grt-fst_api.ads | 353 | ||||
| -rw-r--r-- | src/grt/grt-modules.adb | 2 | ||||
| -rw-r--r-- | src/grt/grt-vcd.adb | 3 | ||||
| -rw-r--r-- | src/grt/grt-vcd.ads | 2 | 
15 files changed, 10205 insertions, 3 deletions
diff --git a/src/grt/Makefile.inc b/src/grt/Makefile.inc index bc59bb555..3bd6ac2cb 100644 --- a/src/grt/Makefile.inc +++ b/src/grt/Makefile.inc @@ -96,8 +96,10 @@ ifndef GRT_TARGET_OBJS    GRT_EXTRA_LIB=-lpthread -ldl -lm  endif +GRT_FST_OBJS := fstapi.o lz4.o fastlz.o +  # Additionnal object files (C or asm files). -GRT_ADD_OBJS:=$(GRT_TARGET_OBJS) grt-cbinding.o grt-cvpi.o +GRT_ADD_OBJS:=$(GRT_TARGET_OBJS) grt-cbinding.o grt-cvpi.o $(GRT_FST_OBJS)  #GRT_USE_PTHREADS=y  ifeq ($(GRT_USE_PTHREADS),y) @@ -183,6 +185,15 @@ grt-cvpi.o: $(GRTSRCDIR)/grt-cvpi.c  grt-cthreads.o: $(GRTSRCDIR)/grt-cthreads.c  	$(CC) -c $(GRT_FLAGS) -o $@ $< +fstapi.o: $(GRTSRCDIR)/fst/fstapi.c +	$(CC) -c $(GRT_FLAGS) -o $@ -I$(GRTSRCDIR)/fst $< + +lz4.o: $(GRTSRCDIR)/fst/lz4.c +	$(CC) -c $(GRT_FLAGS) -o $@ $< + +fastlz.o: $(GRTSRCDIR)/fst/fastlz.c +	$(CC) -c $(GRT_FLAGS) -o $@ $< +  grt-disp-config:  	@echo "target: $(target)"  	@echo "targ: $(targ)" diff --git a/src/grt/fst/block_format.txt b/src/grt/fst/block_format.txt new file mode 100644 index 000000000..0cab3a443 --- /dev/null +++ b/src/grt/fst/block_format.txt @@ -0,0 +1,130 @@ +See fstapi.h for the values for the FST_BL_XXX enums. + +=========================================================================== + +compressed wrapper (typically over whole file) + +uint8_t		FST_BL_ZWRAPPER +uint64_t        section length +uint64_t        length of uncompressed data +[zlib compressed data] + +=========================================================================== + +header block + +uint8_t		FST_BL_HDR +uint64_t	section length +uint64_t	start time +uint64_t	end time +double		endian test for "e" +uint64_t	memory used by writer +uint64_t	scope creation count +uint64_t	var creation count +uint64_t	max var idcode +uint64_t	vc section count +int8_t		timescale exponent +[128 bytes]	version +[128 bytes]	date + +=========================================================================== + +geometry block + +uint8_t         FST_BL_GEOM +uint64_t        section length +uint64_t        length of uncompressed geometry data +uint64_t        maxhandle +[compressed data] + +(length of compressed data is section length - 24) + +=========================================================================== + +hierarchy block + +uint8_t         FST_BL_HIER +uint64_t        section length +uint64_t        length of uncompressed hier data +[zlib compressed data] + +or + +uint8_t         FST_BL_HIER_LZ4 +uint64_t        section length +uint64_t        length of uncompressed hier data +[lz4 compressed data] + +uint8_t         FST_BL_HIER_LZ4DUO +uint64_t        section length +uint64_t        length of uncompressed hier data +varint		length of hier data compressed once with lz4 +[lz4 double compressed data] + + +=========================================================================== + +dumpon/off block + +uint8_t         FST_BL_BLACKOUT +uint64_t        section length +varint		num blackouts (section below is repeated this # times) +[ +uint8_t		on/off (nonzero = on) +varint		delta time +] + +=========================================================================== + +1..n value change blocks: + +// header + +uint8_t		FST_BL_VCDATA (or FST_BL_VCDATA_DYN_ALIAS) +uint64_t	section length +uint64_t	begin time of section +uint64_t	end time of section +uint64_t	amount of buffer memory required in reader for full vc traversal +varint		maxvalpos (length of uncompressed data) +varint		length of compressed data +varint		maxhandle associated with this checkpoint data +[compressed data] + +--- + +// value changes + +varint		maxhandle associated with the value change data +uint8_t		pack type ('F' is fastlz, '4' is lz4,  +			others ['Z'/'!'] are zlib) + +varint		chain 0 compressed data length (0 = uncompressed) +[compressed data]	 +... +varint		chain n compressed data length (0 = uncompressed) +[compressed data]	 + +--- + +// index: chain pointer table (from 0..maxhandle-1) + +varint		if &1 == 1, this is <<1 literal delta +		if &1 == 0, this is <<1 RLE count of zeros +		if == 0, next varint is handle of prev chain to use, +			bit only if FST_BL_VCDATA_DYN_ALIAS or +			later VCDATA format + +--- + +uint64_t	index length (subtract from here to get index position) + +--- + +[compressed data for time section] +uint64_t	uncompressed data length in bytes +uint64_t	compressed data length in bytes +uint64_t	number of time items + +// end of section + +=========================================================================== diff --git a/src/grt/fst/config.h b/src/grt/fst/config.h new file mode 100644 index 000000000..71c5a2d31 --- /dev/null +++ b/src/grt/fst/config.h @@ -0,0 +1,2 @@ +/* config.h for fst.  */ +#define HAVE_FSEEKO 1 diff --git a/src/grt/fst/fastlz.c b/src/grt/fst/fastlz.c new file mode 100644 index 000000000..50bf56a46 --- /dev/null +++ b/src/grt/fst/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; */ /* scan-build, never used */ +      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/src/grt/fst/fastlz.h b/src/grt/fst/fastlz.h new file mode 100644 index 000000000..8b4eac2e8 --- /dev/null +++ b/src/grt/fst/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 <inttypes.h> + +#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/src/grt/fst/fstapi.c b/src/grt/fst/fstapi.c new file mode 100644 index 000000000..b0d7dfc40 --- /dev/null +++ b/src/grt/fst/fstapi.c @@ -0,0 +1,6531 @@ +/* + * Copyright (c) 2009-2014 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. + */ + +/* + * possible disables: + * + * FST_DYNAMIC_ALIAS_DISABLE : dynamic aliases are not processed + * FST_DYNAMIC_ALIAS2_DISABLE : new encoding for dynamic aliases is not generated + * FST_WRITEX_DISABLE : fast write I/O routines are disabled + * + * possible enables: + * + * FST_DEBUG : not for production use, only enable for development + * FST_REMOVE_DUPLICATE_VC : glitch removal (has writer performance impact) + * HAVE_LIBPTHREAD -> FST_WRITER_PARALLEL : enables inclusion of parallel writer code + * FST_DO_MISALIGNED_OPS (defined automatically for x86 and some others) : CPU architecture can handle misaligned loads/stores + * _WAVE_HAVE_JUDY : use Judy arrays instead of Jenkins (undefine if LGPL is not acceptable) + * + */ + +#include <config.h> + +#include "fstapi.h" +#include "fastlz.h" +#include "lz4.h" + +#ifndef HAVE_LIBPTHREAD +#undef FST_WRITER_PARALLEL +#endif + +#ifdef FST_WRITER_PARALLEL +#include <pthread.h> +#endif + +#ifdef __MINGW32__ +#include <windows.h> +#endif + +#ifdef HAVE_ALLOCA_H +#include <alloca.h> +#elif defined(__GNUC__) +#ifndef __MINGW32__ +#ifndef alloca +#define alloca __builtin_alloca +#endif +#else +#include <malloc.h> +#endif +#elif defined(_MSC_VER) +#include <malloc.h> +#define alloca _alloca +#endif + +#ifndef PATH_MAX +#define PATH_MAX (4096) +#endif + +/* note that Judy versus Jenkins requires more experimentation: they are  */ +/* functionally equivalent though it appears Jenkins is slightly faster.  */ +/* in addition, Jenkins is not bound by the LGPL.                         */ +#ifdef _WAVE_HAVE_JUDY +#include <Judy.h> +#else +/* should be more than enough for fstWriterSetSourceStem() */ +#define FST_PATH_HASHMASK               ((1UL << 16) - 1) +typedef const void *Pcvoid_t; +typedef void *Pvoid_t; +typedef void **PPvoid_t; +#define JudyHSIns(a,b,c,d) JenkinsIns((a),(b),(c),(hashmask)) +#define JudyHSFreeArray(a,b) JenkinsFree((a),(hashmask)) +void JenkinsFree(void *base_i, uint32_t hashmask); +void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint32_t hashmask); +#endif + + +#ifndef FST_WRITEX_DISABLE +#define FST_WRITEX_MAX                  (64 * 1024) +#else +#define fstWritex(a,b,c) fstFwrite((b), (c), 1, fv) +#endif + + +/* these defines have a large impact on writer speed when a model has a */ +/* huge number of symbols.  as a default, use 128MB and increment when  */ +/* every 1M signals are defined.                                        */ +#define FST_BREAK_SIZE                  (1UL << 27) +#define FST_BREAK_ADD_SIZE              (1UL << 22) +#define FST_BREAK_SIZE_MAX              (1UL << 31) +#define FST_ACTIVATE_HUGE_BREAK         (1000000) +#define FST_ACTIVATE_HUGE_INC           (1000000) + +#define FST_WRITER_STR                  "fstWriter" +#define FST_ID_NAM_SIZ                  (512) +#define FST_ID_NAM_ATTR_SIZ             (65536+4096) +#define FST_DOUBLE_ENDTEST              (2.7182818284590452354) +#define FST_HDR_SIM_VERSION_SIZE        (128) +#define FST_HDR_DATE_SIZE               (119) +#define FST_HDR_FILETYPE_SIZE           (1) +#define FST_HDR_TIMEZERO_SIZE           (8) +#define FST_GZIO_LEN                    (32768) +#define FST_HDR_FOURPACK_DUO_SIZE       (4*1024*1024) + +#if defined(__i386__) || defined(__x86_64__) || defined(_AIX) +#define FST_DO_MISALIGNED_OPS +#endif + +#if defined(__APPLE__) && defined(__MACH__) +#define FST_MACOSX +#include <sys/sysctl.h> +#endif + + +/***********************/ +/***                 ***/ +/*** common function ***/ +/***                 ***/ +/***********************/ + +#ifdef __MINGW32__ +#include <io.h> +#ifndef HAVE_FSEEKO +#define ftello ftell +#define fseeko fseek +#endif +#endif + +/* + * the recoded "extra" values... + * note that FST_RCV_Q is currently unused and is for future expansion. + * its intended use is as another level of escape such that any arbitrary + * value can be stored as the value: { time_delta, 8 bits, FST_RCV_Q }. + * this is currently not implemented so that the branchless decode is: + * uint32_t shcnt = 2 << (vli & 1); tdelta = vli >> shcnt; + */ +#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_Q (1 | (7<<1)) + +#define FST_RCV_STR "xzhuwl-?" +/*                   01234567 */ + + +/* + * prevent old file overwrite when currently being read + */ +static FILE *unlink_fopen(const char *nam, const char *mode) +{ +unlink(nam); +return(fopen(nam, mode)); +} + + +/* + * system-specific temp file handling + */ +#ifdef __MINGW32__ + +static FILE* tmpfile_open(char **nam) +{ +char *fname = NULL; +TCHAR szTempFileName[MAX_PATH]; +TCHAR lpTempPathBuffer[MAX_PATH]; +DWORD dwRetVal = 0; +UINT uRetVal = 0; +FILE *fh = NULL; + +if(nam) /* cppcheck warning fix: nam is always defined, so this is not needed */ +        { +        dwRetVal = GetTempPath(MAX_PATH, lpTempPathBuffer); +        if((dwRetVal > MAX_PATH) || (dwRetVal == 0)) +                { +                fprintf(stderr, "GetTempPath() failed in "__FILE__" line %d, exiting.\n", __LINE__); +                exit(255); +                } +                else +                { +                uRetVal = GetTempFileName(lpTempPathBuffer, TEXT("FSTW"), 0, szTempFileName); +                if (uRetVal == 0) +                        { +                        fprintf(stderr, "GetTempFileName() failed in "__FILE__" line %d, exiting.\n", __LINE__); +                        exit(255); +                        } +                        else +                        { +                        fname = strdup(szTempFileName); +                        } +                } + +        if(fname) +                { +                *nam = fname; +                fh = unlink_fopen(fname, "w+b"); +                } +        } + +return(fh); +} + +#else + +static FILE* tmpfile_open(char **nam) +{ +FILE *f = tmpfile(); /* replace with mkstemp() + fopen(), etc if this is not good enough */ +if(nam) { *nam = NULL; } +return(f); +} + +#endif + + +static void tmpfile_close(FILE **f, char **nam) +{ +if(f) +        { +        if(*f) { fclose(*f); *f = NULL; } +        } + +if(nam) +        { +        if(*nam) +                { +                unlink(*nam); +                free(*nam); +                *nam = NULL; +                } +        } +} + +/*****************************************/ + + +/* + * 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)); +} + + +/* + * realpath compatibility + */ +static char *fstRealpath(const char *path, char *resolved_path) +{ +#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED || defined __CYGWIN__ || defined HAVE_REALPATH + +#if (defined(__MACH__) && defined(__APPLE__)) +if(!resolved_path) +        { +        resolved_path = malloc(PATH_MAX+1); /* fixes bug on Leopard when resolved_path == NULL */ +        } +#endif + +return(realpath(path, resolved_path)); + +#else +#ifdef __MINGW32__ +if(!resolved_path) +        { +        resolved_path = malloc(PATH_MAX+1); +        } +return(_fullpath(resolved_path, path, PATH_MAX)); +#else +return(NULL); +#endif +#endif +} + + +/* + * mmap compatibility + */ +#if defined __CYGWIN__ || defined __MINGW32__ +#include <limits.h> +#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) +{ +(void)__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 <sys/mman.h> +#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)) +#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); +} +#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)]; +unsigned int i; + +fstFread(buf, sizeof(uint64_t), 1, f); +for(i=0;i<sizeof(uint64_t);i++) +        { +        val <<= 8; +        val |= buf[i]; +        } + +return(val); +} + + +static uint32_t fstGetVarint32(unsigned char *mem, int *skiplen) +{ +unsigned char *mem_orig = mem; +uint32_t rc = 0; +while(*mem & 0x80) +        { +        mem++; +        } + +*skiplen = mem - mem_orig + 1; +for(;;) +        { +        rc <<= 7; +        rc |= (uint32_t)(*mem & 0x7f); +        if(mem == mem_orig) +                { +                break; +                } +        mem--; +        } + +return(rc); +} + + +static uint32_t fstGetVarint32Length(unsigned char *mem) +{ +unsigned char *mem_orig = mem; + +while(*mem & 0x80) +        { +        mem++; +        } + +return(mem - mem_orig + 1); +} + + +static uint32_t fstGetVarint32NoSkip(unsigned char *mem) +{ +unsigned char *mem_orig = mem; +uint32_t rc = 0; +while(*mem & 0x80) +        { +        mem++; +        } + +for(;;) +        { +        rc <<= 7; +        rc |= (uint32_t)(*mem & 0x7f); +        if(mem == mem_orig) +                { +                break; +                } +        mem--; +        } + +return(rc); +} + + +static unsigned char *fstCopyVarint32ToLeft(unsigned char *pnt, uint32_t v) +{ +unsigned char *spnt; +uint32_t nxt = v; +int cnt = 1; +int i; + +while((nxt = nxt>>7)) /* determine len to avoid temp buffer copying to cut down on load-hit-store */ +        { +        cnt++; +        } + +pnt -= cnt; +spnt = pnt; +cnt--; + +for(i=0;i<cnt;i++) /* now generate left to right as normal */ +        { +        nxt = v>>7; +        *(spnt++) = ((unsigned char)v) | 0x80; +        v = nxt; +        } +*spnt = (unsigned char)v; + +return(pnt); +} + + +static unsigned char *fstCopyVarint64ToRight(unsigned char *pnt, uint64_t v) +{ +uint64_t nxt; + +while((nxt = v>>7)) +        { +        *(pnt++) = ((unsigned char)v) | 0x80; +        v = nxt; +        } +*(pnt++) = (unsigned char)v; + +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[10]; /* ceil(64/7) = 10 */ +unsigned char *pnt = buf; +int len; + +while((nxt = v>>7)) +        { +        *(pnt++) = ((unsigned char)v) | 0x80; +        v = nxt; +        } +*(pnt++) = (unsigned char)v; + +len = pnt-buf; +fstFwrite(buf, len, 1, handle); +return(len); +} + + +/* signed integer read/write routines are currently unused */ +static int64_t fstGetSVarint64(unsigned char *mem, int *skiplen) +{ +unsigned char *mem_orig = mem; +int64_t rc = 0; +const int64_t one = 1; +const int siz = sizeof(int64_t) * 8; +int shift = 0; +unsigned char byt; + +do      { +        byt = *(mem++); +        rc |= ((int64_t)(byt & 0x7f)) << shift; +        shift += 7; + +        } while(byt & 0x80); + +if((shift<siz) && (byt & 0x40)) +        { +        rc |= -(one << shift); /* sign extend */ +        } + +*skiplen = mem - mem_orig; + +return(rc); +} + + +static int fstWriterSVarint(FILE *handle, int64_t v) +{ +unsigned char buf[15]; /* ceil(64/7) = 10 + sign byte padded way up */ +unsigned char byt; +unsigned char *pnt = buf; +int more = 1; +int len; + +do      { +        byt = v | 0x80; +        v >>= 7; + +        if (((!v) && (!(byt & 0x40))) || ((v == -1) && (byt & 0x40))) +                { +                more = 0; +                byt &= 0x7f; +                } + +        *(pnt++) = byt; +        } while(more); + +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 *tchn_handle; + +unsigned char *vchg_mem; + +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 fourpack : 1; +unsigned fastpack : 1; + +int64_t timezero; +off_t section_header_truncpos; +uint32_t tchn_cnt, tchn_idx; +uint64_t curtime; +uint64_t firsttime; +uint32_t vchg_siz; +uint32_t vchg_alloc_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 char filetype; /* default is 0, FST_FT_VERILOG */ + +unsigned compress_hier : 1; +unsigned repack_on_close : 1; +unsigned skip_writing_section_hdr : 1; +unsigned size_limit_locked : 1; +unsigned section_header_only : 1; +unsigned flush_context_pending : 1; +unsigned parallel_enabled : 1; +unsigned parallel_was_enabled : 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 */ + +#ifdef FST_WRITER_PARALLEL +pthread_mutex_t mutex; +pthread_t thread; +pthread_attr_t thread_attr; +struct fstWriterContext *xc_parent; +#endif + +size_t fst_orig_break_size; +size_t fst_orig_break_add_size; + +size_t fst_break_size; +size_t fst_break_add_size; + +size_t fst_huge_break_size; + +fstHandle next_huge_break; + +Pvoid_t path_array; +uint32_t path_array_count; + +unsigned fseek_failed : 1; + +char *geom_handle_nam; +char *valpos_handle_nam; +char *curval_handle_nam; +char *tchn_handle_nam; +}; + + +static int fstWriterFseeko(struct fstWriterContext *xc, FILE *stream, off_t offset, int whence) +{ +int rc = fseeko(stream, offset, whence); + +if(rc<0) +        { +        xc->fseek_failed = 1; +#ifdef FST_DEBUG +        fprintf(stderr, "Seek to #%"PRId64" (whence = %d) failed!\n", offset, whence); +        perror("Why"); +#endif +        } + +return(rc); +} + + +static uint32_t fstWriterUint32WithVarint32(struct fstWriterContext *xc, uint32_t *u, uint32_t v, const void *dbuf, uint32_t siz) +{ +unsigned char *buf = xc->vchg_mem + xc->vchg_siz; +unsigned char *pnt = buf; +uint32_t nxt; +uint32_t len; + +#ifdef FST_DO_MISALIGNED_OPS +(*(uint32_t *)(pnt)) = (*(uint32_t *)(u)); +#else +memcpy(pnt, u, sizeof(uint32_t)); +#endif +pnt += 4; + +while((nxt = v>>7)) +        { +        *(pnt++) = ((unsigned char)v) | 0x80; +        v = nxt; +        } +*(pnt++) = (unsigned char)v; +memcpy(pnt, dbuf, siz); + +len = pnt-buf + siz; +return(len); +} + + +static uint32_t fstWriterUint32WithVarint32AndLength(struct fstWriterContext *xc, uint32_t *u, uint32_t v, const void *dbuf, uint32_t siz) +{ +unsigned char *buf = xc->vchg_mem + xc->vchg_siz; +unsigned char *pnt = buf; +uint32_t nxt; +uint32_t len; + +#ifdef FST_DO_MISALIGNED_OPS +(*(uint32_t *)(pnt)) = (*(uint32_t *)(u)); +#else +memcpy(pnt, u, sizeof(uint32_t)); +#endif +pnt += 4; + +while((nxt = v>>7)) +        { +        *(pnt++) = ((unsigned char)v) | 0x80; +        v = nxt; +        } +*(pnt++) = (unsigned char)v; + +v = siz; +while((nxt = v>>7)) +        { +        *(pnt++) = ((unsigned char)v) | 0x80; +        v = nxt; +        } +*(pnt++) = (unsigned char)v; + +memcpy(pnt, dbuf, siz); + +len = pnt-buf + siz; +return(len); +} + + +/* + * 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, xc->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 */ + +/* date size is deliberately overspecified at 119 bytes (originally 128) in order to provide backfill for new args */ + +#define FST_HDR_OFFS_FILETYPE                   (FST_HDR_OFFS_DATE + FST_HDR_DATE_SIZE) +fputc(xc->filetype, xc->handle);                /* +321 filetype */ + +#define FST_HDR_OFFS_TIMEZERO                   (FST_HDR_OFFS_FILETYPE + FST_HDR_FILETYPE_SIZE) +fstWriterUint64(xc->handle, xc->timezero);      /* +322 timezero */ + +#define FST_HDR_LENGTH                          (FST_HDR_OFFS_TIMEZERO + FST_HDR_TIMEZERO_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 */ +fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_START_TIME, SEEK_SET); +fstWriterUint64(xc->handle, xc->firsttime); +fstWriterUint64(xc->handle, xc->curtime); +fstWriterFseeko(xc, 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); +fstWriterFseeko(xc, 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) +{ +(void)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; +} + + +/* + * set up large and small memory usages + * crossover point in model is FST_ACTIVATE_HUGE_BREAK number of signals + */ +static void fstDetermineBreakSize(struct fstWriterContext *xc) +{ +#if defined(__linux__) || defined(FST_MACOSX) +int was_set = 0; + +#ifdef __linux__ +FILE *f = fopen("/proc/meminfo", "rb"); + +if(f) +        { +        char buf[257]; +        char *s; +        while(!feof(f)) +                { +                buf[0] = 0; +                s = fgets(buf, 256, f); +                if(s && *s) +                        { +                        if(!strncmp(s, "MemTotal:", 9)) +                                { +                                size_t v = atol(s+10); +                                v *= 1024; /* convert to bytes */ +                                v /= 8; /* chop down to 1/8 physical memory */ +                                if(v > FST_BREAK_SIZE) +                                        { +                                        if(v > FST_BREAK_SIZE_MAX) +                                                { +                                                v = FST_BREAK_SIZE_MAX; +                                                } + +                                        xc->fst_huge_break_size = v; +                                        was_set = 1; +                                        break; +                                        } +                                } +                        } +                } + +        fclose(f); +        } + +if(!was_set) +        { +        xc->fst_huge_break_size = FST_BREAK_SIZE; +        } +#else +int mib[2]; +int64_t v; +size_t length; + +mib[0] = CTL_HW; +mib[1] = HW_MEMSIZE; +length = sizeof(int64_t); +if(!sysctl(mib, 2, &v, &length, NULL, 0)) +        { +        v /= 8; + +        if(v > (int64_t)FST_BREAK_SIZE) +                { +                if(v > (int64_t)FST_BREAK_SIZE_MAX) +                        { +                        v = FST_BREAK_SIZE_MAX; +                        } + +                xc->fst_huge_break_size = v; +                was_set = 1; +                } +        } + +if(!was_set) +        { +        xc->fst_huge_break_size = FST_BREAK_SIZE; +        } +#endif +#else +xc->fst_huge_break_size = FST_BREAK_SIZE; +#endif + +xc->fst_break_size = xc->fst_orig_break_size = FST_BREAK_SIZE; +xc->fst_break_add_size = xc->fst_orig_break_add_size = FST_BREAK_ADD_SIZE; +xc->next_huge_break = FST_ACTIVATE_HUGE_BREAK; +} + + +/* + * 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; +fstDetermineBreakSize(xc); + +if((!nam)|| +        (!(xc->handle=unlink_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 = unlink_fopen(hf, "w+b"); + +        xc->geom_handle = tmpfile_open(&xc->geom_handle_nam);           /* .geom */ +        xc->valpos_handle = tmpfile_open(&xc->valpos_handle_nam);       /* .offs */ +        xc->curval_handle = tmpfile_open(&xc->curval_handle_nam);       /* .bits */ +        xc->tchn_handle = tmpfile_open(&xc->tchn_handle_nam);           /* .tchn */ +        xc->vchg_alloc_siz = xc->fst_break_size + xc->fst_break_add_size; +        xc->vchg_mem = malloc(xc->vchg_alloc_siz); + +        if(xc->hier_handle && xc->geom_handle && xc->valpos_handle && xc->curval_handle && xc->vchg_mem && xc->tchn_handle) +                { +                xc->filename = strdup(nam); +                xc->is_initial_time = 1; + +                fstWriterEmitHdrBytes(xc); +                xc->nan = strtod("NaN", NULL); +#ifdef FST_WRITER_PARALLEL +                pthread_mutex_init(&xc->mutex, NULL); +                pthread_attr_init(&xc->thread_attr); +                pthread_attr_setdetachstate(&xc->thread_attr, PTHREAD_CREATE_DETACHED); +#endif +                } +                else +                { +                fclose(xc->handle); +                if(xc->hier_handle) { fclose(xc->hier_handle); unlink(hf); } +                tmpfile_close(&xc->geom_handle, &xc->geom_handle_nam); +                tmpfile_close(&xc->valpos_handle, &xc->valpos_handle_nam); +                tmpfile_close(&xc->curval_handle, &xc->curval_handle_nam); +                tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam); +                free(xc->vchg_mem); +                free(xc); +                xc=NULL; +                } + +        free(hf); +        } + +return(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(compressBound(destlen)); +        rc = compress2(dmem, &destlen, xc->curval_mem, xc->maxvalpos, 4); /* was 9...which caused performance drag on traces with many signals */ + +        fputc(FST_BL_SKIP, xc->handle);                 /* temporarily tag the section, use FST_BL_VCDATA on finalize */ +        xc->section_start = ftello(xc->handle); +#ifdef FST_WRITER_PARALLEL +        if(xc->xc_parent) xc->xc_parent->section_start = xc->section_start; +#endif +        xc->section_header_only = 1;                    /* indicates truncate might be needed */ +        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); +        } +} + + +/* + * only to be called directly by fst code...otherwise must + * be synced up with time changes + */ +#ifdef FST_WRITER_PARALLEL +static void fstWriterFlushContextPrivate2(void *ctx) +#else +static void fstWriterFlushContextPrivate(void *ctx) +#endif +{ +#ifdef FST_DEBUG +int cnt = 0; +#endif +unsigned 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; +#ifdef FST_WRITER_PARALLEL +struct fstWriterContext *xc2 = xc->xc_parent; +#else +struct fstWriterContext *xc2 = xc; +#endif + +#ifndef FST_DYNAMIC_ALIAS_DISABLE +Pvoid_t PJHSArray = (Pvoid_t) NULL; +#ifndef _WAVE_HAVE_JUDY +uint32_t hashmask =  xc->maxhandle; +hashmask |= hashmask >> 1; +hashmask |= hashmask >> 2; +hashmask |= hashmask >> 4; +hashmask |= hashmask >> 8; +hashmask |= hashmask >> 16; +#endif +#endif + +if((xc->vchg_siz <= 1)||(xc->already_in_flush)) return; +xc->already_in_flush = 1; /* should really do this with a semaphore */ + +xc->section_header_only = 0; +scratchpad = malloc(xc->vchg_siz); + +vchg_mem = xc->vchg_mem; + +f = xc->handle; +fstWriterVarint(f, xc->maxhandle);      /* emit current number of handles */ +fputc(xc->fourpack ? '4' : (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;i<xc->maxhandle;i++) +        { +        vm4ip = &(xc->valpos_mem[4*i]); + +        if(vm4ip[2]) +                { +                uint32_t offs = vm4ip[2]; +                uint32_t next_offs; +                unsigned int wrlen; + +                vm4ip[2] = fpos; + +                scratchpnt = scratchpad + xc->vchg_siz;         /* build this buffer backwards */ +                if(vm4ip[1] <= 1) +                        { +                        if(vm4ip[1] == 1) +                                { +                                wrlen = fstGetVarint32Length(vchg_mem + offs + 4); /* used to advance and determine wrlen */ +#ifndef FST_REMOVE_DUPLICATE_VC +                                xc->curval_mem[vm4ip[0]] = vchg_mem[offs + 4 + wrlen]; /* checkpoint variable */ +#endif +                                while(offs) +                                        { +                                        unsigned char val; +                                        uint32_t time_delta, rcv; +                                        next_offs = fstGetUint32(vchg_mem + offs); +                                        offs += 4; + +                                        time_delta = fstGetVarint32(vchg_mem + offs, (int *)&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 +                                { +                                /* variable length */ +                                /* fstGetUint32 (next_offs) + fstGetVarint32 (time_delta) + fstGetVarint32 (len) + payload */ +                                unsigned char *pnt; +                                uint32_t record_len; +                                uint32_t time_delta; + +                                while(offs) +                                        { +                                        next_offs = fstGetUint32(vchg_mem + offs); +                                        offs += 4; +                                        pnt = vchg_mem + offs; +                                        offs = next_offs; +                                        time_delta = fstGetVarint32(pnt, (int *)&wrlen); +                                        pnt += wrlen; +                                        record_len = fstGetVarint32(pnt, (int *)&wrlen); +                                        pnt += wrlen; + +                                        scratchpnt -= record_len; +                                        memcpy(scratchpnt, pnt, record_len); + +                                        scratchpnt = fstCopyVarint32ToLeft(scratchpnt, record_len); +                                        scratchpnt = fstCopyVarint32ToLeft(scratchpnt, (time_delta << 1)); /* reserve | 1 case for future expansion */ +                                        } +                                } +                        } +                        else +                        { +                        wrlen = fstGetVarint32Length(vchg_mem + offs + 4); /* used to advance and determine wrlen */ +#ifndef FST_REMOVE_DUPLICATE_VC +                        memcpy(xc->curval_mem + vm4ip[0], vchg_mem + offs + 4 + wrlen, vm4ip[1]); /* checkpoint variable */ +#endif +                        while(offs) +                                { +                                unsigned 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, (int *)&wrlen); + +                                pnt = vchg_mem+offs+wrlen; +                                offs = next_offs; + +                                for(idx=0;idx<vm4ip[1];idx++) +                                        { +                                        if((pnt[idx] == '0') || (pnt[idx] == '1')) +                                                { +                                                continue; +                                                } +                                                else +                                                { +                                                is_binary = 0; +                                                break; +                                                } +                                        } + +                                if(is_binary) +                                        { +                                        unsigned char acc = 0; +                                        /* new algorithm */ +                                        idx = ((vm4ip[1]+7) & ~7); +                                        switch(vm4ip[1] & 7) +                                                { +                                                case 0: do {    acc  = (pnt[idx+7-8] & 1) << 0; +                                                case 7:         acc |= (pnt[idx+6-8] & 1) << 1; +                                                case 6:         acc |= (pnt[idx+5-8] & 1) << 2; +                                                case 5:         acc |= (pnt[idx+4-8] & 1) << 3; +                                                case 4:         acc |= (pnt[idx+3-8] & 1) << 4; +                                                case 3:         acc |= (pnt[idx+2-8] & 1) << 5; +                                                case 2:         acc |= (pnt[idx+1-8] & 1) << 6; +                                                case 1:         acc |= (pnt[idx+0-8] & 1) << 7; +                                                                *(--scratchpnt) = acc; +                                                                idx -= 8; +                                                        } while(idx); +                                                } + +                                        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->vchg_siz - scratchpnt; +                unc_memreq += wrlen; +                if(wrlen > 32) +                        { +                        unsigned long destlen = wrlen; +                        unsigned char *dmem; +                        unsigned int rc; + +                        if(!xc->fastpack) +                                { +                                if(wrlen <= packmemlen) +                                        { +                                        dmem = packmem; +                                        } +                                        else +                                        { +                                        free(packmem); +                                        dmem = packmem = malloc(compressBound(packmemlen = wrlen)); +                                        } + +                                rc = compress2(dmem, &destlen, scratchpnt, wrlen, 4); +                                if(rc == Z_OK) +                                        { +#ifndef FST_DYNAMIC_ALIAS_DISABLE +                                        PPvoid_t pv = JudyHSIns(&PJHSArray, dmem, destlen, NULL); +                                        if(*pv) +                                                { +                                                uint32_t pvi = (long)(*pv); +                                                vm4ip[2] = -pvi; +                                                } +                                                else +                                                { +                                                *pv = (void *)(long)(i+1); +#endif +                                                fpos += fstWriterVarint(f, wrlen); +                                                fpos += destlen; +                                                fstFwrite(dmem, destlen, 1, f); +#ifndef FST_DYNAMIC_ALIAS_DISABLE +                                                } +#endif +                                        } +                                        else +                                        { +#ifndef FST_DYNAMIC_ALIAS_DISABLE +                                        PPvoid_t pv = JudyHSIns(&PJHSArray, scratchpnt, wrlen, NULL); +                                        if(*pv) +                                                { +                                                uint32_t pvi = (long)(*pv); +                                                vm4ip[2] = -pvi; +                                                } +                                                else +                                                { +                                                *pv = (void *)(long)(i+1); +#endif +                                                fpos += fstWriterVarint(f, 0); +                                                fpos += wrlen; +                                                fstFwrite(scratchpnt, wrlen, 1, f); +#ifndef FST_DYNAMIC_ALIAS_DISABLE +                                                } +#endif +                                        } +                                } +                                else +                                { +                                /* this is extremely conservative: fastlz needs +5% for worst case, lz4 needs siz+(siz/255)+16 */ +                                if(((wrlen * 2) + 2) <= packmemlen) +                                        { +                                        dmem = packmem; +                                        } +                                        else +                                        { +                                        free(packmem); +                                        dmem = packmem = malloc(packmemlen = (wrlen * 2) + 2); +                                        } + +                                rc = (xc->fourpack) ? LZ4_compress((char *)scratchpnt, (char *)dmem, wrlen) : fastlz_compress(scratchpnt, wrlen, dmem); +                                if(rc < destlen) +                                        { +#ifndef FST_DYNAMIC_ALIAS_DISABLE +                                        PPvoid_t pv = JudyHSIns(&PJHSArray, dmem, rc, NULL); +                                        if(*pv) +                                                { +                                                uint32_t pvi = (long)(*pv); +                                                vm4ip[2] = -pvi; +                                                } +                                                else +                                                { +                                                *pv = (void *)(long)(i+1); +#endif +                                                fpos += fstWriterVarint(f, wrlen); +                                                fpos += rc; +                                                fstFwrite(dmem, rc, 1, f); +#ifndef FST_DYNAMIC_ALIAS_DISABLE +                                                } +#endif +                                        } +                                        else +                                        { +#ifndef FST_DYNAMIC_ALIAS_DISABLE +                                        PPvoid_t pv = JudyHSIns(&PJHSArray, scratchpnt, wrlen, NULL); +                                        if(*pv) +                                                { +                                                uint32_t pvi = (long)(*pv); +                                                vm4ip[2] = -pvi; +                                                } +                                                else +                                                { +                                                *pv = (void *)(long)(i+1); +#endif +                                                fpos += fstWriterVarint(f, 0); +                                                fpos += wrlen; +                                                fstFwrite(scratchpnt, wrlen, 1, f); +#ifndef FST_DYNAMIC_ALIAS_DISABLE +                                                } +#endif +                                        } +                                } +                        } +                        else +                        { +#ifndef FST_DYNAMIC_ALIAS_DISABLE +                        PPvoid_t pv = JudyHSIns(&PJHSArray, scratchpnt, wrlen, NULL); +                        if(*pv) +                                { +                                uint32_t pvi = (long)(*pv); +                                vm4ip[2] = -pvi; +                                } +                                else +                                { +                                *pv = (void *)(long)(i+1); +#endif +                                fpos += fstWriterVarint(f, 0); +                                fpos += wrlen; +                                fstFwrite(scratchpnt, wrlen, 1, f); +#ifndef FST_DYNAMIC_ALIAS_DISABLE +                                } +#endif +                        } + +                /* vm4ip[3] = 0; ...redundant with clearing below */ +#ifdef FST_DEBUG +                cnt++; +#endif +                } +        } + +#ifndef FST_DYNAMIC_ALIAS_DISABLE +JudyHSFreeArray(&PJHSArray, NULL); +#endif + +free(packmem); packmem = NULL; /* packmemlen = 0; */ /* scan-build */ + +prevpos = 0; zerocnt = 0; +free(scratchpad); scratchpad = NULL; + +indxpos = ftello(f); +xc->secnum++; + +#ifndef FST_DYNAMIC_ALIAS2_DISABLE +if(1) +        { +        uint32_t prev_alias = 0; + +        for(i=0;i<xc->maxhandle;i++) +                { +                vm4ip = &(xc->valpos_mem[4*i]); + +                if(vm4ip[2]) +                        { +                        if(zerocnt) +                                { +                                fpos += fstWriterVarint(f, (zerocnt << 1)); +                                zerocnt = 0; +                                } + +                        if(vm4ip[2] & 0x80000000) +                                { +                                if(vm4ip[2] != prev_alias) +                                        { +                                        fpos += fstWriterSVarint(f, (((int64_t)((int32_t)(prev_alias = vm4ip[2]))) << 1) | 1); +                                        } +                                        else +                                        { +                                        fpos += fstWriterSVarint(f, (0 << 1) | 1); +                                        } +                                } +                                else +                                { +                                fpos += fstWriterSVarint(f, ((vm4ip[2] - prevpos) << 1) | 1); +                                prevpos = vm4ip[2]; +                                } +                        vm4ip[2] = 0; +                        vm4ip[3] = 0; /* clear out tchn idx */ +                        } +                        else +                        { +                        zerocnt++; +                        } +                } +        } +        else +#endif +        { +        for(i=0;i<xc->maxhandle;i++) +                { +                vm4ip = &(xc->valpos_mem[4*i]); + +                if(vm4ip[2]) +                        { +                        if(zerocnt) +                                { +                                fpos += fstWriterVarint(f, (zerocnt << 1)); +                                zerocnt = 0; +                                } + +                        if(vm4ip[2] & 0x80000000) +                                { +                                fpos += fstWriterVarint(f, 0); /* signal, note that using a *signed* varint would be more efficient than this byte escape! */ +                                fpos += fstWriterVarint(f, (-(int32_t)vm4ip[2])); +                                } +                                else +                                { +                                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)); /* scan-build */ +        } +#ifdef FST_DEBUG +fprintf(stderr, "value chains: %d\n", cnt); +#endif + +xc->vchg_mem[0] = '!'; +xc->vchg_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); +fstWriterFseeko(xc, 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(compressBound(destlen)); +        int rc = compress2(dmem, &destlen, tmem, tlen, 9); + +        if((rc == Z_OK) && (((off_t)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; +fstWriterFseeko(xc, xc->tchn_handle, 0, SEEK_SET); +fstFtruncate(fileno(xc->tchn_handle), 0); + +/* write block trailer */ +endpos = ftello(xc->handle); +fstWriterFseeko(xc, xc->handle, xc->section_start, SEEK_SET); +fstWriterUint64(xc->handle, endpos - xc->section_start);        /* write block length */ +fstWriterFseeko(xc, 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); + +fstWriterFseeko(xc, xc->handle, xc->section_start-1, SEEK_SET);         /* write out FST_BL_VCDATA over FST_BL_SKIP */ + +#ifndef FST_DYNAMIC_ALIAS_DISABLE +#ifndef FST_DYNAMIC_ALIAS2_DISABLE +fputc(FST_BL_VCDATA_DYN_ALIAS2, xc->handle); +#else +fputc(FST_BL_VCDATA_DYN_ALIAS, xc->handle); +#endif +#else +fputc(FST_BL_VCDATA, xc->handle); +#endif + +fflush(xc->handle); + +fstWriterFseeko(xc, xc->handle, endpos, SEEK_SET);                              /* seek to end of file */ + +xc2->section_header_truncpos = endpos;                          /* cache in case of need to truncate */ +if(xc->dump_size_limit) +        { +        if(endpos >= ((off_t)xc->dump_size_limit)) +                { +                xc2->skip_writing_section_hdr = 1; +                xc2->size_limit_locked = 1; +                xc2->is_initial_time = 1; /* to trick emit value and emit time change */ +#ifdef FST_DEBUG +                fprintf(stderr, "<< dump file size limit reached, stopping dumping >>\n"); +#endif +                } +        } + +if(!xc2->skip_writing_section_hdr) +        { +        fstWriterEmitSectionHeader(xc);                         /* emit next section header */ +        } +fflush(xc->handle); + +xc->already_in_flush = 0; +} + + +#ifdef FST_WRITER_PARALLEL +static void *fstWriterFlushContextPrivate1(void *ctx) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; + +fstWriterFlushContextPrivate2(xc); + +pthread_mutex_unlock(&(xc->xc_parent->mutex)); + +#ifdef FST_REMOVE_DUPLICATE_VC +free(xc->curval_mem); +#endif +free(xc->valpos_mem); +free(xc->vchg_mem); +tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam); +free(xc); + +return(NULL); +} + + +static void fstWriterFlushContextPrivate(void *ctx) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; + +if(xc->parallel_enabled) +        { +        struct fstWriterContext *xc2 = malloc(sizeof(struct fstWriterContext)); +        unsigned int i; + +        pthread_mutex_lock(&xc->mutex); +        pthread_mutex_unlock(&xc->mutex); + +        xc->xc_parent = xc; +        memcpy(xc2, xc, sizeof(struct fstWriterContext)); + +        xc2->valpos_mem = malloc(xc->maxhandle * 4 * sizeof(uint32_t)); +        memcpy(xc2->valpos_mem, xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t)); + +        /* curval mem is updated in the thread */ +#ifdef FST_REMOVE_DUPLICATE_VC +        xc2->curval_mem = malloc(xc->maxvalpos); +        memcpy(xc2->curval_mem, xc->curval_mem, xc->maxvalpos); +#endif + +        xc->vchg_mem = malloc(xc->vchg_alloc_siz); +        xc->vchg_mem[0] = '!'; +        xc->vchg_siz = 1; + +        for(i=0;i<xc->maxhandle;i++) +                { +                uint32_t *vm4ip = &(xc->valpos_mem[4*i]); +                vm4ip[2] = 0; /* zero out offset val */ +                vm4ip[3] = 0; /* zero out last time change val */ +                } + +        xc->tchn_cnt = xc->tchn_idx = 0; +        xc->tchn_handle = tmpfile_open(&xc->tchn_handle_nam); /* child thread will deallocate file/name */ +        fstWriterFseeko(xc, xc->tchn_handle, 0, SEEK_SET); +        fstFtruncate(fileno(xc->tchn_handle), 0); + +        xc->section_header_only = 0; +        xc->secnum++; + +        pthread_mutex_lock(&xc->mutex); + +        pthread_create(&xc->thread, &xc->thread_attr, fstWriterFlushContextPrivate1, xc2); +        } +        else +        { +        if(xc->parallel_was_enabled) /* conservatively block */ +                { +                pthread_mutex_lock(&xc->mutex); +                pthread_mutex_unlock(&xc->mutex); +                } + +        xc->xc_parent = xc; +        fstWriterFlushContextPrivate2(xc); +        } +} +#endif + + +/* + * queues up a flush context operation + */ +void fstWriterFlushContext(void *ctx) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc) +        { +        if(xc->tchn_idx > 1) +                { +                xc->flush_context_pending = 1; +                } +        } +} + + +/* + * close out FST file + */ +void fstWriterClose(void *ctx) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; + +#ifdef FST_WRITER_PARALLEL +if(xc) +        { +        pthread_mutex_lock(&xc->mutex); +        pthread_mutex_unlock(&xc->mutex); +        } +#endif + +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 */ + +        if(xc->section_header_only && xc->section_header_truncpos && (xc->vchg_siz <= 1) && (!xc->is_initial_time)) +                { +                fstFtruncate(fileno(xc->handle), xc->section_header_truncpos); +                fstWriterFseeko(xc, xc->handle, xc->section_header_truncpos, SEEK_SET); +                xc->section_header_only = 0; +                } +                else +                { +                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]); +                                        } +                                } +                        fstWriterFlushContextPrivate(xc); +#ifdef FST_WRITER_PARALLEL +                        pthread_mutex_lock(&xc->mutex); +                        pthread_mutex_unlock(&xc->mutex); +#endif +                        } +                } +        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(compressBound(destlen)); +                int rc = compress2(dmem, &destlen, tmem, tlen, 9); + +                if((rc != Z_OK) || (((off_t)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((((off_t)destlen) != tlen) ? dmem : tmem, destlen, 1, xc->handle); +                fflush(xc->handle); + +                fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET); +                fputc(FST_BL_GEOM, xc->handle);                 /* actual tag */ + +                fstWriterFseeko(xc, 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;i<xc->num_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); +                fstWriterFseeko(xc, xc->handle, bpos, SEEK_SET); +                fstWriterUint64(xc->handle, eos - bpos); +                fflush(xc->handle); + +                fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET); +                fputc(FST_BL_BLACKOUT, xc->handle);     /* actual tag */ + +                fstWriterFseeko(xc, xc->handle, 0, SEEK_END);   /* move file pointer to end for any section adds */ +                fflush(xc->handle); +                } + +        if(xc->compress_hier) +                { +                off_t hl, eos; +                gzFile zhandle; +                int zfd; +                int fourpack_duo = 0; +#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 */ + +                if(!xc->fourpack) +                        { +                        unsigned char *mem = malloc(FST_GZIO_LEN); +                        zfd = dup(fileno(xc->handle)); +                        fflush(xc->handle); +                        zhandle = gzdopen(zfd, "wb4"); +                        if(zhandle) +                                { +                                fstWriterFseeko(xc, 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); +                                } +                                else +                                { +                                close(zfd); +                                } +                        free(mem); +                        } +                        else +                        { +                        int lz4_maxlen; +                        unsigned char *mem; +                        unsigned char *hmem; +                        int packed_len; + +                        fflush(xc->handle); + +                        lz4_maxlen = LZ4_compressBound(xc->hier_file_len); +                        mem = malloc(lz4_maxlen); +                        hmem = fstMmap(NULL, xc->hier_file_len, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->hier_handle), 0); +                        packed_len = LZ4_compress((char *)hmem, (char *)mem, xc->hier_file_len); +                        fstMunmap(hmem, xc->hier_file_len); + +                        fourpack_duo = (!xc->repack_on_close) && (xc->hier_file_len > FST_HDR_FOURPACK_DUO_SIZE); /* double pack when hierarchy is large */ + +                        if(fourpack_duo)        /* double packing with LZ4 is faster than gzip */ +                                { +                                unsigned char *mem_duo; +                                int lz4_maxlen_duo; +                                int packed_len_duo; + +                                lz4_maxlen_duo = LZ4_compressBound(packed_len); +                                mem_duo = malloc(lz4_maxlen_duo); +                                packed_len_duo = LZ4_compress((char *)mem, (char *)mem_duo, packed_len); + +                                fstWriterVarint(xc->handle, packed_len); /* 1st round compressed length */ +                                fstFwrite(mem_duo, packed_len_duo, 1, xc->handle); +                                free(mem_duo); +                                } +                                else +                                { +                                fstFwrite(mem, packed_len, 1, xc->handle); +                                } + +                        free(mem); +                        } + +                fstWriterFseeko(xc, xc->handle, 0, SEEK_END); +                eos = ftello(xc->handle); +                fstWriterFseeko(xc, xc->handle, hlen, SEEK_SET); +                fstWriterUint64(xc->handle, eos - hlen); +                fflush(xc->handle); + +                fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET); +                fputc(xc->fourpack ? +                        ( fourpack_duo ? FST_BL_HIER_LZ4DUO : FST_BL_HIER_LZ4) : +                        FST_BL_HIER, xc->handle); /* actual tag now also == compression type */ + +                fstWriterFseeko(xc, 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 */ +        fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_START_TIME, SEEK_SET); +        fstWriterUint64(xc->handle, xc->firsttime); +        fstWriterUint64(xc->handle, xc->curtime); +        fstWriterFseeko(xc, 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); + +        tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam); +        free(xc->vchg_mem); xc->vchg_mem = NULL; +        tmpfile_close(&xc->curval_handle, &xc->curval_handle_nam); +        tmpfile_close(&xc->valpos_handle, &xc->valpos_handle_nam); +        tmpfile_close(&xc->geom_handle, &xc->geom_handle_nam); +        if(xc->hier_handle) { fclose(xc->hier_handle); xc->hier_handle = NULL; } +        if(xc->handle) +                { +                if(xc->repack_on_close) +                        { +                        FILE *fp; +                        off_t offpnt, uclen; +                        int flen = strlen(xc->filename); +                        char *hf = calloc(1, flen + 5); + +                        strcpy(hf, xc->filename); +                        strcpy(hf+flen, ".pak"); +                        fp = fopen(hf, "wb"); + +                        if(fp) +                                { +                                void *dsth; +                                int zfd; +                                char gz_membuf[FST_GZIO_LEN]; + +                                fstWriterFseeko(xc, xc->handle, 0, SEEK_END); +                                uclen = ftello(xc->handle); + +                                fputc(FST_BL_ZWRAPPER, fp); +                                fstWriterUint64(fp, 0); +                                fstWriterUint64(fp, uclen); +                                fflush(fp); + +                                fstWriterFseeko(xc, xc->handle, 0, SEEK_SET); +                                zfd = dup(fileno(fp)); +                                dsth = gzdopen(zfd, "wb4"); +                                if(dsth) +                                        { +                                        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); +                                        } +                                        else +                                        { +                                        close(zfd); +                                        } +                                fstWriterFseeko(xc, fp, 0, SEEK_END); +                                offpnt = ftello(fp); +                                fstWriterFseeko(xc, 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 + +#ifdef FST_WRITER_PARALLEL +        pthread_mutex_destroy(&xc->mutex); +        pthread_attr_destroy(&xc->thread_attr); +#endif + +        if(xc->path_array) +                { +#ifndef _WAVE_HAVE_JUDY +                const uint32_t hashmask = FST_PATH_HASHMASK; +#endif +                JudyHSFreeArray(&(xc->path_array), NULL); +                } + +        free(xc->filename); xc->filename = NULL; +        free(xc); +        } +} + + +/* + * 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); + +        fstWriterFseeko(xc, 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); +        fstWriterFseeko(xc, 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); + +        fstWriterFseeko(xc, 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); +        fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET); +        } +} + + +void fstWriterSetFileType(void *ctx, enum fstFileType filetype) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc) +        { +        if(/*(filetype >= FST_FT_MIN) &&*/ (filetype <= FST_FT_MAX)) +                { +                off_t fpos = ftello(xc->handle); + +                xc->filetype = filetype; + +                fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_FILETYPE, SEEK_SET); +                fputc(xc->filetype, xc->handle); +                fflush(xc->handle); +                fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET); +                } +        } +} + + +static void fstWriterSetAttrDoubleArgGeneric(void *ctx, int typ, uint64_t arg1, uint64_t arg2) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc) +        { +        unsigned char buf[11]; /* ceil(64/7) = 10 + null term */ +        unsigned char *pnt = fstCopyVarint64ToRight(buf, arg1); +        if(arg1) +                { +                *pnt = 0; /* this converts any *nonzero* arg1 when made a varint into a null-term string */ +                } + +        fstWriterSetAttrBegin(xc, FST_AT_MISC, typ, (char *)buf, arg2); +        } +} + + +static void fstWriterSetAttrGeneric(void *ctx, const char *comm, int typ, uint64_t arg) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc && comm) +        { +        char *s = strdup(comm); +        char *sf = s; + +        while(*s) +                { +                if((*s == '\n') || (*s == '\r')) *s = ' '; +                s++; +                } + +        fstWriterSetAttrBegin(xc, FST_AT_MISC, typ, sf, arg); +        free(sf); +        } +} + + +static void fstWriterSetSourceStem_2(void *ctx, const char *path, unsigned int line, unsigned int use_realpath, int typ) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; + +if(xc && path && path[0]) +        { +        uint64_t sidx = 0; +        int slen = strlen(path); +#ifndef _WAVE_HAVE_JUDY +        const uint32_t hashmask = FST_PATH_HASHMASK; +        const unsigned char *path2 = (const unsigned char *)path; +#else +        char *path2 = alloca(slen + 1); /* judy lacks const qualifier in its JudyHSIns definition */ +        strcpy(path2, path); +#endif + +        PPvoid_t pv = JudyHSIns(&(xc->path_array), path2, slen, NULL); +        if(*pv) +                { +                sidx = (long)(*pv); +                } +                else +                { +                char *rp = NULL; + +                sidx = ++xc->path_array_count; +                *pv = (void *)(long)(xc->path_array_count); + +                if(use_realpath) +                        { +                        rp = fstRealpath( +#ifndef _WAVE_HAVE_JUDY +                                (const char *) +#endif +                                path2, NULL); +                        } + +                fstWriterSetAttrGeneric(xc, rp ? rp : +#ifndef _WAVE_HAVE_JUDY +                        (const char *) +#endif +                        path2, FST_MT_PATHNAME, sidx); + +                if(rp) +                        { +                        free(rp); +                        } +                } + +        fstWriterSetAttrDoubleArgGeneric(xc, typ, sidx, line); +        } +} + + +void fstWriterSetSourceStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath) +{ +fstWriterSetSourceStem_2(ctx, path, line, use_realpath, FST_MT_SOURCESTEM); +} + + +void fstWriterSetSourceInstantiationStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath) +{ +fstWriterSetSourceStem_2(ctx, path, line, use_realpath, FST_MT_SOURCEISTEM); +} + + +void fstWriterSetComment(void *ctx, const char *comm) +{ +fstWriterSetAttrGeneric(ctx, comm, FST_MT_COMMENT, 0); +} + + +void fstWriterSetEnvVar(void *ctx, const char *envvar) +{ +fstWriterSetAttrGeneric(ctx, envvar, FST_MT_ENVVAR, 0); +} + + +void fstWriterSetTimescale(void *ctx, int ts) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc) +        { +        off_t fpos = ftello(xc->handle); +        fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_TIMESCALE, SEEK_SET); +        fputc(ts & 255, xc->handle); +        fflush(xc->handle); +        fstWriterFseeko(xc, 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 fstWriterSetTimezero(void *ctx, int64_t tim) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc) +        { +        off_t fpos = ftello(xc->handle); +        fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_TIMEZERO, SEEK_SET); +        fstWriterUint64(xc->handle, (xc->timezero = tim)); +        fflush(xc->handle); +        fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET); +        } +} + + +void fstWriterSetPackType(void *ctx, enum fstWriterPackType typ) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc) +        { +        xc->fastpack     = (typ != FST_WR_PT_ZLIB); +        xc->fourpack     = (typ == FST_WR_PT_LZ4); +        } +} + + +void fstWriterSetRepackOnClose(void *ctx, int enable) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc) +        { +        xc->repack_on_close = (enable != 0); +        } +} + + +void fstWriterSetParallelMode(void *ctx, int enable) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc) +        { +        xc->parallel_was_enabled |= xc->parallel_enabled; /* make sticky */ +        xc->parallel_enabled = (enable != 0); +#ifndef FST_WRITER_PARALLEL +        if(xc->parallel_enabled) +                { +                fprintf(stderr, "ERROR: fstWriterSetParallelMode(), FST_WRITER_PARALLEL not enabled during compile, exiting.\n"); +                exit(255); +                } +#endif +        } +} + + +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); +} + + +int fstWriterGetFseekFailed(void *ctx) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc) +        { +        return(xc->fseek_failed != 0); +        } + +return(0); +} + + +/* + * writer attr/scope/var creation: + * fstWriterCreateVar2() is used to dump VHDL or other languages, but the + * underlying variable needs to map to Verilog/SV via the proper fstVarType vt + */ +fstHandle fstWriterCreateVar2(void *ctx, enum fstVarType vt, enum fstVarDir vd, +        uint32_t len, const char *nam, fstHandle aliasHandle, +        const char *type, enum fstSupplementalVarType svt, enum fstSupplementalDataType sdt) +{ +fstWriterSetAttrGeneric(ctx, type ? type : "", FST_MT_SUPVAR, (svt<<FST_SDT_SVT_SHIFT_COUNT) | (sdt & FST_SDT_ABS_MAX)); +return(fstWriterCreateVar(ctx, vt, vd, len, nam, aliasHandle)); +} + + +fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir vd, +        uint32_t len, const char *nam, fstHandle aliasHandle) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +unsigned int i; +int 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) || (vt == FST_VT_SV_SHORTREAL)) +                { +                is_real = 1; +                len = 8; /* recast number of bytes to that of what a double is */ +                } +                else +                { +                is_real = 0; +                if(vt == FST_VT_GEN_STRING) +                        { +                        len = 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(xc->numsigs == xc->next_huge_break) +                { +                if(xc->fst_break_size < xc->fst_huge_break_size) +                        { +                        xc->next_huge_break += FST_ACTIVATE_HUGE_INC; +                        xc->fst_break_size += xc->fst_orig_break_size; +                        xc->fst_break_add_size += xc->fst_orig_break_add_size; + +                        xc->vchg_alloc_siz = xc->fst_break_size + xc->fst_break_add_size; +                        if(xc->vchg_mem) +                                { +                                xc->vchg_mem = realloc(xc->vchg_mem, xc->vchg_alloc_siz); +                                } +                        } +                } + +        if(!aliasHandle) +                { +                uint32_t zero = 0; + +                if(len) +                        { +                        fstWriterVarint(xc->geom_handle, !is_real ? len : 0); /* geom section encodes reals as zero byte */ +                        } +                        else +                        { +                        fstWriterVarint(xc->geom_handle, 0xFFFFFFFF);         /* geom section encodes zero len as 32b -1 */ +                        } + +                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;i<len;i++) +                                { +                                fputc('x', xc->curval_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) +        { +        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++; +        } +} + + +void fstWriterSetAttrBegin(void *ctx, enum fstAttrType attrtype, int subtype, +                const char *attrname, uint64_t arg) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; + +if(xc) +        { +        fputc(FST_ST_GEN_ATTRBEGIN, xc->hier_handle); +        if(/*(attrtype < FST_AT_MISC) ||*/ (attrtype > FST_AT_MAX)) { attrtype = FST_AT_MISC; subtype = FST_MT_UNKNOWN; } +        fputc(attrtype, xc->hier_handle); + +        switch(attrtype) +                { +                case FST_AT_ARRAY:      if((subtype < FST_AR_NONE) || (subtype > FST_AR_MAX)) subtype = FST_AR_NONE; break; +                case FST_AT_ENUM:       if((subtype < FST_EV_SV_INTEGER) || (subtype > FST_EV_MAX)) subtype = FST_EV_SV_INTEGER; break; +                case FST_AT_PACK:       if((subtype < FST_PT_NONE) || (subtype > FST_PT_MAX)) subtype = FST_PT_NONE; break; + +                case FST_AT_MISC: +                default:                break; +                } + +        fputc(subtype, xc->hier_handle); +        fprintf(xc->hier_handle, "%s%c", +                attrname ? attrname : "", 0); + +        if(attrname) +                { +                xc->hier_file_len += strlen(attrname); +                } + +        xc->hier_file_len += 4; /* FST_ST_GEN_ATTRBEGIN + type + subtype + string terminating zero */ +        xc->hier_file_len += fstWriterVarint(xc->hier_handle, arg); +        } +} + + +void fstWriterSetAttrEnd(void *ctx) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; + +if(xc) +        { +        fputc(FST_ST_GEN_ATTREND, xc->hier_handle); +        xc->hier_file_len++; +        } +} + + +/* + * value and time change emission + */ +void fstWriterEmitValueChange(void *ctx, fstHandle handle, const void *val) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +const unsigned char *buf = (const unsigned char *)val; +uint32_t offs; +int len; + +if((xc) && (handle <= xc->maxhandle)) +        { +        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]); + +        len  = vm4ip[1]; +        if(len) /* len of zero = variable length, use fstWriterEmitVariableLengthValueChange */ +                { +                if(!xc->is_initial_time) +                        { +                        fpos = xc->vchg_siz; + +                        if((fpos + len + 10) > xc->vchg_alloc_siz) +                                { +                                xc->vchg_alloc_siz += (xc->fst_break_add_size + len); /* +len added in the case of extremely long vectors and small break add sizes */ +                                xc->vchg_mem = realloc(xc->vchg_mem, xc->vchg_alloc_siz); +                                if(!xc->vchg_mem) +                                        { +                                        fprintf(stderr, "FATAL ERROR, could not realloc() in fstWriterEmitValueChange, exiting.\n"); +                                        exit(255); +                                        } +                                } +#ifdef FST_REMOVE_DUPLICATE_VC +                        offs = vm4ip[0]; + +                        if(len != 1) +                                { +                                if((vm4ip[3]==xc->tchn_idx)&&(vm4ip[2])) +                                        { +                                        unsigned char *old_value = xc->vchg_mem + vm4ip[2] + 4; /* the +4 skips old vm4ip[2] value */ +                                        while(*(old_value++) & 0x80) { /* skips over varint encoded "xc->tchn_idx - vm4ip[3]" */ } +                                        memcpy(old_value, buf, len); /* overlay new value */ + +                                        memcpy(xc->curval_mem + offs, buf, len); +                                        return; +                                        } +                                else +                                        { +                                        if(!memcmp(xc->curval_mem + offs, buf, len)) +                                                { +                                                if(!xc->curtime) +                                                        { +                                                        int i; +                                                        for(i=0;i<len;i++) +                                                                { +                                                                if(buf[i]!='x') break; +                                                                } + +                                                        if(i<len) return; +                                                        } +                                                        else +                                                        { +                                                        return; +                                                        } +                                                } +                                        } + +                                memcpy(xc->curval_mem + offs, buf, len); +                                } +                                else +                                { +                                if((vm4ip[3]==xc->tchn_idx)&&(vm4ip[2])) +                                        { +                                        unsigned char *old_value = xc->vchg_mem + vm4ip[2] + 4; /* the +4 skips old vm4ip[2] value */ +                                        while(*(old_value++) & 0x80) { /* skips over varint encoded "xc->tchn_idx - vm4ip[3]" */ } +                                        *old_value = *buf; /* overlay new value */ + +                                        *(xc->curval_mem + offs) = *buf; +                                        return; +                                        } +                                else +                                        { +                                        if((*(xc->curval_mem + offs)) == (*buf)) +                                                { +                                                if(!xc->curtime) +                                                        { +                                                        if(*buf != 'x') return; +                                                        } +                                                        else +                                                        { +                                                        return; +                                                        } +                                                } +                                        } + +                                *(xc->curval_mem + offs) = *buf; +                                } +#endif +                        xc->vchg_siz += fstWriterUint32WithVarint32(xc, &vm4ip[2], xc->tchn_idx - vm4ip[3], buf, len); /* do one fwrite op only */ +                        vm4ip[3] = xc->tchn_idx; +                        vm4ip[2] = fpos; +                        } +                        else +                        { +                        offs = vm4ip[0]; +                        memcpy(xc->curval_mem + offs, buf, len); +                        } +                } +        } +} + + +void fstWriterEmitVariableLengthValueChange(void *ctx, fstHandle handle, const void *val, uint32_t len) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +const unsigned char *buf = (const unsigned char *)val; + +if((xc) && (handle <= xc->maxhandle)) +        { +        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]); + +        /* there is no initial time dump for variable length value changes */ +        if(!vm4ip[1]) /* len of zero = variable length */ +                { +                fpos = xc->vchg_siz; + +                if((fpos + len + 10 + 5) > xc->vchg_alloc_siz) +                        { +                        xc->vchg_alloc_siz += (xc->fst_break_add_size + len + 5); /* +len added in the case of extremely long vectors and small break add sizes */ +                        xc->vchg_mem = realloc(xc->vchg_mem, xc->vchg_alloc_siz); +                        if(!xc->vchg_mem) +                                { +                                fprintf(stderr, "FATAL ERROR, could not realloc() in fstWriterEmitVariableLengthValueChange, exiting.\n"); +                                exit(255); +                                } +                        } + +                xc->vchg_siz += fstWriterUint32WithVarint32AndLength(xc, &vm4ip[2], xc->tchn_idx - vm4ip[3], buf, len); /* do one fwrite op only */ +                vm4ip[3] = xc->tchn_idx; +                vm4ip[2] = fpos; +                } +        } +} + + +void fstWriterEmitTimeChange(void *ctx, uint64_t tim) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +unsigned 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; +                xc->vchg_mem[0] = '!'; +                xc->vchg_siz = 1; +                fstWriterEmitSectionHeader(xc); +                for(i=0;i<xc->maxhandle;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->vchg_siz >= xc->fst_break_size) || (xc->flush_context_pending)) +                        { +                        xc->flush_context_pending = 0; +                        fstWriterFlushContextPrivate(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", "sparray", "realtime", +        "string", +        "bit", "logic", "int", "shortint", "longint", "byte", "enum", "shortreal" +        }; + +static const char *modtypes[] = { +        "module", "task", "function", "begin", "fork", "generate", "struct", "union", "class", "interface", "package", "program", +        "vhdl_architecture", "vhdl_procedure", "vhdl_function", "vhdl_record", "vhdl_process", "vhdl_block", "vhdl_for_generate", "vhdl_if_generate", "vhdl_generate", "vhdl_package" +        }; + +static const char *attrtypes[] = { +        "misc", "array", "enum", "class" +        }; + +static const char *arraytypes[] = { +        "none", "unpacked", "packed", "sparse" +        }; + +static const char *enumvaluetypes[] = { +        "integer", "bit", "logic", "int", "shortint", "longint", "byte", +        "unsigned_integer", "unsigned_bit", "unsigned_logic", "unsigned_int", "unsigned_shortint", "unsigned_longint", "unsigned_byte" +        }; + +static const char *packtypes[] = { +        "none", "unpacked", "packed", "tagged_packed" +        }; + + +struct fstCurrHier +{ +struct fstCurrHier *prev; +void *user_info; +int len; +}; + + +struct fstReaderContext +{ +/* common entries */ + +FILE *f, *fh; + +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 char filetype; + +unsigned use_vcd_extensions : 1; +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 contains_hier_section_lz4duo : 1; /* valid for hier_pos (contains_hier_section_lz4 always also set) */ +unsigned contains_hier_section_lz4 : 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]; +int64_t timezero; + +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]; + +unsigned fseek_failed : 1; + +/* self-buffered I/O for writes */ + +#ifndef FST_WRITEX_DISABLE +int writex_pos; +int writex_fd; +unsigned char writex_buf[FST_WRITEX_MAX]; +#endif + +char *f_nam; +char *fh_nam; +}; + + +int fstReaderFseeko(struct fstReaderContext *xc, FILE *stream, off_t offset, int whence) +{ +int rc = fseeko(stream, offset, whence); + +if(rc<0) +        { +        xc->fseek_failed = 1; +#ifdef FST_DEBUG +        fprintf(stderr, "Seek to #%"PRId64" (whence = %d) failed!\n", offset, whence); +        perror("Why"); +#endif +        } + +return(rc); +} + + +#ifndef FST_WRITEX_DISABLE +static void fstWritex(struct fstReaderContext *xc, void *v, int len) +{ +unsigned char *s = (unsigned char *)v; + +if(len) +        { +        if(len < FST_WRITEX_MAX) +                { +                if(xc->writex_pos + len >= FST_WRITEX_MAX) +                        { +                        fstWritex(xc, NULL, 0); +                        } + +                memcpy(xc->writex_buf + xc->writex_pos, s, len); +                xc->writex_pos += len; +                } +                else +                { +                fstWritex(xc, NULL, 0); +                if (write(xc->writex_fd, s, len)) { }; +                } +        } +        else +        { +        if(xc->writex_pos) +                { +                if(write(xc->writex_fd, xc->writex_buf, xc->writex_pos)) { }; +                xc->writex_pos = 0; +                } +        } +} +#endif + + +/* + * 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); +} + + +int fstReaderGetCurrentScopeLen(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; + +if(xc && xc->curr_hier) +        { +        return(xc->curr_hier->len); +        } + +return(0); +} + + +int fstReaderGetFseekFailed(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +if(xc) +        { +        return(xc->fseek_failed != 0); +        } + +return(0); +} + + +/* + * iter mask manipulation util functions + */ +int fstReaderGetFacProcessMask(void *ctx, fstHandle facidx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; + +if(xc) +        { +        facidx--; +        if(facidx<xc->maxhandle) +                { +                int process_idx = facidx/8; +                int process_bit = facidx&7; + +                return( (xc->process_mask[process_idx]&(1<<process_bit)) != 0 ); +                } +        } +return(0); +} + + +void fstReaderSetFacProcessMask(void *ctx, fstHandle facidx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; + +if(xc) +        { +        facidx--; +        if(facidx<xc->maxhandle) +                { +                int idx = facidx/8; +                int bitpos = facidx&7; + +                xc->process_mask[idx] |= (1<<bitpos); +                } +        } +} + + +void fstReaderClrFacProcessMask(void *ctx, fstHandle facidx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; + +if(xc) +        { +        facidx--; +        if(facidx<xc->maxhandle) +                { +                int idx = facidx/8; +                int bitpos = facidx&7; + +                xc->process_mask[idx] &= (~(1<<bitpos)); +                } +        } +} + + +void fstReaderSetFacProcessMaskAll(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; + +if(xc) +        { +        memset(xc->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); +} + + +int fstReaderGetFileType(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +return(xc ? xc->filetype : FST_FT_VERILOG); +} + + +int64_t fstReaderGetTimezero(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +return(xc ? xc->timezero : 0); +} + + +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 fstReaderSetVcdExtensions(void *ctx, int enable) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; + +if(xc) +        { +        xc->use_vcd_extensions = (enable != 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 void fstVcdID(char *buf, unsigned int value) +{ +char *pnt = buf; + +/* zero is illegal for a value...it is assumed they start at one */ +while (value) +        { +        value--; +        *(pnt++) = (char)('!' + value % 94); +        value = value / 94; +        } + +*pnt = 0; +} + +static int fstVcdIDForFwrite(char *buf, unsigned int value) +{ +char *pnt = buf; + +/* zero is illegal for a value...it is assumed they start at one */ +while (value) +        { +        value--; +        *(pnt++) = (char)('!' + value % 94); +        value = value / 94; +        } + +return(pnt - buf); +} + + +static int fstReaderRecreateHierFile(struct fstReaderContext *xc) +{ +int pass_status = 1; + +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, uclen; +        off_t clen = 0; +        gzFile zhandle = NULL; +        int zfd; +        int htyp = FST_BL_SKIP; + +        /* can't handle both set at once should never happen in a real file */ +        if(!xc->contains_hier_section_lz4 && xc->contains_hier_section) +                { +                htyp = FST_BL_HIER; +                } +        else +        if(xc->contains_hier_section_lz4 && !xc->contains_hier_section) +                { +                htyp = xc->contains_hier_section_lz4duo ? FST_BL_HIER_LZ4DUO : FST_BL_HIER_LZ4; +                } + +        sprintf(fnam, "%s.hier_%d_%p", xc->filename, getpid(), (void *)xc); +        fstReaderFseeko(xc, xc->f, xc->hier_pos, SEEK_SET); +        uclen = fstReaderUint64(xc->f); +#ifndef __MINGW32__ +        fflush(xc->f); +#endif +        if(htyp == FST_BL_HIER) +                { +                fstReaderFseeko(xc, xc->f, xc->hier_pos, SEEK_SET); +                uclen = fstReaderUint64(xc->f); +#ifndef __MINGW32__ +                fflush(xc->f); +#endif +                zfd = dup(fileno(xc->f)); +                zhandle = gzdopen(zfd, "rb"); +                if(!zhandle) +                        { +                        close(zfd); +                        free(mem); +                        free(fnam); +                        return(0); +                        } +                } +        else +        if((htyp == FST_BL_HIER_LZ4) || (htyp == FST_BL_HIER_LZ4DUO)) +                { +                fstReaderFseeko(xc, xc->f, xc->hier_pos - 8, SEEK_SET); /* get section len */ +                clen =  fstReaderUint64(xc->f) - 16; +                uclen = fstReaderUint64(xc->f); +#ifndef __MINGW32__ +                fflush(xc->f); +#endif +                } + +#ifndef __MINGW32__ +        xc->fh = fopen(fnam, "w+b"); +        if(!xc->fh) +#endif +                { +                xc->fh = tmpfile_open(&xc->fh_nam); +                free(fnam); fnam = NULL; +                if(!xc->fh) +                        { +                        tmpfile_close(&xc->fh, &xc->fh_nam); +                        free(mem); +                        return(0); +                        } +                } + +#ifndef __MINGW32__ +        if(fnam) unlink(fnam); +#endif + +        if(htyp == FST_BL_HIER) +                { +                for(hl = 0; hl < uclen; hl += FST_GZIO_LEN) +                        { +                        size_t len = ((uclen - hl) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - hl); +                        size_t gzreadlen = gzread(zhandle, mem, len); /* rc should equal len... */ +                        size_t fwlen; + +                        if(gzreadlen != len) +                                { +                                pass_status = 0; +                                break; +                                } + +                        fwlen = fstFwrite(mem, len, 1, xc->fh); +                        if(fwlen != 1) +                                { +                                pass_status = 0; +                                break; +                                } +                        } +                gzclose(zhandle); +                } +        else +        if(htyp == FST_BL_HIER_LZ4DUO) +                { +                unsigned char *lz4_cmem  = malloc(clen); +                unsigned char *lz4_ucmem = malloc(uclen); +                unsigned char *lz4_ucmem2; +                uint64_t uclen2; +                int skiplen2 = 0; + +                fstFread(lz4_cmem, clen, 1, xc->f); + +                uclen2 = fstGetVarint64(lz4_cmem, &skiplen2); +                lz4_ucmem2 = malloc(uclen2); +                pass_status = (uclen2 == (uint64_t)LZ4_decompress_safe_partial ((char *)lz4_cmem + skiplen2, (char *)lz4_ucmem2, clen - skiplen2, uclen2, uclen2)); +                if(pass_status) +                        { +                        pass_status = (uclen == LZ4_decompress_safe_partial ((char *)lz4_ucmem2, (char *)lz4_ucmem, uclen2, uclen, uclen)); + +                        if(fstFwrite(lz4_ucmem, uclen, 1, xc->fh) != 1) +                                { +                                pass_status = 0; +                                } +                        } + +                free(lz4_ucmem2); +                free(lz4_ucmem); +                free(lz4_cmem); +                } +        else +        if(htyp == FST_BL_HIER_LZ4) +                { +                unsigned char *lz4_cmem  = malloc(clen); +                unsigned char *lz4_ucmem = malloc(uclen); + +                fstFread(lz4_cmem, clen, 1, xc->f); +                pass_status = (uclen == LZ4_decompress_safe_partial ((char *)lz4_cmem, (char *)lz4_ucmem, clen, uclen, uclen)); + +                if(fstFwrite(lz4_ucmem, uclen, 1, xc->fh) != 1) +                        { +                        pass_status = 0; +                        } + +                free(lz4_ucmem); +                free(lz4_cmem); +                } +        else /* FST_BL_SKIP */ +                { +                pass_status = 0; +                } + +        free(mem); +        free(fnam); + +        fstReaderFseeko(xc, xc->f, offs_cache, SEEK_SET); +        } + +return(pass_status); +} + + +int fstReaderIterateHierRewind(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +int pass_status = 0; + +if(xc) +        { +        pass_status = 1; +        if(!xc->fh) +                { +                pass_status = fstReaderRecreateHierFile(xc); +                } + +        xc->do_rewind = 1; +        } + +return(pass_status); +} + + +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) +        { +        if(!fstReaderRecreateHierFile(xc)) +                { +                return(NULL); +                } +        } + +if(xc->do_rewind) +        { +        xc->do_rewind = 0; +        xc->current_handle = 0; +        fstReaderFseeko(xc, 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.name_length = pnt - xc->hier.u.scope.name; + +                        xc->hier.u.scope.component = pnt = xc->str_scope_comp; +                        while((ch = fgetc(xc->fh))) +                                { +                                *(pnt++) = ch; +                                }; /* scopecomp */ +                        *pnt = 0; +                        xc->hier.u.scope.component_length = pnt - xc->hier.u.scope.component; +                        break; + +                case FST_ST_VCD_UPSCOPE: +                        xc->hier.htyp = FST_HT_UPSCOPE; +                        break; + +                case FST_ST_GEN_ATTRBEGIN: +                        xc->hier.htyp = FST_HT_ATTRBEGIN; +                        xc->hier.u.attr.typ = fgetc(xc->fh); +                        xc->hier.u.attr.subtype = fgetc(xc->fh); +                        xc->hier.u.attr.name = pnt = xc->str_scope_nam; +                        while((ch = fgetc(xc->fh))) +                                { +                                *(pnt++) = ch; +                                }; /* scopename */ +                        *pnt = 0; +                        xc->hier.u.attr.name_length = pnt - xc->hier.u.scope.name; + +                        xc->hier.u.attr.arg = fstReaderVarint64(xc->fh); + +                        if(xc->hier.u.attr.typ == FST_AT_MISC) +                                { +                                if((xc->hier.u.attr.subtype == FST_MT_SOURCESTEM)||(xc->hier.u.attr.subtype == FST_MT_SOURCEISTEM)) +                                        { +                                        int sidx_skiplen_dummy = 0; +                                        xc->hier.u.attr.arg_from_name = fstGetVarint64((unsigned char *)xc->str_scope_nam, &sidx_skiplen_dummy); +                                        } +                                } +                        break; + +                case FST_ST_GEN_ATTREND: +                        xc->hier.htyp = FST_HT_ATTREND; +                        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_SPARRAY: +                case FST_VT_VCD_REALTIME: +                case FST_VT_GEN_STRING: +                case FST_VT_SV_BIT: +                case FST_VT_SV_LOGIC: +                case FST_VT_SV_INT: +                case FST_VT_SV_SHORTINT: +                case FST_VT_SV_LONGINT: +                case FST_VT_SV_BYTE: +                case FST_VT_SV_ENUM: +                case FST_VT_SV_SHORTREAL: +                        xc->hier.htyp = FST_HT_VAR; +                        xc->hier.u.var.svt_workspace = FST_SVT_NONE; +                        xc->hier.u.var.sdt_workspace = FST_SDT_NONE; +                        xc->hier.u.var.sxt_workspace = 0; +                        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.name_length = pnt - xc->hier.u.var.name; +                        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); +} + + +int fstReaderProcessHier(void *ctx, FILE *fv) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +char *str; +char *pnt; +int ch, scopetype; +int vartype; +uint32_t len, alias; +/* uint32_t maxvalpos=0; */ +unsigned int num_signal_dyn = 65536; +int attrtype, subtype; +uint64_t attrarg; +fstHandle maxhandle_scanbuild; + +if(!xc) return(0); + +xc->longest_signal_value_len = 32; /* arbitrarily set at 32...this is much longer than an expanded double */ + +if(!xc->fh) +        { +        if(!fstReaderRecreateHierFile(xc)) +                { +                return(0); +                } +        } + +str = malloc(FST_ID_NAM_ATTR_SIZ+1); + +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); +        if(xc->timezero) fprintf(fv, "$timezero\n\t%"PRId64"\n$end\n", xc->timezero); + +        switch(xc->timescale) +                { +                case  2:        time_scale = 100;               time_dimension[0] = 0;   break; +                case  1:        time_scale = 10; +                case  0:                                        time_dimension[0] = 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)); + +fstReaderFseeko(xc, 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); +                        if((scopetype < FST_ST_MIN) || (scopetype > FST_ST_MAX)) scopetype = FST_ST_VCD_MODULE; +                        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_ST_GEN_ATTRBEGIN: +                        attrtype = fgetc(xc->fh); +                        subtype = fgetc(xc->fh); +                        pnt = str; +                        while((ch = fgetc(xc->fh))) +                                { +                                *(pnt++) = ch; +                                }; /* attrname */ +                        *pnt = 0; + +                        if(!str[0]) { strcpy(str, "\"\""); } + +                        attrarg = fstReaderVarint64(xc->fh); + +                        if(fv && xc->use_vcd_extensions) +                                { +                                switch(attrtype) +                                        { +                                        case FST_AT_ARRAY:      if((subtype < FST_AR_NONE) || (subtype > FST_AR_MAX)) subtype = FST_AR_NONE; +                                                                fprintf(fv, "$attrbegin %s %s %s %"PRId64" $end\n", attrtypes[attrtype], arraytypes[subtype], str, attrarg); +                                                                break; +                                        case FST_AT_ENUM:       if((subtype < FST_EV_SV_INTEGER) || (subtype > FST_EV_MAX)) subtype = FST_EV_SV_INTEGER; +                                                                fprintf(fv, "$attrbegin %s %s %s %"PRId64" $end\n", attrtypes[attrtype], enumvaluetypes[subtype], str, attrarg); +                                                                break; +                                        case FST_AT_PACK:       if((subtype < FST_PT_NONE) || (subtype > FST_PT_MAX)) subtype = FST_PT_NONE; +                                                                fprintf(fv, "$attrbegin %s %s %s %"PRId64" $end\n", attrtypes[attrtype], packtypes[subtype], str, attrarg); +                                                                break; +                                        case FST_AT_MISC: +                                        default:                attrtype = FST_AT_MISC; +                                                                if(subtype == FST_MT_COMMENT) +                                                                        { +                                                                        fprintf(fv, "$comment\n\t%s\n$end\n", str); +                                                                        } +                                                                        else +                                                                        { +                                                                        if((subtype == FST_MT_SOURCESTEM)||(subtype == FST_MT_SOURCEISTEM)) +                                                                                { +                                                                                int sidx_skiplen_dummy = 0; +                                                                                uint64_t sidx = fstGetVarint64((unsigned char *)str, &sidx_skiplen_dummy); + +                                                                                fprintf(fv, "$attrbegin %s %02x %"PRId64" %"PRId64" $end\n", attrtypes[attrtype], subtype, sidx, attrarg); +                                                                                } +                                                                                else +                                                                                { +                                                                                fprintf(fv, "$attrbegin %s %02x %s %"PRId64" $end\n", attrtypes[attrtype], subtype, str, attrarg); +                                                                                } +                                                                        } +                                                                break; +                                        } +                                } +                        break; + +                case FST_ST_GEN_ATTREND: +                        if(fv && xc->use_vcd_extensions) fprintf(fv, "$attrend $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_SPARRAY: +                case FST_VT_VCD_REALTIME: +                case FST_VT_GEN_STRING: +                case FST_VT_SV_BIT: +                case FST_VT_SV_LOGIC: +                case FST_VT_SV_INT: +                case FST_VT_SV_SHORTINT: +                case FST_VT_SV_LONGINT: +                case FST_VT_SV_BYTE: +                case FST_VT_SV_ENUM: +                case FST_VT_SV_SHORTREAL: +                        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) || (vartype == FST_VT_SV_SHORTREAL)) +                                        { +                                        len = (vartype != FST_VT_SV_SHORTREAL) ? 64 : 32; +                                        xc->signal_typs[xc->maxhandle] = FST_VT_VCD_REAL; +                                        } +                                if(fv) +                                        { +                                        char vcdid_buf[16]; +                                        uint32_t modlen = (vartype != FST_VT_VCD_PORT) ? len : ((len - 2) / 3); +                                        fstVcdID(vcdid_buf, xc->maxhandle+1); +                                        fprintf(fv, "$var %s %"PRIu32" %s %s $end\n", vartypes[vartype], modlen, vcdid_buf, str); +                                        } +                                xc->maxhandle++; +                                } +                                else +                                { +                                if((vartype == FST_VT_VCD_REAL) || (vartype == FST_VT_VCD_REAL_PARAMETER) || (vartype == FST_VT_VCD_REALTIME) || (vartype == FST_VT_SV_SHORTREAL)) +                                        { +                                        len = (vartype != FST_VT_SV_SHORTREAL) ? 64 : 32; +                                        xc->signal_typs[xc->maxhandle] = FST_VT_VCD_REAL; +                                        } +                                if(fv) +                                        { +                                        char vcdid_buf[16]; +                                        uint32_t modlen = (vartype != FST_VT_VCD_PORT) ? len : ((len - 2) / 3); +                                        fstVcdID(vcdid_buf, alias); +                                        fprintf(fv, "$var %s %"PRIu32" %s %s $end\n", vartypes[vartype], modlen, vcdid_buf, str); +                                        } +                                xc->num_alias++; +                                } + +                        break; + +                default: +                        break; +                } +        } +if(fv) fprintf(fv, "$enddefinitions $end\n"); + +maxhandle_scanbuild = xc->maxhandle ? xc->maxhandle : 1; /*scan-build warning suppression, in reality we have at least one signal */ + +xc->signal_lens = realloc(xc->signal_lens, maxhandle_scanbuild*sizeof(uint32_t)); +xc->signal_typs = realloc(xc->signal_typs, maxhandle_scanbuild*sizeof(unsigned char)); + +free(xc->process_mask); +xc->process_mask = calloc(1, (maxhandle_scanbuild+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; + +free(str); +return(1); +} + + +/* + * 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; +int gzread_pass_status = 1; + +sectype = fgetc(xc->f); +if(sectype == FST_BL_ZWRAPPER) +        { +        FILE *fcomp; +        off_t offpnt, uclen; +        char gz_membuf[FST_GZIO_LEN]; +        void *zhandle; +        int zfd; +        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"); +        if(!fcomp) +                { +                fcomp = tmpfile_open(&xc->f_nam); +                free(hf); hf = NULL; +                if(!fcomp) { tmpfile_close(&fcomp, &xc->f_nam); return(0); } +                } + +#if defined(FST_MACOSX) +        setvbuf(fcomp, (char *)NULL, _IONBF, 0);   /* keeps gzip from acting weird in tandem with fopen */ +#endif + +#ifdef __MINGW32__ +        setvbuf(fcomp, (char *)NULL, _IONBF, 0);   /* keeps gzip from acting weird in tandem with fopen */ +        xc->filename_unpacked = hf; +#else +        if(hf) +                { +                unlink(hf); +                free(hf); +                } +#endif + +        fstReaderFseeko(xc, xc->f, 1+8+8, SEEK_SET); +#ifndef __MINGW32__ +        fflush(xc->f); +#endif + +        zfd = dup(fileno(xc->f)); +        zhandle = gzdopen(zfd, "rb"); +        if(zhandle) +                { +                for(offpnt = 0; offpnt < uclen; offpnt += FST_GZIO_LEN) +                        { +                        size_t this_len = ((uclen - offpnt) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - offpnt); +                        size_t gzreadlen = gzread(zhandle, gz_membuf, this_len); +                        size_t fwlen; + +                        if(gzreadlen != this_len) +                                { +                                gzread_pass_status = 0; +                                break; +                                } +                        fwlen = fstFwrite(gz_membuf, this_len, 1, fcomp); +                        if(fwlen != 1) +                                { +                                gzread_pass_status = 0; +                                break; +                                } +                        } +                gzclose(zhandle); +                } +                else +                { +                close(zfd); +                } +        fflush(fcomp); +        fclose(xc->f); +        xc->f = fcomp; +        } + +if(gzread_pass_status) +        { +        fstReaderFseeko(xc, xc->f, 0, SEEK_END); +        endfile = ftello(xc->f); + +        while(blkpos < endfile) +                { +                fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET); + +                sectype = fgetc(xc->f); +                seclen = fstReaderUint64(xc->f); + +                if(sectype == EOF) +                        { +                        break; +                        } + +                if((hdr_incomplete) && (!seclen)) +                        { +                        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; +                                ch = fgetc(xc->f); +                                xc->filetype = (unsigned char)ch; +                                xc->timezero = fstReaderUint64(xc->f); +                                } +                        } +                else if((sectype == FST_BL_VCDATA) || (sectype == FST_BL_VCDATA_DYN_ALIAS) || (sectype == FST_BL_VCDATA_DYN_ALIAS2)) +                        { +                        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; +                                unsigned 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;i<xc->maxhandle;i++) +                                        { +                                        int skiplen; +                                        uint64_t val = fstGetVarint32(pnt, &skiplen); + +                                        pnt += skiplen; + +                                        if(val) +                                                { +                                                xc->signal_lens[i] = (val != 0xFFFFFFFF) ? val : 0; +                                                xc->signal_typs[i] = FST_VT_VCD_WIRE; +                                                if(xc->signal_lens[i] > xc->longest_signal_value_len) +                                                        { +                                                        xc->longest_signal_value_len = xc->signal_lens[i]; +                                                        } +                                                } +                                                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_HIER_LZ4DUO) +                        { +                        xc->contains_hier_section_lz4    = 1; +                        xc->contains_hier_section_lz4duo = 1; +                        xc->hier_pos = ftello(xc->f); +                        } +                else if(sectype == FST_BL_HIER_LZ4) +                        { +                        xc->contains_hier_section_lz4 = 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;i<xc->num_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 *fstReaderOpenForUtilitiesOnly(void) +{ +struct fstReaderContext *xc = calloc(1, sizeof(struct fstReaderContext)); + +return(xc); +} + + +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; + +#if defined(__MINGW32__) || defined(FST_MACOSX) +        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||(xc->contains_hier_section_lz4)))) +                { +                /* 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) +                { +                tmpfile_close(&xc->fh, &xc->fh_nam); +                } + +        if(xc->f) +                { +                tmpfile_close(&xc->f, &xc->f_nam); +                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) +{ +return(fstReaderIterBlocks2(ctx, value_change_callback, NULL, user_callback_data_pointer, fv)); +} + + +int fstReaderIterBlocks2(void *ctx, +        void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value), +        void (*value_change_callback_varlen)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value, uint32_t len), +        void *user_callback_data_pointer, FILE *fv) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; + +uint64_t previous_time = UINT64_MAX; +uint64_t *time_table = NULL; +uint64_t tsec_nitems; +unsigned int secnum = 0; +int blocks_skipped = 0; +off_t blkpos = 0; +uint64_t seclen, beg_tim; +#ifdef FST_DEBUG +uint64_t end_tim; +#endif +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; +unsigned char *mc_mem = NULL; +uint32_t mc_mem_len; /* corresponds to largest value encountered in chain_table_lengths[i] */ + +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)); + +if(fv) +        { +        fprintf(fv, "$dumpvars\n"); +#ifndef FST_WRITEX_DISABLE +        fflush(fv); +        setvbuf(fv, (char *) NULL, _IONBF, 0); /* even buffered IO is slow so disable it and use our own routines that don't need seeking */ +        xc->writex_fd = fileno(fv); +#endif +        } + +for(;;) +        { +        uint32_t *tc_head = NULL; +        traversal_mem_offs = 0; + +        fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET); + +        sectype = fgetc(xc->f); +        seclen = fstReaderUint64(xc->f); + +        if((sectype == EOF) || (sectype == FST_BL_SKIP)) +                { +#ifdef FST_DEBUG +                fprintf(stderr, "<< EOF >>\n"); +#endif +                break; +                } + +        blkpos++; +        if((sectype != FST_BL_VCDATA) && (sectype != FST_BL_VCDATA_DYN_ALIAS) && (sectype != FST_BL_VCDATA_DYN_ALIAS2)) +                { +                blkpos += seclen; +                continue; +                } + +        if(!seclen) break; + +        beg_tim = fstReaderUint64(xc->f); +#ifdef FST_DEBUG +        end_tim = +#endif +        fstReaderUint64(xc->f); + +        if(xc->limit_range_valid) +                { +                if(beg_tim < xc->limit_range_start) +                        { +                        blocks_skipped++; +                        blkpos += seclen; +                        continue; +                        } + +                if(beg_tim > xc->limit_range_end) /* likely the compare in for(i=0;i<tsec_nitems;i++) below would do this earlier */ +                        { +                        break; +                        } +                } + + +        mem_required_for_traversal = fstReaderUint64(xc->f); +        mem_for_traversal = malloc(mem_required_for_traversal + 66); /* add in potential fastlz overhead */ +#ifdef FST_DEBUG +        fprintf(stderr, "sec: %u seclen: %d begtim: %d endtim: %d\n", +                secnum, (int)seclen, (int)beg_tim, (int)end_tim); +        fprintf(stderr, "\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 */; /* scan-build */ +        unsigned long sourcelen /*= tsec_clen */; /* scan-build */ +        int rc; +        unsigned char *tpnt; +        uint64_t tpval; +        unsigned int ti; + +        if(fstReaderFseeko(xc, xc->f, blkpos + seclen - 24, SEEK_SET) != 0) break; +        tsec_uclen = fstReaderUint64(xc->f); +        tsec_clen = fstReaderUint64(xc->f); +        tsec_nitems = fstReaderUint64(xc->f); +#ifdef FST_DEBUG +        fprintf(stderr, "\ttime section unc: %d, com: %d (%d items)\n", +                (int)tsec_uclen, (int)tsec_clen, (int)tsec_nitems); +#endif +        if(tsec_clen > seclen) break; /* corrupted tsec_clen: by definition it can't be larger than size of section */ +        ucdata = malloc(tsec_uclen); +        if(!ucdata) break; /* malloc fail as tsec_uclen out of range from corrupted file */ +        destlen = tsec_uclen; +        sourcelen = tsec_clen; + +        fstReaderFseeko(xc, 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;ti<tsec_nitems;ti++) +                { +                int skiplen; +                uint64_t val = fstGetVarint64(tpnt, &skiplen); +                tpval = time_table[ti] = tpval + val; +                tpnt += skiplen; +                } + +        tc_head = calloc(tsec_nitems /* scan-build */ ? tsec_nitems : 1, sizeof(uint32_t)); +        free(ucdata); +        } + +        fstReaderFseeko(xc, xc->f, 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]) || (blocks_skipped)) +                        { +                        unsigned char *mu = malloc(frame_uclen); +                        uint32_t sig_offs = 0; + +                        if(fv) +                                { +                                char wx_buf[32]; +                                int wx_len; + +                                if(beg_tim) +                                        { +                                        wx_len = sprintf(wx_buf, "#%"PRIu64"\n", beg_tim); +                                        fstWritex(xc, wx_buf, wx_len); +                                        } +                                if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts)) +                                        { +                                        if(beg_tim == xc->blackout_times[cur_blackout]) +                                                { +                                                wx_len = sprintf(wx_buf, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off"); +                                                fstWritex(xc, wx_buf, wx_len); +                                                } +                                        } +                                } + +                        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;idx<frame_maxhandle;idx++) +                                { +                                int process_idx = idx/8; +                                int process_bit = idx&7; + +                                if(xc->process_mask[process_idx]&(1<<process_bit)) +                                        { +                                        if(xc->signal_lens[idx] <= 1) +                                                { +                                                if(xc->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) +                                                                        { +                                                                        char vcd_id[16]; + +                                                                        int vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1); +                                                                        vcd_id[0] = val; /* collapse 3 writes into one I/O call */ +                                                                        vcd_id[vcdid_len + 1] = '\n'; +                                                                        fstWritex(xc, vcd_id, vcdid_len + 2); +                                                                        } +                                                                } +                                                        } +                                                        else +                                                        { +                                                        /* variable-length ("0" length) records have no initial state */ +                                                        } +                                                } +                                                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) +                                                                        { +                                                                        char vcd_id[16]; +                                                                        int vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1); + +                                                                        vcd_id[0] = (xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p'; +                                                                        fstWritex(xc, vcd_id, 1); +                                                                        fstWritex(xc,mu+sig_offs, xc->signal_lens[idx]); + +                                                                        vcd_id[0] = ' '; /* collapse 3 writes into one I/O call */ +                                                                        vcd_id[vcdid_len + 1] = '\n'; +                                                                        fstWritex(xc, vcd_id, vcdid_len + 2); +                                                                        } +                                                                } +                                                        } +                                                        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) +                                                                        { +                                                                        char vcdid_buf[16]; +                                                                        char wx_buf[64]; +                                                                        int wx_len; + +                                                                        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]; +                                                                                        } +                                                                                } + +                                                                        fstVcdID(vcdid_buf, idx+1); +                                                                        wx_len = sprintf(wx_buf, "r%.16g %s\n", d, vcdid_buf); +                                                                        fstWritex(xc, wx_buf, wx_len); +                                                                        } +                                                                } +                                                        } +                                                } +                                        } + +                                sig_offs += xc->signal_lens[idx]; +                                } + +                        free(mu); +                        fstReaderFseeko(xc, xc->f, -((off_t)frame_clen), SEEK_CUR); +                        } +                } + +        fstReaderFseeko(xc, 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 +        fprintf(stderr, "\tframe_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n", +                (int)frame_uclen, (int)frame_clen, (int)frame_maxhandle); +        fprintf(stderr, "\tvc_maxhandle: %d, packtype: %c\n", (int)vc_maxhandle, packtype); +#endif + +        indx_pntr = blkpos + seclen - 24 -tsec_clen -8; +        fstReaderFseeko(xc, xc->f, indx_pntr, SEEK_SET); +        chain_clen = fstReaderUint64(xc->f); +        indx_pos = indx_pntr - chain_clen; +#ifdef FST_DEBUG +        fprintf(stderr, "\tindx_pos: %d (%d bytes)\n", (int)indx_pos, (int)chain_clen); +#endif +        chain_cmem = malloc(chain_clen); +        if(!chain_cmem) goto block_err; +        fstReaderFseeko(xc, 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 = calloc((vc_maxhandle+1), sizeof(off_t)); +                chain_table_lengths = calloc((vc_maxhandle+1), sizeof(uint32_t)); +                } + +        if(!chain_table || !chain_table_lengths) goto block_err; + +        pnt = chain_cmem; +        idx = 0; +        pval = 0; + +        if(sectype == FST_BL_VCDATA_DYN_ALIAS2) +                { +                uint32_t prev_alias = 0; + +                do      { +                        int skiplen; + +                        if(*pnt & 0x01) +                                { +                                int64_t shval = fstGetSVarint64(pnt, &skiplen) >> 1; +                                if(shval > 0) +                                        { +                                        pval = chain_table[idx] = pval + shval; +                                        if(idx) { chain_table_lengths[pidx] = pval - chain_table[pidx]; } +                                        pidx = idx++; +                                        } +                                else if(shval < 0) +                                        { +                                        chain_table[idx] = 0;                                   /* need to explicitly zero as calloc above might not run */ +                                        chain_table_lengths[idx] = prev_alias = shval;          /* because during this loop iter would give stale data! */ +                                        idx++; +                                        } +                                else +                                        { +                                        chain_table[idx] = 0;                                   /* need to explicitly zero as calloc above might not run */ +                                        chain_table_lengths[idx] = prev_alias;                  /* because during this loop iter would give stale data! */ +                                        idx++; +                                        } +                                } +                                else +                                { +                                uint64_t val = fstGetVarint32(pnt, &skiplen); + +                                fstHandle loopcnt = val >> 1; +                                for(i=0;i<loopcnt;i++) +                                        { +                                        chain_table[idx++] = 0; +                                        } +                                } + +                        pnt += skiplen; +                        } while (pnt != (chain_cmem + chain_clen)); +                } +                else +                { +                do      { +                        int skiplen; +                        uint64_t val = fstGetVarint32(pnt, &skiplen); + +                        if(!val) +                                { +                                pnt += skiplen; +                                val = fstGetVarint32(pnt, &skiplen); +                                chain_table[idx] = 0;                   /* need to explicitly zero as calloc above might not run */ +                                chain_table_lengths[idx] = -val;        /* because during this loop iter would give stale data! */ +                                idx++; +                                } +                        else +                        if(val&1) +                                { +                                pval = chain_table[idx] = pval + (val >> 1); +                                if(idx) { chain_table_lengths[pidx] = pval - chain_table[pidx]; } +                                pidx = idx++; +                                } +                        else +                                { +                                fstHandle loopcnt = val >> 1; +                                for(i=0;i<loopcnt;i++) +                                        { +                                        chain_table[idx++] = 0; +                                        } +                                } + +                        pnt += skiplen; +                        } while (pnt != (chain_cmem + chain_clen)); +                } + +        chain_table[idx] = indx_pos - vc_start; +        chain_table_lengths[pidx] = chain_table[idx] - chain_table[pidx]; + +        for(i=0;i<idx;i++) +                { +                int32_t v32 = chain_table_lengths[i]; +                if((v32 < 0) && (!chain_table[i])) +                        { +                        v32 = -v32; +                        v32--; +                        if(((uint32_t)v32) < i) /* sanity check */ +                                { +                                chain_table[i] = chain_table[v32]; +                                chain_table_lengths[i] = chain_table_lengths[v32]; +                                } +                        } +                } + +#ifdef FST_DEBUG +        fprintf(stderr, "\tdecompressed chain idx len: %"PRIu32"\n", idx); +#endif + +        mc_mem_len = 16384; +        mc_mem = malloc(mc_mem_len); /* buffer for compressed reads */ + +        /* check compressed VC data */ +        if(idx > xc->maxhandle) idx = xc->maxhandle; +        for(i=0;i<idx;i++) +                { +                if(chain_table[i]) +                        { +                        int process_idx = i/8; +                        int process_bit = i&7; + +                        if(xc->process_mask[process_idx]&(1<<process_bit)) +                                { +                                int rc = Z_OK; +                                uint32_t val; +                                uint32_t skiplen; +                                uint32_t tdelta; + +                                fstReaderFseeko(xc, xc->f, vc_start + chain_table[i], SEEK_SET); +                                val = fstReaderVarint32WithSkip(xc->f, &skiplen); +                                if(val) +                                        { +                                        unsigned char *mu = mem_for_traversal + traversal_mem_offs; /* uncomp: dst */ +                                        unsigned char *mc;                                          /* comp:   src */ +                                        unsigned long destlen = val; +                                        unsigned long sourcelen = chain_table_lengths[i]; + +                                        if(mc_mem_len < chain_table_lengths[i]) +                                                { +                                                free(mc_mem); +                                                mc_mem = malloc(mc_mem_len = chain_table_lengths[i]); +                                                } +                                        mc = mc_mem; + +                                        fstFread(mc, chain_table_lengths[i], 1, xc->f); + +                                        switch(packtype) +                                                { +                                                case '4': rc = (destlen == (unsigned long)LZ4_decompress_safe_partial((char *)mc, (char *)mu, sourcelen, destlen, destlen)) ? Z_OK : Z_DATA_ERROR; +                                                          break; +                                                case 'F': fastlz_decompress(mc, sourcelen, mu, destlen); /* rc appears unreliable */ +                                                          break; +                                                default:  rc = uncompress(mu, &destlen, mc, sourcelen); +                                                          break; +                                                } + +                                        /* data to process is for(j=0;j<destlen;j++) in mu[j] */ +                                        headptr[i] = traversal_mem_offs; +                                        length_remaining[i] = val; +                                        traversal_mem_offs += val; +                                        } +                                        else +                                        { +                                        int destlen = chain_table_lengths[i] - skiplen; +                                        unsigned char *mu = mem_for_traversal + traversal_mem_offs; +                                        fstFread(mu, destlen, 1, xc->f); +                                        /* data to process is for(j=0;j<destlen;j++) in mu[j] */ +                                        headptr[i] = traversal_mem_offs; +                                        length_remaining[i] = destlen; +                                        traversal_mem_offs += destlen; +                                        } + +                                if(rc != Z_OK) +                                        { +                                        printf("\tfac: %d clen: %d (rc=%d)\n", (int)i, (int)val, rc); +                                        exit(255); +                                        } + +                                if(xc->signal_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; +                                } +                        } +                } + +        free(mc_mem); /* there is no usage below for this, no real need to clear out mc_mem or mc_mem_len */ + +        for(i=0;i<tsec_nitems;i++) +                { +                uint32_t tdelta; +                int skiplen, skiplen2; +                uint32_t vli; + +                if(fv) +                        { +                        char wx_buf[32]; +                        int wx_len; + +                        if(time_table[i] != previous_time) +                                { +                                if(xc->limit_range_valid) +                                        { +                                        if(time_table[i] > xc->limit_range_end) +                                                { +                                                break; +                                                } +                                        } + +                                wx_len = sprintf(wx_buf, "#%"PRIu64"\n", time_table[i]); +                                fstWritex(xc, wx_buf, wx_len); + +                                if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts)) +                                        { +                                        if(time_table[i] == xc->blackout_times[cur_blackout]) +                                                { +                                                wx_len = sprintf(wx_buf, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off"); +                                                fstWritex(xc, wx_buf, wx_len); +                                                } +                                        } +                                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) +                                { +                                if(xc->signal_lens[idx] == 1) +                                        { +                                        unsigned char val; +                                        if(!(vli & 1)) +                                                { +                                                /* tdelta = vli >> 2; */ /* scan-build */ +                                                val = ((vli >> 1) & 1) | '0'; +                                                } +                                                else +                                                { +                                                /* tdelta = vli >> 4; */ /* scan-build */ +                                                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) +                                                        { +                                                        char vcd_id[16]; +                                                        int vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1); + +                                                        vcd_id[0] = val; +                                                        vcd_id[vcdid_len+1] = '\n'; +                                                        fstWritex(xc, vcd_id, vcdid_len+2); +                                                        } +                                                } +                                        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 +                                        { +                                        unsigned char *vdata; +                                        uint32_t len; + +                                        vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen); +                                        len = fstGetVarint32(mem_for_traversal + headptr[idx] + skiplen, &skiplen2); +                                        /* tdelta = vli >> 1; */ /* scan-build */ +                                        skiplen += skiplen2; +                                        vdata = mem_for_traversal + headptr[idx] + skiplen; + +                                        if(!(vli & 1)) +                                                { +                                                if(value_change_callback_varlen) +                                                        { +                                                        value_change_callback_varlen(user_callback_data_pointer, time_table[i], idx+1, vdata, len); +                                                        } +                                                        else +                                                        { +                                                        if(fv) +                                                                { +                                                                char vcd_id[16]; +                                                                int vcdid_len; + +                                                                vcd_id[0] = 's'; +                                                                fstWritex(xc, vcd_id, 1); + +                                                                vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1); +                                                                { +                                                                unsigned char *vesc = malloc(len*4 + 1); +                                                                int vlen = fstUtilityBinToEsc(vesc, vdata, len); +                                                                fstWritex(xc, vesc, vlen); +                                                                free(vesc); +                                                                } + +                                                                vcd_id[0] = ' '; +                                                                vcd_id[vcdid_len + 1] = '\n'; +                                                                fstWritex(xc, vcd_id, vcdid_len+2); +                                                                } +                                                        } +                                                } + +                                        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; +                                                } +                                        } +                                } +                                else +                                { +                                uint32_t len = xc->signal_lens[idx]; +                                unsigned char *vdata; + +                                vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen); +                                /* tdelta = vli >> 1; */ /* scan-build */ +                                vdata = mem_for_traversal + headptr[idx] + skiplen; + +                                if(xc->signal_typs[idx] != FST_VT_VCD_REAL) +                                        { +                                        if(!(vli & 1)) +                                                { +                                                int byte = 0; +                                                int bit; +                                                unsigned int j; + +                                                for(j=0;j<len;j++) +                                                        { +                                                        unsigned char ch; +                                                        byte = j/8; +                                                        bit = 7 - (j & 7); +                                                        ch = ((vdata[byte] >> 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)  { +                                                                unsigned char ch_bp = (xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p'; + +                                                                fstWritex(xc, &ch_bp, 1); +                                                                fstWritex(xc, xc->temp_signal_value_buf, len); +                                                                } +                                                        } + +                                                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) +                                                                { +                                                                unsigned char ch_bp =  (xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p'; + +                                                                fstWritex(xc, &ch_bp, 1); +                                                                fstWritex(xc, vdata, len); +                                                                } +                                                        } +                                                } +                                        } +                                        else +                                        { +                                        double d; +                                        unsigned char *clone_d /*= (unsigned char *)&d */; /* scan-build */ +                                        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) +                                                        { +                                                        char wx_buf[32]; +                                                        int wx_len; + +                                                        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]; +                                                                        } +                                                                } + +                                                        wx_len = sprintf(wx_buf, "r%.16g", d); +                                                        fstWritex(xc, wx_buf, wx_len); +                                                        } +                                                } +                                        } + +                                if(fv) +                                        { +                                        char vcd_id[16]; +                                        int vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1); +                                        vcd_id[0] = ' '; +                                        vcd_id[vcdid_len+1] = '\n'; +                                        fstWritex(xc, vcd_id, vcdid_len+2); +                                        } + +                                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; +                                        } +                                } +                        } +                } + +block_err: +        free(tc_head); +        free(chain_cmem); +        free(mem_for_traversal); mem_for_traversal = NULL; + +        secnum++; +        if(secnum == xc->vc_section_count) break; /* in case file is growing, keep with original block count */ +        blkpos += seclen; +        } + +if(mem_for_traversal) free(mem_for_traversal); /* scan-build */ +free(length_remaining); +free(headptr); +free(scatterptr); + +if(chain_table) free(chain_table); +if(chain_table_lengths) free(chain_table_lengths); + +free(time_table); + +#ifndef FST_WRITEX_DISABLE +if(fv) +        { +        fstWritex(xc, NULL, 0); +        } +#endif + +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; +unsigned int secnum = 0; +uint64_t seclen; +uint64_t tsec_uclen = 0, tsec_clen = 0; +uint64_t tsec_nitems; +uint64_t frame_uclen, frame_clen; +#ifdef FST_DEBUG +uint64_t mem_required_for_traversal; +#endif +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) || (!xc->signal_lens[facidx-1])) +        { +        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;i<xc->maxhandle;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(;;) +        { +        fstReaderFseeko(xc, 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) && (sectype != FST_BL_VCDATA_DYN_ALIAS) && (sectype != FST_BL_VCDATA_DYN_ALIAS2)) +                { +                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); +                        fstReaderFseeko(xc, 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)&&(sectype != FST_BL_VCDATA_DYN_ALIAS)&&(sectype != FST_BL_VCDATA_DYN_ALIAS2)) || (!seclen) || (beg_tim2 != tim)) +                                { +                                blkpos = prev_blkpos; +                                break; +                                } +                        beg_tim = beg_tim2; +                        end_tim = end_tim2; +                        fstReaderFseeko(xc, xc->f, cached_pos, SEEK_SET); +                        } +                break; +                } + +        blkpos += seclen; +        secnum++; +        } + +xc->rvat_beg_tim = beg_tim; +xc->rvat_end_tim = end_tim; + +#ifdef FST_DEBUG +mem_required_for_traversal = +#endif +        fstReaderUint64(xc->f); + +#ifdef FST_DEBUG +fprintf(stderr, "rvat sec: %u seclen: %d begtim: %d endtim: %d\n", +        secnum, (int)seclen, (int)beg_tim, (int)end_tim); +fprintf(stderr, "\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 */; /* scan-build */ +unsigned long sourcelen /* = tsec_clen */; /* scan-build */ +int rc; +unsigned char *tpnt; +uint64_t tpval; +unsigned int ti; + +fstReaderFseeko(xc, 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 +fprintf(stderr, "\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; + +fstReaderFseeko(xc, 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;ti<tsec_nitems;ti++) +        { +        int skiplen; +        uint64_t val = fstGetVarint64(tpnt, &skiplen); +        tpval = xc->rvat_time_table[ti] = tpval + val; +        tpnt += skiplen; +        } + +free(ucdata); +} + +fstReaderFseeko(xc, 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 +fprintf(stderr, "\tframe_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n", +        (int)frame_uclen, (int)frame_clen, (int)xc->rvat_frame_maxhandle); +fprintf(stderr, "\tvc_maxhandle: %d\n", (int)xc->rvat_vc_maxhandle); +#endif + +indx_pntr = blkpos + seclen - 24 -tsec_clen -8; +fstReaderFseeko(xc, xc->f, indx_pntr, SEEK_SET); +chain_clen = fstReaderUint64(xc->f); +indx_pos = indx_pntr - chain_clen; +#ifdef FST_DEBUG +fprintf(stderr, "\tindx_pos: %d (%d bytes)\n", (int)indx_pos, (int)chain_clen); +#endif +chain_cmem = malloc(chain_clen); +fstReaderFseeko(xc, xc->f, indx_pos, SEEK_SET); +fstFread(chain_cmem, chain_clen, 1, xc->f); + +xc->rvat_chain_table = calloc((xc->rvat_vc_maxhandle+1), sizeof(off_t)); +xc->rvat_chain_table_lengths = calloc((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) +                { +                pnt += skiplen; +                val = fstGetVarint32(pnt, &skiplen); +                xc->rvat_chain_table[idx] = 0; +                xc->rvat_chain_table_lengths[idx] = -val; +                idx++; +                } +        else +        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 +                { +                fstHandle loopcnt = val >> 1; +                for(i=0;i<loopcnt;i++) +                        { +                        xc->rvat_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]; + +for(i=0;i<idx;i++) +        { +        int32_t v32 = xc->rvat_chain_table_lengths[i]; +        if((v32 < 0) && (!xc->rvat_chain_table[i])) +                { +                v32 = -v32; +                v32--; +                if(((uint32_t)v32) < i) /* sanity check */ +                        { +                        xc->rvat_chain_table[i] = xc->rvat_chain_table[v32]; +                        xc->rvat_chain_table_lengths[i] = xc->rvat_chain_table_lengths[v32]; +                        } +                } +        } + +#ifdef FST_DEBUG +fprintf(stderr, "\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; +        fstReaderFseeko(xc, 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;j<destlen;j++) in mu[j] */ +                xc->rvat_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;j<destlen;j++) in mu[j] */ +                xc->rvat_chain_mem = mu; +                } + +        xc->rvat_chain_facidx = facidx; +        } + +/* process value chain here */ + +{ +uint32_t tidx = 0, ptidx = 0; +uint32_t tdelta; +int skiplen; +unsigned 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(i<xc->rvat_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; */ /* scan-build */ + +                        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(i<xc->rvat_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; +                                unsigned int j; + +                                for(j=0;j<xc->signal_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); */ +} + + + +/**********************************************************************/ +#ifndef _WAVE_HAVE_JUDY + +/***********************/ +/***                 ***/ +/***  jenkins hash   ***/ +/***                 ***/ +/***********************/ + +/* +-------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. +For every delta with one or two bits set, and the deltas of all three +  high bits or all three low bits, whether the original value of a,b,c +  is almost all zero or is uniformly distributed, +* If mix() is run forward or backward, at least 32 bits in a,b,c +  have at least 1/4 probability of changing. +* If mix() is run forward, every bit of c will change between 1/3 and +  2/3 of the time.  (Well, 22/100 and 78/100 for some 2-bit deltas.) +mix() was built out of 36 single-cycle latency instructions in a +  structure that could supported 2x parallelism, like so: +      a -= b; +      a -= c; x = (c>>13); +      b -= c; a ^= x; +      b -= a; x = (a<<8); +      c -= a; b ^= x; +      c -= b; x = (b>>13); +      ... +  Unfortunately, superscalar Pentiums and Sparcs can't take advantage +  of that parallelism.  They've also turned some of those single-cycle +  latency instructions into multi-cycle latency instructions.  Still, +  this is the fastest good hash I could find.  There were about 2^^68 +  to choose from.  I only looked at a billion or so. +-------------------------------------------------------------------- +*/ +#define mix(a,b,c) \ +{ \ +  a -= b; a -= c; a ^= (c>>13); \ +  b -= c; b -= a; b ^= (a<<8); \ +  c -= a; c -= b; c ^= (b>>13); \ +  a -= b; a -= c; a ^= (c>>12);  \ +  b -= c; b -= a; b ^= (a<<16); \ +  c -= a; c -= b; c ^= (b>>5); \ +  a -= b; a -= c; a ^= (c>>3);  \ +  b -= c; b -= a; b ^= (a<<10); \ +  c -= a; c -= b; c ^= (b>>15); \ +} + +/* +-------------------------------------------------------------------- +j_hash() -- hash a variable-length key into a 32-bit value +  k       : the key (the unaligned variable-length array of bytes) +  len     : the length of the key, counting by bytes +  initval : can be any 4-byte value +Returns a 32-bit value.  Every bit of the key affects every bit of +the return value.  Every 1-bit and 2-bit delta achieves avalanche. +About 6*len+35 instructions. + +The best hash table sizes are powers of 2.  There is no need to do +mod a prime (mod is sooo slow!).  If you need less than 32 bits, +use a bitmask.  For example, if you need only 10 bits, do +  h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (uint8_t **)k, do it like this: +  for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h); + +By Bob Jenkins, 1996.  bob_jenkins@burtleburtle.net.  You may use this +code any way you wish, private, educational, or commercial.  It's free. + +See http://burtleburtle.net/bob/hash/evahash.html +Use for hash table lookup, or anything where one collision in 2^^32 is +acceptable.  Do NOT use for cryptographic purposes. +-------------------------------------------------------------------- +*/ + +static uint32_t j_hash(const uint8_t *k, uint32_t length, uint32_t initval) +{ +   uint32_t a,b,c,len; + +   /* Set up the internal state */ +   len = length; +   a = b = 0x9e3779b9;  /* the golden ratio; an arbitrary value */ +   c = initval;         /* the previous hash value */ + +   /*---------------------------------------- handle most of the key */ +   while (len >= 12) +   { +      a += (k[0] +((uint32_t)k[1]<<8) +((uint32_t)k[2]<<16) +((uint32_t)k[3]<<24)); +      b += (k[4] +((uint32_t)k[5]<<8) +((uint32_t)k[6]<<16) +((uint32_t)k[7]<<24)); +      c += (k[8] +((uint32_t)k[9]<<8) +((uint32_t)k[10]<<16)+((uint32_t)k[11]<<24)); +      mix(a,b,c); +      k += 12; len -= 12; +   } + +   /*------------------------------------- handle the last 11 bytes */ +   c += length; +   switch(len)              /* all the case statements fall through */ +   { +   case 11: c+=((uint32_t)k[10]<<24); +   case 10: c+=((uint32_t)k[9]<<16); +   case 9 : c+=((uint32_t)k[8]<<8); +      /* the first byte of c is reserved for the length */ +   case 8 : b+=((uint32_t)k[7]<<24); +   case 7 : b+=((uint32_t)k[6]<<16); +   case 6 : b+=((uint32_t)k[5]<<8); +   case 5 : b+=k[4]; +   case 4 : a+=((uint32_t)k[3]<<24); +   case 3 : a+=((uint32_t)k[2]<<16); +   case 2 : a+=((uint32_t)k[1]<<8); +   case 1 : a+=k[0]; +     /* case 0: nothing left to add */ +   } +   mix(a,b,c); +   /*-------------------------------------------- report the result */ +   return(c); +} + +/********************************************************************/ + +/***************************/ +/***                     ***/ +/***  judy HS emulation  ***/ +/***                     ***/ +/***************************/ + +struct collchain_t +{ +struct collchain_t *next; +void *payload; +uint32_t fullhash, length; +unsigned char mem[1]; +}; + + +void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint32_t hashmask) +{ +struct collchain_t ***base = (struct collchain_t ***)base_i; +uint32_t hf, h; +struct collchain_t **ar; +struct collchain_t *chain, *pchain; + +if(!*base) +        { +        *base = calloc(1, (hashmask + 1) * sizeof(void *)); +        } +ar = *base; + +h = (hf = j_hash(mem, length, length)) & hashmask; +pchain = chain = ar[h]; +while(chain) +        { +        if((chain->fullhash == hf) && (chain->length == length) && !memcmp(chain->mem, mem, length)) +                { +                if(pchain != chain) /* move hit to front */ +                        { +                        pchain->next = chain->next; +                        chain->next = ar[h]; +                        ar[h] = chain; +                        } +                return(&(chain->payload)); +                } + +        pchain = chain; +        chain = chain->next; +        } + +chain = calloc(1, sizeof(struct collchain_t) + length - 1); +memcpy(chain->mem, mem, length); +chain->fullhash = hf; +chain->length = length; +chain->next = ar[h]; +ar[h] = chain; +return(&(chain->payload)); +} + + +void JenkinsFree(void *base_i, uint32_t hashmask) +{ +struct collchain_t ***base = (struct collchain_t ***)base_i; +uint32_t h; +struct collchain_t **ar; +struct collchain_t *chain, *chain_next; + +if(base && *base) +        { +        ar = *base; +        for(h=0;h<=hashmask;h++) +                { +                chain = ar[h]; +                while(chain) +                        { +                        chain_next = chain->next; +                        free(chain); +                        chain = chain_next; +                        } +                } + +        free(*base); +        *base = NULL; +        } +} + +#endif + +/**********************************************************************/ + +/************************/ +/***                  ***/ +/*** utility function ***/ +/***                  ***/ +/************************/ + +int fstUtilityBinToEsc(unsigned char *d, unsigned char *s, int len) +{ +unsigned char *src = s; +unsigned char *dst = d; +unsigned char val; +int i; + +for(i=0;i<len;i++) +        { +        switch(src[i]) +                { +                case '\a':      *(dst++) = '\\'; *(dst++) = 'a'; break; +                case '\b':      *(dst++) = '\\'; *(dst++) = 'b'; break; +                case '\f':      *(dst++) = '\\'; *(dst++) = 'f'; break; +                case '\n':      *(dst++) = '\\'; *(dst++) = 'n'; break; +                case '\r':      *(dst++) = '\\'; *(dst++) = 'r'; break; +                case '\t':      *(dst++) = '\\'; *(dst++) = 't'; break; +                case '\v':      *(dst++) = '\\'; *(dst++) = 'v'; break; +                case '\'':      *(dst++) = '\\'; *(dst++) = '\''; break; +                case '\"':      *(dst++) = '\\'; *(dst++) = '\"'; break; +                case '\\':      *(dst++) = '\\'; *(dst++) = '\\'; break; +                case '\?':      *(dst++) = '\\'; *(dst++) = '\?'; break; +                default:        if((src[i] > ' ') && (src[i] <= '~')) /* no white spaces in output */ +                                        { +                                        *(dst++) = src[i]; +                                        } +                                        else +                                        { +                                        val = src[i]; +                                        *(dst++) = '\\'; +                                        *(dst++) = (val/64) + '0'; val = val & 63; +                                        *(dst++) = (val/8)  + '0'; val = val & 7; +                                        *(dst++) = (val) + '0'; +                                        } +                                break; +                } +        } + +return(dst - d); +} + + +/* + * this overwrites the original string if the destination pointer is NULL + */ +int fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len) +{ +unsigned char *src = s; +unsigned char *dst = (!d) ? s : (s = d); +unsigned char val[3]; +int i; + +for(i=0;i<len;i++) +        { +        if(src[i] != '\\') +                { +                *(dst++) = src[i]; +                } +                else +                { +                switch(src[++i]) +                        { +                        case 'a':       *(dst++) = '\a'; break; +                        case 'b':       *(dst++) = '\b'; break; +                        case 'f':       *(dst++) = '\f'; break; +                        case 'n':       *(dst++) = '\n'; break; +                        case 'r':       *(dst++) = '\r'; break; +                        case 't':       *(dst++) = '\t'; break; +                        case 'v':       *(dst++) = '\v'; break; +                        case '\'':      *(dst++) = '\''; break; +                        case '\"':      *(dst++) = '\"'; break; +                        case '\\':      *(dst++) = '\\'; break; +                        case '\?':      *(dst++) = '\?'; break; + +                        case 'x':       val[0] = toupper(src[++i]); +                                        val[1] = toupper(src[++i]); +                                        val[0] = ((val[0]>='A')&&(val[0]<='F')) ? (val[0] - 'A' + 10) : (val[0] - '0'); +                                        val[1] = ((val[1]>='A')&&(val[1]<='F')) ? (val[1] - 'A' + 10) : (val[1] - '0'); +                                        *(dst++) = val[0] * 16 + val[1]; +                                        break; + +                        case '0': +                        case '1': +                        case '2': +                        case '3': +                        case '4': +                        case '5': +                        case '6': +                        case '7':       val[0] = src[  i] - '0'; +                                        val[1] = src[++i] - '0'; +                                        val[2] = src[++i] - '0'; +                                        *(dst++) = val[0] * 64 + val[1] * 8 + val[2]; +                                        break; + +                        default:        *(dst++) = src[i]; break; +                        } +                } +        } + +return(dst - s); +} diff --git a/src/grt/fst/fstapi.h b/src/grt/fst/fstapi.h new file mode 100644 index 000000000..83daac4b0 --- /dev/null +++ b/src/grt/fst/fstapi.h @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2009-2014 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <zlib.h> +#include <inttypes.h> +#include <unistd.h> +#include <time.h> + +#define FST_RDLOAD "FSTLOAD | " + +typedef uint32_t fstHandle; + +enum fstWriterPackType { +    FST_WR_PT_ZLIB             = 0, +    FST_WR_PT_FASTLZ           = 1, +    FST_WR_PT_LZ4              = 2 +}; + +enum fstFileType { +    FST_FT_MIN                 = 0, + +    FST_FT_VERILOG             = 0, +    FST_FT_VHDL                = 1, +    FST_FT_VERILOG_VHDL        = 2, + +    FST_FT_MAX                 = 2 +}; + +enum fstBlockType { +    FST_BL_HDR                 = 0, +    FST_BL_VCDATA              = 1, +    FST_BL_BLACKOUT            = 2, +    FST_BL_GEOM                = 3, +    FST_BL_HIER                = 4, +    FST_BL_VCDATA_DYN_ALIAS    = 5, +    FST_BL_HIER_LZ4            = 6, +    FST_BL_HIER_LZ4DUO         = 7, +    FST_BL_VCDATA_DYN_ALIAS2   = 8, + +    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_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_GENERATE        = 5, +    FST_ST_VCD_STRUCT          = 6, +    FST_ST_VCD_UNION           = 7, +    FST_ST_VCD_CLASS           = 8, +    FST_ST_VCD_INTERFACE       = 9, +    FST_ST_VCD_PACKAGE         = 10, +    FST_ST_VCD_PROGRAM         = 11, + +    FST_ST_VHDL_ARCHITECTURE   = 12, +    FST_ST_VHDL_PROCEDURE      = 13, +    FST_ST_VHDL_FUNCTION       = 14, +    FST_ST_VHDL_RECORD         = 15, +    FST_ST_VHDL_PROCESS        = 16, +    FST_ST_VHDL_BLOCK          = 17, +    FST_ST_VHDL_FOR_GENERATE   = 18, +    FST_ST_VHDL_IF_GENERATE    = 19, +    FST_ST_VHDL_GENERATE       = 20, +    FST_ST_VHDL_PACKAGE        = 21, + +    FST_ST_MAX                 = 21, + +    FST_ST_GEN_ATTRBEGIN       = 252, +    FST_ST_GEN_ATTREND         = 253, + +    FST_ST_VCD_SCOPE           = 254, +    FST_ST_VCD_UPSCOPE         = 255 +}; + +enum fstVarType { +    FST_VT_MIN                 = 0,     /* start of vartypes */ + +    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_SPARRAY         = 19,    /* used to define the rownum (index) port for a sparse array */ +    FST_VT_VCD_REALTIME        = 20, + +    FST_VT_GEN_STRING          = 21,    /* generic string type   (max len is defined dynamically via fstWriterEmitVariableLengthValueChange) */ + +    FST_VT_SV_BIT              = 22, +    FST_VT_SV_LOGIC            = 23, +    FST_VT_SV_INT              = 24,    /* declare as size = 32 */ +    FST_VT_SV_SHORTINT         = 25,    /* declare as size = 16 */ +    FST_VT_SV_LONGINT          = 26,    /* declare as size = 64 */ +    FST_VT_SV_BYTE             = 27,    /* declare as size = 8  */ +    FST_VT_SV_ENUM             = 28,    /* declare as appropriate type range */ +    FST_VT_SV_SHORTREAL        = 29,    /* declare and emit same as FST_VT_VCD_REAL (needs to be emitted as double, not a float) */ + +    FST_VT_MAX                 = 29     /* end of vartypes */ +}; + +enum fstVarDir { +    FST_VD_MIN         = 0, + +    FST_VD_IMPLICIT    = 0, +    FST_VD_INPUT       = 1, +    FST_VD_OUTPUT      = 2, +    FST_VD_INOUT       = 3, +    FST_VD_BUFFER      = 4, +    FST_VD_LINKAGE     = 5, + +    FST_VD_MAX         = 5 +}; + +enum fstHierType { +    FST_HT_MIN         = 0, + +    FST_HT_SCOPE       = 0, +    FST_HT_UPSCOPE     = 1, +    FST_HT_VAR         = 2, +    FST_HT_ATTRBEGIN   = 3, +    FST_HT_ATTREND     = 4, + +    FST_HT_MAX         = 4 +}; + +enum fstAttrType { +    FST_AT_MIN         = 0, + +    FST_AT_MISC        = 0,     /* self-contained: does not need matching FST_HT_ATTREND */ +    FST_AT_ARRAY       = 1, +    FST_AT_ENUM        = 2, +    FST_AT_PACK        = 3, + +    FST_AT_MAX         = 3 +}; + +enum fstMiscType { +    FST_MT_MIN         = 0, + +    FST_MT_COMMENT     = 0,     /* use fstWriterSetComment() to emit */ +    FST_MT_ENVVAR      = 1,     /* use fstWriterSetEnvVar() to emit */ +    FST_MT_SUPVAR      = 2,     /* use fstWriterCreateVar2() to emit */ +    FST_MT_PATHNAME    = 3,     /* reserved for fstWriterSetSourceStem() string -> number management */ +    FST_MT_SOURCESTEM  = 4,     /* use fstWriterSetSourceStem() to emit */ +    FST_MT_SOURCEISTEM = 5,     /* use fstWriterSetSourceInstantiationStem() to emit */ +    FST_MT_UNKNOWN     = 6, + +    FST_MT_MAX         = 6 +}; + +enum fstArrayType { +    FST_AR_MIN         = 0, + +    FST_AR_NONE        = 0, +    FST_AR_UNPACKED    = 1, +    FST_AR_PACKED      = 2, +    FST_AR_SPARSE      = 3, + +    FST_AR_MAX         = 3 +}; + +enum fstEnumValueType { +    FST_EV_SV_INTEGER           = 0, +    FST_EV_SV_BIT               = 1, +    FST_EV_SV_LOGIC             = 2, +    FST_EV_SV_INT               = 3, +    FST_EV_SV_SHORTINT          = 4, +    FST_EV_SV_LONGINT           = 5, +    FST_EV_SV_BYTE              = 6, +    FST_EV_SV_UNSIGNED_INTEGER  = 7, +    FST_EV_SV_UNSIGNED_BIT      = 8, +    FST_EV_SV_UNSIGNED_LOGIC    = 9, +    FST_EV_SV_UNSIGNED_INT      = 10, +    FST_EV_SV_UNSIGNED_SHORTINT = 11, +    FST_EV_SV_UNSIGNED_LONGINT  = 12, +    FST_EV_SV_UNSIGNED_BYTE     = 13, + +    FST_EV_MAX                  = 13 +}; + +enum fstPackType { +    FST_PT_NONE          = 0, +    FST_PT_UNPACKED      = 1, +    FST_PT_PACKED        = 2, +    FST_PT_TAGGED_PACKED = 3, + +    FST_PT_MAX           = 3 +}; + +enum fstSupplementalVarType { +    FST_SVT_MIN                    = 0, + +    FST_SVT_NONE                   = 0, + +    FST_SVT_VHDL_SIGNAL            = 1, +    FST_SVT_VHDL_VARIABLE          = 2, +    FST_SVT_VHDL_CONSTANT          = 3, +    FST_SVT_VHDL_FILE              = 4, +    FST_SVT_VHDL_MEMORY            = 5, + +    FST_SVT_MAX                    = 5, +}; + +enum fstSupplementalDataType { +    FST_SDT_MIN                    = 0, + +    FST_SDT_NONE                   = 0, + +    FST_SDT_VHDL_BOOLEAN           = 1, +    FST_SDT_VHDL_BIT               = 2, +    FST_SDT_VHDL_BIT_VECTOR        = 3, +    FST_SDT_VHDL_STD_ULOGIC        = 4, +    FST_SDT_VHDL_STD_ULOGIC_VECTOR = 5, +    FST_SDT_VHDL_STD_LOGIC         = 6, +    FST_SDT_VHDL_STD_LOGIC_VECTOR  = 7, +    FST_SDT_VHDL_UNSIGNED          = 8, +    FST_SDT_VHDL_SIGNED            = 9, +    FST_SDT_VHDL_INTEGER           = 10, +    FST_SDT_VHDL_REAL              = 11, +    FST_SDT_VHDL_NATURAL           = 12, +    FST_SDT_VHDL_POSITIVE          = 13, +    FST_SDT_VHDL_TIME              = 14, +    FST_SDT_VHDL_CHARACTER         = 15, +    FST_SDT_VHDL_STRING            = 16, + +    FST_SDT_MAX                    = 16, + +    FST_SDT_SVT_SHIFT_COUNT        = 10, /* FST_SVT_* is ORed in by fstWriterCreateVar2() to the left after shifting FST_SDT_SVT_SHIFT_COUNT */ +    FST_SDT_ABS_MAX                = ((1<<(FST_SDT_SVT_SHIFT_COUNT))-1) +}; + + +struct fstHier +{ +unsigned char htyp; + +union { +        /* if htyp == FST_HT_SCOPE */ +        struct fstHierScope { +                unsigned char typ; /* FST_ST_MIN ... FST_ST_MAX */ +                const char *name; +                const char *component; +                uint32_t name_length;           /* strlen(u.scope.name) */ +                uint32_t component_length;      /* strlen(u.scope.component) */ +                } scope; + +        /* if htyp == FST_HT_VAR */ +        struct fstHierVar { +                unsigned char typ; /* FST_VT_MIN ... FST_VT_MAX */ +                unsigned char direction; /* FST_VD_MIN ... FST_VD_MAX */ +                unsigned char svt_workspace; /* zeroed out by FST reader, for client code use */ +                unsigned char sdt_workspace; /* zeroed out by FST reader, for client code use */ +                unsigned int  sxt_workspace; /* zeroed out by FST reader, for client code use */ +                const char *name; +                uint32_t length; +                fstHandle handle; +                uint32_t name_length; /* strlen(u.var.name) */ +                unsigned is_alias : 1; +                } var; + +        /* if htyp == FST_HT_ATTRBEGIN */ +        struct fstHierAttr { +                unsigned char typ; /* FST_AT_MIN ... FST_AT_MAX */ +                unsigned char subtype; /* from fstMiscType, fstArrayType, fstEnumValueType, fstPackType */ +                const char *name; +                uint64_t arg; /* number of array elements, struct members, or some other payload (possibly ignored) */ +                uint64_t arg_from_name; /* for when name is overloaded as a variable-length integer (FST_AT_MISC + FST_MT_SOURCESTEM) */ +                uint32_t name_length; /* strlen(u.attr.name) */ +                } attr; +        } u; +}; + + +/* + * writer functions + */ +void            fstWriterClose(void *ctx); +void *          fstWriterCreate(const char *nam, int use_compressed_hier); +                /* used for Verilog/SV */ +fstHandle       fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir vd, +                        uint32_t len, const char *nam, fstHandle aliasHandle); +                /* future expansion for VHDL and other languages.  The variable type, data type, etc map onto +                   the current Verilog/SV one.  The "type" string is optional for a more verbose or custom description */ +fstHandle       fstWriterCreateVar2(void *ctx, enum fstVarType vt, enum fstVarDir vd, +                        uint32_t len, const char *nam, fstHandle aliasHandle, +                        const char *type, enum fstSupplementalVarType svt, enum fstSupplementalDataType sdt); +void            fstWriterEmitValueChange(void *ctx, fstHandle handle, const void *val); +void            fstWriterEmitVariableLengthValueChange(void *ctx, fstHandle handle, const void *val, uint32_t len); +void            fstWriterEmitDumpActive(void *ctx, int enable); +void            fstWriterEmitTimeChange(void *ctx, uint64_t tim); +void            fstWriterFlushContext(void *ctx); +int             fstWriterGetDumpSizeLimitReached(void *ctx); +int             fstWriterGetFseekFailed(void *ctx); +void            fstWriterSetAttrBegin(void *ctx, enum fstAttrType attrtype, int subtype, +                        const char *attrname, uint64_t arg); +void            fstWriterSetAttrEnd(void *ctx); +void            fstWriterSetComment(void *ctx, const char *comm); +void            fstWriterSetDate(void *ctx, const char *dat); +void            fstWriterSetDumpSizeLimit(void *ctx, uint64_t numbytes); +void            fstWriterSetEnvVar(void *ctx, const char *envvar); +void            fstWriterSetFileType(void *ctx, enum fstFileType filetype); +void            fstWriterSetPackType(void *ctx, enum fstWriterPackType typ); +void            fstWriterSetParallelMode(void *ctx, int enable); +void            fstWriterSetRepackOnClose(void *ctx, int enable);       /* type = 0 (none), 1 (libz) */ +void            fstWriterSetScope(void *ctx, enum fstScopeType scopetype, +                        const char *scopename, const char *scopecomp); +void            fstWriterSetSourceInstantiationStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath); +void            fstWriterSetSourceStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath); +void            fstWriterSetTimescale(void *ctx, int ts); +void            fstWriterSetTimescaleFromString(void *ctx, const char *s); +void            fstWriterSetTimezero(void *ctx, int64_t tim); +void            fstWriterSetUpscope(void *ctx); +void            fstWriterSetVersion(void *ctx, const char *vers); + + +/* + * reader functions + */ +void            fstReaderClose(void *ctx); +void            fstReaderClrFacProcessMask(void *ctx, fstHandle facidx); +void            fstReaderClrFacProcessMaskAll(void *ctx); +uint64_t        fstReaderGetAliasCount(void *ctx); +const char *    fstReaderGetCurrentFlatScope(void *ctx); +void *          fstReaderGetCurrentScopeUserInfo(void *ctx); +int             fstReaderGetCurrentScopeLen(void *ctx); +const char *    fstReaderGetDateString(void *ctx); +int             fstReaderGetDoubleEndianMatchState(void *ctx); +uint64_t        fstReaderGetDumpActivityChangeTime(void *ctx, uint32_t idx); +unsigned char   fstReaderGetDumpActivityChangeValue(void *ctx, uint32_t idx); +uint64_t        fstReaderGetEndTime(void *ctx); +int             fstReaderGetFacProcessMask(void *ctx, fstHandle facidx); +int             fstReaderGetFileType(void *ctx); +int             fstReaderGetFseekFailed(void *ctx); +fstHandle       fstReaderGetMaxHandle(void *ctx); +uint64_t        fstReaderGetMemoryUsedByWriter(void *ctx); +uint32_t        fstReaderGetNumberDumpActivityChanges(void *ctx); +uint64_t        fstReaderGetScopeCount(void *ctx); +uint64_t        fstReaderGetStartTime(void *ctx); +signed char     fstReaderGetTimescale(void *ctx); +int64_t         fstReaderGetTimezero(void *ctx); +uint64_t        fstReaderGetValueChangeSectionCount(void *ctx); +char *          fstReaderGetValueFromHandleAtTime(void *ctx, uint64_t tim, fstHandle facidx, char *buf); +uint64_t        fstReaderGetVarCount(void *ctx); +const char *    fstReaderGetVersionString(void *ctx); +struct fstHier *fstReaderIterateHier(void *ctx); +int             fstReaderIterateHierRewind(void *ctx); +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); +int             fstReaderIterBlocks2(void *ctx, +                        void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value), +                        void (*value_change_callback_varlen)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value, uint32_t len), +                        void *user_callback_data_pointer, FILE *vcdhandle); +void            fstReaderIterBlocksSetNativeDoublesOnCallback(void *ctx, int enable); +void *          fstReaderOpen(const char *nam); +void *          fstReaderOpenForUtilitiesOnly(void); +const char *    fstReaderPopScope(void *ctx); +int             fstReaderProcessHier(void *ctx, FILE *vcdhandle); +const char *    fstReaderPushScope(void *ctx, const char *nam, void *user_info); +void            fstReaderResetScope(void *ctx); +void            fstReaderSetFacProcessMask(void *ctx, fstHandle facidx); +void            fstReaderSetFacProcessMaskAll(void *ctx); +void            fstReaderSetLimitTimeRange(void *ctx, uint64_t start_time, uint64_t end_time); +void            fstReaderSetUnlimitedTimeRange(void *ctx); +void            fstReaderSetVcdExtensions(void *ctx, int enable); + + +/* + * utility functions + */ +int             fstUtilityBinToEsc(unsigned char *d, unsigned char *s, int len); +int             fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/grt/fst/lz4.c b/src/grt/fst/lz4.c new file mode 100644 index 000000000..39f176faf --- /dev/null +++ b/src/grt/fst/lz4.c @@ -0,0 +1,1267 @@ +/* +   LZ4 - Fast LZ compression algorithm +   Copyright (C) 2011-2014, Yann Collet. +   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + +   Redistribution and use in source and binary forms, with or without +   modification, are permitted provided that the following conditions are +   met: + +       * Redistributions of source code must retain the above copyright +   notice, this list of conditions and the following disclaimer. +       * Redistributions in binary form must reproduce the above +   copyright notice, this list of conditions and the following disclaimer +   in the documentation and/or other materials provided with the +   distribution. + +   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +   You can contact the author at : +   - LZ4 source repository : http://code.google.com/p/lz4/ +   - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c +*/ + +/************************************** +   Tuning parameters +**************************************/ +/* + * HEAPMODE : + * Select how default compression functions will allocate memory for their hash table, + * in memory stack (0:default, fastest), or in memory heap (1:requires memory allocation (malloc)). + */ +#define HEAPMODE 0 + + +/************************************** +   CPU Feature Detection +**************************************/ +/* 32 or 64 bits ? */ +#if (defined(__x86_64__) || defined(_M_X64) || defined(_WIN64) \ +  || defined(__64BIT__)  || defined(__mips64) \ +  || defined(__powerpc64__) || defined(__powerpc64le__) \ +  || defined(__ppc64__) || defined(__ppc64le__) \ +  || defined(__PPC64__) || defined(__PPC64LE__) \ +  || defined(__ia64) || defined(__itanium__) || defined(_M_IA64) \ +  || defined(__s390x__) )   /* Detects 64 bits mode */ +#  define LZ4_ARCH64 1 +#else +#  define LZ4_ARCH64 0 +#endif +#define LZ4_32BITS (sizeof(void*)==4) +#define LZ4_64BITS (sizeof(void*)==8) + +/* + * Little Endian or Big Endian ? + * Overwrite the #define below if you know your architecture endianess + */ +#include <stdlib.h>   /* Apparently required to detect endianess */ +#if defined (__GLIBC__) +#  include <endian.h> +#  if (__BYTE_ORDER == __BIG_ENDIAN) +#     define LZ4_BIG_ENDIAN 1 +#  endif +#elif (defined(__BIG_ENDIAN__) || defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN)) && !(defined(__LITTLE_ENDIAN__) || defined(__LITTLE_ENDIAN) || defined(_LITTLE_ENDIAN)) +#  define LZ4_BIG_ENDIAN 1 +#elif defined(__sparc) || defined(__sparc__) \ +   || defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) \ +   || defined(__hpux)  || defined(__hppa) \ +   || defined(_MIPSEB) || defined(__s390__) +#  define LZ4_BIG_ENDIAN 1 +#else +/* Little Endian assumed. PDP Endian and other very rare endian format are unsupported. */ +#endif + +/* + * Unaligned memory access is automatically enabled for "common" CPU, such as x86. + * For others CPU, such as ARM, the compiler may be more cautious, inserting unnecessary extra code to ensure aligned access property + * If you know your target CPU supports unaligned memory access, you want to force this option manually to improve performance + */ +#if defined(__ARM_FEATURE_UNALIGNED) +#  define LZ4_FORCE_UNALIGNED_ACCESS 1 +#endif + +/* Define this parameter if your target system or compiler does not support hardware bit count */ +#if defined(_MSC_VER) && defined(_WIN32_WCE)   /* Visual Studio for Windows CE does not support Hardware bit count */ +#  define LZ4_FORCE_SW_BITCOUNT +#endif + +/* + * BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE : + * This option may provide a small boost to performance for some big endian cpu, although probably modest. + * You may set this option to 1 if data will remain within closed environment. + * This option is useless on Little_Endian CPU (such as x86) + */ + +/* #define BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE 1 */ + + +/************************************** + Compiler Options +**************************************/ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)   /* C99 */ +/* "restrict" is a known keyword */ +#else +#  define restrict /* Disable restrict */ +#endif + +#ifdef _MSC_VER    /* Visual Studio */ +#  define FORCE_INLINE static __forceinline +#  include <intrin.h>                    /* For Visual 2005 */ +#  if LZ4_ARCH64   /* 64-bits */ +#    pragma intrinsic(_BitScanForward64) /* For Visual 2005 */ +#    pragma intrinsic(_BitScanReverse64) /* For Visual 2005 */ +#  else            /* 32-bits */ +#    pragma intrinsic(_BitScanForward)   /* For Visual 2005 */ +#    pragma intrinsic(_BitScanReverse)   /* For Visual 2005 */ +#  endif +#  pragma warning(disable : 4127)        /* disable: C4127: conditional expression is constant */ +#else +#  ifdef __GNUC__ +#    define FORCE_INLINE static inline __attribute__((always_inline)) +#  else +#    define FORCE_INLINE static inline +#  endif +#endif + +#ifdef _MSC_VER  /* Visual Studio */ +#  define lz4_bswap16(x) _byteswap_ushort(x) +#else +#  define lz4_bswap16(x) ((unsigned short int) ((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8))) +#endif + +#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) + +#if (GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__) +#  define expect(expr,value)    (__builtin_expect ((expr),(value)) ) +#else +#  define expect(expr,value)    (expr) +#endif + +#define likely(expr)     expect((expr) != 0, 1) +#define unlikely(expr)   expect((expr) != 0, 0) + + +/************************************** +   Memory routines +**************************************/ +#include <stdlib.h>   /* malloc, calloc, free */ +#define ALLOCATOR(n,s) calloc(n,s) +#define FREEMEM        free +#include <string.h>   /* memset, memcpy */ +#define MEM_INIT       memset + + +/************************************** +   Includes +**************************************/ +#include "lz4.h" + + +/************************************** +   Basic Types +**************************************/ +#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)   /* C99 */ +# include <stdint.h> +  typedef  uint8_t BYTE; +  typedef uint16_t U16; +  typedef uint32_t U32; +  typedef  int32_t S32; +  typedef uint64_t U64; +#else +  typedef unsigned char       BYTE; +  typedef unsigned short      U16; +  typedef unsigned int        U32; +  typedef   signed int        S32; +  typedef unsigned long long  U64; +#endif + +#if defined(__GNUC__)  && !defined(LZ4_FORCE_UNALIGNED_ACCESS) +#  define _PACKED __attribute__ ((packed)) +#else +#  define _PACKED +#endif + +#if !defined(LZ4_FORCE_UNALIGNED_ACCESS) && !defined(__GNUC__) +#  if defined(__IBMC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#    pragma pack(1) +#  else +#    pragma pack(push, 1) +#  endif +#endif + +typedef struct { U16 v; }  _PACKED U16_S; +typedef struct { U32 v; }  _PACKED U32_S; +typedef struct { U64 v; }  _PACKED U64_S; +typedef struct {size_t v;} _PACKED size_t_S; + +#if !defined(LZ4_FORCE_UNALIGNED_ACCESS) && !defined(__GNUC__) +#  if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#    pragma pack(0) +#  else +#    pragma pack(pop) +#  endif +#endif + +#define A16(x)   (((U16_S *)(x))->v) +#define A32(x)   (((U32_S *)(x))->v) +#define A64(x)   (((U64_S *)(x))->v) +#define AARCH(x) (((size_t_S *)(x))->v) + + +/************************************** +   Constants +**************************************/ +#define LZ4_HASHLOG   (LZ4_MEMORY_USAGE-2) +#define HASHTABLESIZE (1 << LZ4_MEMORY_USAGE) +#define HASH_SIZE_U32 (1 << LZ4_HASHLOG) + +#define MINMATCH 4 + +#define COPYLENGTH 8 +#define LASTLITERALS 5 +#define MFLIMIT (COPYLENGTH+MINMATCH) +static const int LZ4_minLength = (MFLIMIT+1); + +#define KB *(1U<<10) +#define MB *(1U<<20) +#define GB *(1U<<30) + +#define LZ4_64KLIMIT ((64 KB) + (MFLIMIT-1)) +#define SKIPSTRENGTH 6   /* Increasing this value will make the compression run slower on incompressible data */ + +#define MAXD_LOG 16 +#define MAX_DISTANCE ((1 << MAXD_LOG) - 1) + +#define ML_BITS  4 +#define ML_MASK  ((1U<<ML_BITS)-1) +#define RUN_BITS (8-ML_BITS) +#define RUN_MASK ((1U<<RUN_BITS)-1) + + +/************************************** +   Structures and local types +**************************************/ +typedef struct { +    U32  hashTable[HASH_SIZE_U32]; +    U32  currentOffset; +    U32  initCheck; +    const BYTE* dictionary; +    const BYTE* bufferStart; +    U32  dictSize; +} LZ4_stream_t_internal; + +typedef enum { notLimited = 0, limitedOutput = 1 } limitedOutput_directive; +typedef enum { byPtr, byU32, byU16 } tableType_t; + +typedef enum { noDict = 0, withPrefix64k, usingExtDict } dict_directive; +typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive; + +typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive; +typedef enum { full = 0, partial = 1 } earlyEnd_directive; + + +/************************************** +   Architecture-specific macros +**************************************/ +#define STEPSIZE                  sizeof(size_t) +#define LZ4_COPYSTEP(d,s)         { AARCH(d) = AARCH(s); d+=STEPSIZE; s+=STEPSIZE; } +#define LZ4_COPY8(d,s)            { LZ4_COPYSTEP(d,s); if (STEPSIZE<8) LZ4_COPYSTEP(d,s); } + +#if (defined(LZ4_BIG_ENDIAN) && !defined(BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE)) +#  define LZ4_READ_LITTLEENDIAN_16(d,s,p) { U16 v = A16(p); v = lz4_bswap16(v); d = (s) - v; } +#  define LZ4_WRITE_LITTLEENDIAN_16(p,i)  { U16 v = (U16)(i); v = lz4_bswap16(v); A16(p) = v; p+=2; } +#else      /* Little Endian */ +#  define LZ4_READ_LITTLEENDIAN_16(d,s,p) { d = (s) - A16(p); } +#  define LZ4_WRITE_LITTLEENDIAN_16(p,v)  { A16(p) = v; p+=2; } +#endif + + +/************************************** +   Macros +**************************************/ +#define LZ4_STATIC_ASSERT(c)    { enum { LZ4_static_assert = 1/(!!(c)) }; }   /* use only *after* variable declarations */ +#if LZ4_ARCH64 || !defined(__GNUC__) +#  define LZ4_WILDCOPY(d,s,e)   { do { LZ4_COPY8(d,s) } while (d<e); }        /* at the end, d>=e; */ +#else +#  define LZ4_WILDCOPY(d,s,e)   { if (likely(e-d <= 8)) LZ4_COPY8(d,s) else do { LZ4_COPY8(d,s) } while (d<e); } +#endif + + +/**************************** +   Private local functions +****************************/ +#if LZ4_ARCH64 + +static int LZ4_NbCommonBytes (register U64 val) +{ +# if defined(LZ4_BIG_ENDIAN) +#   if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) +    unsigned long r = 0; +    _BitScanReverse64( &r, val ); +    return (int)(r>>3); +#   elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) +    return (__builtin_clzll(val) >> 3); +#   else +    int r; +    if (!(val>>32)) { r=4; } else { r=0; val>>=32; } +    if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } +    r += (!val); +    return r; +#   endif +# else +#   if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) +    unsigned long r = 0; +    _BitScanForward64( &r, val ); +    return (int)(r>>3); +#   elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) +    return (__builtin_ctzll(val) >> 3); +#   else +    static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; +    return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; +#   endif +# endif +} + +#else + +static int LZ4_NbCommonBytes (register U32 val) +{ +# if defined(LZ4_BIG_ENDIAN) +#   if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) +    unsigned long r = 0; +    _BitScanReverse( &r, val ); +    return (int)(r>>3); +#   elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) +    return (__builtin_clz(val) >> 3); +#   else +    int r; +    if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } +    r += (!val); +    return r; +#   endif +# else +#   if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) +    unsigned long r; +    _BitScanForward( &r, val ); +    return (int)(r>>3); +#   elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) +    return (__builtin_ctz(val) >> 3); +#   else +    static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; +    return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; +#   endif +# endif +} + +#endif + + +/******************************** +   Compression functions +********************************/ +int LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; } +int LZ4_compressBound(int isize)  { return LZ4_COMPRESSBOUND(isize); } + +static int LZ4_hashSequence(U32 sequence, tableType_t tableType) +{ +    if (tableType == byU16) +        return (((sequence) * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); +    else +        return (((sequence) * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); +} + +static int LZ4_hashPosition(const BYTE* p, tableType_t tableType) { return LZ4_hashSequence(A32(p), tableType); } + +static void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase) +{ +    switch (tableType) +    { +    case byPtr: { const BYTE** hashTable = (const BYTE**) tableBase; hashTable[h] = p; break; } +    case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); break; } +    case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); break; } +    } +} + +static void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) +{ +    U32 h = LZ4_hashPosition(p, tableType); +    LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); +} + +static const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase) +{ +    if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; } +    if (tableType == byU32) { U32* hashTable = (U32*) tableBase; return hashTable[h] + srcBase; } +    { U16* hashTable = (U16*) tableBase; return hashTable[h] + srcBase; }   /* default, to ensure a return */ +} + +static const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) +{ +    U32 h = LZ4_hashPosition(p, tableType); +    return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); +} + +static unsigned LZ4_count(const BYTE* pIn, const BYTE* pRef, const BYTE* pInLimit) +{ +    const BYTE* const pStart = pIn; + +    while (likely(pIn<pInLimit-(STEPSIZE-1))) +    { +        size_t diff = AARCH(pRef) ^ AARCH(pIn); +        if (!diff) { pIn+=STEPSIZE; pRef+=STEPSIZE; continue; } +        pIn += LZ4_NbCommonBytes(diff); +        return (unsigned)(pIn - pStart); +    } +    if (LZ4_64BITS) if ((pIn<(pInLimit-3)) && (A32(pRef) == A32(pIn))) { pIn+=4; pRef+=4; } +    if ((pIn<(pInLimit-1)) && (A16(pRef) == A16(pIn))) { pIn+=2; pRef+=2; } +    if ((pIn<pInLimit) && (*pRef == *pIn)) pIn++; + +    return (unsigned)(pIn - pStart); +} + + +static int LZ4_compress_generic( +                 void* ctx, +                 const char* source, +                 char* dest, +                 int inputSize, +                 int maxOutputSize, + +                 limitedOutput_directive outputLimited, +                 tableType_t tableType, +                 dict_directive dict, +                 dictIssue_directive dictIssue) +{ +    LZ4_stream_t_internal* const dictPtr = (LZ4_stream_t_internal*)ctx; + +    const BYTE* ip = (const BYTE*) source; +    const BYTE* base; +    const BYTE* lowLimit; +    const BYTE* const lowRefLimit = ip - dictPtr->dictSize; +    const BYTE* const dictionary = dictPtr->dictionary; +    const BYTE* const dictEnd = dictionary + dictPtr->dictSize; +    const size_t dictDelta = dictEnd - (const BYTE*)source; +    const BYTE* anchor = (const BYTE*) source; +    const BYTE* const iend = ip + inputSize; +    const BYTE* const mflimit = iend - MFLIMIT; +    const BYTE* const matchlimit = iend - LASTLITERALS; + +    BYTE* op = (BYTE*) dest; +    BYTE* const olimit = op + maxOutputSize; + +    const int skipStrength = SKIPSTRENGTH; +    U32 forwardH; +    size_t refDelta=0; + +    /* Init conditions */ +    if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0;          /* Unsupported input size, too large (or negative) */ +    switch(dict) +    { +    case noDict: +    default: +        base = (const BYTE*)source; +        lowLimit = (const BYTE*)source; +        break; +    case withPrefix64k: +        base = (const BYTE*)source - dictPtr->currentOffset; +        lowLimit = (const BYTE*)source - dictPtr->dictSize; +        break; +    case usingExtDict: +        base = (const BYTE*)source - dictPtr->currentOffset; +        lowLimit = (const BYTE*)source; +        break; +    } +    if ((tableType == byU16) && (inputSize>=(int)LZ4_64KLIMIT)) return 0;   /* Size too large (not within 64K limit) */ +    if (inputSize<LZ4_minLength) goto _last_literals;                       /* Input too small, no compression (all literals) */ + +    /* First Byte */ +    LZ4_putPosition(ip, ctx, tableType, base); +    ip++; forwardH = LZ4_hashPosition(ip, tableType); + +    /* Main Loop */ +    for ( ; ; ) +    { +        const BYTE* ref; +        BYTE* token; +        { +            const BYTE* forwardIp = ip; +            unsigned step=1; +            unsigned searchMatchNb = (1U << skipStrength); + +            /* Find a match */ +            do { +                U32 h = forwardH; +                ip = forwardIp; +                forwardIp += step; +                step = searchMatchNb++ >> skipStrength; + +                if (unlikely(forwardIp > mflimit)) goto _last_literals; + +                ref = LZ4_getPositionOnHash(h, ctx, tableType, base); +                if (dict==usingExtDict) +                { +                    if (ref<(const BYTE*)source) +                    { +                        refDelta = dictDelta; +                        lowLimit = dictionary; +                    } +                    else +                    { +                        refDelta = 0; +                        lowLimit = (const BYTE*)source; +                    } +                } +                forwardH = LZ4_hashPosition(forwardIp, tableType); +                LZ4_putPositionOnHash(ip, h, ctx, tableType, base); + +            } while ( ((dictIssue==dictSmall) ? (ref < lowRefLimit) : 0) +                || ((tableType==byU16) ? 0 : (ref + MAX_DISTANCE < ip)) +                || (A32(ref+refDelta) != A32(ip)) ); +        } + +        /* Catch up */ +        while ((ip>anchor) && (ref+refDelta > lowLimit) && (unlikely(ip[-1]==ref[refDelta-1]))) { ip--; ref--; } + +        { +            /* Encode Literal length */ +            unsigned litLength = (unsigned)(ip - anchor); +            token = op++; +            if ((outputLimited) && (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit))) +                return 0;   /* Check output limit */ +            if (litLength>=RUN_MASK) +            { +                int len = (int)litLength-RUN_MASK; +                *token=(RUN_MASK<<ML_BITS); +                for(; len >= 255 ; len-=255) *op++ = 255; +                *op++ = (BYTE)len; +            } +            else *token = (BYTE)(litLength<<ML_BITS); + +            /* Copy Literals */ +            { BYTE* end = op+litLength; LZ4_WILDCOPY(op,anchor,end); op=end; } +        } + +_next_match: +        /* Encode Offset */ +        LZ4_WRITE_LITTLEENDIAN_16(op, (U16)(ip-ref)); + +        /* Encode MatchLength */ +        { +            unsigned matchLength; + +            if ((dict==usingExtDict) && (lowLimit==dictionary)) +            { +                const BYTE* limit; +                ref += refDelta; +                limit = ip + (dictEnd-ref); +                if (limit > matchlimit) limit = matchlimit; +                matchLength = LZ4_count(ip+MINMATCH, ref+MINMATCH, limit); +                ip += MINMATCH + matchLength; +                if (ip==limit) +                { +                    unsigned more = LZ4_count(ip, (const BYTE*)source, matchlimit); +                    matchLength += more; +                    ip += more; +                } +            } +            else +            { +                matchLength = LZ4_count(ip+MINMATCH, ref+MINMATCH, matchlimit); +                ip += MINMATCH + matchLength; +            } + +            if (matchLength>=ML_MASK) +            { +                if ((outputLimited) && (unlikely(op + (1 + LASTLITERALS) + (matchLength>>8) > olimit))) +                    return 0;    /* Check output limit */ +                *token += ML_MASK; +                matchLength -= ML_MASK; +                for (; matchLength >= 510 ; matchLength-=510) { *op++ = 255; *op++ = 255; } +                if (matchLength >= 255) { matchLength-=255; *op++ = 255; } +                *op++ = (BYTE)matchLength; +            } +            else *token += (BYTE)(matchLength); +        } + +        anchor = ip; + +        /* Test end of chunk */ +        if (ip > mflimit) break; + +        /* Fill table */ +        LZ4_putPosition(ip-2, ctx, tableType, base); + +        /* Test next position */ +        ref = LZ4_getPosition(ip, ctx, tableType, base); +        if (dict==usingExtDict) +        { +            if (ref<(const BYTE*)source) +            { +                refDelta = dictDelta; +                lowLimit = dictionary; +            } +            else +            { +                refDelta = 0; +                lowLimit = (const BYTE*)source; +            } +        } +        LZ4_putPosition(ip, ctx, tableType, base); +        if ( ((dictIssue==dictSmall) ? (ref>=lowRefLimit) : 1) +            && (ref+MAX_DISTANCE>=ip) +            && (A32(ref+refDelta)==A32(ip)) ) +        { token=op++; *token=0; goto _next_match; } + +        /* Prepare next loop */ +        forwardH = LZ4_hashPosition(++ip, tableType); +    } + +_last_literals: +    /* Encode Last Literals */ +    { +        int lastRun = (int)(iend - anchor); +        if ((outputLimited) && (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) +            return 0;   /* Check output limit */ +        if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK<<ML_BITS); lastRun-=RUN_MASK; for(; lastRun >= 255 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; } +        else *op++ = (BYTE)(lastRun<<ML_BITS); +        memcpy(op, anchor, iend - anchor); +        op += iend-anchor; +    } + +    /* End */ +    return (int) (((char*)op)-dest); +} + + +int LZ4_compress(const char* source, char* dest, int inputSize) +{ +#if (HEAPMODE) +    void* ctx = ALLOCATOR(LZ4_STREAMSIZE_U32, 4);   /* Aligned on 4-bytes boundaries */ +#else +    U32 ctx[LZ4_STREAMSIZE_U32] = {0};      /* Ensure data is aligned on 4-bytes boundaries */ +#endif +    int result; + +    if (inputSize < (int)LZ4_64KLIMIT) +        result = LZ4_compress_generic((void*)ctx, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue); +    else +        result = LZ4_compress_generic((void*)ctx, source, dest, inputSize, 0, notLimited, LZ4_64BITS ? byU32 : byPtr, noDict, noDictIssue); + +#if (HEAPMODE) +    FREEMEM(ctx); +#endif +    return result; +} + +int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize) +{ +#if (HEAPMODE) +    void* ctx = ALLOCATOR(LZ4_STREAMSIZE_U32, 4);   /* Aligned on 4-bytes boundaries */ +#else +    U32 ctx[LZ4_STREAMSIZE_U32] = {0};      /* Ensure data is aligned on 4-bytes boundaries */ +#endif +    int result; + +    if (inputSize < (int)LZ4_64KLIMIT) +        result = LZ4_compress_generic((void*)ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue); +    else +        result = LZ4_compress_generic((void*)ctx, source, dest, inputSize, maxOutputSize, limitedOutput, LZ4_64BITS ? byU32 : byPtr, noDict, noDictIssue); + +#if (HEAPMODE) +    FREEMEM(ctx); +#endif +    return result; +} + + +/***************************************** +   Experimental : Streaming functions +*****************************************/ + +/* + * LZ4_initStream + * Use this function once, to init a newly allocated LZ4_stream_t structure + * Return : 1 if OK, 0 if error + */ +void LZ4_resetStream (LZ4_stream_t* LZ4_stream) +{ +    MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t)); +} + +LZ4_stream_t* LZ4_createStream(void) +{ +    LZ4_stream_t* lz4s = (LZ4_stream_t*)ALLOCATOR(4, LZ4_STREAMSIZE_U32); +    LZ4_resetStream(lz4s); +    return lz4s; +} + +int LZ4_freeStream (LZ4_stream_t* LZ4_stream) +{ +    FREEMEM(LZ4_stream); +    return (0); +} + + +int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize) +{ +    LZ4_stream_t_internal* dict = (LZ4_stream_t_internal*) LZ4_dict; +    const BYTE* p = (const BYTE*)dictionary; +    const BYTE* const dictEnd = p + dictSize; +    const BYTE* base; + +    LZ4_STATIC_ASSERT(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal));    /* A compilation error here means LZ4_STREAMSIZE is not large enough */ +    if (dict->initCheck) LZ4_resetStream(LZ4_dict);                         /* Uninitialized structure detected */ + +    if (dictSize < MINMATCH) +    { +        dict->dictionary = NULL; +        dict->dictSize = 0; +        return 1; +    } + +    if (p <= dictEnd - 64 KB) p = dictEnd - 64 KB; +    base = p - dict->currentOffset; +    dict->dictionary = p; +    dict->dictSize = (U32)(dictEnd - p); +    dict->currentOffset += dict->dictSize; + +    while (p <= dictEnd-MINMATCH) +    { +        LZ4_putPosition(p, dict, byU32, base); +        p+=3; +    } + +    return 1; +} + + +static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src) +{ +    if ((LZ4_dict->currentOffset > 0x80000000) || +        ((size_t)LZ4_dict->currentOffset > (size_t)src))   /* address space overflow */ +    { +        /* rescale hash table */ +        U32 delta = LZ4_dict->currentOffset - 64 KB; +        const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize; +        int i; +        for (i=0; i<HASH_SIZE_U32; i++) +        { +            if (LZ4_dict->hashTable[i] < delta) LZ4_dict->hashTable[i]=0; +            else LZ4_dict->hashTable[i] -= delta; +        } +        LZ4_dict->currentOffset = 64 KB; +        if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB; +        LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize; +    } +} + + +FORCE_INLINE int LZ4_compress_continue_generic (void* LZ4_stream, const char* source, char* dest, int inputSize, +                                                int maxOutputSize, limitedOutput_directive limit) +{ +    LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_stream; +    const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; + +    const BYTE* smallest = (const BYTE*) source; +    if (streamPtr->initCheck) return 0;   /* Uninitialized structure detected */ +    if ((streamPtr->dictSize>0) && (smallest>dictEnd)) smallest = dictEnd; +    LZ4_renormDictT(streamPtr, smallest); + +    /* Check overlapping input/dictionary space */ +    { +        const BYTE* sourceEnd = (const BYTE*) source + inputSize; +        if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) +        { +            streamPtr->dictSize = (U32)(dictEnd - sourceEnd); +            if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB; +            if (streamPtr->dictSize < 4) streamPtr->dictSize = 0; +            streamPtr->dictionary = dictEnd - streamPtr->dictSize; +        } +    } + +    /* prefix mode : source data follows dictionary */ +    if (dictEnd == (const BYTE*)source) +    { +        int result; +        if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) +            result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limit, byU32, withPrefix64k, dictSmall); +        else +            result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limit, byU32, withPrefix64k, noDictIssue); +        streamPtr->dictSize += (U32)inputSize; +        streamPtr->currentOffset += (U32)inputSize; +        return result; +    } + +    /* external dictionary mode */ +    { +        int result; +        if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) +            result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limit, byU32, usingExtDict, dictSmall); +        else +            result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limit, byU32, usingExtDict, noDictIssue); +        streamPtr->dictionary = (const BYTE*)source; +        streamPtr->dictSize = (U32)inputSize; +        streamPtr->currentOffset += (U32)inputSize; +        return result; +    } +} + +int LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize) +{ +    return LZ4_compress_continue_generic(LZ4_stream, source, dest, inputSize, 0, notLimited); +} + +int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize) +{ +    return LZ4_compress_continue_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput); +} + + +/* Hidden debug function, to force separate dictionary mode */ +int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int inputSize) +{ +    LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_dict; +    int result; +    const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; + +    const BYTE* smallest = dictEnd; +    if (smallest > (const BYTE*) source) smallest = (const BYTE*) source; +    LZ4_renormDictT((LZ4_stream_t_internal*)LZ4_dict, smallest); + +    result = LZ4_compress_generic(LZ4_dict, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue); + +    streamPtr->dictionary = (const BYTE*)source; +    streamPtr->dictSize = (U32)inputSize; +    streamPtr->currentOffset += (U32)inputSize; + +    return result; +} + + +int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize) +{ +    LZ4_stream_t_internal* dict = (LZ4_stream_t_internal*) LZ4_dict; +    const BYTE* previousDictEnd = dict->dictionary + dict->dictSize; + +    if ((U32)dictSize > 64 KB) dictSize = 64 KB;   /* useless to define a dictionary > 64 KB */ +    if ((U32)dictSize > dict->dictSize) dictSize = dict->dictSize; + +    memmove(safeBuffer, previousDictEnd - dictSize, dictSize); + +    dict->dictionary = (const BYTE*)safeBuffer; +    dict->dictSize = (U32)dictSize; + +    return dictSize; +} + + + +/**************************** +   Decompression functions +****************************/ +/* + * This generic decompression function cover all use cases. + * It shall be instantiated several times, using different sets of directives + * Note that it is essential this generic function is really inlined, + * in order to remove useless branches during compilation optimization. + */ +FORCE_INLINE int LZ4_decompress_generic( +                 const char* source, +                 char* dest, +                 int inputSize, +                 int outputSize,         /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */ + +                 int endOnInput,         /* endOnOutputSize, endOnInputSize */ +                 int partialDecoding,    /* full, partial */ +                 int targetOutputSize,   /* only used if partialDecoding==partial */ +                 int dict,               /* noDict, withPrefix64k, usingExtDict */ +                 const char* dictStart,  /* only if dict==usingExtDict */ +                 int dictSize            /* note : = 0 if noDict */ +                 ) +{ +    /* Local Variables */ +    const BYTE* restrict ip = (const BYTE*) source; +    const BYTE* ref; +    const BYTE* const iend = ip + inputSize; + +    BYTE* op = (BYTE*) dest; +    BYTE* const oend = op + outputSize; +    BYTE* cpy; +    BYTE* oexit = op + targetOutputSize; +    const BYTE* const lowLimit = (const BYTE*)dest - dictSize; + +    const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize; +    const size_t dec32table[] = {4, 1, 2, 1, 4, 4, 4, 4}; +    const size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3}; + +    const int safeDecode = (endOnInput==endOnInputSize); +    const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); + + +    /* Special cases */ +    if ((partialDecoding) && (oexit> oend-MFLIMIT)) oexit = oend-MFLIMIT;                         /* targetOutputSize too high => decode everything */ +    if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1;  /* Empty output buffer */ +    if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1); + + +    /* Main Loop */ +    while (1) +    { +        unsigned token; +        size_t length; + +        /* get runlength */ +        token = *ip++; +        if ((length=(token>>ML_BITS)) == RUN_MASK) +        { +            unsigned s; +            do +            { +                s = *ip++; +                length += s; +            } +            while (likely((endOnInput)?ip<iend-RUN_MASK:1) && (s==255)); +            if ((safeDecode) && LZ4_32BITS && unlikely((size_t)(op+length)<(size_t)(op))) goto _output_error;   /* overflow detection */ +            if ((safeDecode) && LZ4_32BITS && unlikely((size_t)(ip+length)<(size_t)(ip))) goto _output_error;   /* overflow detection */ +        } + +        /* copy literals */ +        cpy = op+length; +        if (((endOnInput) && ((cpy>(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) ) +            || ((!endOnInput) && (cpy>oend-COPYLENGTH))) +        { +            if (partialDecoding) +            { +                if (cpy > oend) goto _output_error;                           /* Error : write attempt beyond end of output buffer */ +                if ((endOnInput) && (ip+length > iend)) goto _output_error;   /* Error : read attempt beyond end of input buffer */ +            } +            else +            { +                if ((!endOnInput) && (cpy != oend)) goto _output_error;       /* Error : block decoding must stop exactly there */ +                if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error;   /* Error : input must be consumed */ +            } +            memcpy(op, ip, length); +            ip += length; +            op += length; +            break;     /* Necessarily EOF, due to parsing restrictions */ +        } +        LZ4_WILDCOPY(op, ip, cpy); ip -= (op-cpy); op = cpy; + +        /* get offset */ +        LZ4_READ_LITTLEENDIAN_16(ref,cpy,ip); ip+=2; +        if ((checkOffset) && (unlikely(ref < lowLimit))) goto _output_error;   /* Error : offset outside destination buffer */ + +        /* get matchlength */ +        if ((length=(token&ML_MASK)) == ML_MASK) +        { +            unsigned s; +            do +            { +                if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error; +                s = *ip++; +                length += s; +            } while (s==255); +            if ((safeDecode) && LZ4_32BITS && unlikely((size_t)(op+length)<(size_t)op)) goto _output_error;   /* overflow detection */ +        } +        length += MINMATCH; + +        /* check external dictionary */ +        if ((dict==usingExtDict) && (ref < (BYTE* const)dest)) +        { +            if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; + +            if (length <= (size_t)(dest-(char*)ref)) +            { +                ref = dictEnd - (dest-(char*)ref); +                memcpy(op, ref, length); +                op += length; +            } +            else +            { +                size_t copySize = (size_t)(dest-(char*)ref); +                memcpy(op, dictEnd - copySize, copySize); +                op += copySize; +                copySize = length - copySize; +                if (copySize > (size_t)((char*)op-dest))   /* overlap */ +                { +                    BYTE* const endOfMatch = op + copySize; +                    const BYTE* copyFrom = (BYTE*)dest; +                    while (op < endOfMatch) *op++ = *copyFrom++; +                } +                else +                { +                    memcpy(op, dest, copySize); +                    op += copySize; +                } +            } +            continue; +        } + +        /* copy repeated sequence */ +        cpy = op + length; +        if (unlikely((op-ref)<(int)STEPSIZE)) +        { +            const size_t dec64 = dec64table[op-ref]; +            op[0] = ref[0]; +            op[1] = ref[1]; +            op[2] = ref[2]; +            op[3] = ref[3]; +            ref += dec32table[op-ref]; +            A32(op+4) = A32(ref); +            op += 8; ref -= dec64; +        } else { LZ4_COPY8(op,ref); } + +        if (unlikely(cpy>oend-12)) +        { +            if (cpy > oend-LASTLITERALS) goto _output_error;    /* Error : last 5 bytes must be literals */ +            if (op<oend-COPYLENGTH) LZ4_WILDCOPY(op, ref, (oend-COPYLENGTH)); +            while(op<cpy) *op++=*ref++; +        } +        else LZ4_WILDCOPY(op, ref, cpy); +        op=cpy;   /* correction */ +    } + +    /* end of decoding */ +    if (endOnInput) +       return (int) (((char*)op)-dest);     /* Nb of output bytes decoded */ +    else +       return (int) (((char*)ip)-source);   /* Nb of input bytes read */ + +    /* Overflow error detected */ +_output_error: +    return (int) (-(((char*)ip)-source))-1; +} + + +int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize) +{ +    return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, NULL, 0); +} + +int LZ4_decompress_safe_partial(const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize) +{ +    return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, partial, targetOutputSize, noDict, NULL, 0); +} + +int LZ4_decompress_fast(const char* source, char* dest, int originalSize) +{ +    return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, NULL, 64 KB); +} + +/* streaming decompression functions */ + +typedef struct +{ +    const char* dictionary; +    int dictSize; +} LZ4_streamDecode_t_internal; + +/* + * If you prefer dynamic allocation methods, + * LZ4_createStreamDecode() + * provides a pointer (void*) towards an initialized LZ4_streamDecode_t structure. + */ +LZ4_streamDecode_t* LZ4_createStreamDecode(void) +{ +    LZ4_streamDecode_t* lz4s = (LZ4_streamDecode_t*) ALLOCATOR(sizeof(U32), LZ4_STREAMDECODESIZE_U32); +    MEM_INIT(lz4s, 0, LZ4_STREAMDECODESIZE); +    return lz4s; +} + +int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream) +{ +    FREEMEM(LZ4_stream); +    return 0; +} + +/* + * LZ4_setStreamDecode + * Use this function to instruct where to find the dictionary + * This function is not necessary if previous data is still available where it was decoded. + * Loading a size of 0 is allowed (same effect as no dictionary). + * Return : 1 if OK, 0 if error + */ +int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize) +{ +    LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode; +    lz4sd->dictionary = dictionary; +    lz4sd->dictSize = dictSize; +    return 1; +} + +/* +*_continue() : +    These decoding functions allow decompression of multiple blocks in "streaming" mode. +    Previously decoded blocks must still be available at the memory position where they were decoded. +    If it's not possible, save the relevant part of decoded data into a safe buffer, +    and indicate where it stands using LZ4_setDictDecode() +*/ +int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize) +{ +    LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode; +    int result; + +    result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, lz4sd->dictionary, lz4sd->dictSize); +    if (result <= 0) return result; +    if (lz4sd->dictionary + lz4sd->dictSize == dest) +    { +        lz4sd->dictSize += result; +    } +    else +    { +        lz4sd->dictionary = dest; +        lz4sd->dictSize = result; +    } + +    return result; +} + +int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize) +{ +    LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode; +    int result; + +    result = LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, usingExtDict, lz4sd->dictionary, lz4sd->dictSize); +    if (result <= 0) return result; +    if (lz4sd->dictionary + lz4sd->dictSize == dest) +    { +        lz4sd->dictSize += result; +    } +    else +    { +        lz4sd->dictionary = dest; +        lz4sd->dictSize = result; +    } + +    return result; +} + + +/* +Advanced decoding functions : +*_usingDict() : +    These decoding functions work the same as "_continue" ones, +    the dictionary must be explicitly provided within parameters +*/ + +FORCE_INLINE int LZ4_decompress_usingDict_generic(const char* source, char* dest, int compressedSize, int maxOutputSize, int safe, const char* dictStart, int dictSize) +{ +    if (dictSize==0) +        return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, NULL, 64 KB); +    if ((dictStart+dictSize == dest) && (dictSize >= (int)(64 KB - 1))) +        return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, NULL, 64 KB); +    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, usingExtDict, dictStart, dictSize); +} + +int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) +{ +    //return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, dictStart, dictSize); +    return LZ4_decompress_usingDict_generic(source, dest, compressedSize, maxOutputSize, 1, dictStart, dictSize); +} + +int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize) +{ +    //return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, usingExtDict, dictStart, dictSize); +    return LZ4_decompress_usingDict_generic(source, dest, 0, originalSize, 0, dictStart, dictSize); +} + +/* debug function */ +int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) +{ +    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, dictStart, dictSize); +} + + +/*************************************************** +    Obsolete Functions +***************************************************/ +/* +These function names are deprecated and should no longer be used. +They are only provided here for compatibility with older user programs. +- LZ4_uncompress is totally equivalent to LZ4_decompress_fast +- LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe +*/ +int LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); } +int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); } + + +/* Obsolete Streaming functions */ + +int LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; } + +static void LZ4_init(LZ4_stream_t_internal* lz4ds, const BYTE* base) +{ +    MEM_INIT(lz4ds, 0, LZ4_STREAMSIZE); +    lz4ds->bufferStart = base; +} + +int LZ4_resetStreamState(void* state, const char* inputBuffer) +{ +    if ((((size_t)state) & 3) != 0) return 1;   /* Error : pointer is not aligned on 4-bytes boundary */ +    LZ4_init((LZ4_stream_t_internal*)state, (const BYTE*)inputBuffer); +    return 0; +} + +void* LZ4_create (const char* inputBuffer) +{ +    void* lz4ds = ALLOCATOR(4, LZ4_STREAMSIZE_U32); +    LZ4_init ((LZ4_stream_t_internal*)lz4ds, (const BYTE*)inputBuffer); +    return lz4ds; +} + +char* LZ4_slideInputBuffer (void* LZ4_Data) +{ +    LZ4_stream_t_internal* lz4ds = (LZ4_stream_t_internal*)LZ4_Data; + +    LZ4_saveDict((LZ4_stream_t*)LZ4_Data, (char*)lz4ds->bufferStart, 64 KB); + +    return (char*)(lz4ds->bufferStart + 64 KB); +} + +/*  Obsolete compresson functions using User-allocated state */ + +int LZ4_sizeofState() { return LZ4_STREAMSIZE; } + +int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize) +{ +    if (((size_t)(state)&3) != 0) return 0;   /* Error : state is not aligned on 4-bytes boundary */ +    MEM_INIT(state, 0, LZ4_STREAMSIZE); + +    if (inputSize < (int)LZ4_64KLIMIT) +        return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue); +    else +        return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, LZ4_64BITS ? byU32 : byPtr, noDict, noDictIssue); +} + +int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize) +{ +    if (((size_t)(state)&3) != 0) return 0;   /* Error : state is not aligned on 4-bytes boundary */ +    MEM_INIT(state, 0, LZ4_STREAMSIZE); + +    if (inputSize < (int)LZ4_64KLIMIT) +        return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue); +    else +        return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, LZ4_64BITS ? byU32 : byPtr, noDict, noDictIssue); +} + +/* Obsolete streaming decompression functions */ + +int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize) +{ +    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, withPrefix64k, NULL, 64 KB); +} + +int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize) +{ +    return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, NULL, 64 KB); +} diff --git a/src/grt/fst/lz4.h b/src/grt/fst/lz4.h new file mode 100644 index 000000000..44ada149e --- /dev/null +++ b/src/grt/fst/lz4.h @@ -0,0 +1,323 @@ +/* +   LZ4 - Fast LZ compression algorithm +   Header File +   Copyright (C) 2011-2014, Yann Collet. +   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + +   Redistribution and use in source and binary forms, with or without +   modification, are permitted provided that the following conditions are +   met: + +       * Redistributions of source code must retain the above copyright +   notice, this list of conditions and the following disclaimer. +       * Redistributions in binary form must reproduce the above +   copyright notice, this list of conditions and the following disclaimer +   in the documentation and/or other materials provided with the +   distribution. + +   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +   You can contact the author at : +   - LZ4 source repository : http://code.google.com/p/lz4/ +   - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c +*/ +#pragma once + +#if defined (__cplusplus) +extern "C" { +#endif + +/* + * lz4.h provides raw compression format functions, for optimal performance and integration into programs. + * If you need to generate data using an inter-operable format (respecting the framing specification), + * please use lz4frame.h instead. +*/ + +/************************************** +   Version +**************************************/ +#define LZ4_VERSION_MAJOR    1    /* for major interface/format changes  */ +#define LZ4_VERSION_MINOR    3    /* for minor interface/format changes  */ +#define LZ4_VERSION_RELEASE  1    /* for tweaks, bug-fixes, or development */ +#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE) +int LZ4_versionNumber (void); + +/************************************** +   Tuning parameter +**************************************/ +/* + * LZ4_MEMORY_USAGE : + * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) + * Increasing memory usage improves compression ratio + * Reduced memory usage can improve speed, due to cache effect + * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache + */ +#define LZ4_MEMORY_USAGE 14 + + +/************************************** +   Simple Functions +**************************************/ + +int LZ4_compress        (const char* source, char* dest, int sourceSize); +int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize); + +/* +LZ4_compress() : +    Compresses 'sourceSize' bytes from 'source' into 'dest'. +    Destination buffer must be already allocated, +    and must be sized to handle worst cases situations (input data not compressible) +    Worst case size evaluation is provided by function LZ4_compressBound() +    inputSize : Max supported value is LZ4_MAX_INPUT_SIZE +    return : the number of bytes written in buffer dest +             or 0 if the compression fails + +LZ4_decompress_safe() : +    compressedSize : is obviously the source size +    maxDecompressedSize : is the size of the destination buffer, which must be already allocated. +    return : the number of bytes decompressed into the destination buffer (necessarily <= maxDecompressedSize) +             If the destination buffer is not large enough, decoding will stop and output an error code (<0). +             If the source stream is detected malformed, the function will stop decoding and return a negative result. +             This function is protected against buffer overflow exploits, +             and never writes outside of output buffer, nor reads outside of input buffer. +             It is also protected against malicious data packets. +*/ + + +/************************************** +   Advanced Functions +**************************************/ +#define LZ4_MAX_INPUT_SIZE        0x7E000000   /* 2 113 929 216 bytes */ +#define LZ4_COMPRESSBOUND(isize)  ((unsigned int)(isize) > (unsigned int)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16) + +/* +LZ4_compressBound() : +    Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible) +    This function is primarily useful for memory allocation purposes (output buffer size). +    Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example). + +    isize  : is the input size. Max supported value is LZ4_MAX_INPUT_SIZE +    return : maximum output size in a "worst case" scenario +             or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE) +*/ +int LZ4_compressBound(int isize); + + +/* +LZ4_compress_limitedOutput() : +    Compress 'sourceSize' bytes from 'source' into an output buffer 'dest' of maximum size 'maxOutputSize'. +    If it cannot achieve it, compression will stop, and result of the function will be zero. +    This saves time and memory on detecting non-compressible (or barely compressible) data. +    This function never writes outside of provided output buffer. + +    sourceSize  : Max supported value is LZ4_MAX_INPUT_VALUE +    maxOutputSize : is the size of the destination buffer (which must be already allocated) +    return : the number of bytes written in buffer 'dest' +             or 0 if compression fails +*/ +int LZ4_compress_limitedOutput (const char* source, char* dest, int sourceSize, int maxOutputSize); + + +/* +LZ4_compress_withState() : +    Same compression functions, but using an externally allocated memory space to store compression state. +    Use LZ4_sizeofState() to know how much memory must be allocated, +    and then, provide it as 'void* state' to compression functions. +*/ +int LZ4_sizeofState(void); +int LZ4_compress_withState               (void* state, const char* source, char* dest, int inputSize); +int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize); + + +/* +LZ4_decompress_fast() : +    originalSize : is the original and therefore uncompressed size +    return : the number of bytes read from the source buffer (in other words, the compressed size) +             If the source stream is detected malformed, the function will stop decoding and return a negative result. +             Destination buffer must be already allocated. Its size must be a minimum of 'originalSize' bytes. +    note : This function fully respect memory boundaries for properly formed compressed data. +           It is a bit faster than LZ4_decompress_safe(). +           However, it does not provide any protection against intentionally modified data stream (malicious input). +           Use this function in trusted environment only (data to decode comes from a trusted source). +*/ +int LZ4_decompress_fast (const char* source, char* dest, int originalSize); + + +/* +LZ4_decompress_safe_partial() : +    This function decompress a compressed block of size 'compressedSize' at position 'source' +    into destination buffer 'dest' of size 'maxDecompressedSize'. +    The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached, +    reducing decompression time. +    return : the number of bytes decoded in the destination buffer (necessarily <= maxDecompressedSize) +       Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller. +             Always control how many bytes were decoded. +             If the source stream is detected malformed, the function will stop decoding and return a negative result. +             This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets +*/ +int LZ4_decompress_safe_partial (const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize); + + +/*********************************************** +   Experimental Streaming Compression Functions +***********************************************/ + +#define LZ4_STREAMSIZE_U32 ((1 << (LZ4_MEMORY_USAGE-2)) + 8) +#define LZ4_STREAMSIZE     (LZ4_STREAMSIZE_U32 * sizeof(unsigned int)) +/* + * LZ4_stream_t + * information structure to track an LZ4 stream. + * important : init this structure content before first use ! + */ +typedef struct { unsigned int table[LZ4_STREAMSIZE_U32]; } LZ4_stream_t; + +/* + * LZ4_resetStream + * Use this function to init an allocated LZ4_stream_t structure + */ +void LZ4_resetStream (LZ4_stream_t* LZ4_streamPtr); + +/* + * If you prefer dynamic allocation methods, + * LZ4_createStream will allocate and initialize an LZ4_stream_t structure + * LZ4_freeStream releases its memory. + */ +LZ4_stream_t* LZ4_createStream(void); +int           LZ4_freeStream (LZ4_stream_t* LZ4_stream); + +/* + * LZ4_loadDict + * Use this function to load a static dictionary into LZ4_stream. + * Any previous data will be forgotten, only 'dictionary' will remain in memory. + * Loading a size of 0 is allowed. + * Return : 1 if OK, 0 if error + */ +int LZ4_loadDict (LZ4_stream_t* LZ4_stream, const char* dictionary, int dictSize); + +/* + * LZ4_compress_continue + * Compress data block 'source', using blocks compressed before as dictionary to improve compression ratio + * Previous data blocks are assumed to still be present at their previous location. + */ +int LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize); + +/* + * LZ4_compress_limitedOutput_continue + * Same as before, but also specify a maximum target compressed size (maxOutputSize) + * If objective cannot be met, compression exits, and returns a zero. + */ +int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize); + +/* + * LZ4_saveDict + * If previously compressed data block is not guaranteed to remain available at its memory location + * save it into a safer place (char* safeBuffer) + * Note : you don't need to call LZ4_loadDict() afterwards, + *        dictionary is immediately usable, you can therefore call again LZ4_compress_continue() + * Return : dictionary size in bytes, or 0 if error + * Note : any dictSize > 64 KB will be interpreted as 64KB. + */ +int LZ4_saveDict (LZ4_stream_t* LZ4_stream, char* safeBuffer, int dictSize); + + +/************************************************ +  Experimental Streaming Decompression Functions +************************************************/ + +#define LZ4_STREAMDECODESIZE_U32 4 +#define LZ4_STREAMDECODESIZE     (LZ4_STREAMDECODESIZE_U32 * sizeof(unsigned int)) +/* + * LZ4_streamDecode_t + * information structure to track an LZ4 stream. + * important : init this structure content using LZ4_setStreamDecode or memset() before first use ! + */ +typedef struct { unsigned int table[LZ4_STREAMDECODESIZE_U32]; } LZ4_streamDecode_t; + +/* + * LZ4_setStreamDecode + * Use this function to instruct where to find the dictionary. + * This function can be used to specify a static dictionary, + * or to instruct where to find some previously decoded data saved into a different memory space. + * Setting a size of 0 is allowed (same effect as no dictionary). + * Return : 1 if OK, 0 if error + */ +int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize); + +/* + * If you prefer dynamic allocation methods, + * LZ4_createStreamDecode will allocate and initialize an LZ4_streamDecode_t structure + * LZ4_freeStreamDecode releases its memory. + */ +LZ4_streamDecode_t* LZ4_createStreamDecode(void); +int                 LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream); + +/* +*_continue() : +    These decoding functions allow decompression of multiple blocks in "streaming" mode. +    Previously decoded blocks must still be available at the memory position where they were decoded. +    If it's not possible, save the relevant part of decoded data into a safe buffer, +    and indicate where its new address using LZ4_setStreamDecode() +*/ +int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxDecompressedSize); +int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize); + + +/* +Advanced decoding functions : +*_usingDict() : +    These decoding functions work the same as +    a combination of LZ4_setDictDecode() followed by LZ4_decompress_x_continue() +    They don't use nor update an LZ4_streamDecode_t structure. +*/ +int LZ4_decompress_safe_usingDict (const char* source, char* dest, int compressedSize, int maxDecompressedSize, const char* dictStart, int dictSize); +int LZ4_decompress_fast_usingDict (const char* source, char* dest, int originalSize, const char* dictStart, int dictSize); + + + +/************************************** +   Obsolete Functions +**************************************/ +/* +Obsolete decompression functions +These function names are deprecated and should no longer be used. +They are only provided here for compatibility with older user programs. +- LZ4_uncompress is the same as LZ4_decompress_fast +- LZ4_uncompress_unknownOutputSize is the same as LZ4_decompress_safe +These function prototypes are now disabled; uncomment them if you really need them. +It is highly recommended to stop using these functions and migrated to newer ones */ +/* int LZ4_uncompress (const char* source, char* dest, int outputSize); */ +/* int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); */ + +/* + * If you prefer dynamic allocation methods, + * LZ4_createStreamDecode() + * provides a pointer (void*) towards an initialized LZ4_streamDecode_t structure. + * LZ4_free just frees it. + */ +/* void* LZ4_createStreamDecode(void); */ +/*int   LZ4_free (void* LZ4_stream);    yes, it's the same one as for compression */ + +/* Obsolete streaming functions; use new streaming interface whenever possible */ +void* LZ4_create (const char* inputBuffer); +int   LZ4_sizeofStreamState(void); +int   LZ4_resetStreamState(void* state, const char* inputBuffer); +char* LZ4_slideInputBuffer (void* state); + +/* Obsolete streaming decoding functions */ +int LZ4_decompress_safe_withPrefix64k (const char* source, char* dest, int compressedSize, int maxOutputSize); +int LZ4_decompress_fast_withPrefix64k (const char* source, char* dest, int originalSize); + + +#if defined (__cplusplus) +} +#endif diff --git a/src/grt/grt-fst.adb b/src/grt/grt-fst.adb new file mode 100644 index 000000000..bd7b9a940 --- /dev/null +++ b/src/grt/grt-fst.adb @@ -0,0 +1,474 @@ +--  GHDL Run Time (GRT) - FST generator. +--  Copyright (C) 2014 Tristan Gingold +-- +--  GHDL is free software; you can redistribute it and/or modify it under +--  the terms of the GNU General Public License as published by the Free +--  Software Foundation; either version 2, or (at your option) any later +--  version. +-- +--  GHDL 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 GCC; see the file COPYING.  If not, write to the Free +--  Software Foundation, 59 Temple Place - Suite 330, Boston, MA +--  02111-1307, USA. +-- +--  As a special exception, if other files instantiate generics from this +--  unit, or you link this unit with other files to produce an executable, +--  this unit does not by itself cause the resulting executable to be +--  covered by the GNU General Public License. This exception does not +--  however invalidate any other reasons why the executable file might be +--  covered by the GNU Public License. +with Interfaces; use Interfaces; +with Interfaces.C; +with System; use System; +with Grt.Types; use Grt.Types; +with Grt.Fst_Api; use Grt.Fst_Api; +with Grt.Vcd; use Grt.Vcd; +with Grt.Avhpi; use Grt.Avhpi; +with System.Storage_Elements; --  Work around GNAT bug. +pragma Unreferenced (System.Storage_Elements); +with Grt.Errors; use Grt.Errors; +with Grt.Signals; use Grt.Signals; +with Grt.Table; +with Grt.Astdio; use Grt.Astdio; +with Grt.Hooks; use Grt.Hooks; +with Grt.Rtis; use Grt.Rtis; +with Grt.Rtis_Types; use Grt.Rtis_Types; +with Grt.Vstrings; +pragma Elaborate_All (Grt.Table); + +package body Grt.Fst is +   Context : fstContext := Null_fstContext; + +   --  Index type of the table of vcd variables to dump. +   type Fst_Index_Type is new Integer; + +   --  Return TRUE if OPT is an option for FST. +   function Fst_Option (Opt : String) return Boolean +   is +      F : constant Natural := Opt'First; +      Fst_Filename : String_Access; +   begin +      if Opt'Length < 6 or else Opt (F .. F + 5) /= "--fst=" then +         return False; +      end if; +      if Context /= Null_fstContext then +         Error ("--fst: file already set"); +         return True; +      end if; + +      --  Add an extra NUL character. +      Fst_Filename := new String (1 .. Opt'Length - 6 + 1); +      Fst_Filename (1 .. Opt'Length - 6) := Opt (F + 6 .. Opt'Last); +      Fst_Filename (Fst_Filename'Last) := NUL; + +      Context := fstWriterCreate +        (To_Ghdl_C_String (Fst_Filename.all'Address), 1); +      if Context = Null_fstContext then +         Error_C ("fst: cannot open "); +         Error_E (Fst_Filename (Fst_Filename'First .. Fst_Filename'Last - 1)); +      end if; +      return True; +   end Fst_Option; + +   procedure Fst_Help is +   begin +      Put_Line (" --fst=FILENAME     dump signal values into an FST file"); +   end Fst_Help; + +   --  Called before elaboration. +   procedure Fst_Init +   is +      Version : constant String := "GHDL FST v0" & NUL; +   begin +      if Context = Null_fstContext then +         return; +      end if; + +      fstWriterSetFileType (Context, FST_FT_VHDL); +      fstWriterSetPackType (Context, FST_WR_PT_LZ4); +      fstWriterSetTimescale (Context, -15); --  fs +      fstWriterSetVersion (Context, To_Ghdl_C_String (Version'Address)); +      fstWriterSetRepackOnClose (Context, 1); +      fstWriterSetParallelMode (Context, 0); +   end Fst_Init; + +   type Fst_Sig_Info is record +      Wire : Verilog_Wire_Info; +      Hand : fstHandle; +   end record; + +   package Fst_Table is new Grt.Table +     (Table_Component_Type => Fst_Sig_Info, +      Table_Index_Type => Fst_Index_Type, +      Table_Low_Bound => 0, +      Table_Initial => 32); + +   procedure Avhpi_Error (Err : AvhpiErrorT) +   is +      pragma Unreferenced (Err); +   begin +      Put_Line ("Fst.Avhpi_Error!"); +   end Avhpi_Error; + +   procedure Fst_Add_Signal (Sig : VhpiHandleT) +   is +      Vcd_El : Verilog_Wire_Info; +      Vt : fstVarType; +      Sdt : fstSupplementalDataType; +      Dir : fstVarDir; +      Len : Interfaces.C.unsigned; +      Name : String (1 .. 128); +      Name_Len : Natural; +      Hand : fstHandle; +   begin +      Get_Verilog_Wire (Sig, Vcd_El); + +      if Vcd_El.Kind = Vcd_Bad then +         --  Not handled. +         return; +      end if; + + +      case Vcd_El.Kind is +         when Vcd_Bad => +            raise Program_Error; +         when Vcd_Bool => +            Vt := FST_VT_VCD_REG; +            Len := 1; +            Sdt := FST_SDT_VHDL_BOOLEAN; +         when Vcd_Integer32 => +            Vt := FST_VT_VCD_INTEGER; +            Len := 1; +            Sdt := FST_SDT_VHDL_INTEGER; +         when Vcd_Float64 => +            Vt := FST_VT_VCD_REAL; +            Len := 1; +            Sdt := FST_SDT_VHDL_REAL; +         when Vcd_Bit => +            Vt := FST_VT_VCD_REG; +            Len := 1; +            Sdt := FST_SDT_VHDL_BIT; +         when Vcd_Stdlogic => +            Vt := FST_VT_VCD_REG; +            Len := 1; +            Sdt := FST_SDT_VHDL_STD_LOGIC; +         when Vcd_Bitvector => +            Vt := FST_VT_VCD_REG; +            Len := Interfaces.C.unsigned (Vcd_El.Irange.I32.Len); +            Sdt := FST_SDT_VHDL_BIT_VECTOR; +         when Vcd_Stdlogic_Vector => +            Vt := FST_VT_VCD_REG; +            Len := Interfaces.C.unsigned (Vcd_El.Irange.I32.Len); +            Sdt := FST_SDT_VHDL_STD_LOGIC_VECTOR; +      end case; + +      if Vhpi_Get_Kind (Sig) = VhpiPortDeclK then +         case Vhpi_Get_Mode (Sig) is +            when VhpiInMode => +               Dir := FST_VD_INPUT; +            when VhpiInoutMode => +               Dir := FST_VD_INOUT; +            when VhpiBufferMode => +               Dir := FST_VD_BUFFER; +            when VhpiLinkageMode => +               Dir := FST_VD_LINKAGE; +            when VhpiOutMode => +               Dir := FST_VD_OUTPUT; +            when VhpiErrorMode => +               Dir := FST_VD_IMPLICIT; +         end case; +      else +         Dir := FST_VD_IMPLICIT; +      end if; + +      Vhpi_Get_Str (VhpiNameP, Sig, Name, Name_Len); +      if Name_Len >= Name'Length +        or else Vcd_El.Irange /= null +      then +         declare +            Name2 : String (1 .. Name_Len + 3 + 2 * 11 + 1); + +            procedure Append (N : Ghdl_I32) +            is +               Num : String (1 .. 11); +               Num_First : Natural; +               Num_Len : Natural; +            begin +               Grt.Vstrings.To_String (Num, Num_First, N); +               Num_Len := Num'Last - Num_First + 1; +               Name2 (Name_Len + 1 .. Name_Len + Num_Len) := +                 Num (Num_First .. Num'Last); +               Name_Len := Name_Len + Num_Len; +            end Append; +         begin +            Vhpi_Get_Str (VhpiNameP, Sig, Name2, Name_Len); +            if Vcd_El.Irange /= null then +               Name2 (Name_Len + 1) := '['; +               Name_Len := Name_Len + 1; +               Append (Vcd_El.Irange.I32.Left); +               Name2 (Name_Len + 1) := ':'; +               Name_Len := Name_Len + 1; +               Append (Vcd_El.Irange.I32.Right); +               Name2 (Name_Len + 1) := ']'; +               Name_Len := Name_Len + 1; +            end if; +            Name2 (Name_Len + 1) := NUL; +            Name_Len := Name_Len + 1; + +            Hand := fstWriterCreateVar2 +              (Context, Vt, Dir, Len, To_Ghdl_C_String (Name2'Address), +               Null_fstHandle, null, FST_SVT_VHDL_SIGNAL, Sdt); +         end; +      else +         Name (Name_Len) := NUL; +         Hand := fstWriterCreateVar2 +           (Context, Vt, Dir, Len, To_Ghdl_C_String (Name'Address), +            Null_fstHandle, null, FST_SVT_VHDL_SIGNAL, Sdt); +      end if; + +      Fst_Table.Append (Fst_Sig_Info'(Wire => Vcd_El, Hand => Hand)); +   end Fst_Add_Signal; + +   procedure Fst_Put_Hierarchy (Inst : VhpiHandleT); + +   procedure Fst_Put_Scope (Scope : fstScopeType; Decl : VhpiHandleT) +   is +      Name : String (1 .. 128); +      Name_Len : Integer; +   begin +      Vhpi_Get_Str (VhpiNameP, Decl, Name, Name_Len); +      if Name_Len < Name'Last then +         Name (Name_Len + 1) := NUL; +      else +         --  Truncate +         Name (Name'Last) := NUL; +      end if; + +      fstWriterSetScope +        (Context, Scope, To_Ghdl_C_String (Name'Address), null); +      Fst_Put_Hierarchy (Decl); +      fstWriterSetUpscope (Context); +   end Fst_Put_Scope; + +   procedure Fst_Put_Hierarchy (Inst : VhpiHandleT) +   is +      Decl_It : VhpiHandleT; +      Decl : VhpiHandleT; +      Error : AvhpiErrorT; +   begin +      Vhpi_Iterator (VhpiDecls, Inst, Decl_It, Error); +      if Error /= AvhpiErrorOk then +         Avhpi_Error (Error); +         return; +      end if; + +      --  Extract signals. +      loop +         Vhpi_Scan (Decl_It, Decl, Error); +         exit when Error = AvhpiErrorIteratorEnd; +         if Error /= AvhpiErrorOk then +            Avhpi_Error (Error); +            return; +         end if; + +         case Vhpi_Get_Kind (Decl) is +            when VhpiPortDeclK +              | VhpiSigDeclK => +               Fst_Add_Signal (Decl); +            when others => +               null; +         end case; +      end loop; + +      --  Extract sub-scopes. +      Vhpi_Iterator (VhpiInternalRegions, Inst, Decl_It, Error); +      if Error /= AvhpiErrorOk then +         Avhpi_Error (Error); +         return; +      end if; + +      loop +         Vhpi_Scan (Decl_It, Decl, Error); +         exit when Error = AvhpiErrorIteratorEnd; +         if Error /= AvhpiErrorOk then +            Avhpi_Error (Error); +            return; +         end if; + +         case Vhpi_Get_Kind (Decl) is +            when VhpiIfGenerateK => +               Fst_Put_Scope (FST_ST_VHDL_IF_GENERATE, Decl); +            when VhpiForGenerateK => +               Fst_Put_Scope (FST_ST_VHDL_FOR_GENERATE, Decl); +            when  VhpiBlockStmtK => +               Fst_Put_Scope (FST_ST_VHDL_BLOCK, Decl); +            when VhpiCompInstStmtK => +               Fst_Put_Scope (FST_ST_VHDL_ARCHITECTURE, Decl); +            when others => +               null; +         end case; +      end loop; +   end Fst_Put_Hierarchy; + +   procedure Fst_Put_Integer32 (Hand : fstHandle; V : Ghdl_U32) +   is +      Str : String (1 .. 32); +      Val : Ghdl_U32; +   begin +      Val := V; +      for I in Str'Range loop +         Str (I) := Character'Val (Character'Pos ('0') + (Val and 1)); +         Val := Val / 2; +      end loop; +      fstWriterEmitValueChange (Context, Hand, Str'Address); +   end Fst_Put_Integer32; + +   procedure Fst_Put_Var (I : Fst_Index_Type) +   is +      From_Bit : constant array (Ghdl_B1) of Character := "01"; +      type Map_Type is array (Ghdl_E8 range 0 .. 8) of Character; +      From_Std : constant Map_Type := "UX01ZWLH-"; +      Sig : Signal_Arr_Ptr; +      V : Fst_Sig_Info renames Fst_Table.Table (I); +      Len : Ghdl_Index_Type; +      Hand : constant fstHandle := V.Hand; +   begin +      Sig := To_Signal_Arr_Ptr (V.Wire.Addr); +      if V.Wire.Irange = null then +         Len := 1; +      else +         Len := V.Wire.Irange.I32.Len; +      end if; +      case V.Wire.Val is +         when Vcd_Effective => +            case V.Wire.Kind is +               when Vcd_Bit +                 | Vcd_Bool +                 | Vcd_Bitvector => +                  declare +                     Str : Std_String_Uncons (0 .. Len - 1); +                  begin +                     for I in Str'Range loop +                        Str (I) := From_Bit (Sig (I).Value.B1); +                     end loop; +                     fstWriterEmitValueChange (Context, Hand, Str'Address); +                  end; +               when Vcd_Stdlogic +                 | Vcd_Stdlogic_Vector => +                  declare +                     Str : Std_String_Uncons (0 .. Len - 1); +                  begin +                     for I in Str'Range loop +                        Str (I) := From_Std (Sig (I).Value.E8); +                     end loop; +                     fstWriterEmitValueChange (Context, Hand, Str'Address); +                  end; +               when Vcd_Integer32 => +                  Fst_Put_Integer32 (Hand, Sig (0).Value.E32); +               when Vcd_Float64 => +                  null; +               when Vcd_Bad => +                  null; +            end case; +         when Vcd_Driving => +            case V.Wire.Kind is +               when Vcd_Bit +                 | Vcd_Bool +                 | Vcd_Bitvector => +                  declare +                     Str : Std_String_Uncons (0 .. Len - 1); +                  begin +                     for I in Str'Range loop +                        Str (I) := From_Bit (Sig (I).Driving_Value.B1); +                     end loop; +                     fstWriterEmitValueChange (Context, Hand, Str'Address); +                  end; +               when Vcd_Stdlogic +                 | Vcd_Stdlogic_Vector => +                  declare +                     Str : Std_String_Uncons (0 .. Len - 1); +                  begin +                     for I in Str'Range loop +                        Str (I) := From_Std (Sig (I).Driving_Value.E8); +                     end loop; +                     fstWriterEmitValueChange (Context, Hand, Str'Address); +                  end; +               when Vcd_Integer32 => +                  Fst_Put_Integer32 (Hand, Sig (0).Driving_Value.E32); +               when Vcd_Float64 => +                  null; +               when Vcd_Bad => +                  null; +            end case; +      end case; +   end Fst_Put_Var; + +   procedure Fst_Cycle; + +   --  Called after elaboration. +   procedure Fst_Start +   is +      Root : VhpiHandleT; +   begin +      --  Do nothing if there is no VCD file to generate. +      if Context = Null_fstContext then +         return; +      end if; + +      --  Be sure the RTI of std_ulogic is set. +      Search_Types_RTI; + +      --  Put hierarchy. +      Get_Root_Inst (Root); +      Fst_Put_Hierarchy (Root); + +      Register_Cycle_Hook (Fst_Cycle'Access); +   end Fst_Start; + +   --  Called before each non delta cycle. +   procedure Fst_Cycle is +   begin +      --  Disp values. +      fstWriterEmitTimeChange (Context, Unsigned_64 (Cycle_Time)); + +      if Cycle_Time = 0 then +         --  Disp all values. +         for I in Fst_Table.First .. Fst_Table.Last loop +            Fst_Put_Var (I); +         end loop; +      else +         --  Disp only values changed. +         for I in Fst_Table.First .. Fst_Table.Last loop +            if Verilog_Wire_Changed (Fst_Table.Table (I).Wire, Cycle_Time) then +               Fst_Put_Var (I); +            end if; +         end loop; +      end if; +   end Fst_Cycle; + +   --  Called at the end of the simulation. +   procedure Fst_End is +   begin +      if Context /= Null_fstContext then +         fstWriterClose (Context); +         Context := Null_fstContext; +      end if; +   end Fst_End; + +   Fst_Hooks : aliased constant Hooks_Type := +     (Option => Fst_Option'Access, +      Help => Fst_Help'Access, +      Init => Fst_Init'Access, +      Start => Fst_Start'Access, +      Finish => Fst_End'Access); + +   procedure Register is +   begin +      Register_Hooks (Fst_Hooks'Access); +   end Register; +end Grt.Fst; diff --git a/src/grt/grt-fst.ads b/src/grt/grt-fst.ads new file mode 100644 index 000000000..81b6abd97 --- /dev/null +++ b/src/grt/grt-fst.ads @@ -0,0 +1,28 @@ +--  GHDL Run Time (GRT) - FST generator. +--  Copyright (C) 2014 Tristan Gingold +-- +--  GHDL is free software; you can redistribute it and/or modify it under +--  the terms of the GNU General Public License as published by the Free +--  Software Foundation; either version 2, or (at your option) any later +--  version. +-- +--  GHDL 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 GCC; see the file COPYING.  If not, write to the Free +--  Software Foundation, 59 Temple Place - Suite 330, Boston, MA +--  02111-1307, USA. +-- +--  As a special exception, if other files instantiate generics from this +--  unit, or you link this unit with other files to produce an executable, +--  this unit does not by itself cause the resulting executable to be +--  covered by the GNU General Public License. This exception does not +--  however invalidate any other reasons why the executable file might be +--  covered by the GNU Public License. + +package Grt.Fst is +   procedure Register; +end Grt.Fst; diff --git a/src/grt/grt-fst_api.ads b/src/grt/grt-fst_api.ads new file mode 100644 index 000000000..ba0ec0c5d --- /dev/null +++ b/src/grt/grt-fst_api.ads @@ -0,0 +1,353 @@ +with Interfaces; use Interfaces; +with Interfaces.C; use Interfaces.C; +with System; +with Grt.Types; use Grt.Types; + +package Grt.Fst_Api is + +   subtype fstHandle is unsigned; +   Null_fstHandle : constant fstHandle := 0; + +   type fstWriterPackType is +     (FST_WR_PT_ZLIB, +      FST_WR_PT_FASTLZ, +      FST_WR_PT_LZ4); +   pragma Convention (C, fstWriterPackType); + +   subtype fstFileType is unsigned; +   FST_FT_MIN          : constant fstFileType := 0; +   FST_FT_VERILOG      : constant fstFileType := 0; +   FST_FT_VHDL         : constant fstFileType := 1; +   FST_FT_VERILOG_VHDL : constant fstFileType := 2; +   FST_FT_MAX          : constant fstFileType := 2; + +   subtype fstBlockType is unsigned; +   FST_BL_HDR               : constant fstBlockType := 0; +   FST_BL_VCDATA            : constant fstBlockType := 1; +   FST_BL_BLACKOUT          : constant fstBlockType := 2; +   FST_BL_GEOM              : constant fstBlockType := 3; +   FST_BL_HIER              : constant fstBlockType := 4; +   FST_BL_VCDATA_DYN_ALIAS  : constant fstBlockType := 5; +   FST_BL_HIER_LZ4          : constant fstBlockType := 6; +   FST_BL_HIER_LZ4DUO       : constant fstBlockType := 7; +   FST_BL_VCDATA_DYN_ALIAS2 : constant fstBlockType := 8; +   FST_BL_ZWRAPPER          : constant fstBlockType := 254; +   FST_BL_SKIP              : constant fstBlockType := 255; + +   subtype fstScopeType is unsigned; +   FST_ST_MIN               : constant fstScopeType := 0; +   FST_ST_VCD_MODULE        : constant fstScopeType := 0; +   FST_ST_VCD_TASK          : constant fstScopeType := 1; +   FST_ST_VCD_FUNCTION      : constant fstScopeType := 2; +   FST_ST_VCD_BEGIN         : constant fstScopeType := 3; +   FST_ST_VCD_FORK          : constant fstScopeType := 4; +   FST_ST_VCD_GENERATE      : constant fstScopeType := 5; +   FST_ST_VCD_STRUCT        : constant fstScopeType := 6; +   FST_ST_VCD_UNION         : constant fstScopeType := 7; +   FST_ST_VCD_CLASS         : constant fstScopeType := 8; +   FST_ST_VCD_INTERFACE     : constant fstScopeType := 9; +   FST_ST_VCD_PACKAGE       : constant fstScopeType := 10; +   FST_ST_VCD_PROGRAM       : constant fstScopeType := 11; +   FST_ST_VHDL_ARCHITECTURE : constant fstScopeType := 12; +   FST_ST_VHDL_PROCEDURE    : constant fstScopeType := 13; +   FST_ST_VHDL_FUNCTION     : constant fstScopeType := 14; +   FST_ST_VHDL_RECORD       : constant fstScopeType := 15; +   FST_ST_VHDL_PROCESS      : constant fstScopeType := 16; +   FST_ST_VHDL_BLOCK        : constant fstScopeType := 17; +   FST_ST_VHDL_FOR_GENERATE : constant fstScopeType := 18; +   FST_ST_VHDL_IF_GENERATE  : constant fstScopeType := 19; +   FST_ST_VHDL_GENERATE     : constant fstScopeType := 20; +   FST_ST_VHDL_PACKAGE      : constant fstScopeType := 21; +   FST_ST_MAX               : constant fstScopeType := 21; +   FST_ST_GEN_ATTRBEGIN     : constant fstScopeType := 252; +   FST_ST_GEN_ATTREND       : constant fstScopeType := 253; +   FST_ST_VCD_SCOPE         : constant fstScopeType := 254; +   FST_ST_VCD_UPSCOPE       : constant fstScopeType := 255; + +   subtype fstVarType is unsigned; +   FST_VT_MIN                : constant fstVarType := 0; +   FST_VT_VCD_EVENT          : constant fstVarType := 0; +   FST_VT_VCD_INTEGER        : constant fstVarType := 1; +   FST_VT_VCD_PARAMETER      : constant fstVarType := 2; +   FST_VT_VCD_REAL           : constant fstVarType := 3; +   FST_VT_VCD_REAL_PARAMETER : constant fstVarType := 4; +   FST_VT_VCD_REG            : constant fstVarType := 5; +   FST_VT_VCD_SUPPLY0        : constant fstVarType := 6; +   FST_VT_VCD_SUPPLY1        : constant fstVarType := 7; +   FST_VT_VCD_TIME           : constant fstVarType := 8; +   FST_VT_VCD_TRI            : constant fstVarType := 9; +   FST_VT_VCD_TRIAND         : constant fstVarType := 10; +   FST_VT_VCD_TRIOR          : constant fstVarType := 11; +   FST_VT_VCD_TRIREG         : constant fstVarType := 12; +   FST_VT_VCD_TRI0           : constant fstVarType := 13; +   FST_VT_VCD_TRI1           : constant fstVarType := 14; +   FST_VT_VCD_WAND           : constant fstVarType := 15; +   FST_VT_VCD_WIRE           : constant fstVarType := 16; +   FST_VT_VCD_WOR            : constant fstVarType := 17; +   FST_VT_VCD_PORT           : constant fstVarType := 18; +   FST_VT_VCD_SPARRAY        : constant fstVarType := 19; +   FST_VT_VCD_REALTIME       : constant fstVarType := 20; +   FST_VT_GEN_STRING         : constant fstVarType := 21; +   FST_VT_SV_BIT             : constant fstVarType := 22; +   FST_VT_SV_LOGIC           : constant fstVarType := 23; +   FST_VT_SV_INT             : constant fstVarType := 24; +   FST_VT_SV_SHORTINT        : constant fstVarType := 25; +   FST_VT_SV_LONGINT         : constant fstVarType := 26; +   FST_VT_SV_BYTE            : constant fstVarType := 27; +   FST_VT_SV_ENUM            : constant fstVarType := 28; +   FST_VT_SV_SHORTREAL       : constant fstVarType := 29; +   FST_VT_MAX                : constant fstVarType := 29; + +   subtype fstVarDir is unsigned; +   FST_VD_MIN      : constant fstVarDir := 0; +   FST_VD_IMPLICIT : constant fstVarDir := 0; +   FST_VD_INPUT    : constant fstVarDir := 1; +   FST_VD_OUTPUT   : constant fstVarDir := 2; +   FST_VD_INOUT    : constant fstVarDir := 3; +   FST_VD_BUFFER   : constant fstVarDir := 4; +   FST_VD_LINKAGE  : constant fstVarDir := 5; +   FST_VD_MAX      : constant fstVarDir := 5; + +   subtype fstHierType is unsigned; +   FST_HT_MIN       : constant fstHierType := 0; +   FST_HT_SCOPE     : constant fstHierType := 0; +   FST_HT_UPSCOPE   : constant fstHierType := 1; +   FST_HT_VAR       : constant fstHierType := 2; +   FST_HT_ATTRBEGIN : constant fstHierType := 3; +   FST_HT_ATTREND   : constant fstHierType := 4; +   FST_HT_MAX       : constant fstHierType := 4; + +   subtype fstAttrType is unsigned; +   FST_AT_MIN   : constant fstAttrType := 0; +   FST_AT_MISC  : constant fstAttrType := 0; +   FST_AT_ARRAY : constant fstAttrType := 1; +   FST_AT_ENUM  : constant fstAttrType := 2; +   FST_AT_PACK  : constant fstAttrType := 3; +   FST_AT_MAX   : constant fstAttrType := 3; + +   subtype fstMiscType is unsigned; +   FST_MT_MIN         : constant fstMiscType := 0; +   FST_MT_COMMENT     : constant fstMiscType := 0; +   FST_MT_ENVVAR      : constant fstMiscType := 1; +   FST_MT_SUPVAR      : constant fstMiscType := 2; +   FST_MT_PATHNAME    : constant fstMiscType := 3; +   FST_MT_SOURCESTEM  : constant fstMiscType := 4; +   FST_MT_SOURCEISTEM : constant fstMiscType := 5; +   FST_MT_UNKNOWN     : constant fstMiscType := 6; +   FST_MT_MAX         : constant fstMiscType := 6; + +   subtype fstArrayType is unsigned; +   FST_AR_MIN      : constant fstArrayType := 0; +   FST_AR_NONE     : constant fstArrayType := 0; +   FST_AR_UNPACKED : constant fstArrayType := 1; +   FST_AR_PACKED   : constant fstArrayType := 2; +   FST_AR_SPARSE   : constant fstArrayType := 3; +   FST_AR_MAX      : constant fstArrayType := 3; + +   subtype fstEnumValueType is unsigned; +   FST_EV_SV_INTEGER           : constant fstEnumValueType := 0; +   FST_EV_SV_BIT               : constant fstEnumValueType := 1; +   FST_EV_SV_LOGIC             : constant fstEnumValueType := 2; +   FST_EV_SV_INT               : constant fstEnumValueType := 3; +   FST_EV_SV_SHORTINT          : constant fstEnumValueType := 4; +   FST_EV_SV_LONGINT           : constant fstEnumValueType := 5; +   FST_EV_SV_BYTE              : constant fstEnumValueType := 6; +   FST_EV_SV_UNSIGNED_INTEGER  : constant fstEnumValueType := 7; +   FST_EV_SV_UNSIGNED_BIT      : constant fstEnumValueType := 8; +   FST_EV_SV_UNSIGNED_LOGIC    : constant fstEnumValueType := 9; +   FST_EV_SV_UNSIGNED_INT      : constant fstEnumValueType := 10; +   FST_EV_SV_UNSIGNED_SHORTINT : constant fstEnumValueType := 11; +   FST_EV_SV_UNSIGNED_LONGINT  : constant fstEnumValueType := 12; +   FST_EV_SV_UNSIGNED_BYTE     : constant fstEnumValueType := 13; +   FST_EV_MAX                  : constant fstEnumValueType := 13; + +   subtype fstPackType is unsigned; +   FST_PT_NONE          : constant fstPackType := 0; +   FST_PT_UNPACKED      : constant fstPackType := 1; +   FST_PT_PACKED        : constant fstPackType := 2; +   FST_PT_TAGGED_PACKED : constant fstPackType := 3; +   FST_PT_MAX           : constant fstPackType := 3; + +   subtype fstSupplementalVarType is unsigned; +   FST_SVT_MIN           : constant fstSupplementalVarType := 0; +   FST_SVT_NONE          : constant fstSupplementalVarType := 0; +   FST_SVT_VHDL_SIGNAL   : constant fstSupplementalVarType := 1; +   FST_SVT_VHDL_VARIABLE : constant fstSupplementalVarType := 2; +   FST_SVT_VHDL_CONSTANT : constant fstSupplementalVarType := 3; +   FST_SVT_VHDL_FILE     : constant fstSupplementalVarType := 4; +   FST_SVT_VHDL_MEMORY   : constant fstSupplementalVarType := 5; +   FST_SVT_MAX           : constant fstSupplementalVarType := 5; + +   subtype fstSupplementalDataType is unsigned; +   FST_SDT_MIN                    : constant fstSupplementalDataType := 0; +   FST_SDT_NONE                   : constant fstSupplementalDataType := 0; +   FST_SDT_VHDL_BOOLEAN           : constant fstSupplementalDataType := 1; +   FST_SDT_VHDL_BIT               : constant fstSupplementalDataType := 2; +   FST_SDT_VHDL_BIT_VECTOR        : constant fstSupplementalDataType := 3; +   FST_SDT_VHDL_STD_ULOGIC        : constant fstSupplementalDataType := 4; +   FST_SDT_VHDL_STD_ULOGIC_VECTOR : constant fstSupplementalDataType := 5; +   FST_SDT_VHDL_STD_LOGIC         : constant fstSupplementalDataType := 6; +   FST_SDT_VHDL_STD_LOGIC_VECTOR  : constant fstSupplementalDataType := 7; +   FST_SDT_VHDL_UNSIGNED          : constant fstSupplementalDataType := 8; +   FST_SDT_VHDL_SIGNED            : constant fstSupplementalDataType := 9; +   FST_SDT_VHDL_INTEGER           : constant fstSupplementalDataType := 10; +   FST_SDT_VHDL_REAL              : constant fstSupplementalDataType := 11; +   FST_SDT_VHDL_NATURAL           : constant fstSupplementalDataType := 12; +   FST_SDT_VHDL_POSITIVE          : constant fstSupplementalDataType := 13; +   FST_SDT_VHDL_TIME              : constant fstSupplementalDataType := 14; +   FST_SDT_VHDL_CHARACTER         : constant fstSupplementalDataType := 15; +   FST_SDT_VHDL_STRING            : constant fstSupplementalDataType := 16; +   FST_SDT_MAX                    : constant fstSupplementalDataType := 16; +   FST_SDT_SVT_SHIFT_COUNT        : constant fstSupplementalDataType := 10; +   FST_SDT_ABS_MAX                : constant fstSupplementalDataType := 1023; + +   type fstContext is new System.Address; +   Null_fstContext : constant fstContext := fstContext (System.Null_Address); + +   procedure fstWriterClose (ctx : fstContext); +   pragma Import (C, fstWriterClose, "fstWriterClose"); + +   function fstWriterCreate (nam : Ghdl_C_String; use_compressed_hier : int) +                             return fstContext; +   pragma Import (C, fstWriterCreate, "fstWriterCreate"); + +   function fstWriterCreateVar +     (ctx : fstContext; +      vt : fstVarType; +      vd : fstVarDir; +      len : unsigned; +      nam : Ghdl_C_String; +      aliasHandle : fstHandle) return fstHandle; +   pragma Import (C, fstWriterCreateVar, "fstWriterCreateVar"); + +   function fstWriterCreateVar2 +     (ctx : fstContext; +      vt : fstVarType; +      vd : fstVarDir; +      len : unsigned; +      nam : Ghdl_C_String; +      aliasHandle : fstHandle; +      c_type : Ghdl_C_String; +      svt : fstSupplementalVarType; +      sdt : fstSupplementalDataType) return fstHandle; +   pragma Import (C, fstWriterCreateVar2, "fstWriterCreateVar2"); + +   procedure fstWriterEmitValueChange +     (ctx : fstContext; +      handle : fstHandle; +      val : System.Address); +   pragma Import (C, fstWriterEmitValueChange, "fstWriterEmitValueChange"); + +   procedure fstWriterEmitVariableLengthValueChange +     (ctx : fstContext; +      handle : fstHandle; +      val : System.Address; +      len : unsigned); +   pragma Import (C, fstWriterEmitVariableLengthValueChange, +                  "fstWriterEmitVariableLengthValueChange"); + +   procedure fstWriterEmitDumpActive (ctx : fstContext; enable : int); +   pragma Import (C, fstWriterEmitDumpActive, "fstWriterEmitDumpActive"); + +   procedure fstWriterEmitTimeChange +     (ctx : fstContext; tim : Unsigned_64); +   pragma Import (C, fstWriterEmitTimeChange, "fstWriterEmitTimeChange"); + +   procedure fstWriterFlushContext (ctx : fstContext); +   pragma Import (C, fstWriterFlushContext, "fstWriterFlushContext"); + +   function fstWriterGetDumpSizeLimitReached (ctx : fstContext) return int; +   pragma Import (C, fstWriterGetDumpSizeLimitReached, +                  "fstWriterGetDumpSizeLimitReached"); + +   function fstWriterGetFseekFailed (ctx : fstContext) return int; +   pragma Import (C, fstWriterGetFseekFailed, "fstWriterGetFseekFailed"); + +   procedure fstWriterSetAttrBegin +     (ctx : fstContext; +      attrtype : fstAttrType; +      c_subtype : int; +      attrname : Ghdl_C_String; +      arg : Unsigned_64); +   pragma Import (C, fstWriterSetAttrBegin, "fstWriterSetAttrBegin"); + +   procedure fstWriterSetAttrEnd (ctx : fstContext); +   pragma Import (C, fstWriterSetAttrEnd, "fstWriterSetAttrEnd"); + +   procedure fstWriterSetComment (ctx : fstContext; comm : Ghdl_C_String); +   pragma Import (C, fstWriterSetComment, "fstWriterSetComment"); + +   procedure fstWriterSetDate (ctx : fstContext; dat : Ghdl_C_String); +   pragma Import (C, fstWriterSetDate, "fstWriterSetDate"); + +   procedure fstWriterSetDumpSizeLimit +     (ctx : Ghdl_C_String; numbytes : Unsigned_64); +   pragma Import (C, fstWriterSetDumpSizeLimit, "fstWriterSetDumpSizeLimit"); + +   procedure fstWriterSetEnvVar (ctx : fstContext; envvar : Ghdl_C_String); +   pragma Import (C, fstWriterSetEnvVar, "fstWriterSetEnvVar"); + +   procedure fstWriterSetFileType (ctx : fstContext; filetype : fstFileType); +   pragma Import (C, fstWriterSetFileType, "fstWriterSetFileType"); + +   procedure fstWriterSetPackType (ctx : fstContext; typ : fstWriterPackType); +   pragma Import (C, fstWriterSetPackType, "fstWriterSetPackType"); + +   procedure fstWriterSetParallelMode (ctx : fstContext; enable : int); +   pragma Import (C, fstWriterSetParallelMode, "fstWriterSetParallelMode"); + +   procedure fstWriterSetRepackOnClose (ctx : fstContext; enable : int); +   pragma Import (C, fstWriterSetRepackOnClose, "fstWriterSetRepackOnClose"); + +   procedure fstWriterSetScope +     (ctx : fstContext; +      scopetype : fstScopeType; +      scopename : Ghdl_C_String; +      scopecomp : Ghdl_C_String); +   pragma Import (C, fstWriterSetScope, "fstWriterSetScope"); + +   procedure fstWriterSetSourceInstantiationStem +     (ctx : fstContext; +      path : Ghdl_C_String; +      line : unsigned; +      use_realpath : unsigned); +   pragma Import (C, fstWriterSetSourceInstantiationStem, +                  "fstWriterSetSourceInstantiationStem"); + +   procedure fstWriterSetSourceStem +     (ctx : fstContext; +      path : Ghdl_C_String; +      line : unsigned; +      use_realpath : unsigned); +   pragma Import (C, fstWriterSetSourceStem, "fstWriterSetSourceStem"); + +   procedure fstWriterSetTimescale (ctx : fstContext; ts : Integer); +   pragma Import (C, fstWriterSetTimescale, "fstWriterSetTimescale"); + +   procedure fstWriterSetTimescaleFromString +     (ctx : fstContext; s : Ghdl_C_String); +   pragma Import (C, fstWriterSetTimescaleFromString, +                  "fstWriterSetTimescaleFromString"); + +   procedure fstWriterSetTimezero (ctx : fstContext; tim : Unsigned_64); +   pragma Import (C, fstWriterSetTimezero, "fstWriterSetTimezero"); + +   procedure fstWriterSetUpscope (ctx : fstContext); +   pragma Import (C, fstWriterSetUpscope, "fstWriterSetUpscope"); + +   procedure fstWriterSetVersion (ctx : fstContext; vers : Ghdl_C_String); +   pragma Import (C, fstWriterSetVersion, "fstWriterSetVersion"); + +   function fstUtilityBinToEsc +     (d : access unsigned_char; +      s : access unsigned_char; +      len : int) return int; +   pragma Import (C, fstUtilityBinToEsc, "fstUtilityBinToEsc"); + +   function fstUtilityEscToBin +     (d : access unsigned_char; +      s : access unsigned_char; +      len : int) return int; +   pragma Import (C, fstUtilityEscToBin, "fstUtilityEscToBin"); + +end Grt.Fst_Api; diff --git a/src/grt/grt-modules.adb b/src/grt/grt-modules.adb index e5304f04d..3fc6c4ec2 100644 --- a/src/grt/grt-modules.adb +++ b/src/grt/grt-modules.adb @@ -27,6 +27,7 @@ pragma Unreferenced (System.Storage_Elements);  with Grt.Vcd;  with Grt.Vcdz;  with Grt.Vpi; +with Grt.Fst;  with Grt.Waves;  with Grt.Vital_Annotate;  with Grt.Disp_Tree; @@ -40,6 +41,7 @@ package body Grt.Modules is        Grt.Vcd.Register;        Grt.Vcdz.Register;        Grt.Waves.Register; +      Grt.Fst.Register;        Grt.Vpi.Register;        Grt.Vital_Annotate.Register;        Grt.Disp_Rti.Register; diff --git a/src/grt/grt-vcd.adb b/src/grt/grt-vcd.adb index d4a9ea066..13c1f20d5 100644 --- a/src/grt/grt-vcd.adb +++ b/src/grt/grt-vcd.adb @@ -714,8 +714,7 @@ package body Grt.Vcd is        Vcd_Newline;     end Vcd_Put_Var; -   function Verilog_Wire_Changed (Info : Verilog_Wire_Info; -                                  Last : Std_Time) +   function Verilog_Wire_Changed (Info : Verilog_Wire_Info; Last : Std_Time)                                   return Boolean     is        Len : Ghdl_Index_Type; diff --git a/src/grt/grt-vcd.ads b/src/grt/grt-vcd.ads index ed015af80..73096c5dd 100644 --- a/src/grt/grt-vcd.ads +++ b/src/grt/grt-vcd.ads @@ -47,7 +47,9 @@ package Grt.Vcd is     type Vcd_Value_Kind is (Vcd_Effective, Vcd_Driving);     type Verilog_Wire_Info is record +      --  Signal address        Addr : Address; +        Irange : Ghdl_Range_Ptr;        Kind : Vcd_Var_Kind;        Val : Vcd_Value_Kind;  | 
