// Support for FST files in CppSim with Verilator
// written by Michael H Perrott (March 2010)
// This code leveraged the verilated_vcd_c.cpp code
// written by Wilson Snyder (see below)
// Essentially, this code hijacks the VCD support of Verilator
// No warranty or support is provided for this code
/*
 * 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.
 */


// -*- SystemC -*-
//=============================================================================
//
// THIS MODULE IS PUBLICLY LICENSED
//
// Copyright 2001-2010 by Wilson Snyder.  This program is free software;
// you can redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License Version 2.0.
//
// This 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.
//
//=============================================================================
///
/// \file
/// \brief C++ Tracing in VCD Format
///
/// AUTHOR:  Wilson Snyder
///
//=============================================================================
// SPDIFF_OFF

#include "verilatedos.h"
#include "verilated.h"
#include "verilated_vcd_c.h"
#include "fst/fstapi.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cerrno>
#include <ctime>
#include <algorithm>

#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
# include <io.h>
#else
# include <unistd.h>
#endif

// SPDIFF_ON

#ifndef O_LARGEFILE // For example on WIN32
# define O_LARGEFILE 0
#endif
#ifndef O_NONBLOCK
# define O_NONBLOCK 0
#endif


// CREATORS
VerilatedVcd::VerilatedVcd () {
   first_fst_symbol = NULL;
   current_fst_symbol = NULL;
}

VerilatedVcd::~VerilatedVcd() {
FST_SYMBOL_INFO *cur_fst_symbol,*next_fst_symbol;
cur_fst_symbol = first_fst_symbol;
while (cur_fst_symbol != NULL)
   {
    next_fst_symbol = cur_fst_symbol->next;
    free(cur_fst_symbol);
    cur_fst_symbol = next_fst_symbol;
   }
}

void VerilatedVcd::scopeEscape(char flag) {}

void VerilatedVcd::module (string name) {
    m_modName = name;
}

void VerilatedVcd::declBit      (vluint32_t code, const char* name, int arraynum)
       {
	 declare_fst_symbol_bits(name,(int) code, 0, 0, arraynum);
       }
void VerilatedVcd::declBus      (vluint32_t code, const char* name, int arraynum, int msb, int lsb)
       {
	 declare_fst_symbol_bits(name,(int) code, msb, lsb, arraynum);
       }
void VerilatedVcd::declQuad     (vluint32_t code, const char* name, int arraynum, int msb, int lsb)
       {
	 declare_fst_symbol_bits(name,(int) code, msb, lsb, arraynum);
       }
void VerilatedVcd::declArray    (vluint32_t code, const char* name, int arraynum, int msb, int lsb)
       {
	 declare_fst_symbol_bits(name,(int) code, msb, lsb, arraynum);
       }
void VerilatedVcd::declTriBit   (vluint32_t code, const char* name, int arraynum)
       {
	 declare_fst_symbol_bits(name,(int) code, 0, 0, arraynum);
       }
void VerilatedVcd::declTriBus   (vluint32_t code, const char* name, int arraynum, int msb, int lsb)
       {
	 declare_fst_symbol_bits(name,(int) code, msb, lsb, arraynum);
       }
void VerilatedVcd::declTriQuad   (vluint32_t code, const char* name, int arraynum, int msb, int lsb)
       {
	 declare_fst_symbol_bits(name,(int) code, msb, lsb, arraynum);
       }
void VerilatedVcd::declTriArray (vluint32_t code, const char* name, int arraynum, int msb, int lsb)
       {
	 declare_fst_symbol_bits(name,(int) code, msb, lsb, arraynum);
       }
void VerilatedVcd::declDouble   (vluint32_t code, const char* name, int arraynum)
       {
	 declare_fst_symbol_dbl(name,(int) code, arraynum);
       }
void VerilatedVcd::declFloat   (vluint32_t code, const char* name, int arraynum)
       {
	 declare_fst_symbol_dbl(name,(int) code, arraynum);
       }


    /// Inside dumping routines, dump one signal
void VerilatedVcd::fullBit (vluint32_t code, const vluint32_t newval) {
        FST_SYMBOL_INFO *cur_fst_symbol = find_fst_symbol((int) code);
        cur_fst_symbol->value_string[0] = ('0'+(char)(newval&1));
    }
void VerilatedVcd::fullBus (vluint32_t code, const vluint32_t newval, int bits) {
        FST_SYMBOL_INFO *cur_fst_symbol = find_fst_symbol((int) code);
        int i;
	for (int bit=bits-1, i = 0; bit>=0; --bit, i++) {
	    cur_fst_symbol->value_string[i]=((newval&(1L<<bit))?'1':'0');
	}
    }
void VerilatedVcd::fullQuad (vluint32_t code, const vluint64_t newval, int bits) {
        FST_SYMBOL_INFO *cur_fst_symbol = find_fst_symbol((int) code);
        int i;
	for (int bit=bits-1,i=0; bit>=0; --bit,i++) {
	    cur_fst_symbol->value_string[i]=((newval&(1ULL<<bit))?'1':'0');
	}
    }
