forked from github/verilator
Improve tracing performance. (#2257)
* Improve tracing performance. Various tactics used to improve performance of both VCD and FST tracing: - Both: Change tracing functions to templates to take variable widths as template parameters. For VCD, subsequently specialize these to the values used by Verilator. This avoids redundant instructions and hard to predict branches. - Both: Check for value changes via direct pointer access into the previous signal value buffer. This eliminates a lot of simple pointer arithmetic instructions form the tracing code. - Both: Verilator provides clean input, no need to mask out used bits. - VCD: pre-compute identifier codes and use memory copy instead of re-computing them every time a code is emitted. This saves a lot of instructions and hard to predict branches. The added D-cache misses are cheaper than the removed branches/instructions. - VCD: re-write the routines emitting the changes to be more efficient. - FST: Use previous signal value buffer the same way as the VCD tracing code, and only call the FST API when a change is detected. Performance as measured on SweRV EH1, with the pre-canned CoreMark benchmark running from DCCM/ICCM, clang 6.0.0, Intel i7-3770 @ 3.40GHz, and IO to ramdisk: +--------------+---------------+----------------------+ | VCD | FST | FST separate thread | | (--trace) | (--trace-fst) | (--trace-fst-thread) | ------------+-----------------------------------------------------+ Before | 30.2 s | 121.1 s | 69.8 s | ============+==============+===============+======================+ After | 24.7 s | 45.7 s | 32.4 s | ------------+--------------+---------------+----------------------+ Speedup | 22 % | 256 % | 215 % | ------------+--------------+---------------+----------------------+ Rel. to VCD | 1 x | 1.85 x | 1.31 x | ------------+--------------+---------------+----------------------+ In addition, FST trace size for the above reduced by 48%.
This commit is contained in:
parent
dc27a179e2
commit
dc5c259069
4
Changes
4
Changes
@ -15,11 +15,11 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
**** Add error if use SystemC 2.2 and earlier (pre-2011) as is deprecated.
|
||||
|
||||
**** Improve FST dump performance, #2244, #2250. [Geza Lore]
|
||||
**** Greatly improve FST dump performance, #2244, #2250, #2257. [Geza Lore]
|
||||
|
||||
**** Fix build of fast path tracing code to use OPT_FAST, #2245. [Geza Lore]
|
||||
|
||||
**** Improve VCD dump performance, #2246, #2250. [Geza Lore]
|
||||
**** Improve VCD dump performance, #2246, #2250, #2257. [Geza Lore]
|
||||
|
||||
|
||||
* Verilator 4.032 2020-04-04
|
||||
|
@ -4987,6 +4987,12 @@ using the Verilator --exe flag.
|
||||
Note you can also call ->trace on multiple Verilated objects with the same
|
||||
trace file if you want all data to land in the same output file.
|
||||
|
||||
When using SystemC 2.3, the SystemC library must have been built with the
|
||||
experiemntal simulation phase callback based tracing disabled. This is
|
||||
disabled by default when building SystemC with its configure based build
|
||||
system, but when building SystemC with CMake, you must pass
|
||||
-DENABLE_PHASE_CALLBACKS_TRACING=OFF to disable this feature.
|
||||
|
||||
#include "verilated_vcd_sc.h"
|
||||
...
|
||||
int main(int argc, char** argv, char** env) {
|
||||
|
@ -17,6 +17,8 @@
|
||||
//=============================================================================
|
||||
// SPDIFF_OFF
|
||||
|
||||
// clang-format off
|
||||
|
||||
#define __STDC_LIMIT_MACROS // UINT64_MAX
|
||||
#include "verilatedos.h"
|
||||
#include "verilated.h"
|
||||
@ -49,6 +51,8 @@
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
// clang-format on
|
||||
|
||||
//=============================================================================
|
||||
|
||||
class VerilatedFstCallInfo {
|
||||
@ -79,13 +83,15 @@ VerilatedFst::VerilatedFst(void* fst)
|
||||
, m_minNextDumpTime(0)
|
||||
, m_nextCode(1)
|
||||
, m_scopeEscape('.')
|
||||
, m_symbolp(NULL) {
|
||||
, m_symbolp(NULL)
|
||||
, m_sigs_oldvalp(NULL) {
|
||||
m_valueStrBuffer.reserve(64 + 1); // Need enough room for quad
|
||||
}
|
||||
|
||||
VerilatedFst::~VerilatedFst() {
|
||||
if (m_fst) fstWriterClose(m_fst);
|
||||
if (m_symbolp) VL_DO_CLEAR(delete[] m_symbolp, m_symbolp = NULL);
|
||||
if (m_sigs_oldvalp) VL_DO_CLEAR(delete[] m_sigs_oldvalp, m_sigs_oldvalp = NULL);
|
||||
}
|
||||
|
||||
void VerilatedFst::open(const char* filename) VL_MT_UNSAFE {
|
||||
@ -121,6 +127,9 @@ void VerilatedFst::open(const char* filename) VL_MT_UNSAFE {
|
||||
}
|
||||
}
|
||||
m_code2symbol.clear();
|
||||
|
||||
// Allocate space now we know the number of codes
|
||||
if (!m_sigs_oldvalp) m_sigs_oldvalp = new vluint32_t[m_nextCode + 10];
|
||||
}
|
||||
|
||||
void VerilatedFst::module(const std::string& name) { m_module = name; }
|
||||
@ -214,9 +223,9 @@ void VerilatedFst::addCallback(VerilatedFstCallback_t initcb, VerilatedFstCallba
|
||||
void VerilatedFst::dump(vluint64_t timeui) {
|
||||
if (!isOpen()) return;
|
||||
if (timeui < m_minNextDumpTime) {
|
||||
VL_PRINTF_MT("%%Warning: previous dump at t=%" VL_PRI64 "u, requesting t=%" VL_PRI64 "u\n",
|
||||
m_minNextDumpTime - 1, timeui);
|
||||
return;
|
||||
VL_PRINTF_MT("%%Warning: previous dump at t=%" VL_PRI64 "u, requesting t=%" VL_PRI64 "u\n",
|
||||
m_minNextDumpTime - 1, timeui);
|
||||
return;
|
||||
}
|
||||
m_minNextDumpTime = timeui + 1;
|
||||
if (VL_UNLIKELY(m_fullDump)) {
|
||||
|
@ -57,11 +57,11 @@ private:
|
||||
Local2FstDtype m_local2fstdtype;
|
||||
std::list<std::string> m_curScope;
|
||||
fstHandle* m_symbolp; ///< same as m_code2symbol, but as an array
|
||||
vluint32_t* m_sigs_oldvalp;
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedFst);
|
||||
void declSymbol(vluint32_t code, const char* name,
|
||||
int dtypenum, fstVarDir vardir, fstVarType vartype,
|
||||
bool array, int arraynum, vluint32_t len, vluint32_t bits);
|
||||
void declSymbol(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum, vluint32_t len, vluint32_t bits);
|
||||
// helpers
|
||||
std::vector<char> m_valueStrBuffer;
|
||||
|
||||
@ -94,102 +94,108 @@ public:
|
||||
void dump(vluint64_t timeui);
|
||||
/// Inside dumping routines, declare callbacks for tracings
|
||||
void addCallback(VerilatedFstCallback_t initcb, VerilatedFstCallback_t fullcb,
|
||||
VerilatedFstCallback_t changecb,
|
||||
void* userthis) VL_MT_UNSAFE_ONE;
|
||||
VerilatedFstCallback_t changecb, void* userthis) VL_MT_UNSAFE_ONE;
|
||||
|
||||
/// Inside dumping routines, declare a module
|
||||
void module(const std::string& name);
|
||||
/// Inside dumping routines, declare a data type
|
||||
void declDTypeEnum(int dtypenum, const char* name, vluint32_t elements,
|
||||
unsigned int minValbits,
|
||||
const char** itemNamesp, const char** itemValuesp);
|
||||
unsigned int minValbits, const char** itemNamesp, const char** itemValuesp);
|
||||
/// Inside dumping routines, declare a signal
|
||||
void declBit(vluint32_t code, const char* name,
|
||||
int dtypenum, fstVarDir vardir, fstVarType vartype,
|
||||
bool array, int arraynum) {
|
||||
void declBit(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum) {
|
||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1, 1);
|
||||
}
|
||||
void declBus(vluint32_t code, const char* name,
|
||||
int dtypenum, fstVarDir vardir, fstVarType vartype,
|
||||
bool array, int arraynum, int msb, int lsb) {
|
||||
void declBus(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
|
||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
|
||||
msb - lsb + 1);
|
||||
}
|
||||
void declDouble(vluint32_t code, const char* name,
|
||||
int dtypenum, fstVarDir vardir, fstVarType vartype,
|
||||
bool array, int arraynum) {
|
||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 2, 64);
|
||||
void declQuad(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
|
||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
|
||||
msb - lsb + 1);
|
||||
}
|
||||
void declFloat(vluint32_t code, const char* name,
|
||||
int dtypenum, fstVarDir vardir, fstVarType vartype,
|
||||
bool array, int arraynum) {
|
||||
void declArray(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
|
||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
|
||||
msb - lsb + 1);
|
||||
}
|
||||
void declFloat(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum) {
|
||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1, 32);
|
||||
}
|
||||
void declQuad(vluint32_t code, const char* name,
|
||||
int dtypenum, fstVarDir vardir, fstVarType vartype,
|
||||
bool array, int arraynum, int msb, int lsb) {
|
||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
|
||||
msb - lsb + 1);
|
||||
}
|
||||
void declArray(vluint32_t code, const char* name,
|
||||
int dtypenum, fstVarDir vardir, fstVarType vartype,
|
||||
bool array, int arraynum, int msb, int lsb) {
|
||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
|
||||
msb - lsb + 1);
|
||||
void declDouble(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum) {
|
||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 2, 64);
|
||||
}
|
||||
|
||||
/// Inside dumping routines, dump one signal if it has changed
|
||||
void chgBit(vluint32_t code, const vluint32_t newval) {
|
||||
fstWriterEmitValueChange(m_fst, m_symbolp[code], newval ? "1" : "0");
|
||||
//=========================================================================
|
||||
// Inside dumping routines used by Verilator
|
||||
|
||||
vluint32_t* oldp(vluint32_t code) { return m_sigs_oldvalp + code; }
|
||||
|
||||
//=========================================================================
|
||||
// Write back to previous value buffer value and emit
|
||||
|
||||
void fullBit(vluint32_t* oldp, vluint32_t newval) {
|
||||
*oldp = newval;
|
||||
fstWriterEmitValueChange(m_fst, m_symbolp[oldp - m_sigs_oldvalp], newval ? "1" : "0");
|
||||
}
|
||||
void chgBus(vluint32_t code, const vluint32_t newval, int bits) {
|
||||
fstWriterEmitValueChange32(m_fst, m_symbolp[code], bits, newval);
|
||||
template <int T_Bits> void fullBus(vluint32_t* oldp, vluint32_t newval) {
|
||||
*oldp = newval;
|
||||
fstWriterEmitValueChange32(m_fst, m_symbolp[oldp - m_sigs_oldvalp], T_Bits, newval);
|
||||
}
|
||||
void chgDouble(vluint32_t code, const double newval) {
|
||||
double val = newval;
|
||||
fstWriterEmitValueChange(m_fst, m_symbolp[code], &val);
|
||||
void fullQuad(vluint32_t* oldp, vluint64_t newval, int bits) {
|
||||
*reinterpret_cast<vluint64_t*>(oldp) = newval;
|
||||
fstWriterEmitValueChange64(m_fst, m_symbolp[oldp - m_sigs_oldvalp], bits, newval);
|
||||
}
|
||||
void chgFloat(vluint32_t code, const float newval) {
|
||||
double val = (double)newval;
|
||||
fstWriterEmitValueChange(m_fst, m_symbolp[code], &val);
|
||||
void fullArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) {
|
||||
for (int i = 0; i < (bits + 31) / 32; ++i) oldp[i] = newvalp[i];
|
||||
fstWriterEmitValueChangeVec32(m_fst, m_symbolp[oldp - m_sigs_oldvalp], bits, newvalp);
|
||||
}
|
||||
void chgQuad(vluint32_t code, const vluint64_t newval, int bits) {
|
||||
fstWriterEmitValueChange64(m_fst, m_symbolp[code], bits, newval);
|
||||
void fullFloat(vluint32_t* oldp, float newval) {
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
*reinterpret_cast<float*>(oldp) = newval;
|
||||
fstWriterEmitValueChange(m_fst, m_symbolp[oldp - m_sigs_oldvalp], oldp);
|
||||
}
|
||||
void chgArray(vluint32_t code, const vluint32_t* newval, int bits) {
|
||||
fstWriterEmitValueChangeVec32(m_fst, m_symbolp[code], bits, newval);
|
||||
void fullDouble(vluint32_t* oldp, double newval) {
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
*reinterpret_cast<double*>(oldp) = newval;
|
||||
fstWriterEmitValueChange(m_fst, m_symbolp[oldp - m_sigs_oldvalp], oldp);
|
||||
}
|
||||
|
||||
void fullBit(vluint32_t code, const vluint32_t newval) { chgBit(code, newval); }
|
||||
void fullBus(vluint32_t code, const vluint32_t newval, int bits) {
|
||||
chgBus(code, newval, bits);
|
||||
}
|
||||
void fullDouble(vluint32_t code, const double newval) { chgDouble(code, newval); }
|
||||
void fullFloat(vluint32_t code, const float newval) { chgFloat(code, newval); }
|
||||
void fullQuad(vluint32_t code, const vluint64_t newval, int bits) {
|
||||
chgQuad(code, newval, bits);
|
||||
}
|
||||
void fullArray(vluint32_t code, const vluint32_t* newval, int bits) {
|
||||
chgArray(code, newval, bits);
|
||||
}
|
||||
//=========================================================================
|
||||
// Check previous value and emit if changed
|
||||
|
||||
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 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 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);
|
||||
void chgTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri);
|
||||
void chgTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits);
|
||||
void chgTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits);
|
||||
void chgTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, int bits);
|
||||
inline void chgBit(vluint32_t* oldp, vluint32_t newval) {
|
||||
const vluint32_t diff = *oldp ^ newval;
|
||||
if (VL_UNLIKELY(diff)) fullBit(oldp, newval);
|
||||
}
|
||||
template <int T_Bits> inline void chgBus(vluint32_t* oldp, vluint32_t newval) {
|
||||
const vluint32_t diff = *oldp ^ newval;
|
||||
if (VL_UNLIKELY(diff)) fullBus<T_Bits>(oldp, newval);
|
||||
}
|
||||
inline void chgQuad(vluint32_t* oldp, vluint64_t newval, int bits) {
|
||||
const vluint64_t diff = *reinterpret_cast<vluint64_t*>(oldp) ^ newval;
|
||||
if (VL_UNLIKELY(diff)) fullQuad(oldp, newval, bits);
|
||||
}
|
||||
inline void chgArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) {
|
||||
for (int i = 0; i < (bits + 31) / 32; ++i) {
|
||||
if (VL_UNLIKELY(oldp[i] ^ newvalp[i])) {
|
||||
fullArray(oldp, newvalp, bits);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void chgFloat(vluint32_t* oldp, float newval) {
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
if (VL_UNLIKELY(*reinterpret_cast<float*>(oldp) != newval)) fullFloat(oldp, newval);
|
||||
}
|
||||
inline void chgDouble(vluint32_t* oldp, double newval) {
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
if (VL_UNLIKELY(*reinterpret_cast<double*>(oldp) != newval)) fullDouble(oldp, newval);
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
|
@ -17,6 +17,8 @@
|
||||
//=============================================================================
|
||||
// SPDIFF_OFF
|
||||
|
||||
// clang-format off
|
||||
|
||||
#include "verilatedos.h"
|
||||
#include "verilated.h"
|
||||
#include "verilated_vcd_c.h"
|
||||
@ -45,6 +47,19 @@
|
||||
# define O_CLOEXEC 0
|
||||
#endif
|
||||
|
||||
// clang-format on
|
||||
|
||||
// This size comes form VCD allowing use of printable ASCII characters between
|
||||
// '!' and '~' inclusive, which are a total of 94 different values. Encoding a
|
||||
// 32 bit code hence needs a maximum of ceil(log94(2**32-1)) == 5 bytes.
|
||||
#define VL_TRACE_MAX_VCD_CODE_SIZE 5 ///< Maximum length of a VCD string code
|
||||
// We use 8 bytes per code in a suffix buffer array.
|
||||
// 1 byte optional separator + VL_TRACE_MAX_VCD_CODE_SIZE bytes for code
|
||||
// + 1 byte '\n' + 1 byte suffix size. This luckily comes out to a power of 2,
|
||||
// meaning the array can be aligned such that entries never straddle multiple
|
||||
// cache-lines.
|
||||
#define VL_TRACE_SUFFIX_ENTRY_SIZE 8 ///< Size of a suffix entry
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedVcdImp
|
||||
/// Base class to hold some static state
|
||||
@ -57,7 +72,10 @@ private:
|
||||
VerilatedMutex s_vcdMutex; ///< Protect the singleton
|
||||
VcdVec s_vcdVecp VL_GUARDED_BY(s_vcdMutex); ///< List of all created traces
|
||||
};
|
||||
static Singleton& singleton() { static Singleton s; return s; }
|
||||
static Singleton& singleton() {
|
||||
static Singleton s;
|
||||
return s;
|
||||
}
|
||||
|
||||
public:
|
||||
static void pushVcd(VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
|
||||
@ -152,6 +170,7 @@ VerilatedVcd::VerilatedVcd(VerilatedVcdFile* filep)
|
||||
m_wrFlushp = m_wrBufp + m_wrChunkSize * 6;
|
||||
m_writep = m_wrBufp;
|
||||
m_wroteBytes = 0;
|
||||
m_suffixesp = NULL;
|
||||
}
|
||||
|
||||
void VerilatedVcd::open(const char* filename) {
|
||||
@ -175,6 +194,9 @@ void VerilatedVcd::open(const char* filename) {
|
||||
// Allocate space now we know the number of codes
|
||||
if (!m_sigs_oldvalp) m_sigs_oldvalp = new vluint32_t[m_nextCode + 10];
|
||||
|
||||
// Get the direct access pointer to the code strings
|
||||
m_suffixesp = &m_suffixes[0]; // Note: C++11 m_suffixes.data();
|
||||
|
||||
if (m_rolloverMB) {
|
||||
openNext(true);
|
||||
if (!isOpen()) return;
|
||||
@ -191,10 +213,8 @@ void VerilatedVcd::openNext(bool incFilename) {
|
||||
std::string name = m_filename;
|
||||
size_t pos = name.rfind('.');
|
||||
if (pos > 8 && 0 == strncmp("_cat", name.c_str() + pos - 8, 4)
|
||||
&& isdigit(name.c_str()[pos - 4])
|
||||
&& isdigit(name.c_str()[pos - 3])
|
||||
&& isdigit(name.c_str()[pos - 2])
|
||||
&& isdigit(name.c_str()[pos - 1])) {
|
||||
&& isdigit(name.c_str()[pos - 4]) && isdigit(name.c_str()[pos - 3])
|
||||
&& isdigit(name.c_str()[pos - 2]) && isdigit(name.c_str()[pos - 1])) {
|
||||
// Increment code.
|
||||
if ((++(name[pos - 1])) > '9') {
|
||||
name[pos - 1] = '0';
|
||||
@ -404,7 +424,8 @@ void VerilatedVcd::set_time_resolution(const char* unitp) {
|
||||
double VerilatedVcd::timescaleToDouble(const char* unitp) {
|
||||
char* endp;
|
||||
double value = strtod(unitp, &endp);
|
||||
if (value == 0.0 && endp == unitp) value = 1; // On error so we allow just "ns" to return 1e-9.
|
||||
// On error so we allow just "ns" to return 1e-9.
|
||||
if (value == 0.0 && endp == unitp) value = 1;
|
||||
unitp = endp;
|
||||
for (; *unitp && isspace(*unitp); unitp++) {}
|
||||
switch (*unitp) {
|
||||
@ -421,27 +442,41 @@ double VerilatedVcd::timescaleToDouble(const char* unitp) {
|
||||
|
||||
std::string VerilatedVcd::doubleToTimescale(double value) {
|
||||
const char* suffixp = "s";
|
||||
if (value>=1e0) { suffixp="s"; value *= 1e0; }
|
||||
else if (value>=1e-3 ) { suffixp="ms"; value *= 1e3; }
|
||||
else if (value>=1e-6 ) { suffixp="us"; value *= 1e6; }
|
||||
else if (value>=1e-9 ) { suffixp="ns"; value *= 1e9; }
|
||||
else if (value>=1e-12) { suffixp="ps"; value *= 1e12; }
|
||||
else if (value>=1e-15) { suffixp="fs"; value *= 1e15; }
|
||||
else if (value>=1e-18) { suffixp="as"; value *= 1e18; }
|
||||
// clang-format off
|
||||
if (value >= 1e0) { suffixp = "s"; value *= 1e0; }
|
||||
else if (value >= 1e-3 ) { suffixp = "ms"; value *= 1e3; }
|
||||
else if (value >= 1e-6 ) { suffixp = "us"; value *= 1e6; }
|
||||
else if (value >= 1e-9 ) { suffixp = "ns"; value *= 1e9; }
|
||||
else if (value >= 1e-12) { suffixp = "ps"; value *= 1e12; }
|
||||
else if (value >= 1e-15) { suffixp = "fs"; value *= 1e15; }
|
||||
else if (value >= 1e-18) { suffixp = "as"; value *= 1e18; }
|
||||
// clang-format on
|
||||
char valuestr[100];
|
||||
sprintf(valuestr, "%3.0f%s", value, suffixp);
|
||||
return valuestr; // Gets converted to string, so no ref to stack
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// VCD string code
|
||||
|
||||
char* VerilatedVcd::writeCode(char* writep, vluint32_t code) {
|
||||
*writep++ = static_cast<char>('!' + code % 94);
|
||||
code /= 94;
|
||||
while (code) {
|
||||
code--;
|
||||
*writep++ = static_cast<char>('!' + code % 94);
|
||||
code /= 94;
|
||||
}
|
||||
return writep;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Definitions
|
||||
|
||||
void VerilatedVcd::printIndent(int level_change) {
|
||||
if (level_change < 0) m_modDepth += level_change;
|
||||
assert(m_modDepth >= 0);
|
||||
for (int i = 0; i < m_modDepth; i++) {
|
||||
printStr(" ");
|
||||
}
|
||||
for (int i = 0; i < m_modDepth; i++) printStr(" ");
|
||||
if (level_change > 0) m_modDepth += level_change;
|
||||
}
|
||||
|
||||
@ -539,8 +574,8 @@ void VerilatedVcd::module(const std::string& name) {
|
||||
m_modName = name;
|
||||
}
|
||||
|
||||
void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep,
|
||||
bool array, int arraynum, bool tri, bool bussed, int msb, int lsb) {
|
||||
void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep, bool array,
|
||||
int arraynum, bool tri, bool bussed, int msb, int lsb) {
|
||||
if (!code) {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", "Internal: internal trace problem, code 0 is illegal");
|
||||
}
|
||||
@ -554,6 +589,9 @@ void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep,
|
||||
if (m_sigs.capacity() <= m_nextCode) {
|
||||
m_sigs.reserve(m_nextCode * 2); // Power-of-2 allocation speeds things up
|
||||
}
|
||||
if (m_suffixes.size() <= m_nextCode * VL_TRACE_SUFFIX_ENTRY_SIZE) {
|
||||
m_suffixes.resize(m_nextCode * VL_TRACE_SUFFIX_ENTRY_SIZE * 2, 0);
|
||||
}
|
||||
|
||||
// Make sure write buffer is large enough (one character per bit), plus header
|
||||
bufferResize(bits + 1024);
|
||||
@ -601,7 +639,21 @@ void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep,
|
||||
sprintf(buf, "<%u", code);
|
||||
decl += buf;
|
||||
} else {
|
||||
decl += stringCode(code);
|
||||
// Add string code to decl
|
||||
char* const endp = writeCode(buf, code);
|
||||
*endp = '\0';
|
||||
decl += buf;
|
||||
// Build suffix array entry
|
||||
char* const entryp = &m_suffixes[code * VL_TRACE_SUFFIX_ENTRY_SIZE];
|
||||
const size_t length = endp - buf;
|
||||
assert(length <= VL_TRACE_MAX_VCD_CODE_SIZE);
|
||||
// 1 bit values don't have a ' ' separator between value and string code
|
||||
const bool isBit = bits == 1;
|
||||
entryp[0] = ' '; // Separator
|
||||
std::strcpy(entryp + !isBit, buf); // Code (overwrite separator if isBit)
|
||||
entryp[length + !isBit] = '\n'; // Replace '\0' with line termination '\n'
|
||||
// Set length of suffix (used to increment write pointer)
|
||||
entryp[VL_TRACE_SUFFIX_ENTRY_SIZE - 1] = !isBit + length + 1;
|
||||
}
|
||||
decl += " ";
|
||||
decl += basename;
|
||||
@ -633,6 +685,13 @@ void VerilatedVcd::declArray(vluint32_t code, const char* name, bool array, int
|
||||
int lsb) {
|
||||
declare(code, name, "wire", array, arraynum, false, true, msb, lsb);
|
||||
}
|
||||
void VerilatedVcd::declFloat(vluint32_t code, const char* name, bool array, int arraynum) {
|
||||
declare(code, name, "real", array, arraynum, false, false, 31, 0);
|
||||
}
|
||||
void VerilatedVcd::declDouble(vluint32_t code, const char* name, bool array, int arraynum) {
|
||||
declare(code, name, "real", array, arraynum, false, false, 63, 0);
|
||||
}
|
||||
#ifndef VL_TRACE_VCD_OLD_API
|
||||
void VerilatedVcd::declTriBit(vluint32_t code, const char* name, bool array, int arraynum) {
|
||||
declare(code, name, "wire", array, arraynum, true, false, 0, 0);
|
||||
}
|
||||
@ -648,20 +707,234 @@ void VerilatedVcd::declTriArray(vluint32_t code, const char* name, bool array, i
|
||||
int msb, int lsb) {
|
||||
declare(code, name, "wire", array, arraynum, true, true, msb, lsb);
|
||||
}
|
||||
void VerilatedVcd::declFloat(vluint32_t code, const char* name, bool array, int arraynum) {
|
||||
declare(code, name, "real", array, arraynum, false, false, 31, 0);
|
||||
}
|
||||
void VerilatedVcd::declDouble(vluint32_t code, const char* name, bool array, int arraynum) {
|
||||
declare(code, name, "real", array, arraynum, false, false, 63, 0);
|
||||
}
|
||||
#endif // VL_TRACE_VCD_OLD_API
|
||||
|
||||
//=============================================================================
|
||||
// Trace recording routines
|
||||
|
||||
#ifndef VL_TRACE_VCD_OLD_API
|
||||
|
||||
//=============================================================================
|
||||
// Pointer based variants used by Verilator
|
||||
|
||||
// Emit suffix, write back write pointer, check buffer
|
||||
void VerilatedVcd::finishLine(vluint32_t* oldp, char* writep) {
|
||||
const vluint32_t code = oldp - m_sigs_oldvalp;
|
||||
const char* const suffixp = m_suffixesp + code * VL_TRACE_SUFFIX_ENTRY_SIZE;
|
||||
// Copy the whole suffix (this avoid having hard to predict branches which
|
||||
// helps a lot). Note suffixp could be aligned, so could load it in one go,
|
||||
// but then we would be endiannes dependent which we don't have a way to
|
||||
// test right now and probably would make little difference...
|
||||
// Note: The maximum length of the suffix is
|
||||
// VL_TRACE_MAX_VCD_CODE_SIZE + 2 == 7, but we unroll this here for speed.
|
||||
writep[0] = suffixp[0];
|
||||
writep[1] = suffixp[1];
|
||||
writep[2] = suffixp[2];
|
||||
writep[3] = suffixp[3];
|
||||
writep[4] = suffixp[4];
|
||||
writep[5] = suffixp[5];
|
||||
writep[6] = '\n'; // The 6th index is always '\n' if it's relevant, no need to fetch it.
|
||||
// Now write back the write pointer incremented by the actual size of the
|
||||
// suffix, which was stored in the last byte of the suffix buffer entry.
|
||||
m_writep = writep + suffixp[VL_TRACE_SUFFIX_ENTRY_SIZE - 1];
|
||||
bufferCheck();
|
||||
}
|
||||
|
||||
void VerilatedVcd::fullBit(vluint32_t* oldp, vluint32_t newval) {
|
||||
*oldp = newval;
|
||||
char* wp = m_writep;
|
||||
*wp++ = '0' | static_cast<char>(newval);
|
||||
finishLine(oldp, wp);
|
||||
}
|
||||
|
||||
// We do want these functions specialized for sizes to avoid hard to predict
|
||||
// branches, but we don't want them inlined, so we explicitly create one
|
||||
// specialization for each size used here here.
|
||||
|
||||
// T_Bits is the number of used bits in the value
|
||||
template <int T_Bits> void VerilatedVcd::fullBus(vluint32_t* oldp, vluint32_t newval) {
|
||||
*oldp = newval;
|
||||
char* wp = m_writep;
|
||||
*wp++ = 'b';
|
||||
newval <<= 32 - T_Bits;
|
||||
int bits = T_Bits;
|
||||
do {
|
||||
*wp++ = '0' | static_cast<char>(newval >> 31);
|
||||
newval <<= 1;
|
||||
} while (--bits);
|
||||
finishLine(oldp, wp);
|
||||
}
|
||||
// Note: No specialization for width 1, covered by 'fullBit'
|
||||
template void VerilatedVcd::fullBus<2>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<3>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<4>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<5>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<6>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<7>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<8>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<9>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<10>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<11>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<12>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<13>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<14>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<15>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<16>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<17>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<18>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<19>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<20>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<21>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<22>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<23>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<24>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<25>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<26>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<27>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<28>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<29>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<30>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<31>(vluint32_t* oldp, vluint32_t newval);
|
||||
template void VerilatedVcd::fullBus<32>(vluint32_t* oldp, vluint32_t newval);
|
||||
|
||||
// T_Bits is the number of used bits in the value
|
||||
void VerilatedVcd::fullQuad(vluint32_t* oldp, vluint64_t newval, int bits) {
|
||||
*reinterpret_cast<vluint64_t*>(oldp) = newval;
|
||||
char* wp = m_writep;
|
||||
*wp++ = 'b';
|
||||
newval <<= 64 - bits;
|
||||
// Handle the top 32 bits within the 64 bit input
|
||||
const int bitsInTopHalf = bits - 32;
|
||||
wp += bitsInTopHalf;
|
||||
// clang-format off
|
||||
switch (bitsInTopHalf) {
|
||||
case 32: wp[-32] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 31: wp[-31] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 30: wp[-30] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 29: wp[-29] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 28: wp[-28] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 27: wp[-27] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 26: wp[-26] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 25: wp[-25] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 24: wp[-24] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 23: wp[-23] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 22: wp[-22] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 21: wp[-21] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 20: wp[-20] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 19: wp[-19] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 18: wp[-18] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 17: wp[-17] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 16: wp[-16] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 15: wp[-15] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 14: wp[-14] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 13: wp[-13] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 12: wp[-12] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 11: wp[-11] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 10: wp[-10] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 9: wp[ -9] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 8: wp[ -8] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 7: wp[ -7] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 6: wp[ -6] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 5: wp[ -5] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 4: wp[ -4] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 3: wp[ -3] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 2: wp[ -2] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
case 1: wp[ -1] = '0' | static_cast<char>(newval >> 63); newval<<=1; //FALLTHRU
|
||||
}
|
||||
// clang-format on
|
||||
// Handle the bottom 32 bits within the 64 bit input
|
||||
int remaining = 32;
|
||||
do {
|
||||
*wp++ = '0' | static_cast<char>(newval >> 63);
|
||||
newval <<= 1;
|
||||
} while (--remaining);
|
||||
finishLine(oldp, wp);
|
||||
}
|
||||
|
||||
void VerilatedVcd::fullArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) {
|
||||
int words = (bits + 31) / 32;
|
||||
for (int i = 0; i < words; ++i) oldp[i] = newvalp[i];
|
||||
char* wp = m_writep;
|
||||
*wp++ = 'b';
|
||||
// Handle the most significant word
|
||||
const int bitsInMSW = bits % 32 == 0 ? 32 : bits % 32;
|
||||
vluint32_t val = newvalp[--words] << (32 - bitsInMSW);
|
||||
wp += bitsInMSW;
|
||||
// clang-format off
|
||||
switch (bitsInMSW) {
|
||||
case 32: wp[-32] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 31: wp[-31] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 30: wp[-30] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 29: wp[-29] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 28: wp[-28] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 27: wp[-27] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 26: wp[-26] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 25: wp[-25] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 24: wp[-24] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 23: wp[-23] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 22: wp[-22] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 21: wp[-21] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 20: wp[-20] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 19: wp[-19] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 18: wp[-18] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 17: wp[-17] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 16: wp[-16] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 15: wp[-15] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 14: wp[-14] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 13: wp[-13] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 12: wp[-12] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 11: wp[-11] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 10: wp[-10] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 9: wp[ -9] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 8: wp[ -8] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 7: wp[ -7] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 6: wp[ -6] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 5: wp[ -5] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 4: wp[ -4] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 3: wp[ -3] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 2: wp[ -2] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
case 1: wp[ -1] = '0' | static_cast<char>(val >> 31); val<<=1; //FALLTHRU
|
||||
}
|
||||
// clang-format on
|
||||
// Handle the remaining words
|
||||
while (words > 0) {
|
||||
vluint32_t val = newvalp[--words];
|
||||
int bits = 32;
|
||||
do {
|
||||
*wp++ = '0' | static_cast<char>(val >> 31);
|
||||
val <<= 1;
|
||||
} while (--bits);
|
||||
}
|
||||
finishLine(oldp, wp);
|
||||
}
|
||||
|
||||
void VerilatedVcd::fullFloat(vluint32_t* oldp, float newval) {
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
*reinterpret_cast<float*>(oldp) = newval;
|
||||
char* wp = m_writep;
|
||||
// Buffer can't overflow before sprintf; we sized during declaration
|
||||
sprintf(wp, "r%.16g", static_cast<double>(newval));
|
||||
wp += strlen(wp);
|
||||
finishLine(oldp, wp);
|
||||
}
|
||||
|
||||
void VerilatedVcd::fullDouble(vluint32_t* oldp, double newval) {
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
*reinterpret_cast<double*>(oldp) = newval;
|
||||
char* wp = m_writep;
|
||||
// Buffer can't overflow before sprintf; we sized during declaration
|
||||
sprintf(wp, "r%.16g", newval);
|
||||
wp += strlen(wp);
|
||||
finishLine(oldp, wp);
|
||||
}
|
||||
|
||||
#else // VL_TRACE_VCD_OLD_API
|
||||
|
||||
void VerilatedVcd::fullBit(vluint32_t code, const vluint32_t newval) {
|
||||
// Note the &1, so we don't require clean input -- makes more common no change case faster
|
||||
m_sigs_oldvalp[code] = newval;
|
||||
*m_writep++ = ('0' + static_cast<char>(newval & 1));
|
||||
printCode(code);
|
||||
m_writep = writeCode(m_writep, code);
|
||||
*m_writep++ = '\n';
|
||||
bufferCheck();
|
||||
}
|
||||
@ -672,7 +945,7 @@ void VerilatedVcd::fullBus(vluint32_t code, const vluint32_t newval, int bits) {
|
||||
*m_writep++ = ((newval & (1L << bit)) ? '1' : '0');
|
||||
}
|
||||
*m_writep++ = ' ';
|
||||
printCode(code);
|
||||
m_writep = writeCode(m_writep, code);
|
||||
*m_writep++ = '\n';
|
||||
bufferCheck();
|
||||
}
|
||||
@ -683,7 +956,7 @@ void VerilatedVcd::fullQuad(vluint32_t code, const vluint64_t newval, int bits)
|
||||
*m_writep++ = ((newval & (VL_ULL(1) << bit)) ? '1' : '0');
|
||||
}
|
||||
*m_writep++ = ' ';
|
||||
printCode(code);
|
||||
m_writep = writeCode(m_writep, code);
|
||||
*m_writep++ = '\n';
|
||||
bufferCheck();
|
||||
}
|
||||
@ -696,7 +969,7 @@ void VerilatedVcd::fullArray(vluint32_t code, const vluint32_t* newval, int bits
|
||||
*m_writep++ = ((newval[(bit / 32)] & (1L << (bit & 0x1f))) ? '1' : '0');
|
||||
}
|
||||
*m_writep++ = ' ';
|
||||
printCode(code);
|
||||
m_writep = writeCode(m_writep, code);
|
||||
*m_writep++ = '\n';
|
||||
bufferCheck();
|
||||
}
|
||||
@ -709,7 +982,7 @@ void VerilatedVcd::fullArray(vluint32_t code, const vluint64_t* newval, int bits
|
||||
*m_writep++ = ((newval[(bit / 64)] & (VL_ULL(1) << (bit & 0x3f))) ? '1' : '0');
|
||||
}
|
||||
*m_writep++ = ' ';
|
||||
printCode(code);
|
||||
m_writep = writeCode(m_writep, code);
|
||||
*m_writep++ = '\n';
|
||||
bufferCheck();
|
||||
}
|
||||
@ -717,11 +990,12 @@ void VerilatedVcd::fullTriBit(vluint32_t code, const vluint32_t newval, const vl
|
||||
m_sigs_oldvalp[code] = newval;
|
||||
m_sigs_oldvalp[code + 1] = newtri;
|
||||
*m_writep++ = "01zz"[m_sigs_oldvalp[code] | (m_sigs_oldvalp[code + 1] << 1)];
|
||||
printCode(code);
|
||||
m_writep = writeCode(m_writep, code);
|
||||
*m_writep++ = '\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void VerilatedVcd::fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits) {
|
||||
void VerilatedVcd::fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri,
|
||||
int bits) {
|
||||
m_sigs_oldvalp[code] = newval;
|
||||
m_sigs_oldvalp[code + 1] = newtri;
|
||||
*m_writep++ = 'b';
|
||||
@ -729,25 +1003,26 @@ void VerilatedVcd::fullTriBus(vluint32_t code, const vluint32_t newval, const vl
|
||||
*m_writep++ = "01zz"[((newval >> bit) & 1) | (((newtri >> bit) & 1) << 1)];
|
||||
}
|
||||
*m_writep++ = ' ';
|
||||
printCode(code);
|
||||
m_writep = writeCode(m_writep, code);
|
||||
*m_writep++ = '\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void VerilatedVcd::fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits) {
|
||||
void VerilatedVcd::fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri,
|
||||
int bits) {
|
||||
(*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[code]))) = newval;
|
||||
(*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[code + 1]))) = newtri;
|
||||
*m_writep++ = 'b';
|
||||
for (int bit = bits - 1; bit >= 0; --bit) {
|
||||
*m_writep++ = "01zz"[((newval >> bit) & VL_ULL(1))
|
||||
| (((newtri >> bit) & VL_ULL(1)) << VL_ULL(1))];
|
||||
*m_writep++
|
||||
= "01zz"[((newval >> bit) & VL_ULL(1)) | (((newtri >> bit) & VL_ULL(1)) << VL_ULL(1))];
|
||||
}
|
||||
*m_writep++ = ' ';
|
||||
printCode(code);
|
||||
m_writep = writeCode(m_writep, code);
|
||||
*m_writep++ = '\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void VerilatedVcd::fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip,
|
||||
int bits) {
|
||||
void VerilatedVcd::fullTriArray(vluint32_t code, const vluint32_t* newvalp,
|
||||
const vluint32_t* newtrip, int bits) {
|
||||
for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) {
|
||||
m_sigs_oldvalp[code + word * 2] = newvalp[word];
|
||||
m_sigs_oldvalp[code + word * 2 + 1] = newtrip[word];
|
||||
@ -759,7 +1034,7 @@ void VerilatedVcd::fullTriArray(vluint32_t code, const vluint32_t* newvalp, cons
|
||||
*m_writep++ = "01zz"[valbit | (tribit << 1)];
|
||||
}
|
||||
*m_writep++ = ' ';
|
||||
printCode(code);
|
||||
m_writep = writeCode(m_writep, code);
|
||||
*m_writep++ = '\n';
|
||||
bufferCheck();
|
||||
}
|
||||
@ -770,7 +1045,7 @@ void VerilatedVcd::fullDouble(vluint32_t code, const double newval) {
|
||||
sprintf(m_writep, "r%.16g", newval);
|
||||
m_writep += strlen(m_writep);
|
||||
*m_writep++ = ' ';
|
||||
printCode(code);
|
||||
m_writep = writeCode(m_writep, code);
|
||||
*m_writep++ = '\n';
|
||||
bufferCheck();
|
||||
}
|
||||
@ -781,29 +1056,29 @@ void VerilatedVcd::fullFloat(vluint32_t code, const float newval) {
|
||||
sprintf(m_writep, "r%.16g", static_cast<double>(newval));
|
||||
m_writep += strlen(m_writep);
|
||||
*m_writep++ = ' ';
|
||||
printCode(code);
|
||||
m_writep = writeCode(m_writep, code);
|
||||
*m_writep++ = '\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void VerilatedVcd::fullBitX(vluint32_t code) {
|
||||
*m_writep++ = 'x';
|
||||
printCode(code);
|
||||
m_writep = writeCode(m_writep, code);
|
||||
*m_writep++ = '\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void VerilatedVcd::fullBusX(vluint32_t code, int bits) {
|
||||
*m_writep++ = 'b';
|
||||
for (int bit = bits - 1; bit >= 0; --bit) {
|
||||
*m_writep++ = 'x';
|
||||
}
|
||||
for (int bit = bits - 1; bit >= 0; --bit) *m_writep++ = 'x';
|
||||
*m_writep++ = ' ';
|
||||
printCode(code);
|
||||
m_writep = writeCode(m_writep, code);
|
||||
*m_writep++ = '\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void VerilatedVcd::fullQuadX(vluint32_t code, int bits) { fullBusX(code, bits); }
|
||||
void VerilatedVcd::fullArrayX(vluint32_t code, int bits) { fullBusX(code, bits); }
|
||||
|
||||
#endif // VL_TRACE_VCD_OLD_API
|
||||
|
||||
//=============================================================================
|
||||
// Callbacks
|
||||
|
||||
@ -867,6 +1142,8 @@ void VerilatedVcd::flush_all() VL_MT_UNSAFE_ONE { VerilatedVcdSingleton::flush_a
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
|
||||
// clang-format off
|
||||
|
||||
#ifdef VERILATED_VCD_TEST
|
||||
#include <iostream>
|
||||
|
||||
|
@ -97,6 +97,9 @@ private:
|
||||
vluint64_t m_wrChunkSize; ///< Output buffer size
|
||||
vluint64_t m_wroteBytes; ///< Number of bytes written to this file
|
||||
|
||||
std::vector<char> m_suffixes; ///< VCD line end string codes + metadata
|
||||
const char* m_suffixesp; ///< Pointer to first element of above
|
||||
|
||||
vluint32_t* m_sigs_oldvalp; ///< Pointer to old signal values
|
||||
typedef std::vector<VerilatedVcdSig> SigVec;
|
||||
SigVec m_sigs; ///< Pointer to signal information
|
||||
@ -131,26 +134,9 @@ private:
|
||||
void dumpFull(vluint64_t timeui);
|
||||
// cppcheck-suppress functionConst
|
||||
void dumpDone();
|
||||
inline void printCode(vluint32_t code) {
|
||||
*m_writep++ = static_cast<char>('!' + code % 94);
|
||||
code /= 94;
|
||||
while (code) {
|
||||
code--;
|
||||
*m_writep++ = static_cast<char>('!' + code % 94);
|
||||
code /= 94;
|
||||
}
|
||||
}
|
||||
static std::string stringCode(vluint32_t code) VL_PURE {
|
||||
std::string out;
|
||||
out += static_cast<char>('!' + code % 94);
|
||||
code /= 94;
|
||||
while (code) {
|
||||
code--;
|
||||
out += static_cast<char>('!' + code % 94);
|
||||
code /= 94;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
char* writeCode(char* writep, vluint32_t code);
|
||||
|
||||
void finishLine(vluint32_t* oldp, char* writep);
|
||||
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedVcd);
|
||||
@ -206,27 +192,116 @@ public:
|
||||
void declBus(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||
void declQuad(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||
void declArray(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||
void declFloat(vluint32_t code, const char* name, bool array, int arraynum);
|
||||
void declDouble(vluint32_t code, const char* name, bool array, int arraynum);
|
||||
#ifndef VL_TRACE_VCD_OLD_API
|
||||
void declTriBit(vluint32_t code, const char* name, bool array, int arraynum);
|
||||
void declTriBus(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||
void declTriQuad(vluint32_t code, const char* name, bool array, int arraynum, int msb,
|
||||
int lsb);
|
||||
void declTriArray(vluint32_t code, const char* name, bool array, int arraynum, int msb,
|
||||
int lsb);
|
||||
void declDouble(vluint32_t code, const char* name, bool array, int arraynum);
|
||||
void declFloat(vluint32_t code, const char* name, bool array, int arraynum);
|
||||
#endif // VL_TRACE_VCD_OLD_API
|
||||
// ... other module_start for submodules (based on cell name)
|
||||
|
||||
//=========================================================================
|
||||
// Inside dumping routines used by Verilator
|
||||
|
||||
vluint32_t* oldp(vluint32_t code) { return m_sigs_oldvalp + code; }
|
||||
|
||||
#ifndef VL_TRACE_VCD_OLD_API
|
||||
|
||||
//=========================================================================
|
||||
// Write back to previous value buffer value and emit
|
||||
|
||||
void fullBit(vluint32_t* oldp, vluint32_t newval);
|
||||
template <int T_Bits> void fullBus(vluint32_t* oldp, vluint32_t newval);
|
||||
void fullQuad(vluint32_t* oldp, vluint64_t newval, int bits);
|
||||
void fullArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits);
|
||||
void fullFloat(vluint32_t* oldp, float newval);
|
||||
void fullDouble(vluint32_t* oldp, double newval);
|
||||
|
||||
//=========================================================================
|
||||
// Check previous value and emit if changed
|
||||
|
||||
inline void chgBit(vluint32_t* oldp, vluint32_t newval) {
|
||||
const vluint32_t diff = *oldp ^ newval;
|
||||
if (VL_UNLIKELY(diff)) fullBit(oldp, newval);
|
||||
}
|
||||
template <int T_Bits> inline void chgBus(vluint32_t* oldp, vluint32_t newval) {
|
||||
const vluint32_t diff = *oldp ^ newval;
|
||||
if (VL_UNLIKELY(diff)) fullBus<T_Bits>(oldp, newval);
|
||||
}
|
||||
inline void chgQuad(vluint32_t* oldp, vluint64_t newval, int bits) {
|
||||
const vluint64_t diff = *reinterpret_cast<vluint64_t*>(oldp) ^ newval;
|
||||
if (VL_UNLIKELY(diff)) fullQuad(oldp, newval, bits);
|
||||
}
|
||||
inline void chgArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) {
|
||||
for (int i = 0; i < (bits + 31) / 32; ++i) {
|
||||
if (VL_UNLIKELY(oldp[i] ^ newvalp[i])) {
|
||||
fullArray(oldp, newvalp, bits);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void chgFloat(vluint32_t* oldp, float newval) {
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
if (VL_UNLIKELY(*reinterpret_cast<float*>(oldp) != newval)) fullFloat(oldp, newval);
|
||||
}
|
||||
inline void chgDouble(vluint32_t* oldp, double newval) {
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
if (VL_UNLIKELY(*reinterpret_cast<double*>(oldp) != newval)) fullDouble(oldp, newval);
|
||||
}
|
||||
|
||||
#else // VL_TRACE_VCD_OLD_API
|
||||
|
||||
// Note: These are only for testing for backward compatibility. Verilator
|
||||
// should use the more efficient versions above.
|
||||
|
||||
//=========================================================================
|
||||
// Write back to previous value buffer value and emit
|
||||
|
||||
void fullBit(vluint32_t* oldp, vluint32_t newval) { fullBit(oldp - m_sigs_oldvalp, newval); }
|
||||
template <int T_Bits> void fullBus(vluint32_t* oldp, vluint32_t newval) {
|
||||
fullBus(oldp - m_sigs_oldvalp, newval, T_Bits);
|
||||
}
|
||||
void fullQuad(vluint32_t* oldp, vluint64_t newval, int bits) {
|
||||
fullQuad(oldp - m_sigs_oldvalp, newval, bits);
|
||||
}
|
||||
void fullArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) {
|
||||
fullArray(oldp - m_sigs_oldvalp, newvalp, bits);
|
||||
}
|
||||
void fullFloat(vluint32_t* oldp, float newval) { fullFloat(oldp - m_sigs_oldvalp, newval); }
|
||||
void fullDouble(vluint32_t* oldp, double newval) { fullDouble(oldp - m_sigs_oldvalp, newval); }
|
||||
|
||||
//=========================================================================
|
||||
// Check previous value and emit if changed
|
||||
|
||||
void chgBit(vluint32_t* oldp, vluint32_t newval) { chgBit(oldp - m_sigs_oldvalp, newval); }
|
||||
template <int T_Bits> void chgBus(vluint32_t* oldp, vluint32_t newval) {
|
||||
chgBus(oldp - m_sigs_oldvalp, newval, T_Bits);
|
||||
}
|
||||
void chgQuad(vluint32_t* oldp, vluint64_t newval, int bits) {
|
||||
chgQuad(oldp - m_sigs_oldvalp, newval, bits);
|
||||
}
|
||||
void chgArray(vluint32_t* oldp, const vluint32_t* newvalp, int bits) {
|
||||
chgArray(oldp - m_sigs_oldvalp, newvalp, bits);
|
||||
}
|
||||
void chgFloat(vluint32_t* oldp, float newval) { chgFloat(oldp - m_sigs_oldvalp, newval); }
|
||||
void chgDouble(vluint32_t* oldp, double newval) { chgDouble(oldp - m_sigs_oldvalp, newval); }
|
||||
|
||||
/// Inside dumping routines, dump one signal, faster when not inlined
|
||||
/// due to code size reduction.
|
||||
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 fullArray(vluint32_t code, const vluint64_t* newval, int bits);
|
||||
void fullArray(vluint32_t code, const vluint32_t* newvalp, int bits);
|
||||
void fullArray(vluint32_t code, const vluint64_t* newvalp, 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 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);
|
||||
|
||||
@ -243,9 +318,7 @@ public:
|
||||
/// We do want to inline these to avoid calls when the value did not change.
|
||||
inline void chgBit(vluint32_t code, const vluint32_t newval) {
|
||||
vluint32_t diff = m_sigs_oldvalp[code] ^ newval;
|
||||
if (VL_UNLIKELY(diff)) {
|
||||
fullBit(code, newval);
|
||||
}
|
||||
if (VL_UNLIKELY(diff)) fullBit(code, newval);
|
||||
}
|
||||
inline void chgBus(vluint32_t code, const vluint32_t newval, int bits) {
|
||||
vluint32_t diff = m_sigs_oldvalp[code] ^ newval;
|
||||
@ -263,18 +336,18 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void chgArray(vluint32_t code, const vluint32_t* newval, int bits) {
|
||||
inline void chgArray(vluint32_t code, const vluint32_t* newvalp, int bits) {
|
||||
for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) {
|
||||
if (VL_UNLIKELY(m_sigs_oldvalp[code + word] ^ newval[word])) {
|
||||
fullArray(code, newval, bits);
|
||||
if (VL_UNLIKELY(m_sigs_oldvalp[code + word] ^ newvalp[word])) {
|
||||
fullArray(code, newvalp, bits);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void chgArray(vluint32_t code, const vluint64_t* newval, int bits) {
|
||||
inline void chgArray(vluint32_t code, const vluint64_t* newvalp, int bits) {
|
||||
for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) {
|
||||
if (VL_UNLIKELY(m_sigs_oldvalp[code + word] ^ newval[word])) {
|
||||
fullArray(code, newval, bits);
|
||||
if (VL_UNLIKELY(m_sigs_oldvalp[code + word] ^ newvalp[word])) {
|
||||
fullArray(code, newvalp, bits);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -332,6 +405,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
#endif // VL_TRACE_VCD_OLD_API
|
||||
|
||||
protected:
|
||||
// METHODS
|
||||
void evcd(bool flag) { m_evcd = flag; }
|
||||
|
@ -3100,6 +3100,7 @@ class EmitCTrace : EmitCStmts {
|
||||
AstCFunc* m_funcp; // Function we're in now
|
||||
bool m_slow; // Making slow file
|
||||
int m_enumNum; // Enumeration number (whole netlist)
|
||||
int m_baseCode; // Code of first AstTraceInc in this function
|
||||
|
||||
// METHODS
|
||||
void newOutCFile(int filenum) {
|
||||
@ -3380,28 +3381,24 @@ class EmitCTrace : EmitCStmts {
|
||||
? "full":"chg");
|
||||
bool emitWidth = false;
|
||||
if (nodep->dtypep()->basicp()->isDouble()) {
|
||||
puts("vcdp->"+full+"Double");
|
||||
puts("vcdp->" + full + "Double");
|
||||
} else if (nodep->isWide() || emitTraceIsScBv(nodep) || emitTraceIsScBigUint(nodep)) {
|
||||
puts("vcdp->"+full+"Array");
|
||||
puts("vcdp->" + full + "Array");
|
||||
emitWidth = true;
|
||||
} else if (nodep->isQuad()) {
|
||||
puts("vcdp->"+full+"Quad");
|
||||
emitWidth = true;
|
||||
} else if (nodep->declp()->bitRange().ranged()
|
||||
// 1 element smaller to use Bit dump
|
||||
&& nodep->declp()->bitRange().elements() != 1) {
|
||||
puts("vcdp->"+full+"Bus");
|
||||
puts("vcdp->" + full + "Quad");
|
||||
emitWidth = true;
|
||||
} else if (nodep->declp()->widthMin() > 1) {
|
||||
puts("vcdp->" + full + "Bus<" + cvtToStr(nodep->declp()->widthMin()) + ">");
|
||||
} else {
|
||||
puts("vcdp->"+full+"Bit");
|
||||
puts("vcdp->" + full + "Bit");
|
||||
}
|
||||
puts("(c+"+cvtToStr(nodep->declp()->code()
|
||||
+ ((arrayindex<0) ? 0 : (arrayindex*nodep->declp()->widthWords()))));
|
||||
puts(",");
|
||||
|
||||
const uint32_t offset = (arrayindex < 0) ? 0 : (arrayindex * nodep->declp()->widthWords());
|
||||
const uint32_t code = nodep->declp()->code() + offset;
|
||||
puts("(oldp+" + cvtToStr(code - m_baseCode) + ",");
|
||||
emitTraceValue(nodep, arrayindex);
|
||||
if (emitWidth) {
|
||||
puts(","+cvtToStr(nodep->declp()->widthMin()));
|
||||
}
|
||||
if (emitWidth) puts("," + cvtToStr(nodep->declp()->widthMin()));
|
||||
puts(");\n");
|
||||
}
|
||||
void emitTraceValue(AstTraceInc* nodep, int arrayindex) {
|
||||
@ -3460,8 +3457,24 @@ class EmitCTrace : EmitCStmts {
|
||||
|
||||
if (nodep->symProlog()) puts(EmitCBaseVisitor::symTopAssign()+"\n");
|
||||
|
||||
puts("int c = code;\n");
|
||||
puts("if (false && vcdp && c) {} // Prevent unused\n");
|
||||
m_baseCode = -1;
|
||||
|
||||
if (nodep->funcType() == AstCFuncType::TRACE_FULL_SUB
|
||||
|| nodep->funcType() == AstCFuncType::TRACE_CHANGE_SUB) {
|
||||
const AstTraceInc* const stmtp = VN_CAST_CONST(nodep->stmtsp(), TraceInc);
|
||||
if (!stmtp) {
|
||||
nodep->stmtsp()->v3fatalSrc("Trace sub function should contain AstTraceInc");
|
||||
}
|
||||
m_baseCode = stmtp->declp()->code();
|
||||
puts("vluint32_t* oldp = vcdp->oldp(code+" + cvtToStr(m_baseCode) + ");\n");
|
||||
puts("if (false && vcdp && oldp) {} // Prevent unused\n");
|
||||
} else if (nodep->funcType() == AstCFuncType::TRACE_INIT_SUB) {
|
||||
puts("int c = code;\n");
|
||||
puts("if (false && vcdp && c) {} // Prevent unused\n");
|
||||
} else {
|
||||
puts("if (false && vcdp) {} // Prevent unused\n");
|
||||
}
|
||||
|
||||
if (nodep->funcType() == AstCFuncType::TRACE_INIT) {
|
||||
puts("vcdp->module(vlSymsp->name()); // Setup signal names\n");
|
||||
} else if (nodep->funcType() == AstCFuncType::TRACE_INIT_SUB) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
$date
|
||||
Tue Jan 21 18:08:49 2020
|
||||
Sun Apr 12 20:15:55 2020
|
||||
|
||||
$end
|
||||
$version
|
||||
@ -101,7 +101,6 @@ b00000000000000000000000000000011 A
|
||||
#10
|
||||
b00000000000000000000000000000101 ?
|
||||
b00000000000000000000000000000101 >
|
||||
b000000 :
|
||||
b111 9
|
||||
b00000000000000000000000000000010 8
|
||||
b00000000000000000000000000000001 7
|
||||
@ -144,14 +143,10 @@ b00000000000000000000000000000010 7
|
||||
b00000000000000000000000000000100 8
|
||||
b110 9
|
||||
b111111 :
|
||||
b00000000000000000000000000000101 >
|
||||
b00000000000000000000000000000101 ?
|
||||
#25
|
||||
0!
|
||||
#30
|
||||
1!
|
||||
b00000000000000000000000000000101 ?
|
||||
b00000000000000000000000000000101 >
|
||||
b110110 :
|
||||
b101 9
|
||||
b00000000000000000000000000000110 8
|
||||
@ -194,14 +189,10 @@ b00000000000000000000000000000100 7
|
||||
b00000000000000000000000000001000 8
|
||||
b100 9
|
||||
b101101 :
|
||||
b00000000000000000000000000000101 >
|
||||
b00000000000000000000000000000101 ?
|
||||
#45
|
||||
0!
|
||||
#50
|
||||
1!
|
||||
b00000000000000000000000000000101 ?
|
||||
b00000000000000000000000000000101 >
|
||||
b100100 :
|
||||
b011 9
|
||||
b00000000000000000000000000001010 8
|
||||
@ -244,5 +235,3 @@ b00000000000000000000000000000110 7
|
||||
b00000000000000000000000000001100 8
|
||||
b010 9
|
||||
b011011 :
|
||||
b00000000000000000000000000000101 >
|
||||
b00000000000000000000000000000101 ?
|
||||
|
38
test_regress/t/t_trace_complex_old_api.pl
Executable file
38
test_regress/t/t_trace_complex_old_api.pl
Executable file
@ -0,0 +1,38 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003-2009 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.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
# Same test as t_trace_complex, but exercising the old VCD tracing API
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
top_filename("t/t_trace_complex.v");
|
||||
|
||||
compile(
|
||||
verilator_flags2 => ['--cc --trace -CFLAGS -DVL_TRACE_VCD_OLD_API'],
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_strp /);
|
||||
file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_strp_strp /);
|
||||
file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arrp /);
|
||||
file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arrp_arrp /);
|
||||
file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arrp_strp /);
|
||||
file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arru\(/);
|
||||
file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arru_arru\(/);
|
||||
file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arru_arrp\(/);
|
||||
file_grep ("$Self->{obj_dir}/simx.vcd", qr/ v_arru_strp\(/);
|
||||
|
||||
vcd_identical ("$Self->{obj_dir}/simx.vcd", "t/t_trace_complex.out");
|
||||
|
||||
ok(1);
|
||||
1;
|
@ -1,5 +1,5 @@
|
||||
$date
|
||||
Tue Jan 21 18:15:28 2020
|
||||
Sun Apr 12 20:17:15 2020
|
||||
|
||||
$end
|
||||
$version
|
||||
@ -101,7 +101,6 @@ b00000000000000000000000000000011 A
|
||||
#10
|
||||
b00000000000000000000000000000101 ?
|
||||
b00000000000000000000000000000101 >
|
||||
b000000 :
|
||||
b111 9
|
||||
b00000000000000000000000000000010 8
|
||||
b00000000000000000000000000000001 7
|
||||
@ -144,14 +143,10 @@ b00000000000000000000000000000010 7
|
||||
b00000000000000000000000000000100 8
|
||||
b110 9
|
||||
b111111 :
|
||||
b00000000000000000000000000000101 >
|
||||
b00000000000000000000000000000101 ?
|
||||
#25
|
||||
0!
|
||||
#30
|
||||
1!
|
||||
b00000000000000000000000000000101 ?
|
||||
b00000000000000000000000000000101 >
|
||||
b110110 :
|
||||
b101 9
|
||||
b00000000000000000000000000000110 8
|
||||
@ -194,14 +189,10 @@ b00000000000000000000000000000100 7
|
||||
b00000000000000000000000000001000 8
|
||||
b100 9
|
||||
b101101 :
|
||||
b00000000000000000000000000000101 >
|
||||
b00000000000000000000000000000101 ?
|
||||
#45
|
||||
0!
|
||||
#50
|
||||
1!
|
||||
b00000000000000000000000000000101 ?
|
||||
b00000000000000000000000000000101 >
|
||||
b100100 :
|
||||
b011 9
|
||||
b00000000000000000000000000001010 8
|
||||
@ -244,5 +235,3 @@ b00000000000000000000000000000110 7
|
||||
b00000000000000000000000000001100 8
|
||||
b010 9
|
||||
b011011 :
|
||||
b00000000000000000000000000000101 >
|
||||
b00000000000000000000000000000101 ?
|
||||
|
@ -1,5 +1,5 @@
|
||||
$date
|
||||
Tue Jan 21 18:55:14 2020
|
||||
Sun Apr 12 20:14:19 2020
|
||||
|
||||
$end
|
||||
$version
|
||||
@ -151,8 +151,6 @@ b00000000000000000000000000000000 L
|
||||
#10
|
||||
b00000000000000000000000000000101 L
|
||||
b00000000000000000000000000000101 K
|
||||
b000 G
|
||||
b000 F
|
||||
b111 E
|
||||
b00000000000000000000000000000010 D
|
||||
b00000000000000000000000000000001 C
|
||||
@ -218,18 +216,14 @@ b00000000000000000000000000000010 B
|
||||
b00000000000000000000000000000010 C
|
||||
b00000000000000000000000000000100 D
|
||||
b110 E
|
||||
b111 F
|
||||
b111 G
|
||||
b00000000000000000000000000000101 K
|
||||
b00000000000000000000000000000101 L
|
||||
b111 F
|
||||
#25
|
||||
0!
|
||||
#30
|
||||
1!
|
||||
b00000000000000000000000000000101 L
|
||||
b00000000000000000000000000000101 K
|
||||
b110 G
|
||||
b110 F
|
||||
b110 G
|
||||
b101 E
|
||||
b00000000000000000000000000000110 D
|
||||
b00000000000000000000000000000011 C
|
||||
@ -294,18 +288,14 @@ b00000000000000000000000000000100 B
|
||||
b00000000000000000000000000000100 C
|
||||
b00000000000000000000000000001000 D
|
||||
b100 E
|
||||
b101 F
|
||||
b101 G
|
||||
b00000000000000000000000000000101 K
|
||||
b00000000000000000000000000000101 L
|
||||
b101 F
|
||||
#45
|
||||
0!
|
||||
#50
|
||||
1!
|
||||
b00000000000000000000000000000101 L
|
||||
b00000000000000000000000000000101 K
|
||||
b100 G
|
||||
b100 F
|
||||
b100 G
|
||||
b011 E
|
||||
b00000000000000000000000000001010 D
|
||||
b00000000000000000000000000000101 C
|
||||
@ -370,7 +360,5 @@ b00000000000000000000000000000110 B
|
||||
b00000000000000000000000000000110 C
|
||||
b00000000000000000000000000001100 D
|
||||
b010 E
|
||||
b011 F
|
||||
b011 G
|
||||
b00000000000000000000000000000101 K
|
||||
b00000000000000000000000000000101 L
|
||||
b011 F
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
$date
|
||||
Sun Oct 21 21:56:54 2018
|
||||
Sun Apr 12 20:19:35 2020
|
||||
|
||||
$end
|
||||
$version
|
||||
@ -42,4 +42,3 @@ b00000000000000000000000000000011 "
|
||||
0!
|
||||
#40
|
||||
1!
|
||||
b00000000000000000000000000000011 "
|
||||
|
Loading…
Reference in New Issue
Block a user