// Support for FST files in CppSim with Verilator
// written by Michael H Perrott (March 2010)
// This code leveraged the verilated_vcd_c.h 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

#ifndef _VERILATED_VCD_C_H_
#define _VERILATED_VCD_C_H_ 1

#include "verilatedos.h"

#include <string>
#include <vector>
#include <map>

typedef uint32_t fstHandle;

using namespace std;

class VerilatedVcd;


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

typedef void (*VerilatedVcdCallback_t)(VerilatedVcd* vcdp, void* userthis, vluint32_t code);

//=============================================================================
// VerilatedVcd

#define MAX_NODE_NAME_LENGTH_FST 2000

struct FST_SYMBOL_FILE_INFO_PROBES
{
fstHandle s;  // fstHandle s;
struct FST_SYMBOL_INFO *s_info;
char name[MAX_NODE_NAME_LENGTH_FST];
struct FST_SYMBOL_FILE_INFO_PROBES *next;
};
typedef struct FST_SYMBOL_FILE_INFO_PROBES FST_SYMBOL_FILE_INFO_PROBES;


struct FST_SYMBOL_FILE_INFO
{
void *lt;
struct FST_SYMBOL_FILE_INFO_PROBES *first_probe_symbol;
struct FST_SYMBOL_FILE_INFO *next;
};
typedef struct FST_SYMBOL_FILE_INFO FST_SYMBOL_FILE_INFO;


struct FST_SYMBOL_NAME_INFO
{
char name[MAX_NODE_NAME_LENGTH_FST];
struct FST_SYMBOL_NAME_INFO *next;
};
typedef struct FST_SYMBOL_NAME_INFO FST_SYMBOL_NAME_INFO;


struct FST_SYMBOL_INFO
  {
  int symbol_number, min_bit, max_bit, num_bits, array_number;
  int bits_flag, dbl_flag, int_flag;
  char value_string[2001], prev_value_string[2001];
  double value_dbl, prev_value_dbl;
  int value_int, prev_value_int;
  int transition_flag;
  struct FST_SYMBOL_FILE_INFO *first_file;
  struct FST_SYMBOL_NAME_INFO *first_name;
  struct FST_SYMBOL_INFO *next;
};
typedef struct FST_SYMBOL_INFO FST_SYMBOL_INFO;

FST_SYMBOL_FILE_INFO_PROBES *init_verilator_fst_probe_symbol(fstHandle s, FST_SYMBOL_INFO *s_info,
                                                    const char *name);
int verilator_fst_transition_activity(FST_SYMBOL_FILE_INFO_PROBES *first_master_file_probe);
void verilator_fst_emit_file_traces(void *lt, FST_SYMBOL_FILE_INFO_PROBES *first_master_file_probe);

class VerilatedVcd {
private:
    FST_SYMBOL_INFO *first_fst_symbol, *current_fst_symbol;
    string		m_modName;	///< Module name being traced now
public:

    VerilatedVcd();
    ~VerilatedVcd();
    // METHODS
    /// Inside dumping routines, declare callbacks for tracings
    void addCallback (VerilatedVcdCallback_t init, VerilatedVcdCallback_t full,
		      VerilatedVcdCallback_t change,
		      void* userthis);

    void scopeEscape(char flag);
    /// Inside dumping routines, declare a module
    void module (const string name);
    /// Inside dumping routines, declare a signal
    FST_SYMBOL_INFO *init_fst_symbol_info(const char *name, int symbol_number);
    FST_SYMBOL_FILE_INFO *init_fst_symbol_file_info(void *lt, fstHandle s, 
                                                      FST_SYMBOL_INFO *s_info, 
                                     FST_SYMBOL_FILE_INFO_PROBES *master_file_probe, const char *name);
    FST_SYMBOL_NAME_INFO *init_fst_symbol_name_info(const char *name);
    void add_fst_symbol_name(const char *name, FST_SYMBOL_INFO *fst_symbol);
    int fst_asterisk_compare_node_names(const char *node_name, const char *asterisk_node_name);
    void add_probe_node(void *lt, const char *prefix, const char *probe_expr, 
			FST_SYMBOL_FILE_INFO_PROBES *first_master_file_probe);

