Add initial fst support.
This patch is a slight modification to files Tony Bybell (the author of GTKWave) send to me. We still have a few more changes we plan to make, but this should be functional enough for initial testing. Multi-treading and speed/size flags will be added shortly.
This commit is contained in:
parent
09d59d744d
commit
f11ba81202
|
|
@ -73,6 +73,7 @@ ifeq (@HAVE_LIBBZ2@,yes)
|
|||
O += sys_lxt.o lxt_write.o
|
||||
endif
|
||||
O += sys_lxt2.o lxt2_write.o
|
||||
O += sys_fst.o fstapi.o fastlz.o
|
||||
endif
|
||||
|
||||
# Object files for v2005_math.vpi
|
||||
|
|
|
|||
|
|
@ -0,0 +1,547 @@
|
|||
/*
|
||||
FastLZ - lightning-fast lossless compression library
|
||||
|
||||
Copyright (C) 2007 Ariya Hidayat (ariya@kde.org)
|
||||
Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
|
||||
Copyright (C) 2005 Ariya Hidayat (ariya@kde.org)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "fastlz.h"
|
||||
|
||||
#if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR)
|
||||
|
||||
/*
|
||||
* Always check for bound when decompressing.
|
||||
* Generally it is best to leave it defined.
|
||||
*/
|
||||
#define FASTLZ_SAFE
|
||||
|
||||
|
||||
/*
|
||||
* Give hints to the compiler for branch prediction optimization.
|
||||
*/
|
||||
#if defined(__GNUC__) && (__GNUC__ > 2)
|
||||
#define FASTLZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1))
|
||||
#define FASTLZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0))
|
||||
#else
|
||||
#define FASTLZ_EXPECT_CONDITIONAL(c) (c)
|
||||
#define FASTLZ_UNEXPECT_CONDITIONAL(c) (c)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Use inlined functions for supported systems.
|
||||
*/
|
||||
#if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) || defined(__WATCOMC__) || defined(__SUNPRO_C)
|
||||
#define FASTLZ_INLINE inline
|
||||
#elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__)
|
||||
#define FASTLZ_INLINE __inline
|
||||
#else
|
||||
#define FASTLZ_INLINE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Prevent accessing more than 8-bit at once, except on x86 architectures.
|
||||
*/
|
||||
#if !defined(FASTLZ_STRICT_ALIGN)
|
||||
#define FASTLZ_STRICT_ALIGN
|
||||
#if defined(__i386__) || defined(__386) /* GNU C, Sun Studio */
|
||||
#undef FASTLZ_STRICT_ALIGN
|
||||
#elif defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__amd64) /* GNU C */
|
||||
#undef FASTLZ_STRICT_ALIGN
|
||||
#elif defined(_M_IX86) /* Intel, MSVC */
|
||||
#undef FASTLZ_STRICT_ALIGN
|
||||
#elif defined(__386)
|
||||
#undef FASTLZ_STRICT_ALIGN
|
||||
#elif defined(_X86_) /* MinGW */
|
||||
#undef FASTLZ_STRICT_ALIGN
|
||||
#elif defined(__I86__) /* Digital Mars */
|
||||
#undef FASTLZ_STRICT_ALIGN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* prototypes */
|
||||
int fastlz_compress(const void* input, int length, void* output);
|
||||
int fastlz_compress_level(int level, const void* input, int length, void* output);
|
||||
int fastlz_decompress(const void* input, int length, void* output, int maxout);
|
||||
|
||||
#define MAX_COPY 32
|
||||
#define MAX_LEN 264 /* 256 + 8 */
|
||||
#define MAX_DISTANCE 8192
|
||||
|
||||
#if !defined(FASTLZ_STRICT_ALIGN)
|
||||
#define FASTLZ_READU16(p) *((const flzuint16*)(p))
|
||||
#else
|
||||
#define FASTLZ_READU16(p) ((p)[0] | (p)[1]<<8)
|
||||
#endif
|
||||
|
||||
#define HASH_LOG 13
|
||||
#define HASH_SIZE (1<< HASH_LOG)
|
||||
#define HASH_MASK (HASH_SIZE-1)
|
||||
#define HASH_FUNCTION(v,p) { v = FASTLZ_READU16(p); v ^= FASTLZ_READU16(p+1)^(v>>(16-HASH_LOG));v &= HASH_MASK; }
|
||||
|
||||
#undef FASTLZ_LEVEL
|
||||
#define FASTLZ_LEVEL 1
|
||||
|
||||
#undef FASTLZ_COMPRESSOR
|
||||
#undef FASTLZ_DECOMPRESSOR
|
||||
#define FASTLZ_COMPRESSOR fastlz1_compress
|
||||
#define FASTLZ_DECOMPRESSOR fastlz1_decompress
|
||||
static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output);
|
||||
static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout);
|
||||
#include "fastlz.c"
|
||||
|
||||
#undef FASTLZ_LEVEL
|
||||
#define FASTLZ_LEVEL 2
|
||||
|
||||
#undef MAX_DISTANCE
|
||||
#define MAX_DISTANCE 8191
|
||||
#define MAX_FARDISTANCE (65535+MAX_DISTANCE-1)
|
||||
|
||||
#undef FASTLZ_COMPRESSOR
|
||||
#undef FASTLZ_DECOMPRESSOR
|
||||
#define FASTLZ_COMPRESSOR fastlz2_compress
|
||||
#define FASTLZ_DECOMPRESSOR fastlz2_decompress
|
||||
static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output);
|
||||
static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout);
|
||||
#include "fastlz.c"
|
||||
|
||||
int fastlz_compress(const void* input, int length, void* output)
|
||||
{
|
||||
/* for short block, choose fastlz1 */
|
||||
if(length < 65536)
|
||||
return fastlz1_compress(input, length, output);
|
||||
|
||||
/* else... */
|
||||
return fastlz2_compress(input, length, output);
|
||||
}
|
||||
|
||||
int fastlz_decompress(const void* input, int length, void* output, int maxout)
|
||||
{
|
||||
/* magic identifier for compression level */
|
||||
int level = ((*(const flzuint8*)input) >> 5) + 1;
|
||||
|
||||
if(level == 1)
|
||||
return fastlz1_decompress(input, length, output, maxout);
|
||||
if(level == 2)
|
||||
return fastlz2_decompress(input, length, output, maxout);
|
||||
|
||||
/* unknown level, trigger error */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fastlz_compress_level(int level, const void* input, int length, void* output)
|
||||
{
|
||||
if(level == 1)
|
||||
return fastlz1_compress(input, length, output);
|
||||
if(level == 2)
|
||||
return fastlz2_compress(input, length, output);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */
|
||||
|
||||
static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output)
|
||||
{
|
||||
const flzuint8* ip = (const flzuint8*) input;
|
||||
const flzuint8* ip_bound = ip + length - 2;
|
||||
const flzuint8* ip_limit = ip + length - 12;
|
||||
flzuint8* op = (flzuint8*) output;
|
||||
|
||||
const flzuint8* htab[HASH_SIZE];
|
||||
const flzuint8** hslot;
|
||||
flzuint32 hval;
|
||||
|
||||
flzuint32 copy;
|
||||
|
||||
/* sanity check */
|
||||
if(FASTLZ_UNEXPECT_CONDITIONAL(length < 4))
|
||||
{
|
||||
if(length)
|
||||
{
|
||||
/* create literal copy only */
|
||||
*op++ = length-1;
|
||||
ip_bound++;
|
||||
while(ip <= ip_bound)
|
||||
*op++ = *ip++;
|
||||
return length+1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* initializes hash table */
|
||||
for (hslot = htab; hslot < htab + HASH_SIZE; hslot++)
|
||||
*hslot = ip;
|
||||
|
||||
/* we start with literal copy */
|
||||
copy = 2;
|
||||
*op++ = MAX_COPY-1;
|
||||
*op++ = *ip++;
|
||||
*op++ = *ip++;
|
||||
|
||||
/* main loop */
|
||||
while(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit))
|
||||
{
|
||||
const flzuint8* ref;
|
||||
flzuint32 distance;
|
||||
|
||||
/* minimum match length */
|
||||
flzuint32 len = 3;
|
||||
|
||||
/* comparison starting-point */
|
||||
const flzuint8* anchor = ip;
|
||||
|
||||
/* check for a run */
|
||||
#if FASTLZ_LEVEL==2
|
||||
if(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1))
|
||||
{
|
||||
distance = 1;
|
||||
ip += 3;
|
||||
ref = anchor - 1 + 3;
|
||||
goto match;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* find potential match */
|
||||
HASH_FUNCTION(hval,ip);
|
||||
hslot = htab + hval;
|
||||
ref = htab[hval];
|
||||
|
||||
/* calculate distance to the match */
|
||||
distance = anchor - ref;
|
||||
|
||||
/* update hash table */
|
||||
*hslot = anchor;
|
||||
|
||||
/* is this a match? check the first 3 bytes */
|
||||
if(distance==0 ||
|
||||
#if FASTLZ_LEVEL==1
|
||||
(distance >= MAX_DISTANCE) ||
|
||||
#else
|
||||
(distance >= MAX_FARDISTANCE) ||
|
||||
#endif
|
||||
*ref++ != *ip++ || *ref++!=*ip++ || *ref++!=*ip++)
|
||||
goto literal;
|
||||
|
||||
#if FASTLZ_LEVEL==2
|
||||
/* far, needs at least 5-byte match */
|
||||
if(distance >= MAX_DISTANCE)
|
||||
{
|
||||
if(*ip++ != *ref++ || *ip++!= *ref++)
|
||||
goto literal;
|
||||
len += 2;
|
||||
}
|
||||
|
||||
match:
|
||||
#endif
|
||||
|
||||
/* last matched byte */
|
||||
ip = anchor + len;
|
||||
|
||||
/* distance is biased */
|
||||
distance--;
|
||||
|
||||
if(!distance)
|
||||
{
|
||||
/* zero distance means a run */
|
||||
flzuint8 x = ip[-1];
|
||||
while(ip < ip_bound)
|
||||
if(*ref++ != x) break; else ip++;
|
||||
}
|
||||
else
|
||||
for(;;)
|
||||
{
|
||||
/* safe because the outer check against ip limit */
|
||||
if(*ref++ != *ip++) break;
|
||||
if(*ref++ != *ip++) break;
|
||||
if(*ref++ != *ip++) break;
|
||||
if(*ref++ != *ip++) break;
|
||||
if(*ref++ != *ip++) break;
|
||||
if(*ref++ != *ip++) break;
|
||||
if(*ref++ != *ip++) break;
|
||||
if(*ref++ != *ip++) break;
|
||||
while(ip < ip_bound)
|
||||
if(*ref++ != *ip++) break;
|
||||
break;
|
||||
}
|
||||
|
||||
/* if we have copied something, adjust the copy count */
|
||||
if(copy)
|
||||
/* copy is biased, '0' means 1 byte copy */
|
||||
*(op-copy-1) = copy-1;
|
||||
else
|
||||
/* back, to overwrite the copy count */
|
||||
op--;
|
||||
|
||||
/* reset literal counter */
|
||||
copy = 0;
|
||||
|
||||
/* length is biased, '1' means a match of 3 bytes */
|
||||
ip -= 3;
|
||||
len = ip - anchor;
|
||||
|
||||
/* encode the match */
|
||||
#if FASTLZ_LEVEL==2
|
||||
if(distance < MAX_DISTANCE)
|
||||
{
|
||||
if(len < 7)
|
||||
{
|
||||
*op++ = (len << 5) + (distance >> 8);
|
||||
*op++ = (distance & 255);
|
||||
}
|
||||
else
|
||||
{
|
||||
*op++ = (7 << 5) + (distance >> 8);
|
||||
for(len-=7; len >= 255; len-= 255)
|
||||
*op++ = 255;
|
||||
*op++ = len;
|
||||
*op++ = (distance & 255);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* far away, but not yet in the another galaxy... */
|
||||
if(len < 7)
|
||||
{
|
||||
distance -= MAX_DISTANCE;
|
||||
*op++ = (len << 5) + 31;
|
||||
*op++ = 255;
|
||||
*op++ = distance >> 8;
|
||||
*op++ = distance & 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
distance -= MAX_DISTANCE;
|
||||
*op++ = (7 << 5) + 31;
|
||||
for(len-=7; len >= 255; len-= 255)
|
||||
*op++ = 255;
|
||||
*op++ = len;
|
||||
*op++ = 255;
|
||||
*op++ = distance >> 8;
|
||||
*op++ = distance & 255;
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
if(FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN-2))
|
||||
while(len > MAX_LEN-2)
|
||||
{
|
||||
*op++ = (7 << 5) + (distance >> 8);
|
||||
*op++ = MAX_LEN - 2 - 7 -2;
|
||||
*op++ = (distance & 255);
|
||||
len -= MAX_LEN-2;
|
||||
}
|
||||
|
||||
if(len < 7)
|
||||
{
|
||||
*op++ = (len << 5) + (distance >> 8);
|
||||
*op++ = (distance & 255);
|
||||
}
|
||||
else
|
||||
{
|
||||
*op++ = (7 << 5) + (distance >> 8);
|
||||
*op++ = len - 7;
|
||||
*op++ = (distance & 255);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* update the hash at match boundary */
|
||||
HASH_FUNCTION(hval,ip);
|
||||
htab[hval] = ip++;
|
||||
HASH_FUNCTION(hval,ip);
|
||||
htab[hval] = ip++;
|
||||
|
||||
/* assuming literal copy */
|
||||
*op++ = MAX_COPY-1;
|
||||
|
||||
continue;
|
||||
|
||||
literal:
|
||||
*op++ = *anchor++;
|
||||
ip = anchor;
|
||||
copy++;
|
||||
if(FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY))
|
||||
{
|
||||
copy = 0;
|
||||
*op++ = MAX_COPY-1;
|
||||
}
|
||||
}
|
||||
|
||||
/* left-over as literal copy */
|
||||
ip_bound++;
|
||||
while(ip <= ip_bound)
|
||||
{
|
||||
*op++ = *ip++;
|
||||
copy++;
|
||||
if(copy == MAX_COPY)
|
||||
{
|
||||
copy = 0;
|
||||
*op++ = MAX_COPY-1;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we have copied something, adjust the copy length */
|
||||
if(copy)
|
||||
*(op-copy-1) = copy-1;
|
||||
else
|
||||
op--;
|
||||
|
||||
#if FASTLZ_LEVEL==2
|
||||
/* marker for fastlz2 */
|
||||
*(flzuint8*)output |= (1 << 5);
|
||||
#endif
|
||||
|
||||
return op - (flzuint8*)output;
|
||||
}
|
||||
|
||||
static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout)
|
||||
{
|
||||
const flzuint8* ip = (const flzuint8*) input;
|
||||
const flzuint8* ip_limit = ip + length;
|
||||
flzuint8* op = (flzuint8*) output;
|
||||
flzuint8* op_limit = op + maxout;
|
||||
flzuint32 ctrl = (*ip++) & 31;
|
||||
int loop = 1;
|
||||
|
||||
do
|
||||
{
|
||||
const flzuint8* ref = op;
|
||||
flzuint32 len = ctrl >> 5;
|
||||
flzuint32 ofs = (ctrl & 31) << 8;
|
||||
|
||||
if(ctrl >= 32)
|
||||
{
|
||||
#if FASTLZ_LEVEL==2
|
||||
flzuint8 code;
|
||||
#endif
|
||||
len--;
|
||||
ref -= ofs;
|
||||
if (len == 7-1)
|
||||
#if FASTLZ_LEVEL==1
|
||||
len += *ip++;
|
||||
ref -= *ip++;
|
||||
#else
|
||||
do
|
||||
{
|
||||
code = *ip++;
|
||||
len += code;
|
||||
} while (code==255);
|
||||
code = *ip++;
|
||||
ref -= code;
|
||||
|
||||
/* match from 16-bit distance */
|
||||
if(FASTLZ_UNEXPECT_CONDITIONAL(code==255))
|
||||
if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8)))
|
||||
{
|
||||
ofs = (*ip++) << 8;
|
||||
ofs += *ip++;
|
||||
ref = op - ofs - MAX_DISTANCE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FASTLZ_SAFE
|
||||
if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit))
|
||||
return 0;
|
||||
|
||||
if (FASTLZ_UNEXPECT_CONDITIONAL(ref-1 < (flzuint8 *)output))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
if(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit))
|
||||
ctrl = *ip++;
|
||||
else
|
||||
loop = 0;
|
||||
|
||||
if(ref == op)
|
||||
{
|
||||
/* optimize copy for a run */
|
||||
flzuint8 b = ref[-1];
|
||||
*op++ = b;
|
||||
*op++ = b;
|
||||
*op++ = b;
|
||||
for(; len; --len)
|
||||
*op++ = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if !defined(FASTLZ_STRICT_ALIGN)
|
||||
const flzuint16* p;
|
||||
flzuint16* q;
|
||||
#endif
|
||||
/* copy from reference */
|
||||
ref--;
|
||||
*op++ = *ref++;
|
||||
*op++ = *ref++;
|
||||
*op++ = *ref++;
|
||||
|
||||
#if !defined(FASTLZ_STRICT_ALIGN)
|
||||
/* copy a byte, so that now it's word aligned */
|
||||
if(len & 1)
|
||||
{
|
||||
*op++ = *ref++;
|
||||
len--;
|
||||
}
|
||||
|
||||
/* copy 16-bit at once */
|
||||
q = (flzuint16*) op;
|
||||
op += len;
|
||||
p = (const flzuint16*) ref;
|
||||
for(len>>=1; len > 4; len-=4)
|
||||
{
|
||||
*q++ = *p++;
|
||||
*q++ = *p++;
|
||||
*q++ = *p++;
|
||||
*q++ = *p++;
|
||||
}
|
||||
for(; len; --len)
|
||||
*q++ = *p++;
|
||||
#else
|
||||
for(; len; --len)
|
||||
*op++ = *ref++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ctrl++;
|
||||
#ifdef FASTLZ_SAFE
|
||||
if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit))
|
||||
return 0;
|
||||
if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
*op++ = *ip++;
|
||||
for(--ctrl; ctrl; ctrl--)
|
||||
*op++ = *ip++;
|
||||
|
||||
loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit);
|
||||
if(loop)
|
||||
ctrl = *ip++;
|
||||
}
|
||||
}
|
||||
while(FASTLZ_EXPECT_CONDITIONAL(loop));
|
||||
|
||||
return op - (flzuint8*)output;
|
||||
}
|
||||
|
||||
#endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */
|
||||
|
|
@ -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 */
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* Copyright (c) 2009-2010 Tony Bybell.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef FST_API_H
|
||||
#define FST_API_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <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 fstBlockType {
|
||||
FST_BL_HDR = 0,
|
||||
FST_BL_VCDATA = 1,
|
||||
FST_BL_BLACKOUT = 2,
|
||||
FST_BL_GEOM = 3,
|
||||
FST_BL_HIER = 4,
|
||||
|
||||
FST_BL_ZWRAPPER = 254, /* indicates that whole trace is gz wrapped */
|
||||
FST_BL_SKIP = 255 /* used while block is being written */
|
||||
};
|
||||
|
||||
enum fstScopeType {
|
||||
FST_ST_VCD_MIN = 0,
|
||||
FST_ST_VCD_MODULE = 0,
|
||||
FST_ST_VCD_TASK = 1,
|
||||
FST_ST_VCD_FUNCTION = 2,
|
||||
FST_ST_VCD_BEGIN = 3,
|
||||
FST_ST_VCD_FORK = 4,
|
||||
FST_ST_VCD_MAX = 4,
|
||||
|
||||
FST_ST_MAX = 4,
|
||||
|
||||
FST_ST_VCD_SCOPE = 254,
|
||||
FST_ST_VCD_UPSCOPE = 255
|
||||
};
|
||||
|
||||
enum fstVarType {
|
||||
FST_VT_VCD_MIN = 0, /* start of VCD datatypes */
|
||||
FST_VT_VCD_EVENT = 0,
|
||||
FST_VT_VCD_INTEGER = 1,
|
||||
FST_VT_VCD_PARAMETER = 2,
|
||||
FST_VT_VCD_REAL = 3,
|
||||
FST_VT_VCD_REAL_PARAMETER = 4,
|
||||
FST_VT_VCD_REG = 5,
|
||||
FST_VT_VCD_SUPPLY0 = 6,
|
||||
FST_VT_VCD_SUPPLY1 = 7,
|
||||
FST_VT_VCD_TIME = 8,
|
||||
FST_VT_VCD_TRI = 9,
|
||||
FST_VT_VCD_TRIAND = 10,
|
||||
FST_VT_VCD_TRIOR = 11,
|
||||
FST_VT_VCD_TRIREG = 12,
|
||||
FST_VT_VCD_TRI0 = 13,
|
||||
FST_VT_VCD_TRI1 = 14,
|
||||
FST_VT_VCD_WAND = 15,
|
||||
FST_VT_VCD_WIRE = 16,
|
||||
FST_VT_VCD_WOR = 17,
|
||||
FST_VT_VCD_PORT = 18,
|
||||
FST_VT_VCD_ARRAY = 19, /* used to define the rownum (index) port on the array */
|
||||
FST_VT_VCD_REALTIME = 20,
|
||||
FST_VT_VCD_MAX = 20, /* end of VCD datatypes */
|
||||
|
||||
FST_VT_GEN_STRING = 254, /* generic string type (max len is defined as the len in fstWriterCreateVar() */
|
||||
FST_VT_GEN_MEMBLOCK = 255 /* generic memblock type (max len is defined as the len in fstWriterCreateVar() */
|
||||
};
|
||||
|
||||
enum fstVarDir {
|
||||
FST_VD_IMPLICIT = 0,
|
||||
FST_VD_INPUT = 1,
|
||||
FST_VD_OUTPUT = 2,
|
||||
FST_VD_INOUT = 3,
|
||||
|
||||
FST_VD_MAX = 3
|
||||
};
|
||||
|
||||
enum fstHierType {
|
||||
FST_HT_SCOPE = 0,
|
||||
FST_HT_UPSCOPE = 1,
|
||||
FST_HT_VAR = 2,
|
||||
|
||||
FST_HT_MAX = 2
|
||||
};
|
||||
|
||||
struct fstHier
|
||||
{
|
||||
unsigned char htyp;
|
||||
|
||||
union {
|
||||
/* if htyp == FST_HT_SCOPE */
|
||||
struct fstHierScope {
|
||||
unsigned char typ; /* FST_ST_VCD_MODULE ... FST_ST_VCD_FORK */
|
||||
const char *name;
|
||||
const char *component;
|
||||
} scope;
|
||||
|
||||
/* if htyp == FST_HT_VAR */
|
||||
struct fstHierVar {
|
||||
unsigned char typ; /* FST_VT_VCD_EVENT ... FST_VT_VCD_WOR */
|
||||
unsigned char direction; /* FST_VD_IMPLICIT ... FST_VD_INOUT */
|
||||
const char *name;
|
||||
uint32_t length;
|
||||
fstHandle handle;
|
||||
unsigned is_alias : 1;
|
||||
} var;
|
||||
} u;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* writer functions
|
||||
*/
|
||||
fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir vd,
|
||||
uint32_t len, const char *nam, fstHandle aliasHandle);
|
||||
|
||||
void fstWriterSetPackType(void *ctx, int typ); /* type = 0 (libz), 1 (fastlz) */
|
||||
void fstWriterSetRepackOnClose(void *ctx, int enable); /* type = 0 (none), 1 (libz) */
|
||||
void fstWriterSetDumpSizeLimit(void *ctx, uint64_t numbytes);
|
||||
int fstWriterGetDumpSizeLimitReached(void *ctx);
|
||||
|
||||
void *fstWriterCreate(const char *nam, int use_compressed_hier);
|
||||
void fstWriterClose(void *ctx);
|
||||
void fstWriterSetDate(void *ctx, const char *dat);
|
||||
void fstWriterSetVersion(void *ctx, const char *vers);
|
||||
void fstWriterSetTimescale(void *ctx, int ts);
|
||||
void fstWriterSetTimescaleFromString(void *ctx, const char *s);
|
||||
void fstWriterSetScope(void *ctx, enum fstScopeType scopetype,
|
||||
const char *scopename, const char *scopecomp);
|
||||
void fstWriterSetUpscope(void *ctx);
|
||||
void fstWriterEmitValueChange(void *ctx, fstHandle handle, void *val);
|
||||
void fstWriterEmitDumpActive(void *ctx, int enable);
|
||||
void fstWriterEmitTimeChange(void *ctx, uint64_t tim);
|
||||
void fstWriterFlushContext(void *ctx);
|
||||
|
||||
/*
|
||||
* reader functions
|
||||
*/
|
||||
void *fstReaderOpen(const char *nam);
|
||||
void fstReaderClose(void *ctx);
|
||||
|
||||
void fstReaderProcessHier(void *ctx, FILE *vcdhandle);
|
||||
void fstReaderIterateHierRewind(void *ctx);
|
||||
struct fstHier *fstReaderIterateHier(void *ctx);
|
||||
|
||||
void fstReaderResetScope(void *ctx);
|
||||
const char *fstReaderPopScope(void *ctx);
|
||||
const char *fstReaderPushScope(void *ctx, const char *nam, void *user_info);
|
||||
const char *fstReaderGetCurrentFlatScope(void *ctx);
|
||||
void *fstReaderGetCurrentScopeUserInfo(void *ctx);
|
||||
|
||||
signed char fstReaderGetTimescale(void *ctx);
|
||||
uint64_t fstReaderGetStartTime(void *ctx);
|
||||
uint64_t fstReaderGetEndTime(void *ctx);
|
||||
uint64_t fstReaderGetMemoryUsedByWriter(void *ctx);
|
||||
uint64_t fstReaderGetScopeCount(void *ctx);
|
||||
uint64_t fstReaderGetVarCount(void *ctx);
|
||||
fstHandle fstReaderGetMaxHandle(void *ctx);
|
||||
uint64_t fstReaderGetAliasCount(void *ctx);
|
||||
uint64_t fstReaderGetValueChangeSectionCount(void *ctx);
|
||||
int fstReaderGetDoubleEndianMatchState(void *ctx);
|
||||
const char *fstReaderGetVersionString(void *ctx);
|
||||
const char *fstReaderGetDateString(void *ctx);
|
||||
|
||||
void fstReaderSetLimitTimeRange(void *ctx, uint64_t start_time, uint64_t end_time);
|
||||
void fstReaderSetUnlimitedTimeRange(void *ctx);
|
||||
|
||||
uint32_t fstReaderGetNumberDumpActivityChanges(void *ctx);
|
||||
uint64_t fstReaderGetDumpActivityChangeTime(void *ctx, uint32_t idx);
|
||||
unsigned char fstReaderGetDumpActivityChangeValue(void *ctx, uint32_t idx);
|
||||
|
||||
int fstReaderGetFacProcessMask(void *ctx, fstHandle facidx);
|
||||
void fstReaderSetFacProcessMask(void *ctx, fstHandle facidx);
|
||||
void fstReaderClrFacProcessMask(void *ctx, fstHandle facidx);
|
||||
void fstReaderSetFacProcessMaskAll(void *ctx);
|
||||
void fstReaderClrFacProcessMaskAll(void *ctx);
|
||||
|
||||
void fstReaderIterBlocksSetNativeDoublesOnCallback(void *ctx, int enable);
|
||||
|
||||
int fstReaderIterBlocks(void *ctx,
|
||||
void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value),
|
||||
void *user_callback_data_pointer, FILE *vcdhandle);
|
||||
|
||||
char *fstReaderGetValueFromHandleAtTime(void *ctx, uint64_t tim, fstHandle facidx, char *buf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,868 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
# include "sys_priv.h"
|
||||
# include "vcd_priv.h"
|
||||
# include "fstapi.h"
|
||||
|
||||
/*
|
||||
* This file contains the implementations of the VCD related
|
||||
* funcitons.
|
||||
*/
|
||||
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
# include <assert.h>
|
||||
# include <time.h>
|
||||
#ifdef HAVE_MALLOC_H
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
|
||||
static char *dump_path = NULL;
|
||||
static struct fstContext *dump_file = NULL;
|
||||
|
||||
struct vcd_info {
|
||||
vpiHandle item;
|
||||
vpiHandle cb;
|
||||
struct t_vpi_time time;
|
||||
struct vcd_info *next;
|
||||
struct vcd_info *dmp_next;
|
||||
fstHandle handle;
|
||||
int scheduled;
|
||||
};
|
||||
|
||||
|
||||
static struct vcd_info *vcd_list = NULL;
|
||||
static struct vcd_info *vcd_dmp_list = NULL;
|
||||
static PLI_UINT64 vcd_cur_time = 0;
|
||||
static int dump_is_off = 0;
|
||||
static long dump_limit = 0;
|
||||
static int dump_is_full = 0;
|
||||
static int finish_status = 0;
|
||||
|
||||
|
||||
static const char*units_names[] = {
|
||||
"s",
|
||||
"ms",
|
||||
"us",
|
||||
"ns",
|
||||
"ps",
|
||||
"fs"
|
||||
};
|
||||
|
||||
static void show_this_item(struct vcd_info*info)
|
||||
{
|
||||
s_vpi_value value;
|
||||
PLI_INT32 type = vpi_get(vpiType, info->item);
|
||||
|
||||
if (type == vpiRealVar) {
|
||||
value.format = vpiRealVal;
|
||||
vpi_get_value(info->item, &value);
|
||||
fstWriterEmitValueChange(dump_file, info->handle, &value.value.real);
|
||||
} else {
|
||||
value.format = vpiBinStrVal;
|
||||
vpi_get_value(info->item, &value);
|
||||
fstWriterEmitValueChange(dump_file, info->handle, value.value.str);
|
||||
}
|
||||
}
|
||||
|
||||
/* Dump values for a $dumpoff. */
|
||||
static void show_this_item_x(struct vcd_info*info)
|
||||
{
|
||||
PLI_INT32 type = vpi_get(vpiType, info->item);
|
||||
|
||||
if (type == vpiRealVar) {
|
||||
/* Some tools dump nothing here...? */
|
||||
double mynan = strtod("NaN", NULL);
|
||||
fstWriterEmitValueChange(dump_file, info->handle, &mynan);
|
||||
} else if (type == vpiNamedEvent) {
|
||||
/* Do nothing for named events. */
|
||||
} else {
|
||||
int siz = vpi_get(vpiSize, info->item);
|
||||
char *xmem = malloc(siz);
|
||||
memset(xmem, 'x', siz);
|
||||
fstWriterEmitValueChange(dump_file, info->handle, xmem);
|
||||
free(xmem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* managed qsorted list of scope names/variables for duplicates bsearching
|
||||
*/
|
||||
|
||||
struct vcd_names_list_s fst_tab = { 0 };
|
||||
struct vcd_names_list_s fst_var = { 0 };
|
||||
|
||||
|
||||
static int dumpvars_status = 0; /* 0:fresh 1:cb installed, 2:callback done */
|
||||
static PLI_UINT64 dumpvars_time;
|
||||
__inline__ static int dump_header_pending(void)
|
||||
{
|
||||
return dumpvars_status != 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function writes out all the traced variables, whether they
|
||||
* changed or not.
|
||||
*/
|
||||
static void vcd_checkpoint()
|
||||
{
|
||||
struct vcd_info*cur;
|
||||
|
||||
for (cur = vcd_list ; cur ; cur = cur->next)
|
||||
show_this_item(cur);
|
||||
}
|
||||
|
||||
static void vcd_checkpoint_x()
|
||||
{
|
||||
struct vcd_info*cur;
|
||||
|
||||
for (cur = vcd_list ; cur ; cur = cur->next)
|
||||
show_this_item_x(cur);
|
||||
}
|
||||
|
||||
static PLI_INT32 variable_cb_2(p_cb_data cause)
|
||||
{
|
||||
struct vcd_info* info = vcd_dmp_list;
|
||||
PLI_UINT64 now = timerec_to_time64(cause->time);
|
||||
|
||||
if (now != vcd_cur_time) {
|
||||
fstWriterEmitTimeChange(dump_file, now);
|
||||
vcd_cur_time = now;
|
||||
}
|
||||
|
||||
do {
|
||||
show_this_item(info);
|
||||
info->scheduled = 0;
|
||||
} while ((info = info->dmp_next) != 0);
|
||||
|
||||
vcd_dmp_list = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PLI_INT32 variable_cb_1(p_cb_data cause)
|
||||
{
|
||||
struct t_cb_data cb;
|
||||
struct vcd_info*info = (struct vcd_info*)cause->user_data;
|
||||
|
||||
if (dump_is_full) return 0;
|
||||
if (dump_is_off) return 0;
|
||||
if (dump_header_pending()) return 0;
|
||||
if (info->scheduled) return 0;
|
||||
|
||||
if ((dump_limit > 0) && fstWriterGetDumpSizeLimitReached(dump_file)) {
|
||||
dump_is_full = 1;
|
||||
vpi_printf("WARNING: Dump file limit (%ld bytes) "
|
||||
"exceeded.\n", dump_limit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!vcd_dmp_list) {
|
||||
cb = *cause;
|
||||
cb.reason = cbReadOnlySynch;
|
||||
cb.cb_rtn = variable_cb_2;
|
||||
vpi_register_cb(&cb);
|
||||
}
|
||||
|
||||
info->scheduled = 1;
|
||||
info->dmp_next = vcd_dmp_list;
|
||||
vcd_dmp_list = info;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PLI_INT32 dumpvars_cb(p_cb_data cause)
|
||||
{
|
||||
if (dumpvars_status != 1) return 0;
|
||||
|
||||
dumpvars_status = 2;
|
||||
|
||||
dumpvars_time = timerec_to_time64(cause->time);
|
||||
vcd_cur_time = dumpvars_time;
|
||||
|
||||
/* nothing to do for $enddefinitions $end */
|
||||
|
||||
if (!dump_is_off) {
|
||||
fstWriterEmitTimeChange(dump_file, dumpvars_time);
|
||||
/* nothing to do for $dumpvars... */
|
||||
vcd_checkpoint();
|
||||
/* ...nothing to do for $end */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PLI_INT32 finish_cb(p_cb_data cause)
|
||||
{
|
||||
struct vcd_info *cur, *next;
|
||||
|
||||
if (finish_status != 0) return 0;
|
||||
|
||||
finish_status = 1;
|
||||
|
||||
dumpvars_time = timerec_to_time64(cause->time);
|
||||
|
||||
if (!dump_is_off && !dump_is_full && dumpvars_time != vcd_cur_time) {
|
||||
fstWriterEmitTimeChange(dump_file, dumpvars_time);
|
||||
}
|
||||
|
||||
fstWriterClose(dump_file);
|
||||
|
||||
for (cur = vcd_list ; cur ; cur = next) {
|
||||
next = cur->next;
|
||||
free(cur);
|
||||
}
|
||||
vcd_list = 0;
|
||||
vcd_names_delete(&fst_tab);
|
||||
vcd_names_delete(&fst_var);
|
||||
nexus_ident_delete();
|
||||
free(dump_path);
|
||||
dump_path = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__inline__ static int install_dumpvars_callback(void)
|
||||
{
|
||||
struct t_cb_data cb;
|
||||
static struct t_vpi_time now;
|
||||
|
||||
if (dumpvars_status == 1) return 0;
|
||||
|
||||
if (dumpvars_status == 2) {
|
||||
vpi_printf("FST warning: $dumpvars ignored, previously"
|
||||
" called at simtime %" PLI_UINT64_FMT "\n",
|
||||
dumpvars_time);
|
||||
return 1;
|
||||
}
|
||||
|
||||
now.type = vpiSimTime;
|
||||
cb.time = &now;
|
||||
cb.reason = cbReadOnlySynch;
|
||||
cb.cb_rtn = dumpvars_cb;
|
||||
cb.user_data = 0x0;
|
||||
cb.obj = 0x0;
|
||||
|
||||
vpi_register_cb(&cb);
|
||||
|
||||
cb.reason = cbEndOfSimulation;
|
||||
cb.cb_rtn = finish_cb;
|
||||
|
||||
vpi_register_cb(&cb);
|
||||
|
||||
dumpvars_status = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PLI_INT32 sys_dumpoff_calltf(PLI_BYTE8*name)
|
||||
{
|
||||
s_vpi_time now;
|
||||
PLI_UINT64 now64;
|
||||
|
||||
if (dump_is_off) return 0;
|
||||
|
||||
dump_is_off = 1;
|
||||
|
||||
if (dump_file == 0) return 0;
|
||||
if (dump_header_pending()) return 0;
|
||||
|
||||
now.type = vpiSimTime;
|
||||
vpi_get_time(0, &now);
|
||||
now64 = timerec_to_time64(&now);
|
||||
|
||||
if (now64 > vcd_cur_time) {
|
||||
fstWriterEmitTimeChange(dump_file, now64);
|
||||
vcd_cur_time = now64;
|
||||
}
|
||||
|
||||
fstWriterEmitDumpActive(dump_file, 0); /* $dumpoff */
|
||||
vcd_checkpoint_x();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PLI_INT32 sys_dumpon_calltf(PLI_BYTE8*name)
|
||||
{
|
||||
s_vpi_time now;
|
||||
PLI_UINT64 now64;
|
||||
|
||||
if (!dump_is_off) return 0;
|
||||
|
||||
dump_is_off = 0;
|
||||
|
||||
if (dump_file == 0) return 0;
|
||||
if (dump_header_pending()) return 0;
|
||||
|
||||
now.type = vpiSimTime;
|
||||
vpi_get_time(0, &now);
|
||||
now64 = timerec_to_time64(&now);
|
||||
|
||||
if (now64 > vcd_cur_time) {
|
||||
fstWriterEmitTimeChange(dump_file, now64);
|
||||
vcd_cur_time = now64;
|
||||
}
|
||||
|
||||
fstWriterEmitDumpActive(dump_file, 1); /* $dumpon */
|
||||
vcd_checkpoint();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PLI_INT32 sys_dumpall_calltf(PLI_BYTE8*name)
|
||||
{
|
||||
s_vpi_time now;
|
||||
PLI_UINT64 now64;
|
||||
|
||||
if (dump_is_off) return 0;
|
||||
if (dump_file == 0) return 0;
|
||||
if (dump_header_pending()) return 0;
|
||||
|
||||
now.type = vpiSimTime;
|
||||
vpi_get_time(0, &now);
|
||||
now64 = timerec_to_time64(&now);
|
||||
|
||||
if (now64 > vcd_cur_time) {
|
||||
fstWriterEmitTimeChange(dump_file, now64);
|
||||
vcd_cur_time = now64;
|
||||
}
|
||||
|
||||
/* nothing to do for $dumpall... */
|
||||
vcd_checkpoint();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void open_dumpfile(vpiHandle callh)
|
||||
{
|
||||
if (dump_path == 0) dump_path = strdup("dump.fst");
|
||||
|
||||
dump_file = fstWriterCreate(dump_path, 1);
|
||||
|
||||
if (dump_file == 0) {
|
||||
vpi_printf("FST Error: %s:%d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("Unable to open %s for output.\n", dump_path);
|
||||
vpi_control(vpiFinish, 1);
|
||||
return;
|
||||
} else {
|
||||
int prec = vpi_get(vpiTimePrecision, 0);
|
||||
unsigned scale = 1;
|
||||
unsigned udx = 0;
|
||||
time_t walltime;
|
||||
char scale_buf[65];
|
||||
|
||||
vpi_printf("FST info: dumpfile %s opened for output.\n",
|
||||
dump_path);
|
||||
|
||||
time(&walltime);
|
||||
|
||||
assert(prec >= -15);
|
||||
while (prec < 0) {
|
||||
udx += 1;
|
||||
prec += 3;
|
||||
}
|
||||
while (prec > 0) {
|
||||
scale *= 10;
|
||||
prec -= 1;
|
||||
}
|
||||
|
||||
fstWriterSetDate(dump_file, asctime(localtime(&walltime)));
|
||||
fstWriterSetVersion(dump_file, "Icarus Verilog");
|
||||
sprintf(scale_buf, "\t%u%s\n", scale, units_names[udx]);
|
||||
fstWriterSetTimescaleFromString(dump_file, scale_buf);
|
||||
}
|
||||
}
|
||||
|
||||
static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
char *path;
|
||||
|
||||
/* $dumpfile must be called before $dumpvars starts! */
|
||||
if (dumpvars_status != 0) {
|
||||
char msg [64];
|
||||
snprintf(msg, 64, "FST warning: %s:%d:",
|
||||
vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("%s %s called after $dumpvars started,\n", msg, name);
|
||||
vpi_printf("%*s using existing file (%s).\n",
|
||||
(int) strlen(msg), " ", dump_path);
|
||||
vpi_free_object(argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
path = get_filename(callh, name, vpi_scan(argv));
|
||||
vpi_free_object(argv);
|
||||
if (! path) return 0;
|
||||
|
||||
if (dump_path) {
|
||||
vpi_printf("FST warning: %s:%d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("Overriding dump file %s with %s.\n", dump_path, path);
|
||||
free(dump_path);
|
||||
}
|
||||
dump_path = path;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PLI_INT32 sys_dumpflush_calltf(PLI_BYTE8*name)
|
||||
{
|
||||
if (dump_file) fstWriterFlushContext(dump_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PLI_INT32 sys_dumplimit_calltf(PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
s_vpi_value val;
|
||||
|
||||
/* Get the value and set the dump limit. */
|
||||
val.format = vpiIntVal;
|
||||
vpi_get_value(vpi_scan(argv), &val);
|
||||
dump_limit = val.value.integer;
|
||||
fstWriterSetDumpSizeLimit(dump_file, dump_limit);
|
||||
|
||||
vpi_free_object(argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void scan_item(unsigned depth, vpiHandle item, int skip)
|
||||
{
|
||||
struct t_cb_data cb;
|
||||
struct vcd_info* info;
|
||||
|
||||
PLI_INT32 type;
|
||||
const char* name;
|
||||
const char* fullname;
|
||||
const char* prefix;
|
||||
const char *ident;
|
||||
fstHandle new_ident;
|
||||
int nexus_id;
|
||||
unsigned size;
|
||||
PLI_INT32 item_type;
|
||||
|
||||
/* list of types to iterate upon */
|
||||
int i;
|
||||
static int types[] = {
|
||||
/* Value */
|
||||
vpiNamedEvent,
|
||||
vpiNet,
|
||||
// vpiParameter,
|
||||
vpiReg,
|
||||
vpiVariables,
|
||||
/* Scope */
|
||||
vpiFunction,
|
||||
vpiModule,
|
||||
vpiNamedBegin,
|
||||
vpiNamedFork,
|
||||
vpiTask,
|
||||
-1
|
||||
};
|
||||
|
||||
/* Get the displayed type for the various $var and $scope types. */
|
||||
/* Not all of these are supported now, but they should be in a
|
||||
* future development version. */
|
||||
item_type = vpi_get(vpiType, item);
|
||||
switch (item_type) {
|
||||
case vpiNamedEvent: type = FST_VT_VCD_EVENT; break;
|
||||
case vpiIntegerVar: type = FST_VT_VCD_INTEGER; break;
|
||||
case vpiParameter: type = FST_VT_VCD_PARAMETER; break;
|
||||
/* Icarus converts realtime to real. */
|
||||
case vpiRealVar: type = FST_VT_VCD_REAL; break;
|
||||
case vpiMemoryWord:
|
||||
case vpiReg: type = FST_VT_VCD_REG; break;
|
||||
/* Icarus converts a time to a plain register. */
|
||||
case vpiTimeVar: type = FST_VT_VCD_TIME; break;
|
||||
case vpiNet:
|
||||
switch (vpi_get(vpiNetType, item)) {
|
||||
case vpiWand: type = FST_VT_VCD_WAND; break;
|
||||
case vpiWor: type = FST_VT_VCD_WOR; break;
|
||||
case vpiTri: type = FST_VT_VCD_TRI; break;
|
||||
case vpiTri0: type = FST_VT_VCD_TRI0; break;
|
||||
case vpiTri1: type = FST_VT_VCD_TRI1; break;
|
||||
case vpiTriReg: type = FST_VT_VCD_TRIREG; break;
|
||||
case vpiTriAnd: type = FST_VT_VCD_TRIAND; break;
|
||||
case vpiTriOr: type = FST_VT_VCD_TRIOR; break;
|
||||
case vpiSupply1: type = FST_VT_VCD_SUPPLY1; break;
|
||||
case vpiSupply0: type = FST_VT_VCD_SUPPLY0; break;
|
||||
default: type = FST_VT_VCD_WIRE; break;
|
||||
}
|
||||
break;
|
||||
|
||||
case vpiNamedBegin: type = FST_ST_VCD_BEGIN; break;
|
||||
case vpiNamedFork: type = FST_ST_VCD_FORK; break;
|
||||
case vpiFunction: type = FST_ST_VCD_FUNCTION; break;
|
||||
case vpiModule: type = FST_ST_VCD_MODULE; break;
|
||||
case vpiTask: type = FST_ST_VCD_TASK; break;
|
||||
|
||||
default:
|
||||
vpi_printf("FST warning: $dumpvars: Unsupported argument "
|
||||
"type (%s)\n", vpi_get_str(vpiType, item));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Do some special processing/checking on array words. Dumping
|
||||
* array words is an Icarus extension. */
|
||||
if (item_type == vpiMemoryWord) {
|
||||
/* Turn a non-constant array word select into a constant
|
||||
* word select. */
|
||||
if (vpi_get(vpiConstantSelect, item) == 0) {
|
||||
vpiHandle array = vpi_handle(vpiParent, item);
|
||||
PLI_INT32 idx = vpi_get(vpiIndex, item);
|
||||
item = vpi_handle_by_index(array, idx);
|
||||
}
|
||||
|
||||
/* An array word is implicitly escaped so look for an
|
||||
* escaped identifier that this could conflict with. */
|
||||
/* This does not work as expected since we always find at
|
||||
* least the array word. We likely need a custom routine. */
|
||||
if (vpi_get(vpiType, item) == vpiMemoryWord &&
|
||||
vpi_handle_by_name(vpi_get_str(vpiFullName, item), 0)) {
|
||||
vpi_printf("FST warning: array word %s will conflict "
|
||||
"with an escaped identifier.\n",
|
||||
vpi_get_str(vpiFullName, item));
|
||||
}
|
||||
}
|
||||
|
||||
fullname = vpi_get_str(vpiFullName, item);
|
||||
|
||||
/* Generate the $var or $scope commands. */
|
||||
switch (item_type) {
|
||||
case vpiParameter:
|
||||
vpi_printf("VCD sorry: $dumpvars: can not dump parameters.\n");
|
||||
break;
|
||||
|
||||
case vpiNamedEvent:
|
||||
case vpiIntegerVar:
|
||||
// case vpiParameter:
|
||||
case vpiRealVar:
|
||||
case vpiMemoryWord:
|
||||
case vpiReg:
|
||||
case vpiTimeVar:
|
||||
case vpiNet:
|
||||
|
||||
/* If we are skipping all signal or this is in an automatic
|
||||
* scope then just return. */
|
||||
if (skip || vpi_get(vpiAutomatic, item)) return;
|
||||
|
||||
/* Skip this signal if it has already been included.
|
||||
* This can only happen for implicitly given signals. */
|
||||
if (vcd_names_search(&fst_var, fullname)) return;
|
||||
|
||||
/* Declare the variable in the VCD file. */
|
||||
name = vpi_get_str(vpiName, item);
|
||||
prefix = is_escaped_id(name) ? "\\" : "";
|
||||
|
||||
/* Some signals can have an alias so handle that. */
|
||||
nexus_id = vpi_get(_vpiNexusId, item);
|
||||
|
||||
ident = 0;
|
||||
if (nexus_id) ident = find_nexus_ident(nexus_id);
|
||||
|
||||
/* Named events do not have a size, but other tools use
|
||||
* a size of 1 and some viewers do not accept a width of
|
||||
* zero so we will also use a width of one for events. */
|
||||
if (item_type == vpiNamedEvent) size = 1;
|
||||
else size = vpi_get(vpiSize, item);
|
||||
|
||||
|
||||
if (vpi_get(vpiSize, item) > 1
|
||||
|| vpi_get(vpiLeftRange, item) != 0)
|
||||
{
|
||||
int slen = strlen(name);
|
||||
char *buf = malloc(slen + 65);
|
||||
sprintf(buf, "%s [%i:%i]", name,
|
||||
(int)vpi_get(vpiLeftRange, item),
|
||||
(int)vpi_get(vpiRightRange, item));
|
||||
|
||||
|
||||
new_ident = fstWriterCreateVar(dump_file, type, FST_VD_IMPLICIT, size, buf, (fstHandle)ident);
|
||||
free(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
new_ident = fstWriterCreateVar(dump_file, type, FST_VD_IMPLICIT, size, name, (fstHandle)ident);
|
||||
}
|
||||
|
||||
if (!ident) {
|
||||
if (nexus_id) set_nexus_ident(nexus_id, (const char *)new_ident);
|
||||
|
||||
/* Add a callback for the signal. */
|
||||
info = malloc(sizeof(*info));
|
||||
|
||||
info->time.type = vpiSimTime;
|
||||
info->item = item;
|
||||
info->handle = new_ident;
|
||||
info->scheduled = 0;
|
||||
|
||||
cb.time = &info->time;
|
||||
cb.user_data = (char*)info;
|
||||
cb.value = NULL;
|
||||
cb.obj = item;
|
||||
cb.reason = cbValueChange;
|
||||
cb.cb_rtn = variable_cb_1;
|
||||
|
||||
info->dmp_next = 0;
|
||||
info->next = vcd_list;
|
||||
vcd_list = info;
|
||||
|
||||
info->cb = vpi_register_cb(&cb);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case vpiModule:
|
||||
case vpiNamedBegin:
|
||||
case vpiTask:
|
||||
case vpiFunction:
|
||||
case vpiNamedFork:
|
||||
|
||||
if (depth > 0) {
|
||||
int nskip = (vcd_names_search(&fst_tab, fullname) != 0);
|
||||
|
||||
/* We have to always scan the scope because the
|
||||
* depth could be different for this call. */
|
||||
if (nskip) {
|
||||
vpi_printf("FST warning: ignoring signals in "
|
||||
"previously scanned scope %s.\n", fullname);
|
||||
} else {
|
||||
vcd_names_add(&fst_tab, fullname);
|
||||
vcd_names_sort(&fst_tab);
|
||||
}
|
||||
|
||||
name = vpi_get_str(vpiName, item);
|
||||
fstWriterSetScope(dump_file, type, name, NULL);
|
||||
|
||||
for (i=0; types[i]>0; i++) {
|
||||
vpiHandle hand;
|
||||
vpiHandle argv = vpi_iterate(types[i], item);
|
||||
while (argv && (hand = vpi_scan(argv))) {
|
||||
scan_item(depth-1, hand, nskip);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sort any signals that we added above. */
|
||||
fstWriterSetUpscope(dump_file);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int draw_scope(vpiHandle item, vpiHandle callh)
|
||||
{
|
||||
int depth;
|
||||
const char *name;
|
||||
PLI_INT32 type;
|
||||
|
||||
vpiHandle scope = vpi_handle(vpiScope, item);
|
||||
if (!scope) return 0;
|
||||
|
||||
depth = 1 + draw_scope(scope, callh);
|
||||
name = vpi_get_str(vpiName, scope);
|
||||
|
||||
switch (vpi_get(vpiType, scope)) {
|
||||
case vpiNamedBegin: type = FST_ST_VCD_BEGIN; break;
|
||||
case vpiTask: type = FST_ST_VCD_TASK; break;
|
||||
case vpiFunction: type = FST_ST_VCD_FUNCTION; break;
|
||||
case vpiNamedFork: type = FST_ST_VCD_FORK; break;
|
||||
case vpiModule: type = FST_ST_VCD_MODULE; break;
|
||||
default:
|
||||
type = FST_ST_VCD_MODULE;
|
||||
vpi_printf("FST Error: %s:%d: $dumpvars: Unsupported scope "
|
||||
"type (%d)\n", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh),
|
||||
(int)vpi_get(vpiType, item));
|
||||
assert(0);
|
||||
}
|
||||
|
||||
fstWriterSetScope(dump_file, type, name, NULL);
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
vpiHandle item;
|
||||
s_vpi_value value;
|
||||
unsigned depth = 0;
|
||||
|
||||
if (dump_file == 0) {
|
||||
open_dumpfile(callh);
|
||||
if (dump_file == 0) {
|
||||
if (argv) vpi_free_object(argv);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (install_dumpvars_callback()) {
|
||||
if (argv) vpi_free_object(argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the depth if it exists. */
|
||||
if (argv) {
|
||||
value.format = vpiIntVal;
|
||||
vpi_get_value(vpi_scan(argv), &value);
|
||||
depth = value.value.integer;
|
||||
}
|
||||
if (!depth) depth = 10000;
|
||||
|
||||
/* This dumps all the modules in the design if none are given. */
|
||||
if (!argv || !(item = vpi_scan(argv))) {
|
||||
argv = vpi_iterate(vpiModule, 0x0);
|
||||
assert(argv); /* There must be at least one top level module. */
|
||||
item = vpi_scan(argv);
|
||||
}
|
||||
|
||||
for ( ; item; item = vpi_scan(argv)) {
|
||||
char *scname;
|
||||
const char *fullname;
|
||||
int add_var = 0;
|
||||
int dep;
|
||||
PLI_INT32 item_type = vpi_get(vpiType, item);
|
||||
|
||||
/* If this is a signal make sure it has not already
|
||||
* been included. */
|
||||
switch (item_type) {
|
||||
case vpiIntegerVar:
|
||||
case vpiMemoryWord:
|
||||
case vpiNamedEvent:
|
||||
case vpiNet:
|
||||
case vpiParameter:
|
||||
case vpiRealVar:
|
||||
case vpiReg:
|
||||
case vpiTimeVar:
|
||||
/* Warn if the variables scope (which includes the
|
||||
* variable) or the variable itself was already
|
||||
* included. A scope does not automatically include
|
||||
* memory words so do not check the scope for them. */
|
||||
scname = strdup(vpi_get_str(vpiFullName,
|
||||
vpi_handle(vpiScope, item)));
|
||||
fullname = vpi_get_str(vpiFullName, item);
|
||||
if (((item_type != vpiMemoryWord) &&
|
||||
vcd_names_search(&fst_tab, scname)) ||
|
||||
vcd_names_search(&fst_var, fullname)) {
|
||||
vpi_printf("FST warning: skipping signal %s, "
|
||||
"it was previously included.\n",
|
||||
fullname);
|
||||
free(scname);
|
||||
continue;
|
||||
} else {
|
||||
add_var = 1;
|
||||
}
|
||||
free(scname);
|
||||
}
|
||||
|
||||
dep = draw_scope(item, callh);
|
||||
|
||||
scan_item(depth, item, 0);
|
||||
|
||||
while (dep--) fstWriterSetUpscope(dump_file);
|
||||
|
||||
/* Add this signal to the variable list so we can verify it
|
||||
* is not included twice. This must be done after it has
|
||||
* been added */
|
||||
if (add_var) {
|
||||
vcd_names_add(&fst_var, vpi_get_str(vpiFullName, item));
|
||||
vcd_names_sort(&fst_var);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sys_fst_register()
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
vpiHandle res;
|
||||
|
||||
/* All the compiletf routines are located in vcd_priv.c. */
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpall";
|
||||
tf_data.calltf = sys_dumpall_calltf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpall";
|
||||
res = vpi_register_systf(&tf_data);
|
||||
vpip_make_systf_system_defined(res);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpfile";
|
||||
tf_data.calltf = sys_dumpfile_calltf;
|
||||
tf_data.compiletf = sys_one_string_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpfile";
|
||||
res = vpi_register_systf(&tf_data);
|
||||
vpip_make_systf_system_defined(res);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpflush";
|
||||
tf_data.calltf = sys_dumpflush_calltf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpflush";
|
||||
res = vpi_register_systf(&tf_data);
|
||||
vpip_make_systf_system_defined(res);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumplimit";
|
||||
tf_data.calltf = sys_dumplimit_calltf;
|
||||
tf_data.compiletf = sys_one_numeric_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumplimit";
|
||||
res = vpi_register_systf(&tf_data);
|
||||
vpip_make_systf_system_defined(res);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpoff";
|
||||
tf_data.calltf = sys_dumpoff_calltf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpoff";
|
||||
res = vpi_register_systf(&tf_data);
|
||||
vpip_make_systf_system_defined(res);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpon";
|
||||
tf_data.calltf = sys_dumpon_calltf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpon";
|
||||
res = vpi_register_systf(&tf_data);
|
||||
vpip_make_systf_system_defined(res);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpvars";
|
||||
tf_data.calltf = sys_dumpvars_calltf;
|
||||
tf_data.compiletf = sys_dumpvars_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpvars";
|
||||
res = vpi_register_systf(&tf_data);
|
||||
vpip_make_systf_system_defined(res);
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1999-2008 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -47,9 +47,11 @@ extern void sys_lxt_register();
|
|||
static void sys_lxt_register() { fputs("LXT support disabled since libbzip2 not available\n",stderr); exit(1); }
|
||||
#endif
|
||||
extern void sys_lxt2_register();
|
||||
extern void sys_fst_register();
|
||||
#else
|
||||
static void sys_lxt_register() { fputs("LXT support disabled since zlib not available\n",stderr); exit(1); }
|
||||
static void sys_lxt2_register() { fputs("LXT2 support disabled since zlib not available\n",stderr); exit(1); }
|
||||
static void sys_fst_register() { fputs("FST support disabled since zlib not available\n",stderr); exit(1); }
|
||||
#endif
|
||||
|
||||
static void sys_lxt_or_vcd_register()
|
||||
|
|
@ -78,7 +80,13 @@ static void sys_lxt_or_vcd_register()
|
|||
|
||||
for (idx = 0 ; idx < vlog_info.argc ; idx += 1) {
|
||||
|
||||
if (strcmp(vlog_info.argv[idx],"-lxt") == 0) {
|
||||
if (strcmp(vlog_info.argv[idx],"-fst") == 0) {
|
||||
dumper = "fst";
|
||||
|
||||
} else if (strcmp(vlog_info.argv[idx],"-fst-none") == 0) {
|
||||
dumper = "none";
|
||||
|
||||
} else if (strcmp(vlog_info.argv[idx],"-lxt") == 0) {
|
||||
dumper = "lxt";
|
||||
|
||||
} else if (strcmp(vlog_info.argv[idx],"-lxt-space") == 0) {
|
||||
|
|
@ -135,6 +143,12 @@ static void sys_lxt_or_vcd_register()
|
|||
else if (strcmp(dumper, "VCD") == 0)
|
||||
sys_vcd_register();
|
||||
|
||||
else if (strcmp(dumper, "fst") == 0)
|
||||
sys_fst_register();
|
||||
|
||||
else if (strcmp(dumper, "FST") == 0)
|
||||
sys_fst_register();
|
||||
|
||||
else if (strcmp(dumper, "lxt") == 0)
|
||||
sys_lxt_register();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.TH vvp 1 "April 17th, 2009" "" "Version %M.%m.%n %E"
|
||||
.TH vvp 1 "May 21st, 2010" "" "Version %M.%m.%n %E"
|
||||
.SH NAME
|
||||
vvp - Icarus Verilog vvp runtime engine
|
||||
|
||||
|
|
@ -102,10 +102,15 @@ space, and is written out incrementally. Thus, you can view lxt2 files
|
|||
while a simulation is still running (or paused) or if your simulation
|
||||
crashes or is killed, you still have a useful dump.
|
||||
|
||||
.TP 8
|
||||
.B -fst
|
||||
A modern dumping format this is both faster and more compact than the
|
||||
other dumping formats.
|
||||
|
||||
.TP 8
|
||||
.B -none
|
||||
This flag can be used by itself or appended to the end of the above
|
||||
dumpers (vcd/lxt/lxt2/lx2) to suppress all waveform output. This can
|
||||
dumpers (vcd/lxt/lxt2/lx2/fst) to suppress all waveform output. This can
|
||||
make long simulations run faster.
|
||||
|
||||
.TP 8
|
||||
|
|
@ -128,7 +133,7 @@ The vvp command also accepts some environment variables that control
|
|||
its behavior. These can be used to make semi-permanent changes.
|
||||
|
||||
.TP 8
|
||||
.B IVERILOG_DUMPER=\fIlxt|lxt2|lx2|vcd|none\fP
|
||||
.B IVERILOG_DUMPER=\fIfst|lxt|lxt2|lx2|vcd|none\fP
|
||||
This selects the output format for the waveform output. Normally,
|
||||
waveforms are dumped in vcd format, but this variable can be used to
|
||||
select lxt format, which is far more compact, though limited to
|
||||
|
|
@ -158,7 +163,7 @@ iverilog\-vpi(1),
|
|||
|
||||
.SH COPYRIGHT
|
||||
.nf
|
||||
Copyright \(co 2001\-2009 Stephen Williams
|
||||
Copyright \(co 2001\-2010 Stephen Williams
|
||||
|
||||
This document can be freely redistributed according to the terms of the
|
||||
GNU General Public License version 2.0
|
||||
|
|
|
|||
Loading…
Reference in New Issue