void VerilatedVcd::fullArray (vluint32_t code, const vluint32_t* newval, int bits) {
        FST_SYMBOL_INFO *cur_fst_symbol = find_fst_symbol((int) code);
        int i;
	for (int bit=bits-1,i = 0; bit>=0; --bit,i++) {
	    cur_fst_symbol->value_string[i]=((newval[(bit/32)]&(1L<<(bit&0x1f)))?'1':'0');
	}
    }
void VerilatedVcd::fullTriBit (vluint32_t code, const vluint32_t newval, const vluint32_t newtri) {
        FST_SYMBOL_INFO *cur_fst_symbol = find_fst_symbol((int) code);
	cur_fst_symbol->value_string[0] = "01zz"[newval | (newtri<<1)];
    }
void VerilatedVcd::fullTriBus (vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits) {
        FST_SYMBOL_INFO *cur_fst_symbol = find_fst_symbol((int) code);
	int i;
	for (int bit=bits-1,i=0; bit>=0; --bit,i++) {
	    cur_fst_symbol->value_string[i] = "01zz"[((newval >> bit)&1)
				 | (((newtri >> bit)&1)<<1)];
	}
    }
void VerilatedVcd::fullTriQuad (vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits) {
        FST_SYMBOL_INFO *cur_fst_symbol = find_fst_symbol((int) code);
	int i;
	for (int bit=bits-1,i=0; bit>=0; --bit,i++) {
	    cur_fst_symbol->value_string[i] = "01zz"[((newval >> bit)&1ULL)
				 | (((newtri >> bit)&1ULL)<<1ULL)];
	}
    }
void VerilatedVcd::fullTriArray (vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, int bits) {
        FST_SYMBOL_INFO *cur_fst_symbol = find_fst_symbol((int) code);
	int i;
	for (int bit=bits-1,i=0; bit>=0; --bit,i++) {
	    vluint32_t valbit = (newvalp[(bit/32)]>>(bit&0x1f)) & 1;
	    vluint32_t tribit = (newtrip[(bit/32)]>>(bit&0x1f)) & 1;
	    cur_fst_symbol->value_string[i] = "01zz"[valbit | (tribit<<1)];
	}
    }
void VerilatedVcd::fullDouble (vluint32_t code, const double newval)
       {
        FST_SYMBOL_INFO *cur_fst_symbol = find_fst_symbol((int) code);
	cur_fst_symbol->value_dbl = newval;
       }
void VerilatedVcd::fullFloat (vluint32_t code, const float newval)
       {
        FST_SYMBOL_INFO *cur_fst_symbol = find_fst_symbol((int) code);
	cur_fst_symbol->value_dbl = (double) newval;
       }

    /// Inside dumping routines, dump one signal as unknowns
    /// Presently this code doesn't change the oldval vector.
    /// Thus this is for special standalone applications that after calling
    /// fullBitX, must when then value goes non-X call fullBit.
void VerilatedVcd::fullBitX (vluint32_t code) {
        FST_SYMBOL_INFO *cur_fst_symbol = find_fst_symbol((int) code);
	cur_fst_symbol->value_string[0] = 'x';
    }
void VerilatedVcd::fullBusX (vluint32_t code, int bits) {
        FST_SYMBOL_INFO *cur_fst_symbol = find_fst_symbol((int) code);
	int i;
	for (i = 0; i < bits; i++)
	   cur_fst_symbol->value_string[i] = 'x';
    }
void VerilatedVcd::fullQuadX (vluint32_t code, int bits) { fullBusX (code, bits); }
void VerilatedVcd::fullArrayX (vluint32_t code, int bits) { fullBusX (code, bits); }

void VerilatedVcd::add_fst_symbol_name(const char *name, FST_SYMBOL_INFO *fst_symbol)
  {
    FST_SYMBOL_NAME_INFO *cur_name,*prev_name;

    if (fst_symbol == NULL)
      {
	printf("error in 'add_fst_symbol_name':  fst_symbol is NULL!\n");
	printf("  -> this should never happen! ??\n");
	exit(1);
      }

    if (fst_symbol->first_name == NULL)
      {
       fst_symbol->first_name = init_fst_symbol_name_info(name);
      }
    else
      {
	cur_name = fst_symbol->first_name;
	while (cur_name != NULL)
	  {
	    if (strcmp(cur_name->name,name) == 0)
	      break;
	    prev_name = cur_name;
	    cur_name = cur_name->next;
	  }
	if (cur_name == NULL)
           prev_name->next = init_fst_symbol_name_info(name);
      }
  }

FST_SYMBOL_NAME_INFO *VerilatedVcd::init_fst_symbol_name_info(const char *name)
{
FST_SYMBOL_NAME_INFO *A;

if ((A = (FST_SYMBOL_NAME_INFO *) malloc(sizeof(FST_SYMBOL_NAME_INFO))) == NULL)
   {   
   printf("error in 'init_fst_symbol_name_info':  malloc call failed\n");   
   printf("out of memory!\n");   
   exit(1);   
  }   
strncpy(A->name,name,MAX_NODE_NAME_LENGTH_FST-1);
A->next = NULL;
return(A);
}

