2012-04-13 01:08:20 +00:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2010-01-24 23:37:01 +00:00
|
|
|
//=============================================================================
|
|
|
|
//
|
|
|
|
// THIS MODULE IS PUBLICLY LICENSED
|
|
|
|
//
|
2020-03-21 15:24:24 +00:00
|
|
|
// Copyright 2001-2020 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
|
2010-01-24 23:37:01 +00:00
|
|
|
//
|
|
|
|
//=============================================================================
|
|
|
|
///
|
|
|
|
/// \file
|
|
|
|
/// \brief C++ Tracing in VCD Format
|
|
|
|
///
|
|
|
|
//=============================================================================
|
|
|
|
// SPDIFF_OFF
|
|
|
|
|
2020-04-13 23:13:10 +00:00
|
|
|
// clang-format off
|
|
|
|
|
2010-01-24 23:37:01 +00:00
|
|
|
#include "verilatedos.h"
|
|
|
|
#include "verilated.h"
|
|
|
|
#include "verilated_vcd_c.h"
|
|
|
|
|
2018-10-14 11:04:18 +00:00
|
|
|
#include <algorithm>
|
2010-01-24 23:37:01 +00:00
|
|
|
#include <cerrno>
|
|
|
|
#include <ctime>
|
2018-10-14 11:04:18 +00:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/stat.h>
|
2010-01-24 23:37:01 +00:00
|
|
|
|
|
|
|
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
|
|
|
|
# include <io.h>
|
|
|
|
#else
|
|
|
|
# include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// SPDIFF_ON
|
|
|
|
|
2018-08-22 23:14:06 +00:00
|
|
|
#ifndef O_LARGEFILE // For example on WIN32
|
2010-01-24 23:37:01 +00:00
|
|
|
# define O_LARGEFILE 0
|
|
|
|
#endif
|
|
|
|
#ifndef O_NONBLOCK
|
|
|
|
# define O_NONBLOCK 0
|
|
|
|
#endif
|
2018-10-14 22:39:33 +00:00
|
|
|
#ifndef O_CLOEXEC
|
|
|
|
# define O_CLOEXEC 0
|
|
|
|
#endif
|
2010-01-24 23:37:01 +00:00
|
|
|
|
2020-04-13 23:13:10 +00:00
|
|
|
// 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
|
|
|
|
|
2020-04-19 22:57:36 +00:00
|
|
|
//=============================================================================
|
|
|
|
// Specialization of the generics for this trace format
|
|
|
|
|
|
|
|
#define VL_DERIVED_T VerilatedVcd
|
|
|
|
#include "verilated_trace_imp.cpp"
|
|
|
|
#undef VL_DERIVED_T
|
|
|
|
|
2017-10-14 17:00:25 +00:00
|
|
|
//=============================================================================
|
|
|
|
// VerilatedVcdImp
|
|
|
|
/// Base class to hold some static state
|
|
|
|
/// This is an internally used class
|
|
|
|
|
|
|
|
class VerilatedVcdSingleton {
|
|
|
|
private:
|
|
|
|
typedef std::vector<VerilatedVcd*> VcdVec;
|
|
|
|
struct Singleton {
|
2020-03-01 01:41:13 +00:00
|
|
|
VerilatedMutex s_vcdMutex; ///< Protect the singleton
|
|
|
|
VcdVec s_vcdVecp VL_GUARDED_BY(s_vcdMutex); ///< List of all created traces
|
2017-10-14 17:00:25 +00:00
|
|
|
};
|
2020-04-13 23:13:10 +00:00
|
|
|
static Singleton& singleton() {
|
|
|
|
static Singleton s;
|
|
|
|
return s;
|
|
|
|
}
|
2020-04-04 17:45:24 +00:00
|
|
|
|
2017-10-14 17:00:25 +00:00
|
|
|
public:
|
2017-10-27 01:51:51 +00:00
|
|
|
static void pushVcd(VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
|
2018-08-22 23:14:06 +00:00
|
|
|
VerilatedLockGuard lock(singleton().s_vcdMutex);
|
|
|
|
singleton().s_vcdVecp.push_back(vcdp);
|
2017-10-14 17:00:25 +00:00
|
|
|
}
|
2017-10-27 01:51:51 +00:00
|
|
|
static void removeVcd(const VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
|
2018-08-22 23:14:06 +00:00
|
|
|
VerilatedLockGuard lock(singleton().s_vcdMutex);
|
2020-04-04 17:45:24 +00:00
|
|
|
VcdVec::iterator pos
|
|
|
|
= find(singleton().s_vcdVecp.begin(), singleton().s_vcdVecp.end(), vcdp);
|
2018-08-22 23:14:06 +00:00
|
|
|
if (pos != singleton().s_vcdVecp.end()) { singleton().s_vcdVecp.erase(pos); }
|
2017-10-14 17:00:25 +00:00
|
|
|
}
|
2017-10-27 01:51:51 +00:00
|
|
|
static void flush_all() VL_EXCLUDES(singleton().s_vcdMutex) VL_MT_UNSAFE_ONE {
|
2019-05-15 02:49:21 +00:00
|
|
|
// Thread safety: Although this function is protected by a mutex so
|
|
|
|
// perhaps in the future we can allow tracing in separate threads,
|
|
|
|
// vcdp->flush() assumes call from single thread
|
2018-08-22 23:14:06 +00:00
|
|
|
VerilatedLockGuard lock(singleton().s_vcdMutex);
|
2019-05-15 02:49:21 +00:00
|
|
|
for (VcdVec::const_iterator it = singleton().s_vcdVecp.begin();
|
|
|
|
it != singleton().s_vcdVecp.end(); ++it) {
|
2018-08-22 23:14:06 +00:00
|
|
|
VerilatedVcd* vcdp = *it;
|
|
|
|
vcdp->flush();
|
|
|
|
}
|
2017-10-14 17:00:25 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-03-05 13:54:57 +00:00
|
|
|
//=============================================================================
|
|
|
|
//=============================================================================
|
|
|
|
//=============================================================================
|
|
|
|
// VerilatedVcdFile
|
|
|
|
|
2017-10-27 01:51:51 +00:00
|
|
|
bool VerilatedVcdFile::open(const std::string& name) VL_MT_UNSAFE {
|
2020-04-04 17:45:24 +00:00
|
|
|
m_fd = ::open(name.c_str(),
|
|
|
|
O_CREAT | O_WRONLY | O_TRUNC | O_LARGEFILE | O_NONBLOCK | O_CLOEXEC, 0666);
|
2020-03-02 02:39:23 +00:00
|
|
|
return m_fd >= 0;
|
2015-03-05 13:54:57 +00:00
|
|
|
}
|
|
|
|
|
2020-04-04 17:45:24 +00:00
|
|
|
void VerilatedVcdFile::close() VL_MT_UNSAFE { ::close(m_fd); }
|
2015-03-05 13:54:57 +00:00
|
|
|
|
2017-10-27 01:51:51 +00:00
|
|
|
ssize_t VerilatedVcdFile::write(const char* bufp, ssize_t len) VL_MT_UNSAFE {
|
2015-03-05 13:54:57 +00:00
|
|
|
return ::write(m_fd, bufp, len);
|
|
|
|
}
|
|
|
|
|
2010-01-24 23:37:01 +00:00
|
|
|
//=============================================================================
|
|
|
|
//=============================================================================
|
|
|
|
//=============================================================================
|
|
|
|
// Opening/Closing
|
|
|
|
|
2015-03-05 13:54:57 +00:00
|
|
|
VerilatedVcd::VerilatedVcd(VerilatedVcdFile* filep)
|
2020-03-02 02:39:23 +00:00
|
|
|
: m_isOpen(false)
|
|
|
|
, m_rolloverMB(0)
|
2020-04-19 22:57:36 +00:00
|
|
|
, m_modDepth(0) {
|
2015-03-05 13:54:57 +00:00
|
|
|
// Not in header to avoid link issue if header is included without this .cpp file
|
|
|
|
m_fileNewed = (filep == NULL);
|
|
|
|
m_filep = m_fileNewed ? new VerilatedVcdFile : filep;
|
|
|
|
m_namemapp = NULL;
|
|
|
|
m_evcd = false;
|
2020-04-04 17:45:24 +00:00
|
|
|
m_wrChunkSize = 8 * 1024;
|
|
|
|
m_wrBufp = new char[m_wrChunkSize * 8];
|
2015-03-05 13:54:57 +00:00
|
|
|
m_wrFlushp = m_wrBufp + m_wrChunkSize * 6;
|
|
|
|
m_writep = m_wrBufp;
|
|
|
|
m_wroteBytes = 0;
|
2020-04-13 23:13:10 +00:00
|
|
|
m_suffixesp = NULL;
|
2015-03-05 13:54:57 +00:00
|
|
|
}
|
|
|
|
|
2018-08-22 23:14:06 +00:00
|
|
|
void VerilatedVcd::open(const char* filename) {
|
2017-10-27 01:51:51 +00:00
|
|
|
m_assertOne.check();
|
2020-03-24 21:32:47 +00:00
|
|
|
if (isOpen()) return;
|
2010-01-24 23:37:01 +00:00
|
|
|
|
|
|
|
// Set member variables
|
2020-03-24 21:32:47 +00:00
|
|
|
m_filename = filename; // "" is ok, as someone may overload open
|
2017-10-14 17:00:25 +00:00
|
|
|
VerilatedVcdSingleton::pushVcd(this);
|
2010-01-24 23:37:01 +00:00
|
|
|
|
2010-03-13 01:00:08 +00:00
|
|
|
// SPDIFF_OFF
|
|
|
|
// Set callback so an early exit will flush us
|
|
|
|
Verilated::flushCb(&flush_all);
|
|
|
|
|
|
|
|
// SPDIFF_ON
|
2020-04-04 17:45:24 +00:00
|
|
|
openNext(m_rolloverMB != 0);
|
2010-01-24 23:37:01 +00:00
|
|
|
if (!isOpen()) return;
|
|
|
|
|
|
|
|
dumpHeader();
|
|
|
|
|
2020-04-13 23:13:10 +00:00
|
|
|
// Get the direct access pointer to the code strings
|
|
|
|
m_suffixesp = &m_suffixes[0]; // Note: C++11 m_suffixes.data();
|
|
|
|
|
2020-04-19 22:57:36 +00:00
|
|
|
// When using rollover, the first chunk contains the header only.
|
|
|
|
if (m_rolloverMB) openNext(true);
|
2010-01-24 23:37:01 +00:00
|
|
|
}
|
|
|
|
|
2018-08-22 23:14:06 +00:00
|
|
|
void VerilatedVcd::openNext(bool incFilename) {
|
2010-01-24 23:37:01 +00:00
|
|
|
// Open next filename in concat sequence, mangle filename if
|
|
|
|
// incFilename is true.
|
2017-10-27 01:51:51 +00:00
|
|
|
m_assertOne.check();
|
2018-08-22 23:14:06 +00:00
|
|
|
closePrev(); // Close existing
|
2010-01-24 23:37:01 +00:00
|
|
|
if (incFilename) {
|
2018-08-22 23:14:06 +00:00
|
|
|
// Find _0000.{ext} in filename
|
|
|
|
std::string name = m_filename;
|
2018-10-14 02:28:59 +00:00
|
|
|
size_t pos = name.rfind('.');
|
2020-04-04 17:45:24 +00:00
|
|
|
if (pos > 8 && 0 == strncmp("_cat", name.c_str() + pos - 8, 4)
|
2020-04-13 23:13:10 +00:00
|
|
|
&& isdigit(name.c_str()[pos - 4]) && isdigit(name.c_str()[pos - 3])
|
|
|
|
&& isdigit(name.c_str()[pos - 2]) && isdigit(name.c_str()[pos - 1])) {
|
2018-08-22 23:14:06 +00:00
|
|
|
// Increment code.
|
2020-04-04 17:45:24 +00:00
|
|
|
if ((++(name[pos - 1])) > '9') {
|
|
|
|
name[pos - 1] = '0';
|
|
|
|
if ((++(name[pos - 2])) > '9') {
|
|
|
|
name[pos - 2] = '0';
|
|
|
|
if ((++(name[pos - 3])) > '9') {
|
|
|
|
name[pos - 3] = '0';
|
|
|
|
if ((++(name[pos - 4])) > '9') { name[pos - 4] = '0'; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-08-22 23:14:06 +00:00
|
|
|
} else {
|
|
|
|
// Append _cat0000
|
2020-04-04 17:45:24 +00:00
|
|
|
name.insert(pos, "_cat0000");
|
2018-08-22 23:14:06 +00:00
|
|
|
}
|
|
|
|
m_filename = name;
|
2010-01-24 23:37:01 +00:00
|
|
|
}
|
2020-04-04 17:45:24 +00:00
|
|
|
if (m_filename[0] == '|') {
|
2018-08-22 23:14:06 +00:00
|
|
|
assert(0); // Not supported yet.
|
2010-01-24 23:37:01 +00:00
|
|
|
} else {
|
2018-08-22 23:14:06 +00:00
|
|
|
// cppcheck-suppress duplicateExpression
|
|
|
|
if (!m_filep->open(m_filename)) {
|
|
|
|
// User code can check isOpen()
|
|
|
|
m_isOpen = false;
|
|
|
|
return;
|
|
|
|
}
|
2010-01-24 23:37:01 +00:00
|
|
|
}
|
|
|
|
m_isOpen = true;
|
2020-04-19 22:57:36 +00:00
|
|
|
fullDump(true); // First dump must be full
|
2010-01-24 23:37:01 +00:00
|
|
|
m_wroteBytes = 0;
|
|
|
|
}
|
|
|
|
|
2020-04-19 22:57:36 +00:00
|
|
|
bool VerilatedVcd::preChangeDump() {
|
|
|
|
if (VL_UNLIKELY(m_rolloverMB && m_wroteBytes > m_rolloverMB)) { openNext(true); }
|
|
|
|
return isOpen();
|
|
|
|
}
|
|
|
|
|
|
|
|
void VerilatedVcd::emitTimeChange(vluint64_t timeui) {
|
|
|
|
printStr("#");
|
|
|
|
printQuad(timeui);
|
|
|
|
printStr("\n");
|
|
|
|
}
|
|
|
|
|
2010-03-22 22:38:24 +00:00
|
|
|
void VerilatedVcd::makeNameMap() {
|
|
|
|
// Take signal information from each module and build m_namemapp
|
2013-02-24 02:10:25 +00:00
|
|
|
deleteNameMap();
|
2010-03-22 22:38:24 +00:00
|
|
|
m_namemapp = new NameMap;
|
2020-04-19 22:57:36 +00:00
|
|
|
|
|
|
|
VerilatedTrace<VerilatedVcd>::traceInit();
|
2010-03-22 22:38:24 +00:00
|
|
|
|
|
|
|
// Though not speced, it's illegal to generate a vcd with signals
|
|
|
|
// not under any module - it crashes at least two viewers.
|
|
|
|
// If no scope was specified, prefix everything with a "top"
|
|
|
|
// This comes from user instantiations with no name - IE Vtop("").
|
|
|
|
bool nullScope = false;
|
2020-04-04 17:45:24 +00:00
|
|
|
for (NameMap::const_iterator it = m_namemapp->begin(); it != m_namemapp->end(); ++it) {
|
2018-08-22 23:14:06 +00:00
|
|
|
const std::string& hiername = it->first;
|
2020-04-04 17:45:24 +00:00
|
|
|
if (!hiername.empty() && hiername[0] == '\t') nullScope = true;
|
2010-03-22 22:38:24 +00:00
|
|
|
}
|
|
|
|
if (nullScope) {
|
2018-08-22 23:14:06 +00:00
|
|
|
NameMap* newmapp = new NameMap;
|
2020-04-04 17:45:24 +00:00
|
|
|
for (NameMap::const_iterator it = m_namemapp->begin(); it != m_namemapp->end(); ++it) {
|
2018-08-22 23:14:06 +00:00
|
|
|
const std::string& hiername = it->first;
|
2020-04-04 17:45:24 +00:00
|
|
|
const std::string& decl = it->second;
|
2018-08-22 23:14:06 +00:00
|
|
|
std::string newname = std::string("top");
|
|
|
|
if (hiername[0] != '\t') newname += ' ';
|
|
|
|
newname += hiername;
|
2020-04-04 17:45:24 +00:00
|
|
|
newmapp->insert(std::make_pair(newname, decl));
|
2018-08-22 23:14:06 +00:00
|
|
|
}
|
|
|
|
deleteNameMap();
|
|
|
|
m_namemapp = newmapp;
|
2010-03-22 22:38:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-24 02:10:25 +00:00
|
|
|
void VerilatedVcd::deleteNameMap() {
|
2020-04-04 17:06:31 +00:00
|
|
|
if (m_namemapp) VL_DO_CLEAR(delete m_namemapp, m_namemapp = NULL);
|
2013-02-24 02:10:25 +00:00
|
|
|
}
|
|
|
|
|
2010-01-24 23:37:01 +00:00
|
|
|
VerilatedVcd::~VerilatedVcd() {
|
|
|
|
close();
|
2020-04-04 17:06:31 +00:00
|
|
|
if (m_wrBufp) VL_DO_CLEAR(delete[] m_wrBufp, m_wrBufp = NULL);
|
2013-02-24 02:10:25 +00:00
|
|
|
deleteNameMap();
|
2020-04-04 17:06:31 +00:00
|
|
|
if (m_filep && m_fileNewed) VL_DO_CLEAR(delete m_filep, m_filep = NULL);
|
2017-10-14 17:00:25 +00:00
|
|
|
VerilatedVcdSingleton::removeVcd(this);
|
2010-01-24 23:37:01 +00:00
|
|
|
}
|
|
|
|
|
2018-08-22 23:14:06 +00:00
|
|
|
void VerilatedVcd::closePrev() {
|
2017-10-21 21:53:23 +00:00
|
|
|
// This function is on the flush() call path
|
2010-01-24 23:37:01 +00:00
|
|
|
if (!isOpen()) return;
|
|
|
|
|
|
|
|
bufferFlush();
|
|
|
|
m_isOpen = false;
|
2015-03-05 13:54:57 +00:00
|
|
|
m_filep->close();
|
2010-01-24 23:37:01 +00:00
|
|
|
}
|
|
|
|
|
2018-08-22 23:14:06 +00:00
|
|
|
void VerilatedVcd::closeErr() {
|
2017-10-27 01:51:51 +00:00
|
|
|
// This function is on the flush() call path
|
2010-01-24 23:37:01 +00:00
|
|
|
// Close due to an error. We might abort before even getting here,
|
|
|
|
// depending on the definition of vl_fatal.
|
|
|
|
if (!isOpen()) return;
|
|
|
|
|
|
|
|
// No buffer flush, just fclose
|
|
|
|
m_isOpen = false;
|
2015-03-05 13:54:57 +00:00
|
|
|
m_filep->close(); // May get error, just ignore it
|
2010-01-24 23:37:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void VerilatedVcd::close() {
|
2017-10-21 21:53:23 +00:00
|
|
|
// This function is on the flush() call path
|
2017-10-27 01:51:51 +00:00
|
|
|
m_assertOne.check();
|
2010-01-24 23:37:01 +00:00
|
|
|
if (!isOpen()) return;
|
|
|
|
if (m_evcd) {
|
2018-08-22 23:14:06 +00:00
|
|
|
printStr("$vcdclose ");
|
2020-04-19 22:57:36 +00:00
|
|
|
printQuad(timeLastDump());
|
2018-08-22 23:14:06 +00:00
|
|
|
printStr(" $end\n");
|
2010-01-24 23:37:01 +00:00
|
|
|
}
|
|
|
|
closePrev();
|
|
|
|
}
|
|
|
|
|
2018-08-22 23:14:06 +00:00
|
|
|
void VerilatedVcd::printStr(const char* str) {
|
2010-01-24 23:37:01 +00:00
|
|
|
// Not fast...
|
|
|
|
while (*str) {
|
2018-08-22 23:14:06 +00:00
|
|
|
*m_writep++ = *str++;
|
|
|
|
bufferCheck();
|
2010-01-24 23:37:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-22 23:14:06 +00:00
|
|
|
void VerilatedVcd::printQuad(vluint64_t n) {
|
2020-04-04 17:45:24 +00:00
|
|
|
char buf[100];
|
|
|
|
sprintf(buf, "%" VL_PRI64 "u", n);
|
2010-01-24 23:37:01 +00:00
|
|
|
printStr(buf);
|
|
|
|
}
|
|
|
|
|
2014-11-06 03:22:27 +00:00
|
|
|
void VerilatedVcd::bufferResize(vluint64_t minsize) {
|
|
|
|
// minsize is size of largest write. We buffer at least 8 times as much data,
|
|
|
|
// writing when we are 3/4 full (with thus 2*minsize remaining free)
|
|
|
|
if (VL_UNLIKELY(minsize > m_wrChunkSize)) {
|
2018-08-22 23:14:06 +00:00
|
|
|
char* oldbufp = m_wrBufp;
|
2020-04-04 17:06:31 +00:00
|
|
|
m_wrChunkSize = minsize * 2;
|
|
|
|
m_wrBufp = new char[m_wrChunkSize * 8];
|
2018-08-22 23:14:06 +00:00
|
|
|
memcpy(m_wrBufp, oldbufp, m_writep - oldbufp);
|
2014-11-06 03:22:27 +00:00
|
|
|
m_writep = m_wrBufp + (m_writep - oldbufp);
|
2018-08-22 23:14:06 +00:00
|
|
|
m_wrFlushp = m_wrBufp + m_wrChunkSize * 6;
|
2020-04-04 17:06:31 +00:00
|
|
|
VL_DO_CLEAR(delete[] oldbufp, oldbufp = NULL);
|
2014-11-06 03:22:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-22 23:14:06 +00:00
|
|
|
void VerilatedVcd::bufferFlush() VL_MT_UNSAFE_ONE {
|
2017-10-21 21:53:23 +00:00
|
|
|
// This function is on the flush() call path
|
2010-01-24 23:37:01 +00:00
|
|
|
// We add output data to m_writep.
|
|
|
|
// When it gets nearly full we dump it using this routine which calls write()
|
|
|
|
// This is much faster than using buffered I/O
|
2017-10-27 01:51:51 +00:00
|
|
|
m_assertOne.check();
|
2010-02-03 11:52:02 +00:00
|
|
|
if (VL_UNLIKELY(!isOpen())) return;
|
2010-01-24 23:37:01 +00:00
|
|
|
char* wp = m_wrBufp;
|
2020-04-04 02:31:54 +00:00
|
|
|
while (true) {
|
2018-08-22 23:14:06 +00:00
|
|
|
ssize_t remaining = (m_writep - wp);
|
2020-04-04 17:45:24 +00:00
|
|
|
if (remaining == 0) break;
|
2018-08-22 23:14:06 +00:00
|
|
|
errno = 0;
|
|
|
|
ssize_t got = m_filep->write(wp, remaining);
|
2020-04-04 17:45:24 +00:00
|
|
|
if (got > 0) {
|
2018-08-22 23:14:06 +00:00
|
|
|
wp += got;
|
|
|
|
m_wroteBytes += got;
|
|
|
|
} else if (got < 0) {
|
|
|
|
if (errno != EAGAIN && errno != EINTR) {
|
|
|
|
// write failed, presume error (perhaps out of disk space)
|
2020-04-04 17:45:24 +00:00
|
|
|
std::string msg = std::string("VerilatedVcd::bufferFlush: ") + strerror(errno);
|
|
|
|
VL_FATAL_MT("", 0, "", msg.c_str());
|
2018-08-22 23:14:06 +00:00
|
|
|
closeErr();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-01-24 23:37:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Reset buffer
|
|
|
|
m_writep = m_wrBufp;
|
|
|
|
}
|
|
|
|
|
2020-04-13 23:13:10 +00:00
|
|
|
//=============================================================================
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2010-01-24 23:37:01 +00:00
|
|
|
//=============================================================================
|
|
|
|
// Definitions
|
|
|
|
|
2018-08-22 23:14:06 +00:00
|
|
|
void VerilatedVcd::printIndent(int level_change) {
|
2020-04-04 17:45:24 +00:00
|
|
|
if (level_change < 0) m_modDepth += level_change;
|
|
|
|
assert(m_modDepth >= 0);
|
2020-04-13 23:13:10 +00:00
|
|
|
for (int i = 0; i < m_modDepth; i++) printStr(" ");
|
2020-04-04 17:45:24 +00:00
|
|
|
if (level_change > 0) m_modDepth += level_change;
|
2010-01-24 23:37:01 +00:00
|
|
|
}
|
|
|
|
|
2018-08-22 23:14:06 +00:00
|
|
|
void VerilatedVcd::dumpHeader() {
|
2010-01-24 23:37:01 +00:00
|
|
|
printStr("$version Generated by VerilatedVcd $end\n");
|
|
|
|
time_t time_str = time(NULL);
|
2020-04-04 17:45:24 +00:00
|
|
|
printStr("$date ");
|
|
|
|
printStr(ctime(&time_str));
|
|
|
|
printStr(" $end\n");
|
2010-01-24 23:37:01 +00:00
|
|
|
|
|
|
|
printStr("$timescale ");
|
2020-04-19 22:57:36 +00:00
|
|
|
printStr(timeResStr().c_str()); // lintok-begin-on-ref
|
2010-01-24 23:37:01 +00:00
|
|
|
printStr(" $end\n");
|
|
|
|
|
2010-03-22 22:38:24 +00:00
|
|
|
makeNameMap();
|
2010-01-24 23:37:01 +00:00
|
|
|
|
|
|
|
// Signal header
|
2020-04-04 17:45:24 +00:00
|
|
|
assert(m_modDepth == 0);
|
2010-01-24 23:37:01 +00:00
|
|
|
printIndent(1);
|
|
|
|
printStr("\n");
|
|
|
|
|
|
|
|
// We detect the spaces in module names to determine hierarchy. This
|
|
|
|
// allows signals to be declared without fixed ordering, which is
|
|
|
|
// required as Verilog signals might be separately declared from
|
2017-09-08 01:08:49 +00:00
|
|
|
// SC module signals.
|
2010-01-24 23:37:01 +00:00
|
|
|
|
|
|
|
// Print the signal names
|
|
|
|
const char* lastName = "";
|
2020-04-04 17:45:24 +00:00
|
|
|
for (NameMap::const_iterator it = m_namemapp->begin(); it != m_namemapp->end(); ++it) {
|
2018-08-22 23:14:06 +00:00
|
|
|
const std::string& hiernamestr = it->first;
|
|
|
|
const std::string& decl = it->second;
|
|
|
|
|
|
|
|
// Determine difference between the old and new names
|
|
|
|
const char* hiername = hiernamestr.c_str();
|
|
|
|
const char* lp = lastName;
|
|
|
|
const char* np = hiername;
|
|
|
|
lastName = hiername;
|
|
|
|
|
|
|
|
// Skip common prefix, it must break at a space or tab
|
|
|
|
for (; *np && (*np == *lp); np++, lp++) {}
|
2020-04-04 17:45:24 +00:00
|
|
|
while (np != hiername && *np && *np != ' ' && *np != '\t') {
|
|
|
|
np--;
|
|
|
|
lp--;
|
|
|
|
}
|
|
|
|
// printf("hier %s\n lp=%s\n np=%s\n",hiername,lp,np);
|
2018-08-22 23:14:06 +00:00
|
|
|
|
|
|
|
// Any extra spaces in last name are scope ups we need to do
|
|
|
|
bool first = true;
|
|
|
|
for (; *lp; lp++) {
|
2020-04-04 17:45:24 +00:00
|
|
|
if (*lp == ' ' || (first && *lp != '\t')) {
|
2018-08-22 23:14:06 +00:00
|
|
|
printIndent(-1);
|
|
|
|
printStr("$upscope $end\n");
|
|
|
|
}
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Any new spaces are scope downs we need to do
|
|
|
|
while (*np) {
|
2020-04-04 17:45:24 +00:00
|
|
|
if (*np == ' ') np++;
|
|
|
|
if (*np == '\t') break; // tab means signal name starts
|
2018-08-22 23:14:06 +00:00
|
|
|
printIndent(1);
|
|
|
|
printStr("$scope module ");
|
2020-04-04 17:45:24 +00:00
|
|
|
for (; *np && *np != ' ' && *np != '\t'; np++) {
|
|
|
|
if (*np == '[') {
|
|
|
|
printStr("(");
|
|
|
|
} else if (*np == ']') {
|
|
|
|
printStr(")");
|
|
|
|
} else {
|
|
|
|
*m_writep++ = *np;
|
|
|
|
}
|
2018-08-22 23:14:06 +00:00
|
|
|
}
|
|
|
|
printStr(" $end\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
printIndent(0);
|
|
|
|
printStr(decl.c_str());
|
2010-01-24 23:37:01 +00:00
|
|
|
}
|
|
|
|
|
2020-04-04 17:45:24 +00:00
|
|
|
while (m_modDepth > 1) {
|
2018-08-22 23:14:06 +00:00
|
|
|
printIndent(-1);
|
|
|
|
printStr("$upscope $end\n");
|
2010-01-24 23:37:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
printIndent(-1);
|
|
|
|
printStr("$enddefinitions $end\n\n\n");
|
2020-03-01 01:41:13 +00:00
|
|
|
assert(m_modDepth == 0);
|
2010-01-24 23:37:01 +00:00
|
|
|
|
|
|
|
// Reclaim storage
|
2013-02-24 02:10:25 +00:00
|
|
|
deleteNameMap();
|
2010-01-24 23:37:01 +00:00
|
|
|
}
|
|
|
|
|
2020-04-13 23:13:10 +00:00
|
|
|
void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep, bool array,
|
|
|
|
int arraynum, bool tri, bool bussed, int msb, int lsb) {
|
2020-04-19 22:57:36 +00:00
|
|
|
const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1;
|
2010-01-24 23:37:01 +00:00
|
|
|
|
2020-04-19 22:57:36 +00:00
|
|
|
VerilatedTrace<VerilatedVcd>::declCode(code, bits, tri);
|
2010-01-24 23:37:01 +00:00
|
|
|
|
2020-04-19 22:57:36 +00:00
|
|
|
if (m_suffixes.size() <= nextCode() * VL_TRACE_SUFFIX_ENTRY_SIZE) {
|
|
|
|
m_suffixes.resize(nextCode() * VL_TRACE_SUFFIX_ENTRY_SIZE * 2, 0);
|
2020-04-13 23:13:10 +00:00
|
|
|
}
|
2010-01-24 23:37:01 +00:00
|
|
|
|
2014-11-06 03:22:27 +00:00
|
|
|
// Make sure write buffer is large enough (one character per bit), plus header
|
2020-04-04 17:45:24 +00:00
|
|
|
bufferResize(bits + 1024);
|
2014-11-06 03:22:27 +00:00
|
|
|
|
2010-01-24 23:37:01 +00:00
|
|
|
// Split name into basename
|
|
|
|
// Spaces and tabs aren't legal in VCD signal names, so:
|
|
|
|
// Space separates each level of scope
|
|
|
|
// Tab separates final scope from signal name
|
|
|
|
// Tab sorts before spaces, so signals nicely will print before scopes
|
|
|
|
// Note the hiername may be nothing, if so we'll add "\t{name}"
|
2017-09-23 11:32:37 +00:00
|
|
|
std::string nameasstr = name;
|
2020-04-19 22:57:36 +00:00
|
|
|
if (!moduleName().empty()) {
|
|
|
|
nameasstr = moduleName() + scopeEscape() + nameasstr; // Optional ->module prefix
|
2018-10-14 22:39:33 +00:00
|
|
|
}
|
2017-09-23 11:32:37 +00:00
|
|
|
std::string hiername;
|
|
|
|
std::string basename;
|
2020-04-04 17:45:24 +00:00
|
|
|
for (const char* cp = nameasstr.c_str(); *cp; cp++) {
|
2018-08-22 23:14:06 +00:00
|
|
|
if (isScopeEscape(*cp)) {
|
|
|
|
// Ahh, we've just read a scope, not a basename
|
2018-10-14 22:39:33 +00:00
|
|
|
if (!hiername.empty()) hiername += " ";
|
2018-08-22 23:14:06 +00:00
|
|
|
hiername += basename;
|
|
|
|
basename = "";
|
|
|
|
} else {
|
|
|
|
basename += *cp;
|
|
|
|
}
|
2010-01-24 23:37:01 +00:00
|
|
|
}
|
2020-04-04 17:45:24 +00:00
|
|
|
hiername += "\t" + basename;
|
2010-01-24 23:37:01 +00:00
|
|
|
|
|
|
|
// Print reference
|
2017-09-23 11:32:37 +00:00
|
|
|
std::string decl = "$var ";
|
2020-04-04 17:45:24 +00:00
|
|
|
if (m_evcd) {
|
|
|
|
decl += "port";
|
|
|
|
} else {
|
|
|
|
decl += wirep; // usually "wire"
|
|
|
|
}
|
|
|
|
|
|
|
|
char buf[1000];
|
2010-01-24 23:37:01 +00:00
|
|
|
sprintf(buf, " %2d ", bits);
|
|
|
|
decl += buf;
|
|
|
|
if (m_evcd) {
|
2018-06-14 22:59:24 +00:00
|
|
|
sprintf(buf, "<%u", code);
|
2018-08-22 23:14:06 +00:00
|
|
|
decl += buf;
|
2010-01-24 23:37:01 +00:00
|
|
|
} else {
|
2020-04-13 23:13:10 +00:00
|
|
|
// 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;
|
2010-01-24 23:37:01 +00:00
|
|
|
}
|
|
|
|
decl += " ";
|
|
|
|
decl += basename;
|
2020-01-08 12:32:31 +00:00
|
|
|
if (array) {
|
2018-08-22 23:14:06 +00:00
|
|
|
sprintf(buf, "(%d)", arraynum);
|
|
|
|
decl += buf;
|
|
|
|
hiername += buf;
|
2010-01-24 23:37:01 +00:00
|
|
|
}
|
|
|
|
if (bussed) {
|
2018-08-22 23:14:06 +00:00
|
|
|
sprintf(buf, " [%d:%d]", msb, lsb);
|
|
|
|
decl += buf;
|
2010-01-24 23:37:01 +00:00
|
|
|
}
|
|
|
|
decl += " $end\n";
|
2020-04-04 17:45:24 +00:00
|
|
|
m_namemapp->insert(std::make_pair(hiername, decl));
|
2010-01-24 23:37:01 +00:00
|
|
|
}
|
|
|
|
|
2020-01-08 12:32:31 +00:00
|
|
|
void VerilatedVcd::declBit(vluint32_t code, const char* name, bool array, int arraynum) {
|
|
|
|
declare(code, name, "wire", array, arraynum, false, false, 0, 0);
|
|
|
|
}
|
|
|
|
void VerilatedVcd::declBus(vluint32_t code, const char* name, bool array, int arraynum, int msb,
|
|
|
|
int lsb) {
|
|
|
|
declare(code, name, "wire", array, arraynum, false, true, msb, lsb);
|
|
|
|
}
|
|
|
|
void VerilatedVcd::declQuad(vluint32_t code, const char* name, bool array, int arraynum, int msb,
|
|
|
|
int lsb) {
|
|
|
|
declare(code, name, "wire", array, arraynum, false, true, msb, lsb);
|
|
|
|
}
|
|
|
|
void VerilatedVcd::declArray(vluint32_t code, const char* name, bool array, int arraynum, int msb,
|
|
|
|
int lsb) {
|
|
|
|
declare(code, name, "wire", array, arraynum, false, true, msb, lsb);
|
|
|
|
}
|
2020-04-13 23:13:10 +00:00
|
|
|
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);
|
|
|
|
}
|
2020-04-19 22:57:36 +00:00
|
|
|
#ifdef VL_TRACE_VCD_OLD_API
|
2020-01-08 12:32:31 +00:00
|
|
|
void VerilatedVcd::declTriBit(vluint32_t code, const char* name, bool array, int arraynum) {
|
|
|
|
declare(code, name, "wire", array, arraynum, true, false, 0, 0);
|
|
|
|
}
|
|
|
|
void VerilatedVcd::declTriBus(vluint32_t code, const char* name, bool array, int arraynum, int msb,
|
|
|
|
int lsb) {
|
|
|
|
declare(code, name, "wire", array, arraynum, true, true, msb, lsb);
|
|
|
|
}
|
|
|
|
void VerilatedVcd::declTriQuad(vluint32_t code, const char* name, bool array, int arraynum,
|
|
|
|
int msb, int lsb) {
|
|
|
|
declare(code, name, "wire", array, arraynum, true, true, msb, lsb);
|
|
|
|
}
|
|
|
|
void VerilatedVcd::declTriArray(vluint32_t code, const char* name, bool array, int arraynum,
|
|
|
|
int msb, int lsb) {
|
|
|
|
declare(code, name, "wire", array, arraynum, true, true, msb, lsb);
|
|
|
|
}
|
2020-04-13 23:13:10 +00:00
|
|
|
#endif // VL_TRACE_VCD_OLD_API
|
|
|
|
|
|
|
|
//=============================================================================
|
|
|
|
// Trace recording routines
|
|
|
|
|
|
|
|
//=============================================================================
|
2020-04-19 22:57:36 +00:00
|
|
|
// Emit trace entries
|
2020-04-13 23:13:10 +00:00
|
|
|
|
|
|
|
// Emit suffix, write back write pointer, check buffer
|
2020-04-19 22:57:36 +00:00
|
|
|
void VerilatedVcd::finishLine(vluint32_t code, char* writep) {
|
2020-04-13 23:13:10 +00:00
|
|
|
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();
|
2020-01-08 12:32:31 +00:00
|
|
|
}
|
2020-04-13 23:13:10 +00:00
|
|
|
|
2020-04-19 22:57:36 +00:00
|
|
|
void VerilatedVcd::emitBit(vluint32_t code, vluint32_t newval) {
|
2020-04-13 23:13:10 +00:00
|
|
|
char* wp = m_writep;
|
|
|
|
*wp++ = '0' | static_cast<char>(newval);
|
2020-04-19 22:57:36 +00:00
|
|
|
finishLine(code, wp);
|
2020-01-08 12:32:31 +00:00
|
|
|
}
|
2010-01-24 23:37:01 +00:00
|
|
|
|
2020-04-19 22:57:36 +00:00
|
|
|
template <int T_Bits> void VerilatedVcd::emitBus(vluint32_t code, vluint32_t newval) {
|
2020-04-13 23:13:10 +00:00
|
|
|
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);
|
2020-04-19 22:57:36 +00:00
|
|
|
finishLine(code, wp);
|
2020-04-13 23:13:10 +00:00
|
|
|
}
|
2020-04-19 22:57:36 +00:00
|
|
|
|
|
|
|
void VerilatedVcd::emitQuad(vluint32_t code, vluint64_t newval, int bits) {
|
2020-04-13 23:13:10 +00:00
|
|
|
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);
|
2020-04-19 22:57:36 +00:00
|
|
|
finishLine(code, wp);
|
2020-04-13 23:13:10 +00:00
|
|
|
}
|
|
|
|
|
2020-04-19 22:57:36 +00:00
|
|
|
void VerilatedVcd::emitArray(vluint32_t code, const vluint32_t* newvalp, int bits) {
|
2020-04-13 23:13:10 +00:00
|
|
|
int words = (bits + 31) / 32;
|
|
|
|
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);
|
|
|
|
}
|
2020-04-19 22:57:36 +00:00
|
|
|
finishLine(code, wp);
|
2020-04-13 23:13:10 +00:00
|
|
|
}
|
|
|
|
|
2020-04-19 22:57:36 +00:00
|
|
|
void VerilatedVcd::emitFloat(vluint32_t code, float newval) {
|
2020-04-13 23:13:10 +00:00
|
|
|
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);
|
2020-04-19 22:57:36 +00:00
|
|
|
finishLine(code, wp);
|
2020-04-13 23:13:10 +00:00
|
|
|
}
|
|
|
|
|
2020-04-19 22:57:36 +00:00
|
|
|
void VerilatedVcd::emitDouble(vluint32_t code, double newval) {
|
2020-04-13 23:13:10 +00:00
|
|
|
char* wp = m_writep;
|
|
|
|
// Buffer can't overflow before sprintf; we sized during declaration
|
|
|
|
sprintf(wp, "r%.16g", newval);
|
|
|
|
wp += strlen(wp);
|
2020-04-19 22:57:36 +00:00
|
|
|
finishLine(code, wp);
|
2020-04-13 23:13:10 +00:00
|
|
|
}
|
|
|
|
|
2020-04-19 22:57:36 +00:00
|
|
|
#ifdef VL_TRACE_VCD_OLD_API
|
2010-01-24 23:37:01 +00:00
|
|
|
|
2020-04-09 12:19:26 +00:00
|
|
|
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
|
2020-04-19 22:57:36 +00:00
|
|
|
*oldp(code) = newval;
|
2020-04-09 12:19:26 +00:00
|
|
|
*m_writep++ = ('0' + static_cast<char>(newval & 1));
|
2020-04-13 23:13:10 +00:00
|
|
|
m_writep = writeCode(m_writep, code);
|
2020-04-09 12:19:26 +00:00
|
|
|
*m_writep++ = '\n';
|
|
|
|
bufferCheck();
|
|
|
|
}
|
|
|
|
void VerilatedVcd::fullBus(vluint32_t code, const vluint32_t newval, int bits) {
|
2020-04-19 22:57:36 +00:00
|
|
|
*oldp(code) = newval;
|
2020-04-09 12:19:26 +00:00
|
|
|
*m_writep++ = 'b';
|
|
|
|
for (int bit = bits - 1; bit >= 0; --bit) {
|
|
|
|
*m_writep++ = ((newval & (1L << bit)) ? '1' : '0');
|
|
|
|
}
|
|
|
|
*m_writep++ = ' ';
|
2020-04-13 23:13:10 +00:00
|
|
|
m_writep = writeCode(m_writep, code);
|
2020-04-09 12:19:26 +00:00
|
|
|
*m_writep++ = '\n';
|
|
|
|
bufferCheck();
|
|
|
|
}
|
|
|
|
void VerilatedVcd::fullQuad(vluint32_t code, const vluint64_t newval, int bits) {
|
2020-04-19 22:57:36 +00:00
|
|
|
(*(reinterpret_cast<vluint64_t*>(oldp(code)))) = newval;
|
2020-04-09 12:19:26 +00:00
|
|
|
*m_writep++ = 'b';
|
|
|
|
for (int bit = bits - 1; bit >= 0; --bit) {
|
|
|
|
*m_writep++ = ((newval & (VL_ULL(1) << bit)) ? '1' : '0');
|
|
|
|
}
|
|
|
|
*m_writep++ = ' ';
|
2020-04-13 23:13:10 +00:00
|
|
|
m_writep = writeCode(m_writep, code);
|
2020-04-09 12:19:26 +00:00
|
|
|
*m_writep++ = '\n';
|
|
|
|
bufferCheck();
|
|
|
|
}
|
|
|
|
void VerilatedVcd::fullArray(vluint32_t code, const vluint32_t* newval, int bits) {
|
2020-04-19 22:57:36 +00:00
|
|
|
for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) { oldp(code)[word] = newval[word]; }
|
2020-04-09 12:19:26 +00:00
|
|
|
*m_writep++ = 'b';
|
|
|
|
for (int bit = bits - 1; bit >= 0; --bit) {
|
|
|
|
*m_writep++ = ((newval[(bit / 32)] & (1L << (bit & 0x1f))) ? '1' : '0');
|
|
|
|
}
|
|
|
|
*m_writep++ = ' ';
|
2020-04-13 23:13:10 +00:00
|
|
|
m_writep = writeCode(m_writep, code);
|
2020-04-09 12:19:26 +00:00
|
|
|
*m_writep++ = '\n';
|
|
|
|
bufferCheck();
|
|
|
|
}
|
|
|
|
void VerilatedVcd::fullArray(vluint32_t code, const vluint64_t* newval, int bits) {
|
2020-04-19 22:57:36 +00:00
|
|
|
for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) { oldp(code)[word] = newval[word]; }
|
2020-04-09 12:19:26 +00:00
|
|
|
*m_writep++ = 'b';
|
|
|
|
for (int bit = bits - 1; bit >= 0; --bit) {
|
|
|
|
*m_writep++ = ((newval[(bit / 64)] & (VL_ULL(1) << (bit & 0x3f))) ? '1' : '0');
|
|
|
|
}
|
|
|
|
*m_writep++ = ' ';
|
2020-04-13 23:13:10 +00:00
|
|
|
m_writep = writeCode(m_writep, code);
|
2020-04-09 12:19:26 +00:00
|
|
|
*m_writep++ = '\n';
|
|
|
|
bufferCheck();
|
|
|
|
}
|
|
|
|
void VerilatedVcd::fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri) {
|
2020-04-19 22:57:36 +00:00
|
|
|
oldp(code)[0] = newval;
|
|
|
|
oldp(code)[1] = newtri;
|
|
|
|
*m_writep++ = "01zz"[newval | (newtri << 1)];
|
2020-04-13 23:13:10 +00:00
|
|
|
m_writep = writeCode(m_writep, code);
|
2020-04-09 12:19:26 +00:00
|
|
|
*m_writep++ = '\n';
|
|
|
|
bufferCheck();
|
|
|
|
}
|
2020-04-13 23:13:10 +00:00
|
|
|
void VerilatedVcd::fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri,
|
|
|
|
int bits) {
|
2020-04-19 22:57:36 +00:00
|
|
|
oldp(code)[0] = newval;
|
|
|
|
oldp(code)[1] = newtri;
|
2020-04-09 12:19:26 +00:00
|
|
|
*m_writep++ = 'b';
|
|
|
|
for (int bit = bits - 1; bit >= 0; --bit) {
|
|
|
|
*m_writep++ = "01zz"[((newval >> bit) & 1) | (((newtri >> bit) & 1) << 1)];
|
|
|
|
}
|
|
|
|
*m_writep++ = ' ';
|
2020-04-13 23:13:10 +00:00
|
|
|
m_writep = writeCode(m_writep, code);
|
2020-04-09 12:19:26 +00:00
|
|
|
*m_writep++ = '\n';
|
|
|
|
bufferCheck();
|
|
|
|
}
|
2020-04-13 23:13:10 +00:00
|
|
|
void VerilatedVcd::fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri,
|
|
|
|
int bits) {
|
2020-04-19 22:57:36 +00:00
|
|
|
(*(reinterpret_cast<vluint64_t*>(oldp(code)))) = newval;
|
|
|
|
(*(reinterpret_cast<vluint64_t*>(oldp(code + 1)))) = newtri;
|
2020-04-09 12:19:26 +00:00
|
|
|
*m_writep++ = 'b';
|
|
|
|
for (int bit = bits - 1; bit >= 0; --bit) {
|
2020-04-13 23:13:10 +00:00
|
|
|
*m_writep++
|
|
|
|
= "01zz"[((newval >> bit) & VL_ULL(1)) | (((newtri >> bit) & VL_ULL(1)) << VL_ULL(1))];
|
2020-04-09 12:19:26 +00:00
|
|
|
}
|
|
|
|
*m_writep++ = ' ';
|
2020-04-13 23:13:10 +00:00
|
|
|
m_writep = writeCode(m_writep, code);
|
2020-04-09 12:19:26 +00:00
|
|
|
*m_writep++ = '\n';
|
|
|
|
bufferCheck();
|
|
|
|
}
|
2020-04-13 23:13:10 +00:00
|
|
|
void VerilatedVcd::fullTriArray(vluint32_t code, const vluint32_t* newvalp,
|
|
|
|
const vluint32_t* newtrip, int bits) {
|
2020-04-09 12:19:26 +00:00
|
|
|
for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) {
|
2020-04-19 22:57:36 +00:00
|
|
|
oldp(code)[word * 2] = newvalp[word];
|
|
|
|
oldp(code)[word * 2 + 1] = newtrip[word];
|
2020-04-09 12:19:26 +00:00
|
|
|
}
|
|
|
|
*m_writep++ = 'b';
|
|
|
|
for (int bit = bits - 1; bit >= 0; --bit) {
|
|
|
|
vluint32_t valbit = (newvalp[(bit / 32)] >> (bit & 0x1f)) & 1;
|
|
|
|
vluint32_t tribit = (newtrip[(bit / 32)] >> (bit & 0x1f)) & 1;
|
|
|
|
*m_writep++ = "01zz"[valbit | (tribit << 1)];
|
|
|
|
}
|
|
|
|
*m_writep++ = ' ';
|
2020-04-13 23:13:10 +00:00
|
|
|
m_writep = writeCode(m_writep, code);
|
2020-04-09 12:19:26 +00:00
|
|
|
*m_writep++ = '\n';
|
|
|
|
bufferCheck();
|
|
|
|
}
|
2018-08-22 23:14:06 +00:00
|
|
|
void VerilatedVcd::fullDouble(vluint32_t code, const double newval) {
|
2017-07-07 00:25:59 +00:00
|
|
|
// cppcheck-suppress invalidPointerCast
|
2020-04-19 22:57:36 +00:00
|
|
|
(*(reinterpret_cast<double*>(oldp(code)))) = newval;
|
2014-11-06 03:22:27 +00:00
|
|
|
// Buffer can't overflow before sprintf; we sized during declaration
|
2010-01-24 23:37:01 +00:00
|
|
|
sprintf(m_writep, "r%.16g", newval);
|
|
|
|
m_writep += strlen(m_writep);
|
2020-04-04 17:45:24 +00:00
|
|
|
*m_writep++ = ' ';
|
2020-04-13 23:13:10 +00:00
|
|
|
m_writep = writeCode(m_writep, code);
|
2020-04-04 17:45:24 +00:00
|
|
|
*m_writep++ = '\n';
|
2010-01-24 23:37:01 +00:00
|
|
|
bufferCheck();
|
|
|
|
}
|
2018-08-22 23:14:06 +00:00
|
|
|
void VerilatedVcd::fullFloat(vluint32_t code, const float newval) {
|
2017-07-07 00:25:59 +00:00
|
|
|
// cppcheck-suppress invalidPointerCast
|
2020-04-19 22:57:36 +00:00
|
|
|
(*(reinterpret_cast<float*>(oldp(code)))) = newval;
|
2014-11-06 03:22:27 +00:00
|
|
|
// Buffer can't overflow before sprintf; we sized during declaration
|
2017-10-07 19:01:19 +00:00
|
|
|
sprintf(m_writep, "r%.16g", static_cast<double>(newval));
|
2010-01-24 23:37:01 +00:00
|
|
|
m_writep += strlen(m_writep);
|
2020-04-04 17:45:24 +00:00
|
|
|
*m_writep++ = ' ';
|
2020-04-13 23:13:10 +00:00
|
|
|
m_writep = writeCode(m_writep, code);
|
2020-04-04 17:45:24 +00:00
|
|
|
*m_writep++ = '\n';
|
2010-01-24 23:37:01 +00:00
|
|
|
bufferCheck();
|
|
|
|
}
|
2020-04-09 12:19:26 +00:00
|
|
|
void VerilatedVcd::fullBitX(vluint32_t code) {
|
|
|
|
*m_writep++ = 'x';
|
2020-04-13 23:13:10 +00:00
|
|
|
m_writep = writeCode(m_writep, code);
|
2020-04-09 12:19:26 +00:00
|
|
|
*m_writep++ = '\n';
|
|
|
|
bufferCheck();
|
|
|
|
}
|
|
|
|
void VerilatedVcd::fullBusX(vluint32_t code, int bits) {
|
|
|
|
*m_writep++ = 'b';
|
2020-04-13 23:13:10 +00:00
|
|
|
for (int bit = bits - 1; bit >= 0; --bit) *m_writep++ = 'x';
|
2020-04-09 12:19:26 +00:00
|
|
|
*m_writep++ = ' ';
|
2020-04-13 23:13:10 +00:00
|
|
|
m_writep = writeCode(m_writep, code);
|
2020-04-09 12:19:26 +00:00
|
|
|
*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); }
|
2010-01-24 23:37:01 +00:00
|
|
|
|
2020-04-13 23:13:10 +00:00
|
|
|
#endif // VL_TRACE_VCD_OLD_API
|
|
|
|
|
2010-01-24 23:37:01 +00:00
|
|
|
//======================================================================
|
|
|
|
// Static members
|
|
|
|
|
2020-04-04 17:45:24 +00:00
|
|
|
void VerilatedVcd::flush_all() VL_MT_UNSAFE_ONE { VerilatedVcdSingleton::flush_all(); }
|
2010-01-24 23:37:01 +00:00
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
//======================================================================
|
|
|
|
//======================================================================
|
|
|
|
|
2020-04-13 23:13:10 +00:00
|
|
|
// clang-format off
|
|
|
|
|
2010-01-24 23:37:01 +00:00
|
|
|
#ifdef VERILATED_VCD_TEST
|
2019-12-06 03:25:30 +00:00
|
|
|
#include <iostream>
|
|
|
|
|
2010-01-24 23:37:01 +00:00
|
|
|
vluint32_t v1, v2, s1, s2[3];
|
|
|
|
vluint32_t tri96[3];
|
|
|
|
vluint32_t tri96__tri[3];
|
2019-12-06 03:25:30 +00:00
|
|
|
vluint64_t quad96[2];
|
2010-01-24 23:37:01 +00:00
|
|
|
vluint8_t ch;
|
|
|
|
vluint64_t timestamp = 1;
|
|
|
|
double doub = 0;
|
|
|
|
|
2018-08-22 23:14:06 +00:00
|
|
|
void vcdInit(VerilatedVcd* vcdp, void* userthis, vluint32_t code) {
|
2010-01-24 23:37:01 +00:00
|
|
|
vcdp->scopeEscape('.');
|
2018-08-22 23:14:06 +00:00
|
|
|
vcdp->module("top");
|
|
|
|
vcdp->declBus(0x2, "v1",-1,5,1);
|
|
|
|
vcdp->declBus(0x3, "v2",-1,6,0);
|
|
|
|
vcdp->module("top.sub1");
|
|
|
|
vcdp->declBit(0x4, "s1",-1);
|
|
|
|
vcdp->declBit(0x5, "ch",-1);
|
|
|
|
vcdp->module("top.sub2");
|
|
|
|
vcdp->declArray(0x6, "s2",-1, 40,3);
|
2010-01-24 23:37:01 +00:00
|
|
|
// Note need to add 3 for next code.
|
2018-08-22 23:14:06 +00:00
|
|
|
vcdp->module("top2");
|
|
|
|
vcdp->declBus(0x2, "t2v1",-1,4,1);
|
2020-04-04 17:45:24 +00:00
|
|
|
vcdp->declTriBit(0x10, "io1",-1);
|
|
|
|
vcdp->declTriBus(0x12, "io5",-1,4,0);
|
2018-08-22 23:14:06 +00:00
|
|
|
vcdp->declTriArray(0x16, "io96",-1,95,0);
|
2010-01-24 23:37:01 +00:00
|
|
|
// Note need to add 6 for next code.
|
2020-04-04 17:45:24 +00:00
|
|
|
vcdp->declDouble(0x1c, "doub",-1);
|
2010-01-24 23:37:01 +00:00
|
|
|
// Note need to add 2 for next code.
|
2020-04-04 17:45:24 +00:00
|
|
|
vcdp->declArray(0x1e, "q2",-1,95,0);
|
2019-12-06 03:25:30 +00:00
|
|
|
// Note need to add 4 for next code.
|
2010-01-24 23:37:01 +00:00
|
|
|
}
|
|
|
|
|
2018-08-22 23:14:06 +00:00
|
|
|
void vcdFull(VerilatedVcd* vcdp, void* userthis, vluint32_t code) {
|
2020-04-04 17:45:24 +00:00
|
|
|
vcdp->fullBus(0x2, v1, 5);
|
|
|
|
vcdp->fullBus(0x3, v2, 7);
|
|
|
|
vcdp->fullBit(0x4, s1);
|
|
|
|
vcdp->fullBus(0x5, ch, 2);
|
2010-01-24 23:37:01 +00:00
|
|
|
vcdp->fullArray(0x6, &s2[0], 38);
|
2020-04-04 17:45:24 +00:00
|
|
|
vcdp->fullTriBit(0x10, tri96[0] & 1, tri96__tri[0] & 1);
|
|
|
|
vcdp->fullTriBus(0x12, tri96[0] & 0x1f, tri96__tri[0] & 0x1f, 5);
|
|
|
|
vcdp->fullTriArray(0x16, tri96, tri96__tri, 96);
|
2010-01-24 23:37:01 +00:00
|
|
|
vcdp->fullDouble(0x1c, doub);
|
2019-12-06 03:25:30 +00:00
|
|
|
vcdp->fullArray(0x1e, &quad96[0], 96);
|
2010-01-24 23:37:01 +00:00
|
|
|
}
|
|
|
|
|
2018-08-22 23:14:06 +00:00
|
|
|
void vcdChange(VerilatedVcd* vcdp, void* userthis, vluint32_t code) {
|
2020-04-04 17:45:24 +00:00
|
|
|
vcdp->chgBus(0x2, v1, 5);
|
|
|
|
vcdp->chgBus(0x3, v2, 7);
|
|
|
|
vcdp->chgBit(0x4, s1);
|
|
|
|
vcdp->chgBus(0x5, ch, 2);
|
2010-01-24 23:37:01 +00:00
|
|
|
vcdp->chgArray(0x6, &s2[0], 38);
|
2020-04-04 17:45:24 +00:00
|
|
|
vcdp->chgTriBit(0x10, tri96[0] & 1, tri96__tri[0] & 1);
|
|
|
|
vcdp->chgTriBus(0x12, tri96[0] & 0x1f, tri96__tri[0] & 0x1f, 5);
|
|
|
|
vcdp->chgTriArray(0x16, tri96, tri96__tri, 96);
|
|
|
|
vcdp->chgDouble(0x1c, doub);
|
2019-12-06 03:25:30 +00:00
|
|
|
vcdp->chgArray(0x1e, &quad96[0], 96);
|
2010-01-24 23:37:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
main() {
|
2019-12-06 03:25:30 +00:00
|
|
|
std::cout << "test: O_LARGEFILE=" << O_LARGEFILE << std::endl;
|
2010-01-24 23:37:01 +00:00
|
|
|
|
|
|
|
v1 = v2 = s1 = 0;
|
|
|
|
s2[0] = s2[1] = s2[2] = 0;
|
|
|
|
tri96[2] = tri96[1] = tri96[0] = 0;
|
|
|
|
tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = ~0;
|
2019-12-06 03:25:30 +00:00
|
|
|
quad96[1] = quad96[0] = 0;
|
2010-01-24 23:37:01 +00:00
|
|
|
ch = 0;
|
|
|
|
doub = 0;
|
|
|
|
{
|
2018-08-22 23:14:06 +00:00
|
|
|
VerilatedVcdC* vcdp = new VerilatedVcdC;
|
|
|
|
vcdp->spTrace()->addCallback(&vcdInit, &vcdFull, &vcdChange, 0);
|
|
|
|
vcdp->open("test.vcd");
|
|
|
|
// Dumping
|
|
|
|
vcdp->dump(timestamp++);
|
|
|
|
v1 = 0xfff;
|
|
|
|
tri96[2] = 4; tri96[1] = 2; tri96[0] = 1;
|
|
|
|
tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = ~0; // Still tri
|
2020-04-04 17:45:24 +00:00
|
|
|
quad96[1] = 0xffffffff; quad96[0] = 0;
|
2018-08-22 23:14:06 +00:00
|
|
|
doub = 1.5;
|
|
|
|
vcdp->dump(timestamp++);
|
|
|
|
v2 = 0x1;
|
|
|
|
s2[1] = 2;
|
|
|
|
tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = 0; // enable w/o data change
|
2020-04-04 17:45:24 +00:00
|
|
|
quad96[1] = 0; quad96[0] = ~0;
|
2018-08-22 23:14:06 +00:00
|
|
|
doub = -1.66e13;
|
|
|
|
vcdp->dump(timestamp++);
|
|
|
|
ch = 2;
|
|
|
|
tri96[2] = ~4; tri96[1] = ~2; tri96[0] = ~1;
|
|
|
|
doub = -3.33e-13;
|
|
|
|
vcdp->dump(timestamp++);
|
|
|
|
vcdp->dump(timestamp++);
|
2010-01-24 23:37:01 +00:00
|
|
|
# ifdef VERILATED_VCD_TEST_64BIT
|
2019-12-06 03:25:30 +00:00
|
|
|
vluint64_t bytesPerDump = VL_ULL(15);
|
|
|
|
for (vluint64_t i = 0; i < ((VL_ULL(1) << 32) / bytesPerDump); i++) {
|
2018-08-22 23:14:06 +00:00
|
|
|
v1 = i;
|
|
|
|
vcdp->dump(timestamp++);
|
|
|
|
}
|
2010-01-24 23:37:01 +00:00
|
|
|
# endif
|
2018-08-22 23:14:06 +00:00
|
|
|
vcdp->close();
|
2010-01-24 23:37:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//********************************************************************
|
2020-03-01 01:41:13 +00:00
|
|
|
// ;compile-command: "mkdir -p ../test_dir && cd ../test_dir && c++ -DVERILATED_VCD_TEST ../include/verilated_vcd_c.cpp -o verilated_vcd_c && ./verilated_vcd_c && cat test.vcd"
|
|
|
|
//
|
2010-01-24 23:37:01 +00:00
|
|
|
// Local Variables:
|
|
|
|
// End:
|