    void update_transition_info();

    FST_SYMBOL_INFO *declare_fst_symbol_base(const char *name, int symbol_number);
    void declare_fst_symbol_bits(const char *name, int symbol_number, int min_bit, int max_bit, int array_number);
    void declare_fst_symbol_dbl(const char *name, int symbol_number, int array_number);
    void declare_fst_symbol_int(const char *name, int symbol_number, int array_number);
    FST_SYMBOL_INFO *find_fst_symbol(int symbol_number);
    void declBit      (vluint32_t code, const char* name, int arraynum);
    void declBus      (vluint32_t code, const char* name, int arraynum, int msb, int lsb);
    void declQuad     (vluint32_t code, const char* name, int arraynum, int msb, int lsb);
    void declArray    (vluint32_t code, const char* name, int arraynum, int msb, int lsb);
    void declTriBit   (vluint32_t code, const char* name, int arraynum);
    void declTriBus   (vluint32_t code, const char* name, int arraynum, int msb, int lsb);
    void declTriQuad  (vluint32_t code, const char* name, int arraynum, int msb, int lsb);
    void declTriArray (vluint32_t code, const char* name, int arraynum, int msb, int lsb);
    void declDouble   (vluint32_t code, const char* name, int arraynum);
    void declFloat    (vluint32_t code, const char* name, int arraynum);


    void fullBit (vluint32_t code, const vluint32_t newval);
    void fullBus (vluint32_t code, const vluint32_t newval, int bits);
    void fullQuad (vluint32_t code, const vluint64_t newval, int bits);
    void fullArray (vluint32_t code, const vluint32_t* newval, int bits);
    void fullTriBit (vluint32_t code, const vluint32_t newval, const vluint32_t newtri);
    void fullTriBus (vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits);
    void fullTriQuad (vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits);
    void fullTriArray (vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, int bits);
    void fullDouble (vluint32_t code, const double newval);
    void fullFloat (vluint32_t code, const float newval);

    void fullBitX (vluint32_t code);
    void fullBusX (vluint32_t code, int bits);
    void fullQuadX (vluint32_t code, int bits);
    void fullArrayX (vluint32_t code, int bits);

    /// Inside dumping routines, dump one signal if it has changed

    inline void chgBit (vluint32_t code, const vluint32_t newval) {
		fullBit (code, newval);
    }
    inline void chgBus (vluint32_t code, const vluint32_t newval, int bits) {
		fullBus (code, newval, bits);
    }
    inline void chgQuad (vluint32_t code, const vluint64_t newval, int bits) {
		fullQuad(code, newval, bits);
    }
    inline void chgArray (vluint32_t code, const vluint32_t* newval, int bits) {
		fullArray (code,newval,bits);
    }
    inline void chgTriBit (vluint32_t code, const vluint32_t newval, const vluint32_t newtri) {
		fullTriBit (code, newval, newtri);
    }
    inline void chgTriBus (vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits) {
		fullTriBus (code, newval, newtri, bits);
    }
    inline void chgTriQuad (vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits) {
		fullTriQuad(code, newval, newtri, bits);
    }
    inline void chgTriArray (vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, int bits) {
		fullTriArray (code,newvalp,newtrip,bits);
    }
    inline void chgDouble (vluint32_t code, const double newval) {
	    fullDouble (code, newval);
    }
    inline void chgFloat (vluint32_t code, const float newval) {
	    fullFloat (code, newval);
    }


};

//=============================================================================
// VerilatedVcdC
/// Create a VCD dump file in C standalone (no SystemC) simulations.

class VerilatedVcdC {
    VerilatedVcd		m_sptrace;	///< SystemPerl trace file being created
public:
    // CONSTRUCTORS
    VerilatedVcdC() {}
    ~VerilatedVcdC() {}
    // METHODS
    /// Internal class access
    inline VerilatedVcd* spTrace () { return &m_sptrace; };
};

#endif // guard