FST_SYMBOL_FILE_INFO_PROBES *init_verilator_fst_probe_symbol(fstHandle s, FST_SYMBOL_INFO *s_info,
                                                              const char *name)
{
FST_SYMBOL_FILE_INFO_PROBES *A;

if ((A = (FST_SYMBOL_FILE_INFO_PROBES *) malloc(sizeof(FST_SYMBOL_FILE_INFO_PROBES))) == NULL)
   {   
   printf("error in 'init_verilator_fst_probe_symbol':  malloc call failed\n");   
   printf("out of memory!\n");   
   exit(1);   
  }
/******
if (s == NULL)
   {
   printf("error in 'init_verilator_fst_probe_symbol':  s is NULL!\n");  
   printf(" -> this should never happen!\n");
   exit(1);
   }   
if (s_info == NULL)
   {
   printf("error in 'init_verilator_fst_probe_symbol':  s_info is NULL!\n");  
   printf(" -> this should never happen!\n");
   exit(1);
   }   
*******/
strncpy(A->name,name,MAX_NODE_NAME_LENGTH_FST-1);
A->s = s;
A->s_info = s_info;
A->next = NULL;
return(A);
}


FST_SYMBOL_FILE_INFO *VerilatedVcd::init_fst_symbol_file_info(void *lt, fstHandle s,
                        FST_SYMBOL_INFO *s_info, FST_SYMBOL_FILE_INFO_PROBES *first_master_file_probe,
                        const char *name)
{
FST_SYMBOL_FILE_INFO *A;
FST_SYMBOL_FILE_INFO_PROBES *cur_master_file_probe;

if ((A = (FST_SYMBOL_FILE_INFO *) malloc(sizeof(FST_SYMBOL_FILE_INFO))) == NULL)
   {   
   printf("error in 'init_fst_symbol_file_info':  malloc call failed\n");   
   printf("out of memory!\n");   
   exit(1);   
  }   
A->lt = lt;
A->first_probe_symbol = init_verilator_fst_probe_symbol(s,s_info,name);
A->next = NULL;

if (first_master_file_probe == NULL)
   {
     printf("error in 'VerilatedVcd::init_fst_symbol_file_info':\n");
     printf("   first_master_file_probe is NULL!\n");
     printf("   -> this should never happen! ??\n");
     exit(1);
   }
if (first_master_file_probe->s == 0)
  {
    first_master_file_probe->s = s;
    first_master_file_probe->s_info = s_info;
  }
else
  {
    cur_master_file_probe = first_master_file_probe;
    while (cur_master_file_probe->next != NULL)
      {
	cur_master_file_probe = cur_master_file_probe->next;
      }
    cur_master_file_probe->next = init_verilator_fst_probe_symbol(s,s_info,name);
  }
return(A);
}


FST_SYMBOL_INFO *VerilatedVcd::init_fst_symbol_info(const char *name, int symbol_number)
{
FST_SYMBOL_INFO *A;

if ((A = (FST_SYMBOL_INFO *) malloc(sizeof(FST_SYMBOL_INFO))) == NULL)
   {   
   printf("error in 'init_fst_symbol_info':  malloc call failed\n");   
   printf("out of memory!\n");   
   exit(1);   
  }   
A->symbol_number = symbol_number;
A->min_bit = -1;
A->max_bit = -1;
A->num_bits = -1;
A->array_number = -1;
A->bits_flag = 0;
A->dbl_flag = 0;
A->int_flag = 0;
A->transition_flag = 0;
A->first_file = NULL;
A->first_name = init_fst_symbol_name_info(name);
A->next = NULL;
return(A);
}

// returns one if node match, two if instance match, 0 if no match
int VerilatedVcd::fst_asterisk_compare_node_names(const char *node_name, const char *asterisk_node_name)
{
int i,j,aster_ind, node_ind, aster_dot_ind, node_dot_ind, flag;

if (strcmp(node_name,asterisk_node_name) == 0)
   return(1);
else
   {
   for (i = 0; asterisk_node_name[i] != '\0' && node_name[i] != '\0'; i++)
     {
      if (asterisk_node_name[i] == '*')
	 break;
      if (asterisk_node_name[i] != node_name[i])
	 return(0);
     }
   if (asterisk_node_name[i] != '*')
     {
       if (node_name[i] == '\0')
          return(0);
       else if (node_name[i] != '.')
	  return(0);
       else // node_name[i] must be '.'
	 {
	   i++;
	   for (    ; node_name[i] != '\0'; i++)
	      {
	       if (node_name[i] == '.')
		   return(0);
	      }
	   return(2); // corresponds to node of instance specified by asterisk_node_name
	 }
     }
   }

aster_dot_ind = 0;
node_dot_ind = 0;

while(1)
   {
   /// check for prefix match
   for (i = aster_dot_ind, j = node_dot_ind; asterisk_node_name[i] != '\0' && node_name[j] != '\0'; i++,j++)
      {
       if (asterisk_node_name[i] == '*')
           break;
       if (node_name[j] != asterisk_node_name[i])
           break;
      }
   if (asterisk_node_name[i] == '\0')
      {
       if (node_name[j] == '\0')
          return(1);
       else
          return(0);
      }
   else if (node_name[j] == '\0' && asterisk_node_name[i] == '*')
       return(1);

   if (asterisk_node_name[i] != '*') // names disagree before '*' character
       return(0);

   aster_ind = i;
   node_ind =  j;
   // asterisk_node_name[aster_ind] now equals '*'

   /// check for suffix match
   flag = 0;
   for (i = aster_ind+1; asterisk_node_name[i] != '.' && asterisk_node_name[i] != '*' && asterisk_node_name[i] != '\0'; i++)
     {
      if (asterisk_node_name[i] != ' ')
         flag = 1;
     }

   if (asterisk_node_name[i] == '.')
      aster_dot_ind = i;
   else
      aster_dot_ind = -1;

   for (j = node_ind; node_name[j] != '.' && node_name[j] != '\0'; j++);

   if (node_name[j] == '.')
      node_dot_ind = j;
   else
      node_dot_ind = -1;

   if (asterisk_node_name[i] == '*')
     {
      printf("error in 'fst_asterisk_compare_node_names':\n");
      printf("   within a 'probe:' statement in your CppSim simulation file\n");
      printf("   you have specified probe node '...%s'\n",asterisk_node_name);
      printf("   which has more than one '*' character per instance or node section\n");
      printf("   for instance, '...*.*' is OK, but '...*x*.*'  and '...*.*x*' is not OK\n");
      printf("   -> please fix this probe node specification in your simulation file\n");
      exit(1);
     }
   else if (asterisk_node_name[i] == '\0')
     {
      if (node_dot_ind >= 0) // only allow signals at the level of the * statement
        return(0);
     else if (flag == 0) // nothing after '*' character
        return(1);
     }
   i--;
   j--;

   for (   ; i >= aster_ind && j >= node_ind  ; i--,j-- )
     {
     if (node_name[j] != asterisk_node_name[i])
       break;
     }
   if (asterisk_node_name[i] != '*') // names disagree after '*' character
     return(0);
   else if (node_dot_ind < 0)
     return(1);

   if (aster_dot_ind < 0)
     break;
   }
return(0);

}


// only worry about bit level signals (i.e., do not track transitions on double and int signals)
void VerilatedVcd::update_transition_info()
{
FST_SYMBOL_INFO *cur_fst_symbol;

cur_fst_symbol = first_fst_symbol;
while (cur_fst_symbol != NULL)
   {
     if (cur_fst_symbol->bits_flag == 1)
       {
	 if (strcmp(cur_fst_symbol->value_string,cur_fst_symbol->prev_value_string) != 0)
	   {
	   cur_fst_symbol->transition_flag = 1;
	   strcpy(cur_fst_symbol->prev_value_string,cur_fst_symbol->value_string);
	   }
	 else
	   cur_fst_symbol->transition_flag = 0;
       }
     cur_fst_symbol = cur_fst_symbol->next;
   }
}

int verilator_fst_transition_activity(FST_SYMBOL_FILE_INFO_PROBES *first_master_file_probe)
{
FST_SYMBOL_FILE_INFO_PROBES *cur_master_file_probe;

cur_master_file_probe = first_master_file_probe;
while (cur_master_file_probe != NULL)
   {
     if (cur_master_file_probe->s_info != NULL && cur_master_file_probe->s != 0)
       {
	 if (cur_master_file_probe->s_info->transition_flag == 1)
	    return(1);
       }
     cur_master_file_probe = cur_master_file_probe->next;
   }
return(0);
}


void verilator_fst_emit_file_traces(void *lt, FST_SYMBOL_FILE_INFO_PROBES *first_master_file_probe)
{
FST_SYMBOL_FILE_INFO_PROBES *cur_master_file_probe;

cur_master_file_probe = first_master_file_probe;
while (cur_master_file_probe != NULL)
   {
     if (cur_master_file_probe->s_info != NULL && cur_master_file_probe->s != 0)
       {
	 if (cur_master_file_probe->s_info->bits_flag == 1)
	   {
            // commenting this out to achieve reliable trigger and enable with CppSim
	    // if (cur_master_file_probe->s_info->transition_flag == 1)
	    //   {
               fstWriterEmitValueChange(lt,cur_master_file_probe->s,cur_master_file_probe->s_info->value_string);
	    //   }
	   }
	 else if (cur_master_file_probe->s_info->dbl_flag == 1)
	   {
               fstWriterEmitValueChange(lt,cur_master_file_probe->s,&cur_master_file_probe->s_info->value_dbl);
	   }
	 else if (cur_master_file_probe->s_info->int_flag == 1)
	   {
               fstWriterEmitValueChange(lt,cur_master_file_probe->s,cur_master_file_probe->s_info->value_string);
	   }
       }
     cur_master_file_probe = cur_master_file_probe->next;
   }
}


void VerilatedVcd::add_probe_node(void *lt,const char *prefix, const char *probe_expr, FST_SYMBOL_FILE_INFO_PROBES *first_master_file_probe)
{
FST_SYMBOL_FILE_INFO *cur_file,*prev_file;
FST_SYMBOL_NAME_INFO *cur_name,*temp_name;
FST_SYMBOL_INFO *cur_fst_symbol;
FST_SYMBOL_FILE_INFO_PROBES *cur_probe_symbol,*prev_probe_symbol, *cur_master_file_probe;
uint32_t new_fst_probe_symbol;
char temp_string[MAX_NODE_NAME_LENGTH_FST];
int i,j,count,check_flag,flag,found_flag;
int k, fst_scope_count;
char fst_node_name[MAX_NODE_NAME_LENGTH_FST];


if (first_master_file_probe == NULL)
   {
     printf("error in 'VerilatedVcd::add_probe_node':\n");
     printf("   first_master_file_probe is NULL!\n");
     printf("   -> this should never happen! ??\n");
     exit(1);
   }
if (lt == NULL)
   {
     printf("error in 'VerilatedVcd::add_probe_node':\n");
     printf("   fst_wr_trace input is NULL!\n");
     printf("   -> this should never happen! ??\n");
     exit(1);
   }

found_flag = 0;


cur_fst_symbol = first_fst_symbol;
while (cur_fst_symbol != NULL)
   {
     cur_name = cur_fst_symbol->first_name;
     while (cur_name != NULL)
       {
	 // case check_flag = 2 below checks if this is an instance node
	 // by examining other signals in this cur_lxt_symbol
	 check_flag = fst_asterisk_compare_node_names(cur_name->name,probe_expr);
         if (check_flag != 0)
	   {
	     // printf("found signal '%s' (probe '%s')\n",cur_name->name, probe_expr);
	     if (check_flag == 2)
	       {
		 // printf("***** found potential port signal *****\n");
		 count = 0;
		 for (i = 0; cur_name->name[i] != '\0'; i++)
		   {
		   if (cur_name->name[i] == '.')
		     count++;
		   }
		 flag = 0;
		 temp_name = cur_fst_symbol->first_name;
		 while (temp_name != NULL)
		   {
		     if (temp_name != cur_name)
		       {
		        j = 0;
		        for (i = 0; cur_name->name[i] != '\0'; i++)
		          {
		           if (temp_name->name[i] == '.')
		              j++;
		          }
			if (j == (count-1)) // port node will have a counterpart at one higher level
			  {
			    // printf("----> found port node: '%s'\n",cur_name->name);
			    flag = 1;
			  }
		       }
		     temp_name = temp_name->next;
		   }
		 if (flag == 0)
		   {
		     cur_name = cur_name->next;
		     continue;
		   }
	       }
	     found_flag = 1;

             for (i = 0; i < (MAX_NODE_NAME_LENGTH_FST-2); i++)
               {
               if (prefix[i] == '\0')
                  break;
               temp_string[i] = prefix[i];
               }
             if (prefix[i] != '\0')
               {
               printf("error on 'VerilatedVcd::add_probe_node()':\n");
               printf("   want to add probe node '%s'\n",probe_expr);
               printf("   with prefix '%s'\n",prefix);
               printf("   but overall name exceeds MAX_NODE_NAME_LENGTH_FST characters\n");
               printf("   MAX_NODE_NAME_LENGTH_FST is set to be '%d'\n",MAX_NODE_NAME_LENGTH_FST);
               printf("   -> must increase MAX_NODE_NAME_LENGTH_FST within 'verilated_fst_c.h' file\n");
               exit(1);
               }
             temp_string[i++] = '.';
             for (j = 0; i < (MAX_NODE_NAME_LENGTH_FST-1); i++,j++)
               {
		 if (cur_name->name[j] == '\0')
		   break;
		 temp_string[i] = cur_name->name[j];
               }
	     if (cur_name->name[j] != '\0')
	       {
               printf("error on 'VerilatedVcd::add_probe_node()':\n");
               printf("   want to add probe node '%s'\n",probe_expr);
               printf("   with prefix '%s'\n",prefix);
               printf("   but overall name exceeds MAX_NODE_NAME_LENGTH_FST characters\n");
               printf("   MAX_NODE_NAME_LENGTH_FST is set to be '%d'\n",MAX_NODE_NAME_LENGTH_FST);
               printf("   -> must increase MAX_NODE_NAME_LENGTH_FST within 'verilated_fst_c.h' file\n");
               exit(1);
	       }
	     temp_string[i] = '\0';

	     if (cur_fst_symbol->first_file == NULL)
	       {
                 k = 0;
                 fst_scope_count = 0;
		 for (j = 0; temp_string[j] != '\0'; j++)
		    {
		     fst_node_name[k] = temp_string[j];
                     if (temp_string[j] == '.')
		       {
			fst_scope_count++;
                        fst_node_name[k] = '\0';
                        fstWriterSetScope(lt, FST_ST_VCD_MODULE, fst_node_name,NULL);
                        k = 0;
		       }
                     else
		        k++;
		    }
                 fst_node_name[k] = '\0';

		 if (cur_fst_symbol->bits_flag == 1)
		   {
		     //	if (cur_fst_symbol->min_bit != 0)
		     //	    sprintf(fst_node_name,"%s_%d_%d", fst_node_name, cur_fst_symbol->max_bit, cur_fst_symbol->min_bit);
                     new_fst_probe_symbol = fstWriterCreateVar(lt,FST_VT_VCD_WIRE,FST_VD_IMPLICIT,
                                 cur_fst_symbol->max_bit - cur_fst_symbol->min_bit+1,fst_node_name,0);
		   }
		 else if (cur_fst_symbol->dbl_flag == 1)
		   {
                   new_fst_probe_symbol = fstWriterCreateVar(lt,FST_VT_VCD_REAL,FST_VD_IMPLICIT,1,fst_node_name,0);
		   }
		 else if (cur_fst_symbol->int_flag == 1)
		   {
                   new_fst_probe_symbol = fstWriterCreateVar(lt,FST_VT_VCD_INTEGER,FST_VD_IMPLICIT,32,fst_node_name,0);
		   }
		 else
		   {
		     printf("error on 'VerilatedVcd::add_probe_node()':\n");
		     printf("   want to add probe node '%s'\n",temp_string);
		     printf("   but corresponding symbol is neither bits, double, or int\n");
		     printf("   -> this should never happen! ??\n");
		     exit(1);
		   }
                 for (j = 0; j < fst_scope_count; j++)
                    fstWriterSetUpscope(lt);

                 cur_fst_symbol->first_file = init_fst_symbol_file_info(lt,new_fst_probe_symbol,
                                               cur_fst_symbol, first_master_file_probe, temp_string);
	       }
	     else
	       {
		 cur_file = cur_fst_symbol->first_file;
		 while (cur_file != NULL)
		   {
		     if (cur_file->lt == lt) // this probe node already exists within lt trace
		       {
		       // put in code to take care of aliased signals here - zippy
		       if (cur_file->first_probe_symbol == NULL)
			   {
		           printf("error on 'VerilatedVcd::add_probe_node()':\n");
		           printf("   want to add alias probe node '%s'\n",temp_string);
		           printf("   but cur_file->first_probe_symbol == NULL\n");
		           printf("   -> this should never happen! ??\n");
		           exit(1);
			   }
		       cur_probe_symbol = cur_file->first_probe_symbol;
		       while(cur_probe_symbol != NULL)
			 {
			   if (strcmp(cur_probe_symbol->name,temp_string) == 0)
			      break;
			   prev_probe_symbol = cur_probe_symbol;
			   cur_probe_symbol = cur_probe_symbol->next;
			 }
		       if (cur_probe_symbol == NULL)
			 {
			  /****** aliasing did not seem to work ******
                          new_fst_probe_symbol = fst_wr_symbol_alias(lt,
                             cur_fst_symbol->first_name->name, temp_string, 
                             cur_fst_symbol->max_bit, cur_fst_symbol->min_bit);
			  *******************************************/
			   /***** Replacement code for aliasing is here ********/
                          k = 0;
                          fst_scope_count = 0;
		          for (j = 0; temp_string[j] != '\0'; j++)
		             {
		              fst_node_name[k] = temp_string[j];
                              if (temp_string[j] == '.')
		                 {
			          fst_scope_count++;
                                  fst_node_name[k] = '\0';
                                  fstWriterSetScope(lt, FST_ST_VCD_MODULE, fst_node_name,NULL);
                                  k = 0;
		                 }
                              else
		                 k++;
		             }
                          fst_node_name[k] = '\0';

		          if (cur_fst_symbol->bits_flag == 1)
		             {
			     // if (cur_fst_symbol->min_bit != 0)
			     //     sprintf(fst_node_name,"%s_%d_%d", fst_node_name, cur_fst_symbol->max_bit, cur_fst_symbol->min_bit);
                             new_fst_probe_symbol = fstWriterCreateVar(lt,FST_VT_VCD_WIRE,FST_VD_IMPLICIT,
                                      cur_fst_symbol->max_bit - cur_fst_symbol->min_bit+1,fst_node_name,0);
		             }
		          else if (cur_fst_symbol->dbl_flag == 1)
		             {
                              new_fst_probe_symbol = fstWriterCreateVar(lt,FST_VT_VCD_REAL,FST_VD_IMPLICIT,1,fst_node_name,0);
		             }
		          else if (cur_fst_symbol->int_flag == 1)
		             {
                             new_fst_probe_symbol = fstWriterCreateVar(lt,FST_VT_VCD_INTEGER,FST_VD_IMPLICIT,32,fst_node_name,0);
		             }
		          else
		             {
		             printf("error on 'VerilatedVcd::add_probe_node()':\n");
		             printf("   want to add probe node '%s'\n",temp_string);
		             printf("   but corresponding symbol is neither bits, double, or int\n");
		             printf("   -> this should never happen! ??\n");
		             exit(1);
		             }
                          for (j = 0; j < fst_scope_count; j++)
                             fstWriterSetUpscope(lt);

			  /*****************************************/

		          prev_probe_symbol->next = 
                                init_verilator_fst_probe_symbol(new_fst_probe_symbol,cur_fst_symbol,
                                      temp_string);

                          if (first_master_file_probe->s == 0)
                             {
                              first_master_file_probe->s = new_fst_probe_symbol;
                              first_master_file_probe->s_info = cur_fst_symbol;
                             }
                         else
                             {
                             cur_master_file_probe = first_master_file_probe;
                             while (cur_master_file_probe->next != NULL)
                                {
	                        cur_master_file_probe = cur_master_file_probe->next;
                                }
                             cur_master_file_probe->next = init_verilator_fst_probe_symbol(new_fst_probe_symbol,
                                        cur_fst_symbol, temp_string);
                            }
			 }
		       break;
		       }
		     prev_file = cur_file;
		     cur_file = cur_file->next;
		   }
		 if (cur_file == NULL)
		   {
                    k = 0;
                    fst_scope_count = 0;
		    for (j = 0; temp_string[j] != '\0'; j++)
		       {
		        fst_node_name[k] = temp_string[j];
                        if (temp_string[j] == '.')
		          {
			   fst_scope_count++;
                           fst_node_name[k] = '\0';
                           fstWriterSetScope(lt, FST_ST_VCD_MODULE, fst_node_name,NULL);
                           k = 0;
		          }
                        else
		           k++;
		       }
                    fst_node_name[k] = '\0';

		    if (cur_fst_symbol->bits_flag == 1)
		      {
		       // if (cur_fst_symbol->min_bit != 0)
		       //    sprintf(fst_node_name,"%s_%d_%d", fst_node_name, cur_fst_symbol->max_bit, cur_fst_symbol->min_bit);
                       new_fst_probe_symbol = fstWriterCreateVar(lt,FST_VT_VCD_WIRE,FST_VD_IMPLICIT,
                                      cur_fst_symbol->max_bit - cur_fst_symbol->min_bit+1,fst_node_name,0);
		      }
		    else if (cur_fst_symbol->dbl_flag == 1)
		      {
                       new_fst_probe_symbol = fstWriterCreateVar(lt,FST_VT_VCD_REAL,FST_VD_IMPLICIT,1,fst_node_name,0);
		      }
		    else if (cur_fst_symbol->int_flag == 1)
		      {
                       new_fst_probe_symbol = fstWriterCreateVar(lt,FST_VT_VCD_INTEGER,FST_VD_IMPLICIT,32,fst_node_name,0);
		      }
		    else
		      {
		       printf("error on 'VerilatedVcd::add_probe_node()':\n");
		       printf("   want to add probe node '%s'\n",temp_string);
		       printf("   but corresponding symbol is neither bits, double, or int\n");
		       printf("   -> this should never happen! ??\n");
		       exit(1);
		      }
                    for (j = 0; j < fst_scope_count; j++)
                           fstWriterSetUpscope(lt);

                    prev_file->next = init_fst_symbol_file_info(lt,new_fst_probe_symbol,
                           cur_fst_symbol, first_master_file_probe, temp_string);
		   }
	       }
	    
	   }
	 cur_name = cur_name->next;
       }
     cur_fst_symbol = cur_fst_symbol->next;
   }

if (found_flag == 0)
   {
     printf("Warning 'VerilatedVcd::add_probe_node':  can't find nodes corresponding to\n");
     printf("   probe '%s.%s'\n",prefix,probe_expr);
     printf("   -> please look in the 'probe:' section of your Sim File to correct this\n");
   }
}


