diff --git a/config.h.in b/config.h.in index cce688618..85b9d1384 100644 --- a/config.h.in +++ b/config.h.in @@ -1,7 +1,7 @@ #ifndef __config_H /* -*- c++ -*- */ #define __config_H /* - * Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -52,6 +52,8 @@ /* These two are needed by the lxt and lxt2 files (copied from GTKWave). */ # undef HAVE_ALLOCA_H # undef HAVE_FSEEKO +/* And this is needed by the fst files (copied from GTKWave). */ +# undef HAVE_LIBPTHREAD /* * Define this if you want to compile vvp with memory freeing and diff --git a/vpi/fstapi.c b/vpi/fstapi.c index f59a12fc8..d23b84388 100644 --- a/vpi/fstapi.c +++ b/vpi/fstapi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2011 Tony Bybell. + * Copyright (c) 2009-2012 Tony Bybell. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,13 @@ #include "fstapi.h" #include "fastlz.h" +#ifndef HAVE_LIBPTHREAD +#undef FST_WRITER_PARALLEL +#endif + +#ifdef FST_WRITER_PARALLEL +#include +#endif /* this define is to force writer backward compatibility with old readers */ #ifndef FST_DYNAMIC_ALIAS_DISABLE @@ -47,13 +54,17 @@ void **JenkinsIns(void *base_i, unsigned char *mem, uint32_t length, uint32_t ha #undef FST_DEBUG -#define FST_BREAK_SIZE (128 * 1024 * 1024) -#define FST_BREAK_ADD_SIZE (4 * 1024 * 1024) +#define FST_BREAK_SIZE (1UL << 27) +#define FST_BREAK_ADD_SIZE (1UL << 22) +#define FST_BREAK_SIZE_MAX (1UL << 31) +#define FST_ACTIVATE_HUGE_BREAK (2000000) +#define FST_ACTIVATE_HUGE_INC (2000000) + #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_HDR_DATE_SIZE (120) #define FST_GZIO_LEN (32768) #if defined(__i386__) || defined(__x86_64__) || defined(_AIX) @@ -73,8 +84,8 @@ void **JenkinsIns(void *base_i, unsigned char *mem, uint32_t length, uint32_t ha #ifdef __MINGW32__ #include -#define ftello ftell -#define fseeko fseek +/* #define ftello ftell */ +/* #define fseeko fseek */ #endif @@ -480,6 +491,7 @@ unsigned vc_emitted : 1; unsigned is_initial_time : 1; unsigned fastpack : 1; +int64_t timezero; off_t section_header_truncpos; uint32_t tchn_cnt, tchn_idx; uint64_t curtime; @@ -506,10 +518,29 @@ unsigned skip_writing_section_hdr : 1; unsigned size_limit_locked : 1; unsigned section_header_only : 1; unsigned flush_context_pending : 1; +unsigned parallel_enabled : 1; +unsigned parallel_was_enabled : 1; /* should really be semaphores, but are bytes to cut down on read-modify-write window size */ unsigned char already_in_flush; /* in case control-c handlers interrupt */ unsigned char already_in_close; /* in case control-c handlers interrupt */ + +#ifdef FST_WRITER_PARALLEL +pthread_mutex_t mutex; +pthread_t thread; +pthread_attr_t thread_attr; +struct fstWriterContext *xc_parent; +#endif + +size_t fst_orig_break_size; +size_t fst_orig_break_add_size; + +size_t fst_break_size; +size_t fst_break_add_size; + +size_t fst_huge_break_size; + +fstHandle next_huge_break; }; @@ -603,7 +634,7 @@ fstWriterUint64(xc->handle, 0); /* +17 end time */ 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 */ +fstWriterUint64(xc->handle, xc->fst_break_size);/* +33 memory used by writer */ #define FST_HDR_OFFS_NUM_SCOPES (FST_HDR_OFFS_MEM_USED + 8) fstWriterUint64(xc->handle, 0); /* +41 scope creation count */ @@ -631,7 +662,12 @@ 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) +/* date size is deliberately overspecified at 120 bytes in order to provide backfill for new args */ + +#define FST_HDR_OFFS_TIMEZERO (FST_HDR_OFFS_DATE + FST_HDR_DATE_SIZE) +fstWriterUint64(xc->handle, xc->timezero); /* +322 timezero */ + +#define FST_HDR_LENGTH (FST_HDR_OFFS_TIMEZERO + 8) /* +330 next section starts here */ fflush(xc->handle); } @@ -703,6 +739,79 @@ xc->curval_mem = NULL; } +/* + * set up large and small memory usages + * crossover point in model is FST_ACTIVATE_HUGE_BREAK number of signals + */ +static void fstDetermineBreakSize(struct fstWriterContext *xc) +{ +#if defined(__linux__) || defined(FST_MACOSX) + +#ifdef __linux__ +FILE *f = fopen("/proc/meminfo", "rb"); +#else +FILE *f = popen("system_profiler", "r"); +#endif + +int was_set = 0; + +if(f) + { + char buf[257]; + char *s; + while(!feof(f)) + { + buf[0] = 0; + s = fgets(buf, 256, f); + if(s && *s) + { +#ifdef __linux__ + if(!strncmp(s, "MemTotal:", 9)) + { + size_t v = atol(s+10); + v *= 1024; /* convert to bytes */ +#else + if((s=strstr(s, "Memory:"))) + { + size_t v = atol(s+7); + v <<= 30; /* convert GB to bytes */ +#endif + + v /= 8; /* chop down to 1/8 physical memory */ + if(v > FST_BREAK_SIZE) + { + if(v > FST_BREAK_SIZE_MAX) + { + v = FST_BREAK_SIZE_MAX; + } + + xc->fst_huge_break_size = v; + was_set = 1; + break; + } + } + } + } + +#ifdef __linux__ + fclose(f); +#else + pclose(f); +#endif + } + +if(!was_set) +#endif + { + xc->fst_huge_break_size = FST_BREAK_SIZE; + } + +xc->fst_break_size = xc->fst_orig_break_size = FST_BREAK_SIZE; +xc->fst_break_add_size = xc->fst_orig_break_add_size = FST_BREAK_ADD_SIZE; +xc->next_huge_break = FST_ACTIVATE_HUGE_BREAK; +} + + /* * file creation and close */ @@ -711,6 +820,7 @@ void *fstWriterCreate(const char *nam, int use_compressed_hier) struct fstWriterContext *xc = calloc(1, sizeof(struct fstWriterContext)); xc->compress_hier = use_compressed_hier; +fstDetermineBreakSize(xc); if((!nam)||(!(xc->handle=unlink_fopen(nam, "w+b")))) { @@ -730,7 +840,7 @@ if((!nam)||(!(xc->handle=unlink_fopen(nam, "w+b")))) xc->valpos_handle = tmpfile(); /* .offs */ xc->curval_handle = tmpfile(); /* .bits */ xc->tchn_handle = tmpfile(); /* .tchn */ - xc->vchg_alloc_siz = FST_BREAK_SIZE + FST_BREAK_ADD_SIZE; + xc->vchg_alloc_siz = xc->fst_break_size + xc->fst_break_add_size; xc->vchg_mem = malloc(xc->vchg_alloc_siz); free(hf); @@ -741,6 +851,11 @@ if((!nam)||(!(xc->handle=unlink_fopen(nam, "w+b")))) fstWriterEmitHdrBytes(xc); xc->nan = strtod("NaN", NULL); +#ifdef FST_WRITER_PARALLEL + pthread_mutex_init(&xc->mutex, NULL); + pthread_attr_init(&xc->thread_attr); + pthread_attr_setdetachstate(&xc->thread_attr, PTHREAD_CREATE_DETACHED); +#endif } else { @@ -778,6 +893,9 @@ if(xc) fputc(FST_BL_SKIP, xc->handle); /* temporarily tag the section, use FST_BL_VCDATA on finalize */ xc->section_start = ftello(xc->handle); +#ifdef FST_WRITER_PARALLEL + if(xc->xc_parent) xc->xc_parent->section_start = xc->section_start; +#endif xc->section_header_only = 1; /* indicates truncate might be needed */ fstWriterUint64(xc->handle, 0); /* placeholder = section length */ fstWriterUint64(xc->handle, xc->is_initial_time ? xc->firsttime : xc->curtime); /* begin time of section */ @@ -813,7 +931,11 @@ if(xc) * only to be called directly by fst code...otherwise must * be synced up with time changes */ +#ifdef FST_WRITER_PARALLEL +static void fstWriterFlushContextPrivate2(void *ctx) +#else static void fstWriterFlushContextPrivate(void *ctx) +#endif { #ifdef FST_DEBUG int cnt = 0; @@ -833,6 +955,11 @@ unsigned char *packmem; unsigned int packmemlen; uint32_t *vm4ip; struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +#ifdef FST_WRITER_PARALLEL +struct fstWriterContext *xc2 = xc->xc_parent; +#else +struct fstWriterContext *xc2 = xc; +#endif #ifndef FST_DYNAMIC_ALIAS_DISABLE Pvoid_t PJHSArray = (Pvoid_t) NULL; @@ -880,8 +1007,9 @@ for(i=0;imaxhandle;i++) if(vm4ip[1] == 1) { wrlen = fstGetVarint32Length(vchg_mem + offs + 4); /* used to advance and determine wrlen */ +#ifndef FST_REMOVE_DUPLICATE_VC xc->curval_mem[vm4ip[0]] = vchg_mem[offs + 4 + wrlen]; /* checkpoint variable */ - +#endif while(offs) { unsigned char val; @@ -941,8 +1069,9 @@ for(i=0;imaxhandle;i++) else { wrlen = fstGetVarint32Length(vchg_mem + offs + 4); /* used to advance and determine wrlen */ +#ifndef FST_REMOVE_DUPLICATE_VC memcpy(xc->curval_mem + vm4ip[0], vchg_mem + offs + 4 + wrlen, vm4ip[1]); /* checkpoint variable */ - +#endif while(offs) { int idx; @@ -1137,7 +1266,7 @@ for(i=0;imaxhandle;i++) #endif } - vm4ip[3] = 0; + /* vm4ip[3] = 0; ...redundant with clearing below */ #ifdef FST_DEBUG cnt++; #endif @@ -1253,21 +1382,21 @@ 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 */ +xc2->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 */ + xc2->skip_writing_section_hdr = 1; + xc2->size_limit_locked = 1; + xc2->is_initial_time = 1; /* to trick emit value and emit time change */ #ifdef FST_DEBUG printf("<< dump file size limit reached, stopping dumping >>\n"); #endif } } -if(!xc->skip_writing_section_hdr) +if(!xc2->skip_writing_section_hdr) { fstWriterEmitSectionHeader(xc); /* emit next section header */ } @@ -1277,6 +1406,89 @@ xc->already_in_flush = 0; } +#ifdef FST_WRITER_PARALLEL +static void *fstWriterFlushContextPrivate1(void *ctx) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; + +fstWriterFlushContextPrivate2(xc); + +pthread_mutex_unlock(&(xc->xc_parent->mutex)); + +#ifdef FST_REMOVE_DUPLICATE_VC +free(xc->curval_mem); +#endif +free(xc->valpos_mem); +free(xc->vchg_mem); +fclose(xc->tchn_handle); +free(xc); + +return(NULL); +} + + +static void fstWriterFlushContextPrivate(void *ctx) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; + +if(xc->parallel_enabled) + { + struct fstWriterContext *xc2 = malloc(sizeof(struct fstWriterContext)); + int i; + + pthread_mutex_lock(&xc->mutex); + pthread_mutex_unlock(&xc->mutex); + + xc->xc_parent = xc; + memcpy(xc2, xc, sizeof(struct fstWriterContext)); + + xc2->valpos_mem = malloc(xc->maxhandle * 4 * sizeof(uint32_t)); + memcpy(xc2->valpos_mem, xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t)); + + /* curval mem is updated in the thread */ +#ifdef FST_REMOVE_DUPLICATE_VC + xc2->curval_mem = malloc(xc->maxvalpos); + memcpy(xc2->curval_mem, xc->curval_mem, xc->maxvalpos); +#endif + + xc->vchg_mem = malloc(xc->vchg_alloc_siz); + xc->vchg_mem[0] = '!'; + xc->vchg_siz = 1; + + for(i=0;imaxhandle;i++) + { + uint32_t *vm4ip = &(xc->valpos_mem[4*i]); + vm4ip[2] = 0; /* zero out offset val */ + vm4ip[3] = 0; /* zero out last time change val */ + } + + xc->tchn_cnt = xc->tchn_idx = 0; + xc->tchn_handle = tmpfile(); + fseeko(xc->tchn_handle, 0, SEEK_SET); + fstFtruncate(fileno(xc->tchn_handle), 0); + + xc->section_header_only = 0; + xc->secnum++; + + pthread_mutex_lock(&xc->mutex); + + pthread_create(&xc->thread, &xc->thread_attr, fstWriterFlushContextPrivate1, xc2); + } + else + { + if(xc->parallel_was_enabled) /* conservatively block */ + { + pthread_mutex_lock(&xc->mutex); + pthread_mutex_unlock(&xc->mutex); + } + + xc->xc_parent = xc; + fstWriterFlushContextPrivate2(xc); + } +} +#endif + + /* * queues up a flush context operation */ @@ -1299,6 +1511,15 @@ if(xc) void fstWriterClose(void *ctx) { struct fstWriterContext *xc = (struct fstWriterContext *)ctx; + +#ifdef FST_WRITER_PARALLEL +if(xc) + { + pthread_mutex_lock(&xc->mutex); + pthread_mutex_unlock(&xc->mutex); + } +#endif + if(xc && !xc->already_in_close && !xc->already_in_flush) { unsigned char *tmem; @@ -1328,6 +1549,10 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) } } fstWriterFlushContextPrivate(xc); +#ifdef FST_WRITER_PARALLEL + pthread_mutex_lock(&xc->mutex); + pthread_mutex_unlock(&xc->mutex); +#endif } } fstDestroyMmaps(xc, 1); @@ -1556,6 +1781,11 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) } #endif +#ifdef FST_WRITER_PARALLEL + pthread_mutex_destroy(&xc->mutex); + pthread_attr_destroy(&xc->thread_attr); +#endif + free(xc->filename); xc->filename = NULL; free(xc); } @@ -1661,6 +1891,20 @@ if(xc && s) } +void fstWriterSetTimezero(void *ctx, int64_t tim) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc) + { + off_t fpos = ftello(xc->handle); + fseeko(xc->handle, FST_HDR_OFFS_TIMEZERO, SEEK_SET); + fstWriterUint64(xc->handle, (xc->timezero = tim)); + fflush(xc->handle); + fseeko(xc->handle, fpos, SEEK_SET); + } +} + + void fstWriterSetPackType(void *ctx, int typ) { struct fstWriterContext *xc = (struct fstWriterContext *)ctx; @@ -1681,6 +1925,24 @@ if(xc) } +void fstWriterSetParallelMode(void *ctx, int enable) +{ +struct fstWriterContext *xc = (struct fstWriterContext *)ctx; +if(xc) + { + xc->parallel_was_enabled |= xc->parallel_enabled; /* make sticky */ + xc->parallel_enabled = (enable != 0); +#ifndef FST_WRITER_PARALLEL + if(xc->parallel_enabled) + { + fprintf(stderr, "ERROR: fstWriterSetParallelMode(), FST_WRITER_PARALLEL not enabled during compile, exiting.\n"); + exit(255); + } +#endif + } +} + + void fstWriterSetDumpSizeLimit(void *ctx, uint64_t numbytes) { struct fstWriterContext *xc = (struct fstWriterContext *)ctx; @@ -1745,6 +2007,22 @@ if(xc && nam) if(aliasHandle > xc->maxhandle) aliasHandle = 0; xc->hier_file_len += fstWriterVarint(xc->hier_handle, aliasHandle); xc->numsigs++; + if(xc->numsigs == xc->next_huge_break) + { + if(xc->fst_break_size < xc->fst_huge_break_size) + { + xc->next_huge_break += FST_ACTIVATE_HUGE_INC; + xc->fst_break_size += xc->fst_orig_break_size; + xc->fst_break_add_size += xc->fst_orig_break_add_size; + + xc->vchg_alloc_siz = xc->fst_break_size + xc->fst_break_add_size; + if(xc->vchg_mem) + { + xc->vchg_mem = realloc(xc->vchg_mem, xc->vchg_alloc_siz); + } + } + } + if(!aliasHandle) { uint32_t zero = 0; @@ -1863,7 +2141,7 @@ if((xc) && (handle <= xc->maxhandle)) if((fpos + len + 10) > xc->vchg_alloc_siz) { - xc->vchg_alloc_siz += (FST_BREAK_ADD_SIZE + len); /* +len added in the case of extremely long vectors and small break add sizes */ + xc->vchg_alloc_siz += (xc->fst_break_add_size + len); /* +len added in the case of extremely long vectors and small break add sizes */ xc->vchg_mem = realloc(xc->vchg_mem, xc->vchg_alloc_siz); if(!xc->vchg_mem) { @@ -1871,7 +2149,72 @@ if((xc) && (handle <= xc->maxhandle)) exit(255); } } +#ifdef FST_REMOVE_DUPLICATE_VC + offs = vm4ip[0]; + + if(len != 1) + { + if((vm4ip[3]==xc->tchn_idx)&&(vm4ip[2])) + { + unsigned char *old_value = xc->vchg_mem + vm4ip[2] + 4; /* the +4 skips old vm4ip[2] value */ + while(*(old_value++) & 0x80) { /* skips over varint encoded "xc->tchn_idx - vm4ip[3]" */ } + memcpy(old_value, buf, len); /* overlay new value */ + memcpy(xc->curval_mem + offs, buf, len); + return; + } + else + { + if(!memcmp(xc->curval_mem + offs, buf, len)) + { + if(!xc->curtime) + { + int i; + for(i=0;icurval_mem + offs, buf, len); + } + else + { + if((vm4ip[3]==xc->tchn_idx)&&(vm4ip[2])) + { + unsigned char *old_value = xc->vchg_mem + vm4ip[2] + 4; /* the +4 skips old vm4ip[2] value */ + while(*(old_value++) & 0x80) { /* skips over varint encoded "xc->tchn_idx - vm4ip[3]" */ } + *old_value = *buf; /* overlay new value */ + + *(xc->curval_mem + offs) = *buf; + return; + } + else + { + if((*(xc->curval_mem + offs)) == (*buf)) + { + if(!xc->curtime) + { + if(*buf != 'x') return; + } + else + { + return; + } + } + } + + *(xc->curval_mem + offs) = *buf; + } +#endif xc->vchg_siz += fstWriterUint32WithVarint32(xc, &vm4ip[2], xc->tchn_idx - vm4ip[3], buf, len); /* do one fwrite op only */ vm4ip[3] = xc->tchn_idx; vm4ip[2] = fpos; @@ -1912,7 +2255,7 @@ if((xc) && (handle <= xc->maxhandle)) if((fpos + len + 10 + 5) > xc->vchg_alloc_siz) { - xc->vchg_alloc_siz += (FST_BREAK_ADD_SIZE + len + 5); /* +len added in the case of extremely long vectors and small break add sizes */ + xc->vchg_alloc_siz += (xc->fst_break_add_size + len + 5); /* +len added in the case of extremely long vectors and small break add sizes */ xc->vchg_mem = realloc(xc->vchg_mem, xc->vchg_alloc_siz); if(!xc->vchg_mem) { @@ -1964,7 +2307,7 @@ if(xc) } else { - if((xc->vchg_siz >= FST_BREAK_SIZE) || (xc->flush_context_pending)) + if((xc->vchg_siz >= xc->fst_break_size) || (xc->flush_context_pending)) { xc->flush_context_pending = 0; fstWriterFlushContextPrivate(xc); @@ -2044,9 +2387,6 @@ 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; @@ -2071,6 +2411,7 @@ unsigned limit_range_valid : 1; /* valid for limit_range_start, limit_range_end char version[FST_HDR_SIM_VERSION_SIZE + 1]; char date[FST_HDR_DATE_SIZE + 1]; +int64_t timezero; char *filename, *filename_unpacked; off_t hier_pos; @@ -2410,6 +2751,12 @@ struct fstReaderContext *xc = (struct fstReaderContext *)ctx; return(xc ? xc->date : NULL); } +int64_t fstReaderGetTimezero(void *ctx) +{ +struct fstReaderContext *xc = (struct fstReaderContext *)ctx; +return(xc ? xc->timezero : 0); +} + uint32_t fstReaderGetNumberDumpActivityChanges(void *ctx) { @@ -2562,8 +2909,10 @@ if(!xc->fh) return(0); } +#ifndef __MINGW32__ xc->fh = fopen(fnam, "w+b"); if(!xc->fh) +#endif { xc->fh = tmpfile(); free(fnam); fnam = NULL; @@ -2599,12 +2948,7 @@ if(!xc->fh) } gzclose(zhandle); free(mem); - -#ifndef __MINGW32__ free(fnam); -#else - xc->fh_name = fnam; -#endif fseeko(xc->f, offs_cache, SEEK_SET); } @@ -2784,10 +3128,13 @@ if(fv) fprintf(fv, "$date\n\t%s\n$end\n", xc->date); fprintf(fv, "$version\n\t%s\n$end\n", xc->version); + if(xc->timezero) fprintf(fv, "$timezero\n\t%"PRId64"\n$end\n", xc->timezero); switch(xc->timescale) { - case 0: break; + case 2: time_scale = 100; time_dimension[0] = ' '; break; + case 1: time_scale = 10; + case 0: time_dimension[0] = ' '; break; case -1: time_scale = 100; time_dimension[0] = 'm'; break; case -2: time_scale = 10; @@ -3117,6 +3464,7 @@ if(gzread_pass_status) 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; + xc->timezero = fstReaderUint64(xc->f); } } else if((sectype == FST_BL_VCDATA) || (sectype == FST_BL_VCDATA_DYN_ALIAS)) @@ -3254,6 +3602,14 @@ return(hdr_seen); } +void *fstReaderOpenForUtilitiesOnly(void) +{ +struct fstReaderContext *xc = calloc(1, sizeof(struct fstReaderContext)); + +return(xc); +} + + void *fstReaderOpen(const char *nam) { struct fstReaderContext *xc = calloc(1, sizeof(struct fstReaderContext)); @@ -3333,14 +3689,7 @@ if(xc) 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 + fclose(xc->fh); xc->fh = NULL; } if(xc->f) @@ -5042,6 +5391,7 @@ int fstUtilityBinToEsc(unsigned char *d, unsigned char *s, int len) { unsigned char *src = s; unsigned char *dst = d; +unsigned char val; int i; for(i=0;inumfacs)) lt->sorted_facs[i]->facnum = i; } - lt->facname_offset=lt->position; + if(!lt->timezero) + { + lxt2_wr_emit_u32(lt, lt->numfacs); /* uncompressed */ + } + else + { + lxt2_wr_emit_u32(lt, 0); /* uncompressed, flag to insert extra parameters */ + lxt2_wr_emit_u32(lt, 8); /* uncompressed 8 counts timezero and on */ + lxt2_wr_emit_u32(lt, lt->numfacs); /* uncompressed */ + lxt2_wr_emit_u64(lt, (lt->timezero >> 32) & 0xffffffffL, lt->timezero & 0xffffffffL); /* uncompressed */ + } + - lxt2_wr_emit_u32(lt, lt->numfacs); /* uncompressed */ lxt2_wr_emit_u32(lt, lt->numfacbytes); /* uncompressed */ lxt2_wr_emit_u32(lt, lt->longestname); /* uncompressed */ + + lt->facname_offset=lt->position; + lxt2_wr_emit_u32(lt, 0); /* uncompressed : placeholder for zfacnamesize */ lxt2_wr_emit_u32(lt, 0); /* uncompressed : placeholder for zfacname_predec_size */ lxt2_wr_emit_u32(lt, 0); /* uncompressed : placeholder for zfacgeometrysize */ @@ -720,7 +733,7 @@ if((lt)&&(lt->numfacs)) lt->break_header_size = lt->position; /* in case we need to emit multiple lxt2s with same header */ lt->zfacgeometry_size = lt->position - lt->facgeometry_offset; - fseeko(lt->handle, lt->facname_offset + 12, SEEK_SET); + fseeko(lt->handle, lt->facname_offset, SEEK_SET); lxt2_wr_emit_u32(lt, lt->zfacname_size); /* backpatch sizes... */ lxt2_wr_emit_u32(lt, lt->zfacname_predec_size); lxt2_wr_emit_u32(lt, lt->zfacgeometry_size); @@ -2178,3 +2191,15 @@ if(lt) } } + +/* + * time zero offset + */ +void lxt2_wr_set_timezero(struct lxt2_wr_trace *lt, lxtstime_t timeval) +{ +if(lt) + { + lt->timezero = timeval; + } +} + diff --git a/vpi/lxt2_write.h b/vpi/lxt2_write.h index cd27ca662..f1487fb34 100644 --- a/vpi/lxt2_write.h +++ b/vpi/lxt2_write.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2010 Tony Bybell. + * Copyright (c) 2003-2012 Tony Bybell. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -60,6 +60,7 @@ extern "C" { #define LXT2_WR_SYMPRIME 500009 typedef uint64_t lxttime_t; +typedef int64_t lxtstime_t; #ifndef _MSC_VER @@ -170,6 +171,7 @@ int numsections, numblock; off_t facname_offset, facgeometry_offset; lxttime_t mintime, maxtime; +lxtstime_t timezero; unsigned int timegranule; int timescale; int timepos; @@ -291,6 +293,7 @@ void lxt2_wr_set_maxgranule(struct lxt2_wr_trace *lt, unsigned int maxgranule /* time ops */ void lxt2_wr_set_timescale(struct lxt2_wr_trace *lt, int timescale); +void lxt2_wr_set_timezero(struct lxt2_wr_trace *lt, lxtstime_t timeval); int lxt2_wr_set_time(struct lxt2_wr_trace *lt, unsigned int timeval); int lxt2_wr_inc_time_by_delta(struct lxt2_wr_trace *lt, unsigned int timeval); int lxt2_wr_set_time64(struct lxt2_wr_trace *lt, lxttime_t timeval); diff --git a/vpi/lxt_write.c b/vpi/lxt_write.c index 42b452268..9e9cf2ea9 100644 --- a/vpi/lxt_write.c +++ b/vpi/lxt_write.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-9 Tony Bybell. + * Copyright (c) 2001-2012 Tony Bybell. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -1208,6 +1208,12 @@ if(lt) lt->dumpoffcount = 0; } + if(lt->timezero) + { + lt->timezero_offset = lt->position; + lt_emit_u64(lt, (int)((lt->timezero)>>32), (int)lt->timezero); + } + /* prefix */ lt_emit_u8(lt, LT_SECTION_END); @@ -1237,6 +1243,9 @@ if(lt) /* Version 5 adds */ if(lt->exclude_offset) { lt_emit_u32(lt, lt->exclude_offset); lt_emit_u8(lt, LT_SECTION_EXCLUDE_TABLE); lt->exclude_offset = 0; } + /* Version 6 adds */ + if(lt->timezero_offset) { lt_emit_u32(lt, lt->timezero_offset); lt_emit_u8(lt, LT_SECTION_TIMEZERO); lt->timezero_offset = 0; } + /* suffix */ lt_emit_u8(lt, LT_TRLID); @@ -2808,3 +2817,11 @@ if((lt)&&(lt->dumpoff_active)) } } +void lt_set_timezero(struct lt_trace *lt, lxtotime_t timeval) +{ +if(lt) + { + lt->timezero = timeval; + } +} + diff --git a/vpi/lxt_write.h b/vpi/lxt_write.h index f029b7b4e..8fbb0a797 100644 --- a/vpi/lxt_write.h +++ b/vpi/lxt_write.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-3 Tony Bybell. + * Copyright (c) 2001-2012 Tony Bybell. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -72,9 +72,11 @@ enum lt_zmode_types { LT_ZMODE_NONE, LT_ZMODE_GZIP, LT_ZMODE_BZIP2 }; #ifndef _MSC_VER typedef uint64_t lxttime_t; #define ULLDescriptor(x) x##ULL +typedef int64_t lxtotime_t; #else typedef unsigned __int64 lxttime_t; #define ULLDescriptor(x) x##i64 +typedef __int64 lxtotime_t; #endif @@ -108,6 +110,7 @@ unsigned int position; #define LT_SECTION_ZDICTIONARY (17) #define LT_SECTION_ZDICTIONARY_SIZE (18) #define LT_SECTION_EXCLUDE_TABLE (19) +#define LT_SECTION_TIMEZERO (20) struct lt_trace { @@ -164,11 +167,13 @@ unsigned int timescale_offset; unsigned int double_test_offset; unsigned int dictionary_offset; unsigned int exclude_offset; +unsigned int timezero_offset; char *compress_fac_str; int compress_fac_len; lxttime_t timeval; /* for clock induction, current time */ +lxtotime_t timezero; /* for allowing negative values */ unsigned dumpoff_active : 1; /* when set we're not dumping */ unsigned double_used : 1; @@ -234,6 +239,7 @@ void lt_set_clock_compress(struct lt_trace *lt); void lt_set_dict_compress(struct lt_trace *lt, unsigned int minwidth); void lt_set_initial_value(struct lt_trace *lt, char value); void lt_set_timescale(struct lt_trace *lt, int timescale); +void lt_set_timezero(struct lt_trace *lt, lxtotime_t timeval); int lt_set_time(struct lt_trace *lt, unsigned int timeval); int lt_inc_time_by_delta(struct lt_trace *lt, unsigned int timeval);