4378 lines
98 KiB
C
4378 lines
98 KiB
C
/*
|
|
* Copyright (c) 2009-2010 Tony Bybell.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#include "fstapi.h"
|
|
#include "fastlz.h"
|
|
|
|
#undef FST_DEBUG
|
|
|
|
#define FST_BREAK_SIZE (32 * 1024 * 1024)
|
|
#define FST_WRITER_STR "fstWriter"
|
|
#define FST_ID_NAM_SIZ (512)
|
|
#define FST_DOUBLE_ENDTEST (2.7182818284590452354)
|
|
#define FST_HDR_SIM_VERSION_SIZE (128)
|
|
#define FST_HDR_DATE_SIZE (128)
|
|
#define FST_GZIO_LEN (32768)
|
|
|
|
|
|
#if defined(__i386__) || defined(__x86_64__) || defined(_AIX)
|
|
#define FST_DO_MISALIGNED_OPS
|
|
#endif
|
|
|
|
#if defined(__APPLE__) && defined(__MACH__)
|
|
#define FST_MACOSX
|
|
#endif
|
|
|
|
#if defined(__CYGWIN__) && defined(__GNUC__)
|
|
#define FST_USE_FWRITE_COMBINING
|
|
#endif
|
|
|
|
|
|
/***********************/
|
|
/*** ***/
|
|
/*** common function ***/
|
|
/*** ***/
|
|
/***********************/
|
|
|
|
#ifdef __MINGW32__
|
|
#include <io.h>
|
|
#define ftello ftell
|
|
#define fseeko fseek
|
|
#endif
|
|
|
|
|
|
/* the recoded "extra" values... */
|
|
#define FST_RCV_X (1 | (0<<1))
|
|
#define FST_RCV_Z (1 | (1<<1))
|
|
#define FST_RCV_H (1 | (2<<1))
|
|
#define FST_RCV_U (1 | (3<<1))
|
|
#define FST_RCV_W (1 | (4<<1))
|
|
#define FST_RCV_L (1 | (5<<1))
|
|
#define FST_RCV_D (1 | (6<<1))
|
|
|
|
#define FST_RCV_STR "xzhuwl-?"
|
|
/* 01234567 */
|
|
|
|
|
|
/*
|
|
* to remove warn_unused_result compile time messages
|
|
* (in the future there needs to be results checking)
|
|
*/
|
|
static size_t fstFread(void *buf, size_t siz, size_t cnt, FILE *fp)
|
|
{
|
|
return(fread(buf, siz, cnt, fp));
|
|
}
|
|
|
|
static size_t fstFwrite(const void *buf, size_t siz, size_t cnt, FILE *fp)
|
|
{
|
|
return(fwrite(buf, siz, cnt, fp));
|
|
}
|
|
|
|
static int fstFtruncate(int fd, off_t length)
|
|
{
|
|
return(ftruncate(fd, length));
|
|
}
|
|
|
|
|
|
/*
|
|
* mmap compatibility
|
|
*/
|
|
#if defined __CYGWIN__ || defined __MINGW32__
|
|
#include <limits.h>
|
|
#define fstMmap(__addr,__len,__prot,__flags,__fd,__off) fstMmap2((__len), (__fd), (__off))
|
|
#define fstMunmap(__addr,__len) free(__addr)
|
|
|
|
static void *fstMmap2(size_t __len, int __fd, off_t __off)
|
|
{
|
|
unsigned char *pnt = malloc(__len);
|
|
off_t cur_offs = lseek(__fd, 0, SEEK_CUR);
|
|
size_t i;
|
|
|
|
lseek(__fd, 0, SEEK_SET);
|
|
for(i=0;i<__len;i+=SSIZE_MAX)
|
|
{
|
|
read(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i));
|
|
}
|
|
lseek(__fd, cur_offs, SEEK_SET);
|
|
return(pnt);
|
|
}
|
|
#else
|
|
#include <sys/mman.h>
|
|
#if defined(__SUNPRO_C)
|
|
#define FST_CADDR_T_CAST (caddr_t)
|
|
#else
|
|
#define FST_CADDR_T_CAST
|
|
#endif
|
|
#define fstMmap(__addr,__len,__prot,__flags,__fd,__off) (void*)mmap(FST_CADDR_T_CAST (__addr),(__len),(__prot),(__flags),(__fd),(__off))
|
|
#define fstMunmap(__addr,__len) { if(__addr) munmap(FST_CADDR_T_CAST (__addr),(__len)); }
|
|
#endif
|
|
|
|
|
|
/*
|
|
* regular and variable-length integer access functions
|
|
*/
|
|
#ifdef FST_DO_MISALIGNED_OPS
|
|
#define fstGetUint32(x) (*(uint32_t *)(x))
|
|
#define fstWriterSetUint32(x,y) (*(uint32_t *)(x)) = (y)
|
|
#else
|
|
static uint32_t fstGetUint32(unsigned char *mem)
|
|
{
|
|
uint32_t u32;
|
|
unsigned char *buf = (unsigned char *)(&u32);
|
|
|
|
buf[0] = mem[0];
|
|
buf[1] = mem[1];
|
|
buf[2] = mem[2];
|
|
buf[3] = mem[3];
|
|
|
|
return(*(uint32_t *)buf);
|
|
}
|
|
|
|
|
|
static void fstWriterSetUint32(unsigned char *mem, uint32_t u32)
|
|
{
|
|
unsigned char *buf = (unsigned char *)(&u32);
|
|
|
|
mem[0] = buf[0];
|
|
mem[1] = buf[1];
|
|
mem[2] = buf[2];
|
|
mem[3] = buf[3];
|
|
}
|
|
#endif
|
|
|
|
|
|
static int fstWriterUint64(FILE *handle, uint64_t v)
|
|
{
|
|
unsigned char buf[8];
|
|
int i;
|
|
|
|
for(i=7;i>=0;i--)
|
|
{
|
|
buf[i] = v & 0xff;
|
|
v >>= 8;
|
|
}
|
|
|
|
fstFwrite(buf, 8, 1, handle);
|
|
return(8);
|
|
}
|
|
|
|
|
|
static uint64_t fstReaderUint64(FILE *f)
|
|
{
|
|
uint64_t val = 0;
|
|
unsigned char buf[sizeof(uint64_t)];
|
|
int i;
|
|
|
|
fstFread(buf, sizeof(uint64_t), 1, f);
|
|
for(i=0;i<sizeof(uint64_t);i++)
|
|
{
|
|
val <<= 8;
|
|
val |= buf[i];
|
|
}
|
|
|
|
return(val);
|
|
}
|
|
|
|
|
|
static uint32_t fstGetVarint32(unsigned char *mem, int *skiplen)
|
|
{
|
|
unsigned char *mem_orig = mem;
|
|
uint32_t rc = 0;
|
|
while(*mem & 0x80)
|
|
{
|
|
mem++;
|
|
}
|
|
|
|
*skiplen = mem - mem_orig + 1;
|
|
for(;;)
|
|
{
|
|
rc <<= 7;
|
|
rc |= (uint32_t)(*mem & 0x7f);
|
|
if(mem == mem_orig)
|
|
{
|
|
break;
|
|
}
|
|
mem--;
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
static uint32_t fstGetVarint32NoSkip(unsigned char *mem)
|
|
{
|
|
unsigned char *mem_orig = mem;
|
|
uint32_t rc = 0;
|
|
while(*mem & 0x80)
|
|
{
|
|
mem++;
|
|
}
|
|
|
|
for(;;)
|
|
{
|
|
rc <<= 7;
|
|
rc |= (uint32_t)(*mem & 0x7f);
|
|
if(mem == mem_orig)
|
|
{
|
|
break;
|
|
}
|
|
mem--;
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
static unsigned char *fstCopyVarint32ToLeft(unsigned char *pnt, uint32_t v)
|
|
{
|
|
unsigned char buf[5];
|
|
unsigned char *spnt = buf;
|
|
uint32_t nxt;
|
|
|
|
while((nxt = v>>7))
|
|
{
|
|
*(spnt++) = (v&0x7f) | 0x80;
|
|
v = nxt;
|
|
}
|
|
*(spnt++) = (v&0x7f);
|
|
|
|
do {
|
|
*(--pnt) = *(--spnt);
|
|
} while(spnt != buf);
|
|
|
|
return(pnt);
|
|
}
|
|
|
|
|
|
static uint64_t fstGetVarint64(unsigned char *mem, int *skiplen)
|
|
{
|
|
unsigned char *mem_orig = mem;
|
|
uint64_t rc = 0;
|
|
while(*mem & 0x80)
|
|
{
|
|
mem++;
|
|
}
|
|
|
|
*skiplen = mem - mem_orig + 1;
|
|
for(;;)
|
|
{
|
|
rc <<= 7;
|
|
rc |= (uint64_t)(*mem & 0x7f);
|
|
if(mem == mem_orig)
|
|
{
|
|
break;
|
|
}
|
|
mem--;
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
static uint32_t fstReaderVarint32(FILE *f)
|
|
{
|
|
unsigned char buf[5];
|
|
unsigned char *mem = buf;
|
|
uint32_t rc = 0;
|
|
int ch;
|
|
|
|
do
|
|
{
|
|
ch = fgetc(f);
|
|
*(mem++) = ch;
|
|
} while(ch & 0x80);
|
|
mem--;
|
|
|
|
for(;;)
|
|
{
|
|
rc <<= 7;
|
|
rc |= (uint32_t)(*mem & 0x7f);
|
|
if(mem == buf)
|
|
{
|
|
break;
|
|
}
|
|
mem--;
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
static uint32_t fstReaderVarint32WithSkip(FILE *f, uint32_t *skiplen)
|
|
{
|
|
unsigned char buf[5];
|
|
unsigned char *mem = buf;
|
|
uint32_t rc = 0;
|
|
int ch;
|
|
|
|
do
|
|
{
|
|
ch = fgetc(f);
|
|
*(mem++) = ch;
|
|
} while(ch & 0x80);
|
|
*skiplen = mem - buf;
|
|
mem--;
|
|
|
|
for(;;)
|
|
{
|
|
rc <<= 7;
|
|
rc |= (uint32_t)(*mem & 0x7f);
|
|
if(mem == buf)
|
|
{
|
|
break;
|
|
}
|
|
mem--;
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
static uint64_t fstReaderVarint64(FILE *f)
|
|
{
|
|
unsigned char buf[16];
|
|
unsigned char *mem = buf;
|
|
uint64_t rc = 0;
|
|
int ch;
|
|
|
|
do
|
|
{
|
|
ch = fgetc(f);
|
|
*(mem++) = ch;
|
|
} while(ch & 0x80);
|
|
mem--;
|
|
|
|
for(;;)
|
|
{
|
|
rc <<= 7;
|
|
rc |= (uint64_t)(*mem & 0x7f);
|
|
if(mem == buf)
|
|
{
|
|
break;
|
|
}
|
|
mem--;
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
static int fstWriterVarint(FILE *handle, uint64_t v)
|
|
{
|
|
uint64_t nxt;
|
|
unsigned char buf[10]; /* ceil(64/7) = 10 */
|
|
unsigned char *pnt = buf;
|
|
int len;
|
|
|
|
while((nxt = v>>7))
|
|
{
|
|
*(pnt++) = (v&0x7f) | 0x80;
|
|
v = nxt;
|
|
}
|
|
*(pnt++) = (v&0x7f);
|
|
|
|
len = pnt-buf;
|
|
fstFwrite(buf, len, 1, handle);
|
|
return(len);
|
|
}
|
|
|
|
#ifndef FST_USE_FWRITE_COMBINING
|
|
static int fstWriterUint32WithVarint(FILE *handle, uint32_t *u, uint64_t v)
|
|
{
|
|
uint64_t nxt;
|
|
unsigned char buf[10 + sizeof(uint32_t)];
|
|
unsigned char *pnt = buf + sizeof(uint32_t);
|
|
int len;
|
|
|
|
memcpy(buf, u, sizeof(uint32_t));
|
|
|
|
while((nxt = v>>7))
|
|
{
|
|
*(pnt++) = (v&0x7f) | 0x80;
|
|
v = nxt;
|
|
}
|
|
*(pnt++) = (v&0x7f);
|
|
|
|
len = pnt-buf;
|
|
fstFwrite(buf, len, 1, handle);
|
|
return(len);
|
|
}
|
|
#else
|
|
static int fstWriterUint32WithVarint(FILE *handle, uint32_t *u, uint64_t v, const void *dbuf, size_t siz)
|
|
{
|
|
uint64_t nxt;
|
|
unsigned char buf[10 + sizeof(uint32_t) + siz]; /* gcc extension ok for cygwin */
|
|
unsigned char *pnt = buf + sizeof(uint32_t);
|
|
int len;
|
|
|
|
memcpy(buf, u, sizeof(uint32_t));
|
|
|
|
while((nxt = v>>7))
|
|
{
|
|
*(pnt++) = (v&0x7f) | 0x80;
|
|
v = nxt;
|
|
}
|
|
*(pnt++) = (v&0x7f);
|
|
memcpy(pnt, dbuf, siz);
|
|
|
|
len = pnt-buf + siz;
|
|
fstFwrite(buf, len, 1, handle);
|
|
return(len);
|
|
}
|
|
#endif
|
|
|
|
/***********************/
|
|
/*** ***/
|
|
/*** writer function ***/
|
|
/*** ***/
|
|
/***********************/
|
|
|
|
/*
|
|
* private structs
|
|
*/
|
|
struct fstBlackoutChain
|
|
{
|
|
struct fstBlackoutChain *next;
|
|
uint64_t tim;
|
|
unsigned active : 1;
|
|
};
|
|
|
|
|
|
struct fstWriterContext
|
|
{
|
|
FILE *handle;
|
|
FILE *hier_handle;
|
|
FILE *geom_handle;
|
|
FILE *valpos_handle;
|
|
FILE *curval_handle;
|
|
FILE *vchn_handle;
|
|
FILE *tchn_handle;
|
|
|
|
off_t hier_file_len;
|
|
|
|
uint32_t *valpos_mem;
|
|
unsigned char *curval_mem;
|
|
|
|
char *filename;
|
|
|
|
fstHandle maxhandle;
|
|
fstHandle numsigs;
|
|
uint32_t maxvalpos;
|
|
|
|
unsigned vc_emitted : 1;
|
|
unsigned is_initial_time : 1;
|
|
unsigned fastpack : 1;
|
|
|
|
off_t section_header_truncpos;
|
|
uint32_t tchn_cnt, tchn_idx;
|
|
uint64_t curtime;
|
|
uint64_t firsttime;
|
|
off_t vchn_siz;
|
|
|
|
uint32_t secnum;
|
|
off_t section_start;
|
|
|
|
uint32_t numscopes;
|
|
double nan; /* nan value for uninitialized doubles */
|
|
|
|
struct fstBlackoutChain *blackout_head;
|
|
struct fstBlackoutChain *blackout_curr;
|
|
uint32_t num_blackouts;
|
|
|
|
uint64_t dump_size_limit;
|
|
|
|
unsigned compress_hier : 1;
|
|
unsigned repack_on_close : 1;
|
|
unsigned skip_writing_section_hdr : 1;
|
|
unsigned size_limit_locked : 1;
|
|
unsigned section_header_only : 1;
|
|
|
|
/* should really be semaphores, but are bytes to cut down on read-modify-write window size */
|
|
unsigned char already_in_flush; /* in case control-c handlers interrupt */
|
|
unsigned char already_in_close; /* in case control-c handlers interrupt */
|
|
};
|
|
|
|
|
|
/*
|
|
* header bytes, write here so defines are set up before anything else
|
|
* that needs to use them
|
|
*/
|
|
static void fstWriterEmitHdrBytes(struct fstWriterContext *xc)
|
|
{
|
|
char vbuf[FST_HDR_SIM_VERSION_SIZE];
|
|
char dbuf[FST_HDR_DATE_SIZE];
|
|
double endtest = FST_DOUBLE_ENDTEST;
|
|
time_t walltime;
|
|
|
|
#define FST_HDR_OFFS_TAG (0)
|
|
fputc(FST_BL_HDR, xc->handle); /* +0 tag */
|
|
|
|
#define FST_HDR_OFFS_SECLEN (FST_HDR_OFFS_TAG + 1)
|
|
fstWriterUint64(xc->handle, 329); /* +1 section length */
|
|
|
|
#define FST_HDR_OFFS_START_TIME (FST_HDR_OFFS_SECLEN + 8)
|
|
fstWriterUint64(xc->handle, 0); /* +9 start time */
|
|
|
|
#define FST_HDR_OFFS_END_TIME (FST_HDR_OFFS_START_TIME + 8)
|
|
fstWriterUint64(xc->handle, 0); /* +17 end time */
|
|
|
|
#define FST_HDR_OFFS_ENDIAN_TEST (FST_HDR_OFFS_END_TIME + 8)
|
|
fstFwrite(&endtest, 8, 1, xc->handle); /* +25 endian test for reals */
|
|
|
|
#define FST_HDR_OFFS_MEM_USED (FST_HDR_OFFS_ENDIAN_TEST + 8)
|
|
fstWriterUint64(xc->handle, FST_BREAK_SIZE); /* +33 memory used by writer */
|
|
|
|
#define FST_HDR_OFFS_NUM_SCOPES (FST_HDR_OFFS_MEM_USED + 8)
|
|
fstWriterUint64(xc->handle, 0); /* +41 scope creation count */
|
|
|
|
#define FST_HDR_OFFS_NUM_VARS (FST_HDR_OFFS_NUM_SCOPES + 8)
|
|
fstWriterUint64(xc->handle, 0); /* +49 var creation count */
|
|
|
|
#define FST_HDR_OFFS_MAXHANDLE (FST_HDR_OFFS_NUM_VARS + 8)
|
|
fstWriterUint64(xc->handle, 0); /* +57 max var idcode */
|
|
|
|
#define FST_HDR_OFFS_SECTION_CNT (FST_HDR_OFFS_MAXHANDLE + 8)
|
|
fstWriterUint64(xc->handle, 0); /* +65 vc section count */
|
|
|
|
#define FST_HDR_OFFS_TIMESCALE (FST_HDR_OFFS_SECTION_CNT + 8)
|
|
fputc((-9)&255, xc->handle); /* +73 timescale 1ns */
|
|
|
|
#define FST_HDR_OFFS_SIM_VERSION (FST_HDR_OFFS_TIMESCALE + 1)
|
|
memset(vbuf, 0, FST_HDR_SIM_VERSION_SIZE);
|
|
strcpy(vbuf, FST_WRITER_STR);
|
|
fstFwrite(vbuf, FST_HDR_SIM_VERSION_SIZE, 1, xc->handle); /* +74 version */
|
|
|
|
#define FST_HDR_OFFS_DATE (FST_HDR_OFFS_SIM_VERSION + FST_HDR_SIM_VERSION_SIZE)
|
|
memset(dbuf, 0, FST_HDR_DATE_SIZE);
|
|
time(&walltime);
|
|
strcpy(dbuf, asctime(localtime(&walltime)));
|
|
fstFwrite(dbuf, FST_HDR_DATE_SIZE, 1, xc->handle); /* +202 date */
|
|
|
|
#define FST_HDR_LENGTH (FST_HDR_OFFS_DATE + FST_HDR_DATE_SIZE)
|
|
/* +330 next section starts here */
|
|
fflush(xc->handle);
|
|
}
|
|
|
|
|
|
/*
|
|
* mmap functions
|
|
*/
|
|
static void fstWriterCreateMmaps(struct fstWriterContext *xc)
|
|
{
|
|
off_t curpos = ftello(xc->handle);
|
|
|
|
fflush(xc->hier_handle);
|
|
|
|
/* write out intermediate header */
|
|
fseeko(xc->handle, FST_HDR_OFFS_START_TIME, SEEK_SET);
|
|
fstWriterUint64(xc->handle, xc->firsttime);
|
|
fstWriterUint64(xc->handle, xc->curtime);
|
|
fseeko(xc->handle, FST_HDR_OFFS_NUM_SCOPES, SEEK_SET);
|
|
fstWriterUint64(xc->handle, xc->numscopes);
|
|
fstWriterUint64(xc->handle, xc->numsigs);
|
|
fstWriterUint64(xc->handle, xc->maxhandle);
|
|
fstWriterUint64(xc->handle, xc->secnum);
|
|
fseeko(xc->handle, curpos, SEEK_SET);
|
|
fflush(xc->handle);
|
|
|
|
/* do mappings */
|
|
if(!xc->valpos_mem)
|
|
{
|
|
fflush(xc->valpos_handle);
|
|
xc->valpos_mem = fstMmap(NULL, xc->maxhandle * 4 * sizeof(uint32_t), PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->valpos_handle), 0);
|
|
}
|
|
if(!xc->curval_mem)
|
|
{
|
|
fflush(xc->curval_handle);
|
|
xc->curval_mem = fstMmap(NULL, xc->maxvalpos, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->curval_handle), 0);
|
|
}
|
|
}
|
|
|
|
|
|
static void fstDestroyMmaps(struct fstWriterContext *xc, int is_closing)
|
|
{
|
|
fstMunmap(xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t));
|
|
xc->valpos_mem = NULL;
|
|
|
|
#if defined __CYGWIN__ || defined __MINGW32__
|
|
if(xc->curval_mem)
|
|
{
|
|
if(!is_closing) /* need to flush out for next emulated mmap() read */
|
|
{
|
|
unsigned char *pnt = xc->curval_mem;
|
|
int __fd = fileno(xc->curval_handle);
|
|
off_t cur_offs = lseek(__fd, 0, SEEK_CUR);
|
|
size_t i;
|
|
size_t __len = xc->maxvalpos;
|
|
|
|
lseek(__fd, 0, SEEK_SET);
|
|
for(i=0;i<__len;i+=SSIZE_MAX)
|
|
{
|
|
write(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i));
|
|
}
|
|
lseek(__fd, cur_offs, SEEK_SET);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
fstMunmap(xc->curval_mem, xc->maxvalpos);
|
|
xc->curval_mem = NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* file creation and close
|
|
*/
|
|
void *fstWriterCreate(const char *nam, int use_compressed_hier)
|
|
{
|
|
struct fstWriterContext *xc = calloc(1, sizeof(struct fstWriterContext));
|
|
|
|
xc->compress_hier = use_compressed_hier;
|
|
|
|
if((!nam)||(!(xc->handle=fopen(nam, "w+b"))))
|
|
{
|
|
free(xc);
|
|
xc=NULL;
|
|
}
|
|
else
|
|
{
|
|
int flen = strlen(nam);
|
|
char *hf = calloc(1, flen + 6);
|
|
|
|
memcpy(hf, nam, flen);
|
|
strcpy(hf + flen, ".hier");
|
|
xc->hier_handle = fopen(hf, "w+b");
|
|
|
|
xc->geom_handle = tmpfile(); /* .geom */
|
|
xc->valpos_handle = tmpfile(); /* .offs */
|
|
xc->curval_handle = tmpfile(); /* .bits */
|
|
xc->vchn_handle = tmpfile(); /* .vchn */
|
|
xc->tchn_handle = tmpfile(); /* .tchn */
|
|
|
|
free(hf);
|
|
if(xc->hier_handle && xc->geom_handle && xc->valpos_handle && xc->curval_handle && xc->vchn_handle && xc->tchn_handle)
|
|
{
|
|
xc->filename = strdup(nam);
|
|
xc->is_initial_time = 1;
|
|
|
|
fstWriterEmitHdrBytes(xc);
|
|
xc->nan = strtod("NaN", NULL);
|
|
}
|
|
else
|
|
{
|
|
if(xc->hier_handle) fclose(xc->hier_handle);
|
|
if(xc->geom_handle) fclose(xc->geom_handle);
|
|
if(xc->valpos_handle) fclose(xc->valpos_handle);
|
|
if(xc->curval_handle) fclose(xc->curval_handle);
|
|
if(xc->vchn_handle) fclose(xc->vchn_handle);
|
|
if(xc->tchn_handle) fclose(xc->tchn_handle);
|
|
free(xc);
|
|
xc=NULL;
|
|
}
|
|
}
|
|
|
|
return(xc);
|
|
}
|
|
|
|
|
|
void fstWriterClose(void *ctx)
|
|
{
|
|
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
|
|
if(xc && !xc->already_in_close && !xc->already_in_flush)
|
|
{
|
|
unsigned char *tmem;
|
|
off_t fixup_offs, tlen, hlen;
|
|
|
|
xc->already_in_close = 1; /* never need to zero this out as it is freed at bottom */
|
|
|
|
if(xc->section_header_only && xc->section_header_truncpos)
|
|
{
|
|
fstFtruncate(fileno(xc->handle), xc->section_header_truncpos);
|
|
fseeko(xc->handle, xc->section_header_truncpos, SEEK_SET);
|
|
xc->section_header_only = 0;
|
|
}
|
|
|
|
xc->skip_writing_section_hdr = 1;
|
|
if(!xc->size_limit_locked)
|
|
{
|
|
if(xc->is_initial_time) /* simulation time never advanced so mock up the changes as time zero ones */
|
|
{
|
|
fstHandle dupe_idx;
|
|
|
|
fstWriterEmitTimeChange(xc, 0); /* emit some time change just to have one */
|
|
for(dupe_idx = 0; dupe_idx < xc->maxhandle; dupe_idx++) /* now clone the values */
|
|
{
|
|
fstWriterEmitValueChange(xc, dupe_idx+1, xc->curval_mem + xc->valpos_mem[4*dupe_idx]);
|
|
}
|
|
}
|
|
fstWriterFlushContext(xc);
|
|
}
|
|
fstDestroyMmaps(xc, 1);
|
|
|
|
/* write out geom section */
|
|
fflush(xc->geom_handle);
|
|
tlen = ftello(xc->geom_handle);
|
|
tmem = fstMmap(NULL, tlen, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->geom_handle), 0);
|
|
if(tmem)
|
|
{
|
|
unsigned long destlen = tlen;
|
|
unsigned char *dmem = malloc(destlen);
|
|
int rc = compress2(dmem, &destlen, tmem, tlen, 9);
|
|
|
|
if((rc != Z_OK) || (destlen > tlen))
|
|
{
|
|
destlen = tlen;
|
|
}
|
|
|
|
fixup_offs = ftello(xc->handle);
|
|
fputc(FST_BL_SKIP, xc->handle); /* temporary tag */
|
|
fstWriterUint64(xc->handle, destlen + 24); /* section length */
|
|
fstWriterUint64(xc->handle, tlen); /* uncompressed */
|
|
/* compressed len is section length - 24 */
|
|
fstWriterUint64(xc->handle, xc->maxhandle); /* maxhandle */
|
|
fstFwrite((destlen != tlen) ? dmem : tmem, destlen, 1, xc->handle);
|
|
fflush(xc->handle);
|
|
|
|
fseeko(xc->handle, fixup_offs, SEEK_SET);
|
|
fputc(FST_BL_GEOM, xc->handle); /* actual tag */
|
|
|
|
fseeko(xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */
|
|
fflush(xc->handle);
|
|
|
|
free(dmem);
|
|
fstMunmap(tmem, tlen);
|
|
}
|
|
|
|
if(xc->num_blackouts)
|
|
{
|
|
uint64_t cur_bl = 0;
|
|
off_t bpos, eos;
|
|
uint32_t i;
|
|
|
|
fixup_offs = ftello(xc->handle);
|
|
fputc(FST_BL_SKIP, xc->handle); /* temporary tag */
|
|
bpos = fixup_offs + 1;
|
|
fstWriterUint64(xc->handle, 0); /* section length */
|
|
fstWriterVarint(xc->handle, xc->num_blackouts);
|
|
|
|
for(i=0;i<xc->num_blackouts;i++)
|
|
{
|
|
fputc(xc->blackout_head->active, xc->handle);
|
|
fstWriterVarint(xc->handle, xc->blackout_head->tim - cur_bl);
|
|
cur_bl = xc->blackout_head->tim;
|
|
xc->blackout_curr = xc->blackout_head->next;
|
|
free(xc->blackout_head);
|
|
xc->blackout_head = xc->blackout_curr;
|
|
}
|
|
|
|
eos = ftello(xc->handle);
|
|
fseeko(xc->handle, bpos, SEEK_SET);
|
|
fstWriterUint64(xc->handle, eos - bpos);
|
|
fflush(xc->handle);
|
|
|
|
fseeko(xc->handle, fixup_offs, SEEK_SET);
|
|
fputc(FST_BL_BLACKOUT, xc->handle); /* actual tag */
|
|
|
|
fseeko(xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */
|
|
fflush(xc->handle);
|
|
}
|
|
|
|
if(xc->compress_hier)
|
|
{
|
|
unsigned char *mem = malloc(FST_GZIO_LEN);
|
|
off_t hl, eos;
|
|
gzFile zhandle;
|
|
int zfd;
|
|
#ifndef __MINGW32__
|
|
char *fnam = malloc(strlen(xc->filename) + 5 + 1);
|
|
#endif
|
|
|
|
fixup_offs = ftello(xc->handle);
|
|
fputc(FST_BL_SKIP, xc->handle); /* temporary tag */
|
|
hlen = ftello(xc->handle);
|
|
fstWriterUint64(xc->handle, 0); /* section length */
|
|
fstWriterUint64(xc->handle, xc->hier_file_len); /* uncompressed length */
|
|
|
|
fflush(xc->handle);
|
|
zfd = dup(fileno(xc->handle));
|
|
zhandle = gzdopen(zfd, "wb4");
|
|
if(zhandle)
|
|
{
|
|
fseeko(xc->hier_handle, 0, SEEK_SET);
|
|
for(hl = 0; hl < xc->hier_file_len; hl += FST_GZIO_LEN)
|
|
{
|
|
unsigned len = ((xc->hier_file_len - hl) > FST_GZIO_LEN) ? FST_GZIO_LEN : (xc->hier_file_len - hl);
|
|
fstFread(mem, len, 1, xc->hier_handle);
|
|
gzwrite(zhandle, mem, len);
|
|
}
|
|
gzclose(zhandle);
|
|
}
|
|
else
|
|
{
|
|
close(zfd);
|
|
}
|
|
free(mem);
|
|
|
|
fseeko(xc->handle, 0, SEEK_END);
|
|
eos = ftello(xc->handle);
|
|
fseeko(xc->handle, hlen, SEEK_SET);
|
|
fstWriterUint64(xc->handle, eos - hlen);
|
|
fflush(xc->handle);
|
|
|
|
fseeko(xc->handle, fixup_offs, SEEK_SET);
|
|
fputc(FST_BL_HIER, xc->handle); /* actual tag */
|
|
|
|
fseeko(xc->handle, 0, SEEK_END); /* move file pointer to end for any section adds */
|
|
fflush(xc->handle);
|
|
|
|
#ifndef __MINGW32__
|
|
sprintf(fnam, "%s.hier", xc->filename);
|
|
unlink(fnam);
|
|
free(fnam);
|
|
#endif
|
|
}
|
|
|
|
/* finalize out header */
|
|
fseeko(xc->handle, FST_HDR_OFFS_START_TIME, SEEK_SET);
|
|
fstWriterUint64(xc->handle, xc->firsttime);
|
|
fstWriterUint64(xc->handle, xc->curtime);
|
|
fseeko(xc->handle, FST_HDR_OFFS_NUM_SCOPES, SEEK_SET);
|
|
fstWriterUint64(xc->handle, xc->numscopes);
|
|
fstWriterUint64(xc->handle, xc->numsigs);
|
|
fstWriterUint64(xc->handle, xc->maxhandle);
|
|
fstWriterUint64(xc->handle, xc->secnum);
|
|
fflush(xc->handle);
|
|
|
|
if(xc->tchn_handle) { fclose(xc->tchn_handle); xc->tchn_handle = NULL; }
|
|
if(xc->vchn_handle) { fclose(xc->vchn_handle); xc->vchn_handle = NULL; }
|
|
if(xc->curval_handle) { fclose(xc->curval_handle); xc->curval_handle = NULL; }
|
|
if(xc->valpos_handle) { fclose(xc->valpos_handle); xc->valpos_handle = NULL; }
|
|
if(xc->geom_handle) { fclose(xc->geom_handle); xc->geom_handle = NULL; }
|
|
if(xc->hier_handle) { fclose(xc->hier_handle); xc->hier_handle = NULL; }
|
|
if(xc->handle)
|
|
{
|
|
if(xc->repack_on_close)
|
|
{
|
|
FILE *fp;
|
|
off_t offpnt, uclen;
|
|
int flen = strlen(xc->filename);
|
|
char *hf = calloc(1, flen + 5);
|
|
|
|
strcpy(hf, xc->filename);
|
|
strcpy(hf+flen, ".pak");
|
|
fp = fopen(hf, "wb");
|
|
|
|
if(fp)
|
|
{
|
|
void *dsth;
|
|
int zfd;
|
|
char gz_membuf[FST_GZIO_LEN];
|
|
|
|
fseeko(xc->handle, 0, SEEK_END);
|
|
uclen = ftello(xc->handle);
|
|
|
|
fputc(FST_BL_ZWRAPPER, fp);
|
|
fstWriterUint64(fp, 0);
|
|
fstWriterUint64(fp, uclen);
|
|
fflush(fp);
|
|
|
|
fseeko(xc->handle, 0, SEEK_SET);
|
|
zfd = dup(fileno(fp));
|
|
dsth = gzdopen(zfd, "wb4");
|
|
if(dsth)
|
|
{
|
|
for(offpnt = 0; offpnt < uclen; offpnt += FST_GZIO_LEN)
|
|
{
|
|
size_t this_len = ((uclen - offpnt) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - offpnt);
|
|
fstFread(gz_membuf, this_len, 1, xc->handle);
|
|
gzwrite(dsth, gz_membuf, this_len);
|
|
}
|
|
gzclose(dsth);
|
|
}
|
|
else
|
|
{
|
|
close(zfd);
|
|
}
|
|
fseeko(fp, 0, SEEK_END);
|
|
offpnt = ftello(fp);
|
|
fseeko(fp, 1, SEEK_SET);
|
|
fstWriterUint64(fp, offpnt - 1);
|
|
fclose(fp);
|
|
fclose(xc->handle); xc->handle = NULL;
|
|
|
|
unlink(xc->filename);
|
|
rename(hf, xc->filename);
|
|
}
|
|
else
|
|
{
|
|
xc->repack_on_close = 0;
|
|
fclose(xc->handle); xc->handle = NULL;
|
|
}
|
|
|
|
free(hf);
|
|
}
|
|
else
|
|
{
|
|
fclose(xc->handle); xc->handle = NULL;
|
|
}
|
|
}
|
|
|
|
#ifdef __MINGW32__
|
|
{
|
|
int flen = strlen(xc->filename);
|
|
char *hf = calloc(1, flen + 6);
|
|
strcpy(hf, xc->filename);
|
|
|
|
if(xc->compress_hier)
|
|
{
|
|
strcpy(hf + flen, ".hier");
|
|
unlink(hf); /* no longer needed as a section now exists for this */
|
|
}
|
|
|
|
free(hf);
|
|
}
|
|
#endif
|
|
|
|
free(xc->filename); xc->filename = NULL;
|
|
free(xc);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* generation and writing out of value change data sections
|
|
*/
|
|
static void fstWriterEmitSectionHeader(void *ctx)
|
|
{
|
|
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
|
|
|
|
if(xc)
|
|
{
|
|
unsigned long destlen;
|
|
unsigned char *dmem;
|
|
int rc;
|
|
|
|
destlen = xc->maxvalpos;
|
|
dmem = malloc(destlen);
|
|
rc = compress2(dmem, &destlen, xc->curval_mem, xc->maxvalpos, 9);
|
|
|
|
fputc(FST_BL_SKIP, xc->handle); /* temporarily tag the section, use FST_BL_VCDATA on finalize */
|
|
xc->section_start = ftello(xc->handle);
|
|
xc->section_header_only = 1; /* indicates truncate might be needed */
|
|
fstWriterUint64(xc->handle, 0); /* placeholder = section length */
|
|
fstWriterUint64(xc->handle, xc->is_initial_time ? xc->firsttime : xc->curtime); /* begin time of section */
|
|
fstWriterUint64(xc->handle, xc->curtime); /* end time of section (placeholder) */
|
|
fstWriterUint64(xc->handle, 0); /* placeholder = amount of buffer memory required in reader for full vc traversal */
|
|
fstWriterVarint(xc->handle, xc->maxvalpos); /* maxvalpos = length of uncompressed data */
|
|
|
|
if((rc == Z_OK) && (destlen < xc->maxvalpos))
|
|
{
|
|
fstWriterVarint(xc->handle, destlen); /* length of compressed data */
|
|
}
|
|
else
|
|
{
|
|
fstWriterVarint(xc->handle, xc->maxvalpos); /* length of (unable to be) compressed data */
|
|
}
|
|
fstWriterVarint(xc->handle, xc->maxhandle); /* max handle associated with this data (in case of dynamic facility adds) */
|
|
|
|
if((rc == Z_OK) && (destlen < xc->maxvalpos))
|
|
{
|
|
fstFwrite(dmem, destlen, 1, xc->handle);
|
|
}
|
|
else /* comparison between compressed / decompressed len tells if compressed */
|
|
{
|
|
fstFwrite(xc->curval_mem, xc->maxvalpos, 1, xc->handle);
|
|
}
|
|
|
|
free(dmem);
|
|
}
|
|
}
|
|
|
|
|
|
void fstWriterFlushContext(void *ctx)
|
|
{
|
|
#ifdef FST_DEBUG
|
|
int cnt = 0;
|
|
#endif
|
|
int i;
|
|
unsigned char *vchg_mem;
|
|
FILE *f;
|
|
off_t fpos, indxpos, endpos;
|
|
uint32_t prevpos;
|
|
int zerocnt;
|
|
unsigned char *scratchpad;
|
|
unsigned char *scratchpnt;
|
|
unsigned char *tmem;
|
|
off_t tlen;
|
|
off_t unc_memreq = 0; /* for reader */
|
|
unsigned char *packmem;
|
|
unsigned int packmemlen;
|
|
uint32_t *vm4ip;
|
|
|
|
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
|
|
|
|
if((!xc)||(xc->vchn_siz <= 1)||(xc->already_in_flush)) return;
|
|
xc->already_in_flush = 1; /* should really do this with a semaphore */
|
|
|
|
xc->section_header_only = 0;
|
|
scratchpad = malloc(xc->vchn_siz);
|
|
|
|
fflush(xc->vchn_handle);
|
|
vchg_mem = fstMmap(NULL, xc->vchn_siz, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->vchn_handle), 0);
|
|
|
|
f = xc->handle;
|
|
fstWriterVarint(f, xc->maxhandle); /* emit current number of handles */
|
|
fputc(xc->fastpack ? 'F' : 'Z', f);
|
|
fpos = 1;
|
|
|
|
packmemlen = 1024; /* maintain a running "longest" allocation to */
|
|
packmem = malloc(packmemlen); /* prevent continual malloc...free every loop iter */
|
|
|
|
for(i=0;i<xc->maxhandle;i++)
|
|
{
|
|
vm4ip = &(xc->valpos_mem[4*i]);
|
|
|
|
if(vm4ip[2])
|
|
{
|
|
uint32_t offs = vm4ip[2];
|
|
uint32_t next_offs;
|
|
int wrlen;
|
|
|
|
vm4ip[2] = fpos;
|
|
|
|
scratchpnt = scratchpad + xc->vchn_siz; /* build this buffer backwards */
|
|
if(vm4ip[1] == 1)
|
|
{
|
|
while(offs)
|
|
{
|
|
unsigned char val;
|
|
uint32_t time_delta, rcv;
|
|
next_offs = fstGetUint32(vchg_mem + offs);
|
|
offs += 4;
|
|
|
|
time_delta = fstGetVarint32(vchg_mem + offs, &wrlen);
|
|
val = vchg_mem[offs+wrlen];
|
|
offs = next_offs;
|
|
|
|
switch(val)
|
|
{
|
|
case '0':
|
|
case '1': rcv = ((val&1)<<1) | (time_delta<<2);
|
|
break; /* pack more delta bits in for 0/1 vchs */
|
|
|
|
case 'x': case 'X': rcv = FST_RCV_X | (time_delta<<4); break;
|
|
case 'z': case 'Z': rcv = FST_RCV_Z | (time_delta<<4); break;
|
|
case 'h': case 'H': rcv = FST_RCV_H | (time_delta<<4); break;
|
|
case 'u': case 'U': rcv = FST_RCV_U | (time_delta<<4); break;
|
|
case 'w': case 'W': rcv = FST_RCV_W | (time_delta<<4); break;
|
|
case 'l': case 'L': rcv = FST_RCV_L | (time_delta<<4); break;
|
|
default: rcv = FST_RCV_D | (time_delta<<4); break;
|
|
}
|
|
|
|
scratchpnt = fstCopyVarint32ToLeft(scratchpnt, rcv);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while(offs)
|
|
{
|
|
int idx;
|
|
char is_binary = 1;
|
|
unsigned char *pnt;
|
|
uint32_t time_delta;
|
|
|
|
next_offs = fstGetUint32(vchg_mem + offs);
|
|
offs += 4;
|
|
|
|
time_delta = fstGetVarint32(vchg_mem + offs, &wrlen);
|
|
|
|
pnt = vchg_mem+offs+wrlen;
|
|
offs = next_offs;
|
|
|
|
for(idx=0;idx<vm4ip[1];idx++)
|
|
{
|
|
if((pnt[idx] == '0') || (pnt[idx] == '1'))
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
is_binary = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(is_binary)
|
|
{
|
|
unsigned char acc = 0;
|
|
int shift = 7 - ((vm4ip[1]-1) & 7);
|
|
for(idx=vm4ip[1]-1;idx>=0;idx--)
|
|
{
|
|
acc |= (pnt[idx] & 1) << shift;
|
|
shift++;
|
|
if(shift == 8)
|
|
{
|
|
*(--scratchpnt) = acc;
|
|
shift = 0;
|
|
acc = 0;
|
|
}
|
|
}
|
|
|
|
scratchpnt = fstCopyVarint32ToLeft(scratchpnt, (time_delta << 1));
|
|
}
|
|
else
|
|
{
|
|
scratchpnt -= vm4ip[1];
|
|
memcpy(scratchpnt, pnt, vm4ip[1]);
|
|
|
|
scratchpnt = fstCopyVarint32ToLeft(scratchpnt, (time_delta << 1) | 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
wrlen = scratchpad + xc->vchn_siz - scratchpnt;
|
|
unc_memreq += wrlen;
|
|
if(wrlen > 32)
|
|
{
|
|
unsigned long destlen = wrlen;
|
|
unsigned char *dmem;
|
|
int rc;
|
|
|
|
if(!xc->fastpack)
|
|
{
|
|
if(wrlen <= packmemlen)
|
|
{
|
|
dmem = packmem;
|
|
}
|
|
else
|
|
{
|
|
free(packmem);
|
|
dmem = packmem = malloc(packmemlen = wrlen);
|
|
}
|
|
|
|
rc = compress2(dmem, &destlen, scratchpnt, wrlen, 4);
|
|
if(rc == Z_OK)
|
|
{
|
|
fpos += fstWriterVarint(f, wrlen);
|
|
fpos += destlen;
|
|
fstFwrite(dmem, destlen, 1, f);
|
|
}
|
|
else
|
|
{
|
|
fpos += fstWriterVarint(f, 0);
|
|
fpos += wrlen;
|
|
fstFwrite(scratchpnt, wrlen, 1, f);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(((wrlen * 2) + 2) <= packmemlen)
|
|
{
|
|
dmem = packmem;
|
|
}
|
|
else
|
|
{
|
|
free(packmem);
|
|
dmem = packmem = malloc(packmemlen = (wrlen * 2) + 2);
|
|
}
|
|
|
|
rc = fastlz_compress(scratchpnt, wrlen, dmem);
|
|
if(rc < destlen)
|
|
{
|
|
fpos += fstWriterVarint(f, wrlen);
|
|
fpos += rc;
|
|
fstFwrite(dmem, rc, 1, f);
|
|
}
|
|
else
|
|
{
|
|
fpos += fstWriterVarint(f, 0);
|
|
fpos += wrlen;
|
|
fstFwrite(scratchpnt, wrlen, 1, f);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fpos += fstWriterVarint(f, 0);
|
|
fpos += wrlen;
|
|
fstFwrite(scratchpnt, wrlen, 1, f);
|
|
}
|
|
|
|
vm4ip[3] = 0;
|
|
#ifdef FST_DEBUG
|
|
cnt++;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
free(packmem); packmem = NULL; packmemlen = 0;
|
|
|
|
prevpos = 0; zerocnt = 0;
|
|
free(scratchpad); scratchpad = NULL;
|
|
|
|
indxpos = ftello(f);
|
|
xc->secnum++;
|
|
|
|
for(i=0;i<xc->maxhandle;i++)
|
|
{
|
|
vm4ip = &(xc->valpos_mem[4*i]);
|
|
|
|
if(vm4ip[2])
|
|
{
|
|
if(zerocnt)
|
|
{
|
|
fpos += fstWriterVarint(f, (zerocnt << 1));
|
|
zerocnt = 0;
|
|
}
|
|
|
|
fpos += fstWriterVarint(f, ((vm4ip[2] - prevpos) << 1) | 1);
|
|
prevpos = vm4ip[2];
|
|
vm4ip[2] = 0;
|
|
vm4ip[3] = 0; /* clear out tchn idx */
|
|
}
|
|
else
|
|
{
|
|
zerocnt++;
|
|
}
|
|
}
|
|
if(zerocnt)
|
|
{
|
|
fpos += fstWriterVarint(f, (zerocnt << 1));
|
|
}
|
|
#ifdef FST_DEBUG
|
|
printf("value chains: %d\n", cnt);
|
|
#endif
|
|
|
|
fstMunmap(vchg_mem, xc->vchn_siz);
|
|
|
|
fseeko(xc->vchn_handle, 0, SEEK_SET);
|
|
fstFtruncate(fileno(xc->vchn_handle), 0);
|
|
fputc('!', xc->vchn_handle);
|
|
xc->vchn_siz = 1;
|
|
|
|
endpos = ftello(xc->handle);
|
|
fstWriterUint64(xc->handle, endpos-indxpos); /* write delta index position at very end of block */
|
|
|
|
/*emit time changes for block */
|
|
fflush(xc->tchn_handle);
|
|
tlen = ftello(xc->tchn_handle);
|
|
fseeko(xc->tchn_handle, 0, SEEK_SET);
|
|
|
|
tmem = fstMmap(NULL, tlen, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->tchn_handle), 0);
|
|
if(tmem)
|
|
{
|
|
unsigned long destlen = tlen;
|
|
unsigned char *dmem = malloc(destlen);
|
|
int rc = compress2(dmem, &destlen, tmem, tlen, 9);
|
|
|
|
if((rc == Z_OK) && (destlen < tlen))
|
|
{
|
|
fstFwrite(dmem, destlen, 1, xc->handle);
|
|
}
|
|
else /* comparison between compressed / decompressed len tells if compressed */
|
|
{
|
|
fstFwrite(tmem, tlen, 1, xc->handle);
|
|
destlen = tlen;
|
|
}
|
|
free(dmem);
|
|
fstMunmap(tmem, tlen);
|
|
fstWriterUint64(xc->handle, tlen); /* uncompressed */
|
|
fstWriterUint64(xc->handle, destlen); /* compressed */
|
|
fstWriterUint64(xc->handle, xc->tchn_cnt); /* number of time items */
|
|
}
|
|
|
|
xc->tchn_cnt = xc->tchn_idx = 0;
|
|
fseeko(xc->tchn_handle, 0, SEEK_SET);
|
|
fstFtruncate(fileno(xc->tchn_handle), 0);
|
|
|
|
/* write block trailer */
|
|
endpos = ftello(xc->handle);
|
|
fseeko(xc->handle, xc->section_start, SEEK_SET);
|
|
fstWriterUint64(xc->handle, endpos - xc->section_start); /* write block length */
|
|
fseeko(xc->handle, 8, SEEK_CUR); /* skip begin time */
|
|
fstWriterUint64(xc->handle, xc->curtime); /* write end time for section */
|
|
fstWriterUint64(xc->handle, unc_memreq); /* amount of buffer memory required in reader for full traversal */
|
|
fflush(xc->handle);
|
|
|
|
fseeko(xc->handle, xc->section_start-1, SEEK_SET); /* write out FST_BL_VCDATA over FST_BL_SKIP */
|
|
fputc(FST_BL_VCDATA, xc->handle);
|
|
fflush(xc->handle);
|
|
|
|
fseeko(xc->handle, endpos, SEEK_SET); /* seek to end of file */
|
|
|
|
xc->section_header_truncpos = endpos; /* cache in case of need to truncate */
|
|
if(xc->dump_size_limit)
|
|
{
|
|
if(endpos >= xc->dump_size_limit)
|
|
{
|
|
xc->skip_writing_section_hdr = 1;
|
|
xc->size_limit_locked = 1;
|
|
xc->is_initial_time = 1; /* to trick emit value and emit time change */
|
|
#ifdef FST_DEBUG
|
|
printf("<< dump file size limit reached, stopping dumping >>\n");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if(!xc->skip_writing_section_hdr)
|
|
{
|
|
fstWriterEmitSectionHeader(xc); /* emit next section header */
|
|
}
|
|
fflush(xc->handle);
|
|
|
|
xc->already_in_flush = 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* functions to set miscellaneous header/block information
|
|
*/
|
|
void fstWriterSetDate(void *ctx, const char *dat)
|
|
{
|
|
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
|
|
if(xc)
|
|
{
|
|
char s[FST_HDR_DATE_SIZE];
|
|
off_t fpos = ftello(xc->handle);
|
|
int len = strlen(dat);
|
|
|
|
fseeko(xc->handle, FST_HDR_OFFS_DATE, SEEK_SET);
|
|
memset(s, 0, FST_HDR_DATE_SIZE);
|
|
memcpy(s, dat, (len < FST_HDR_DATE_SIZE) ? len : FST_HDR_DATE_SIZE);
|
|
fstFwrite(s, FST_HDR_DATE_SIZE, 1, xc->handle);
|
|
fflush(xc->handle);
|
|
fseeko(xc->handle, fpos, SEEK_SET);
|
|
}
|
|
}
|
|
|
|
|
|
void fstWriterSetVersion(void *ctx, const char *vers)
|
|
{
|
|
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
|
|
if(xc && vers)
|
|
{
|
|
char s[FST_HDR_SIM_VERSION_SIZE];
|
|
off_t fpos = ftello(xc->handle);
|
|
int len = strlen(vers);
|
|
|
|
fseeko(xc->handle, FST_HDR_OFFS_SIM_VERSION, SEEK_SET);
|
|
memset(s, 0, FST_HDR_SIM_VERSION_SIZE);
|
|
memcpy(s, vers, (len < FST_HDR_SIM_VERSION_SIZE) ? len : FST_HDR_SIM_VERSION_SIZE);
|
|
fstFwrite(s, FST_HDR_SIM_VERSION_SIZE, 1, xc->handle);
|
|
fflush(xc->handle);
|
|
fseeko(xc->handle, fpos, SEEK_SET);
|
|
}
|
|
}
|
|
|
|
|
|
void fstWriterSetTimescale(void *ctx, int ts)
|
|
{
|
|
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
|
|
if(xc)
|
|
{
|
|
off_t fpos = ftello(xc->handle);
|
|
fseeko(xc->handle, FST_HDR_OFFS_TIMESCALE, SEEK_SET);
|
|
fputc(ts & 255, xc->handle);
|
|
fflush(xc->handle);
|
|
fseeko(xc->handle, fpos, SEEK_SET);
|
|
}
|
|
}
|
|
|
|
|
|
void fstWriterSetTimescaleFromString(void *ctx, const char *s)
|
|
{
|
|
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
|
|
if(xc && s)
|
|
{
|
|
int mat = 0;
|
|
int seconds_exp = -9;
|
|
int tv = atoi(s);
|
|
const char *pnt = s;
|
|
|
|
while(*pnt)
|
|
{
|
|
switch(*pnt)
|
|
{
|
|
case 'm': seconds_exp = -3; mat = 1; break;
|
|
case 'u': seconds_exp = -6; mat = 1; break;
|
|
case 'n': seconds_exp = -9; mat = 1; break;
|
|
case 'p': seconds_exp = -12; mat = 1; break;
|
|
case 'f': seconds_exp = -15; mat = 1; break;
|
|
case 'a': seconds_exp = -18; mat = 1; break;
|
|
case 'z': seconds_exp = -21; mat = 1; break;
|
|
case 's': seconds_exp = -0; mat = 1; break;
|
|
default: break;
|
|
}
|
|
|
|
if(mat) break;
|
|
pnt++;
|
|
}
|
|
|
|
if(tv == 10)
|
|
{
|
|
seconds_exp++;
|
|
}
|
|
else
|
|
if(tv == 100)
|
|
{
|
|
seconds_exp+=2;
|
|
}
|
|
|
|
fstWriterSetTimescale(ctx, seconds_exp);
|
|
}
|
|
}
|
|
|
|
|
|
void fstWriterSetPackType(void *ctx, int typ)
|
|
{
|
|
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
|
|
if(xc)
|
|
{
|
|
xc->fastpack = (typ != 0);
|
|
}
|
|
}
|
|
|
|
|
|
void fstWriterSetRepackOnClose(void *ctx, int enable)
|
|
{
|
|
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
|
|
if(xc)
|
|
{
|
|
xc->repack_on_close = (enable != 0);
|
|
}
|
|
}
|
|
|
|
|
|
void fstWriterSetDumpSizeLimit(void *ctx, uint64_t numbytes)
|
|
{
|
|
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
|
|
if(xc)
|
|
{
|
|
xc->dump_size_limit = numbytes;
|
|
}
|
|
}
|
|
|
|
|
|
int fstWriterGetDumpSizeLimitReached(void *ctx)
|
|
{
|
|
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
|
|
if(xc)
|
|
{
|
|
return(xc->size_limit_locked != 0);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
* writer scope/var creation
|
|
*/
|
|
fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir vd,
|
|
uint32_t len, const char *nam, fstHandle aliasHandle)
|
|
{
|
|
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
|
|
int i, nlen, is_real;
|
|
|
|
if(xc && nam)
|
|
{
|
|
if(xc->valpos_mem)
|
|
{
|
|
fstDestroyMmaps(xc, 0);
|
|
}
|
|
|
|
fputc(vt, xc->hier_handle);
|
|
fputc(vd, xc->hier_handle);
|
|
nlen = strlen(nam);
|
|
fstFwrite(nam, nlen, 1, xc->hier_handle);
|
|
fputc(0, xc->hier_handle);
|
|
xc->hier_file_len += (nlen+3);
|
|
|
|
if((vt == FST_VT_VCD_REAL) || (vt == FST_VT_VCD_REAL_PARAMETER) || (vt == FST_VT_VCD_REALTIME))
|
|
{
|
|
is_real = 1;
|
|
len = 8; /* recast number of bytes to that of what a double is */
|
|
}
|
|
else
|
|
{
|
|
is_real = 0;
|
|
}
|
|
|
|
xc->hier_file_len += fstWriterVarint(xc->hier_handle, len);
|
|
|
|
if(aliasHandle > xc->maxhandle) aliasHandle = 0;
|
|
xc->hier_file_len += fstWriterVarint(xc->hier_handle, aliasHandle);
|
|
xc->numsigs++;
|
|
if(!aliasHandle)
|
|
{
|
|
uint32_t zero = 0;
|
|
|
|
fstWriterVarint(xc->geom_handle, !is_real ? len : 0); /* geom section encodes reals as zero byte */
|
|
|
|
fstFwrite(&xc->maxvalpos, sizeof(uint32_t), 1, xc->valpos_handle);
|
|
fstFwrite(&len, sizeof(uint32_t), 1, xc->valpos_handle);
|
|
fstFwrite(&zero, sizeof(uint32_t), 1, xc->valpos_handle);
|
|
fstFwrite(&zero, sizeof(uint32_t), 1, xc->valpos_handle);
|
|
|
|
if(!is_real)
|
|
{
|
|
for(i=0;i<len;i++)
|
|
{
|
|
fputc('x', xc->curval_handle);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fstFwrite(&xc->nan, 8, 1, xc->curval_handle); /* initialize doubles to NaN rather than x */
|
|
}
|
|
|
|
xc->maxvalpos+=len;
|
|
xc->maxhandle++;
|
|
return(xc->maxhandle);
|
|
}
|
|
else
|
|
{
|
|
return(aliasHandle);
|
|
}
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
void fstWriterSetScope(void *ctx, enum fstScopeType scopetype,
|
|
const char *scopename, const char *scopecomp)
|
|
{
|
|
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
|
|
|
|
if(xc && scopename)
|
|
{
|
|
fputc(FST_ST_VCD_SCOPE, xc->hier_handle);
|
|
if((scopetype < FST_ST_VCD_MODULE) || (scopetype > FST_ST_MAX)) { scopetype = FST_ST_VCD_MODULE; }
|
|
fputc(scopetype, xc->hier_handle);
|
|
fprintf(xc->hier_handle, "%s%c%s%c",
|
|
scopename ? scopename : "", 0,
|
|
scopecomp ? scopecomp : "", 0);
|
|
|
|
if(scopename)
|
|
{
|
|
xc->hier_file_len += strlen(scopename);
|
|
}
|
|
if(scopecomp)
|
|
{
|
|
xc->hier_file_len += strlen(scopecomp);
|
|
}
|
|
|
|
xc->hier_file_len += 4; /* FST_ST_VCD_SCOPE + scopetype + two string terminating zeros */
|
|
xc->numscopes++;
|
|
}
|
|
}
|
|
|
|
|
|
void fstWriterSetUpscope(void *ctx)
|
|
{
|
|
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
|
|
|
|
if(xc)
|
|
{
|
|
fputc(FST_ST_VCD_UPSCOPE, xc->hier_handle);
|
|
xc->hier_file_len++;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* value and time change emission
|
|
*/
|
|
void fstWriterEmitValueChange(void *ctx, fstHandle handle, void *val)
|
|
{
|
|
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
|
|
unsigned char *buf = (unsigned char *)val;
|
|
uint32_t offs;
|
|
size_t len;
|
|
|
|
if((xc) && (handle <= xc->maxhandle))
|
|
{
|
|
uint32_t fpos;
|
|
uint32_t *vm4ip;
|
|
|
|
if(!xc->valpos_mem)
|
|
{
|
|
xc->vc_emitted = 1;
|
|
fstWriterCreateMmaps(xc);
|
|
}
|
|
|
|
handle--; /* move starting at 1 index to starting at 0 */
|
|
vm4ip = &(xc->valpos_mem[4*handle]);
|
|
offs = vm4ip[0];
|
|
len = vm4ip[1];
|
|
memcpy(xc->curval_mem + offs, buf, len);
|
|
|
|
if(!xc->is_initial_time)
|
|
{
|
|
fpos = xc->vchn_siz;
|
|
/* cygwin runs faster if these writes are combined, so the new fstWriterUint32WithVarint function, but should help with regular */
|
|
#ifndef FST_USE_FWRITE_COMBINING
|
|
xc->vchn_siz += fstWriterUint32WithVarint(xc->vchn_handle, &vm4ip[2], xc->tchn_idx - vm4ip[3]); /* prev_chg is vm4ip[2] */
|
|
fstFwrite(buf, len, 1, xc->vchn_handle);
|
|
xc->vchn_siz += len;
|
|
#else
|
|
xc->vchn_siz += fstWriterUint32WithVarint(xc->vchn_handle, &vm4ip[2], xc->tchn_idx - vm4ip[3], buf, len); /* do one fwrite op only */
|
|
#endif
|
|
vm4ip[3] = xc->tchn_idx;
|
|
vm4ip[2] = fpos;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void fstWriterEmitTimeChange(void *ctx, uint64_t tim)
|
|
{
|
|
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
|
|
int i;
|
|
int skip = 0;
|
|
if(xc)
|
|
{
|
|
if(xc->is_initial_time)
|
|
{
|
|
if(xc->size_limit_locked) /* this resets xc->is_initial_time to one */
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(!xc->valpos_mem)
|
|
{
|
|
fstWriterCreateMmaps(xc);
|
|
}
|
|
|
|
skip = 1;
|
|
|
|
xc->firsttime = (xc->vc_emitted) ? 0: tim;
|
|
xc->curtime = 0;
|
|
fseeko(xc->vchn_handle, 0, SEEK_SET);
|
|
fstFtruncate(fileno(xc->vchn_handle), 0);
|
|
fputc('!', xc->vchn_handle);
|
|
xc->vchn_siz = 1;
|
|
fstWriterEmitSectionHeader(xc);
|
|
for(i=0;i<xc->maxhandle;i++)
|
|
{
|
|
xc->valpos_mem[4*i+2] = 0; /* zero out offset val */
|
|
xc->valpos_mem[4*i+3] = 0; /* zero out last time change val */
|
|
}
|
|
xc->is_initial_time = 0;
|
|
}
|
|
else
|
|
{
|
|
if(xc->vchn_siz >= FST_BREAK_SIZE)
|
|
{
|
|
fstWriterFlushContext(xc);
|
|
xc->tchn_cnt++;
|
|
fstWriterVarint(xc->tchn_handle, xc->curtime);
|
|
}
|
|
}
|
|
|
|
if(!skip)
|
|
{
|
|
xc->tchn_idx++;
|
|
}
|
|
fstWriterVarint(xc->tchn_handle, tim - xc->curtime);
|
|
xc->tchn_cnt++;
|
|
xc->curtime = tim;
|
|
}
|
|
}
|
|
|
|
|
|
void fstWriterEmitDumpActive(void *ctx, int enable)
|
|
{
|
|
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
|
|
|
|
if(xc)
|
|
{
|
|
struct fstBlackoutChain *b = calloc(1, sizeof(struct fstBlackoutChain));
|
|
|
|
b->tim = xc->curtime;
|
|
b->active = (enable != 0);
|
|
|
|
xc->num_blackouts++;
|
|
if(xc->blackout_curr)
|
|
{
|
|
xc->blackout_curr->next = b;
|
|
xc->blackout_curr = b;
|
|
}
|
|
else
|
|
{
|
|
xc->blackout_head = b;
|
|
xc->blackout_curr = b;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************/
|
|
/*** ***/
|
|
/*** reader function ***/
|
|
/*** ***/
|
|
/***********************/
|
|
|
|
/*
|
|
* private structs
|
|
*/
|
|
static const char *vartypes[] = {
|
|
"event", "integer", "parameter", "real", "real_parameter",
|
|
"reg", "supply0", "supply1", "time", "tri",
|
|
"triand", "trior", "trireg", "tri0", "tri1",
|
|
"wand", "wire", "wor", "port", "array", "realtime"
|
|
};
|
|
|
|
static const char *modtypes[] = {
|
|
"module", "task", "function", "begin", "fork"
|
|
};
|
|
|
|
struct fstCurrHier
|
|
{
|
|
struct fstCurrHier *prev;
|
|
void *user_info;
|
|
int len;
|
|
};
|
|
|
|
|
|
struct fstReaderContext
|
|
{
|
|
/* common entries */
|
|
|
|
FILE *f, *fh;
|
|
#ifdef __MINGW32__
|
|
char *fh_name;
|
|
#endif
|
|
|
|
uint64_t start_time, end_time;
|
|
uint64_t mem_used_by_writer;
|
|
uint64_t scope_count;
|
|
uint64_t var_count;
|
|
fstHandle maxhandle;
|
|
uint64_t num_alias;
|
|
uint64_t vc_section_count;
|
|
|
|
uint32_t *signal_lens; /* maxhandle sized */
|
|
unsigned char *signal_typs; /* maxhandle sized */
|
|
unsigned char *process_mask; /* maxhandle-based, bitwise sized */
|
|
uint32_t longest_signal_value_len; /* longest len value encountered */
|
|
unsigned char *temp_signal_value_buf; /* malloced for len in longest_signal_value_len */
|
|
|
|
signed char timescale;
|
|
unsigned double_endian_match : 1;
|
|
unsigned native_doubles_for_cb : 1;
|
|
unsigned contains_geom_section : 1;
|
|
unsigned contains_hier_section : 1; /* valid for hier_pos */
|
|
unsigned limit_range_valid : 1; /* valid for limit_range_start, limit_range_end */
|
|
|
|
char version[FST_HDR_SIM_VERSION_SIZE + 1];
|
|
char date[FST_HDR_DATE_SIZE + 1];
|
|
|
|
char *filename, *filename_unpacked;
|
|
off_t hier_pos;
|
|
|
|
uint32_t num_blackouts;
|
|
uint64_t *blackout_times;
|
|
unsigned char *blackout_activity;
|
|
|
|
uint64_t limit_range_start, limit_range_end;
|
|
|
|
/* entries specific to read value at time functions */
|
|
|
|
unsigned rvat_data_valid : 1;
|
|
uint64_t *rvat_time_table;
|
|
uint64_t rvat_beg_tim, rvat_end_tim;
|
|
unsigned char *rvat_frame_data;
|
|
uint64_t rvat_frame_maxhandle;
|
|
off_t *rvat_chain_table;
|
|
uint32_t *rvat_chain_table_lengths;
|
|
uint64_t rvat_vc_maxhandle;
|
|
off_t rvat_vc_start;
|
|
uint32_t *rvat_sig_offs;
|
|
|
|
uint32_t rvat_chain_len;
|
|
unsigned char *rvat_chain_mem;
|
|
fstHandle rvat_chain_facidx;
|
|
|
|
uint32_t rvat_chain_pos_tidx;
|
|
uint32_t rvat_chain_pos_idx;
|
|
uint64_t rvat_chain_pos_time;
|
|
unsigned rvat_chain_pos_valid : 1;
|
|
|
|
/* entries specific to hierarchy traversal */
|
|
|
|
struct fstHier hier;
|
|
struct fstCurrHier *curr_hier;
|
|
fstHandle current_handle;
|
|
char *curr_flat_hier_nam;
|
|
int flat_hier_alloc_len;
|
|
unsigned do_rewind : 1;
|
|
char str_scope_nam[FST_ID_NAM_SIZ+1];
|
|
char str_scope_comp[FST_ID_NAM_SIZ+1];
|
|
|
|
};
|
|
|
|
|
|
/*
|
|
* scope -> flat name handling
|
|
*/
|
|
static void fstReaderDeallocateScopeData(struct fstReaderContext *xc)
|
|
{
|
|
struct fstCurrHier *chp;
|
|
|
|
free(xc->curr_flat_hier_nam); xc->curr_flat_hier_nam = NULL;
|
|
while(xc->curr_hier)
|
|
{
|
|
chp = xc->curr_hier->prev;
|
|
free(xc->curr_hier);
|
|
xc->curr_hier = chp;
|
|
}
|
|
}
|
|
|
|
|
|
const char *fstReaderGetCurrentFlatScope(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
if(xc)
|
|
{
|
|
return(xc->curr_flat_hier_nam ? xc->curr_flat_hier_nam : "");
|
|
}
|
|
else
|
|
{
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
|
|
void *fstReaderGetCurrentScopeUserInfo(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
if(xc)
|
|
{
|
|
return(xc->curr_hier ? xc->curr_hier->user_info : NULL);
|
|
}
|
|
else
|
|
{
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
|
|
const char *fstReaderPopScope(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
if(xc && xc->curr_hier)
|
|
{
|
|
struct fstCurrHier *ch = xc->curr_hier;
|
|
if(xc->curr_hier->prev)
|
|
{
|
|
xc->curr_flat_hier_nam[xc->curr_hier->prev->len] = 0;
|
|
}
|
|
else
|
|
{
|
|
*xc->curr_flat_hier_nam = 0;
|
|
}
|
|
xc->curr_hier = xc->curr_hier->prev;
|
|
free(ch);
|
|
return(xc->curr_flat_hier_nam ? xc->curr_flat_hier_nam : "");
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
void fstReaderResetScope(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
|
|
if(xc)
|
|
{
|
|
while(fstReaderPopScope(xc)); /* remove any already-built scoping info */
|
|
}
|
|
}
|
|
|
|
|
|
const char *fstReaderPushScope(void *ctx, const char *nam, void *user_info)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
if(xc)
|
|
{
|
|
struct fstCurrHier *ch = malloc(sizeof(struct fstCurrHier));
|
|
int chl = xc->curr_hier ? xc->curr_hier->len : 0;
|
|
int len = chl + 1 + strlen(nam);
|
|
if(len >= xc->flat_hier_alloc_len)
|
|
{
|
|
xc->curr_flat_hier_nam = xc->curr_flat_hier_nam ? realloc(xc->curr_flat_hier_nam, len+1) : malloc(len+1);
|
|
}
|
|
|
|
if(chl)
|
|
{
|
|
xc->curr_flat_hier_nam[chl] = '.';
|
|
strcpy(xc->curr_flat_hier_nam + chl + 1, nam);
|
|
}
|
|
else
|
|
{
|
|
strcpy(xc->curr_flat_hier_nam, nam);
|
|
len--;
|
|
}
|
|
|
|
ch->len = len;
|
|
ch->prev = xc->curr_hier;
|
|
ch->user_info = user_info;
|
|
xc->curr_hier = ch;
|
|
return(xc->curr_flat_hier_nam);
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
/*
|
|
* iter mask manipulation util functions
|
|
*/
|
|
int fstReaderGetFacProcessMask(void *ctx, fstHandle facidx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
|
|
if(xc)
|
|
{
|
|
facidx--;
|
|
if(facidx<xc->maxhandle)
|
|
{
|
|
int process_idx = facidx/8;
|
|
int process_bit = facidx&7;
|
|
|
|
return( (xc->process_mask[process_idx]&(1<<process_bit)) != 0 );
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
void fstReaderSetFacProcessMask(void *ctx, fstHandle facidx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
|
|
if(xc)
|
|
{
|
|
facidx--;
|
|
if(facidx<xc->maxhandle)
|
|
{
|
|
int idx = facidx/8;
|
|
int bitpos = facidx&7;
|
|
|
|
xc->process_mask[idx] |= (1<<bitpos);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void fstReaderClrFacProcessMask(void *ctx, fstHandle facidx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
|
|
if(xc)
|
|
{
|
|
facidx--;
|
|
if(facidx<xc->maxhandle)
|
|
{
|
|
int idx = facidx/8;
|
|
int bitpos = facidx&7;
|
|
|
|
xc->process_mask[idx] &= (~(1<<bitpos));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void fstReaderSetFacProcessMaskAll(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
|
|
if(xc)
|
|
{
|
|
memset(xc->process_mask, 0xff, (xc->maxhandle+7)/8);
|
|
}
|
|
}
|
|
|
|
|
|
void fstReaderClrFacProcessMaskAll(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
|
|
if(xc)
|
|
{
|
|
memset(xc->process_mask, 0x00, (xc->maxhandle+7)/8);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* various utility read/write functions
|
|
*/
|
|
signed char fstReaderGetTimescale(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
return(xc ? xc->timescale : 0);
|
|
}
|
|
|
|
|
|
uint64_t fstReaderGetStartTime(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
return(xc ? xc->start_time : 0);
|
|
}
|
|
|
|
|
|
uint64_t fstReaderGetEndTime(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
return(xc ? xc->end_time : 0);
|
|
}
|
|
|
|
|
|
uint64_t fstReaderGetMemoryUsedByWriter(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
return(xc ? xc->mem_used_by_writer : 0);
|
|
}
|
|
|
|
|
|
uint64_t fstReaderGetScopeCount(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
return(xc ? xc->scope_count : 0);
|
|
}
|
|
|
|
|
|
uint64_t fstReaderGetVarCount(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
return(xc ? xc->var_count : 0);
|
|
}
|
|
|
|
|
|
fstHandle fstReaderGetMaxHandle(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
return(xc ? xc->maxhandle : 0);
|
|
}
|
|
|
|
|
|
uint64_t fstReaderGetAliasCount(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
return(xc ? xc->num_alias : 0);
|
|
}
|
|
|
|
|
|
uint64_t fstReaderGetValueChangeSectionCount(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
return(xc ? xc->vc_section_count : 0);
|
|
}
|
|
|
|
|
|
int fstReaderGetDoubleEndianMatchState(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
return(xc ? xc->double_endian_match : 0);
|
|
}
|
|
|
|
|
|
const char *fstReaderGetVersionString(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
return(xc ? xc->version : NULL);
|
|
}
|
|
|
|
|
|
const char *fstReaderGetDateString(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
return(xc ? xc->date : NULL);
|
|
}
|
|
|
|
|
|
uint32_t fstReaderGetNumberDumpActivityChanges(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
return(xc ? xc->num_blackouts : 0);
|
|
}
|
|
|
|
|
|
uint64_t fstReaderGetDumpActivityChangeTime(void *ctx, uint32_t idx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
|
|
if(xc && (idx < xc->num_blackouts) && (xc->blackout_times))
|
|
{
|
|
return(xc->blackout_times[idx]);
|
|
}
|
|
else
|
|
{
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
|
|
unsigned char fstReaderGetDumpActivityChangeValue(void *ctx, uint32_t idx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
|
|
if(xc && (idx < xc->num_blackouts) && (xc->blackout_activity))
|
|
{
|
|
return(xc->blackout_activity[idx]);
|
|
}
|
|
else
|
|
{
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
|
|
void fstReaderSetLimitTimeRange(void *ctx, uint64_t start_time, uint64_t end_time)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
|
|
if(xc)
|
|
{
|
|
xc->limit_range_valid = 1;
|
|
xc->limit_range_start = start_time;
|
|
xc->limit_range_end = end_time;
|
|
}
|
|
}
|
|
|
|
|
|
void fstReaderSetUnlimitedTimeRange(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
|
|
if(xc)
|
|
{
|
|
xc->limit_range_valid = 0;
|
|
}
|
|
}
|
|
|
|
|
|
void fstReaderIterBlocksSetNativeDoublesOnCallback(void *ctx, int enable)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
if(xc)
|
|
{
|
|
xc->native_doubles_for_cb = (enable != 0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* hierarchy processing
|
|
*/
|
|
static char *fstVcdID(int value)
|
|
{
|
|
static char buf[16];
|
|
char *pnt = buf;
|
|
int vmod;
|
|
|
|
/* zero is illegal for a value...it is assumed they start at one */
|
|
for(;;)
|
|
{
|
|
if((vmod = (value % 94)))
|
|
{
|
|
*(pnt++) = (char)(vmod + 32);
|
|
}
|
|
else
|
|
{
|
|
*(pnt++) = '~'; value -= 94;
|
|
}
|
|
value = value / 94;
|
|
if(!value) { break; }
|
|
}
|
|
|
|
*pnt = 0;
|
|
return(buf);
|
|
}
|
|
|
|
static char *fstVcdIDForFwrite(int value, int *len)
|
|
{
|
|
static char buf[16];
|
|
char *pnt = buf;
|
|
int vmod;
|
|
|
|
/* zero is illegal for a value...it is assumed they start at one */
|
|
for(;;)
|
|
{
|
|
if((vmod = (value % 94)))
|
|
{
|
|
*(pnt++) = (char)(vmod + 32);
|
|
}
|
|
else
|
|
{
|
|
*(pnt++) = '~'; value -= 94;
|
|
}
|
|
value = value / 94;
|
|
if(!value) { break; }
|
|
}
|
|
|
|
*len = pnt-buf;
|
|
return(buf);
|
|
}
|
|
|
|
|
|
static int fstReaderRecreateHierFile(struct fstReaderContext *xc)
|
|
{
|
|
int pass_status = 1;
|
|
|
|
if(!xc->fh)
|
|
{
|
|
off_t offs_cache = ftello(xc->f);
|
|
char *fnam = malloc(strlen(xc->filename) + 6 + 16 + 32 + 1);
|
|
unsigned char *mem = malloc(FST_GZIO_LEN);
|
|
off_t hl, uclen;
|
|
gzFile zhandle;
|
|
int zfd;
|
|
|
|
sprintf(fnam, "%s.hier_%d_%p", xc->filename, getpid(), (void *)xc);
|
|
fseeko(xc->f, xc->hier_pos, SEEK_SET);
|
|
uclen = fstReaderUint64(xc->f);
|
|
fflush(xc->f);
|
|
zfd = dup(fileno(xc->f));
|
|
zhandle = gzdopen(zfd, "rb");
|
|
if(!zhandle)
|
|
{
|
|
close(zfd);
|
|
free(mem);
|
|
free(fnam);
|
|
return(0);
|
|
}
|
|
|
|
xc->fh = fopen(fnam, "w+b");
|
|
if(!xc->fh)
|
|
{
|
|
xc->fh = tmpfile();
|
|
free(fnam); fnam = NULL;
|
|
if(!xc->fh)
|
|
{
|
|
free(mem);
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
#ifndef __MINGW32__
|
|
if(fnam) unlink(fnam);
|
|
#endif
|
|
|
|
for(hl = 0; hl < uclen; hl += FST_GZIO_LEN)
|
|
{
|
|
size_t len = ((uclen - hl) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - hl);
|
|
size_t gzreadlen = gzread(zhandle, mem, len); /* rc should equal len... */
|
|
size_t fwlen;
|
|
|
|
if(gzreadlen != len)
|
|
{
|
|
pass_status = 0;
|
|
break;
|
|
}
|
|
|
|
fwlen = fstFwrite(mem, len, 1, xc->fh);
|
|
if(fwlen != 1)
|
|
{
|
|
pass_status = 0;
|
|
break;
|
|
}
|
|
}
|
|
gzclose(zhandle);
|
|
free(mem);
|
|
|
|
#ifndef __MINGW32__
|
|
free(fnam);
|
|
#else
|
|
xc->fh_name = fnam;
|
|
#endif
|
|
|
|
fseeko(xc->f, offs_cache, SEEK_SET);
|
|
}
|
|
|
|
return(pass_status);
|
|
}
|
|
|
|
|
|
int fstReaderIterateHierRewind(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
int pass_status = 0;
|
|
|
|
if(xc)
|
|
{
|
|
pass_status = 1;
|
|
if(!xc->fh)
|
|
{
|
|
pass_status = fstReaderRecreateHierFile(xc);
|
|
}
|
|
|
|
xc->do_rewind = 1;
|
|
}
|
|
|
|
return(pass_status);
|
|
}
|
|
|
|
|
|
struct fstHier *fstReaderIterateHier(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
int isfeof;
|
|
fstHandle alias;
|
|
char *pnt;
|
|
int ch;
|
|
|
|
if(!xc) return(NULL);
|
|
|
|
if(!xc->fh)
|
|
{
|
|
if(!fstReaderRecreateHierFile(xc))
|
|
{
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
if(xc->do_rewind)
|
|
{
|
|
xc->do_rewind = 0;
|
|
xc->current_handle = 0;
|
|
fseeko(xc->fh, 0, SEEK_SET);
|
|
clearerr(xc->fh);
|
|
}
|
|
|
|
if(!(isfeof=feof(xc->fh)))
|
|
{
|
|
int tag = fgetc(xc->fh);
|
|
switch(tag)
|
|
{
|
|
case FST_ST_VCD_SCOPE:
|
|
xc->hier.htyp = FST_HT_SCOPE;
|
|
xc->hier.u.scope.typ = fgetc(xc->fh);
|
|
xc->hier.u.scope.name = pnt = xc->str_scope_nam;
|
|
while((ch = fgetc(xc->fh)))
|
|
{
|
|
*(pnt++) = ch;
|
|
}; /* scopename */
|
|
*pnt = 0;
|
|
|
|
xc->hier.u.scope.component = pnt = xc->str_scope_comp;
|
|
while((ch = fgetc(xc->fh)))
|
|
{
|
|
*(pnt++) = ch;
|
|
}; /* scopecomp */
|
|
*pnt = 0;
|
|
break;
|
|
|
|
case FST_ST_VCD_UPSCOPE:
|
|
xc->hier.htyp = FST_HT_UPSCOPE;
|
|
break;
|
|
|
|
case FST_VT_VCD_EVENT:
|
|
case FST_VT_VCD_INTEGER:
|
|
case FST_VT_VCD_PARAMETER:
|
|
case FST_VT_VCD_REAL:
|
|
case FST_VT_VCD_REAL_PARAMETER:
|
|
case FST_VT_VCD_REG:
|
|
case FST_VT_VCD_SUPPLY0:
|
|
case FST_VT_VCD_SUPPLY1:
|
|
case FST_VT_VCD_TIME:
|
|
case FST_VT_VCD_TRI:
|
|
case FST_VT_VCD_TRIAND:
|
|
case FST_VT_VCD_TRIOR:
|
|
case FST_VT_VCD_TRIREG:
|
|
case FST_VT_VCD_TRI0:
|
|
case FST_VT_VCD_TRI1:
|
|
case FST_VT_VCD_WAND:
|
|
case FST_VT_VCD_WIRE:
|
|
case FST_VT_VCD_WOR:
|
|
case FST_VT_VCD_PORT:
|
|
case FST_VT_VCD_ARRAY:
|
|
case FST_VT_VCD_REALTIME:
|
|
xc->hier.htyp = FST_HT_VAR;
|
|
|
|
xc->hier.u.var.typ = tag;
|
|
xc->hier.u.var.direction = fgetc(xc->fh);
|
|
xc->hier.u.var.name = pnt = xc->str_scope_nam;
|
|
while((ch = fgetc(xc->fh)))
|
|
{
|
|
*(pnt++) = ch;
|
|
}; /* varname */
|
|
*pnt = 0;
|
|
xc->hier.u.var.length = fstReaderVarint32(xc->fh);
|
|
if(tag == FST_VT_VCD_PORT)
|
|
{
|
|
xc->hier.u.var.length -= 2; /* removal of delimiting spaces */
|
|
xc->hier.u.var.length /= 3; /* port -> signal size adjust */
|
|
}
|
|
|
|
alias = fstReaderVarint32(xc->fh);
|
|
|
|
if(!alias)
|
|
{
|
|
xc->current_handle++;
|
|
xc->hier.u.var.handle = xc->current_handle;
|
|
xc->hier.u.var.is_alias = 0;
|
|
}
|
|
else
|
|
{
|
|
xc->hier.u.var.handle = alias;
|
|
xc->hier.u.var.is_alias = 1;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
isfeof = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(!isfeof ? &xc->hier : NULL);
|
|
}
|
|
|
|
|
|
int fstReaderProcessHier(void *ctx, FILE *fv)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
char str[FST_ID_NAM_SIZ+1];
|
|
char *pnt;
|
|
int ch, scopetype;
|
|
int vartype;
|
|
uint32_t len, alias;
|
|
uint32_t maxvalpos=0;
|
|
int num_signal_dyn = 65536;
|
|
|
|
if(!xc) return(0);
|
|
|
|
xc->longest_signal_value_len = 32; /* arbitrarily set at 32...this is much longer than an expanded double */
|
|
|
|
if(!xc->fh)
|
|
{
|
|
if(!fstReaderRecreateHierFile(xc))
|
|
{
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
if(fv)
|
|
{
|
|
char time_dimension[2] = {0, 0};
|
|
int time_scale = 1;
|
|
|
|
fprintf(fv, "$date\n\t%s\n$end\n", xc->date);
|
|
fprintf(fv, "$version\n\t%s\n$end\n", xc->version);
|
|
|
|
switch(xc->timescale)
|
|
{
|
|
case 0: break;
|
|
|
|
case -1: time_scale = 100; time_dimension[0] = 'm'; break;
|
|
case -2: time_scale = 10;
|
|
case -3: time_dimension[0] = 'm'; break;
|
|
|
|
case -4: time_scale = 100; time_dimension[0] = 'u'; break;
|
|
case -5: time_scale = 10;
|
|
case -6: time_dimension[0] = 'u'; break;
|
|
|
|
case -10: time_scale = 100; time_dimension[0] = 'p'; break;
|
|
case -11: time_scale = 10;
|
|
case -12: time_dimension[0] = 'p'; break;
|
|
|
|
case -13: time_scale = 100; time_dimension[0] = 'f'; break;
|
|
case -14: time_scale = 10;
|
|
case -15: time_dimension[0] = 'f'; break;
|
|
|
|
case -16: time_scale = 100; time_dimension[0] = 'a'; break;
|
|
case -17: time_scale = 10;
|
|
case -18: time_dimension[0] = 'a'; break;
|
|
|
|
case -19: time_scale = 100; time_dimension[0] = 'z'; break;
|
|
case -20: time_scale = 10;
|
|
case -21: time_dimension[0] = 'z'; break;
|
|
|
|
case -7: time_scale = 100; time_dimension[0] = 'n'; break;
|
|
case -8: time_scale = 10;
|
|
case -9:
|
|
default: time_dimension[0] = 'n'; break;
|
|
}
|
|
|
|
if(fv) fprintf(fv, "$timescale\n\t%d%ss\n$end\n", time_scale, time_dimension);
|
|
}
|
|
|
|
xc->maxhandle = 0;
|
|
xc->num_alias = 0;
|
|
|
|
free(xc->signal_lens);
|
|
xc->signal_lens = malloc(num_signal_dyn*sizeof(uint32_t));
|
|
|
|
free(xc->signal_typs);
|
|
xc->signal_typs = malloc(num_signal_dyn*sizeof(unsigned char));
|
|
|
|
fseeko(xc->fh, 0, SEEK_SET);
|
|
while(!feof(xc->fh))
|
|
{
|
|
int tag = fgetc(xc->fh);
|
|
switch(tag)
|
|
{
|
|
case FST_ST_VCD_SCOPE:
|
|
scopetype = fgetc(xc->fh);
|
|
pnt = str;
|
|
while((ch = fgetc(xc->fh)))
|
|
{
|
|
*(pnt++) = ch;
|
|
}; /* scopename */
|
|
*pnt = 0;
|
|
while(fgetc(xc->fh)) { }; /* scopecomp */
|
|
|
|
if(fv) fprintf(fv, "$scope %s %s $end\n", modtypes[scopetype], str);
|
|
break;
|
|
|
|
case FST_ST_VCD_UPSCOPE:
|
|
if(fv) fprintf(fv, "$upscope $end\n");
|
|
break;
|
|
|
|
case FST_VT_VCD_EVENT:
|
|
case FST_VT_VCD_INTEGER:
|
|
case FST_VT_VCD_PARAMETER:
|
|
case FST_VT_VCD_REAL:
|
|
case FST_VT_VCD_REAL_PARAMETER:
|
|
case FST_VT_VCD_REG:
|
|
case FST_VT_VCD_SUPPLY0:
|
|
case FST_VT_VCD_SUPPLY1:
|
|
case FST_VT_VCD_TIME:
|
|
case FST_VT_VCD_TRI:
|
|
case FST_VT_VCD_TRIAND:
|
|
case FST_VT_VCD_TRIOR:
|
|
case FST_VT_VCD_TRIREG:
|
|
case FST_VT_VCD_TRI0:
|
|
case FST_VT_VCD_TRI1:
|
|
case FST_VT_VCD_WAND:
|
|
case FST_VT_VCD_WIRE:
|
|
case FST_VT_VCD_WOR:
|
|
case FST_VT_VCD_PORT:
|
|
case FST_VT_VCD_ARRAY:
|
|
case FST_VT_VCD_REALTIME:
|
|
vartype = tag;
|
|
/* vardir = */ fgetc(xc->fh); /* unused in VCD reader, but need to advance read pointer */
|
|
pnt = str;
|
|
while((ch = fgetc(xc->fh)))
|
|
{
|
|
*(pnt++) = ch;
|
|
}; /* varname */
|
|
*pnt = 0;
|
|
len = fstReaderVarint32(xc->fh);
|
|
alias = fstReaderVarint32(xc->fh);
|
|
|
|
if(!alias)
|
|
{
|
|
if(xc->maxhandle == num_signal_dyn)
|
|
{
|
|
num_signal_dyn *= 2;
|
|
xc->signal_lens = realloc(xc->signal_lens, num_signal_dyn*sizeof(uint32_t));
|
|
xc->signal_typs = realloc(xc->signal_typs, num_signal_dyn*sizeof(unsigned char));
|
|
}
|
|
xc->signal_lens[xc->maxhandle] = len;
|
|
xc->signal_typs[xc->maxhandle] = vartype;
|
|
|
|
maxvalpos+=len;
|
|
if(len > xc->longest_signal_value_len)
|
|
{
|
|
xc->longest_signal_value_len = len;
|
|
}
|
|
|
|
if((vartype == FST_VT_VCD_REAL) || (vartype == FST_VT_VCD_REAL_PARAMETER) || (vartype == FST_VT_VCD_REALTIME))
|
|
{
|
|
len = 64;
|
|
xc->signal_typs[xc->maxhandle] = FST_VT_VCD_REAL;
|
|
}
|
|
if(fv)
|
|
{
|
|
uint32_t modlen = (vartype != FST_VT_VCD_PORT) ? len : ((len - 2) / 3);
|
|
fprintf(fv, "$var %s %"PRIu32" %s %s $end\n", vartypes[vartype], modlen, fstVcdID(xc->maxhandle+1), str);
|
|
}
|
|
xc->maxhandle++;
|
|
}
|
|
else
|
|
{
|
|
if((vartype == FST_VT_VCD_REAL) || (vartype == FST_VT_VCD_REAL_PARAMETER) || (vartype == FST_VT_VCD_REALTIME))
|
|
{
|
|
len = 64;
|
|
xc->signal_typs[xc->maxhandle] = FST_VT_VCD_REAL;
|
|
}
|
|
if(fv)
|
|
{
|
|
uint32_t modlen = (vartype != FST_VT_VCD_PORT) ? len : ((len - 2) / 3);
|
|
fprintf(fv, "$var %s %"PRIu32" %s %s $end\n", vartypes[vartype], modlen, fstVcdID(alias), str);
|
|
}
|
|
xc->num_alias++;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if(fv) fprintf(fv, "$enddefinitions $end\n");
|
|
|
|
xc->signal_lens = realloc(xc->signal_lens, xc->maxhandle*sizeof(uint32_t));
|
|
xc->signal_typs = realloc(xc->signal_typs, xc->maxhandle*sizeof(unsigned char));
|
|
|
|
free(xc->process_mask);
|
|
xc->process_mask = calloc(1, (xc->maxhandle+7)/8);
|
|
|
|
free(xc->temp_signal_value_buf);
|
|
xc->temp_signal_value_buf = malloc(xc->longest_signal_value_len + 1);
|
|
|
|
xc->var_count = xc->maxhandle + xc->num_alias;
|
|
|
|
return(1);
|
|
}
|
|
|
|
|
|
/*
|
|
* reader file open/close functions
|
|
*/
|
|
int fstReaderInit(struct fstReaderContext *xc)
|
|
{
|
|
off_t blkpos = 0;
|
|
off_t endfile;
|
|
uint64_t seclen;
|
|
int sectype;
|
|
uint64_t vc_section_count_actual = 0;
|
|
int hdr_incomplete = 0;
|
|
int hdr_seen = 0;
|
|
int gzread_pass_status = 1;
|
|
|
|
sectype = fgetc(xc->f);
|
|
if(sectype == FST_BL_ZWRAPPER)
|
|
{
|
|
FILE *fcomp;
|
|
off_t offpnt, uclen;
|
|
char gz_membuf[FST_GZIO_LEN];
|
|
void *zhandle;
|
|
int zfd;
|
|
int flen = strlen(xc->filename);
|
|
char *hf;
|
|
|
|
seclen = fstReaderUint64(xc->f);
|
|
uclen = fstReaderUint64(xc->f);
|
|
|
|
if(!seclen) return(0); /* not finished compressing, this is a failed read */
|
|
|
|
hf = calloc(1, flen + 16 + 32 + 1);
|
|
|
|
sprintf(hf, "%s.upk_%d_%p", xc->filename, getpid(), (void *)xc);
|
|
fcomp = fopen(hf, "w+b");
|
|
if(!fcomp)
|
|
{
|
|
fcomp = tmpfile();
|
|
free(hf); hf = NULL;
|
|
if(!fcomp) return(0);
|
|
}
|
|
|
|
#if defined(FST_MACOSX)
|
|
setvbuf(fcomp, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */
|
|
#endif
|
|
|
|
#ifdef __MINGW32__
|
|
setvbuf(fcomp, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */
|
|
xc->filename_unpacked = hf;
|
|
#else
|
|
if(hf)
|
|
{
|
|
unlink(hf);
|
|
free(hf);
|
|
}
|
|
#endif
|
|
|
|
fseeko(xc->f, 1+8+8, SEEK_SET);
|
|
fflush(xc->f);
|
|
|
|
zfd = dup(fileno(xc->f));
|
|
zhandle = gzdopen(zfd, "rb");
|
|
if(zhandle)
|
|
{
|
|
for(offpnt = 0; offpnt < uclen; offpnt += FST_GZIO_LEN)
|
|
{
|
|
size_t this_len = ((uclen - offpnt) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - offpnt);
|
|
size_t gzreadlen = gzread(zhandle, gz_membuf, this_len);
|
|
size_t fwlen;
|
|
|
|
if(gzreadlen != this_len)
|
|
{
|
|
gzread_pass_status = 0;
|
|
break;
|
|
}
|
|
fwlen = fstFwrite(gz_membuf, this_len, 1, fcomp);
|
|
if(fwlen != 1)
|
|
{
|
|
gzread_pass_status = 0;
|
|
break;
|
|
}
|
|
}
|
|
gzclose(zhandle);
|
|
}
|
|
else
|
|
{
|
|
close(zfd);
|
|
}
|
|
fflush(fcomp);
|
|
fclose(xc->f);
|
|
xc->f = fcomp;
|
|
}
|
|
|
|
if(gzread_pass_status)
|
|
{
|
|
fseeko(xc->f, 0, SEEK_END);
|
|
endfile = ftello(xc->f);
|
|
|
|
while(blkpos < endfile)
|
|
{
|
|
fseeko(xc->f, blkpos, SEEK_SET);
|
|
|
|
sectype = fgetc(xc->f);
|
|
seclen = fstReaderUint64(xc->f);
|
|
|
|
if(sectype == EOF)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if(!hdr_seen && (sectype != FST_BL_HDR))
|
|
{
|
|
break;
|
|
}
|
|
|
|
blkpos++;
|
|
if(sectype == FST_BL_HDR)
|
|
{
|
|
if(!hdr_seen)
|
|
{
|
|
int ch;
|
|
double dcheck;
|
|
|
|
xc->start_time = fstReaderUint64(xc->f);
|
|
xc->end_time = fstReaderUint64(xc->f);
|
|
|
|
hdr_incomplete = (xc->start_time == 0) && (xc->end_time == 0);
|
|
|
|
fstFread(&dcheck, 8, 1, xc->f);
|
|
xc->double_endian_match = (dcheck == FST_DOUBLE_ENDTEST);
|
|
if(!xc->double_endian_match)
|
|
{
|
|
union {
|
|
unsigned char rvs_buf[8];
|
|
double d;
|
|
} vu;
|
|
|
|
unsigned char *dcheck_alias = (unsigned char *)&dcheck;
|
|
int rvs_idx;
|
|
|
|
for(rvs_idx=0;rvs_idx<8;rvs_idx++)
|
|
{
|
|
vu.rvs_buf[rvs_idx] = dcheck_alias[7-rvs_idx];
|
|
}
|
|
if(vu.d != FST_DOUBLE_ENDTEST)
|
|
{
|
|
break; /* either corrupt file or wrong architecture (offset +33 also functions as matchword) */
|
|
}
|
|
}
|
|
|
|
hdr_seen = 1;
|
|
|
|
xc->mem_used_by_writer = fstReaderUint64(xc->f);
|
|
xc->scope_count = fstReaderUint64(xc->f);
|
|
xc->var_count = fstReaderUint64(xc->f);
|
|
xc->maxhandle = fstReaderUint64(xc->f);
|
|
xc->num_alias = xc->var_count - xc->maxhandle;
|
|
xc->vc_section_count = fstReaderUint64(xc->f);
|
|
ch = fgetc(xc->f);
|
|
xc->timescale = (signed char)ch;
|
|
fstFread(xc->version, FST_HDR_SIM_VERSION_SIZE, 1, xc->f);
|
|
xc->version[FST_HDR_SIM_VERSION_SIZE] = 0;
|
|
fstFread(xc->date, FST_HDR_DATE_SIZE, 1, xc->f);
|
|
xc->date[FST_HDR_DATE_SIZE] = 0;
|
|
}
|
|
}
|
|
else if(sectype == FST_BL_VCDATA)
|
|
{
|
|
if(hdr_incomplete)
|
|
{
|
|
uint64_t bt = fstReaderUint64(xc->f);
|
|
xc->end_time = fstReaderUint64(xc->f);
|
|
|
|
if(!vc_section_count_actual) { xc->start_time = bt; }
|
|
}
|
|
|
|
vc_section_count_actual++;
|
|
}
|
|
else if(sectype == FST_BL_GEOM)
|
|
{
|
|
if(!hdr_incomplete)
|
|
{
|
|
uint64_t clen = seclen - 24;
|
|
uint64_t uclen = fstReaderUint64(xc->f);
|
|
unsigned char *ucdata = malloc(uclen);
|
|
unsigned char *pnt = ucdata;
|
|
int i;
|
|
|
|
xc->contains_geom_section = 1;
|
|
xc->maxhandle = fstReaderUint64(xc->f);
|
|
xc->longest_signal_value_len = 32; /* arbitrarily set at 32...this is much longer than an expanded double */
|
|
|
|
free(xc->process_mask);
|
|
xc->process_mask = calloc(1, (xc->maxhandle+7)/8);
|
|
|
|
if(clen != uclen)
|
|
{
|
|
unsigned char *cdata = malloc(clen);
|
|
unsigned long destlen = uclen;
|
|
unsigned long sourcelen = clen;
|
|
int rc;
|
|
|
|
fstFread(cdata, clen, 1, xc->f);
|
|
rc = uncompress(ucdata, &destlen, cdata, sourcelen);
|
|
|
|
if(rc != Z_OK)
|
|
{
|
|
printf("geom uncompress rc = %d\n", rc);
|
|
exit(255);
|
|
}
|
|
|
|
free(cdata);
|
|
}
|
|
else
|
|
{
|
|
fstFread(ucdata, uclen, 1, xc->f);
|
|
}
|
|
|
|
free(xc->signal_lens);
|
|
xc->signal_lens = malloc(sizeof(uint32_t) * xc->maxhandle);
|
|
free(xc->signal_typs);
|
|
xc->signal_typs = malloc(sizeof(unsigned char) * xc->maxhandle);
|
|
|
|
for(i=0;i<xc->maxhandle;i++)
|
|
{
|
|
int skiplen;
|
|
uint64_t val = fstGetVarint32(pnt, &skiplen);
|
|
|
|
pnt += skiplen;
|
|
|
|
if(val)
|
|
{
|
|
xc->signal_lens[i] = val;
|
|
xc->signal_typs[i] = FST_VT_VCD_WIRE;
|
|
if(val > xc->longest_signal_value_len)
|
|
{
|
|
xc->longest_signal_value_len = val;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
xc->signal_lens[i] = 8; /* backpatch in real */
|
|
xc->signal_typs[i] = FST_VT_VCD_REAL;
|
|
/* xc->longest_signal_value_len handled above by overly large init size */
|
|
}
|
|
}
|
|
|
|
free(xc->temp_signal_value_buf);
|
|
xc->temp_signal_value_buf = malloc(xc->longest_signal_value_len + 1);
|
|
|
|
free(ucdata);
|
|
}
|
|
}
|
|
else if(sectype == FST_BL_HIER)
|
|
{
|
|
xc->contains_hier_section = 1;
|
|
xc->hier_pos = ftello(xc->f);
|
|
}
|
|
else if(sectype == FST_BL_BLACKOUT)
|
|
{
|
|
uint32_t i;
|
|
uint64_t cur_bl = 0;
|
|
uint64_t delta;
|
|
|
|
xc->num_blackouts = fstReaderVarint32(xc->f);
|
|
free(xc->blackout_times);
|
|
xc->blackout_times = calloc(xc->num_blackouts, sizeof(uint64_t));
|
|
free(xc->blackout_activity);
|
|
xc->blackout_activity = calloc(xc->num_blackouts, sizeof(unsigned char));
|
|
|
|
for(i=0;i<xc->num_blackouts;i++)
|
|
{
|
|
xc->blackout_activity[i] = fgetc(xc->f) != 0;
|
|
delta = fstReaderVarint64(xc->f);
|
|
cur_bl += delta;
|
|
xc->blackout_times[i] = cur_bl;
|
|
}
|
|
}
|
|
|
|
blkpos += seclen;
|
|
if(!hdr_seen) break;
|
|
}
|
|
|
|
if(hdr_seen)
|
|
{
|
|
if(xc->vc_section_count != vc_section_count_actual)
|
|
{
|
|
xc->vc_section_count = vc_section_count_actual;
|
|
}
|
|
|
|
if(!xc->contains_geom_section)
|
|
{
|
|
fstReaderProcessHier(xc, NULL); /* recreate signal_lens/signal_typs info */
|
|
}
|
|
}
|
|
}
|
|
|
|
return(hdr_seen);
|
|
}
|
|
|
|
|
|
void *fstReaderOpen(const char *nam)
|
|
{
|
|
struct fstReaderContext *xc = calloc(1, sizeof(struct fstReaderContext));
|
|
|
|
if((!nam)||(!(xc->f=fopen(nam, "rb"))))
|
|
{
|
|
free(xc);
|
|
xc=NULL;
|
|
}
|
|
else
|
|
{
|
|
int flen = strlen(nam);
|
|
char *hf = calloc(1, flen + 6);
|
|
int rc;
|
|
|
|
#if defined(__MINGW32__) || defined(FST_MACOSX)
|
|
setvbuf(xc->f, (char *)NULL, _IONBF, 0); /* keeps gzip from acting weird in tandem with fopen */
|
|
#endif
|
|
|
|
memcpy(hf, nam, flen);
|
|
strcpy(hf + flen, ".hier");
|
|
xc->fh = fopen(hf, "rb");
|
|
|
|
free(hf);
|
|
xc->filename = strdup(nam);
|
|
rc = fstReaderInit(xc);
|
|
|
|
if((rc) && (xc->vc_section_count) && (xc->maxhandle) && ((xc->fh)||(xc->contains_hier_section)))
|
|
{
|
|
/* more init */
|
|
xc->do_rewind = 1;
|
|
}
|
|
else
|
|
{
|
|
fstReaderClose(xc);
|
|
xc = NULL;
|
|
}
|
|
}
|
|
|
|
return(xc);
|
|
}
|
|
|
|
|
|
static void fstReaderDeallocateRvatData(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
if(xc)
|
|
{
|
|
free(xc->rvat_chain_mem); xc->rvat_chain_mem = NULL;
|
|
free(xc->rvat_frame_data); xc->rvat_frame_data = NULL;
|
|
free(xc->rvat_time_table); xc->rvat_time_table = NULL;
|
|
free(xc->rvat_chain_table); xc->rvat_chain_table = NULL;
|
|
free(xc->rvat_chain_table_lengths); xc->rvat_chain_table_lengths = NULL;
|
|
|
|
xc->rvat_data_valid = 0;
|
|
}
|
|
}
|
|
|
|
|
|
void fstReaderClose(void *ctx)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
|
|
if(xc)
|
|
{
|
|
fstReaderDeallocateScopeData(xc);
|
|
fstReaderDeallocateRvatData(xc);
|
|
free(xc->rvat_sig_offs); xc->rvat_sig_offs = NULL;
|
|
|
|
free(xc->process_mask); xc->process_mask = NULL;
|
|
free(xc->blackout_times); xc->blackout_times = NULL;
|
|
free(xc->blackout_activity); xc->blackout_activity = NULL;
|
|
free(xc->temp_signal_value_buf); xc->temp_signal_value_buf = NULL;
|
|
free(xc->signal_typs); xc->signal_typs = NULL;
|
|
free(xc->signal_lens); xc->signal_lens = NULL;
|
|
free(xc->filename); xc->filename = NULL;
|
|
|
|
if(xc->fh)
|
|
{
|
|
fclose(xc->fh); xc->fh = NULL;
|
|
#ifdef __MINGW32__
|
|
if(xc->fh_name)
|
|
{
|
|
unlink(xc->fh_name);
|
|
free(xc->fh_name); xc->fh_name = NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if(xc->f)
|
|
{
|
|
fclose(xc->f); xc->f = NULL;
|
|
if(xc->filename_unpacked)
|
|
{
|
|
unlink(xc->filename_unpacked);
|
|
free(xc->filename_unpacked);
|
|
}
|
|
}
|
|
|
|
free(xc);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* read processing
|
|
*/
|
|
|
|
/* normal read which re-interleaves the value change data */
|
|
int fstReaderIterBlocks(void *ctx,
|
|
void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value),
|
|
void *user_callback_data_pointer, FILE *fv)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
|
|
uint64_t previous_time = UINT64_MAX;
|
|
uint64_t *time_table = NULL;
|
|
uint64_t tsec_nitems;
|
|
int secnum = 0;
|
|
off_t blkpos = 0;
|
|
uint64_t seclen, beg_tim, end_tim;
|
|
uint64_t frame_uclen, frame_clen, frame_maxhandle, vc_maxhandle;
|
|
off_t vc_start;
|
|
off_t indx_pntr, indx_pos;
|
|
off_t *chain_table = NULL;
|
|
uint32_t *chain_table_lengths = NULL;
|
|
unsigned char *chain_cmem;
|
|
unsigned char *pnt;
|
|
long chain_clen;
|
|
fstHandle idx, pidx=0, i;
|
|
uint64_t pval;
|
|
uint64_t vc_maxhandle_largest = 0;
|
|
uint64_t tsec_uclen = 0, tsec_clen = 0;
|
|
int sectype;
|
|
uint64_t mem_required_for_traversal;
|
|
unsigned char *mem_for_traversal = NULL;
|
|
uint32_t traversal_mem_offs;
|
|
uint32_t *scatterptr, *headptr, *length_remaining;
|
|
uint32_t cur_blackout = 0;
|
|
int packtype;
|
|
|
|
if(!xc) return(0);
|
|
|
|
scatterptr = calloc(xc->maxhandle, sizeof(uint32_t));
|
|
headptr = calloc(xc->maxhandle, sizeof(uint32_t));
|
|
length_remaining = calloc(xc->maxhandle, sizeof(uint32_t));
|
|
|
|
for(;;)
|
|
{
|
|
uint32_t *tc_head = NULL;
|
|
traversal_mem_offs = 0;
|
|
|
|
fseeko(xc->f, blkpos, SEEK_SET);
|
|
|
|
sectype = fgetc(xc->f);
|
|
seclen = fstReaderUint64(xc->f);
|
|
|
|
if((sectype == EOF) || (sectype == FST_BL_SKIP))
|
|
{
|
|
#ifdef FST_DEBUG
|
|
printf("<< EOF >>\n");
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
blkpos++;
|
|
if(sectype != FST_BL_VCDATA)
|
|
{
|
|
blkpos += seclen;
|
|
continue;
|
|
}
|
|
|
|
if(!seclen) break;
|
|
|
|
beg_tim = fstReaderUint64(xc->f);
|
|
end_tim = fstReaderUint64(xc->f);
|
|
|
|
if(xc->limit_range_valid)
|
|
{
|
|
if(beg_tim < xc->limit_range_start)
|
|
{
|
|
blkpos += seclen;
|
|
continue;
|
|
}
|
|
|
|
if(beg_tim > xc->limit_range_end) /* likely the compare in for(i=0;i<tsec_nitems;i++) below would do this earlier */
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
mem_required_for_traversal = fstReaderUint64(xc->f);
|
|
mem_for_traversal = malloc(mem_required_for_traversal + 66); /* add in potential fastlz overhead */
|
|
#ifdef FST_DEBUG
|
|
printf("sec: %d seclen: %d begtim: %d endtim: %d\n",
|
|
secnum, (int)seclen, (int)beg_tim, (int)end_tim);
|
|
printf("\tmem_required_for_traversal: %d\n", (int)mem_required_for_traversal);
|
|
#endif
|
|
/* process time block */
|
|
{
|
|
unsigned char *ucdata;
|
|
unsigned char *cdata;
|
|
unsigned long destlen = tsec_uclen;
|
|
unsigned long sourcelen = tsec_clen;
|
|
int rc;
|
|
unsigned char *tpnt;
|
|
uint64_t tpval;
|
|
int ti;
|
|
|
|
fseeko(xc->f, blkpos + seclen - 24, SEEK_SET);
|
|
tsec_uclen = fstReaderUint64(xc->f);
|
|
tsec_clen = fstReaderUint64(xc->f);
|
|
tsec_nitems = fstReaderUint64(xc->f);
|
|
#ifdef FST_DEBUG
|
|
printf("\ttime section unc: %d, com: %d (%d items)\n",
|
|
(int)tsec_uclen, (int)tsec_clen, (int)tsec_nitems);
|
|
#endif
|
|
ucdata = malloc(tsec_uclen);
|
|
destlen = tsec_uclen;
|
|
sourcelen = tsec_clen;
|
|
|
|
fseeko(xc->f, -24 - ((off_t)tsec_clen), SEEK_CUR);
|
|
|
|
if(tsec_uclen != tsec_clen)
|
|
{
|
|
cdata = malloc(tsec_clen);
|
|
fstFread(cdata, tsec_clen, 1, xc->f);
|
|
|
|
rc = uncompress(ucdata, &destlen, cdata, sourcelen);
|
|
|
|
if(rc != Z_OK)
|
|
{
|
|
printf("tsec uncompress rc = %d\n", rc);
|
|
exit(255);
|
|
}
|
|
|
|
free(cdata);
|
|
}
|
|
else
|
|
{
|
|
fstFread(ucdata, tsec_uclen, 1, xc->f);
|
|
}
|
|
|
|
free(time_table);
|
|
time_table = calloc(tsec_nitems, sizeof(uint64_t));
|
|
tpnt = ucdata;
|
|
tpval = 0;
|
|
for(ti=0;ti<tsec_nitems;ti++)
|
|
{
|
|
int skiplen;
|
|
uint64_t val = fstGetVarint64(tpnt, &skiplen);
|
|
tpval = time_table[ti] = tpval + val;
|
|
tpnt += skiplen;
|
|
}
|
|
|
|
tc_head = calloc(tsec_nitems, sizeof(uint32_t));
|
|
free(ucdata);
|
|
}
|
|
|
|
fseeko(xc->f, blkpos+32, SEEK_SET);
|
|
|
|
frame_uclen = fstReaderVarint64(xc->f);
|
|
frame_clen = fstReaderVarint64(xc->f);
|
|
frame_maxhandle = fstReaderVarint64(xc->f);
|
|
|
|
if(secnum == 0)
|
|
{
|
|
if(beg_tim != time_table[0])
|
|
{
|
|
unsigned char *mu = malloc(frame_uclen);
|
|
uint32_t sig_offs = 0;
|
|
|
|
if(fv)
|
|
{
|
|
if(beg_tim) { fprintf(fv, "#%"PRIu64"\n", beg_tim); }
|
|
if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts))
|
|
{
|
|
if(beg_tim == xc->blackout_times[cur_blackout])
|
|
{
|
|
fprintf(fv, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off");
|
|
}
|
|
}
|
|
}
|
|
|
|
if(frame_uclen == frame_clen)
|
|
{
|
|
fstFread(mu, frame_uclen, 1, xc->f);
|
|
}
|
|
else
|
|
{
|
|
unsigned char *mc = malloc(frame_clen);
|
|
int rc;
|
|
|
|
unsigned long destlen = frame_uclen;
|
|
unsigned long sourcelen = frame_clen;
|
|
|
|
fstFread(mc, sourcelen, 1, xc->f);
|
|
rc = uncompress(mu, &destlen, mc, sourcelen);
|
|
if(rc != Z_OK)
|
|
{
|
|
printf("rc: %d\n", rc);
|
|
exit(255);
|
|
}
|
|
free(mc);
|
|
}
|
|
|
|
|
|
for(idx=0;idx<frame_maxhandle;idx++)
|
|
{
|
|
int process_idx = idx/8;
|
|
int process_bit = idx&7;
|
|
|
|
if(xc->process_mask[process_idx]&(1<<process_bit))
|
|
{
|
|
if(xc->signal_lens[idx] == 1)
|
|
{
|
|
unsigned char val = mu[sig_offs];
|
|
if(value_change_callback)
|
|
{
|
|
xc->temp_signal_value_buf[0] = val;
|
|
xc->temp_signal_value_buf[1] = 0;
|
|
value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf);
|
|
}
|
|
else
|
|
{
|
|
if(fv)
|
|
{
|
|
int vcdid_len;
|
|
const char *vcd_id = fstVcdIDForFwrite(idx+1, &vcdid_len);
|
|
fputc(val, fv);
|
|
fstFwrite(vcd_id, vcdid_len, 1, fv);
|
|
fputc('\n', fv);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(xc->signal_typs[idx] != FST_VT_VCD_REAL)
|
|
{
|
|
if(value_change_callback)
|
|
{
|
|
memcpy(xc->temp_signal_value_buf, mu+sig_offs, xc->signal_lens[idx]);
|
|
xc->temp_signal_value_buf[xc->signal_lens[idx]] = 0;
|
|
value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf);
|
|
}
|
|
else
|
|
{
|
|
if(fv)
|
|
{
|
|
int vcdid_len;
|
|
const char *vcd_id = fstVcdIDForFwrite(idx+1, &vcdid_len);
|
|
fputc((xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p', fv);
|
|
fstFwrite(mu+sig_offs, xc->signal_lens[idx], 1, fv);
|
|
fputc(' ', fv);
|
|
fstFwrite(vcd_id, vcdid_len, 1, fv);
|
|
fputc('\n', fv);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
double d;
|
|
unsigned char *clone_d;
|
|
unsigned char *srcdata = mu+sig_offs;
|
|
|
|
if(value_change_callback)
|
|
{
|
|
if(xc->native_doubles_for_cb)
|
|
{
|
|
if(xc->double_endian_match)
|
|
{
|
|
clone_d = srcdata;
|
|
}
|
|
else
|
|
{
|
|
int j;
|
|
|
|
clone_d = (unsigned char *)&d;
|
|
for(j=0;j<8;j++)
|
|
{
|
|
clone_d[j] = srcdata[7-j];
|
|
}
|
|
}
|
|
value_change_callback(user_callback_data_pointer, beg_tim, idx+1, clone_d);
|
|
}
|
|
else
|
|
{
|
|
clone_d = (unsigned char *)&d;
|
|
if(xc->double_endian_match)
|
|
{
|
|
memcpy(clone_d, srcdata, 8);
|
|
}
|
|
else
|
|
{
|
|
int j;
|
|
|
|
for(j=0;j<8;j++)
|
|
{
|
|
clone_d[j] = srcdata[7-j];
|
|
}
|
|
}
|
|
sprintf((char *)xc->temp_signal_value_buf, "%.16g", d);
|
|
value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(fv)
|
|
{
|
|
clone_d = (unsigned char *)&d;
|
|
if(xc->double_endian_match)
|
|
{
|
|
memcpy(clone_d, srcdata, 8);
|
|
}
|
|
else
|
|
{
|
|
int j;
|
|
|
|
for(j=0;j<8;j++)
|
|
{
|
|
clone_d[j] = srcdata[7-j];
|
|
}
|
|
}
|
|
|
|
fprintf(fv, "r%.16g %s\n", d, fstVcdID(idx+1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sig_offs += xc->signal_lens[idx];
|
|
}
|
|
|
|
free(mu);
|
|
fseeko(xc->f, -((off_t)frame_clen), SEEK_CUR);
|
|
}
|
|
}
|
|
|
|
fseeko(xc->f, (off_t)frame_clen, SEEK_CUR); /* skip past compressed data */
|
|
|
|
vc_maxhandle = fstReaderVarint64(xc->f);
|
|
vc_start = ftello(xc->f); /* points to '!' character */
|
|
packtype = fgetc(xc->f);
|
|
|
|
#ifdef FST_DEBUG
|
|
printf("\tframe_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n",
|
|
(int)frame_uclen, (int)frame_clen, (int)frame_maxhandle);
|
|
printf("\tvc_maxhandle: %d, packtype: %c\n", (int)vc_maxhandle, packtype);
|
|
#endif
|
|
|
|
indx_pntr = blkpos + seclen - 24 -tsec_clen -8;
|
|
fseeko(xc->f, indx_pntr, SEEK_SET);
|
|
chain_clen = fstReaderUint64(xc->f);
|
|
indx_pos = indx_pntr - chain_clen;
|
|
#ifdef FST_DEBUG
|
|
printf("\tindx_pos: %d (%d bytes)\n", (int)indx_pos, (int)chain_clen);
|
|
#endif
|
|
chain_cmem = malloc(chain_clen);
|
|
fseeko(xc->f, indx_pos, SEEK_SET);
|
|
fstFread(chain_cmem, chain_clen, 1, xc->f);
|
|
|
|
if(vc_maxhandle > vc_maxhandle_largest)
|
|
{
|
|
free(chain_table);
|
|
free(chain_table_lengths);
|
|
|
|
vc_maxhandle_largest = vc_maxhandle;
|
|
chain_table = malloc((vc_maxhandle+1) * sizeof(off_t));
|
|
chain_table_lengths = malloc((vc_maxhandle+1) * sizeof(uint32_t));
|
|
}
|
|
|
|
pnt = chain_cmem;
|
|
idx = 0;
|
|
pval = 0;
|
|
do
|
|
{
|
|
int skiplen;
|
|
uint64_t val = fstGetVarint32(pnt, &skiplen);
|
|
|
|
if(val&1)
|
|
{
|
|
pval = chain_table[idx] = pval + (val >> 1);
|
|
if(idx) { chain_table_lengths[pidx] = pval - chain_table[pidx]; }
|
|
pidx = idx++;
|
|
}
|
|
else
|
|
{
|
|
int loopcnt = val >> 1;
|
|
for(i=0;i<loopcnt;i++)
|
|
{
|
|
chain_table[idx++] = 0;
|
|
}
|
|
}
|
|
|
|
pnt += skiplen;
|
|
} while (pnt != (chain_cmem + chain_clen));
|
|
chain_table[idx] = indx_pos - vc_start;
|
|
chain_table_lengths[pidx] = chain_table[idx] - chain_table[pidx];
|
|
#ifdef FST_DEBUG
|
|
printf("\tdecompressed chain idx len: %"PRIu32"\n", idx);
|
|
#endif
|
|
/* check compressed VC data */
|
|
if(idx > xc->maxhandle) idx = xc->maxhandle;
|
|
for(i=0;i<idx;i++)
|
|
{
|
|
if(chain_table[i])
|
|
{
|
|
int process_idx = i/8;
|
|
int process_bit = i&7;
|
|
|
|
if(xc->process_mask[process_idx]&(1<<process_bit))
|
|
{
|
|
int rc = Z_OK;
|
|
uint32_t val;
|
|
uint32_t skiplen;
|
|
uint32_t tdelta;
|
|
|
|
fseeko(xc->f, vc_start + chain_table[i], SEEK_SET);
|
|
val = fstReaderVarint32WithSkip(xc->f, &skiplen);
|
|
if(val)
|
|
{
|
|
unsigned char *mu = mem_for_traversal + traversal_mem_offs;
|
|
unsigned char *mc = malloc(chain_table_lengths[i]);
|
|
unsigned long destlen = val;
|
|
unsigned long sourcelen = chain_table_lengths[i];
|
|
|
|
fstFread(mc, chain_table_lengths[i], 1, xc->f);
|
|
if(packtype == 'F')
|
|
{
|
|
rc = fastlz_decompress(mc, sourcelen, mu, destlen);
|
|
}
|
|
else
|
|
{
|
|
rc = uncompress(mu, &destlen, mc, sourcelen);
|
|
}
|
|
free(mc);
|
|
/* data to process is for(j=0;j<destlen;j++) in mu[j] */
|
|
headptr[i] = traversal_mem_offs;
|
|
length_remaining[i] = val;
|
|
traversal_mem_offs += val;
|
|
}
|
|
else
|
|
{
|
|
int destlen = chain_table_lengths[i] - skiplen;
|
|
unsigned char *mu = mem_for_traversal + traversal_mem_offs;
|
|
fstFread(mu, destlen, 1, xc->f);
|
|
/* data to process is for(j=0;j<destlen;j++) in mu[j] */
|
|
headptr[i] = traversal_mem_offs;
|
|
length_remaining[i] = destlen;
|
|
traversal_mem_offs += destlen;
|
|
}
|
|
|
|
if(rc != Z_OK)
|
|
{
|
|
printf("\tclen: %d (rc=%d)\n", (int)val, rc);
|
|
exit(255);
|
|
}
|
|
|
|
if(xc->signal_lens[i] == 1)
|
|
{
|
|
uint32_t vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[i]);
|
|
uint32_t shcnt = 2 << (vli & 1);
|
|
tdelta = vli >> shcnt;
|
|
}
|
|
else
|
|
{
|
|
uint32_t vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[i]);
|
|
tdelta = vli >> 1;
|
|
}
|
|
|
|
scatterptr[i] = tc_head[tdelta];
|
|
tc_head[tdelta] = i+1;
|
|
}
|
|
}
|
|
}
|
|
|
|
for(i=0;i<tsec_nitems;i++)
|
|
{
|
|
uint32_t tdelta;
|
|
int skiplen;
|
|
uint32_t vli;
|
|
|
|
if(fv)
|
|
{
|
|
if(time_table[i] != previous_time)
|
|
{
|
|
if(xc->limit_range_valid)
|
|
{
|
|
if(time_table[i] > xc->limit_range_end)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
fprintf(fv, "#%"PRIu64"\n", time_table[i]);
|
|
if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts))
|
|
{
|
|
if(time_table[i] == xc->blackout_times[cur_blackout])
|
|
{
|
|
fprintf(fv, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off");
|
|
}
|
|
}
|
|
previous_time = time_table[i];
|
|
}
|
|
}
|
|
|
|
while(tc_head[i])
|
|
{
|
|
idx = tc_head[i] - 1;
|
|
vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen);
|
|
|
|
if(xc->signal_lens[idx] == 1)
|
|
{
|
|
unsigned char val;
|
|
if(!(vli & 1))
|
|
{
|
|
tdelta = vli >> 2;
|
|
val = ((vli >> 1) & 1) | '0';
|
|
}
|
|
else
|
|
{
|
|
tdelta = vli >> 4;
|
|
val = FST_RCV_STR[((vli >> 1) & 7)];
|
|
}
|
|
|
|
if(value_change_callback)
|
|
{
|
|
xc->temp_signal_value_buf[0] = val;
|
|
xc->temp_signal_value_buf[1] = 0;
|
|
value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf);
|
|
}
|
|
else
|
|
{
|
|
if(fv)
|
|
{
|
|
int vcdid_len;
|
|
const char *vcd_id = fstVcdIDForFwrite(idx+1, &vcdid_len);
|
|
fputc(val, fv);
|
|
fstFwrite(vcd_id, vcdid_len, 1, fv);
|
|
fputc('\n', fv);
|
|
}
|
|
}
|
|
headptr[idx] += skiplen;
|
|
length_remaining[idx] -= skiplen;
|
|
|
|
tc_head[i] = scatterptr[idx];
|
|
scatterptr[idx] = 0;
|
|
|
|
if(length_remaining[idx])
|
|
{
|
|
int shamt;
|
|
vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]);
|
|
shamt = 2 << (vli & 1);
|
|
tdelta = vli >> shamt;
|
|
|
|
scatterptr[idx] = tc_head[i+tdelta];
|
|
tc_head[i+tdelta] = idx+1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uint32_t len = xc->signal_lens[idx];
|
|
unsigned char *vdata;
|
|
|
|
vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen);
|
|
tdelta = vli >> 1;
|
|
vdata = mem_for_traversal + headptr[idx] + skiplen;
|
|
|
|
if(xc->signal_typs[idx] != FST_VT_VCD_REAL)
|
|
{
|
|
if(!(vli & 1))
|
|
{
|
|
int byte = 0;
|
|
int bit;
|
|
int j;
|
|
|
|
for(j=0;j<len;j++)
|
|
{
|
|
unsigned char ch;
|
|
byte = j/8;
|
|
bit = 7 - (j & 7);
|
|
ch = ((vdata[byte] >> bit) & 1) | '0';
|
|
xc->temp_signal_value_buf[j] = ch;
|
|
}
|
|
xc->temp_signal_value_buf[j] = 0;
|
|
|
|
if(value_change_callback)
|
|
{
|
|
value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf);
|
|
}
|
|
else
|
|
{
|
|
if(fv) {
|
|
fputc((xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p', fv);
|
|
fstFwrite(xc->temp_signal_value_buf, len, 1, fv);
|
|
}
|
|
}
|
|
|
|
len = byte+1;
|
|
}
|
|
else
|
|
{
|
|
if(value_change_callback)
|
|
{
|
|
memcpy(xc->temp_signal_value_buf, vdata, len);
|
|
xc->temp_signal_value_buf[len] = 0;
|
|
value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf);
|
|
}
|
|
else
|
|
{
|
|
if(fv)
|
|
{
|
|
fputc((xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p', fv);
|
|
fstFwrite(vdata, len, 1, fv);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
double d;
|
|
unsigned char *clone_d = (unsigned char *)&d;
|
|
unsigned char buf[8];
|
|
unsigned char *srcdata;
|
|
|
|
if(!(vli & 1)) /* very rare case, but possible */
|
|
{
|
|
int bit;
|
|
int j;
|
|
|
|
for(j=0;j<8;j++)
|
|
{
|
|
unsigned char ch;
|
|
bit = 7 - (j & 7);
|
|
ch = ((vdata[0] >> bit) & 1) | '0';
|
|
buf[j] = ch;
|
|
}
|
|
|
|
len = 1;
|
|
srcdata = buf;
|
|
}
|
|
else
|
|
{
|
|
srcdata = vdata;
|
|
}
|
|
|
|
if(value_change_callback)
|
|
{
|
|
if(xc->native_doubles_for_cb)
|
|
{
|
|
if(xc->double_endian_match)
|
|
{
|
|
clone_d = srcdata;
|
|
}
|
|
else
|
|
{
|
|
int j;
|
|
|
|
clone_d = (unsigned char *)&d;
|
|
for(j=0;j<8;j++)
|
|
{
|
|
clone_d[j] = srcdata[7-j];
|
|
}
|
|
}
|
|
value_change_callback(user_callback_data_pointer, time_table[i], idx+1, clone_d);
|
|
}
|
|
else
|
|
{
|
|
clone_d = (unsigned char *)&d;
|
|
if(xc->double_endian_match)
|
|
{
|
|
memcpy(clone_d, srcdata, 8);
|
|
}
|
|
else
|
|
{
|
|
int j;
|
|
|
|
for(j=0;j<8;j++)
|
|
{
|
|
clone_d[j] = srcdata[7-j];
|
|
}
|
|
}
|
|
sprintf((char *)xc->temp_signal_value_buf, "%.16g", d);
|
|
value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(fv)
|
|
{
|
|
clone_d = (unsigned char *)&d;
|
|
if(xc->double_endian_match)
|
|
{
|
|
memcpy(clone_d, srcdata, 8);
|
|
}
|
|
else
|
|
{
|
|
int j;
|
|
|
|
for(j=0;j<8;j++)
|
|
{
|
|
clone_d[j] = srcdata[7-j];
|
|
}
|
|
}
|
|
|
|
fprintf(fv, "r%.16g", d);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(fv)
|
|
{
|
|
int vcdid_len;
|
|
const char *vcd_id = fstVcdIDForFwrite(idx+1, &vcdid_len);
|
|
fputc(' ', fv);
|
|
fstFwrite(vcd_id, vcdid_len, 1, fv);
|
|
fputc('\n', fv);
|
|
}
|
|
|
|
skiplen += len;
|
|
headptr[idx] += skiplen;
|
|
length_remaining[idx] -= skiplen;
|
|
|
|
tc_head[i] = scatterptr[idx];
|
|
scatterptr[idx] = 0;
|
|
|
|
if(length_remaining[idx])
|
|
{
|
|
vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]);
|
|
tdelta = vli >> 1;
|
|
|
|
scatterptr[idx] = tc_head[i+tdelta];
|
|
tc_head[i+tdelta] = idx+1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
free(tc_head);
|
|
free(chain_cmem);
|
|
free(mem_for_traversal);
|
|
|
|
secnum++;
|
|
if(secnum == xc->vc_section_count) break; /* in case file is growing, keep with original block count */
|
|
blkpos += seclen;
|
|
}
|
|
|
|
free(length_remaining);
|
|
free(headptr);
|
|
free(scatterptr);
|
|
|
|
if(chain_table)
|
|
{
|
|
free(chain_table);
|
|
free(chain_table_lengths);
|
|
}
|
|
|
|
free(time_table);
|
|
|
|
return(1);
|
|
}
|
|
|
|
|
|
/* rvat functions */
|
|
|
|
static char *fstExtractRvatDataFromFrame(struct fstReaderContext *xc, fstHandle facidx, char *buf)
|
|
{
|
|
if(facidx >= xc->rvat_frame_maxhandle)
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
if(xc->signal_lens[facidx] == 1)
|
|
{
|
|
buf[0] = (char)xc->rvat_frame_data[xc->rvat_sig_offs[facidx]];
|
|
buf[1] = 0;
|
|
}
|
|
else
|
|
{
|
|
if(xc->signal_typs[facidx] != FST_VT_VCD_REAL)
|
|
{
|
|
memcpy(buf, xc->rvat_frame_data + xc->rvat_sig_offs[facidx], xc->signal_lens[facidx]);
|
|
buf[xc->signal_lens[facidx]] = 0;
|
|
}
|
|
else
|
|
{
|
|
double d;
|
|
unsigned char *clone_d = (unsigned char *)&d;
|
|
unsigned char *srcdata = xc->rvat_frame_data + xc->rvat_sig_offs[facidx];
|
|
|
|
if(xc->double_endian_match)
|
|
{
|
|
memcpy(clone_d, srcdata, 8);
|
|
}
|
|
else
|
|
{
|
|
int j;
|
|
|
|
for(j=0;j<8;j++)
|
|
{
|
|
clone_d[j] = srcdata[7-j];
|
|
}
|
|
}
|
|
|
|
sprintf((char *)buf, "%.16g", d);
|
|
}
|
|
}
|
|
|
|
return(buf);
|
|
}
|
|
|
|
|
|
char *fstReaderGetValueFromHandleAtTime(void *ctx, uint64_t tim, fstHandle facidx, char *buf)
|
|
{
|
|
struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|
off_t blkpos = 0, prev_blkpos;
|
|
uint64_t beg_tim, end_tim, beg_tim2, end_tim2;
|
|
int sectype;
|
|
int secnum = 0;
|
|
uint64_t seclen;
|
|
uint64_t tsec_uclen = 0, tsec_clen = 0;
|
|
uint64_t tsec_nitems;
|
|
uint64_t frame_uclen, frame_clen;
|
|
uint64_t mem_required_for_traversal;
|
|
off_t indx_pntr, indx_pos;
|
|
long chain_clen;
|
|
unsigned char *chain_cmem;
|
|
unsigned char *pnt;
|
|
fstHandle idx, pidx=0, i;
|
|
uint64_t pval;
|
|
|
|
if((!xc) || (!facidx) || (facidx > xc->maxhandle) || (!buf))
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
if(!xc->rvat_sig_offs)
|
|
{
|
|
uint32_t cur_offs = 0;
|
|
|
|
xc->rvat_sig_offs = calloc(xc->maxhandle, sizeof(uint32_t));
|
|
for(i=0;i<xc->maxhandle;i++)
|
|
{
|
|
xc->rvat_sig_offs[i] = cur_offs;
|
|
cur_offs += xc->signal_lens[i];
|
|
}
|
|
}
|
|
|
|
if(xc->rvat_data_valid)
|
|
{
|
|
if((xc->rvat_beg_tim <= tim) && (tim <= xc->rvat_end_tim))
|
|
{
|
|
goto process_value;
|
|
}
|
|
|
|
fstReaderDeallocateRvatData(xc);
|
|
}
|
|
|
|
xc->rvat_chain_pos_valid = 0;
|
|
|
|
for(;;)
|
|
{
|
|
fseeko(xc->f, (prev_blkpos = blkpos), SEEK_SET);
|
|
|
|
sectype = fgetc(xc->f);
|
|
seclen = fstReaderUint64(xc->f);
|
|
|
|
if((sectype == EOF) || (sectype == FST_BL_SKIP) || (!seclen))
|
|
{
|
|
return(NULL); /* if this loop exits on break, it's successful */
|
|
}
|
|
|
|
blkpos++;
|
|
if(sectype != FST_BL_VCDATA)
|
|
{
|
|
blkpos += seclen;
|
|
continue;
|
|
}
|
|
|
|
beg_tim = fstReaderUint64(xc->f);
|
|
end_tim = fstReaderUint64(xc->f);
|
|
|
|
if((beg_tim <= tim) && (tim <= end_tim))
|
|
{
|
|
if((tim == end_tim) && (tim != xc->end_time))
|
|
{
|
|
off_t cached_pos = ftello(xc->f);
|
|
fseeko(xc->f, blkpos, SEEK_SET);
|
|
|
|
sectype = fgetc(xc->f);
|
|
seclen = fstReaderUint64(xc->f);
|
|
|
|
beg_tim2 = fstReaderUint64(xc->f);
|
|
end_tim2 = fstReaderUint64(xc->f);
|
|
|
|
if((sectype != FST_BL_VCDATA) || (!seclen) || (beg_tim2 != tim))
|
|
{
|
|
blkpos = prev_blkpos;
|
|
break;
|
|
}
|
|
beg_tim = beg_tim2;
|
|
end_tim = end_tim2;
|
|
fseeko(xc->f, cached_pos, SEEK_SET);
|
|
}
|
|
break;
|
|
}
|
|
|
|
blkpos += seclen;
|
|
secnum++;
|
|
}
|
|
|
|
xc->rvat_beg_tim = beg_tim;
|
|
xc->rvat_end_tim = end_tim;
|
|
|
|
mem_required_for_traversal = fstReaderUint64(xc->f);
|
|
#ifdef FST_DEBUG
|
|
printf("rvat sec: %d seclen: %d begtim: %d endtim: %d\n",
|
|
secnum, (int)seclen, (int)beg_tim, (int)end_tim);
|
|
printf("\tmem_required_for_traversal: %d\n", (int)mem_required_for_traversal);
|
|
#endif
|
|
|
|
/* process time block */
|
|
{
|
|
unsigned char *ucdata;
|
|
unsigned char *cdata;
|
|
unsigned long destlen = tsec_uclen;
|
|
unsigned long sourcelen = tsec_clen;
|
|
int rc;
|
|
unsigned char *tpnt;
|
|
uint64_t tpval;
|
|
int ti;
|
|
|
|
fseeko(xc->f, blkpos + seclen - 24, SEEK_SET);
|
|
tsec_uclen = fstReaderUint64(xc->f);
|
|
tsec_clen = fstReaderUint64(xc->f);
|
|
tsec_nitems = fstReaderUint64(xc->f);
|
|
#ifdef FST_DEBUG
|
|
printf("\ttime section unc: %d, com: %d (%d items)\n",
|
|
(int)tsec_uclen, (int)tsec_clen, (int)tsec_nitems);
|
|
#endif
|
|
ucdata = malloc(tsec_uclen);
|
|
destlen = tsec_uclen;
|
|
sourcelen = tsec_clen;
|
|
|
|
fseeko(xc->f, -24 - ((off_t)tsec_clen), SEEK_CUR);
|
|
if(tsec_uclen != tsec_clen)
|
|
{
|
|
cdata = malloc(tsec_clen);
|
|
fstFread(cdata, tsec_clen, 1, xc->f);
|
|
|
|
rc = uncompress(ucdata, &destlen, cdata, sourcelen);
|
|
|
|
if(rc != Z_OK)
|
|
{
|
|
printf("tsec uncompress rc = %d\n", rc);
|
|
exit(255);
|
|
}
|
|
|
|
free(cdata);
|
|
}
|
|
else
|
|
{
|
|
fstFread(ucdata, tsec_uclen, 1, xc->f);
|
|
}
|
|
|
|
xc->rvat_time_table = calloc(tsec_nitems, sizeof(uint64_t));
|
|
tpnt = ucdata;
|
|
tpval = 0;
|
|
for(ti=0;ti<tsec_nitems;ti++)
|
|
{
|
|
int skiplen;
|
|
uint64_t val = fstGetVarint64(tpnt, &skiplen);
|
|
tpval = xc->rvat_time_table[ti] = tpval + val;
|
|
tpnt += skiplen;
|
|
}
|
|
|
|
free(ucdata);
|
|
}
|
|
|
|
fseeko(xc->f, blkpos+32, SEEK_SET);
|
|
|
|
frame_uclen = fstReaderVarint64(xc->f);
|
|
frame_clen = fstReaderVarint64(xc->f);
|
|
xc->rvat_frame_maxhandle = fstReaderVarint64(xc->f);
|
|
xc->rvat_frame_data = malloc(frame_uclen);
|
|
|
|
if(frame_uclen == frame_clen)
|
|
{
|
|
fstFread(xc->rvat_frame_data, frame_uclen, 1, xc->f);
|
|
}
|
|
else
|
|
{
|
|
unsigned char *mc = malloc(frame_clen);
|
|
int rc;
|
|
|
|
unsigned long destlen = frame_uclen;
|
|
unsigned long sourcelen = frame_clen;
|
|
|
|
fstFread(mc, sourcelen, 1, xc->f);
|
|
rc = uncompress(xc->rvat_frame_data, &destlen, mc, sourcelen);
|
|
if(rc != Z_OK)
|
|
{
|
|
printf("decompress rc: %d\n", rc);
|
|
exit(255);
|
|
}
|
|
free(mc);
|
|
}
|
|
|
|
xc->rvat_vc_maxhandle = fstReaderVarint64(xc->f);
|
|
xc->rvat_vc_start = ftello(xc->f); /* points to '!' character */
|
|
|
|
#ifdef FST_DEBUG
|
|
printf("\tframe_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n",
|
|
(int)frame_uclen, (int)frame_clen, (int)xc->rvat_frame_maxhandle);
|
|
printf("\tvc_maxhandle: %d\n", (int)xc->rvat_vc_maxhandle);
|
|
#endif
|
|
|
|
indx_pntr = blkpos + seclen - 24 -tsec_clen -8;
|
|
fseeko(xc->f, indx_pntr, SEEK_SET);
|
|
chain_clen = fstReaderUint64(xc->f);
|
|
indx_pos = indx_pntr - chain_clen;
|
|
#ifdef FST_DEBUG
|
|
printf("\tindx_pos: %d (%d bytes)\n", (int)indx_pos, (int)chain_clen);
|
|
#endif
|
|
chain_cmem = malloc(chain_clen);
|
|
fseeko(xc->f, indx_pos, SEEK_SET);
|
|
fstFread(chain_cmem, chain_clen, 1, xc->f);
|
|
|
|
xc->rvat_chain_table = malloc((xc->rvat_vc_maxhandle+1) * sizeof(off_t));
|
|
xc->rvat_chain_table_lengths = malloc((xc->rvat_vc_maxhandle+1) * sizeof(uint32_t));
|
|
|
|
pnt = chain_cmem;
|
|
idx = 0;
|
|
pval = 0;
|
|
do
|
|
{
|
|
int skiplen;
|
|
uint64_t val = fstGetVarint32(pnt, &skiplen);
|
|
|
|
if(val&1)
|
|
{
|
|
pval = xc->rvat_chain_table[idx] = pval + (val >> 1);
|
|
if(idx) { xc->rvat_chain_table_lengths[pidx] = pval - xc->rvat_chain_table[pidx]; }
|
|
pidx = idx++;
|
|
}
|
|
else
|
|
{
|
|
int loopcnt = val >> 1;
|
|
for(i=0;i<loopcnt;i++)
|
|
{
|
|
xc->rvat_chain_table[idx++] = 0;
|
|
}
|
|
}
|
|
|
|
pnt += skiplen;
|
|
} while (pnt != (chain_cmem + chain_clen));
|
|
|
|
free(chain_cmem);
|
|
xc->rvat_chain_table[idx] = indx_pos - xc->rvat_vc_start;
|
|
xc->rvat_chain_table_lengths[pidx] = xc->rvat_chain_table[idx] - xc->rvat_chain_table[pidx];
|
|
|
|
#ifdef FST_DEBUG
|
|
printf("\tdecompressed chain idx len: %"PRIu32"\n", idx);
|
|
#endif
|
|
|
|
xc->rvat_data_valid = 1;
|
|
|
|
/* all data at this point is loaded or resident in fst cache, process and return appropriate value */
|
|
process_value:
|
|
if(facidx > xc->rvat_vc_maxhandle)
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
facidx--; /* scale down for array which starts at zero */
|
|
|
|
|
|
if(((tim == xc->rvat_beg_tim)&&(!xc->rvat_chain_table[facidx])) || (!xc->rvat_chain_table[facidx]))
|
|
{
|
|
return(fstExtractRvatDataFromFrame(xc, facidx, buf));
|
|
}
|
|
|
|
if(facidx != xc->rvat_chain_facidx)
|
|
{
|
|
if(xc->rvat_chain_mem)
|
|
{
|
|
free(xc->rvat_chain_mem);
|
|
xc->rvat_chain_mem = NULL;
|
|
|
|
xc->rvat_chain_pos_valid = 0;
|
|
}
|
|
}
|
|
|
|
if(!xc->rvat_chain_mem)
|
|
{
|
|
uint32_t skiplen;
|
|
fseeko(xc->f, xc->rvat_vc_start + xc->rvat_chain_table[facidx], SEEK_SET);
|
|
xc->rvat_chain_len = fstReaderVarint32WithSkip(xc->f, &skiplen);
|
|
if(xc->rvat_chain_len)
|
|
{
|
|
unsigned char *mu = malloc(xc->rvat_chain_len);
|
|
unsigned char *mc = malloc(xc->rvat_chain_table_lengths[facidx]);
|
|
unsigned long destlen = xc->rvat_chain_len;
|
|
unsigned long sourcelen = xc->rvat_chain_table_lengths[facidx];
|
|
int rc;
|
|
|
|
fstFread(mc, xc->rvat_chain_table_lengths[facidx], 1, xc->f);
|
|
rc = uncompress(mu, &destlen, mc, sourcelen);
|
|
free(mc);
|
|
|
|
if(rc != Z_OK)
|
|
{
|
|
printf("\tclen: %d (rc=%d)\n", (int)xc->rvat_chain_len, rc);
|
|
exit(255);
|
|
}
|
|
|
|
/* data to process is for(j=0;j<destlen;j++) in mu[j] */
|
|
xc->rvat_chain_mem = mu;
|
|
}
|
|
else
|
|
{
|
|
int destlen = xc->rvat_chain_table_lengths[facidx] - skiplen;
|
|
unsigned char *mu = malloc(xc->rvat_chain_len = destlen);
|
|
fstFread(mu, destlen, 1, xc->f);
|
|
/* data to process is for(j=0;j<destlen;j++) in mu[j] */
|
|
xc->rvat_chain_mem = mu;
|
|
}
|
|
|
|
xc->rvat_chain_facidx = facidx;
|
|
}
|
|
|
|
/* process value chain here */
|
|
|
|
{
|
|
uint32_t tidx = 0, ptidx = 0;
|
|
uint32_t tdelta;
|
|
int skiplen;
|
|
int iprev = xc->rvat_chain_len;
|
|
uint32_t pvli = 0;
|
|
int pskip = 0;
|
|
|
|
if((xc->rvat_chain_pos_valid)&&(tim >= xc->rvat_chain_pos_time))
|
|
{
|
|
i = xc->rvat_chain_pos_idx;
|
|
tidx = xc->rvat_chain_pos_tidx;
|
|
}
|
|
else
|
|
{
|
|
i = 0;
|
|
tidx = 0;
|
|
xc->rvat_chain_pos_time = xc->rvat_beg_tim;
|
|
}
|
|
|
|
if(xc->signal_lens[facidx] == 1)
|
|
{
|
|
while(i<xc->rvat_chain_len)
|
|
{
|
|
uint32_t vli = fstGetVarint32(xc->rvat_chain_mem + i, &skiplen);
|
|
uint32_t shcnt = 2 << (vli & 1);
|
|
tdelta = vli >> shcnt;
|
|
|
|
if(xc->rvat_time_table[tidx + tdelta] <= tim)
|
|
{
|
|
iprev = i;
|
|
pvli = vli;
|
|
ptidx = tidx;
|
|
pskip = skiplen;
|
|
|
|
tidx += tdelta;
|
|
i+=skiplen;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if(iprev != xc->rvat_chain_len)
|
|
{
|
|
xc->rvat_chain_pos_tidx = ptidx;
|
|
xc->rvat_chain_pos_idx = iprev;
|
|
xc->rvat_chain_pos_time = tim;
|
|
xc->rvat_chain_pos_valid = 1;
|
|
|
|
if(!(pvli & 1))
|
|
{
|
|
buf[0] = ((pvli >> 1) & 1) | '0';
|
|
}
|
|
else
|
|
{
|
|
buf[0] = FST_RCV_STR[((pvli >> 1) & 7)];
|
|
}
|
|
buf[1] = 0;
|
|
return(buf);
|
|
}
|
|
else
|
|
{
|
|
return(fstExtractRvatDataFromFrame(xc, facidx, buf));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while(i<xc->rvat_chain_len)
|
|
{
|
|
uint32_t vli = fstGetVarint32(xc->rvat_chain_mem + i, &skiplen);
|
|
tdelta = vli >> 1;
|
|
|
|
if(xc->rvat_time_table[tidx + tdelta] <= tim)
|
|
{
|
|
iprev = i;
|
|
pvli = vli;
|
|
ptidx = tidx;
|
|
pskip = skiplen;
|
|
|
|
tidx += tdelta;
|
|
i+=skiplen;
|
|
|
|
if(!(pvli & 1))
|
|
{
|
|
i+=((xc->signal_lens[facidx]+7)/8);
|
|
}
|
|
else
|
|
{
|
|
i+=xc->signal_lens[facidx];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(iprev != xc->rvat_chain_len)
|
|
{
|
|
unsigned char *vdata = xc->rvat_chain_mem + iprev + pskip;
|
|
|
|
xc->rvat_chain_pos_tidx = ptidx;
|
|
xc->rvat_chain_pos_idx = iprev;
|
|
xc->rvat_chain_pos_time = tim;
|
|
xc->rvat_chain_pos_valid = 1;
|
|
|
|
if(xc->signal_typs[facidx] != FST_VT_VCD_REAL)
|
|
{
|
|
if(!(pvli & 1))
|
|
{
|
|
int byte = 0;
|
|
int bit;
|
|
int j;
|
|
|
|
for(j=0;j<xc->signal_lens[facidx];j++)
|
|
{
|
|
unsigned char ch;
|
|
byte = j/8;
|
|
bit = 7 - (j & 7);
|
|
ch = ((vdata[byte] >> bit) & 1) | '0';
|
|
buf[j] = ch;
|
|
}
|
|
buf[j] = 0;
|
|
|
|
return(buf);
|
|
}
|
|
else
|
|
{
|
|
memcpy(buf, vdata, xc->signal_lens[facidx]);
|
|
buf[xc->signal_lens[facidx]] = 0;
|
|
return(buf);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
double d;
|
|
unsigned char *clone_d = (unsigned char *)&d;
|
|
unsigned char bufd[8];
|
|
unsigned char *srcdata;
|
|
|
|
if(!(pvli & 1)) /* very rare case, but possible */
|
|
{
|
|
int bit;
|
|
int j;
|
|
|
|
for(j=0;j<8;j++)
|
|
{
|
|
unsigned char ch;
|
|
bit = 7 - (j & 7);
|
|
ch = ((vdata[0] >> bit) & 1) | '0';
|
|
bufd[j] = ch;
|
|
}
|
|
|
|
srcdata = bufd;
|
|
}
|
|
else
|
|
{
|
|
srcdata = vdata;
|
|
}
|
|
|
|
if(xc->double_endian_match)
|
|
{
|
|
memcpy(clone_d, srcdata, 8);
|
|
}
|
|
else
|
|
{
|
|
int j;
|
|
|
|
for(j=0;j<8;j++)
|
|
{
|
|
clone_d[j] = srcdata[7-j];
|
|
}
|
|
}
|
|
|
|
sprintf(buf, "r%.16g", d);
|
|
return(buf);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return(fstExtractRvatDataFromFrame(xc, facidx, buf));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* return(NULL); */
|
|
}
|