FST_SYMBOL_INFO *VerilatedVcd::declare_fst_symbol_base(const char *name, int symbol_number)
{
FST_SYMBOL_INFO *cur_fst_symbol,*prev_fst_symbol;
char temp_name[MAX_NODE_NAME_LENGTH_FST];
int i,j;


i = 0;
if (name[0] == 'v' && name[1] == ' ')
   i = 2;


for (j = 0; i < MAX_NODE_NAME_LENGTH_FST; i++)
  {
   if (name[i] == '\0')
      break;

   if (name[i] == ' ')
     temp_name[j++] = '.';
   else
     temp_name[j++] = name[i];
  }
if (name[i] != '\0')
   {
     printf("error in 'declare_fst_symbol_base': input name is too long!\n");
     printf("   MAX_NODE_NAME_LENGTH_FST is set to be '%d'\n",MAX_NODE_NAME_LENGTH_FST);
     printf("   which is inadequate for name:\n");
     printf("   '%s'\n",name);
     printf("   -> must increase MAX_NODE_NAME_LENGTH_FST within 'verilated_fst_c.h' file\n");
     exit(1);
   }
if (j == 0)
   return(NULL);

temp_name[j] = '\0';

// printf("declaring symbol '%s', code number '%d'\n",temp_name,symbol_number);
if (first_fst_symbol == NULL)
    {
     first_fst_symbol = init_fst_symbol_info(temp_name,symbol_number);
     cur_fst_symbol = first_fst_symbol;
    }
else 
   {
     cur_fst_symbol = first_fst_symbol;

     while (cur_fst_symbol != NULL)
       {
	 if (cur_fst_symbol->symbol_number == symbol_number)
	    break;
	 prev_fst_symbol = cur_fst_symbol;
	 cur_fst_symbol = cur_fst_symbol->next;
       }
     if (cur_fst_symbol == NULL)
       {	 
	 //        printf("new name: '%s', code '%d'\n",temp_name,symbol_number);
        prev_fst_symbol->next = init_fst_symbol_info(temp_name,symbol_number);
	cur_fst_symbol = prev_fst_symbol->next;
       }
     else
       {
	 //	 printf("alias name: '%s', code '%d'\n",temp_name,symbol_number);
       add_fst_symbol_name(temp_name,cur_fst_symbol); // want all name aliases
       return(NULL);
       }
   }
return(cur_fst_symbol);
}

