Reduce .rodata footprint of trace initialization (#3250)

Trace initialization (tracep->decl* functions) used to explicitly pass
the complete hierarchical names of signals as string constants. This
contains a lot of redundancy (path prefixes), does not scale well with
large designs and resulted in .rodata sections (the string constants) in
ELF executables being extremely large.

This patch changes the API of trace initialization that allows pushing
and popping name prefixes as we walk the hierarchy tree, which are
prepended to declared signal names at run-time during trace
initialization. This in turn allows us to emit repeat path/name
components only once, effectively removing all duplicate path prefixes.
On SweRV EH1 this reduces the .rodata section in a --trace build by 94%.

Additionally, trace declarations are now emitted in lexical order by
hierarchical signal names, and the top level trace initialization
function respects --output-split-ctrace.
This commit is contained in:
Geza Lore 2021-12-19 15:15:07 +00:00 committed by GitHub
parent 30ccccdb67
commit ff425369ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 607 additions and 391 deletions

View File

@ -21,6 +21,7 @@ Verilator 4.217 devel
* Support lower dimension looping in foreach loops (#3172). [Ehab Ibrahim]
* Support up to 64 bit enums for .next/.prev/.name (#3244). [Alexander Grobman]
* Reduce .rodata footpring of trace initializatoin (#3250). [Geza Lore, Shunyao CAD]
* Fix MSWIN compile error (#2681). [Unai Martinez-Corral]
* Fix break under foreach loop (#3230).
* Fix VL_STREAML_FAST_QQI with 64 bit left-hand-side (#3232) (#3235)

View File

@ -2625,14 +2625,11 @@ void Verilated::debug(int level) VL_MT_SAFE {
}
}
const char* Verilated::catName(const char* n1, const char* n2, int scopet,
const char* delimiter) VL_MT_SAFE {
// Returns new'ed data
const char* Verilated::catName(const char* n1, const char* n2, const char* delimiter) VL_MT_SAFE {
// Used by symbol table creation to make module names
static VL_THREAD_LOCAL char* t_strp = nullptr;
static VL_THREAD_LOCAL size_t t_len = 0;
const size_t newlen
= std::strlen(n1) + std::strlen(n2) + std::strlen(delimiter) + (scopet > 0 ? 2 : 1);
const size_t newlen = std::strlen(n1) + std::strlen(n2) + std::strlen(delimiter) + 1;
if (VL_UNLIKELY(!t_strp || newlen > t_len)) {
if (t_strp) delete[] t_strp;
t_strp = new char[newlen];
@ -2640,8 +2637,6 @@ const char* Verilated::catName(const char* n1, const char* n2, int scopet,
}
char* dp = t_strp;
for (const char* sp = n1; *sp;) *dp++ = *sp++;
// Add scope type
if (scopet) *dp++ = (char)(0x80 + scopet);
for (const char* sp = delimiter; *sp;) *dp++ = *sp++;
for (const char* sp = n2; *sp;) *dp++ = *sp++;
*dp++ = '\0';

View File

@ -823,8 +823,8 @@ public:
public:
// METHODS - INTERNAL USE ONLY (but public due to what uses it)
// Internal: Create a new module name by concatenating two strings
static const char* catName(const char* n1, const char* n2, int scopet = 0,
const char* delimiter = "."); // Returns static data
// Returns pointer to thread-local static data (overwritten on next call)
static const char* catName(const char* n1, const char* n2, const char* delimiter = ".");
// Internal: Throw signal assertion
static void nullPointerError(const char* filename, int linenum) VL_ATTR_NORETURN VL_MT_SAFE;

View File

@ -163,13 +163,13 @@ void VerilatedFst::declare(vluint32_t code, const char* name, int dtypenum, fstV
VerilatedTrace<VerilatedFst>::declCode(code, bits, false);
std::istringstream nameiss{name};
std::string nameasstr = namePrefix() + name;
std::istringstream nameiss{nameasstr};
std::istream_iterator<std::string> beg(nameiss);
std::istream_iterator<std::string> end;
std::list<std::string> tokens(beg, end); // Split name
std::string symbol_name{tokens.back()};
tokens.pop_back(); // Remove symbol name from hierarchy
tokens.insert(tokens.begin(), moduleName()); // Add current module to the hierarchy
std::string tmpModName;
// Find point where current and new scope diverge

View File

@ -150,7 +150,7 @@ private:
vluint32_t m_nextCode; // Next code number to assign
vluint32_t m_numSignals; // Number of distinct signals
vluint32_t m_maxBits; // Number of bits in the widest signal
std::string m_moduleName; // Name of module being trace initialized now
std::vector<std::string> m_namePrefixStack{""}; // Path prefixes to add to signal names
char m_scopeEscape;
double m_timeRes; // Time resolution (ns/ms etc)
double m_timeUnit; // Time units (ns/ms etc)
@ -213,7 +213,6 @@ protected:
vluint32_t nextCode() const { return m_nextCode; }
vluint32_t numSignals() const { return m_numSignals; }
vluint32_t maxBits() const { return m_maxBits; }
const std::string& moduleName() const { return m_moduleName; }
void fullDump(bool value) { m_fullDump = value; }
vluint64_t timeLastDump() { return m_timeLastDump; }
@ -229,6 +228,8 @@ protected:
bool isScopeEscape(char c) { return std::isspace(c) || c == m_scopeEscape; }
// Character that splits scopes. Note whitespace are ALWAYS escapes.
char scopeEscape() { return m_scopeEscape; }
// Prefix to assume in signal declarations
const std::string& namePrefix() const { return m_namePrefixStack.back(); }
void closeBase();
void flushBase();
@ -269,9 +270,11 @@ public:
void addChgCb(dumpCb_t cb, void* userp) VL_MT_SAFE;
void addCleanupCb(dumpCb_t cb, void* userp) VL_MT_SAFE;
void module(const std::string& name) VL_MT_UNSAFE;
void scopeEscape(char flag) { m_scopeEscape = flag; }
void pushNamePrefix(const std::string&);
void popNamePrefix(unsigned count = 1);
//=========================================================================
// Hot path internal interface to Verilator generated code

View File

@ -504,9 +504,14 @@ template <> void VerilatedTrace<VL_DERIVED_T>::addCleanupCb(dumpCb_t cb, void* u
CallbackRecord cbr{cb, userp};
addCallbackRecord(m_cleanupCbs, cbr);
}
template <> void VerilatedTrace<VL_DERIVED_T>::module(const std::string& name) VL_MT_UNSAFE {
// Called via callbacks way above in call stack, which already hold m_mutex
m_moduleName = name;
template <> void VerilatedTrace<VL_DERIVED_T>::pushNamePrefix(const std::string& prefix) {
m_namePrefixStack.push_back(m_namePrefixStack.back() + prefix);
}
template <> void VerilatedTrace<VL_DERIVED_T>::popNamePrefix(unsigned count) {
while (count--) m_namePrefixStack.pop_back();
assert(!m_namePrefixStack.empty());
}
//=========================================================================

View File

@ -477,10 +477,7 @@ void VerilatedVcd::declare(vluint32_t code, const char* name, const char* wirep,
// 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}"
std::string nameasstr = name;
if (!moduleName().empty()) {
nameasstr = moduleName() + scopeEscape() + nameasstr; // Optional ->module prefix
}
std::string nameasstr = namePrefix() + name;
std::string hiername;
std::string basename;
for (const char* cp = nameasstr.c_str(); *cp; cp++) {
@ -830,16 +827,19 @@ float flo = 0.0f;
void vcdInit(void*, VerilatedVcd* vcdp, vluint32_t) {
vcdp->scopeEscape('.');
vcdp->module("top");
vcdp->pushNamePrefix("top.");
/**/ vcdp->declBus(0x2, "v1", -1, 0, 5, 1);
/**/ vcdp->declBus(0x3, "v2", -1, 0, 6, 1);
/**/ vcdp->module("top.sub1");
/**/ vcdp->pushNamePrefix("sub1.");
/***/ vcdp->declBit(0x4, "s1", -1, 0);
/***/ vcdp->declBit(0x5, "ch", -1, 0);
/**/ vcdp->module("top.sub2");
/**/ vcdp->popNamePrefix();
/**/ vcdp->pushNamePrefix("sub2.");
/***/ vcdp->declArray(0x6, "s2", -1, 0, 40, 3);
/**/ vcdp->popNamePrefix();
vcdp->popNamePrefix();
// Note need to add 3 for next code.
vcdp->module("top2");
vcdp->pushNamePrefix("top2.");
/**/ vcdp->declBus(0x2, "t2v1", -1, 0, 4, 1);
/**/ vcdp->declTriBit(0x10, "io1", -1, 0);
/**/ vcdp->declTriBus(0x12, "io5", -1, 0, 4, 0);
@ -851,6 +851,7 @@ void vcdInit(void*, VerilatedVcd* vcdp, vluint32_t) {
/**/ // Note need to add 4 for next code.
/**/ vcdp->declTriQuad(0x24, "tq", -1, 0, 63, 0);
/**/ // Note need to add 4 for next code.
vcdp->popNamePrefix();
}
void vcdFull(void*, VerilatedVcd* vcdp) {

View File

@ -5257,6 +5257,28 @@ public:
AstNode* widthp() const { return op4p(); }
};
class AstTracePushNamePrefix final : public AstNodeStmt {
const string m_prefix; // Prefix to add to signal names
public:
AstTracePushNamePrefix(FileLine* fl, const string& prefix)
: ASTGEN_SUPER_TracePushNamePrefix(fl)
, m_prefix{prefix} {}
ASTNODE_NODE_FUNCS(TracePushNamePrefix)
virtual bool same(const AstNode* samep) const override { return false; }
string prefix() const { return m_prefix; }
};
class AstTracePopNamePrefix final : public AstNodeStmt {
const unsigned m_count; // How many levels to pop
public:
AstTracePopNamePrefix(FileLine* fl, unsigned count)
: ASTGEN_SUPER_TracePopNamePrefix(fl)
, m_count{count} {}
ASTNODE_NODE_FUNCS(TracePopNamePrefix)
virtual bool same(const AstNode* samep) const override { return false; }
unsigned count() const { return m_count; }
};
class AstTraceDecl final : public AstNodeStmt {
// Trace point declaration
// Separate from AstTraceInc; as a declaration can't be deleted
@ -5271,12 +5293,10 @@ private:
const AstVarType m_varType; // Type of variable (for localparam vs. param)
const AstBasicDTypeKwd m_declKwd; // Keyword at declaration time
const VDirection m_declDirection; // Declared direction input/output etc
const bool m_isScoped; // Uses run-time scope (for interfaces)
public:
AstTraceDecl(FileLine* fl, const string& showname,
AstVar* varp, // For input/output state etc
AstNode* valuep, const VNumRange& bitRange, const VNumRange& arrayRange,
bool isScoped)
AstNode* valuep, const VNumRange& bitRange, const VNumRange& arrayRange)
: ASTGEN_SUPER_TraceDecl(fl)
, m_showname{showname}
, m_bitRange{bitRange}
@ -5286,8 +5306,7 @@ public:
* (VL_EDATASIZE / 32))) // A code is always 32-bits
, m_varType{varp->varType()}
, m_declKwd{varp->declKwd()}
, m_declDirection{varp->declDirection()}
, m_isScoped{isScoped} {
, m_declDirection{varp->declDirection()} {
dtypeFrom(valuep);
addNOp1p(valuep);
}
@ -5307,7 +5326,6 @@ public:
AstVarType varType() const { return m_varType; }
AstBasicDTypeKwd declKwd() const { return m_declKwd; }
VDirection declDirection() const { return m_declDirection; }
bool isScoped() const { return m_isScoped; }
AstNode* valuep() const { return op1p(); }
};

View File

@ -441,9 +441,6 @@ public:
iterateAndNextNull(nodep->exprp());
puts("; }\n");
}
virtual void visit(AstIntfRef* nodep) override {
putsQuoted(VIdProtect::protectWordsIf(AstNode::vcdName(nodep->name()), nodep->protect()));
}
virtual void visit(AstNodeCase* nodep) override { // LCOV_EXCL_LINE
// In V3Case...
nodep->v3fatalSrc("Case statements should have been reduced out");

View File

@ -631,9 +631,7 @@ class EmitCTrace final : EmitCFunc {
puts("(c+" + cvtToStr(nodep->code()));
if (nodep->arrayRange().ranged()) puts("+i*" + cvtToStr(nodep->widthWords()));
puts(",");
if (nodep->isScoped()) puts("Verilated::catName(scopep,");
putsQuoted(VIdProtect::protectWordsIf(nodep->showname(), nodep->protect()));
if (nodep->isScoped()) puts(",(int)scopet,\" \")");
// Direction
if (v3Global.opt.traceFormat().fst()) {
puts("," + cvtToStr(enumNum));
@ -836,12 +834,22 @@ class EmitCTrace final : EmitCFunc {
EmitCFunc::visit(nodep);
}
virtual void visit(AstTracePushNamePrefix* nodep) override {
puts("tracep->pushNamePrefix(");
putsQuoted(VIdProtect::protectWordsIf(nodep->prefix(), nodep->protect()));
puts(");\n");
}
virtual void visit(AstTracePopNamePrefix* nodep) override { //
puts("tracep->popNamePrefix(");
puts(cvtToStr(nodep->count()));
puts(");\n");
}
virtual void visit(AstTraceDecl* nodep) override {
const int enumNum = emitTraceDeclDType(nodep->dtypep());
if (nodep->arrayRange().ranged()) {
puts("{int i; for (i=0; i<" + cvtToStr(nodep->arrayRange().elements()) + "; i++) {\n");
puts("for (int i = 0; i < " + cvtToStr(nodep->arrayRange().elements()) + "; ++i) {\n");
emitTraceInitOne(nodep, enumNum);
puts("}}\n");
puts("\n}\n");
} else {
emitTraceInitOne(nodep, enumNum);
puts("\n");

View File

@ -563,9 +563,10 @@ class EmitCModel final : public EmitCFunc {
"0.\");\n");
puts("}\n");
puts("vlSymsp->__Vm_baseCode = code;\n");
puts("tracep->module(vlSymsp->name());\n");
puts("tracep->scopeEscape(' ');\n");
puts("tracep->pushNamePrefix(std::string{vlSymsp->name()} + ' ');\n");
puts(topModNameProtected + "__" + protect("trace_init_top") + "(vlSelf, tracep);\n");
puts("tracep->popNamePrefix();\n");
puts("tracep->scopeEscape('.');\n"); // Restore so later traced files won't break
puts("}\n");

View File

@ -29,6 +29,62 @@
#include "V3EmitCBase.h"
#include "V3Stats.h"
#include <algorithm>
#include <functional>
#include <limits>
#include <vector>
//######################################################################
// Utility class to emit path adjustments
class PathAdjustor final {
FileLine* const m_flp; // FileLine used for created nodes
std::function<void(AstNodeStmt*)> m_emit; // Function called with adjustment statements
std::vector<std::string> m_stack{""}; // Stack of current paths
static constexpr char SEPARATOR = ' ';
public:
explicit PathAdjustor(FileLine* flp, std::function<void(AstNodeStmt*)> emit)
: m_flp{flp}
, m_emit{emit} {}
// Emit Prefix adjustments until the current path is 'newPath'
void adjust(const string& newPath) {
// Move up to enclosing path
unsigned toPop = 0;
while (!VString::startsWith(newPath, m_stack.back())) {
++toPop;
m_stack.pop_back();
}
if (toPop) m_emit(new AstTracePopNamePrefix{m_flp, toPop});
// Move down, one path element at a time
if (newPath != m_stack.back()) {
const string& extraPrefix = newPath.substr(m_stack.back().size());
size_t begin = 0;
while (true) {
const size_t end = extraPrefix.find(SEPARATOR, begin);
if (end == string::npos) break;
const string& extra = extraPrefix.substr(begin, end + 1 - begin);
m_emit(new AstTracePushNamePrefix{m_flp, extra});
m_stack.push_back(m_stack.back() + extra);
begin = end + 1;
}
const string& extra = extraPrefix.substr(begin);
if (!extra.empty()) {
m_emit(new AstTracePushNamePrefix{m_flp, extra + SEPARATOR});
m_stack.push_back(m_stack.back() + extra);
}
}
}
// Emit Prefix adjustments to unwind the path back to its original state
void unwind() {
const unsigned toPop = m_stack.size() - 1;
if (toPop) m_emit(new AstTracePopNamePrefix{m_flp, toPop});
}
};
//######################################################################
// TraceDecl state, as a visitor of each AstNode
@ -37,15 +93,38 @@ private:
// NODE STATE
// STATE
AstScope* const m_topScopep = v3Global.rootp()->topScopep()->scopep(); // The top AstScope
AstCFunc* m_initFuncp = nullptr; // Trace function being built
AstCFunc* m_initSubFuncp = nullptr; // Trace function being built (under m_init)
int m_initSubStmts = 0; // Number of statements in function
int m_funcNum = 0; // Function number being built
const AstVarScope* m_traVscp = nullptr; // Signal being trace constructed
AstNode* m_traValuep = nullptr; // Signal being traced's value to trace in it
string m_traShowname; // Signal being traced's component name
bool m_interface = false; // Currently tracing an interface
AstTopScope* const m_topScopep; // The singleton AstTopScope
const AstScope* m_currScopep = nullptr; // Current scope being visited
std::vector<AstCFunc*> m_topFuncps; // Top level trace initialization functions
std::vector<AstCFunc*> m_subFuncps; // Trace sub functions for this scope
int m_topFuncSize = 0; // Size of the top function currently being built
int m_subFuncSize = 0; // Size of the sub function currently being built
const int m_funcSizeLimit // Maximum size of a function
= v3Global.opt.outputSplitCTrace() ? v3Global.opt.outputSplitCTrace()
: std::numeric_limits<int>::max();
// Trace init sub functions to invoke for path names in the hierarchy. Note path names and
// AstScope instances are not one to one due to the presence of AstIntfRef.
std::map<std::string, std::vector<AstCFunc*>> m_scopeSubFuncps;
struct Signal final {
AstVarScope* m_vscp; // AstVarScope being traced (non const to allow copy during sorting)
std::string m_path; // Path to enclosing module in hierarchy
std::string m_name; // Name of signal
Signal(AstVarScope* vscp)
: m_vscp{vscp} {
// Compute path in hierarchy and signal name
const string& vcdName = AstNode::vcdName(vscp->varp()->name());
const size_t pos = vcdName.rfind(' ');
const size_t pathLen = pos == string::npos ? 0 : pos + 1;
m_path = vcdName.substr(0, pathLen);
m_name = vcdName.substr(pathLen);
}
};
std::vector<Signal> m_signals; // Signals under current scope
AstVarScope* m_traVscp = nullptr; // Current AstVarScope we are constructing AstTraceDecls for
AstNode* m_traValuep = nullptr; // Value expression for current signal
string m_traName; // Name component for current signal
VDouble0 m_statSigs; // Statistic tracking
VDouble0 m_statIgnSigs; // Statistic tracking
@ -69,38 +148,44 @@ private:
return nullptr;
}
AstCFunc* newCFunc(const string& name) {
FileLine* const flp = m_topScopep->fileline();
AstCFunc* const funcp = new AstCFunc(flp, name, m_topScopep);
string argTypes = v3Global.opt.traceClassBase() + "* tracep";
if (m_interface) argTypes += ", int scopet, const char* scopep";
funcp->argTypes(argTypes);
AstCFunc* newCFunc(FileLine* flp, const string& name) {
AstScope* const topScopep = m_topScopep->scopep();
AstCFunc* const funcp = new AstCFunc{flp, name, topScopep};
funcp->argTypes(v3Global.opt.traceClassBase() + "* tracep");
funcp->isTrace(true);
funcp->isStatic(false);
funcp->isLoose(true);
funcp->slow(true);
m_topScopep->addActivep(funcp);
UINFO(5, " Newfunc " << funcp << endl);
topScopep->addActivep(funcp);
return funcp;
}
void callCFuncSub(AstCFunc* basep, AstCFunc* funcp, AstIntfRef* irp) {
AstCCall* const callp = new AstCCall(funcp->fileline(), funcp);
if (irp) {
callp->argTypes("tracep, VLT_TRACE_SCOPE_INTERFACE");
callp->addArgsp(irp->unlinkFrBack());
} else {
callp->argTypes("tracep");
void addToTopFunc(AstNodeStmt* stmtp) {
if (m_topFuncSize > m_funcSizeLimit || m_topFuncps.empty()) {
m_topFuncSize = 0;
//
const string n = cvtToStr(m_topFuncps.size());
const string name{"trace_init_top__" + n};
AstCFunc* const funcp = newCFunc(m_topScopep->fileline(), name);
m_topFuncps.push_back(funcp);
}
basep->addStmtsp(callp);
m_topFuncps.back()->addStmtsp(stmtp);
m_topFuncSize += EmitCBaseCounterVisitor{stmtp}.count();
}
AstCFunc* newCFuncSub(AstCFunc* basep) {
FileLine* const fl = basep->fileline();
const string name = "trace_init_sub_" + cvtToStr(m_funcNum++);
AstCFunc* const funcp = newCFunc(name);
funcp->addInitsp(new AstCStmt(fl, "const int c = vlSymsp->__Vm_baseCode;\n"));
funcp->addInitsp(new AstCStmt(fl, "if (false && tracep && c) {} // Prevent unused\n"));
if (!m_interface) callCFuncSub(basep, funcp, nullptr);
return funcp;
void addToSubFunc(AstNodeStmt* stmtp) {
if (m_subFuncSize > m_funcSizeLimit || m_subFuncps.empty()) {
m_subFuncSize = 0;
//
FileLine* const flp = m_currScopep->fileline();
const string n = cvtToStr(m_subFuncps.size());
const string name{"trace_init_sub__" + m_currScopep->nameDotless() + "__" + n};
AstCFunc* const funcp = newCFunc(flp, name);
funcp->addInitsp(new AstCStmt{flp, "const int c = vlSymsp->__Vm_baseCode;\n"});
m_subFuncps.push_back(funcp);
}
m_subFuncps.back()->addStmtsp(stmtp);
m_subFuncSize += EmitCBaseCounterVisitor{stmtp}.count();
}
std::string getScopeChar(VltTraceScope sct) { return std::string(1, (char)(0x80 + sct)); }
@ -114,114 +199,124 @@ private:
} else if (const AstBasicDType* const bdtypep = m_traValuep->dtypep()->basicp()) {
bitRange = bdtypep->nrange();
}
AstTraceDecl* const declp
= new AstTraceDecl(m_traVscp->fileline(), m_traShowname, m_traVscp->varp(),
m_traValuep->cloneTree(true), bitRange, arrayRange, m_interface);
UINFO(9, "Decl " << declp << endl);
if (!m_interface && v3Global.opt.outputSplitCTrace()
&& m_initSubStmts > v3Global.opt.outputSplitCTrace()) {
m_initSubFuncp = newCFuncSub(m_initFuncp);
m_initSubStmts = 0;
}
m_initSubFuncp->addStmtsp(declp);
m_initSubStmts += EmitCBaseCounterVisitor(declp).count();
addToSubFunc(new AstTraceDecl{m_traVscp->fileline(), m_traName, m_traVscp->varp(),
m_traValuep->cloneTree(false), bitRange, arrayRange});
}
void addIgnore(const char* why) {
++m_statIgnSigs;
m_initSubFuncp->addStmtsp(new AstComment(
m_traVscp->fileline(), "Tracing: " + m_traShowname + " // Ignored: " + why, true));
addToSubFunc(new AstComment{m_traVscp->fileline(),
"Tracing: " + m_traName + " // Ignored: " + why, true});
}
// VISITORS
virtual void visit(AstTopScope* nodep) override {
// Create the trace init function
m_initFuncp = newCFunc("trace_init_top");
// Create initial sub function
m_initSubFuncp = newCFuncSub(m_initFuncp);
// And find variables
iterateChildren(nodep);
}
virtual void visit(AstScope* nodep) override {
const AstCell* const cellp = nodep->aboveCellp();
if (cellp && VN_IS(cellp->modp(), Iface)) {
AstCFunc* const origSubFunc = m_initSubFuncp;
int origSubStmts = m_initSubStmts;
{
m_interface = true;
m_initSubFuncp = newCFuncSub(origSubFunc);
string scopeName = nodep->prettyName();
const size_t lastDot = scopeName.find_last_of('.');
UASSERT_OBJ(lastDot != string::npos, nodep,
"Expected an interface scope name to have at least one dot");
scopeName = scopeName.substr(0, lastDot + 1);
const size_t scopeLen = scopeName.length();
UASSERT_OBJ(!m_currScopep, nodep, "Should not nest");
UASSERT_OBJ(m_subFuncps.empty(), nodep, "Should not nest");
UASSERT_OBJ(m_signals.empty(), nodep, "Should not nest");
UASSERT_OBJ(!m_traVscp, nodep, "Should not nest");
UASSERT_OBJ(m_traName.empty(), nodep, "Should not nest");
AstIntfRef* nextIrp = cellp->intfRefp();
// While instead of for loop because interface references will
// be unlinked as we go
while (nextIrp) {
AstIntfRef* const irp = nextIrp;
nextIrp = VN_AS(irp->nextp(), IntfRef);
FileLine* const flp = nodep->fileline();
m_currScopep = nodep;
const string irpName = irp->prettyName();
if (scopeLen > irpName.length()) continue;
const string intfScopeName = irpName.substr(0, scopeLen);
if (scopeName != intfScopeName) continue;
callCFuncSub(origSubFunc, m_initSubFuncp, irp);
++origSubStmts;
}
iterateChildren(nodep);
}
m_initSubFuncp = origSubFunc;
m_initSubStmts = origSubStmts;
m_interface = false;
} else {
iterateChildren(nodep);
// Gather all signals under this AstScope
iterateChildrenConst(nodep);
// If nothing to trace in this scope, then job done
if (m_signals.empty()) {
m_currScopep = nullptr;
return;
}
}
virtual void visit(AstVarScope* nodep) override {
iterateChildren(nodep);
// Prefilter - things that get through this if will either get
// traced or get a comment as to why not traced.
// Generally this equation doesn't need updating, instead use
// varp->isTrace() and/or vscIgnoreTrace.
if ((!nodep->varp()->isTemp() || nodep->varp()->isTrace())
&& !nodep->varp()->isClassMember() && !nodep->varp()->isFuncLocal()) {
UINFO(5, " vsc " << nodep << endl);
const AstVar* const varp = nodep->varp();
const AstScope* const scopep = nodep->scopep();
// Compute show name
// This code assumes SPTRACEVCDC_VERSION >= 1330;
// it uses spaces to separate hierarchy components.
if (m_interface) {
m_traShowname = AstNode::vcdName(varp->name());
} else {
m_traShowname = AstNode::vcdName(scopep->name() + " " + varp->name());
if (m_traShowname.substr(0, 4) == "TOP ") m_traShowname.erase(0, 4);
}
UASSERT_OBJ(m_initSubFuncp, nodep, "nullptr");
m_traVscp = nodep;
if (const char* const ignoreReasonp = vscIgnoreTrace(nodep)) {
// Sort signals, first by enclosing instance, then by source location, then by name
std::stable_sort(m_signals.begin(), m_signals.end(), [](const Signal& a, const Signal& b) {
if (const int cmp = a.m_path.compare(b.m_path)) return cmp < 0;
const FileLine* const aflp = a.m_vscp->fileline();
const FileLine* const bflp = b.m_vscp->fileline();
if (const int cmp = aflp->operatorCompare(*bflp)) return cmp < 0;
return a.m_name < b.m_name;
});
// Build trace initialization functions for this AstScope
PathAdjustor pathAdjustor{flp, [&](AstNodeStmt* stmtp) { addToSubFunc(stmtp); }};
for (const Signal& signal : m_signals) {
// Adjust name prefix based on path in hierarchy
pathAdjustor.adjust(signal.m_path);
// Build AstTraceDecl for this signal
m_traVscp = signal.m_vscp;
m_traName = signal.m_name;
if (const char* const ignoreReasonp = vscIgnoreTrace(m_traVscp)) {
addIgnore(ignoreReasonp);
} else {
++m_statSigs;
if (nodep->valuep()) {
m_traValuep = nodep->valuep()->cloneTree(true);
if (AstNode* const valuep = m_traVscp->valuep()) {
m_traValuep = valuep->cloneTree(false);
} else {
m_traValuep = new AstVarRef(nodep->fileline(), nodep, VAccess::READ);
m_traValuep = new AstVarRef{m_traVscp->fileline(), m_traVscp, VAccess::READ};
}
// Recurse into data type of the signal; the visitors will call addTraceDecl()
iterate(varp->dtypep()->skipRefToEnump());
// Recurse into data type of the signal. The visit methods will add AstTraceDecls.
iterate(m_traVscp->varp()->dtypep()->skipRefToEnump());
// Cleanup
if (m_traValuep) VL_DO_CLEAR(m_traValuep->deleteTree(), m_traValuep = nullptr);
if (m_traValuep) VL_DO_DANGLING(m_traValuep->deleteTree(), m_traValuep);
}
m_traVscp = nullptr;
m_traShowname = "";
}
pathAdjustor.unwind();
m_traVscp = nullptr;
m_traName.clear();
UASSERT_OBJ(!m_traValuep, nodep, "Should have been deleted");
m_signals.clear();
// Add sub functions to m_scopeSubFuncps
const AstCell* const cellp = nodep->aboveCellp();
if (cellp && VN_IS(cellp->modp(), Iface)) {
string scopeName = nodep->prettyName();
const size_t lastDot = scopeName.find_last_of('.');
UASSERT_OBJ(lastDot != string::npos, nodep,
"Expected an interface scope name to have at least one dot");
scopeName = scopeName.substr(0, lastDot + 1);
const size_t scopeLen = scopeName.length();
for (AstIntfRef *irp = cellp->intfRefp(), *nextIrp; irp; irp = nextIrp) {
nextIrp = VN_AS(irp->nextp(), IntfRef);
const string irpName = irp->prettyName();
if (scopeLen > irpName.length()) continue;
const string intfScopeName = irpName.substr(0, scopeLen);
if (scopeName != intfScopeName) continue;
string scopeName = AstNode::vcdName(irp->name());
if (scopeName.substr(0, 4) == "TOP ") scopeName.erase(0, 4);
scopeName += getScopeChar(VLT_TRACE_SCOPE_INTERFACE) + ' ';
m_scopeSubFuncps.emplace(scopeName, m_subFuncps);
VL_DO_DANGLING(irp->unlinkFrBack(), irp);
}
m_subFuncps.clear();
} else {
string scopeName = AstNode::vcdName(nodep->name()) + ' ';
if (VString::startsWith(scopeName, "TOP ")) scopeName.erase(0, 4);
m_scopeSubFuncps.emplace(scopeName, std::move(m_subFuncps));
}
m_currScopep = nullptr;
}
virtual void visit(AstVarScope* nodep) override {
UASSERT_OBJ(m_currScopep, nodep, "AstVarScope not under AstScope");
// Prefilter - things that get added to m_vscps will either get traced or get a comment as
// to why they are not traced. Generally these conditions doesn't need updating, instead
// use varp->isTrace() and/or vscIgnoreTrace.
if (nodep->varp()->isTemp() && !nodep->varp()->isTrace()) return;
if (nodep->varp()->isClassMember()) return;
if (nodep->varp()->isFuncLocal()) return;
// Add to traced signal list
m_signals.emplace_back(nodep);
}
// VISITORS - Data types when tracing
virtual void visit(AstConstDType* nodep) override {
if (m_traVscp) iterate(nodep->subDTypep()->skipRefToEnump());
@ -247,20 +342,20 @@ private:
}
} else {
// Unroll now, as have no other method to get right signal names
FileLine* const flp = nodep->fileline();
AstNodeDType* const subtypep = nodep->subDTypep()->skipRefToEnump();
VL_RESTORER(m_traName);
addToSubFunc(new AstTracePushNamePrefix{flp, m_traName});
for (int i = nodep->lo(); i <= nodep->hi(); ++i) {
VL_RESTORER(m_traShowname);
VL_RESTORER(m_traValuep);
{
m_traShowname += string("[") + cvtToStr(i) + string("]");
m_traValuep = new AstArraySel(
nodep->fileline(), m_traValuep->cloneTree(true), i - nodep->lo());
m_traValuep->dtypep(subtypep);
iterate(subtypep);
VL_DO_CLEAR(m_traValuep->deleteTree(), m_traValuep = nullptr);
}
m_traName = string{"["} + cvtToStr(i) + string{"]"};
m_traValuep = m_traValuep->cloneTree(false);
m_traValuep = new AstArraySel{flp, m_traValuep, i - nodep->lo()};
m_traValuep->dtypep(subtypep);
iterate(subtypep);
VL_DO_CLEAR(m_traValuep->deleteTree(), m_traValuep = nullptr);
}
addToSubFunc(new AstTracePopNamePrefix{flp, 1});
}
}
}
@ -272,20 +367,21 @@ private:
// a much faster way to trace
addTraceDecl(VNumRange(), nodep->width());
} else {
FileLine* const flp = nodep->fileline();
AstNodeDType* const subtypep = nodep->subDTypep()->skipRefToEnump();
VL_RESTORER(m_traName);
addToSubFunc(new AstTracePushNamePrefix{flp, m_traName});
for (int i = nodep->lo(); i <= nodep->hi(); ++i) {
VL_RESTORER(m_traShowname);
VL_RESTORER(m_traValuep);
{
m_traShowname += string("[") + cvtToStr(i) + string("]");
m_traValuep
= new AstSel(nodep->fileline(), m_traValuep->cloneTree(true),
(i - nodep->lo()) * subtypep->width(), subtypep->width());
m_traValuep->dtypep(subtypep);
iterate(subtypep);
VL_DO_CLEAR(m_traValuep->deleteTree(), m_traValuep = nullptr);
}
m_traName = string{"["} + cvtToStr(i) + string{"]"};
const int lsb = (i - nodep->lo()) * subtypep->width();
m_traValuep = m_traValuep->cloneTree(false);
m_traValuep = new AstSel{flp, m_traValuep, lsb, subtypep->width()};
m_traValuep->dtypep(subtypep);
iterate(subtypep);
VL_DO_CLEAR(m_traValuep->deleteTree(), m_traValuep = nullptr);
}
addToSubFunc(new AstTracePopNamePrefix{flp, 1});
}
}
}
@ -299,31 +395,30 @@ private:
} else if (!nodep->packed()) {
addIgnore("Unsupported: Unpacked struct/union");
} else {
FileLine* const flp = nodep->fileline();
const bool isStruct = VN_IS(nodep, StructDType); // Otherwise union
VL_RESTORER(m_traName);
string prefix{m_traName};
prefix += isStruct ? getScopeChar(VLT_TRACE_SCOPE_STRUCT) // Mark scope type
: getScopeChar(VLT_TRACE_SCOPE_UNION);
addToSubFunc(new AstTracePushNamePrefix{flp, prefix + ' '});
for (const AstMemberDType* itemp = nodep->membersp(); itemp;
itemp = VN_AS(itemp->nextp(), MemberDType)) {
AstNodeDType* const subtypep = itemp->subDTypep()->skipRefToEnump();
VL_RESTORER(m_traShowname);
VL_RESTORER(m_traValuep);
{
if (VN_IS(nodep, StructDType)) {
// Mark scope as a struct by setting the last char to 0x80 + the
// fstScopeType
m_traShowname += getScopeChar(VLT_TRACE_SCOPE_STRUCT) + " "
+ itemp->prettyName();
m_traValuep
= new AstSel(nodep->fileline(), m_traValuep->cloneTree(true),
itemp->lsb(), subtypep->width());
m_traValuep->dtypep(subtypep);
iterate(subtypep);
VL_DO_CLEAR(m_traValuep->deleteTree(), m_traValuep = nullptr);
} else { // Else union, replicate fields
m_traShowname
+= getScopeChar(VLT_TRACE_SCOPE_UNION) + " " + itemp->prettyName();
iterate(subtypep);
}
m_traName = itemp->prettyName();
if (isStruct) {
VL_RESTORER(m_traValuep);
m_traValuep = m_traValuep->cloneTree(false);
m_traValuep
= new AstSel{flp, m_traValuep, itemp->lsb(), subtypep->width()};
m_traValuep->dtypep(subtypep);
iterate(subtypep);
VL_DO_CLEAR(m_traValuep->deleteTree(), m_traValuep = nullptr);
} else { // Else union, replicate fields
iterate(subtypep);
}
}
addToSubFunc(new AstTracePopNamePrefix{flp, 1});
}
}
}
@ -348,7 +443,48 @@ private:
public:
// CONSTRUCTORS
explicit TraceDeclVisitor(AstNetlist* nodep) { iterate(nodep); }
explicit TraceDeclVisitor(AstNetlist* nodep)
: m_topScopep{nodep->topScopep()} {
FileLine* const flp = nodep->fileline();
// Iterate modules to build per scope initialization sub functions
iterateAndNextConstNull(nodep->modulesp());
UASSERT_OBJ(m_subFuncps.empty(), nodep, "Should have been emptied");
// Build top level trace initialization functions
PathAdjustor pathAdjustor{flp, [&](AstNodeStmt* stmtp) { addToTopFunc(stmtp); }};
for (const auto& item : m_scopeSubFuncps) {
// Adjust name prefix based on path in hierarchy
pathAdjustor.adjust(item.first);
// Call all sub functions for this path
for (AstCFunc* const subFuncp : item.second) {
AstCCall* const callp = new AstCCall{flp, subFuncp};
callp->argTypes("tracep");
addToTopFunc(callp);
}
}
pathAdjustor.unwind();
// Ensure a top function exists, in case there was nothing to trace at all
if (m_topFuncps.empty()) addToTopFunc(new AstComment{flp, "Empty"});
// Create single top level function, if more than one exists
if (m_topFuncps.size() > 1) {
AstCFunc* const topFuncp = newCFunc(flp, "");
for (AstCFunc* funcp : m_topFuncps) {
AstCCall* const callp = new AstCCall{flp, funcp};
callp->argTypes("tracep");
topFuncp->addStmtsp(callp);
}
m_topFuncps.clear();
m_topFuncps.push_back(topFuncp);
}
// Set name of top level function
AstCFunc* const topFuncp = m_topFuncps.front();
topFuncp->name("trace_init_top");
}
virtual ~TraceDeclVisitor() override {
V3Stats::addStat("Tracing, Traced signals", m_statSigs);
V3Stats::addStat("Tracing, Ignored signals", m_statIgnSigs);

View File

@ -1,7 +1,6 @@
$version Generated by VerilatedVcd $end
$date Sun May 31 15:48:42 2020
$end
$timescale 1ps $end
$date Sat Dec 18 13:32:31 2021 $end
$timescale 1ps $end
$scope module top $end
$var wire 1 W clk $end
@ -11,31 +10,31 @@ $timescale 1ps $end
$var wire 8 ' cyc_copy [7:0] $end
$var wire 1 % toggle $end
$var wire 32 ; vlCoverageLineTrace_t_cover_line__102_elsif [31:0] $end
$var wire 32 : vlCoverageLineTrace_t_cover_line__105_elsif [31:0] $end
$var wire 32 9 vlCoverageLineTrace_t_cover_line__112_else [31:0] $end
$var wire 32 8 vlCoverageLineTrace_t_cover_line__112_if [31:0] $end
$var wire 32 < vlCoverageLineTrace_t_cover_line__105_elsif [31:0] $end
$var wire 32 = vlCoverageLineTrace_t_cover_line__112_else [31:0] $end
$var wire 32 > vlCoverageLineTrace_t_cover_line__112_if [31:0] $end
$var wire 32 X vlCoverageLineTrace_t_cover_line__119_block [31:0] $end
$var wire 32 # vlCoverageLineTrace_t_cover_line__15_block [31:0] $end
$var wire 32 $ vlCoverageLineTrace_t_cover_line__18_block [31:0] $end
$var wire 32 > vlCoverageLineTrace_t_cover_line__47_block [31:0] $end
$var wire 32 = vlCoverageLineTrace_t_cover_line__48_else [31:0] $end
$var wire 32 < vlCoverageLineTrace_t_cover_line__48_if [31:0] $end
$var wire 32 ) vlCoverageLineTrace_t_cover_line__52_else [31:0] $end
$var wire 32 ( vlCoverageLineTrace_t_cover_line__52_if [31:0] $end
$var wire 32 + vlCoverageLineTrace_t_cover_line__53_else [31:0] $end
$var wire 32 * vlCoverageLineTrace_t_cover_line__53_if [31:0] $end
$var wire 32 - vlCoverageLineTrace_t_cover_line__58_else [31:0] $end
$var wire 32 , vlCoverageLineTrace_t_cover_line__58_if [31:0] $end
$var wire 32 / vlCoverageLineTrace_t_cover_line__59_else [31:0] $end
$var wire 32 . vlCoverageLineTrace_t_cover_line__59_if [31:0] $end
$var wire 32 1 vlCoverageLineTrace_t_cover_line__65_else [31:0] $end
$var wire 32 0 vlCoverageLineTrace_t_cover_line__65_if [31:0] $end
$var wire 32 3 vlCoverageLineTrace_t_cover_line__66_else [31:0] $end
$var wire 32 2 vlCoverageLineTrace_t_cover_line__66_if [31:0] $end
$var wire 32 ( vlCoverageLineTrace_t_cover_line__47_block [31:0] $end
$var wire 32 ) vlCoverageLineTrace_t_cover_line__48_else [31:0] $end
$var wire 32 * vlCoverageLineTrace_t_cover_line__48_if [31:0] $end
$var wire 32 + vlCoverageLineTrace_t_cover_line__52_else [31:0] $end
$var wire 32 , vlCoverageLineTrace_t_cover_line__52_if [31:0] $end
$var wire 32 - vlCoverageLineTrace_t_cover_line__53_else [31:0] $end
$var wire 32 . vlCoverageLineTrace_t_cover_line__53_if [31:0] $end
$var wire 32 / vlCoverageLineTrace_t_cover_line__58_else [31:0] $end
$var wire 32 0 vlCoverageLineTrace_t_cover_line__58_if [31:0] $end
$var wire 32 1 vlCoverageLineTrace_t_cover_line__59_else [31:0] $end
$var wire 32 2 vlCoverageLineTrace_t_cover_line__59_if [31:0] $end
$var wire 32 3 vlCoverageLineTrace_t_cover_line__65_else [31:0] $end
$var wire 32 4 vlCoverageLineTrace_t_cover_line__65_if [31:0] $end
$var wire 32 5 vlCoverageLineTrace_t_cover_line__66_else [31:0] $end
$var wire 32 6 vlCoverageLineTrace_t_cover_line__66_if [31:0] $end
$var wire 32 7 vlCoverageLineTrace_t_cover_line__75_elsif [31:0] $end
$var wire 32 6 vlCoverageLineTrace_t_cover_line__79_elsif [31:0] $end
$var wire 32 5 vlCoverageLineTrace_t_cover_line__83_else [31:0] $end
$var wire 32 4 vlCoverageLineTrace_t_cover_line__83_if [31:0] $end
$var wire 32 8 vlCoverageLineTrace_t_cover_line__79_elsif [31:0] $end
$var wire 32 9 vlCoverageLineTrace_t_cover_line__83_else [31:0] $end
$var wire 32 : vlCoverageLineTrace_t_cover_line__83_if [31:0] $end
$var wire 32 ] vlCoverageLineTrace_t_cover_line__92_block [31:0] $end
$var wire 32 ^ vlCoverageLineTrace_t_cover_line__93_block [31:0] $end
$var wire 32 _ vlCoverageLineTrace_t_cover_line__96_block [31:0] $end
@ -43,57 +42,57 @@ $timescale 1ps $end
$scope module a1 $end
$var wire 1 W clk $end
$var wire 1 % toggle $end
$var wire 32 B vlCoverageLineTrace_t_cover_line__132_block [31:0] $end
$var wire 32 ? vlCoverageLineTrace_t_cover_line__132_block [31:0] $end
$var wire 32 @ vlCoverageLineTrace_t_cover_line__133_else [31:0] $end
$var wire 32 ? vlCoverageLineTrace_t_cover_line__133_if [31:0] $end
$var wire 32 A vlCoverageLineTrace_t_cover_line__137_else [31:0] $end
$var wire 32 A vlCoverageLineTrace_t_cover_line__133_if [31:0] $end
$var wire 32 B vlCoverageLineTrace_t_cover_line__137_else [31:0] $end
$upscope $end
$scope module a2 $end
$var wire 1 W clk $end
$var wire 1 % toggle $end
$var wire 32 F vlCoverageLineTrace_t_cover_line__132_block [31:0] $end
$var wire 32 C vlCoverageLineTrace_t_cover_line__132_block [31:0] $end
$var wire 32 D vlCoverageLineTrace_t_cover_line__133_else [31:0] $end
$var wire 32 C vlCoverageLineTrace_t_cover_line__133_if [31:0] $end
$var wire 32 E vlCoverageLineTrace_t_cover_line__137_else [31:0] $end
$var wire 32 E vlCoverageLineTrace_t_cover_line__133_if [31:0] $end
$var wire 32 F vlCoverageLineTrace_t_cover_line__137_else [31:0] $end
$upscope $end
$scope module b1 $end
$var wire 1 W clk $end
$var wire 1 % toggle $end
$var wire 32 O vlCoverageLineTrace_t_cover_line__156_block [31:0] $end
$var wire 32 K vlCoverageLineTrace_t_cover_line__158_else [31:0] $end
$var wire 32 K vlCoverageLineTrace_t_cover_line__156_block [31:0] $end
$var wire 32 L vlCoverageLineTrace_t_cover_line__158_else [31:0] $end
$var wire 32 b vlCoverageLineTrace_t_cover_line__158_if [31:0] $end
$var wire 32 M vlCoverageLineTrace_t_cover_line__162_else [31:0] $end
$var wire 32 L vlCoverageLineTrace_t_cover_line__162_if [31:0] $end
$var wire 32 N vlCoverageLineTrace_t_cover_line__166_else [31:0] $end
$var wire 32 N vlCoverageLineTrace_t_cover_line__162_if [31:0] $end
$var wire 32 O vlCoverageLineTrace_t_cover_line__166_else [31:0] $end
$upscope $end
$scope module b2 $end
$var wire 1 W clk $end
$var wire 1 % toggle $end
$var wire 32 T vlCoverageLineTrace_t_cover_line__156_block [31:0] $end
$var wire 32 P vlCoverageLineTrace_t_cover_line__158_else [31:0] $end
$var wire 32 P vlCoverageLineTrace_t_cover_line__156_block [31:0] $end
$var wire 32 Q vlCoverageLineTrace_t_cover_line__158_else [31:0] $end
$var wire 32 c vlCoverageLineTrace_t_cover_line__158_if [31:0] $end
$var wire 32 R vlCoverageLineTrace_t_cover_line__162_else [31:0] $end
$var wire 32 Q vlCoverageLineTrace_t_cover_line__162_if [31:0] $end
$var wire 32 S vlCoverageLineTrace_t_cover_line__166_else [31:0] $end
$var wire 32 S vlCoverageLineTrace_t_cover_line__162_if [31:0] $end
$var wire 32 T vlCoverageLineTrace_t_cover_line__166_else [31:0] $end
$upscope $end
$scope module o1 $end
$var wire 1 W clk $end
$var wire 1 % toggle $end
$var wire 32 J vlCoverageLineTrace_t_cover_line__220_block [31:0] $end
$var wire 32 I vlCoverageLineTrace_t_cover_line__221_else [31:0] $end
$var wire 32 H vlCoverageLineTrace_t_cover_line__221_if [31:0] $end
$var wire 32 G vlCoverageLineTrace_t_cover_line__224_else [31:0] $end
$var wire 32 G vlCoverageLineTrace_t_cover_line__220_block [31:0] $end
$var wire 32 H vlCoverageLineTrace_t_cover_line__221_else [31:0] $end
$var wire 32 I vlCoverageLineTrace_t_cover_line__221_if [31:0] $end
$var wire 32 J vlCoverageLineTrace_t_cover_line__224_else [31:0] $end
$var wire 32 a vlCoverageLineTrace_t_cover_line__224_if [31:0] $end
$upscope $end
$scope module t1 $end
$var wire 1 W clk $end
$var wire 1 % toggle $end
$var wire 32 U vlCoverageLineTrace_t_cover_line__187_block [31:0] $end
$var wire 32 \ vlCoverageLineTrace_t_cover_line__191_block [31:0] $end
$var wire 32 Y vlCoverageLineTrace_t_cover_line__191_block [31:0] $end
$var wire 32 Z vlCoverageLineTrace_t_cover_line__194_else [31:0] $end
$var wire 32 Y vlCoverageLineTrace_t_cover_line__194_if [31:0] $end
$var wire 32 [ vlCoverageLineTrace_t_cover_line__194_if [31:0] $end
$var wire 32 V vlCoverageLineTrace_t_cover_line__197_else [31:0] $end
$var wire 32 [ vlCoverageLineTrace_t_cover_line__197_if [31:0] $end
$var wire 32 \ vlCoverageLineTrace_t_cover_line__197_if [31:0] $end
$upscope $end
$upscope $end
$upscope $end
@ -169,7 +168,8 @@ b00000000000000000000000000000000 c
#10
b00000000000000000000000000000010 &
b00000010 '
b00000000000000000000000000000001 )
b00000000000000000000000000000001 (
b00000000000000000000000000000001 *
b00000000000000000000000000000001 +
b00000000000000000000000000000001 -
b00000000000000000000000000000001 /
@ -177,35 +177,35 @@ b00000000000000000000000000000001 1
b00000000000000000000000000000001 3
b00000000000000000000000000000001 5
b00000000000000000000000000000001 9
b00000000000000000000000000000001 <
b00000000000000000000000000000001 >
b00000000000000000000000000000001 =
b00000000000000000000000000000001 ?
b00000000000000000000000000000001 @
b00000000000000000000000000000001 A
b00000000000000000000000000000001 B
b00000000000000000000000000000001 C
b00000000000000000000000000000001 D
b00000000000000000000000000000001 E
b00000000000000000000000000000001 F
b00000000000000000000000000000001 I
b00000000000000000000000000000001 J
b00000000000000000000000000000001 G
b00000000000000000000000000000001 H
b00000000000000000000000000000001 K
b00000000000000000000000000000001 L
b00000000000000000000000000000001 M
b00000000000000000000000000000001 N
b00000000000000000000000000000001 O
b00000000000000000000000000000001 P
b00000000000000000000000000000001 Q
b00000000000000000000000000000001 R
b00000000000000000000000000000001 S
b00000000000000000000000000000001 T
b00000000000000000000000000000001 U
b00000000000000000000000000000001 V
1W
b00000000000000000000000000000001 Y
b00000000000000000000000000000001 Z
b00000000000000000000000000000001 \
#15
0W
#20
b00000000000000000000000000000011 &
b00000011 '
b00000000000000000000000000000010 )
b00000000000000000000000000000010 (
b00000000000000000000000000000010 *
b00000000000000000000000000000010 +
b00000000000000000000000000000010 -
b00000000000000000000000000000010 /
@ -213,315 +213,314 @@ b00000000000000000000000000000010 1
b00000000000000000000000000000010 3
b00000000000000000000000000000010 5
b00000000000000000000000000000010 9
b00000000000000000000000000000010 <
b00000000000000000000000000000010 >
b00000000000000000000000000000010 =
b00000000000000000000000000000010 ?
b00000000000000000000000000000010 @
b00000000000000000000000000000010 A
b00000000000000000000000000000010 B
b00000000000000000000000000000010 C
b00000000000000000000000000000010 D
b00000000000000000000000000000010 E
b00000000000000000000000000000010 F
b00000000000000000000000000000010 I
b00000000000000000000000000000010 J
b00000000000000000000000000000010 G
b00000000000000000000000000000010 H
b00000000000000000000000000000010 K
b00000000000000000000000000000010 L
b00000000000000000000000000000010 M
b00000000000000000000000000000010 N
b00000000000000000000000000000010 O
b00000000000000000000000000000010 P
b00000000000000000000000000000010 Q
b00000000000000000000000000000010 R
b00000000000000000000000000000010 S
b00000000000000000000000000000010 T
b00000000000000000000000000000010 U
b00000000000000000000000000000010 V
1W
b00000000000000000000000000000010 Y
b00000000000000000000000000000010 Z
b00000000000000000000000000000010 \
#25
0W
#30
1%
b00000000000000000000000000000100 &
b00000100 '
b00000000000000000000000000000001 (
b00000000000000000000000000000001 *
b00000000000000000000000000000011 (
b00000000000000000000000000000011 *
b00000000000000000000000000000001 ,
b00000000000000000000000000000001 .
b00000000000000000000000000000001 0
b00000000000000000000000000000001 2
b00000000000000000000000000000001 4
b00000000000000000000000000000001 6
b00000000000000000000000000000001 7
b00000000000000000000000000000001 ;
b00000000000000000000000000000011 <
b00000000000000000000000000000011 >
b00000000000000000000000000000011 ?
b00000000000000000000000000000011 @
b00000000000000000000000000000011 A
b00000000000000000000000000000011 B
b00000000000000000000000000000011 C
b00000000000000000000000000000011 D
b00000000000000000000000000000011 E
b00000000000000000000000000000011 F
b00000000000000000000000000000011 I
b00000000000000000000000000000011 J
b00000000000000000000000000000011 G
b00000000000000000000000000000011 H
b00000000000000000000000000000011 K
b00000000000000000000000000000011 L
b00000000000000000000000000000011 M
b00000000000000000000000000000011 N
b00000000000000000000000000000011 O
b00000000000000000000000000000011 P
b00000000000000000000000000000011 Q
b00000000000000000000000000000011 R
b00000000000000000000000000000011 S
b00000000000000000000000000000011 T
b00000000000000000000000000000011 U
b00000000000000000000000000000011 V
1W
b00000000000000000000000000000011 Y
b00000000000000000000000000000011 Z
b00000000000000000000000000000011 \
#35
0W
#40
0%
b00000000000000000000000000000101 &
b00000101 '
b00000000000000000000000000000011 )
b00000000000000000000000000000100 (
b00000000000000000000000000000100 *
b00000000000000000000000000000011 +
b00000000000000000000000000000011 -
b00000000000000000000000000000011 /
b00000000000000000000000000000011 1
b00000000000000000000000000000011 3
b00000000000000000000000000000001 6
b00000000000000000000000000000011 9
b00000000000000000000000000000100 <
b00000000000000000000000000000100 >
b00000000000000000000000000000001 ?
b00000000000000000000000000000100 B
b00000000000000000000000000000001 C
b00000000000000000000000000000100 F
b00000000000000000000000000000001 G
b00000000000000000000000000000001 H
b00000000000000000000000000000100 J
b00000000000000000000000000000011 5
b00000000000000000000000000000001 8
b00000000000000000000000000000011 =
b00000000000000000000000000000100 ?
b00000000000000000000000000000001 A
b00000000000000000000000000000100 C
b00000000000000000000000000000001 E
b00000000000000000000000000000100 G
b00000000000000000000000000000001 I
b00000000000000000000000000000001 J
b00000000000000000000000000000100 K
b00000000000000000000000000000001 L
b00000000000000000000000000000100 O
b00000000000000000000000000000100 L
b00000000000000000000000000000001 N
b00000000000000000000000000000100 P
b00000000000000000000000000000001 Q
b00000000000000000000000000000100 T
b00000000000000000000000000000100 Q
b00000000000000000000000000000001 S
b00000000000000000000000000000100 U
b00000000000000000000000000000100 V
1W
b00000000000000000000000000000001 Y
b00000000000000000000000000000100 \
b00000000000000000000000000000100 Y
b00000000000000000000000000000001 [
#45
0W
#50
b00000000000000000000000000000110 &
b00000110 '
b00000000000000000000000000000100 )
b00000000000000000000000000000101 (
b00000000000000000000000000000101 *
b00000000000000000000000000000100 +
b00000000000000000000000000000100 -
b00000000000000000000000000000100 /
b00000000000000000000000000000100 1
b00000000000000000000000000000100 3
b00000000000000000000000000000001 4
b00000000000000000000000000000100 5
b00000000000000000000000000000001 :
b00000000000000000000000000000101 <
b00000000000000000000000000000101 >
b00000000000000000000000000000001 <
b00000000000000000000000000000101 ?
b00000000000000000000000000000100 @
b00000000000000000000000000000100 A
b00000000000000000000000000000101 B
b00000000000000000000000000000100 B
b00000000000000000000000000000101 C
b00000000000000000000000000000100 D
b00000000000000000000000000000100 E
b00000000000000000000000000000101 F
b00000000000000000000000000000100 I
b00000000000000000000000000000101 J
b00000000000000000000000000000100 F
b00000000000000000000000000000101 G
b00000000000000000000000000000100 H
b00000000000000000000000000000101 K
b00000000000000000000000000000101 L
b00000000000000000000000000000100 M
b00000000000000000000000000000100 N
b00000000000000000000000000000101 O
b00000000000000000000000000000100 O
b00000000000000000000000000000101 P
b00000000000000000000000000000101 Q
b00000000000000000000000000000100 R
b00000000000000000000000000000100 S
b00000000000000000000000000000101 T
b00000000000000000000000000000100 T
b00000000000000000000000000000101 U
b00000000000000000000000000000101 V
1W
b00000000000000000000000000000001 X
b00000000000000000000000000000110 Y
b00000000000000000000000000000101 Z
b00000000000000000000000000000001 [
b00000000000000000000000000000110 \
b00000000000000000000000000000001 \
#55
0W
#60
b00000000000000000000000000000111 &
b00000111 '
b00000000000000000000000000000101 )
b00000000000000000000000000000110 (
b00000000000000000000000000000110 *
b00000000000000000000000000000101 +
b00000000000000000000000000000101 -
b00000000000000000000000000000101 /
b00000000000000000000000000000101 1
b00000000000000000000000000000101 3
b00000000000000000000000000000011 5
b00000000000000000000000000000100 9
b00000000000000000000000000000110 <
b00000000000000000000000000000110 >
b00000000000000000000000000000101 5
b00000000000000000000000000000011 9
b00000000000000000000000000000100 =
b00000000000000000000000000000110 ?
b00000000000000000000000000000101 @
b00000000000000000000000000000101 A
b00000000000000000000000000000110 B
b00000000000000000000000000000101 B
b00000000000000000000000000000110 C
b00000000000000000000000000000101 D
b00000000000000000000000000000101 E
b00000000000000000000000000000110 F
b00000000000000000000000000000101 I
b00000000000000000000000000000110 J
b00000000000000000000000000000101 F
b00000000000000000000000000000110 G
b00000000000000000000000000000101 H
b00000000000000000000000000000110 K
b00000000000000000000000000000110 L
b00000000000000000000000000000101 M
b00000000000000000000000000000101 N
b00000000000000000000000000000110 O
b00000000000000000000000000000101 O
b00000000000000000000000000000110 P
b00000000000000000000000000000110 Q
b00000000000000000000000000000101 R
b00000000000000000000000000000101 S
b00000000000000000000000000000110 T
b00000000000000000000000000000101 T
b00000000000000000000000000000110 U
b00000000000000000000000000000110 V
1W
b00000000000000000000000000000111 Y
b00000000000000000000000000000110 Z
b00000000000000000000000000000111 \
#65
0W
#70
b00000000000000000000000000001000 &
b00001000 '
b00000000000000000000000000000110 )
b00000000000000000000000000000111 (
b00000000000000000000000000000111 *
b00000000000000000000000000000110 +
b00000000000000000000000000000110 -
b00000000000000000000000000000110 /
b00000000000000000000000000000110 1
b00000000000000000000000000000110 3
b00000000000000000000000000000100 5
b00000000000000000000000000000101 9
b00000000000000000000000000000111 <
b00000000000000000000000000000111 >
b00000000000000000000000000000110 5
b00000000000000000000000000000100 9
b00000000000000000000000000000101 =
b00000000000000000000000000000111 ?
b00000000000000000000000000000110 @
b00000000000000000000000000000110 A
b00000000000000000000000000000111 B
b00000000000000000000000000000110 B
b00000000000000000000000000000111 C
b00000000000000000000000000000110 D
b00000000000000000000000000000110 E
b00000000000000000000000000000111 F
b00000000000000000000000000000110 I
b00000000000000000000000000000111 J
b00000000000000000000000000000110 F
b00000000000000000000000000000111 G
b00000000000000000000000000000110 H
b00000000000000000000000000000111 K
b00000000000000000000000000000111 L
b00000000000000000000000000000110 M
b00000000000000000000000000000110 N
b00000000000000000000000000000111 O
b00000000000000000000000000000110 O
b00000000000000000000000000000111 P
b00000000000000000000000000000111 Q
b00000000000000000000000000000110 R
b00000000000000000000000000000110 S
b00000000000000000000000000000111 T
b00000000000000000000000000000110 T
b00000000000000000000000000000111 U
b00000000000000000000000000000111 V
1W
b00000000000000000000000000001000 Y
b00000000000000000000000000000111 Z
b00000000000000000000000000001000 \
#75
0W
#80
b00000000000000000000000000001001 &
b00001001 '
b00000000000000000000000000000111 )
b00000000000000000000000000001000 (
b00000000000000000000000000001000 *
b00000000000000000000000000000111 +
b00000000000000000000000000000111 -
b00000000000000000000000000000111 /
b00000000000000000000000000000111 1
b00000000000000000000000000000111 3
b00000000000000000000000000000101 5
b00000000000000000000000000000110 9
b00000000000000000000000000001000 <
b00000000000000000000000000001000 >
b00000000000000000000000000000111 5
b00000000000000000000000000000101 9
b00000000000000000000000000000110 =
b00000000000000000000000000001000 ?
b00000000000000000000000000000111 @
b00000000000000000000000000000111 A
b00000000000000000000000000001000 B
b00000000000000000000000000000111 B
b00000000000000000000000000001000 C
b00000000000000000000000000000111 D
b00000000000000000000000000000111 E
b00000000000000000000000000001000 F
b00000000000000000000000000000111 I
b00000000000000000000000000001000 J
b00000000000000000000000000000111 F
b00000000000000000000000000001000 G
b00000000000000000000000000000111 H
b00000000000000000000000000001000 K
b00000000000000000000000000001000 L
b00000000000000000000000000000111 M
b00000000000000000000000000000111 N
b00000000000000000000000000001000 O
b00000000000000000000000000000111 O
b00000000000000000000000000001000 P
b00000000000000000000000000001000 Q
b00000000000000000000000000000111 R
b00000000000000000000000000000111 S
b00000000000000000000000000001000 T
b00000000000000000000000000000111 T
b00000000000000000000000000001000 U
b00000000000000000000000000001000 V
1W
b00000000000000000000000000001001 Y
b00000000000000000000000000001000 Z
b00000000000000000000000000001001 \
#85
0W
#90
b00000000000000000000000000001010 &
b00001010 '
b00000000000000000000000000001000 )
b00000000000000000000000000001001 (
b00000000000000000000000000001001 *
b00000000000000000000000000001000 +
b00000000000000000000000000001000 -
b00000000000000000000000000001000 /
b00000000000000000000000000001000 1
b00000000000000000000000000001000 3
b00000000000000000000000000000110 5
b00000000000000000000000000000111 9
b00000000000000000000000000001001 <
b00000000000000000000000000001001 >
b00000000000000000000000000001000 5
b00000000000000000000000000000110 9
b00000000000000000000000000000111 =
b00000000000000000000000000001001 ?
b00000000000000000000000000001000 @
b00000000000000000000000000001000 A
b00000000000000000000000000001001 B
b00000000000000000000000000001000 B
b00000000000000000000000000001001 C
b00000000000000000000000000001000 D
b00000000000000000000000000001000 E
b00000000000000000000000000001001 F
b00000000000000000000000000001000 I
b00000000000000000000000000001001 J
b00000000000000000000000000001000 F
b00000000000000000000000000001001 G
b00000000000000000000000000001000 H
b00000000000000000000000000001001 K
b00000000000000000000000000001001 L
b00000000000000000000000000001000 M
b00000000000000000000000000001000 N
b00000000000000000000000000001001 O
b00000000000000000000000000001000 O
b00000000000000000000000000001001 P
b00000000000000000000000000001001 Q
b00000000000000000000000000001000 R
b00000000000000000000000000001000 S
b00000000000000000000000000001001 T
b00000000000000000000000000001000 T
b00000000000000000000000000001001 U
b00000000000000000000000000001001 V
1W
b00000000000000000000000000001010 Y
b00000000000000000000000000001001 Z
b00000000000000000000000000001010 \
#95
0W
#100
b00000000000000000000000000001011 &
b00001011 '
b00000000000000000000000000001001 )
b00000000000000000000000000001010 (
b00000000000000000000000000001010 *
b00000000000000000000000000001001 +
b00000000000000000000000000001001 -
b00000000000000000000000000001001 /
b00000000000000000000000000001001 1
b00000000000000000000000000001001 3
b00000000000000000000000000000111 5
b00000000000000000000000000000001 8
b00000000000000000000000000001010 <
b00000000000000000000000000001010 >
b00000000000000000000000000001001 5
b00000000000000000000000000000111 9
b00000000000000000000000000000001 >
b00000000000000000000000000001010 ?
b00000000000000000000000000001001 @
b00000000000000000000000000001001 A
b00000000000000000000000000001010 B
b00000000000000000000000000001001 B
b00000000000000000000000000001010 C
b00000000000000000000000000001001 D
b00000000000000000000000000001001 E
b00000000000000000000000000001010 F
b00000000000000000000000000001001 I
b00000000000000000000000000001010 J
b00000000000000000000000000001001 F
b00000000000000000000000000001010 G
b00000000000000000000000000001001 H
b00000000000000000000000000001010 K
b00000000000000000000000000001010 L
b00000000000000000000000000001001 M
b00000000000000000000000000001001 N
b00000000000000000000000000001010 O
b00000000000000000000000000001001 O
b00000000000000000000000000001010 P
b00000000000000000000000000001010 Q
b00000000000000000000000000001001 R
b00000000000000000000000000001001 S
b00000000000000000000000000001010 T
b00000000000000000000000000001001 T
b00000000000000000000000000001010 U
b00000000000000000000000000001010 V
1W
b00000000000000000000000000001011 Y
b00000000000000000000000000001010 Z
b00000000000000000000000000001011 \

26
test_regress/t/t_trace_empty.pl Executable file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2021 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
scenarios(simulator => 1);
compile(
verilator_flags2 => ['--trace'],
);
execute(
check_finished => 1,
);
file_grep_not("$Self->{obj_dir}/simx.vcd", qr/scope/);
file_grep_not("$Self->{obj_dir}/simx.vcd", qr/upscope/);
file_grep_not("$Self->{obj_dir}/simx.vcd", qr/var/);
ok(1);
1;

View File

@ -0,0 +1,26 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2021 by Geza Lore.
// SPDX-License-Identifier: CC0-1.0
module t(/*AUTOARG*/
// Inputs
clk
);
/* verilator tracing_off */
input clk;
reg [7:0] cyc = 8'd0;
always @(posedge clk) begin
cyc <= cyc + 1;
if (cyc == 20) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule