/* * 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"), * 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 #include "lxt_write.h" /* * in-place sort to keep chained facs from migrating... */ static void wave_mergesort(struct lt_symbol **a, struct lt_symbol **b, int lo, int hi) { int i, j, k; if (loname, a[j]->name) <= 0) { a[k++]=b[i++]; } else { a[k++]=a[j++]; } } while (kitem); if (dir < 0) { if (t->left == NULL) break; if (strcmp(i, t->left->item)<0) { y = t->left; /* rotate right */ t->left = y->right; y->right = t; t = y; if (t->left == NULL) break; } r->left = t; /* link right */ r = t; t = t->left; } else if (dir > 0) { if (t->right == NULL) break; if (strcmp(i, t->right->item)>0) { y = t->right; /* rotate left */ t->right = y->left; y->left = t; t = y; if (t->right == NULL) break; } l->right = t; /* link left */ l = t; t = t->right; } else { dslxt_success=1; break; } } l->right = t->left; /* assemble */ r->left = t->right; t->left = N.right; t->right = N.left; return t; } static dslxt_Tree * dslxt_insert(char *i, dslxt_Tree * t, unsigned int val) { /* Insert i into the tree t, unless it's already there. */ /* Return a pointer to the resulting tree. */ dslxt_Tree * n; int dir; n = (dslxt_Tree *) calloc (1, sizeof (dslxt_Tree)); if (n == NULL) { fprintf(stderr, "dslxt_insert: ran out of memory, exiting.\n"); exit(255); } n->item = i; n->val = val; if (t == NULL) { n->left = n->right = NULL; return n; } t = dslxt_splay(i,t); dir = strcmp(i,t->item); if (dir<0) { n->left = t->left; n->right = t; t->left = NULL; return n; } else if (dir>0) { n->right = t->right; n->left = t; t->right = NULL; return n; } else { /* We get here if it's already in the tree */ /* Don't add it again */ free(n); return t; } } #if 0 /* unused for now but delete is here for completeness */ static dslxt_Tree * dslxt_delete(char *i, dslxt_Tree * t) { /* Deletes i from the tree if it's there. */ /* Return a pointer to the resulting tree. */ dslxt_Tree * x; if (t==NULL) return NULL; t = dslxt_splay(i,t); if (!strcmp(i, t->item)) { /* found it */ if (t->left == NULL) { x = t->right; } else { x = dslxt_splay(i, t->left); x->right = t->right; } free(t); return x; } return t; /* It wasn't there */ } #endif /************************ splay ************************/ /* * functions which emit various big endian * data to a file */ static int lt_emit_u8(struct lt_trace *lt, int value) { unsigned char buf[1]; int nmemb; buf[0] = value & 0xff; nmemb=fwrite(buf, sizeof(char), 1, lt->handle); lt->position+=nmemb; return(nmemb); } static int lt_emit_u16(struct lt_trace *lt, int value) { unsigned char buf[2]; int nmemb; buf[0] = (value>>8) & 0xff; buf[1] = value & 0xff; nmemb = fwrite(buf, sizeof(char), 2, lt->handle); lt->position+=nmemb; return(nmemb); } static int lt_emit_u24(struct lt_trace *lt, int value) { unsigned char buf[3]; int nmemb; buf[0] = (value>>16) & 0xff; buf[1] = (value>>8) & 0xff; buf[2] = value & 0xff; nmemb=fwrite(buf, sizeof(char), 3, lt->handle); lt->position+=nmemb; return(nmemb); } static int lt_emit_u32(struct lt_trace *lt, int value) { unsigned char buf[4]; int nmemb; buf[0] = (value>>24) & 0xff; buf[1] = (value>>16) & 0xff; buf[2] = (value>>8) & 0xff; buf[3] = value & 0xff; nmemb=fwrite(buf, sizeof(char), 4, lt->handle); lt->position+=nmemb; return(nmemb); } static int lt_emit_u64(struct lt_trace *lt, int valueh, int valuel) { int rc; if((rc=lt_emit_u32(lt, valueh))) { rc=lt_emit_u32(lt, valuel); } return(rc); } static int lt_emit_double(struct lt_trace *lt, double value) { int nmemb; nmemb=fwrite(&value, sizeof(char), sizeof(double)/sizeof(char), lt->handle); lt->position+=nmemb; return(nmemb); } static int lt_emit_string(struct lt_trace *lt, char *value) { int rc=1; do { rc&=lt_emit_u8(lt, *value); } while(*(value++)); return(rc); } /* * gzfunctions which emit various big endian * data to a file. (lt->position needs to be * fixed up on gzclose so the tables don't * get out of sync!) */ static int lt_emit_u8z(struct lt_trace *lt, int value) { unsigned char buf[1]; int nmemb; buf[0] = value & 0xff; nmemb=gzwrite(lt->zhandle, buf, 1); lt->zpackcount++; lt->position++; return(nmemb); } static int lt_emit_u16z(struct lt_trace *lt, int value) { unsigned char buf[2]; int nmemb; buf[0] = (value>>8) & 0xff; buf[1] = value & 0xff; nmemb = gzwrite(lt->zhandle, buf, 2); lt->zpackcount+=2; lt->position+=2; return(nmemb); } static int lt_emit_u24z(struct lt_trace *lt, int value) { unsigned char buf[3]; int nmemb; buf[0] = (value>>16) & 0xff; buf[1] = (value>>8) & 0xff; buf[2] = value & 0xff; nmemb=gzwrite(lt->zhandle, buf, 3); lt->zpackcount+=3; lt->position+=3; return(nmemb); } static int lt_emit_u32z(struct lt_trace *lt, int value) { unsigned char buf[4]; int nmemb; buf[0] = (value>>24) & 0xff; buf[1] = (value>>16) & 0xff; buf[2] = (value>>8) & 0xff; buf[3] = value & 0xff; nmemb=gzwrite(lt->zhandle, buf, 4); lt->zpackcount+=4; lt->position+=4; return(nmemb); } static int lt_emit_u64z(struct lt_trace *lt, int valueh, int valuel) { int rc; if((rc=lt_emit_u32z(lt, valueh))) { rc=lt_emit_u32z(lt, valuel); } return(rc); } static int lt_emit_doublez(struct lt_trace *lt, double value) { int nmemb; nmemb=gzwrite(lt->zhandle, &value, sizeof(double)/sizeof(char)); lt->zpackcount+=(sizeof(double)/sizeof(char)); lt->position+=(sizeof(double)/sizeof(char));; return(nmemb); } static int lt_emit_stringz(struct lt_trace *lt, char *value) { int rc=1; do { rc&=lt_emit_u8z(lt, *value); } while(*(value++)); return(rc); } /* * bz2functions which emit various big endian * data to a file. (lt->position needs to be * fixed up on BZ2_bzclose so the tables don't * get out of sync!) */ static int lt_emit_u8bz(struct lt_trace *lt, int value) { unsigned char buf[1]; int nmemb; buf[0] = value & 0xff; nmemb=BZ2_bzwrite(lt->zhandle, buf, 1); lt->zpackcount++; lt->position++; return(nmemb); } static int lt_emit_u16bz(struct lt_trace *lt, int value) { unsigned char buf[2]; int nmemb; buf[0] = (value>>8) & 0xff; buf[1] = value & 0xff; nmemb = BZ2_bzwrite(lt->zhandle, buf, 2); lt->zpackcount+=2; lt->position+=2; return(nmemb); } static int lt_emit_u24bz(struct lt_trace *lt, int value) { unsigned char buf[3]; int nmemb; buf[0] = (value>>16) & 0xff; buf[1] = (value>>8) & 0xff; buf[2] = value & 0xff; nmemb=BZ2_bzwrite(lt->zhandle, buf, 3); lt->zpackcount+=3; lt->position+=3; return(nmemb); } static int lt_emit_u32bz(struct lt_trace *lt, int value) { unsigned char buf[4]; int nmemb; buf[0] = (value>>24) & 0xff; buf[1] = (value>>16) & 0xff; buf[2] = (value>>8) & 0xff; buf[3] = value & 0xff; nmemb=BZ2_bzwrite(lt->zhandle, buf, 4); lt->zpackcount+=4; lt->position+=4; return(nmemb); } static int lt_emit_u64bz(struct lt_trace *lt, int valueh, int valuel) { int rc; if((rc=lt_emit_u32bz(lt, valueh))) { rc=lt_emit_u32bz(lt, valuel); } return(rc); } static int lt_emit_doublebz(struct lt_trace *lt, double value) { int nmemb; nmemb=BZ2_bzwrite(lt->zhandle, &value, sizeof(double)/sizeof(char)); lt->zpackcount+=(sizeof(double)/sizeof(char)); lt->position+=(sizeof(double)/sizeof(char));; return(nmemb); } static int lt_emit_stringbz(struct lt_trace *lt, char *value) { int rc=1; do { rc&=lt_emit_u8bz(lt, *value); } while(*(value++)); return(rc); } /* * switch between compression modes above */ static void lt_set_zmode(struct lt_trace *lt, int mode) { switch(mode) { case LT_ZMODE_NONE: lt->lt_emit_u8 = lt_emit_u8; lt->lt_emit_u16 = lt_emit_u16; lt->lt_emit_u24 = lt_emit_u24; lt->lt_emit_u32 = lt_emit_u32; lt->lt_emit_u64 = lt_emit_u64; lt->lt_emit_double = lt_emit_double; lt->lt_emit_string = lt_emit_string; break; case LT_ZMODE_GZIP: lt->lt_emit_u8 = lt_emit_u8z; lt->lt_emit_u16 = lt_emit_u16z; lt->lt_emit_u24 = lt_emit_u24z; lt->lt_emit_u32 = lt_emit_u32z; lt->lt_emit_u64 = lt_emit_u64z; lt->lt_emit_double = lt_emit_doublez; lt->lt_emit_string = lt_emit_stringz; break; case LT_ZMODE_BZIP2: lt->lt_emit_u8 = lt_emit_u8bz; lt->lt_emit_u16 = lt_emit_u16bz; lt->lt_emit_u24 = lt_emit_u24bz; lt->lt_emit_u32 = lt_emit_u32bz; lt->lt_emit_u64 = lt_emit_u64bz; lt->lt_emit_double = lt_emit_doublebz; lt->lt_emit_string = lt_emit_stringbz; break; } } /* * hash/symtable manipulation */ static int lt_hash(const char *s) { const char *p; char ch; unsigned int h=0, h2=0, pos=0, g; for(p=s;*p;p++) { ch=*p; h2<<=3; h2-=((unsigned int)ch+(pos++)); /* this handles stranded vectors quite well.. */ h=(h<<4)+ch; if((g=h&0xf0000000)) { h=h^(g>>24); h=h^g; } } h^=h2; /* combine the two hashes */ return(h%LT_SYMPRIME); } static struct lt_symbol *lt_symadd(struct lt_trace *lt, const char *name, int hv) { struct lt_symbol *s; s=(struct lt_symbol *)calloc(1,sizeof(struct lt_symbol)); strcpy(s->name=(char *)malloc((s->namlen=strlen(name))+1),name); s->next=lt->sym[hv]; lt->sym[hv]=s; return(s); } static struct lt_symbol *lt_symfind(struct lt_trace *lt, const char *s) { int hv; struct lt_symbol *temp; hv=lt_hash(s); if(!(temp=lt->sym[hv])) return(NULL); /* no hash entry, add here wanted to add */ while(temp) { if(!strcmp(temp->name,s)) { return(temp); /* in table already */ } if(!temp->next) break; temp=temp->next; } return(NULL); /* not found, add here if you want to add*/ } /* * compress facs to a prefix count + string + 0x00 */ static void lt_compress_fac(struct lt_trace *lt, char *str) { int i; int len = strlen(str); int minlen = (lencompress_fac_len) ? len : lt->compress_fac_len; if(minlen>65535) minlen=65535; /* keep in printable range--most hierarchies won't be this big anyway */ if(lt->compress_fac_str) { for(i=0;icompress_fac_str[i]!=str[i]) break; } lt_emit_u16z(lt, i); lt_emit_stringz(lt, str+i); free(lt->compress_fac_str); } else { lt_emit_u16z(lt, 0); lt_emit_stringz(lt, str); } lt->compress_fac_str = (char *) malloc((lt->compress_fac_len=len)+1); strcpy(lt->compress_fac_str, str); } static void strip_brack(struct lt_symbol *s) { char *lastch = s->name+s->namlen - 1; if(*lastch!=']') return; if(s->namlen<3) return; lastch--; while(lastch!=s->name) { if(*lastch=='.') { return; /* MTI SV [0.3] notation for implicit vars */ } if(*lastch=='[') { *lastch=0x00; return; } lastch--; } return; } static void lt_emitfacs(struct lt_trace *lt) { int i; if((lt)&&(lt->numfacs)) { struct lt_symbol *s = lt->symchain; char is_interlaced_trace = (lt->sorted_facs==NULL); if(!lt->sorted_facs) { if((lt->sorted_facs = (struct lt_symbol **)calloc(lt->numfacs, sizeof(struct lt_symbol *)))) { if(lt->do_strip_brackets) for(i=0;inumfacs;i++) { lt->sorted_facs[lt->numfacs - i - 1] = s; /* facs were chained backwards so reverse to restore bitslicing */ strip_brack(s); s=s->symchain; } else for(i=0;inumfacs;i++) { lt->sorted_facs[lt->numfacs - i - 1] = s; /* facs were chained backwards so reverse to restore bitslicing*/ s=s->symchain; } wave_msort(lt->sorted_facs, lt->numfacs); for(i=0;inumfacs;i++) { lt->sorted_facs[i]->facnum = i; } } } if(lt->sorted_facs) { lt->facname_offset=lt->position; lt_emit_u32(lt, lt->numfacs); /* uncompressed */ lt_emit_u32(lt, lt->numfacbytes); /* uncompressed */ fflush(lt->handle); lt->zfacname_size = lt->position; lt->zhandle = gzdopen(dup(fileno(lt->handle)), "wb9"); lt->zpackcount = 0; for(i=0;inumfacs;i++) { lt_compress_fac(lt, lt->sorted_facs[i]->name); } free(lt->compress_fac_str); lt->compress_fac_str=NULL; lt->compress_fac_len=0; lt->zfacname_predec_size = lt->zpackcount; gzclose(lt->zhandle); fseeko(lt->handle, 0L, SEEK_END); lt->position=ftello(lt->handle); lt->zfacname_size = lt->position - lt->zfacname_size; lt->zhandle = gzdopen(dup(fileno(lt->handle)), "wb9"); lt->facgeometry_offset = lt->position; for(i=0;inumfacs;i++) { if((lt->sorted_facs[i]->flags<_SYM_F_ALIAS)==0) { lt_emit_u32z(lt, lt->sorted_facs[i]->rows); lt_emit_u32z(lt, lt->sorted_facs[i]->msb); lt_emit_u32z(lt, lt->sorted_facs[i]->lsb); lt_emit_u32z(lt, lt->sorted_facs[i]->flags); } else { lt_emit_u32z(lt, lt->sorted_facs[i]->aliased_to->facnum); lt_emit_u32z(lt, lt->sorted_facs[i]->msb); lt_emit_u32z(lt, lt->sorted_facs[i]->lsb); lt_emit_u32z(lt, LT_SYM_F_ALIAS); } } gzclose(lt->zhandle); fseeko(lt->handle, 0L, SEEK_END); lt->position=ftello(lt->handle); lt->zfacgeometry_size = lt->position - lt->facgeometry_offset; if(is_interlaced_trace) { lt->zhandle = gzdopen(dup(fileno(lt->handle)), "wb9"); lt->sync_table_offset = lt->position; for(i=0;inumfacs;i++) { lt_emit_u32z(lt, lt->sorted_facs[i]->last_change); } gzclose(lt->zhandle); lt->zhandle = NULL; fseeko(lt->handle, 0L, SEEK_END); lt->position=ftello(lt->handle); lt->zsync_table_size = lt->position - lt->sync_table_offset; } } } } /* * initialize the trace and get back an lt context */ struct lt_trace *lt_init(const char *name) { struct lt_trace *lt=(struct lt_trace *)calloc(1, sizeof(struct lt_trace)); if(!(lt->handle=fopen(name, "wb"))) { free(lt); lt=NULL; } else { lt_emit_u16(lt, LT_HDRID); lt_emit_u16(lt, LT_VERSION); lt->change_field_offset = lt->position; lt->initial_value = -1; /* if a user sets this it will have a different POSITIVE val */ lt->timescale = -256; /* will be in range of -128<=x<=127 if set */ lt_set_zmode(lt, LT_ZMODE_NONE); lt->mintime=ULLDescriptor(1); lt->maxtime=ULLDescriptor(0); } return(lt); } /* * clock flushing.. */ static void lt_flushclock(struct lt_trace *lt, struct lt_symbol *s) { unsigned int last_change_delta = lt->position - s->last_change - 2; unsigned int start_position = lt->position; int tag; int numbytes, numbytes_trans; int numtrans = s->clk_numtrans - LT_CLKPACK - 1; if(numtrans<0) { /* it never got around to caching */ fprintf(stderr, "Possible Problem with %s with %d?\n", s->name, s->clk_numtrans); return; } if(numtrans >= 256*65536) { numbytes_trans = 3; } else if(numtrans >= 65536) { numbytes_trans = 2; } else if(numtrans >= 256) { numbytes_trans = 1; } else { numbytes_trans = 0; } if(!lt->numfacs_bytes) { if(last_change_delta >= 256*65536) { numbytes = 3; } else if(last_change_delta >= 65536) { numbytes = 2; } else if(last_change_delta >= 256) { numbytes = 1; } else { numbytes = 0; } tag = (numbytes<<4) + 0xC + numbytes_trans; /* yields xC..xF */ lt->lt_emit_u8(lt, tag); switch(numbytes&3) { case 0: lt->lt_emit_u8(lt, last_change_delta); break; case 1: lt->lt_emit_u16(lt, last_change_delta); break; case 2: lt->lt_emit_u24(lt, last_change_delta); break; case 3: lt->lt_emit_u32(lt, last_change_delta); break; } } else { tag = 0xC + numbytes_trans; /* yields C..F */ switch(lt->numfacs_bytes) { case 1: lt->lt_emit_u8(lt, s->facnum); break; case 2: lt->lt_emit_u16(lt, s->facnum); break; case 3: lt->lt_emit_u24(lt, s->facnum); break; case 4: lt->lt_emit_u32(lt, s->facnum); break; } lt->lt_emit_u8(lt, tag); } s->last_change = start_position; /* s->clk_prevval CAN BE INFERRED! */ /* s->clk_prevtrans CAN BE INFERRED! */ /* s->clk_delta CAN BE INFERRED! */ switch(numbytes_trans&3) { case 0: lt->lt_emit_u8(lt, numtrans); break; case 1: lt->lt_emit_u16(lt, numtrans); break; case 2: lt->lt_emit_u24(lt, numtrans); break; case 3: lt->lt_emit_u32(lt, numtrans); break; } /* printf("Clock finish for '%s' at %lld ending with '%c' for %d repeats over a switch delta of %d\n", s->name, lt->timeval, s->clk_prevval, s->clk_numtrans - LT_CLKPACK, s->clk_delta); */ s->clk_prevtrans = ULLDescriptor(~0); s->clk_numtrans = 0; } static void lt_flushclock_m(struct lt_trace *lt, struct lt_symbol *s) { unsigned int last_change_delta = lt->position - s->last_change - 2; unsigned int start_position = lt->position; int tag; int numbytes, numbytes_trans; int numtrans = s->clk_numtrans - LT_CLKPACK_M - 1; if(numtrans<0) { /* it never got around to caching */ fprintf(stderr, "Possible Problem with %s with %d?\n", s->name, s->clk_numtrans); return; } if(numtrans >= 256*65536) { numbytes_trans = 3; } else if(numtrans >= 65536) { numbytes_trans = 2; } else if(numtrans >= 256) { numbytes_trans = 1; } else { numbytes_trans = 0; } if(!lt->numfacs_bytes) { if(last_change_delta >= 256*65536) { numbytes = 3; } else if(last_change_delta >= 65536) { numbytes = 2; } else if(last_change_delta >= 256) { numbytes = 1; } else { numbytes = 0; } tag = (numbytes<<4) + 0xC + numbytes_trans; /* yields xC..xF */ lt->lt_emit_u8(lt, tag); switch(numbytes&3) { case 0: lt->lt_emit_u8(lt, last_change_delta); break; case 1: lt->lt_emit_u16(lt, last_change_delta); break; case 2: lt->lt_emit_u24(lt, last_change_delta); break; case 3: lt->lt_emit_u32(lt, last_change_delta); break; } } else { tag = 0xC + numbytes_trans; /* yields C..F */ switch(lt->numfacs_bytes) { case 1: lt->lt_emit_u8(lt, s->facnum); break; case 2: lt->lt_emit_u16(lt, s->facnum); break; case 3: lt->lt_emit_u24(lt, s->facnum); break; case 4: lt->lt_emit_u32(lt, s->facnum); break; } lt->lt_emit_u8(lt, tag); } s->last_change = start_position; /* s->clk_prevval CAN BE INFERRED! */ /* s->clk_prevtrans CAN BE INFERRED! */ /* s->clk_delta CAN BE INFERRED! */ switch(numbytes_trans&3) { case 0: lt->lt_emit_u8(lt, numtrans); break; case 1: lt->lt_emit_u16(lt, numtrans); break; case 2: lt->lt_emit_u24(lt, numtrans); break; case 3: lt->lt_emit_u32(lt, numtrans); break; } /* printf("Clock finish for '%s' at %lld ending with '%08x' for %d repeats over a switch delta of %lld\n", s->name, lt->timeval, s->clk_prevval, s->clk_numtrans - LT_CLKPACK_M, s->clk_delta); */ s->clk_prevtrans = ULLDescriptor(~0); s->clk_numtrans = 0; } /* * recurse through dictionary */ static void lt_recurse_dictionary(struct lt_trace *lt, dslxt_Tree *ds) { if(ds->left) lt_recurse_dictionary(lt, ds->left); lt->sorted_dict[ds->val] = ds; if(ds->right) lt_recurse_dictionary(lt, ds->right); } static void lt_recurse_dictionary_free(struct lt_trace *lt, dslxt_Tree *ds) { dslxt_Tree *lft = ds->left; dslxt_Tree *rgh = ds->right; if(lft) lt_recurse_dictionary_free(lt, lft); free(ds->item); free(ds); if(rgh) lt_recurse_dictionary_free(lt, rgh); } static int lt_dictval_compare(const void *v1, const void *v2) { const dslxt_Tree *s1 = *(const dslxt_Tree * const *)v1; const dslxt_Tree *s2 = *(const dslxt_Tree * const *)v2; if(s1->val > s2->val) return(1); else return(-1); /* they're *never* equal */ } static void lt_finalize_dictionary(struct lt_trace *lt) { unsigned int i; lt->sorted_dict = calloc(lt->num_dict_entries, sizeof(dslxt_Tree *)); lt->dictionary_offset=lt->position; lt_emit_u32(lt, lt->num_dict_entries); /* uncompressed */ lt_emit_u32(lt, lt->dict_string_mem_required - lt->num_dict_entries); /* uncompressed : minus because leading '1' is implied so its stripped */ lt_emit_u32(lt, lt->dict16_offset); /* uncompressed */ lt_emit_u32(lt, lt->dict24_offset); /* uncompressed */ lt_emit_u32(lt, lt->dict32_offset); /* uncompressed */ lt_emit_u32(lt, lt->mindictwidth); /* uncompressed */ fflush(lt->handle); #if 0 fprintf(stderr, "*** dictionary_offset = %08x\n", lt->dictionary_offset); fprintf(stderr, "*** num_dict_entries = %d\n", lt->num_dict_entries); #endif lt->zdictionary_size = lt->position; lt->zhandle = gzdopen(dup(fileno(lt->handle)), "wb9"); lt_recurse_dictionary(lt, lt->dict); qsort((void *)lt->sorted_dict, lt->num_dict_entries, sizeof(struct dsTree **), lt_dictval_compare); for(i=0;inum_dict_entries;i++) { dslxt_Tree *ds = lt->sorted_dict[i]; /* fprintf(stderr, "%8d) '%s'\n", ds->val, ds->item); */ lt_emit_stringz(lt, ds->item+1); } gzclose(lt->zhandle); fseeko(lt->handle, 0L, SEEK_END); lt->position=ftello(lt->handle); lt->zdictionary_size = lt->position - lt->zdictionary_size; free(lt->sorted_dict); lt->sorted_dict = NULL; lt_recurse_dictionary_free(lt, lt->dict); lt->dict = NULL; } /* * close out the trace and fixate it */ void lt_close(struct lt_trace *lt) { lxttime_t lasttime=ULLDescriptor(0); int lastposition=0; char is64=0; if(lt) { struct lt_symbol *s = lt->symchain; if(lt->clock_compress) while(s) { if(s->clk_prevtrans!=ULLDescriptor(~0)) { int len = ((s->flags)<_SYM_F_INTEGER) ? 32 : s->len; if(len>1) { if(s->clk_numtrans > LT_CLKPACK_M) lt_flushclock_m(lt, s); } else { if(s->clk_numtrans > LT_CLKPACK) lt_flushclock(lt, s); } } s=s->symchain; } lt_set_dumpon(lt); /* in case it was turned off */ if(lt->zmode!=LT_ZMODE_NONE) { lt->chg_table_size = lt->position - lt->change_field_offset; switch(lt->zmode) { case LT_ZMODE_GZIP: gzclose(lt->zhandle); break; case LT_ZMODE_BZIP2: BZ2_bzclose(lt->zhandle); break; } lt->zhandle = NULL; fseeko(lt->handle, 0L, SEEK_END); lt->position=ftello(lt->handle); lt_set_zmode(lt, LT_ZMODE_NONE); lt->zchg_table_size = lt->position - lt->change_field_offset; } lt_emitfacs(lt); if(lt->dict) lt_finalize_dictionary(lt); free(lt->timebuff); lt->timebuff=NULL; if(lt->timehead) { struct lt_timetrail *t=lt->timehead; struct lt_timetrail *t2; lt->time_table_offset = lt->position; lt_emit_u32(lt, lt->timechangecount); /* this is uncompressed! */ fflush(lt->handle); lt->zhandle = gzdopen(dup(fileno(lt->handle)), "wb9"); lt->ztime_table_size = lt->position; is64=(lt->maxtime > ULLDescriptor(0xFFFFFFFF)); if(is64) { lt_emit_u64z(lt, (int)((lt->mintime)>>32), (int)lt->mintime); lt_emit_u64z(lt, (int)((lt->maxtime)>>32), (int)lt->maxtime); } else { lt_emit_u32z(lt, (int)lt->mintime); lt_emit_u32z(lt, (int)lt->maxtime); } while(t) { lt_emit_u32z(lt, t->position - lastposition); lastposition = t->position; t=t->next; } t=lt->timehead; if(is64) { while(t) { lxttime_t delta = t->timeval - lasttime; lt_emit_u64z(lt, (int)(delta>>32), (int)delta); lasttime = t->timeval; t2=t->next; free(t); t=t2; } } else { while(t) { lt_emit_u32z(lt, (int)(t->timeval - lasttime)); lasttime = t->timeval; t2=t->next; free(t); t=t2; } lt->timehead = lt->timecurr = NULL; } gzclose(lt->zhandle); lt->zhandle = NULL; fseeko(lt->handle, 0L, SEEK_END); lt->position=ftello(lt->handle); lt->ztime_table_size = lt->position - lt->ztime_table_size; } if(lt->initial_value>=0) { lt->initial_value_offset = lt->position; lt_emit_u8(lt, lt->initial_value); } if((lt->timescale>-129)&&(lt->timescale<128)) { lt->timescale_offset = lt->position; lt_emit_u8(lt, lt->timescale); } if(lt->double_used) { lt->double_test_offset = lt->position; lt_emit_double(lt, 3.14159); } if(lt->dumpoffcount) { struct lt_timetrail *ltt = lt->dumpoffhead; struct lt_timetrail *ltt2; lt->exclude_offset = lt->position; lt_emit_u32(lt, lt->dumpoffcount); while(ltt) { lt_emit_u64(lt, (int)((ltt->timeval)>>32), (int)ltt->timeval); ltt2 = ltt; ltt=ltt->next; free(ltt2); } lt->dumpoffhead = lt->dumpoffcurr = NULL; 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); /* Version 1 */ if(lt->change_field_offset) { lt_emit_u32(lt, lt->change_field_offset); lt_emit_u8(lt, LT_SECTION_CHG); lt->change_field_offset = 0; } if(lt->sync_table_offset) { lt_emit_u32(lt, lt->sync_table_offset); lt_emit_u8(lt, LT_SECTION_SYNC_TABLE); lt->sync_table_offset = 0; } if(lt->facname_offset) { lt_emit_u32(lt, lt->facname_offset); lt_emit_u8(lt, LT_SECTION_FACNAME); lt->facname_offset = 0; } if(lt->facgeometry_offset) { lt_emit_u32(lt, lt->facgeometry_offset); lt_emit_u8(lt, LT_SECTION_FACNAME_GEOMETRY); lt->facgeometry_offset = 0; } if(lt->timescale_offset) { lt_emit_u32(lt, lt->timescale_offset); lt_emit_u8(lt, LT_SECTION_TIMESCALE); lt->timescale_offset = 0; } if(lt->time_table_offset) { lt_emit_u32(lt, lt->time_table_offset); lt_emit_u8(lt, is64 ? LT_SECTION_TIME_TABLE64 : LT_SECTION_TIME_TABLE); lt->time_table_offset = 0; } if(lt->initial_value_offset) { lt_emit_u32(lt, lt->initial_value_offset); lt_emit_u8(lt, LT_SECTION_INITIAL_VALUE); lt->initial_value_offset = 0; } if(lt->double_test_offset) { lt_emit_u32(lt, lt->double_test_offset); lt_emit_u8(lt, LT_SECTION_DOUBLE_TEST); lt->double_test_offset = 0; } /* Version 2 adds */ if(lt->zfacname_predec_size) { lt_emit_u32(lt, lt->zfacname_predec_size); lt_emit_u8(lt, LT_SECTION_ZFACNAME_PREDEC_SIZE); lt->zfacname_predec_size = 0; } if(lt->zfacname_size) { lt_emit_u32(lt, lt->zfacname_size); lt_emit_u8(lt, LT_SECTION_ZFACNAME_SIZE); lt->zfacname_size = 0; } if(lt->zfacgeometry_size) { lt_emit_u32(lt, lt->zfacgeometry_size); lt_emit_u8(lt, LT_SECTION_ZFACNAME_GEOMETRY_SIZE); lt->zfacgeometry_size = 0; } if(lt->zsync_table_size) { lt_emit_u32(lt, lt->zsync_table_size); lt_emit_u8(lt, LT_SECTION_ZSYNC_SIZE); lt->zsync_table_size = 0; } if(lt->ztime_table_size) { lt_emit_u32(lt, lt->ztime_table_size); lt_emit_u8(lt, LT_SECTION_ZTIME_TABLE_SIZE); lt->ztime_table_size = 0; } if(lt->chg_table_size) { lt_emit_u32(lt, lt->chg_table_size); lt_emit_u8(lt, LT_SECTION_ZCHG_PREDEC_SIZE); lt->chg_table_size = 0; } if(lt->zchg_table_size) { lt_emit_u32(lt, lt->zchg_table_size); lt_emit_u8(lt, LT_SECTION_ZCHG_SIZE); lt->zchg_table_size = 0; } /* Version 4 adds */ if(lt->dictionary_offset) { lt_emit_u32(lt, lt->dictionary_offset); lt_emit_u8(lt, LT_SECTION_ZDICTIONARY); lt->dictionary_offset = 0; } if(lt->zdictionary_size) { lt_emit_u32(lt, lt->zdictionary_size); lt_emit_u8(lt, LT_SECTION_ZDICTIONARY_SIZE); lt->zdictionary_size = 0; } /* 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); if(lt->symchain) { struct lt_symbol *sc = lt->symchain; struct lt_symbol *s2; while(sc) { free(sc->name); s2=sc->symchain; free(sc); sc=s2; } } free(lt->sorted_facs); fclose(lt->handle); free(lt); } } /* * maint function for finding a symbol if it exists */ struct lt_symbol *lt_symbol_find(struct lt_trace *lt, const char *name) { struct lt_symbol *s=NULL; if((lt)&&(name)) s=lt_symfind(lt, name); return(s); } /* * add a trace (if it doesn't exist already) */ struct lt_symbol *lt_symbol_add(struct lt_trace *lt, const char *name, unsigned int rows, int msb, int lsb, int flags) { struct lt_symbol *s; int len; int flagcnt; if((!lt)||(lt->sorted_facs)) return(NULL); flagcnt = ((flags<_SYM_F_INTEGER)!=0) + ((flags<_SYM_F_DOUBLE)!=0) + ((flags<_SYM_F_STRING)!=0); if((flagcnt>1)||(!lt)||(!name)||(lt_symfind(lt, name))) return (NULL); if(flags<_SYM_F_DOUBLE) lt->double_used = 1; s=lt_symadd(lt, name, lt_hash(name)); s->rows = rows; s->flags = flags&(~LT_SYM_F_ALIAS); /* aliasing makes no sense here.. */ if(!flagcnt) { s->msb = msb; s->lsb = lsb; s->len = (msblen==1)&&(s->rows==0)) s->clk_prevtrans = ULLDescriptor(~0); } s->symchain = lt->symchain; lt->symchain = s; lt->numfacs++; if((len=strlen(name)) > lt->longestname) lt->longestname = len; lt->numfacbytes += (len+1); return(s); } /* * add an alias trace (if it doesn't exist already and orig is found) */ struct lt_symbol *lt_symbol_alias(struct lt_trace *lt, const char *existing_name, const char *alias, int msb, int lsb) { struct lt_symbol *s, *sa; int len; int bitlen; int flagcnt; if((!lt)||(!existing_name)||(!alias)||(!(s=lt_symfind(lt, existing_name)))||(lt_symfind(lt, alias))) return (NULL); if(lt->sorted_facs) return(NULL); while(s->aliased_to) /* find root alias */ { s=s->aliased_to; } flagcnt = ((s->flags<_SYM_F_INTEGER)!=0) + ((s->flags<_SYM_F_DOUBLE)!=0) + ((s->flags<_SYM_F_STRING)!=0); bitlen = (msblen)) return(NULL); sa=lt_symadd(lt, alias, lt_hash(alias)); sa->flags = LT_SYM_F_ALIAS; /* only point this can get set */ sa->aliased_to = s; if(!flagcnt) { sa->msb = msb; sa->lsb = lsb; sa->len = bitlen; } sa->symchain = lt->symchain; lt->symchain = sa; lt->numfacs++; if((len=strlen(alias)) > lt->longestname) lt->longestname = len; lt->numfacbytes += (len+1); return(sa); } /* * set current time */ int lt_inc_time_by_delta(struct lt_trace *lt, unsigned int timeval) { return(lt_set_time64(lt, lt->maxtime + (lxttime_t)timeval)); } int lt_set_time(struct lt_trace *lt, unsigned int timeval) { return(lt_set_time64(lt, (lxttime_t)timeval)); } int lt_inc_time_by_delta64(struct lt_trace *lt, lxttime_t timeval) { return(lt_set_time64(lt, lt->maxtime + timeval)); } int lt_set_time64(struct lt_trace *lt, lxttime_t timeval) { int rc=0; if(lt) { struct lt_timetrail *trl=(struct lt_timetrail *)calloc(1, sizeof(struct lt_timetrail)); if(trl) { trl->timeval = timeval; trl->position = lt->position; if((lt->timecurr)||(lt->timebuff)) { if(((timeval>lt->mintime)&&(timeval>lt->maxtime))||((lt->mintime==ULLDescriptor(1))&&(lt->maxtime==ULLDescriptor(0)))) { lt->maxtime = timeval; } else { free(trl); goto bail; } } else { lt->mintime = lt->maxtime = timeval; } free(lt->timebuff); lt->timebuff = trl; lt->timeval = timeval; rc=1; } } bail: return(rc); } /* * sets trace timescale as 10**x seconds */ void lt_set_timescale(struct lt_trace *lt, int timescale) { if(lt) { lt->timescale = timescale; } } /* * sets clock compression heuristic */ void lt_set_clock_compress(struct lt_trace *lt) { if(lt) { lt->clock_compress = 1; } } /* * sets change dump compression */ void lt_set_chg_compress(struct lt_trace *lt) { if(lt) { if((lt->zmode==LT_ZMODE_NONE)&&(!lt->emitted)) { lt_set_zmode(lt, lt->zmode = LT_ZMODE_GZIP); fflush(lt->handle); lt->zhandle = gzdopen(dup(fileno(lt->handle)), "wb9"); } } } /* * sets change dictionary compression */ void lt_set_dict_compress(struct lt_trace *lt, unsigned int minwidth) { if((lt)&&(!lt->emitted)) { lt->dictmode = 1; if(minwidth>1) { lt->mindictwidth = minwidth; } } } /* * sets change interlace */ void lt_set_no_interlace(struct lt_trace *lt) { if((lt)&&(!lt->emitted)&&(!lt->sorted_facs)) { if(lt->zmode==LT_ZMODE_NONE) /* this mode implies BZIP2 compression! */ { lt_set_zmode(lt, lt->zmode = LT_ZMODE_BZIP2); fflush(lt->handle); lt->zhandle = BZ2_bzdopen(dup(fileno(lt->handle)), "wb9"); } if((lt->sorted_facs = (struct lt_symbol **)calloc(lt->numfacs, sizeof(struct lt_symbol *)))) { struct lt_symbol *s = lt->symchain; int i; if(lt->do_strip_brackets) for(i=0;inumfacs;i++) { lt->sorted_facs[lt->numfacs - i - 1] = s; /* facs were chained backwards so reverse to restore bitslicing */ strip_brack(s); s=s->symchain; } else for(i=0;inumfacs;i++) { lt->sorted_facs[lt->numfacs - i - 1] = s; /* facs were chained backwards so reverse to restore bitslicing */ s=s->symchain; } wave_msort(lt->sorted_facs, lt->numfacs); for(i=0;inumfacs;i++) { lt->sorted_facs[i]->facnum = i; } if(lt->numfacs >= 256*65536) { lt->numfacs_bytes = 4; } else if(lt->numfacs >= 65536) { lt->numfacs_bytes = 3; } else if(lt->numfacs >= 256) { lt->numfacs_bytes = 2; } else { lt->numfacs_bytes = 1; } } } } /* * sets trace initial value */ void lt_set_initial_value(struct lt_trace *lt, char value) { if(lt) { int tag; switch(value) { case '0': tag = 0; break; case '1': tag = 1; break; case 'Z': case 'z': tag = 2; break; case 'X': case 'x': tag = 3; break; case 'H': case 'h': tag = 4; break; case 'U': case 'u': tag = 5; break; case 'W': case 'w': tag = 6; break; case 'L': case 'l': tag = 0x7; break; case '-': tag = 0x8; break; default: tag = -1; break; } lt->initial_value = tag; } } /* * Sets bracket stripping (useful for VCD conversions of * bitblasted nets) */ void lt_symbol_bracket_stripping(struct lt_trace *lt, int doit) { if(lt) { lt->do_strip_brackets = (doit!=0); } } /* * emission for trace values.. */ static int lt_optimask[]= { 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff }; static char *lt_expand_integer_to_bits(int len, int value) { static char s[33]; char *p = s; int i; len--; for(i=0;i<=len;i++) { *(p++) = '0' | ((value & (1<<(len-i)))!=0); } *p = 0; return(s); } int lt_emit_value_int(struct lt_trace *lt, struct lt_symbol *s, unsigned int row, int value) { int rc=0; if((!lt)||(!s)) return(rc); if(!lt->emitted) lt->emitted = 1; while(s->aliased_to) /* find root alias if exists */ { s=s->aliased_to; } if(!(s->flags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING))) { int numbytes; /* number of bytes to store value minus one */ unsigned int len = ((s->flags)<_SYM_F_INTEGER) ? 32 : s->len; unsigned int last_change_delta; if((lt->clock_compress)&&(s->rows==0)) { if((len>1)&&(len<=32)) { int ivalue = value; int delta1, delta2; s->clk_mask <<= 1; s->clk_mask |= 1; if( ((s->clk_mask&0x1f)==0x1f) && ( (delta1=(ivalue - s->clk_prevval1) & lt_optimask[s->len]) == ((s->clk_prevval1 - s->clk_prevval3) & lt_optimask[s->len]) ) && ( (delta2=(s->clk_prevval - s->clk_prevval2) & lt_optimask[s->len]) == ((s->clk_prevval2 - s->clk_prevval4) & lt_optimask[s->len]) ) && ( (delta1==delta2) || ((!delta1)&&(!delta2)) ) ) { if(s->clk_prevtrans==ULLDescriptor(~0)) { s->clk_prevtrans = lt->timeval; s->clk_numtrans = 0; } else if(s->clk_numtrans == 0) { s->clk_delta = lt->timeval - s->clk_prevtrans; s->clk_prevtrans = lt->timeval; s->clk_numtrans++; } else { if(s->clk_delta == (lt->timeval - s->clk_prevtrans)) { s->clk_numtrans++; s->clk_prevtrans = lt->timeval; if(s->clk_numtrans > LT_CLKPACK_M) { s->clk_prevval4 = s->clk_prevval3; s->clk_prevval3 = s->clk_prevval2; s->clk_prevval2 = s->clk_prevval1; s->clk_prevval1 = s->clk_prevval; s->clk_prevval = ivalue; /* printf("Clock value '%08x' for '%s' at %lld (#%d)\n", ivalue, s->name, lt->timeval, s->clk_numtrans); */ return(1); } } else { if(s->clk_numtrans > LT_CLKPACK_M) { lt_flushclock_m(lt, s); /* flush clock then continue below! */ } else { s->clk_prevtrans=ULLDescriptor(~0); } } } } else { if(s->clk_numtrans > LT_CLKPACK_M) { lt_flushclock_m(lt, s); /* flush clock then continue below! */ } else { s->clk_prevtrans=ULLDescriptor(~0); } } s->clk_prevval4 = s->clk_prevval3; s->clk_prevval3 = s->clk_prevval2; s->clk_prevval2 = s->clk_prevval1; s->clk_prevval1 = s->clk_prevval; s->clk_prevval = ivalue; } else if(len==1) /* possible clock handling */ { int ivalue = value&1; if(((s->clk_prevval == '1') && (ivalue==0)) || ((s->clk_prevval == '0') && (ivalue==1))) { if(s->clk_prevtrans==ULLDescriptor(~0)) { s->clk_prevtrans = lt->timeval; s->clk_numtrans = 0; } else if(s->clk_numtrans == 0) { s->clk_delta = lt->timeval - s->clk_prevtrans; s->clk_prevtrans = lt->timeval; s->clk_numtrans++; } else { if(s->clk_delta == (lt->timeval - s->clk_prevtrans)) { s->clk_numtrans++; s->clk_prevtrans = lt->timeval; if(s->clk_numtrans > LT_CLKPACK) { s->clk_prevval = ivalue + '0'; /* printf("Clock value '%d' for '%s' at %d (#%d)\n", ivalue, s->name, lt->timeval, s->clk_numtrans); */ return(1); } } else { if(s->clk_numtrans > LT_CLKPACK) { lt_flushclock(lt, s); /* flush clock then continue below! */ } else { s->clk_prevtrans=ULLDescriptor(~0); } } } } else { if(s->clk_numtrans > LT_CLKPACK) { lt_flushclock(lt, s); /* flush clock then continue below! */ } else { s->clk_prevtrans=ULLDescriptor(~0); } } s->clk_prevval = ivalue + '0'; } } /* normal trace handling */ last_change_delta = lt->position - s->last_change - 2; if(last_change_delta >= 256*65536) { numbytes = 3; } else if(last_change_delta >= 65536) { numbytes = 2; } else if(last_change_delta >= 256) { numbytes = 1; } else { numbytes = 0; } if(len<=32) { int start_position = lt->position; int tag; int optimized0 = ((value<_optimask[len])==0); int optimized1 = ((value<_optimask[len])==lt_optimask[len]); int optimized = optimized0|optimized1; if(!lt->numfacs_bytes) { if(optimized) { tag = (numbytes<<4) | (3+optimized1); /* for x3 and x4 cases */ } else { tag = (numbytes<<4); } lt->lt_emit_u8(lt, tag); switch(numbytes&3) { case 0: lt->lt_emit_u8(lt, last_change_delta); break; case 1: lt->lt_emit_u16(lt, last_change_delta); break; case 2: lt->lt_emit_u24(lt, last_change_delta); break; case 3: lt->lt_emit_u32(lt, last_change_delta); break; } } else { switch(lt->numfacs_bytes) { case 1: lt->lt_emit_u8(lt, s->facnum); break; case 2: lt->lt_emit_u16(lt, s->facnum); break; case 3: lt->lt_emit_u24(lt, s->facnum); break; case 4: lt->lt_emit_u32(lt, s->facnum); break; } lt->lt_emit_u8(lt, optimized ? (3+optimized1) : 0); } s->last_change = start_position; if(s->rows>0) { if(s->rows >= 256*65536) { numbytes = 3; } else if(s->rows >= 65536) { numbytes = 2; } else if(s->rows >= 256) { numbytes = 1; } else { numbytes = 0; } switch(numbytes&3) { case 0: lt->lt_emit_u8(lt, row); break; case 1: lt->lt_emit_u16(lt, row); break; case 2: lt->lt_emit_u24(lt, row); break; case 3: lt->lt_emit_u32(lt, row); break; } } if(!optimized) { if((lt->dictmode)&&(len>lt->mindictwidth)) { char *vpnt_orig = lt_expand_integer_to_bits(len, value); char *vpnt = vpnt_orig; while ( (*vpnt == '0') && (*(vpnt+1)) ) vpnt++; lt->dict = dslxt_splay (vpnt, lt->dict); if(!dslxt_success) { unsigned int vlen = strlen(vpnt)+1; char *vcopy = (char *)malloc(vlen); strcpy(vcopy, vpnt); lt->dict_string_mem_required += vlen; lt->dict = dslxt_insert(vcopy, lt->dict, lt->num_dict_entries); if(!lt->dict16_offset) { if(lt->num_dict_entries==256) lt->dict16_offset = lt->position; } else if(!lt->dict24_offset) { if(lt->num_dict_entries==65536) lt->dict24_offset = lt->position; } else if(!lt->dict32_offset) { if(lt->num_dict_entries==(256*65536)) lt->dict32_offset = lt->position; } lt->num_dict_entries++; } if(lt->dict24_offset) { if(lt->dict32_offset) { lt->lt_emit_u32(lt, lt->dict->val); } else { lt->lt_emit_u24(lt, lt->dict->val); } } else { if(lt->dict16_offset) { lt->lt_emit_u16(lt, lt->dict->val); } else { lt->lt_emit_u8(lt, lt->dict->val); } } } else if(len<9) { value <<= (8-len); rc=lt->lt_emit_u8(lt, value); } else if(len<17) { value <<= (16-len); rc=lt->lt_emit_u16(lt, value); } else if(len<25) { value <<= (24-len); rc=lt->lt_emit_u24(lt, value); } else { value <<= (32-len); rc=lt->lt_emit_u32(lt, value); } } } if(lt->timebuff) { lt->timechangecount++; if(lt->timecurr) { lt->timecurr->next = lt->timebuff; lt->timecurr = lt->timebuff; } else { lt->timehead = lt->timecurr = lt->timebuff; } lt->timebuff=NULL; } } return(rc); } int lt_emit_value_double(struct lt_trace *lt, struct lt_symbol *s, unsigned int row, double value) { int rc=0; int start_position; int tag; if((!lt)||(!s)) return(rc); if(!lt->emitted) lt->emitted = 1; while(s->aliased_to) /* find root alias if exists */ { s=s->aliased_to; } if((s->flags)<_SYM_F_DOUBLE) { int numbytes; /* number of bytes to store value minus one */ unsigned int last_change_delta = lt->position - s->last_change - 2; if(!lt->numfacs_bytes) { if(last_change_delta >= 256*65536) { numbytes = 3; } else if(last_change_delta >= 65536) { numbytes = 2; } else if(last_change_delta >= 256) { numbytes = 1; } else { numbytes = 0; } start_position = lt->position; s->last_change = start_position; tag = (numbytes<<4); lt->lt_emit_u8(lt, tag); switch(numbytes&3) { case 0: lt->lt_emit_u8(lt, last_change_delta); break; case 1: lt->lt_emit_u16(lt, last_change_delta); break; case 2: lt->lt_emit_u24(lt, last_change_delta); break; case 3: lt->lt_emit_u32(lt, last_change_delta); break; } } else { switch(lt->numfacs_bytes) { case 1: lt->lt_emit_u8(lt, s->facnum); break; case 2: lt->lt_emit_u16(lt, s->facnum); break; case 3: lt->lt_emit_u24(lt, s->facnum); break; case 4: lt->lt_emit_u32(lt, s->facnum); break; } } if(s->rows>0) { if(s->rows >= 256*65536) { numbytes = 3; } else if(s->rows >= 65536) { numbytes = 2; } else if(s->rows >= 256) { numbytes = 1; } else { numbytes = 0; } switch(numbytes&3) { case 0: lt->lt_emit_u8(lt, row); break; case 1: lt->lt_emit_u16(lt, row); break; case 2: lt->lt_emit_u24(lt, row); break; case 3: lt->lt_emit_u32(lt, row); break; } } rc=lt->lt_emit_double(lt, value); if(lt->timebuff) { lt->timechangecount++; if(lt->timecurr) { lt->timecurr->next = lt->timebuff; lt->timecurr = lt->timebuff; } else { lt->timehead = lt->timecurr = lt->timebuff; } lt->timebuff=NULL; } } return(rc); } int lt_emit_value_string(struct lt_trace *lt, struct lt_symbol *s, unsigned int row, char *value) { int rc=0; int start_position; int tag; if((!lt)||(!s)||(!value)) return(rc); if(!lt->emitted) lt->emitted = 1; while(s->aliased_to) /* find root alias if exists */ { s=s->aliased_to; } if((s->flags)<_SYM_F_STRING) { int numbytes; /* number of bytes to store value minus one */ unsigned int last_change_delta = lt->position - s->last_change - 2; if(!lt->numfacs_bytes) { if(last_change_delta >= 256*65536) { numbytes = 3; } else if(last_change_delta >= 65536) { numbytes = 2; } else if(last_change_delta >= 256) { numbytes = 1; } else { numbytes = 0; } start_position = lt->position; s->last_change = start_position; tag = (numbytes<<4); lt->lt_emit_u8(lt, tag); switch(numbytes&3) { case 0: lt->lt_emit_u8(lt, last_change_delta); break; case 1: lt->lt_emit_u16(lt, last_change_delta); break; case 2: lt->lt_emit_u24(lt, last_change_delta); break; case 3: lt->lt_emit_u32(lt, last_change_delta); break; } } else { switch(lt->numfacs_bytes) { case 1: lt->lt_emit_u8(lt, s->facnum); break; case 2: lt->lt_emit_u16(lt, s->facnum); break; case 3: lt->lt_emit_u24(lt, s->facnum); break; case 4: lt->lt_emit_u32(lt, s->facnum); break; } } if(s->rows>0) { if(s->rows >= 256*65536) { numbytes = 3; } else if(s->rows >= 65536) { numbytes = 2; } else if(s->rows >= 256) { numbytes = 1; } else { numbytes = 0; } switch(numbytes&3) { case 0: lt->lt_emit_u8(lt, row); break; case 1: lt->lt_emit_u16(lt, row); break; case 2: lt->lt_emit_u24(lt, row); break; case 3: lt->lt_emit_u32(lt, row); break; } } rc=lt->lt_emit_string(lt, value); if(lt->timebuff) { lt->timechangecount++; if(lt->timecurr) { lt->timecurr->next = lt->timebuff; lt->timecurr = lt->timebuff; } else { lt->timehead = lt->timecurr = lt->timebuff; } lt->timebuff=NULL; } } return(rc); } int lt_emit_value_bit_string(struct lt_trace *lt, struct lt_symbol *s, unsigned int row, char *value) { int rc=0; int start_position; int tag, tagadd; if((!lt)||(!s)||(!value)||(!*value)) return(rc); if(!lt->emitted) lt->emitted = 1; while(s->aliased_to) /* find root alias if exists */ { s=s->aliased_to; } if(!(s->flags&(LT_SYM_F_DOUBLE|LT_SYM_F_STRING))) { int numbytes; /* number of bytes to store value minus one */ char *pnt; int mvl=0; char ch; char prevch; unsigned int last_change_delta; unsigned int len = ((s->flags)<_SYM_F_INTEGER) ? 32 : s->len; if((lt->clock_compress)&&(s->rows==0)) { if((len>1)&&(len<=32)) { int legal = 0; int ivalue = 0; unsigned int i; char *pntv = value; int delta1, delta2; for(i=0;i0)) { pntv--; } else { legal = 0; break; } } ivalue = (((unsigned int)ivalue) << 1); ivalue |= (*pntv & 1); legal = 1; pntv++; } s->clk_mask <<= 1; s->clk_mask |= legal; if( ((s->clk_mask&0x1f)==0x1f) && ( (delta1=(ivalue - s->clk_prevval1) & lt_optimask[s->len]) == ((s->clk_prevval1 - s->clk_prevval3) & lt_optimask[s->len]) ) && ( (delta2=(s->clk_prevval - s->clk_prevval2) & lt_optimask[s->len]) == ((s->clk_prevval2 - s->clk_prevval4) & lt_optimask[s->len]) ) && ( (delta1==delta2) || ((!delta1)&&(!delta2)) ) ) { if(s->clk_prevtrans==ULLDescriptor(~0)) { s->clk_prevtrans = lt->timeval; s->clk_numtrans = 0; } else if(s->clk_numtrans == 0) { s->clk_delta = lt->timeval - s->clk_prevtrans; s->clk_prevtrans = lt->timeval; s->clk_numtrans++; } else { if(s->clk_delta == (lt->timeval - s->clk_prevtrans)) { s->clk_numtrans++; s->clk_prevtrans = lt->timeval; if(s->clk_numtrans > LT_CLKPACK_M) { s->clk_prevval4 = s->clk_prevval3; s->clk_prevval3 = s->clk_prevval2; s->clk_prevval2 = s->clk_prevval1; s->clk_prevval1 = s->clk_prevval; s->clk_prevval = ivalue; /* printf("Clock value '%08x' for '%s' [len=%d] at %lld (#%d)\n", ivalue, s->name, len, lt->timeval, s->clk_numtrans); */ return(1); } } else { if(s->clk_numtrans > LT_CLKPACK_M) { lt_flushclock_m(lt, s); /* flush clock then continue below! */ } else { s->clk_prevtrans=ULLDescriptor(~0); } } } } else { if(s->clk_numtrans > LT_CLKPACK_M) { lt_flushclock_m(lt, s); /* flush clock then continue below! */ } else { s->clk_prevtrans=ULLDescriptor(~0); } } s->clk_prevval4 = s->clk_prevval3; s->clk_prevval3 = s->clk_prevval2; s->clk_prevval2 = s->clk_prevval1; s->clk_prevval1 = s->clk_prevval; s->clk_prevval = ivalue; } else if(len==1) /* possible clock handling */ { if(((s->clk_prevval == '1') && (value[0]=='0')) || ((s->clk_prevval == '0') && (value[0]=='1'))) { if(s->clk_prevtrans==ULLDescriptor(~0)) { s->clk_prevtrans = lt->timeval; s->clk_numtrans = 0; } else if(s->clk_numtrans == 0) { s->clk_delta = lt->timeval - s->clk_prevtrans; s->clk_prevtrans = lt->timeval; s->clk_numtrans++; } else { if(s->clk_delta == (lt->timeval - s->clk_prevtrans)) { s->clk_numtrans++; s->clk_prevtrans = lt->timeval; if(s->clk_numtrans > LT_CLKPACK) { s->clk_prevval = value[0]; /* printf("Clock value '%c' for '%s' at %lld (#%d)\n", value[0], s->name, lt->timeval, s->clk_numtrans); */ return(1); } } else { if(s->clk_numtrans > LT_CLKPACK) { lt_flushclock(lt, s); /* flush clock then continue below! */ } else { s->clk_prevtrans=ULLDescriptor(~0); } } } } else { if(s->clk_numtrans > LT_CLKPACK) { lt_flushclock(lt, s); /* flush clock then continue below! */ } else { s->clk_prevtrans=ULLDescriptor(~0); } } s->clk_prevval = value[0]; } } /* normal trace handling */ last_change_delta = lt->position - s->last_change - 2; if(last_change_delta >= 256*65536) { numbytes = 3; } else if(last_change_delta >= 65536) { numbytes = 2; } else if(last_change_delta >= 256) { numbytes = 1; } else { numbytes = 0; } pnt = value; prevch = *pnt; while((ch=*(pnt++))) { switch(ch) { case '0': case '1': mvl|=LT_MVL_2; break; case 'Z': case 'z': case 'X': case 'x': mvl|=LT_MVL_4; break; default: mvl|=LT_MVL_9; break; } if(prevch!=ch) prevch = 0; } switch(prevch) { case 0x00: tagadd = 0; break; case '0': tagadd = 3; break; case '1': tagadd = 4; break; case 'Z': case 'z': tagadd = 5; break; case 'X': case 'x': tagadd = 6; break; case 'H': case 'h': tagadd = 7; break; case 'U': case 'u': tagadd = 8; break; case 'W': case 'w': tagadd = 9; break; case 'L': case 'l': tagadd = 0xa; break; default: tagadd = 0xb; break; } if(mvl) { start_position = lt->position; if(!lt->numfacs_bytes) { if(tagadd) { tag = (numbytes<<4) + tagadd; } else { tag = (numbytes<<4) + ((mvl<_MVL_9)? 2 : ((mvl<_MVL_4)? 1 : 0)); } lt->lt_emit_u8(lt, tag); switch(numbytes&3) { case 0: lt->lt_emit_u8(lt, last_change_delta); break; case 1: lt->lt_emit_u16(lt, last_change_delta); break; case 2: lt->lt_emit_u24(lt, last_change_delta); break; case 3: lt->lt_emit_u32(lt, last_change_delta); break; } } else { switch(lt->numfacs_bytes) { case 1: lt->lt_emit_u8(lt, s->facnum); break; case 2: lt->lt_emit_u16(lt, s->facnum); break; case 3: lt->lt_emit_u24(lt, s->facnum); break; case 4: lt->lt_emit_u32(lt, s->facnum); break; } if(tagadd) { lt->lt_emit_u8(lt, tagadd); } else { lt->lt_emit_u8(lt, (mvl<_MVL_9)? 2 : ((mvl<_MVL_4)? 1 : 0) ); } } s->last_change = start_position; if(s->rows>0) { if(s->rows >= 256*65536) { numbytes = 3; } else if(s->rows >= 65536) { numbytes = 2; } else if(s->rows >= 256) { numbytes = 1; } else { numbytes = 0; } switch(numbytes&3) { case 0: lt->lt_emit_u8(lt, row); break; case 1: lt->lt_emit_u16(lt, row); break; case 2: lt->lt_emit_u24(lt, row); break; case 3: lt->lt_emit_u32(lt, row); break; } } if(!tagadd) { unsigned int len2 = ((s->flags)<_SYM_F_INTEGER) ? 32 : s->len; if((mvl & (LT_MVL_2|LT_MVL_4|LT_MVL_9)) == LT_MVL_2) { unsigned int i; int bitpos = 7; int outval = 0; int thisval= 0; pnt = value; if((lt->dictmode)&&(len2>lt->mindictwidth)) { char *vpnt = value; while ( (*vpnt == '0') && (*(vpnt+1)) ) vpnt++; lt->dict = dslxt_splay (vpnt, lt->dict); if(!dslxt_success) { unsigned int vlen = strlen(vpnt)+1; char *vcopy = (char *)malloc(vlen); strcpy(vcopy, vpnt); lt->dict_string_mem_required += vlen; lt->dict = dslxt_insert(vcopy, lt->dict, lt->num_dict_entries); if(!lt->dict16_offset) { if(lt->num_dict_entries==256) lt->dict16_offset = lt->position; } else if(!lt->dict24_offset) { if(lt->num_dict_entries==65536) lt->dict24_offset = lt->position; } else if(!lt->dict32_offset) { if(lt->num_dict_entries==(256*65536)) lt->dict32_offset = lt->position; } lt->num_dict_entries++; } if(lt->dict24_offset) { if(lt->dict32_offset) { lt->lt_emit_u32(lt, lt->dict->val); } else { lt->lt_emit_u24(lt, lt->dict->val); } } else { if(lt->dict16_offset) { lt->lt_emit_u16(lt, lt->dict->val); } else { lt->lt_emit_u8(lt, lt->dict->val); } } } else for(i=0;ilt_emit_u8(lt, outval); outval = 0; bitpos = 7; } } } else if((mvl & (LT_MVL_4|LT_MVL_9)) == LT_MVL_4) { unsigned int i; int bitpos = 6; int outval = 0; int thisval= 0; pnt = value; for(i=0;ilt_emit_u8(lt, outval); outval = 0; bitpos = 6; } } } else /* if(mvl & LT_MVL_9) */ { unsigned int i; int bitpos = 4; int outval = 0; int thisval= 0; pnt = value; for(i=0;ilt_emit_u8(lt, outval); outval = 0; bitpos = 4; } } } } rc=1; } if(lt->timebuff) { lt->timechangecount++; if(lt->timecurr) { lt->timecurr->next = lt->timebuff; lt->timecurr = lt->timebuff; } else { lt->timehead = lt->timecurr = lt->timebuff; } lt->timebuff=NULL; } } return(rc); } /* * blackout functions */ void lt_set_dumpoff(struct lt_trace *lt) { if((lt)&&(!lt->dumpoff_active)) { struct lt_timetrail *ltt = calloc(1, sizeof(struct lt_timetrail)); ltt->timeval = lt->timeval; if(lt->dumpoffhead) { lt->dumpoffcurr->next = ltt; lt->dumpoffcurr = ltt; } else { lt->dumpoffhead = lt->dumpoffcurr = ltt; } lt->dumpoff_active = 1; lt->dumpoffcount++; } } void lt_set_dumpon(struct lt_trace *lt) { if((lt)&&(lt->dumpoff_active)) { struct lt_timetrail *ltt = calloc(1, sizeof(struct lt_timetrail)); ltt->timeval = lt->timeval; lt->dumpoffcurr->next = ltt; lt->dumpoffcurr = ltt; lt->dumpoff_active = 0; } } void lt_set_timezero(struct lt_trace *lt, lxtotime_t timeval) { if(lt) { lt->timezero = timeval; } }