void VerilatedVcd::declare_fst_symbol_bits(const char *name, int symbol_number, int max_bit_in, int min_bit_in, int array_number)
{
FST_SYMBOL_INFO *cur_fst_symbol;
int max_bit, min_bit, num_bits;

if (min_bit_in > max_bit_in)
   {
     max_bit = min_bit_in;
     min_bit = max_bit_in;
   }
else
   {
     max_bit = max_bit_in;
     min_bit = min_bit_in;
   }

num_bits = (max_bit - min_bit) + 1;
if (num_bits > 2000)
   {
     printf("error in 'declare_fst_symbol_bits':  maximum bus length\n");
     printf("   of 2000 bits exceeded for signal '%s'\n",name);
     printf("   which has max_bit = %d, min_bit = %d\n",max_bit,min_bit);
     exit(1);
   }
cur_fst_symbol = declare_fst_symbol_base(name,symbol_number);
if (cur_fst_symbol != NULL) // symbol will be NULL if symbol_number already taken
   {
   cur_fst_symbol->value_string[num_bits] = '\0';
   cur_fst_symbol->prev_value_string[num_bits] = '\0';
   cur_fst_symbol->min_bit = min_bit;
   cur_fst_symbol->max_bit = max_bit;
   cur_fst_symbol->num_bits = num_bits;
   cur_fst_symbol->array_number = array_number;
   cur_fst_symbol->bits_flag = 1;
   }
}

