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:
Cary R 2010-05-21 15:04:17 -07:00 committed by Stephen Williams
parent 09d59d744d
commit f11ba81202
8 changed files with 5953 additions and 6 deletions

View File

@ -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

547
vpi/fastlz.c Normal file
View File

@ -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) */

107
vpi/fastlz.h Normal file
View File

@ -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 */

4186
vpi/fstapi.c Normal file

File diff suppressed because it is too large Load Diff

219
vpi/fstapi.h Normal file
View File

@ -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

868
vpi/sys_fst.c Normal file
View File

@ -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);
}

View File

@ -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();

View File

@ -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