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