From af806ed9c38b3fe2a64aed512818362e21482ca2 Mon Sep 17 00:00:00 2001 From: steve Date: Mon, 1 Sep 2003 04:04:03 +0000 Subject: [PATCH] Add lxt2 support. --- vpi/Makefile.in | 6 +- vpi/lxt2_write.c | 1765 ++++++++++++++++++++++++++++++++++++++++++++++ vpi/lxt2_write.h | 271 +++++++ vpi/sys_lxt2.c | 822 +++++++++++++++++++++ vpi/sys_table.c | 24 +- 5 files changed, 2884 insertions(+), 4 deletions(-) create mode 100644 vpi/lxt2_write.c create mode 100644 vpi/lxt2_write.h create mode 100644 vpi/sys_lxt2.c diff --git a/vpi/Makefile.in b/vpi/Makefile.in index bd88985b6..894b759d3 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -18,7 +18,7 @@ # 59 Temple Place - Suite 330 # Boston, MA 02111-1307, USA # -#ident "$Id: Makefile.in,v 1.41 2003/08/22 04:27:11 steve Exp $" +#ident "$Id: Makefile.in,v 1.42 2003/09/01 04:04:03 steve Exp $" # # SHELL = /bin/sh @@ -59,8 +59,8 @@ dep: O = sys_table.o sys_convert.o sys_deposit.o sys_display.o sys_finish.o \ sys_plusargs.o sys_random.o sys_readmem.o sys_readmem_lex.o sys_time.o \ -sys_vcd.o sys_vcdoff.o sys_lxt.o lxt_write.o vcd_priv.o \ -mt19937int.o stringheap.o +sys_vcd.o sys_vcdoff.o sys_lxt.o lxt_write.o sys_lxt2.o lxt2_write.o \ +vcd_priv.o mt19937int.o stringheap.o LIBS = @LIBS@ SYSTEM_VPI_LDFLAGS = $(LIBS) diff --git a/vpi/lxt2_write.c b/vpi/lxt2_write.c new file mode 100644 index 000000000..296cb217b --- /dev/null +++ b/vpi/lxt2_write.c @@ -0,0 +1,1765 @@ +/* + * Copyright (c) 2003 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 "lxt2_write.h" + + +static char *lxt2_wr_vcd_truncate_bitvec(char *s) +{ +char l, r; + +r=*s; +if(r=='1') + { + return s; + } + else + { + s++; + } + +for(;;s++) + { + l=r; r=*s; + if(!r) return (s-1); + + if(l!=r) + { + return(((l=='0')&&(r=='1'))?s:s-1); + } + } +} + + +/************************ splay ************************/ + +static ds_Tree * ds_splay (granmsk_t i, ds_Tree * t) { +/* Simple top down splay, not requiring i to be in the tree t. */ +/* What it does is described above. */ + ds_Tree N, *l, *r, *y; + if (t == NULL) return t; + N.left = N.right = NULL; + l = r = &N; + + for (;;) { + if (i < t->item) { + if (t->left == NULL) break; + if (i < t->left->item) { + 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 (i > t->item) { + if (t->right == NULL) break; + if (i > t->right->item) { + 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 { + break; + } + } + l->right = t->left; /* assemble */ + r->left = t->right; + t->left = N.right; + t->right = N.left; + return t; +} + + +static ds_Tree * ds_insert(granmsk_t i, ds_Tree * t, int val) { +/* Insert i into the tree t, unless it's already there. */ +/* Return a pointer to the resulting tree. */ + ds_Tree * n; + + n = (ds_Tree *) calloc (1, sizeof (ds_Tree)); + if (n == NULL) { + fprintf(stderr, "ds_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 = ds_splay(i,t); + if (i < t->item) { + n->left = t->left; + n->right = t; + t->left = NULL; + return n; + } else if (i > t->item) { + 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; + } +} + +/************************ splay ************************/ + +static int dslxt_success; + +static dslxt_Tree * dslxt_splay (char *i, dslxt_Tree * t) { +/* Simple top down splay, not requiring i to be in the tree t. */ +/* What it does is described above. */ + dslxt_Tree N, *l, *r, *y; + int dir; + + dslxt_success = 0; + + if (t == NULL) return t; + N.left = N.right = NULL; + l = r = &N; + + for (;;) { + dir = strcmp(i, t->item); + 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; + } +} + +/************************ splay ************************/ + +/* + * functions which emit various big endian + * data to a file + */ +static int lxt2_wr_emit_u8(struct lxt2_wr_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 lxt2_wr_emit_u16(struct lxt2_wr_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 lxt2_wr_emit_u32(struct lxt2_wr_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 lxt2_wr_emit_u64(struct lxt2_wr_trace *lt, int valueh, int valuel) +{ +int rc; + +if((rc=lxt2_wr_emit_u32(lt, valueh))) + { + rc=lxt2_wr_emit_u32(lt, valuel); + } + +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 gzwrite_buffered(struct lxt2_wr_trace *lt) +{ +int rc = 1; + +if(lt->gzbufpnt > LXT2_WR_GZWRITE_BUFFER) + { + rc = gzwrite(lt->zhandle, lt->gzdest, lt->gzbufpnt); + rc = rc ? 1 : 0; + lt->gzbufpnt = 0; + } + +return(rc); +} + +static void gzflush_buffered(struct lxt2_wr_trace *lt, int doclose) +{ +if(lt->gzbufpnt) + { + gzwrite(lt->zhandle, lt->gzdest, lt->gzbufpnt); + lt->gzbufpnt = 0; + if(!doclose) + { + gzflush(lt->zhandle, Z_SYNC_FLUSH); + } + } + +if(doclose) + { + gzclose(lt->zhandle); + } +} + + +static int lxt2_wr_emit_u8z(struct lxt2_wr_trace *lt, int value) +{ +int nmemb; + +lt->gzdest[lt->gzbufpnt++] = value & 0xff; + +nmemb=gzwrite_buffered(lt); +lt->zpackcount++; +lt->position++; +return(nmemb); +} + + +static int lxt2_wr_emit_u16z(struct lxt2_wr_trace *lt, int value) +{ +int nmemb; + +lt->gzdest[lt->gzbufpnt++] = (value>>8) & 0xff; +lt->gzdest[lt->gzbufpnt++] = value & 0xff; +nmemb = gzwrite_buffered(lt); +lt->zpackcount+=2; +lt->position+=2; +return(nmemb); +} + + +static int lxt2_wr_emit_u24z(struct lxt2_wr_trace *lt, int value) +{ +int nmemb; + +lt->gzdest[lt->gzbufpnt++] = (value>>16) & 0xff; +lt->gzdest[lt->gzbufpnt++] = (value>>8) & 0xff; +lt->gzdest[lt->gzbufpnt++] = value & 0xff; +nmemb=gzwrite_buffered(lt); +lt->zpackcount+=3; +lt->position+=3; +return(nmemb); +} + + +static int lxt2_wr_emit_u32z(struct lxt2_wr_trace *lt, int value) +{ +int nmemb; + +lt->gzdest[lt->gzbufpnt++] = (value>>24) & 0xff; +lt->gzdest[lt->gzbufpnt++] = (value>>16) & 0xff; +lt->gzdest[lt->gzbufpnt++] = (value>>8) & 0xff; +lt->gzdest[lt->gzbufpnt++] = value & 0xff; +nmemb=gzwrite_buffered(lt); + +lt->zpackcount+=4; +lt->position+=4; +return(nmemb); +} + + +static int lxt2_wr_emit_u64z(struct lxt2_wr_trace *lt, int valueh, int valuel) +{ +int rc; + +if((rc=lxt2_wr_emit_u32z(lt, valueh))) + { + rc=lxt2_wr_emit_u32z(lt, valuel); + } + +return(rc); +} + + +static int lxt2_wr_emit_stringz(struct lxt2_wr_trace *lt, char *value) +{ +int rc=1; +do + { + rc&=lxt2_wr_emit_u8z(lt, *value); + } while(*(value++)); +return(rc); +} + + +/* + * hash/symtable manipulation + */ +static int lxt2_wr_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%LXT2_WR_SYMPRIME); +} + + +static struct lxt2_wr_symbol *lxt2_wr_symadd(struct lxt2_wr_trace *lt, const char *name, int hv) +{ +struct lxt2_wr_symbol *s; + +s=(struct lxt2_wr_symbol *)calloc(1,sizeof(struct lxt2_wr_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 lxt2_wr_symbol *lxt2_wr_symfind(struct lxt2_wr_trace *lt, const char *s) +{ +int hv; +struct lxt2_wr_symbol *temp; + +hv=lxt2_wr_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 lxt2_wr_compress_fac(struct lxt2_wr_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; + } + lxt2_wr_emit_u16z(lt, i); + lxt2_wr_emit_stringz(lt, str+i); + free(lt->compress_fac_str); + } + else + { + lxt2_wr_emit_u16z(lt, 0); + lxt2_wr_emit_stringz(lt, str); + } + +lt->compress_fac_str = (char *) malloc((lt->compress_fac_len=len)+1); +strcpy(lt->compress_fac_str, str); +} + + +/* + * emit facs in sorted order along with geometry + * and sync table info + */ +static int lxt2_wr_compare(const void *v1, const void *v2) +{ +struct lxt2_wr_symbol *s1 = *(struct lxt2_wr_symbol **)v1; +struct lxt2_wr_symbol *s2 = *(struct lxt2_wr_symbol **)v2; +int rc = strcmp(s1->name, s2->name); +if(rc) + { + return(rc); + } + else + { + return(s1->msb - s2->msb); + } +} + + +static void strip_brack(struct lxt2_wr_symbol *s) +{ +char *lastch = s->name+s->namlen - 1; +if(*lastch!=']') return; +if(s->namlen<3) return; +lastch--; +while(lastch!=s->name) + { + if(*lastch=='[') + { + *lastch=0x00; + return; + } + lastch--; + } +return; +} + + +static void lxt2_wr_emitfacs(struct lxt2_wr_trace *lt) +{ +int i; + +if((lt)&&(lt->numfacs)) + { + struct lxt2_wr_symbol *s = lt->symchain; + + if((lt->sorted_facs = (struct lxt2_wr_symbol **)calloc(lt->numfacs, sizeof(struct lxt2_wr_symbol *)))) + { + if(lt->do_strip_brackets) + for(i=0;inumfacs;i++) + { + lt->sorted_facs[i] = s; + strip_brack(s); + s=s->symchain; + } + else + for(i=0;inumfacs;i++) + { + lt->sorted_facs[i] = s; + s=s->symchain; + } + qsort((void *)lt->sorted_facs, lt->numfacs, sizeof(struct lxt2_wr_symbol *), lxt2_wr_compare); + + for(i=0;inumfacs;i++) + { + lt->sorted_facs[i]->facnum = i; + } + + lt->facname_offset=lt->position; + + lxt2_wr_emit_u32(lt, lt->numfacs); /* uncompressed */ + lxt2_wr_emit_u32(lt, lt->numfacbytes); /* uncompressed */ + lxt2_wr_emit_u32(lt, lt->longestname); /* uncompressed */ + 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 */ + lxt2_wr_emit_u8(lt, lt->timescale); /* timescale (-9 default == nsec) */ + + fflush(lt->handle); + lt->zfacname_size = lt->position; + lt->zhandle = gzdopen(dup(fileno(lt->handle)), "wb9"); + + lt->zpackcount = 0; + for(i=0;inumfacs;i++) + { + lxt2_wr_compress_fac(lt, lt->sorted_facs[i]->name); + free(lt->sorted_facs[i]->name); + lt->sorted_facs[i]->name = NULL; + } + free(lt->compress_fac_str); lt->compress_fac_str=NULL; + lt->compress_fac_len=0; + lt->zfacname_predec_size = lt->zpackcount; + + gzflush_buffered(lt, 1); + fseek(lt->handle, 0L, SEEK_END); + lt->position=ftell(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&LXT2_WR_SYM_F_ALIAS)==0) + { + lxt2_wr_emit_u32z(lt, lt->sorted_facs[i]->rows); + lxt2_wr_emit_u32z(lt, lt->sorted_facs[i]->msb); + lxt2_wr_emit_u32z(lt, lt->sorted_facs[i]->lsb); + lxt2_wr_emit_u32z(lt, lt->sorted_facs[i]->flags); + } + else + { + lxt2_wr_emit_u32z(lt, lt->sorted_facs[i]->aliased_to->facnum); + lxt2_wr_emit_u32z(lt, lt->sorted_facs[i]->msb); + lxt2_wr_emit_u32z(lt, lt->sorted_facs[i]->lsb); + lxt2_wr_emit_u32z(lt, LXT2_WR_SYM_F_ALIAS); + } + } + + gzflush_buffered(lt, 1); + fseek(lt->handle, 0L, SEEK_END); + lt->position=ftell(lt->handle); + lt->zfacgeometry_size = lt->position - lt->facgeometry_offset; + + fseek(lt->handle, lt->facname_offset + 12, 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); + } + } +} + + +/* + * initialize the trace and get back and lt context + */ +struct lxt2_wr_trace *lxt2_wr_init(const char *name) +{ +struct lxt2_wr_trace *lt=(struct lxt2_wr_trace *)calloc(1, sizeof(struct lxt2_wr_trace)); + +if(!(lt->handle=fopen(name, "wb"))) + { + free(lt); + lt=NULL; + } + else + { + lxt2_wr_emit_u16(lt, LXT2_WR_HDRID); + lxt2_wr_emit_u16(lt, LXT2_WR_VERSION); + lxt2_wr_emit_u8 (lt, LXT2_WR_GRANULE_SIZE); /* currently 32 or 64 */ + lt->timescale = -9; + lt->maxgranule = LXT2_WR_GRANULE_NUM; + lxt2_wr_set_compression_depth(lt, 4); /* set fast/loose compression depth, user can fix this any time after init */ + lt->initial_value = 'x'; + } + +return(lt); +} + + +/* + * set initial value of trace (0, 1, x, z) only legal vals + */ +void lxt2_wr_set_initial_value(struct lxt2_wr_trace *lt, char value) +{ +if(lt) + { + switch(value) + { + case '0': + case '1': + case 'x': + case 'z': break; + case 'Z': value = 'z'; break; + default: value = 'x'; break; + } + + lt->initial_value = value; + } +} + + +/* + * maint function for finding a symbol if it exists + */ +struct lxt2_wr_symbol *lxt2_wr_symbol_find(struct lxt2_wr_trace *lt, const char *name) +{ +struct lxt2_wr_symbol *s=NULL; + +if((lt)&&(name)) s=lxt2_wr_symfind(lt, name); +return(s); +} + + +/* + * add a trace (if it doesn't exist already) + */ +struct lxt2_wr_symbol *lxt2_wr_symbol_add(struct lxt2_wr_trace *lt, const char *name, unsigned int rows, int msb, int lsb, int flags) +{ +struct lxt2_wr_symbol *s; +int len; +int flagcnt; + +if((!lt)||(lt->sorted_facs)) return(NULL); + +flagcnt = ((flags&LXT2_WR_SYM_F_INTEGER)!=0) + ((flags&LXT2_WR_SYM_F_DOUBLE)!=0) + ((flags&LXT2_WR_SYM_F_STRING)!=0); + +if((flagcnt>1)||(!lt)||(!name)||(lxt2_wr_symfind(lt, name))) return (NULL); + +s=lxt2_wr_symadd(lt, name, lxt2_wr_hash(name)); +s->rows = rows; +s->flags = flags&(~LXT2_WR_SYM_F_ALIAS); /* aliasing makes no sense here.. */ + +if(!flagcnt) + { + s->msb = msb; + s->lsb = lsb; + s->len = (msbvalue = strdup("NaN"); + } + else + { + if(flags & LXT2_WR_SYM_F_INTEGER) + { + s->len = 32; + } + + s->value = malloc(s->len + 1); + memset(s->value, lt->initial_value, s->len); + s->value[s->len]=0; + + s->msk = LXT2_WR_GRAN_1VAL; /* stuff in an initial value */ + switch(lt->initial_value) + { + case '0': s->chg[0] = LXT2_WR_ENC_0; break; + case '1': s->chg[0] = LXT2_WR_ENC_1; break; + case 'z': s->chg[0] = LXT2_WR_ENC_Z; break; + default: s->chg[0] = LXT2_WR_ENC_X; break; + } + s->chgpos++; /* don't worry that a time doesn't exist as it will soon enough.. */ + } + +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 lxt2_wr_symbol *lxt2_wr_symbol_alias(struct lxt2_wr_trace *lt, const char *existing_name, const char *alias, int msb, int lsb) +{ +struct lxt2_wr_symbol *s, *sa; +int len; +int bitlen; +int flagcnt; + +if((!lt)||(!existing_name)||(!alias)||(!(s=lxt2_wr_symfind(lt, existing_name)))||(lxt2_wr_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&LXT2_WR_SYM_F_INTEGER)!=0) + ((s->flags&LXT2_WR_SYM_F_DOUBLE)!=0) + ((s->flags&LXT2_WR_SYM_F_STRING)!=0); +bitlen = (msblen)) return(NULL); + +sa=lxt2_wr_symadd(lt, alias, lxt2_wr_hash(alias)); +sa->flags = LXT2_WR_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/granule updating + */ +int lxt2_wr_inc_time_by_delta(struct lxt2_wr_trace *lt, unsigned int timeval) +{ +return(lxt2_wr_set_time64(lt, lt->maxtime + (lxttime_t)timeval)); +} + +int lxt2_wr_set_time(struct lxt2_wr_trace *lt, unsigned int timeval) +{ +return(lxt2_wr_set_time64(lt, (lxttime_t)timeval)); +} + +int lxt2_wr_inc_time_by_delta64(struct lxt2_wr_trace *lt, lxttime_t timeval) +{ +return(lxt2_wr_set_time64(lt, lt->maxtime + timeval)); +} + + +void lxt2_wr_flush_granule(struct lxt2_wr_trace *lt, int do_finalize) +{ +unsigned int idx_nbytes, map_nbytes, i, j; +struct lxt2_wr_symbol *s; + +if(lt->flush_valid) + { + if(lt->flushtime == lt->lasttime) + { + return; + } + + lt->flush_valid = 0; + } + +if(!lt->timegranule) + { + fseek(lt->handle, 0L, SEEK_END); + lt->current_chunk=lt->position = ftell(lt->handle); + /* fprintf(stderr, "First chunk position is %d (0x%08x)\n", lt->current_chunk, lt->current_chunk); */ + lxt2_wr_emit_u32(lt, 0); /* size of this section (uncompressed) */ + lxt2_wr_emit_u32(lt, 0); /* size of this section (compressed) */ + lxt2_wr_emit_u64(lt, 0, 0); /* begin time of section */ + lxt2_wr_emit_u64(lt, 0, 0); /* end time of section */ + fflush(lt->handle); + lt->current_chunkz = lt->position; + /* fprintf(stderr, "First chunkz position is %d (0x%08x)\n", lt->current_chunkz, lt->current_chunkz); */ + + lt->zhandle = gzdopen(dup(fileno(lt->handle)), lt->zmode); + lt->zpackcount = 0; + } + +lt->granule_dirty = 0; +lxt2_wr_emit_u8z(lt, LXT2_WR_GRAN_SECT_TIME); + +lxt2_wr_emit_u8z(lt, lt->timepos); +for(i=0;itimepos;i++) + { + lxt2_wr_emit_u64z(lt, (lt->timetable[i]>>32)&0xffffffff, lt->timetable[i]&0xffffffff); + } +gzflush_buffered(lt, 0); + + +for(j=0;jnumfacs;j++) + { + granmsk_t msk = lt->sorted_facs[j]->msk; + + lt->mapdict = ds_splay (msk, lt->mapdict); + if((!lt->mapdict)||(lt->mapdict->item != msk)) + { + lt->mapdict = ds_insert(msk, lt->mapdict, lt->num_map_entries); + lt->num_map_entries++; + + if(lt->mapdict_curr) + { + lt->mapdict_curr->next = lt->mapdict; + lt->mapdict_curr = lt->mapdict; + } + else + { + lt->mapdict_head = lt->mapdict_curr = lt->mapdict; + } + } + } + +if(lt->num_map_entries <= 256) { map_nbytes = 1; } +else if(lt->num_map_entries <= 256*256) { map_nbytes = 2; } +else if(lt->num_map_entries <= 256*256*256) { map_nbytes = 3; } +else { map_nbytes = 4; } + +lxt2_wr_emit_u8z(lt, map_nbytes); +for(j=0;jnumfacs;j++) + { + unsigned int val; + s=lt->sorted_facs[j]; + lt->mapdict = ds_splay (s->msk, lt->mapdict); + val = lt->mapdict->val; + + switch(map_nbytes) + { + case 1: lxt2_wr_emit_u8z(lt, val); break; + case 2: lxt2_wr_emit_u16z(lt, val); break; + case 3: lxt2_wr_emit_u24z(lt, val); break; + case 4: lxt2_wr_emit_u32z(lt, val); break; + } + + s->msk = LXT2_WR_GRAN_0VAL; + } + + +if((lt->num_dict_entries+LXT2_WR_DICT_START) <= 256) { idx_nbytes = 1; } +else if((lt->num_dict_entries+LXT2_WR_DICT_START) <= 256*256) { idx_nbytes = 2; } +else if((lt->num_dict_entries+LXT2_WR_DICT_START) <= 256*256*256) { idx_nbytes = 3; } +else { idx_nbytes = 4; } + +lxt2_wr_emit_u8z(lt, idx_nbytes); +gzflush_buffered(lt, 0); +for(j=0;jnumfacs;j++) + { + s=lt->sorted_facs[j]; + + for(i=0;ichgpos;i++) + { + switch(idx_nbytes) + { + case 1: lxt2_wr_emit_u8z (lt, s->chg[i]); break; + case 2: lxt2_wr_emit_u16z(lt, s->chg[i]); break; + case 3: lxt2_wr_emit_u24z(lt, s->chg[i]); break; + case 4: lxt2_wr_emit_u32z(lt, s->chg[i]); break; + } + } + + s->chgpos = 0; + } + +gzflush_buffered(lt, 0); + +lt->timepos = 0; +lt->timegranule++; +if((lt->timegranule>=lt->maxgranule)||(do_finalize)) + { + unsigned int unclen, clen; + ds_Tree *dt, *dt2; + dslxt_Tree *ds, *ds2; + + /* fprintf(stderr, "reached granule %d, finalizing block for section %d\n", lt->timegranule, lt->numsections); */ + lt->numsections++; + + /* finalize string dictionary */ + lxt2_wr_emit_u8z(lt, LXT2_WR_GRAN_SECT_DICT); + + ds = lt->dict_head; + /* fprintf(stderr, "num_dict_entries: %d\n", lt->num_dict_entries); */ + gzflush_buffered(lt, 0); + for(i=0;inum_dict_entries;i++) + { + /* fprintf(stderr, "%8d %8d) '%s'\n", ds->val, i, ds->item); */ + if(ds->val != i) + { + fprintf(stderr, "internal error line %d\n", __LINE__); + exit(255); + } + + lxt2_wr_emit_stringz(lt, ds->item); + ds2 = ds->next; + free(ds->item); + free(ds); + ds = ds2; + } + lt->dict_head = lt->dict_curr = lt->dict = NULL; + + /* finalize map dictionary */ + dt = lt->mapdict_head; + /* fprintf(stderr, "num_map_entries: %d\n", lt->num_map_entries); */ + gzflush_buffered(lt, 0); + for(i=0;inum_map_entries;i++) + { + /* fprintf(stderr, "+++ %08x (%d)(%d)\n", dt->item, i, dt->val); */ + if(dt->val != i) + { + fprintf(stderr, "internal error line %d\n", __LINE__); + exit(255); + } + +#if LXT2_WR_GRANULE_SIZE > 32 + lxt2_wr_emit_u64z(lt, (dt->item>>32)&0xffffffff, dt->item&0xffffffff); +#else + lxt2_wr_emit_u32z(lt, dt->item); +#endif + + dt2 = dt->next; + free(dt); + dt = dt2; + } + lt->mapdict_head = lt->mapdict_curr = lt->mapdict = NULL; + + lxt2_wr_emit_u32z(lt, lt->num_dict_entries); /* -12 */ + lxt2_wr_emit_u32z(lt, lt->dict_string_mem_required);/* -8 */ + lxt2_wr_emit_u32z(lt, lt->num_map_entries); /* -4 */ + + lt->num_map_entries = 0; + lt->num_dict_entries = lt->dict_string_mem_required = 0; + + /* fprintf(stderr, "returned from finalize..\n"); */ + gzflush_buffered(lt, 1); + fseek(lt->handle, 0L, SEEK_END); + lt->position=ftell(lt->handle); + /* fprintf(stderr, "file position after dumping dict: %d 0x%08x\n", lt->position, lt->position); */ + + unclen = lt->zpackcount; + clen = lt->position - lt->current_chunkz; + + /* fprintf(stderr, "%d/%d un/compressed bytes in section\n", unclen, clen); */ + + fseek(lt->handle, lt->current_chunk, SEEK_SET); + lxt2_wr_emit_u32(lt, unclen); + lxt2_wr_emit_u32(lt, clen); + lxt2_wr_emit_u64(lt, (lt->firsttime>>32)&0xffffffff, lt->firsttime&0xffffffff); + lxt2_wr_emit_u64(lt, (lt->lasttime>>32)&0xffffffff, lt->lasttime&0xffffffff); + + /* fprintf(stderr, "start: %Ld, end %Ld\n", lt->firsttime, lt->lasttime); */ + lt->timegranule=0; + }; + +if(do_finalize) + { + lt->flush_valid = 1; + lt->flushtime = lt->lasttime; + } +} + + +int lxt2_wr_set_time64(struct lxt2_wr_trace *lt, lxttime_t timeval) +{ +int rc=0; + +if(lt) + { + if(lt->timeset) + { + if(timeval > lt->maxtime) + { + if(lt->bumptime) + { + lt->bumptime = 0; + + if(!lt->flush_valid) + { + lt->timepos++; + } + else + { + lt->flush_valid = 0; + } + + if(lt->timepos == LXT2_WR_GRANULE_SIZE) + { + /* fprintf(stderr, "flushing granule to disk at time %d\n", (unsigned int)timeval); */ + lxt2_wr_flush_granule(lt, 0); + } + } + + /* fprintf(stderr, "updating time to %d (%d dict entries/%d bytes)\n", (unsigned int)timeval, lt->num_dict_entries, lt->dict_string_mem_required); */ + lt->timetable[lt->timepos] = timeval; + lt->lasttime = timeval; + } + } + else + { + lt->timeset = 1; + lt->mintime = lt->maxtime = timeval; + + lt->timetable[lt->timepos] = timeval; + } + + if((!lt->timepos)&&(!lt->timegranule)) + { + struct lxt2_wr_symbol *s = lt->symchain; + + lt->firsttime = timeval; + lt->lasttime = timeval; + + /* fprintf(stderr, "initial value burst timepos==0, timegranule==0\n"); */ + if(lt->blackout) + { + lt->blackout = 0; + lxt2_wr_set_dumpoff(lt); + } + else + { + s = lt->symchain; + while(s) + { + if((!(s->flags&LXT2_WR_SYM_F_ALIAS))&&(s->rows<2)) + { + if(!(s->flags&(LXT2_WR_SYM_F_DOUBLE|LXT2_WR_SYM_F_STRING))) + { + lxt2_wr_emit_value_bit_string(lt, s, 0, s->value); + } + else if (s->flags&LXT2_WR_SYM_F_DOUBLE) + { + double value; + + sscanf(s->value, "%lg", &value); + lxt2_wr_emit_value_double(lt, s, 0, value); + } + else if (s->flags&LXT2_WR_SYM_F_STRING) + { + lxt2_wr_emit_value_string(lt, s, 0, s->value); + } + } + s=s->symchain; + } + } + /* fprintf(stderr, "done initial value burst timepos==0, timegranule==0\n"); */ + } + + lt->granule_dirty = 1; + rc = 1; + } + +return(rc); +} + + +/* + * sets trace timescale as 10**x seconds + */ +void lxt2_wr_set_timescale(struct lxt2_wr_trace *lt, int timescale) +{ +if(lt) + { + lt->timescale = timescale; + } +} + + +/* + * set number of granules per section + * (can modify dynamically) + */ +void lxt2_wr_set_maxgranule(struct lxt2_wr_trace *lt, unsigned int maxgranule) +{ +if(lt) + { + if(!maxgranule) maxgranule = ~0; + lt->maxgranule = maxgranule; + } +} + + +/* + * Sets bracket stripping (useful for VCD conversions of + * bitblasted nets) + */ +void lxt2_wr_symbol_bracket_stripping(struct lxt2_wr_trace *lt, int doit) +{ +if(lt) + { + lt->do_strip_brackets = (doit!=0); + } +} + + + +static char *lxt2_wr_expand_integer_to_bits(unsigned int len, int value) +{ +static char s[33]; +char *p = s; +unsigned int i; + +if(len>32) len=32; + +len--; + +for(i=0;iblackout)||(!s)||(row)) return(rc); + +return(lxt2_wr_emit_value_bit_string(lt, s, row, lxt2_wr_expand_integer_to_bits(s->len, value))); +} + + + +int lxt2_wr_emit_value_double(struct lxt2_wr_trace *lt, struct lxt2_wr_symbol *s, unsigned int row, double value) +{ +int rc=0; + +if((!lt)||(lt->blackout)||(!s)||(row)) return(rc); + +if(!lt->emitted) + { + lxt2_wr_emitfacs(lt); + lt->emitted = 1; + + if(!lt->timeset) + { + lxt2_wr_set_time(lt, 0); + } + } + +while(s->aliased_to) /* find root alias if exists */ + { + s=s->aliased_to; + } + +if(s->flags&LXT2_WR_SYM_F_DOUBLE) + { + char d_buf[32]; + unsigned int idx; + + rc = 1; + sprintf(d_buf, "%.16g", value); + if(!strcmp(d_buf, s->value)) return(rc); + + lt->bumptime = 1; + free(s->value); + s->value = strdup(d_buf); + + lt->dict = dslxt_splay (s->value, lt->dict); + + if(!dslxt_success) + { + unsigned int vlen = strlen(d_buf)+1; + char *vcopy = (char *)malloc(vlen); + strcpy(vcopy, d_buf); + lt->dict_string_mem_required += vlen; + lt->dict = dslxt_insert(vcopy, lt->dict, lt->num_dict_entries); + + if(lt->dict_curr) + { + lt->dict_curr->next = lt->dict; + lt->dict_curr = lt->dict; + } + else + { + lt->dict_head = lt->dict_curr = lt->dict; + } + + idx = lt->num_dict_entries + LXT2_WR_DICT_START; + lt->num_dict_entries++; + } + else + { + idx = lt->dict->val + LXT2_WR_DICT_START; + } + + if((s->msk & (LXT2_WR_GRAN_1VAL<timepos)) == LXT2_WR_GRAN_0VAL) + { + s->msk |= (LXT2_WR_GRAN_1VAL<timepos); + s->chg[s->chgpos] = idx; + + s->chgpos++; + } + else + { + s->chg[s->chgpos-1] = idx; + } + + lt->granule_dirty = 1; + } + +return(rc); +} + + +int lxt2_wr_emit_value_string(struct lxt2_wr_trace *lt, struct lxt2_wr_symbol *s, unsigned int row, char *value) +{ +int rc=0; + +if((!lt)||(lt->blackout)||(!s)||(!value)||(row)) return(rc); + +if(!lt->emitted) + { + lxt2_wr_emitfacs(lt); + lt->emitted = 1; + + if(!lt->timeset) + { + lxt2_wr_set_time(lt, 0); + } + } + +while(s->aliased_to) /* find root alias if exists */ + { + s=s->aliased_to; + } + +if(s->flags&LXT2_WR_SYM_F_STRING) + { + unsigned int idx; + + rc = 1; + if(!strcmp(value, s->value)) return(rc); + + lt->bumptime = 1; + free(s->value); + s->value = strdup(value); + + lt->dict = dslxt_splay (s->value, lt->dict); + + if(!dslxt_success) + { + unsigned int vlen = strlen(value)+1; + char *vcopy = (char *)malloc(vlen); + strcpy(vcopy, value); + lt->dict_string_mem_required += vlen; + lt->dict = dslxt_insert(vcopy, lt->dict, lt->num_dict_entries); + + if(lt->dict_curr) + { + lt->dict_curr->next = lt->dict; + lt->dict_curr = lt->dict; + } + else + { + lt->dict_head = lt->dict_curr = lt->dict; + } + + idx = lt->num_dict_entries + LXT2_WR_DICT_START; + lt->num_dict_entries++; + } + else + { + idx = lt->dict->val + LXT2_WR_DICT_START; + } + + if((s->msk & (LXT2_WR_GRAN_1VAL<timepos)) == LXT2_WR_GRAN_0VAL) + { + s->msk |= (LXT2_WR_GRAN_1VAL<timepos); + s->chg[s->chgpos] = idx; + + s->chgpos++; + } + else + { + s->chg[s->chgpos-1] = idx; + } + + lt->granule_dirty = 1; + } + +return(rc); +} + + +int lxt2_wr_emit_value_bit_string(struct lxt2_wr_trace *lt, struct lxt2_wr_symbol *s, unsigned int row, char *value) +{ +int rc=0; +char *vpnt; +char *vfix; +int valuelen; +int i; + +if((!lt)||(lt->blackout)||(!s)||(!value)||(!*value)||(row)) return(rc); + +if(!lt->emitted) + { + lxt2_wr_emitfacs(lt); + lt->emitted = 1; + + if(!lt->timeset) + { + lxt2_wr_set_time(lt, 0); + } + } + +while(s->aliased_to) /* find root alias if exists */ + { + s=s->aliased_to; + } + +valuelen = strlen(value); /* ensure string is proper length */ +if(valuelen == s->len) + { + vfix = alloca(s->len+1); + strcpy(vfix, value); + value = vfix; + } + else + { + vfix = alloca(s->len+1); + + if(valuelen < s->len) + { + int lendelta = s->len - valuelen; + memset(vfix, (value[0]!='1') ? value[0] : '0', lendelta); + strcpy(vfix+lendelta, value); + } + else + { + memcpy(vfix, value, s->len); + vfix[s->len] = 0; + } + + value = vfix; + } + +for(i=0;ilen;i++) + { + unsigned char ch = value[i]; + if((ch>='A')&&(ch<='Z')) value[i] = ch + ('a'-'A'); + } + +if ( (lt->timepos || lt->timegranule) && !strcmp(value, s->value) ) + { + return(1); /* redundant value change */ + } + + +if(!(s->flags&(LXT2_WR_SYM_F_DOUBLE|LXT2_WR_SYM_F_STRING))) + { + char prevch; + int idx; + + lt->bumptime = 1; + + vpnt = value; + prevch = *vpnt; + while(*vpnt) + { + if(prevch == *vpnt) + { + vpnt++; + } + else + { + prevch = 0; + break; + } + } + + switch(prevch) + { + case '0': idx = LXT2_WR_ENC_0; break; + case '1': idx = LXT2_WR_ENC_1; break; + case 'X': + case 'x': idx = LXT2_WR_ENC_X; break; + case 'Z': + case 'z': idx = LXT2_WR_ENC_Z; break; + default: idx = -1; break; + } + + if((lt->timepos)||(lt->timegranule)) + { + for(i=0;ilen;i++) + { + char ch = value[i]; + + switch(ch) + { + case '0': if(s->value[i]!='1') goto nextalg; else break; + case '1': if(s->value[i]!='0') goto nextalg; else break; + default: goto nextalg; + } + } + idx = LXT2_WR_ENC_INV; goto do_enc; + + nextalg: + if(s->len > 1) + { + if(!memcmp(s->value+1, value, s->len-1)) + { + if((value[s->len-1]&0xfe)=='0') + { + idx = LXT2_WR_ENC_LSH0 + (value[s->len-1]&0x01); + goto do_enc; + } + } + else + if(!memcmp(s->value, value+1, s->len-1)) + { + if((value[0]&0xfe)=='0') + { + idx = LXT2_WR_ENC_RSH0 + (value[0]&0x01); + goto do_enc; + } + } + + if(s->len <= 32) + { + unsigned int intval_old = 0, intval_new = 0; + unsigned int msk; + + for(i=0;ilen;i++) + { + char ch = value[i]; + if((ch!='0')&&(ch!='1')) goto idxchk; + intval_new <<= 1; + intval_new |= ((unsigned int)(ch&1)); + + ch = s->value[i]; + if((ch!='0')&&(ch!='1')) goto idxchk; + intval_old <<= 1; + intval_old |= ((unsigned int)(ch&1)); + } + + msk = (~0)>>(32-s->len); + if( ((intval_old+1)&msk) == intval_new ) { idx = LXT2_WR_ENC_ADD1; goto do_enc; } + if( ((intval_old-1)&msk) == intval_new ) { idx = LXT2_WR_ENC_SUB1; goto do_enc; } + + if( ((intval_old+2)&msk) == intval_new ) { idx = LXT2_WR_ENC_ADD2; goto do_enc; } + if( ((intval_old-2)&msk) == intval_new ) { idx = LXT2_WR_ENC_SUB2; goto do_enc; } + + if( ((intval_old+3)&msk) == intval_new ) { idx = LXT2_WR_ENC_ADD3; goto do_enc; } + if( ((intval_old-3)&msk) == intval_new ) { idx = LXT2_WR_ENC_SUB3; goto do_enc; } + + if(s->len > 2) + { + if( ((intval_old+4)&msk) == intval_new ) { idx = LXT2_WR_ENC_ADD4; goto do_enc; } + if( ((intval_old-4)&msk) == intval_new ) { idx = LXT2_WR_ENC_SUB4; goto do_enc; } + } + + } + } + } + + +idxchk: if(idx<0) + { + vpnt = lxt2_wr_vcd_truncate_bitvec(value); + 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->dict_curr) + { + lt->dict_curr->next = lt->dict; + lt->dict_curr = lt->dict; + } + else + { + lt->dict_head = lt->dict_curr = lt->dict; + } + + idx = lt->num_dict_entries + LXT2_WR_DICT_START; + lt->num_dict_entries++; + } + else + { + idx = lt->dict->val + LXT2_WR_DICT_START; + } + } + +do_enc: + if((s->msk & (LXT2_WR_GRAN_1VAL<timepos)) == LXT2_WR_GRAN_0VAL) + { + s->msk |= (LXT2_WR_GRAN_1VAL<timepos); + s->chg[s->chgpos] = idx; + + s->chgpos++; + } + else + { + s->chg[s->chgpos-1] = idx; + } + + strncpy(s->value, value, s->len); + + lt->granule_dirty = 1; + } + +return(rc); +} + + +/* + * dumping control + */ +void lxt2_wr_set_dumpoff(struct lxt2_wr_trace *lt) +{ +struct lxt2_wr_symbol *s; + +if((lt)&&(!lt->blackout)) + { + if(!lt->emitted) + { + lxt2_wr_emitfacs(lt); + lt->emitted = 1; + + if(!lt->timeset) + { + lxt2_wr_set_time(lt, 0); + } + } + + s = lt->symchain; + while(s) + { + if((s->msk & (LXT2_WR_GRAN_1VAL<timepos)) == LXT2_WR_GRAN_0VAL) + { + s->msk |= (LXT2_WR_GRAN_1VAL<timepos); + s->chg[s->chgpos] = LXT2_WR_ENC_BLACKOUT; + + s->chgpos++; + } + else + { + s->chg[s->chgpos-1] = LXT2_WR_ENC_BLACKOUT; + } + + s=s->symchain; + } + + lt->bumptime = 1; + lt->blackout = 1; + lt->granule_dirty = 1; + } +} + + +void lxt2_wr_set_dumpon(struct lxt2_wr_trace *lt) +{ +int i; +struct lxt2_wr_symbol *s; + +if((lt)&&(lt->blackout)) + { + lt->blackout = 0; + + s = lt->symchain; + while(s) + { + if(s->flags&LXT2_WR_SYM_F_DOUBLE) + { + free(s->value); + s->value = strdup("0"); /* will cause mismatch then flush */ + } + else + { + if(!(s->flags&LXT2_WR_SYM_F_STRING)) + { + s->value[0] = '-'; /* will cause mismatch then flush */ + for(i=1;ilen;i++) + { + s->value[i] = 'x'; /* initial value */ + } + s->value[i]=0; + } + else + { + free(s->value); + s->value = calloc(1, 1*sizeof(char)); + } + } + + s=s->symchain; + } + + s = lt->symchain; + while(s) + { + if((!(s->flags&LXT2_WR_SYM_F_ALIAS))&&(s->rows<2)) + { + if(!(s->flags&(LXT2_WR_SYM_F_DOUBLE|LXT2_WR_SYM_F_STRING))) + { + lxt2_wr_emit_value_bit_string(lt, s, 0, "x"); + } + else if (s->flags&LXT2_WR_SYM_F_DOUBLE) + { + double value; + sscanf("NaN", "%lg", &value); + lxt2_wr_emit_value_double(lt, s, 0, value); + } + else if (s->flags&LXT2_WR_SYM_F_STRING) + { + lxt2_wr_emit_value_string(lt, s, 0, "UNDEF"); + } + } + s=s->symchain; + } + } +} + + +/* + * flush the trace... + */ +void lxt2_wr_flush(struct lxt2_wr_trace *lt) +{ +if(lt) + { + if((lt->timegranule)||(lt->timepos > 0)) + { + if(lt->granule_dirty) + { + lt->timepos++; + lxt2_wr_flush_granule(lt, 1); + } + } + } +} + + +/* + * close out the trace and fixate it + */ +void lxt2_wr_close(struct lxt2_wr_trace *lt) +{ +if(lt) + { + if(lt->granule_dirty) + { + lt->timepos++; + lxt2_wr_flush_granule(lt, 1); + } + + if(lt->symchain) + { + struct lxt2_wr_symbol *s = lt->symchain; + struct lxt2_wr_symbol *s2; + + while(s) + { + if(s->name) { free(s->name); } + if(s->value) { free(s->value); } + s2=s->symchain; + free(s); + s=s2; + } + + lt->symchain=NULL; + } + + free(lt->sorted_facs); + fclose(lt->handle); + free(lt); + } + +} + +/* + * set compression depth + */ +void lxt2_wr_set_compression_depth(struct lxt2_wr_trace *lt, unsigned int depth) +{ +if(lt) + { + if(depth > 9) depth = 9; + sprintf(lt->zmode, "wb%d", depth); + } +} + + +/* + * source level compatibility stub functions + */ +void lxt2_wr_set_no_interlace(struct lxt2_wr_trace *lt) { } +void lxt2_wr_set_chg_compress(struct lxt2_wr_trace *lt) { } +void lxt2_wr_set_clock_compress(struct lxt2_wr_trace *lt) { } +void lxt2_wr_set_dict_compress(struct lxt2_wr_trace *lt, unsigned int minwidth) { } diff --git a/vpi/lxt2_write.h b/vpi/lxt2_write.h new file mode 100644 index 000000000..71caf36b5 --- /dev/null +++ b/vpi/lxt2_write.h @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2003 Tony Bybell. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef DEFS_LXTW_H +#define DEFS_LXTW_H + +#include +#include +#include +#include +#include +#include +#include + +#define LXT2_WR_HDRID (0x1380) +#define LXT2_WR_VERSION (0x0001) + +#define LXT2_WR_GRANULE_SIZE (64) +#define LXT2_WR_GRANULE_NUM (8) + +#define LXT2_WR_GRAN_SECT_TIME 0 +#define LXT2_WR_GRAN_SECT_DICT 1 + +#define LXT2_WR_GZWRITE_BUFFER 4096 +#define LXT2_WR_SYMPRIME 65519 + +typedef unsigned long long lxttime_t; + + +#ifndef _MSC_VER + #define LXT2_WR_LLD "%lld" + #define LXT2_WR_LLDESC(x) x##LL + #define LXT2_WR_ULLDESC(x) x##ULL +#else + #define LXT2_WR_LLD "%I64d" + #define LXT2_WR_LLDESC(x) x##i64 + #define LXT2_WR_ULLDESC(x) x##i64 +#endif + +#if LXT2_WR_GRANULE_SIZE > 32 +typedef unsigned long long granmsk_t; +#define LXT2_WR_GRAN_0VAL (LXT2_WR_ULLDESC(0)) +#define LXT2_WR_GRAN_1VAL (LXT2_WR_ULLDESC(1)) +#else +typedef unsigned int granmsk_t; +#define LXT2_WR_GRAN_0VAL (0) +#define LXT2_WR_GRAN_1VAL (1) +#endif + + +enum LXT2_WR_Encodings { + LXT2_WR_ENC_0, + LXT2_WR_ENC_1, + LXT2_WR_ENC_INV, + LXT2_WR_ENC_LSH0, + LXT2_WR_ENC_LSH1, + LXT2_WR_ENC_RSH0, + LXT2_WR_ENC_RSH1, + + LXT2_WR_ENC_ADD1, + LXT2_WR_ENC_ADD2, + LXT2_WR_ENC_ADD3, + LXT2_WR_ENC_ADD4, + + LXT2_WR_ENC_SUB1, + LXT2_WR_ENC_SUB2, + LXT2_WR_ENC_SUB3, + LXT2_WR_ENC_SUB4, + + LXT2_WR_ENC_X, + LXT2_WR_ENC_Z, + + LXT2_WR_ENC_BLACKOUT, + + LXT2_WR_DICT_START, + }; + +/* + * integer splay + */ +typedef struct ds_tree_node ds_Tree; +struct ds_tree_node { + ds_Tree * left, * right; + granmsk_t item; + int val; + ds_Tree * next; +}; + + +/* + * string splay + */ +typedef struct dslxt_tree_node dslxt_Tree; +struct dslxt_tree_node { + dslxt_Tree * left, * right; + char *item; + unsigned int val; + dslxt_Tree * next; +}; + + +struct lxt2_wr_trace +{ +FILE *handle; +gzFile zhandle; + +dslxt_Tree *dict; /* dictionary manipulation */ +unsigned int num_dict_entries; +unsigned int dict_string_mem_required; +dslxt_Tree *dict_head; +dslxt_Tree *dict_curr; + +ds_Tree *mapdict; /* bitmap compression */ +unsigned int num_map_entries; +ds_Tree *mapdict_head; +ds_Tree *mapdict_curr; + +unsigned int position; +unsigned int zfacname_predec_size, zfacname_size, zfacgeometry_size; +unsigned int zpackcount; +unsigned int current_chunk, current_chunkz; + +struct lxt2_wr_symbol *sym[LXT2_WR_SYMPRIME]; +struct lxt2_wr_symbol **sorted_facs; +struct lxt2_wr_symbol *symchain; +int numfacs; +int numfacbytes; +int longestname; + +int numsections; +unsigned int facname_offset, facgeometry_offset; + +lxttime_t mintime, maxtime; +unsigned int timegranule; +int timescale; +int timepos; +unsigned int maxgranule; +lxttime_t firsttime, lasttime; +lxttime_t timetable[LXT2_WR_GRANULE_SIZE]; + +char *compress_fac_str; +int compress_fac_len; + +lxttime_t flushtime; +unsigned flush_valid : 1; + +unsigned do_strip_brackets : 1; +unsigned emitted : 1; /* gate off change field zmode changes when set */ +unsigned timeset : 1; /* time has been modified from 0..0 */ +unsigned bumptime : 1; /* says that must go to next time position in granule as value change exists for current time */ +unsigned granule_dirty : 1; /* for flushing out final block */ +unsigned blackout : 1; /* blackout on/off */ + +char initial_value; + +char zmode[4]; /* fills in with "wb0".."wb9" */ +unsigned int gzbufpnt; +unsigned char gzdest[LXT2_WR_GZWRITE_BUFFER + 4]; /* enough for zlib buffering */ +}; + + +struct lxt2_wr_symbol +{ +struct lxt2_wr_symbol *next; +struct lxt2_wr_symbol *symchain; +char *name; +int namlen; + +int facnum; +struct lxt2_wr_symbol *aliased_to; + +char *value; /* fac's actual value */ + +unsigned int rows; +int msb, lsb; +int len; +int flags; + +unsigned int chgpos; +granmsk_t msk; /* must contain LXT2_WR_GRANULE_SIZE bits! */ +unsigned int chg[LXT2_WR_GRANULE_SIZE]; +}; + + +#define LXT2_WR_SYM_F_BITS (0) +#define LXT2_WR_SYM_F_INTEGER (1<<0) +#define LXT2_WR_SYM_F_DOUBLE (1<<1) +#define LXT2_WR_SYM_F_STRING (1<<2) +#define LXT2_WR_SYM_F_TIME (LXT2_WR_SYM_F_STRING) /* user must correctly format this as a string */ +#define LXT2_WR_SYM_F_ALIAS (1<<3) + +#define LXT2_WR_SYM_F_SIGNED (1<<4) +#define LXT2_WR_SYM_F_BOOLEAN (1<<5) +#define LXT2_WR_SYM_F_NATURAL ((1<<6)|(LXT2_WR_SYM_F_INTEGER)) +#define LXT2_WR_SYM_F_POSITIVE ((1<<7)|(LXT2_WR_SYM_F_INTEGER)) +#define LXT2_WR_SYM_F_CHARACTER (1<<8) + +#define LXT2_WR_SYM_F_CONSTANT (1<<9) +#define LXT2_WR_SYM_F_VARIABLE (1<<10) +#define LXT2_WR_SYM_F_SIGNAL (1<<11) + +#define LXT2_WR_SYM_F_IN (1<<12) +#define LXT2_WR_SYM_F_OUT (1<<13) +#define LXT2_WR_SYM_F_INOUT (1<<14) + +#define LXT2_WR_SYM_F_WIRE (1<<15) +#define LXT2_WR_SYM_F_REG (1<<16) + + + /* file I/O */ +struct lxt2_wr_trace * lxt2_wr_init(const char *name); +void lxt2_wr_flush(struct lxt2_wr_trace *lt); +void lxt2_wr_close(struct lxt2_wr_trace *lt); + + + /* 0 = no compression, 9 = best compression, 4 = default */ +void lxt2_wr_set_compression_depth(struct lxt2_wr_trace *lt, unsigned int depth); + + /* facility creation */ +void lxt2_wr_set_initial_value(struct lxt2_wr_trace *lt, char value); +struct lxt2_wr_symbol * lxt2_wr_symbol_find(struct lxt2_wr_trace *lt, const char *name); +struct lxt2_wr_symbol * lxt2_wr_symbol_add(struct lxt2_wr_trace *lt, const char *name, unsigned int rows, int msb, int lsb, int flags); +struct lxt2_wr_symbol * lxt2_wr_symbol_alias(struct lxt2_wr_trace *lt, const char *existing_name, const char *alias, int msb, int lsb); +void lxt2_wr_symbol_bracket_stripping(struct lxt2_wr_trace *lt, int doit); + + /* each granule is LXT2_WR_GRANULE_SIZE (32 or 64) timesteps, default is 8 per section */ +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); +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); +int lxt2_wr_inc_time_by_delta64(struct lxt2_wr_trace *lt, lxttime_t timeval); + + /* allows blackout regions in LXT files */ +void lxt2_wr_set_dumpoff(struct lxt2_wr_trace *lt); +void lxt2_wr_set_dumpon(struct lxt2_wr_trace *lt); + + /* left fill on bit_string uses vcd semantics (left fill with value[0] unless value[0]=='1', then use '0') */ +int lxt2_wr_emit_value_int(struct lxt2_wr_trace *lt, struct lxt2_wr_symbol *s, unsigned int row, int value); +int lxt2_wr_emit_value_double(struct lxt2_wr_trace *lt, struct lxt2_wr_symbol *s, unsigned int row, double value); +int lxt2_wr_emit_value_string(struct lxt2_wr_trace *lt, struct lxt2_wr_symbol *s, unsigned int row, char *value); +int lxt2_wr_emit_value_bit_string(struct lxt2_wr_trace *lt, struct lxt2_wr_symbol *s, unsigned int row, char *value); + + /* old lxt dummy functions (might be used later) */ +void lxt2_wr_set_no_interlace(struct lxt2_wr_trace *lt); +void lxt2_wr_set_chg_compress(struct lxt2_wr_trace *lt); +void lxt2_wr_set_clock_compress(struct lxt2_wr_trace *lt); +void lxt2_wr_set_dict_compress(struct lxt2_wr_trace *lt, unsigned int minwidth); + +#endif diff --git a/vpi/sys_lxt2.c b/vpi/sys_lxt2.c new file mode 100644 index 000000000..99601b169 --- /dev/null +++ b/vpi/sys_lxt2.c @@ -0,0 +1,822 @@ +/* + * Copyright (c) 20023Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifdef HAVE_CVS_IDENT +#ident "$Id: sys_lxt2.c,v 1.1 2003/09/01 04:04:03 steve Exp $" +#endif + +# include "config.h" +# include "sys_priv.h" +# include "lxt2_write.h" +# include "vcd_priv.h" + +/* + * This file contains the implementations of the VCD related + * funcitons. + */ + +# include "vpi_user.h" +# include +# include +# include +# include +# include +#ifdef HAVE_MALLOC_H +# include +#endif +# include "stringheap.h" + + +static enum lxm_optimum_mode_e { + LXM_NONE = 0, + LXM_SPACE = 1, + LXM_SPEED = 2 +} lxm_optimum_mode = LXM_SPEED; + + +/* + * The lxt_scope head and current pointers are used to keep a scope + * stack that can be accessed from the bottom. The lxt_scope_head + * points to the first (bottom) item in the stack and + * lxt_scope_current points to the last (top) item in the stack. The + * push_scope and pop_scope methods manipulate the stack. + */ +struct lxt_scope +{ + struct lxt_scope *next, *prev; + char *name; + int len; +}; + +static struct lxt_scope *lxt_scope_head=NULL, *lxt_scope_current=NULL; + +static void push_scope(const char *name) +{ + struct lxt_scope *t = (struct lxt_scope *) + calloc(1, sizeof(struct lxt_scope)); + + t->name = strdup(name); + t->len = strlen(name); + + if(!lxt_scope_head) { + lxt_scope_head = lxt_scope_current = t; + } else { + lxt_scope_current->next = t; + t->prev = lxt_scope_current; + lxt_scope_current = t; + } +} + +static void pop_scope(void) +{ + struct lxt_scope *t; + + assert(lxt_scope_current); + + t=lxt_scope_current->prev; + free(lxt_scope_current->name); + free(lxt_scope_current); + lxt_scope_current = t; + if (lxt_scope_current) { + lxt_scope_current->next = 0; + } else { + lxt_scope_head = 0; + } +} + +/* + * This function uses the scope stack to generate a hierarchical + * name. Scan the scope stack from the bottom up to construct the + * name. + */ +static char *create_full_name(const char *name) +{ + char *n, *n2; + int len = 0; + struct lxt_scope *t = lxt_scope_head; + + /* Figure out how long the combined string will be. */ + while(t) { + len+=t->len+1; + t=t->next; + } + + len += strlen(name) + 1; + + /* Allocate a string buffer. */ + n = n2 = malloc(len); + + t = lxt_scope_head; + while(t) { + strcpy(n2, t->name); + n2 += t->len; + *n2 = '.'; + n2++; + t=t->next; + } + + strcpy(n2, name); + n2 += strlen(n2); + assert( (n2 - n + 1) == len ); + + return n; +} + + +static struct lxt2_wr_trace *dump_file = 0; + +struct vcd_info { + vpiHandle item; + vpiHandle cb; + struct t_vpi_time time; + struct lxt2_wr_symbol *sym; + struct vcd_info *next; + struct vcd_info *dmp_next; + int scheduled; +}; + + +static struct vcd_info*vcd_list = 0; +static struct vcd_info*vcd_dmp_list = 0; +static unsigned long vcd_cur_time = 0; +static int dump_is_off = 0; + + +static void show_this_item(struct vcd_info*info) +{ + s_vpi_value value; + + if (vpi_get(vpiType,info->item) == vpiRealVar) { + value.format = vpiRealVal; + vpi_get_value(info->item, &value); + lxt2_wr_emit_value_double(dump_file, info->sym, 0, + value.value.real); + + } else { + value.format = vpiBinStrVal; + vpi_get_value(info->item, &value); + lxt2_wr_emit_value_bit_string(dump_file, info->sym, + 0 /* array row */, + value.value.str); + } +} + + +static void show_this_item_x(struct vcd_info*info) +{ + if (vpi_get(vpiType,info->item) == vpiRealVar) { + /* Should write a NaN here? */ + } else { + lxt2_wr_emit_value_bit_string(dump_file, info->sym, 0, "x"); + } +} + + +/* + * managed qsorted list of scope names for duplicates bsearching + */ + +struct vcd_names_list_s lxt_tab; + + +static int dumpvars_status = 0; /* 0:fresh 1:cb installed, 2:callback done */ +static unsigned long dumpvars_time; +inline static int dump_header_pending(void) +{ + return dumpvars_status != 2; +} + +/* + * This function writes out all the traced variables, whether they + * changed or not. + */ +static void vcd_checkpoint() +{ + struct vcd_info*cur; + + for (cur = vcd_list ; cur ; cur = cur->next) + show_this_item(cur); +} + +static void vcd_checkpoint_x() +{ + struct vcd_info*cur; + + for (cur = vcd_list ; cur ; cur = cur->next) + show_this_item_x(cur); +} + +static int variable_cb_2(p_cb_data cause) +{ + struct vcd_info* info = vcd_dmp_list; + unsigned long now = cause->time->low; + + if (now != vcd_cur_time) { + lxt2_wr_set_time(dump_file, now); + vcd_cur_time = now; + } + + do { + show_this_item(info); + info->scheduled = 0; + } while ((info = info->dmp_next) != 0); + + vcd_dmp_list = 0; + + return 0; +} + +static int variable_cb_1(p_cb_data cause) +{ + struct t_cb_data cb; + struct vcd_info*info = (struct vcd_info*)cause->user_data; + + if (dump_is_off) return 0; + if (dump_header_pending()) return 0; + if (info->scheduled) return 0; + + if (!vcd_dmp_list) { + cb = *cause; + cb.reason = cbReadOnlySynch; + cb.cb_rtn = variable_cb_2; + vpi_register_cb(&cb); + } + + info->scheduled = 1; + info->dmp_next = vcd_dmp_list; + vcd_dmp_list = info; + + return 0; +} + +static int dumpvars_cb(p_cb_data cause) +{ + if (dumpvars_status != 1) + return 0; + + dumpvars_status = 2; + + dumpvars_time = cause->time->low; + vcd_cur_time = dumpvars_time; + + if (!dump_is_off) { + lxt2_wr_set_time(dump_file, dumpvars_time); + vcd_checkpoint(); + } + + return 0; +} + +inline static int install_dumpvars_callback(void) +{ + struct t_cb_data cb; + static struct t_vpi_time time; + + if (dumpvars_status == 1) + return 0; + + if (dumpvars_status == 2) { + vpi_mcd_printf(1, "VCD Error:" + " $dumpvars ignored," + " previously called at simtime %lu\n", + dumpvars_time); + return 1; + } + + time.type = vpiSimTime; + cb.time = &time; + cb.reason = cbReadOnlySynch; + cb.cb_rtn = dumpvars_cb; + cb.user_data = 0x0; + cb.obj = 0x0; + + vpi_register_cb(&cb); + + dumpvars_status = 1; + return 0; +} + +static int sys_dumpoff_calltf(char*name) +{ + s_vpi_time now; + + if (dump_is_off) + return 0; + + dump_is_off = 1; + + if (dump_file == 0) + return 0; + + if (dump_header_pending()) + return 0; + + now.type = vpiSimTime; + vpi_get_time(0, &now); + if (now.low > vcd_cur_time) + lxt2_wr_set_time(dump_file, now.low); + vcd_cur_time = now.low; + + lxt2_wr_set_dumpoff(dump_file); + vcd_checkpoint_x(); + + return 0; +} + +static int sys_dumpon_calltf(char*name) +{ + s_vpi_time now; + + if (!dump_is_off) + return 0; + + dump_is_off = 0; + + if (dump_file == 0) + return 0; + + if (dump_header_pending()) + return 0; + + now.type = vpiSimTime; + vpi_get_time(0, &now); + if (now.low > vcd_cur_time) + lxt2_wr_set_time(dump_file, now.low); + vcd_cur_time = now.low; + + lxt2_wr_set_dumpon(dump_file); + vcd_checkpoint(); + + return 0; +} + +static int sys_dumpall_calltf(char*name) +{ + s_vpi_time now; + + if (dump_file == 0) + return 0; + + if (dump_header_pending()) + return 0; + + now.type = vpiSimTime; + vpi_get_time(0, &now); + if (now.low > vcd_cur_time) + lxt2_wr_set_time(dump_file, now.low); + vcd_cur_time = now.low; + + vcd_checkpoint(); + + return 0; +} + +static void *close_dumpfile(void) +{ + lxt2_wr_close(dump_file); + dump_file = 0; + return 0; +} + +static void open_dumpfile(const char*path) +{ + dump_file = lxt2_wr_init(path); + + if (dump_file == 0) { + vpi_mcd_printf(1, + "LXT Error: Unable to open %s for output.\n", + path); + return; + } else { + int prec = vpi_get(vpiTimePrecision, 0); + + vpi_mcd_printf(1, + "LXT info: dumpfile %s opened for output.\n", + path); + + assert(prec >= -15); + lxt2_wr_set_timescale(dump_file, prec); + + lxt2_wr_set_initial_value(dump_file, 'x'); + lxt2_wr_set_compression_depth(dump_file, 4); + + atexit((void(*)(void))close_dumpfile); + } +} + +static int sys_dumpfile_calltf(char*name) +{ + char*path; + + vpiHandle sys = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, sys); + vpiHandle item; + + if (argv && (item = vpi_scan(argv))) { + s_vpi_value value; + + if (vpi_get(vpiType, item) != vpiConstant + || vpi_get(vpiConstType, item) != vpiStringConst) { + vpi_mcd_printf(1, + "LXT Error:" + " %s parameter must be a string constant\n", + name); + return 0; + } + + value.format = vpiStringVal; + vpi_get_value(item, &value); + path = strdup(value.value.str); + + vpi_free_object(argv); + + } else { + path = strdup("dumpfile.lxt"); + } + + if (dump_file) + close_dumpfile(); + + assert(dump_file == 0); + open_dumpfile(path); + + free(path); + + return 0; +} + +static void scan_item(unsigned depth, vpiHandle item, int skip) +{ + struct t_cb_data cb; + struct vcd_info* info; + + const char* type; + const char* name; + const char* ident; + int nexus_id; + + /* list of types to iterate upon */ + int i; + static int types[] = { + /* Value */ + vpiNet, + vpiReg, + vpiVariables, + /* Scope */ + vpiFunction, + vpiModule, + vpiNamedBegin, + vpiNamedFork, + vpiTask, + -1 + }; + + switch (vpi_get(vpiType, item)) { + + case vpiMemory: + /* don't know how to watch memories. */ + break; + + case vpiNamedEvent: + /* There is nothing in named events to dump. */ + break; + + case vpiNet: type = "wire"; if(0){ + case vpiIntegerVar: + case vpiTimeVar: + case vpiReg: type = "reg"; } + + if (skip) + break; + + name = vpi_get_str(vpiName, item); + nexus_id = vpi_get(_vpiNexusId, item); + if (nexus_id) { + ident = find_nexus_ident(nexus_id); + } else { + ident = 0; + } + + if (!ident) { + char*tmp = create_full_name(name); + ident = strdup_sh(&name_heap, tmp); + free(tmp); + + if (nexus_id) + set_nexus_ident(nexus_id, ident); + + info = malloc(sizeof(*info)); + + info->time.type = vpiSimTime; + info->item = item; + info->sym = lxt2_wr_symbol_add(dump_file, ident, + 0 /* array rows */, + vpi_get(vpiLeftRange, item), + vpi_get(vpiRightRange, item), + LXT2_WR_SYM_F_BITS); + info->scheduled = 0; + + cb.time = &info->time; + cb.user_data = (char*)info; + cb.value = NULL; + cb.obj = item; + cb.reason = cbValueChange; + cb.cb_rtn = variable_cb_1; + + info->next = vcd_list; + vcd_list = info; + + info->cb = vpi_register_cb(&cb); + + } else { + char *n = create_full_name(name); + lxt2_wr_symbol_alias(dump_file, ident, n, + vpi_get(vpiSize, item)-1, 0); + free(n); + } + + break; + + case vpiRealVar: + + if (skip) + break; + + name = vpi_get_str(vpiName, item); + { char*tmp = create_full_name(name); + ident = strdup_sh(&name_heap, tmp); + free(tmp); + } + info = malloc(sizeof(*info)); + + info->time.type = vpiSimTime; + info->item = item; + info->sym = lxt2_wr_symbol_add(dump_file, ident, + 0 /* array rows */, + vpi_get(vpiSize, item)-1, + 0, LXT2_WR_SYM_F_DOUBLE); + info->scheduled = 0; + + cb.time = &info->time; + cb.user_data = (char*)info; + cb.value = NULL; + cb.obj = item; + cb.reason = cbValueChange; + cb.cb_rtn = variable_cb_1; + + info->next = vcd_list; + vcd_list = info; + + info->cb = vpi_register_cb(&cb); + + break; + + case vpiModule: type = "module"; if(0){ + case vpiNamedBegin: type = "begin"; }if(0){ + case vpiTask: type = "task"; }if(0){ + case vpiFunction: type = "function"; }if(0){ + case vpiNamedFork: type = "fork"; } + + if (depth > 0) { + int nskip; + vpiHandle argv; + + const char* fullname = + vpi_get_str(vpiFullName, item); + +#if 0 + vpi_mcd_printf(1, + "LXT info:" + " scanning scope %s, %u levels\n", + fullname, depth); +#endif + nskip = 0 != vcd_names_search(&lxt_tab, fullname); + + if (!nskip) + vcd_names_add(&lxt_tab, fullname); + else + vpi_mcd_printf(1, + "LXT warning:" + " ignoring signals" + " in previously scanned scope %s\n", + fullname); + + name = vpi_get_str(vpiName, item); + + push_scope(name); /* keep in type info determination for possible future usage */ + + for (i=0; types[i]>0; i++) { + vpiHandle hand; + argv = vpi_iterate(types[i], item); + while (argv && (hand = vpi_scan(argv))) { + scan_item(depth-1, hand, nskip); + } + } + + pop_scope(); + } + break; + + default: + vpi_mcd_printf(1, + "LXT Error: $lxtdumpvars: Unsupported parameter " + "type (%d)\n", vpi_get(vpiType, item)); + } + +} + +static int draw_scope(vpiHandle item) +{ + int depth; + const char *name; + char *type; + + vpiHandle scope = vpi_handle(vpiScope, item); + if (!scope) + return 0; + + depth = 1 + draw_scope(scope); + name = vpi_get_str(vpiName, scope); + + switch (vpi_get(vpiType, item)) { + case vpiNamedBegin: type = "begin"; break; + case vpiTask: type = "task"; break; + case vpiFunction: type = "function"; break; + case vpiNamedFork: type = "fork"; break; + default: type = "module"; break; + } + + push_scope(name); /* keep in type info determination for possible future usage */ + + return depth; +} + +static int sys_dumpvars_calltf(char*name) +{ + unsigned depth; + s_vpi_value value; + vpiHandle item = 0; + vpiHandle sys = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv; + + if (dump_file == 0) { + open_dumpfile("dumpfile.lxt"); + if (dump_file == 0) + return 0; + } + + if (install_dumpvars_callback()) { + return 0; + } + + argv = vpi_iterate(vpiArgument, sys); + + depth = 0; + if (argv && (item = vpi_scan(argv))) + switch (vpi_get(vpiType, item)) { + case vpiConstant: + case vpiNet: + case vpiIntegerVar: + case vpiReg: + case vpiMemoryWord: + value.format = vpiIntVal; + vpi_get_value(item, &value); + depth = value.value.integer; + break; + } + + if (!depth) + depth = 10000; + + if (!argv) { + // $dumpvars; + // search for the toplevel module + vpiHandle parent = vpi_handle(vpiScope, sys); + while (parent) { + item = parent; + parent = vpi_handle(vpiScope, item); + } + + } else if (!item || !(item = vpi_scan(argv))) { + // $dumpvars(level); + // $dumpvars(); + // dump the current scope + item = vpi_handle(vpiScope, sys); + argv = 0x0; + } + + for ( ; item; item = argv ? vpi_scan(argv) : 0x0) { + + int dep = draw_scope(item); + + vcd_names_sort(&lxt_tab); + scan_item(depth, item, 0); + + while (dep--) { + pop_scope(); + } + } + + /* Most effective compression. */ + if (lxm_optimum_mode == LXM_SPACE) + lxt2_wr_set_compression_depth(dump_file, 9); + + return 0; +} + +void sys_lxt2_register() +{ + int idx; + struct t_vpi_vlog_info vlog_info; + s_vpi_systf_data tf_data; + + + /* Scan the extended arguments, looking for lxt optimization + flags. */ + vpi_get_vlog_info(&vlog_info); + + for (idx = 0 ; idx < vlog_info.argc ; idx += 1) { + if (strcmp(vlog_info.argv[idx],"-lxt-space") == 0) { + lxm_optimum_mode = LXM_SPACE; + + } else if (strcmp(vlog_info.argv[idx],"-lxt-speed") == 0) { + lxm_optimum_mode = LXM_SPEED; + + } + } + + tf_data.type = vpiSysTask; + tf_data.tfname = "$dumpall"; + tf_data.calltf = sys_dumpall_calltf; + tf_data.compiletf = 0; + tf_data.sizetf = 0; + tf_data.user_data = "$dumpall"; + vpi_register_systf(&tf_data); + + tf_data.type = vpiSysTask; + tf_data.tfname = "$dumpoff"; + tf_data.calltf = sys_dumpoff_calltf; + tf_data.compiletf = 0; + tf_data.sizetf = 0; + tf_data.user_data = "$dumpoff"; + vpi_register_systf(&tf_data); + + tf_data.type = vpiSysTask; + tf_data.tfname = "$dumpon"; + tf_data.calltf = sys_dumpon_calltf; + tf_data.compiletf = 0; + tf_data.sizetf = 0; + tf_data.user_data = "$dumpon"; + vpi_register_systf(&tf_data); + + tf_data.type = vpiSysTask; + tf_data.tfname = "$dumpfile"; + tf_data.calltf = sys_dumpfile_calltf; + tf_data.compiletf = 0; + tf_data.sizetf = 0; + tf_data.user_data = "$dumpfile"; + vpi_register_systf(&tf_data); + + tf_data.type = vpiSysTask; + tf_data.tfname = "$dumpvars"; + tf_data.calltf = sys_dumpvars_calltf; + tf_data.compiletf = sys_vcd_dumpvars_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$dumpvars"; + vpi_register_systf(&tf_data); +} + +/* + * $Log: sys_lxt2.c,v $ + * Revision 1.1 2003/09/01 04:04:03 steve + * Add lxt2 support. + * + * Revision 1.22 2003/08/22 23:14:27 steve + * Preserve variable ranges all the way to the vpi. + * + * Revision 1.21 2003/05/15 16:51:09 steve + * Arrange for mcd id=00_00_00_01 to go to stdout + * as well as a user specified log file, set log + * file to buffer lines. + * + * Add vpi_flush function, and clear up some cunfused + * return codes from other vpi functions. + * + * Adjust $display and vcd/lxt messages to use the + * standard output/log file. + */ diff --git a/vpi/sys_table.c b/vpi/sys_table.c index a1350cb01..d45ca6c60 100644 --- a/vpi/sys_table.c +++ b/vpi/sys_table.c @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: sys_table.c,v 1.20 2003/03/07 02:44:34 steve Exp $" +#ident "$Id: sys_table.c,v 1.21 2003/09/01 04:04:03 steve Exp $" #endif # include "config.h" @@ -36,6 +36,7 @@ extern void sys_readmem_register(); extern void sys_time_register(); extern void sys_vcd_register(); extern void sys_lxt_register(); +extern void sys_lxt2_register(); extern void sys_vcdoff_register(); static void sys_lxt_or_vcd_register() @@ -76,6 +77,18 @@ static void sys_lxt_or_vcd_register() } else if (strcmp(vlog_info.argv[idx],"-lxt-none") == 0) { dumper = "none"; + } else if (strcmp(vlog_info.argv[idx],"-lxt2") == 0) { + dumper = "lxt2"; + + } else if (strcmp(vlog_info.argv[idx],"-lxt2-space") == 0) { + dumper = "lxt2"; + + } else if (strcmp(vlog_info.argv[idx],"-lxt2-speed") == 0) { + dumper = "lxt2"; + + } else if (strcmp(vlog_info.argv[idx],"-lxt2-none") == 0) { + dumper = "none"; + } else if (strcmp(vlog_info.argv[idx],"-vcd") == 0) { dumper = "vcd"; @@ -100,6 +113,12 @@ static void sys_lxt_or_vcd_register() else if (strcmp(dumper, "LXT") == 0) sys_lxt_register(); + else if (strcmp(dumper, "lxt2") == 0) + sys_lxt2_register(); + + else if (strcmp(dumper, "LXT2") == 0) + sys_lxt2_register(); + else if (strcmp(dumper, "none") == 0) sys_vcdoff_register(); @@ -129,6 +148,9 @@ void (*vlog_startup_routines[])() = { /* * $Log: sys_table.c,v $ + * Revision 1.21 2003/09/01 04:04:03 steve + * Add lxt2 support. + * * Revision 1.20 2003/03/07 02:44:34 steve * Implement $realtobits. *