void VerilatedVcd::declare_fst_symbol_dbl(const char *name, int symbol_number, int array_number)
{
FST_SYMBOL_INFO *cur_fst_symbol_info;

cur_fst_symbol_info = declare_fst_symbol_base(name,symbol_number);
if (cur_fst_symbol_info != NULL) // symbol will be NULL if symbol_number already taken
  {
   cur_fst_symbol_info->array_number = array_number;
   cur_fst_symbol_info->dbl_flag = 1;
  }
}

void VerilatedVcd::declare_fst_symbol_int(const char *name, int symbol_number, int array_number)
{
FST_SYMBOL_INFO *cur_fst_symbol_info;

cur_fst_symbol_info = declare_fst_symbol_base(name,symbol_number);
if (cur_fst_symbol_info != NULL) // symbol will be NULL if symbol_number already taken
  {
   cur_fst_symbol_info->array_number = array_number;
   cur_fst_symbol_info->int_flag = 1;
  }
}

FST_SYMBOL_INFO *VerilatedVcd::find_fst_symbol(int symbol_number)
{

if (current_fst_symbol != NULL)
   {
     if (current_fst_symbol->next == NULL)
       current_fst_symbol = first_fst_symbol;
     else
       current_fst_symbol = current_fst_symbol->next;
   
     if (current_fst_symbol->symbol_number == symbol_number)
       {
	 return(current_fst_symbol);
       }
   }
// need to search for symbol

current_fst_symbol = first_fst_symbol;
while (current_fst_symbol != NULL)
   {
    if (current_fst_symbol->symbol_number == symbol_number)
       break;
    current_fst_symbol = current_fst_symbol->next;
   }
if (current_fst_symbol == NULL)
   {
     printf("error in 'find_fst_symbol':  can't find symbol_number '%d'\n",
	    symbol_number);
     exit(1);
   }
return(current_fst_symbol);
}

//=============================================================================

//=============================================================================
// Callbacks

void VerilatedVcd::addCallback (
    VerilatedVcdCallback_t initcb, VerilatedVcdCallback_t fullcb, VerilatedVcdCallback_t changecb,
    void* userthis)
{
    ;
}


