Logo Search packages:      
Sourcecode: iverilog version File versions  Download package

lxt2_write.c

/*
 * Copyright (c) 2003-2007 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.
 */

#ifdef _AIX
#pragma alloca
#endif

#include <config.h>
#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);
                } 
        }
}


/*
 * in-place sort to keep chained facs from migrating...
 */
static void wave_mergesort(struct lxt2_wr_symbol **a, struct lxt2_wr_symbol **b, int lo, int hi)
{
int i, j, k;

if (lo<hi)
      {
        int mid=(lo+hi)/2;

        wave_mergesort(a, b, lo, mid);
        wave_mergesort(a, b, mid+1, hi);

      i=0; j=lo;
      while (j<=mid)
            {
            b[i++]=a[j++];
            }

      i=0; k=lo;
      while ((k<j)&&(j<=hi))
            {
            if (strcmp(b[i]->name, a[j]->name) <= 0)
                  {
                        a[k++]=b[i++];
                  }
                  else
                  {
                        a[k++]=a[j++];
                  }
            }

      while (k<j)
            {
            a[k++]=b[i++];
            }
      }
}

static void wave_msort(struct lxt2_wr_symbol **a, int num)
{
struct lxt2_wr_symbol **b = malloc(((num/2)+1) * sizeof(struct lxt2_wr_symbol *));

wave_mergesort(a, b, 0, num-1);

free(b);
}

/************************ splay ************************/

static lxt2_wr_ds_Tree * lxt2_wr_ds_splay (granmsk_t i, lxt2_wr_ds_Tree * t) {
/* Simple top down splay, not requiring i to be in the tree t.  */
/* What it does is described above.                             */
    lxt2_wr_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 lxt2_wr_ds_Tree * lxt2_wr_ds_insert(granmsk_t i, lxt2_wr_ds_Tree * t, int val) {
/* Insert i into the tree t, unless it's already there.    */
/* Return a pointer to the resulting tree.                 */
    lxt2_wr_ds_Tree * n;
    
    n = (lxt2_wr_ds_Tree *) calloc (1, sizeof (lxt2_wr_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 = lxt2_wr_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 lxt2_wr_dslxt_success;

static lxt2_wr_dslxt_Tree * lxt2_wr_dslxt_splay (char *i, lxt2_wr_dslxt_Tree * t) {
/* Simple top down splay, not requiring i to be in the tree t.  */
/* What it does is described above.                             */
    lxt2_wr_dslxt_Tree N, *l, *r, *y;
    int dir;

    lxt2_wr_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 {
          lxt2_wr_dslxt_success=1;
          break;
      }
    }
    l->right = t->left;                                /* assemble */
    r->left = t->right;
    t->left = N.right;
    t->right = N.left;
    return t;
}


static lxt2_wr_dslxt_Tree * lxt2_wr_dslxt_insert(char *i, lxt2_wr_dslxt_Tree * t, unsigned int val) {
/* Insert i into the tree t, unless it's already there.    */
/* Return a pointer to the resulting tree.                 */
    lxt2_wr_dslxt_Tree * n;
    int dir;
    
    n = (lxt2_wr_dslxt_Tree *) calloc (1, sizeof (lxt2_wr_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 = lxt2_wr_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 = (len<lt->compress_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;i<minlen;i++)
                {
                if(lt->compress_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 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=='.')
                {
                return; /* MTI SV [0.3] notation for implicit vars */
                }

      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;
      struct lxt2_wr_symbol **aliascache = calloc(lt->numalias ? lt->numalias : 1, sizeof(struct lxt2_wr_symbol *));
      int aliases_encountered, facs_encountered;

      lt->sorted_facs = (struct lxt2_wr_symbol **)calloc(lt->numfacs, sizeof(struct lxt2_wr_symbol *));

      if(lt->sorted_facs && aliascache)
            {
            if(lt->do_strip_brackets)
            for(i=0;i<lt->numfacs;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;i<lt->numfacs;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);

            if(lt->partial_preference)
                  {
                  /* move preferenced facs up */
                  struct lxt2_wr_symbol **prefcache = aliascache;
                  int prefs_encountered = 0; 

                  facs_encountered = 0;
                  for(i=0;i<lt->numfacs;i++)
                        {
                        if((lt->sorted_facs[i]->partial_preference)==0)
                              {
                              lt->sorted_facs[facs_encountered] = lt->sorted_facs[i];
                              facs_encountered++;
                              }
                              else
                              {
                              prefcache[prefs_encountered] = lt->sorted_facs[i];
                              prefs_encountered++;
                              }
                        }
                  /* then append the non-preferenced facs */
                  for(i=0;i<facs_encountered;i++)
                        {
                        prefcache[prefs_encountered+i] = lt->sorted_facs[i];
                        }

                  /* now make prefcache the main cache */
                  aliascache = lt->sorted_facs;
                  lt->sorted_facs = prefcache;
                  }

            /* move facs up */
            aliases_encountered = 0, facs_encountered = 0;
            for(i=0;i<lt->numfacs;i++)
                  {
                  if((lt->sorted_facs[i]->flags&LXT2_WR_SYM_F_ALIAS)==0)
                        {
                        lt->sorted_facs[facs_encountered] = lt->sorted_facs[i];
                        facs_encountered++;
                        }
                        else
                        {
                        aliascache[aliases_encountered] = lt->sorted_facs[i];
                        aliases_encountered++;
                        }
                  }
            /* then append the aliases */
            for(i=0;i<aliases_encountered;i++)
                  {
                  lt->sorted_facs[facs_encountered+i] = aliascache[i];
                  }


            for(i=0;i<lt->numfacs;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;i<lt->numfacs;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);
            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;i<lt->numfacs;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);
            fseeko(lt->handle, 0L, SEEK_END);
            lt->position=ftello(lt->handle);
            lt->break_header_size = lt->position;                 /* in case we need to emit multiple lxt2s with same header */
            lt->zfacgeometry_size = lt->position - lt->facgeometry_offset;

            fseeko(lt->handle, lt->facname_offset + 12, SEEK_SET);
            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);

            lt->numfacs = facs_encountered;                       /* don't process alias value changes ever */
            }

      if(aliascache) free(aliascache);
      }
}


/* 
 * initialize the trace and get back an 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((!name)||(!(lt->handle=fopen(name, "wb"))))
      {
      free(lt);
      lt=NULL;
      }
      else
      {
      lt->lxtname = strdup(name);

      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);
}


/*
 * setting break size
 */
void lxt2_wr_set_break_size(struct lxt2_wr_trace *lt, off_t siz)
{
if(lt)
      {
      lt->break_size = siz;
      }
}


/*
 * enable/disable partial dump mode (for faster reads)
 */
void lxt2_wr_set_partial_off(struct lxt2_wr_trace *lt)
{
if(lt)
      {
      lt->partial = 0;
      lt->partial_zip = 0;
      }
}

void lxt2_wr_set_partial_on(struct lxt2_wr_trace *lt, int zipmode)
{
if(lt)
      {
      lt->partial = 1;
      lt->partial_zip = (zipmode != 0);
      lt->partial_iter = LXT2_WR_PARTIAL_SIZE; 
      }
}

void lxt2_wr_set_partial_preference(struct lxt2_wr_trace *lt, const char *name)
{
struct lxt2_wr_symbol *s;
         
if((lt)&&(name)&&(!lt->sorted_facs)) 
      {
      s=lxt2_wr_symfind(lt, name);
      if(s)
            {
            while(s->aliased_to)    /* find root alias */
                    {
                    s=s->aliased_to;
                    }

            s->partial_preference = 1;
            }
      }
}


/*
 * enable/disable checkpointing (for smaller files)
 */
void lxt2_wr_set_checkpoint_off(struct lxt2_wr_trace *lt)
{
if(lt)
      {
      lt->no_checkpoint = 1;
      }
}

void lxt2_wr_set_checkpoint_on(struct lxt2_wr_trace *lt)
{
if(lt)
      {
      lt->no_checkpoint = 0;
      }
}


/*
 * 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 = (msb<lsb) ? (lsb-msb+1) : (msb-lsb+1);
      }

if(flags&LXT2_WR_SYM_F_DOUBLE)
      {
      s->value = 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 = (msb<lsb) ? (lsb-msb+1) : (msb-lsb+1);
if((!flagcnt)&&(bitlen!=s->len)) 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++;
lt->numalias++;
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));
}


/*
 * file size limiting/header cloning...
 */
static void lxt2_wr_emit_do_breakfile(struct lxt2_wr_trace *lt)
{
unsigned int len = strlen(lt->lxtname);
int i;
char *tname = malloc(len + 30);
FILE *f2, *clone;
off_t cnt, seg;
char buf[32768];

for(i=len;i>0;i--)
      {
      if(lt->lxtname[i]=='.') break;
      }

if(!i)
      {
      sprintf(tname, "%s_%03d.lxt", lt->lxtname, ++lt->break_number);
      }
      else
      {
      memcpy(tname, lt->lxtname, i);
      sprintf(tname+i, "_%03d.lxt", ++lt->break_number);
      }

f2 = fopen(tname, "wb");
if(!f2)     /* if error, keep writing to same output file...sorry */
      {
      free(tname);
      return;
      }

clone = fopen(lt->lxtname, "rb");
if(!clone)
      { /* this should never happen */
      fclose(f2);
      unlink(tname);
      free(tname);
      return;
      }

/* clone original header */
for(cnt = 0; cnt < lt->break_header_size; cnt += sizeof(buf))
      {
      seg = lt->break_header_size - cnt;
      if(seg > sizeof(buf))
            {
            seg = sizeof(buf);
            }

      if(fread(buf, seg, 1, clone))
            {
            if(!fwrite(buf, seg, 1, f2)) break; /* write error! */
            }
      }

fclose(clone);
fclose(lt->handle);
lt->handle = f2;
free(tname);
}


/*
 * emit granule
 */
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;
unsigned int partial_iter;
unsigned int iter, iter_hi;
unsigned char using_partial, using_partial_zip=0;
off_t current_iter_pos=0;
int early_flush;

if(lt->flush_valid)
      {
      if(lt->flushtime == lt->lasttime)
            {
            return;
            }

      lt->flush_valid = 0;
      }

lt->granule_dirty = 0;

if((using_partial=(lt->partial)&&(lt->numfacs>lt->partial_iter)))
      {
      partial_iter = lt->partial_iter;
      using_partial_zip = lt->partial_zip;
      }
      else
      {
      partial_iter = lt->numfacs;
      }

if(!lt->timegranule)
      {
      int attempt_break_state = 2;

      do    {
            fseeko(lt->handle, 0L, SEEK_END);
            lt->current_chunk=lt->position = ftello(lt->handle);

            if((lt->break_size)&&(attempt_break_state==2)&&(lt->position >= lt->break_size)&&(lt->position != lt->break_header_size))
                  {
                  lxt2_wr_emit_do_breakfile(lt);
                  attempt_break_state--;
                  }
                  else
                  {
                  attempt_break_state = 0;
                  }
            } while(attempt_break_state);

      /* 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); */

      if(!using_partial_zip)
            {
            lt->zhandle = gzdopen(dup(fileno(lt->handle)), lt->zmode);
            }
            else
            {
            lt->zpackcount_cumulative = 0;
            }
      lt->zpackcount = 0;
      }



for(iter=0; iter<lt->numfacs; iter=iter_hi)
{
unsigned int total_chgs;
unsigned int partial_length;

total_chgs = 0;
partial_length = 0;

iter_hi = iter + partial_iter;
if(iter_hi > lt->numfacs) iter_hi = lt->numfacs;

for(j=iter;j<iter_hi;j++)
      {
      granmsk_t msk = lt->sorted_facs[j]->msk;

      lt->mapdict = lxt2_wr_ds_splay (msk, lt->mapdict);
      if((!lt->mapdict)||(lt->mapdict->item != msk))
            {
            lt->mapdict = lxt2_wr_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; }

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; }

if(using_partial)
      {
      /* skip */
      partial_length = 1 +                /* lt->timepos */
      lt->timepos * sizeof(lxttime_t)+    /* timevals */

      1 +                           /* map_nbytes */
      (iter_hi-iter) * map_nbytes +       /* actual map */
      1;                            /* idx_nbytes */

      for(j=iter;j<iter_hi;j++)
            {
              s=lt->sorted_facs[j];
            total_chgs += s->chgpos;
            }
      total_chgs *= idx_nbytes;           /* vch skip */

      partial_length += total_chgs;             /* actual changes */

      if(using_partial_zip)
            {
            fseeko(lt->handle, 0L, SEEK_END);
            current_iter_pos = ftello(lt->handle);
            lxt2_wr_emit_u32(lt, 0);            /* size of this section (compressed)   */
            lxt2_wr_emit_u32(lt, partial_length+9);   /* size of this section (uncompressed) */
            lxt2_wr_emit_u32(lt, iter);         /* begin iter of section               */
            fflush(lt->handle);
      
            lt->zhandle = gzdopen(dup(fileno(lt->handle)), lt->zmode);
            lt->zpackcount = 0;
            }

      lxt2_wr_emit_u8z(lt, LXT2_WR_GRAN_SECT_TIME_PARTIAL);
      lxt2_wr_emit_u32z(lt, iter);
      lxt2_wr_emit_u32z(lt, partial_length);
      }
      else
      {
      lxt2_wr_emit_u8z(lt, LXT2_WR_GRAN_SECT_TIME);
      }

lxt2_wr_emit_u8z(lt, lt->timepos);
for(i=0;i<lt->timepos;i++)
      {
      lxt2_wr_emit_u64z(lt, (lt->timetable[i]>>32)&0xffffffff, lt->timetable[i]&0xffffffff);
      }
gzflush_buffered(lt, 0);


lxt2_wr_emit_u8z(lt, map_nbytes);
for(j=iter;j<iter_hi;j++)
      {
      unsigned int val;
        s=lt->sorted_facs[j];
      lt->mapdict = lxt2_wr_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;
      }


lxt2_wr_emit_u8z(lt, idx_nbytes);
gzflush_buffered(lt, 0);
for(j=iter;j<iter_hi;j++)
      {
        s=lt->sorted_facs[j];

      for(i=0;i<s->chgpos;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;
      }

if(using_partial_zip)
      {
      off_t clen;

      gzflush_buffered(lt, 1);
      fseeko(lt->handle, 0L, SEEK_END);
      lt->position=ftello(lt->handle);

      clen = lt->position - current_iter_pos - 12;
      fseeko(lt->handle, current_iter_pos, SEEK_SET);

      lt->zpackcount_cumulative+=lt->zpackcount;

      lxt2_wr_emit_u32(lt, clen);
      }
      else
      {
      gzflush_buffered(lt, 0);
      }
} /* ...for(iter) */


lt->timepos = 0;
lt->timegranule++;

if(lt->break_size)
      {
      early_flush = (ftello(lt->handle) >= lt->break_size);
      }
      else
      {
      early_flush = 0;
      }

if((lt->timegranule>=lt->maxgranule)||(do_finalize)||(early_flush))
      {
      off_t unclen, clen;
      lxt2_wr_ds_Tree *dt, *dt2;
      lxt2_wr_dslxt_Tree *ds, *ds2;

      if(using_partial_zip)
            {
            fseeko(lt->handle, 0L, SEEK_END);
            current_iter_pos = ftello(lt->handle);
            lxt2_wr_emit_u32(lt, 0);            /* size of this section (compressed)   */
            lxt2_wr_emit_u32(lt, 0);            /* size of this section (uncompressed) */
            lxt2_wr_emit_u32(lt, ~0);           /* control section                   */
            fflush(lt->handle);
      
            lt->zhandle = gzdopen(dup(fileno(lt->handle)), lt->zmode);
            lt->zpackcount = 0;
            }

      /* 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;i<lt->num_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;i<lt->num_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"); */

      if(using_partial_zip)
            {
            off_t clen;
      
            gzflush_buffered(lt, 1);
            fseeko(lt->handle, 0L, SEEK_END);
            lt->position=ftello(lt->handle);
      
            clen = lt->position - current_iter_pos - 12;
            fseeko(lt->handle, current_iter_pos, SEEK_SET);

            lt->zpackcount_cumulative+=lt->zpackcount;
            lxt2_wr_emit_u32(lt, clen);
            lxt2_wr_emit_u32(lt, lt->zpackcount);
            }
            else
            {
            gzflush_buffered(lt, 1);
            }

        fseeko(lt->handle, 0L, SEEK_END);
        lt->position=ftello(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); */

      fseeko(lt->handle, lt->current_chunk, SEEK_SET);
      if(using_partial_zip)
            {
            lxt2_wr_emit_u32(lt, lt->zpackcount_cumulative);
            lxt2_wr_emit_u32(lt, clen);
            }
            else
            {
            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: %lld, end %lld\n", lt->firsttime, lt->lasttime); */

      lt->timegranule=0;
      lt->numblock++;
      }

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) )
            {
            lt->firsttime = timeval;
            lt->lasttime = timeval;
            }

      if( (!lt->timepos) && (!lt->timegranule) && ((!lt->numblock)||(!lt->no_checkpoint)) )
              {
              struct lxt2_wr_symbol *s = lt->symchain;

            /* 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 = 0;
      
                                    sscanf(s->value, "%lg", &value);
                                    errno = 0;
                                    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;i<=len;i++)
      {
      *(p++) = '0' | ((value & (1<<(len-i)))!=0);
      }
*p = 0;

return(s);
}


int lxt2_wr_emit_value_int(struct lxt2_wr_trace *lt, struct lxt2_wr_symbol *s, unsigned int row, int value)
{
int rc=0;

if((!lt)||(lt->blackout)||(!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 = lxt2_wr_dslxt_splay (s->value, lt->dict);

      if(!lxt2_wr_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 = lxt2_wr_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<<lt->timepos)) == LXT2_WR_GRAN_0VAL)
            {
            s->msk |= (LXT2_WR_GRAN_1VAL<<lt->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 = lxt2_wr_dslxt_splay (s->value, lt->dict);

      if(!lxt2_wr_dslxt_success)
            {
            unsigned int vlen = strlen(value)+1;
            char *vcopy = (char *)malloc(vlen);
            strcpy(vcopy, value);
            lt->dict_string_mem_required += vlen;
            lt->dict = lxt2_wr_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<<lt->timepos)) == LXT2_WR_GRAN_0VAL)
            {
            s->msk |= (LXT2_WR_GRAN_1VAL<<lt->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 = wave_alloca(s->len+1);
      strcpy(vfix, value);
      value = vfix;
      }
      else
      {
      vfix = wave_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;i<s->len;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;i<s->len;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;i<s->len;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 = lxt2_wr_dslxt_splay (vpnt, lt->dict);

            if(!lxt2_wr_dslxt_success)
                  {
                  unsigned int vlen = strlen(vpnt)+1;
                  char *vcopy = (char *)malloc(vlen);
                  strcpy(vcopy, vpnt);
                  lt->dict_string_mem_required += vlen;
                  lt->dict = lxt2_wr_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<<lt->timepos)) == LXT2_WR_GRAN_0VAL)
            {
            s->msk |= (LXT2_WR_GRAN_1VAL<<lt->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->flags&LXT2_WR_SYM_F_ALIAS))
                  {
                  if((s->msk & (LXT2_WR_GRAN_1VAL<<lt->timepos)) == LXT2_WR_GRAN_0VAL)
                        {
                        s->msk |= (LXT2_WR_GRAN_1VAL<<lt->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_ALIAS))
                  {
                  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;i<s->len;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->lxtname);
      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);
      }
}

Generated by  Doxygen 1.6.0   Back to index