This commit is contained in:
parent
831396f848
commit
67b21e4c62
|
|
@ -25,6 +25,7 @@ Andrei Kostovski
|
||||||
Andrew Miloradovsky
|
Andrew Miloradovsky
|
||||||
Andrew Nolte
|
Andrew Nolte
|
||||||
Andrew Voznytsa
|
Andrew Voznytsa
|
||||||
|
anonkey
|
||||||
Anthony Donlon
|
Anthony Donlon
|
||||||
Anthony Moore
|
Anthony Moore
|
||||||
Arkadiusz Kozdra
|
Arkadiusz Kozdra
|
||||||
|
|
|
||||||
|
|
@ -210,6 +210,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
std::vector<bool> m_sigs_enabledVec; // Staging for m_sigs_enabledp
|
std::vector<bool> m_sigs_enabledVec; // Staging for m_sigs_enabledp
|
||||||
std::vector<CallbackRecord> m_initCbs; // Routines to initialize tracing
|
std::vector<CallbackRecord> m_initCbs; // Routines to initialize tracing
|
||||||
|
std::vector<bool> m_initCbsCalled; // Init callbacks already run for this open
|
||||||
std::vector<CallbackRecord> m_constCbs; // Routines to perform const dump
|
std::vector<CallbackRecord> m_constCbs; // Routines to perform const dump
|
||||||
std::vector<CallbackRecord> m_fullCbs; // Routines to perform full dump
|
std::vector<CallbackRecord> m_fullCbs; // Routines to perform full dump
|
||||||
std::vector<CallbackRecord> m_chgCbs; // Routines to perform incremental dump
|
std::vector<CallbackRecord> m_chgCbs; // Routines to perform incremental dump
|
||||||
|
|
@ -220,6 +221,7 @@ private:
|
||||||
uint32_t m_numSignals = 0; // Number of distinct signals
|
uint32_t m_numSignals = 0; // Number of distinct signals
|
||||||
uint32_t m_maxBits = 0; // Number of bits in the widest signal
|
uint32_t m_maxBits = 0; // Number of bits in the widest signal
|
||||||
void* m_initUserp = nullptr; // The callback userp of the instance currently being initialized
|
void* m_initUserp = nullptr; // The callback userp of the instance currently being initialized
|
||||||
|
bool m_rootInit = true; // Whether the current init callback was reached from the root
|
||||||
// TODO: Should keep this as a Trie, that is how it's accessed all the time.
|
// TODO: Should keep this as a Trie, that is how it's accessed all the time.
|
||||||
std::vector<std::pair<int, std::string>> m_dumpvars; // dumpvar() entries
|
std::vector<std::pair<int, std::string>> m_dumpvars; // dumpvar() entries
|
||||||
double m_timeRes = 1e-9; // Time resolution (ns/ms etc)
|
double m_timeRes = 1e-9; // Time resolution (ns/ms etc)
|
||||||
|
|
@ -236,6 +238,7 @@ private:
|
||||||
// to access duck-typed functions to avoid a virtual function call.
|
// to access duck-typed functions to avoid a virtual function call.
|
||||||
T_Trace* self() { return static_cast<T_Trace*>(this); }
|
T_Trace* self() { return static_cast<T_Trace*>(this); }
|
||||||
|
|
||||||
|
void runInitCallback(size_t index, bool rootInit) VL_MT_UNSAFE;
|
||||||
void runCallbacks(const std::vector<CallbackRecord>& cbVec);
|
void runCallbacks(const std::vector<CallbackRecord>& cbVec);
|
||||||
|
|
||||||
// Flush any remaining data for this file
|
// Flush any remaining data for this file
|
||||||
|
|
@ -325,6 +328,7 @@ public:
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
// Non-hot path internal interface to Verilator generated code
|
// Non-hot path internal interface to Verilator generated code
|
||||||
|
|
||||||
|
bool rootInit() const VL_MT_UNSAFE { return m_rootInit; }
|
||||||
void addModel(VerilatedModel*) VL_MT_SAFE_EXCLUDES(m_mutex);
|
void addModel(VerilatedModel*) VL_MT_SAFE_EXCLUDES(m_mutex);
|
||||||
void addInitCb(initCb_t cb, void* userp, const std::string& name, bool isLibInstance,
|
void addInitCb(initCb_t cb, void* userp, const std::string& name, bool isLibInstance,
|
||||||
uint32_t nTraceCodes) VL_MT_SAFE;
|
uint32_t nTraceCodes) VL_MT_SAFE;
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,25 @@ VerilatedTrace<VL_SUB_T, VL_BUF_T>::~VerilatedTrace() {
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
// Internals available to format-specific implementations
|
// Internals available to format-specific implementations
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::runInitCallback(size_t index,
|
||||||
|
bool rootInit) VL_MT_UNSAFE {
|
||||||
|
if (m_initCbsCalled[index]) return;
|
||||||
|
|
||||||
|
const CallbackRecord& cbr = m_initCbs[index];
|
||||||
|
const uint32_t baseCode = nextCode();
|
||||||
|
m_nextCode += cbr.m_nTraceCodes;
|
||||||
|
|
||||||
|
void* const prevInitUserp = m_initUserp;
|
||||||
|
const bool prevRootInit = m_rootInit;
|
||||||
|
m_initUserp = cbr.m_userp;
|
||||||
|
m_rootInit = rootInit;
|
||||||
|
cbr.m_initCb(cbr.m_userp, self(), baseCode);
|
||||||
|
m_initUserp = prevInitUserp;
|
||||||
|
m_rootInit = prevRootInit;
|
||||||
|
m_initCbsCalled[index] = true;
|
||||||
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::traceInit() VL_MT_UNSAFE {
|
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::traceInit() VL_MT_UNSAFE {
|
||||||
// Note: It is possible to re-open a trace file (VCD in particular),
|
// Note: It is possible to re-open a trace file (VCD in particular),
|
||||||
|
|
@ -107,18 +126,13 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::traceInit() VL_MT_UNSAFE {
|
||||||
m_numSignals = 0;
|
m_numSignals = 0;
|
||||||
m_maxBits = 0;
|
m_maxBits = 0;
|
||||||
m_sigs_enabledVec.clear();
|
m_sigs_enabledVec.clear();
|
||||||
|
m_initCbsCalled.assign(m_initCbs.size(), false);
|
||||||
|
|
||||||
// Call all initialize callbacks for root (non-library) instances, which will:
|
// Call all initialize callbacks for root instances, which will:
|
||||||
// - Call decl* for each signal (these eventually call ::declCode)
|
// - Call decl* for each signal (these eventually call ::declCode)
|
||||||
// - Call the initialize callbacks of library instances underneath
|
// - Call the initialize callbacks of library instances underneath
|
||||||
// - Store the base code
|
// - Store the base code
|
||||||
for (const CallbackRecord& cbr : m_initCbs) {
|
for (size_t i = 0; i < m_initCbs.size(); ++i) runInitCallback(i, true);
|
||||||
if (cbr.m_isLibInstance) continue; // Will be called from parent callback
|
|
||||||
const uint32_t baseCode = nextCode();
|
|
||||||
m_nextCode += cbr.m_nTraceCodes;
|
|
||||||
m_initUserp = cbr.m_userp;
|
|
||||||
cbr.m_initCb(cbr.m_userp, self(), baseCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expectedCodes && nextCode() != expectedCodes) {
|
if (expectedCodes && nextCode() != expectedCodes) {
|
||||||
VL_FATAL_MT(__FILE__, __LINE__, "",
|
VL_FATAL_MT(__FILE__, __LINE__, "",
|
||||||
|
|
@ -423,14 +437,9 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addCleanupCb(cleanupCb_t cb, void* user
|
||||||
template <>
|
template <>
|
||||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::initLib(const std::string& name) VL_MT_SAFE {
|
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::initLib(const std::string& name) VL_MT_SAFE {
|
||||||
// Note it's possible the instance doesn't exist if the lib was compiled without tracing
|
// Note it's possible the instance doesn't exist if the lib was compiled without tracing
|
||||||
void* const prevInitUserp = m_initUserp;
|
for (size_t i = 0; i < m_initCbs.size(); ++i) {
|
||||||
for (const CallbackRecord& cbr : m_initCbs) {
|
if (m_initCbs[i].m_name != name) continue;
|
||||||
if (cbr.m_name != name) continue;
|
runInitCallback(i, false);
|
||||||
const uint32_t baseCode = nextCode();
|
|
||||||
m_nextCode += cbr.m_nTraceCodes;
|
|
||||||
m_initUserp = cbr.m_userp;
|
|
||||||
cbr.m_initCb(cbr.m_userp, self(), baseCode);
|
|
||||||
m_initUserp = prevInitUserp;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1276,6 +1276,7 @@ class AstNetlist final : public AstNode {
|
||||||
// @astgen ptr := m_stlFirstIterationp: Optional[AstVarScope] // Settle first iteration flag
|
// @astgen ptr := m_stlFirstIterationp: Optional[AstVarScope] // Settle first iteration flag
|
||||||
VTimescale m_timeunit; // Global time unit
|
VTimescale m_timeunit; // Global time unit
|
||||||
VTimescale m_timeprecision; // Global time precision
|
VTimescale m_timeprecision; // Global time precision
|
||||||
|
std::string m_resolvedTopModuleName; // Selected design top before wrapping under $root
|
||||||
bool m_timescaleSpecified = false; // Input HDL specified timescale
|
bool m_timescaleSpecified = false; // Input HDL specified timescale
|
||||||
uint32_t m_nTraceCodes = 0; // Number of trace codes used by design
|
uint32_t m_nTraceCodes = 0; // Number of trace codes used by design
|
||||||
// V3Param-deferred params awaiting V3LinkDot::linkDotParamed scope-resolution.
|
// V3Param-deferred params awaiting V3LinkDot::linkDotParamed scope-resolution.
|
||||||
|
|
@ -1336,10 +1337,16 @@ public:
|
||||||
void timeprecisionMerge(FileLine*, const VTimescale& value);
|
void timeprecisionMerge(FileLine*, const VTimescale& value);
|
||||||
void timescaleSpecified(bool specified) { m_timescaleSpecified = specified; }
|
void timescaleSpecified(bool specified) { m_timescaleSpecified = specified; }
|
||||||
bool timescaleSpecified() const { return m_timescaleSpecified; }
|
bool timescaleSpecified() const { return m_timescaleSpecified; }
|
||||||
|
const std::string& resolvedTopModuleName() const { return m_resolvedTopModuleName; }
|
||||||
|
void resolvedTopModuleName(const std::string& value) { m_resolvedTopModuleName = value; }
|
||||||
uint32_t nTraceCodes() const { return m_nTraceCodes; }
|
uint32_t nTraceCodes() const { return m_nTraceCodes; }
|
||||||
void nTraceCodes(uint32_t value) { m_nTraceCodes = value; }
|
void nTraceCodes(uint32_t value) { m_nTraceCodes = value; }
|
||||||
AstVarScope* stlFirstIterationp();
|
AstVarScope* stlFirstIterationp();
|
||||||
void clearStlFirstIterationp() { m_stlFirstIterationp = nullptr; }
|
void clearStlFirstIterationp() { m_stlFirstIterationp = nullptr; }
|
||||||
|
const std::string traceLibTopName() const {
|
||||||
|
const std::string& name = resolvedTopModuleName();
|
||||||
|
return prettyName(name.empty() ? v3Global.rootp()->topModulep()->name() : name);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
class AstPackageExport final : public AstNode {
|
class AstPackageExport final : public AstNode {
|
||||||
// A package export declaration
|
// A package export declaration
|
||||||
|
|
|
||||||
|
|
@ -526,10 +526,17 @@ class EmitCModel final : public EmitCFunc {
|
||||||
|
|
||||||
void emitTraceMethods(AstNodeModule* modp) {
|
void emitTraceMethods(AstNodeModule* modp) {
|
||||||
const string topModNameProtected = EmitCUtil::prefixNameProtect(modp);
|
const string topModNameProtected = EmitCUtil::prefixNameProtect(modp);
|
||||||
|
const string topTraceName
|
||||||
|
= V3OutFormatter::quoteNameControls(v3Global.rootp()->traceLibTopName());
|
||||||
|
|
||||||
putSectionDelimiter("Trace configuration");
|
putSectionDelimiter("Trace configuration");
|
||||||
|
|
||||||
// Forward declaration
|
// Forward declaration
|
||||||
|
if (!v3Global.opt.libCreate().empty()) {
|
||||||
|
putns(modp, "\nvoid " + topModNameProtected + "__" + protect("trace_init_root") + "("
|
||||||
|
+ topModNameProtected + "* vlSelf, " + v3Global.opt.traceClassBase()
|
||||||
|
+ "* tracep);\n");
|
||||||
|
}
|
||||||
putns(modp, "\nvoid " + topModNameProtected + "__" + protect("trace_decl_types") + "("
|
putns(modp, "\nvoid " + topModNameProtected + "__" + protect("trace_decl_types") + "("
|
||||||
+ v3Global.opt.traceClassBase() + "* tracep);\n");
|
+ v3Global.opt.traceClassBase() + "* tracep);\n");
|
||||||
putns(modp, "\nvoid " + topModNameProtected + "__" + protect("trace_init_top") + "("
|
putns(modp, "\nvoid " + topModNameProtected + "__" + protect("trace_init_top") + "("
|
||||||
|
|
@ -551,11 +558,23 @@ class EmitCModel final : public EmitCFunc {
|
||||||
puts("vlSymsp->__Vm_baseCode = code;\n");
|
puts("vlSymsp->__Vm_baseCode = code;\n");
|
||||||
if (v3Global.opt.libCreate().empty()) {
|
if (v3Global.opt.libCreate().empty()) {
|
||||||
puts("tracep->pushPrefix(vlSymsp->name(), VerilatedTracePrefixType::SCOPE_MODULE);\n");
|
puts("tracep->pushPrefix(vlSymsp->name(), VerilatedTracePrefixType::SCOPE_MODULE);\n");
|
||||||
|
} else {
|
||||||
|
puts("if (tracep->rootInit()) {\n");
|
||||||
|
puts("tracep->pushPrefix(vlSymsp->name(), VerilatedTracePrefixType::SCOPE_MODULE);\n");
|
||||||
|
puts(topModNameProtected + "__" + protect("trace_init_root") + "(vlSelf, tracep);\n");
|
||||||
|
puts("tracep->pushPrefix(\"" + topTraceName
|
||||||
|
+ "\", VerilatedTracePrefixType::SCOPE_MODULE);\n");
|
||||||
|
puts("}\n");
|
||||||
}
|
}
|
||||||
puts(topModNameProtected + "__" + protect("trace_decl_types") + "(tracep);\n");
|
puts(topModNameProtected + "__" + protect("trace_decl_types") + "(tracep);\n");
|
||||||
puts(topModNameProtected + "__" + protect("trace_init_top") + "(vlSelf, tracep);\n");
|
puts(topModNameProtected + "__" + protect("trace_init_top") + "(vlSelf, tracep);\n");
|
||||||
if (v3Global.opt.libCreate().empty()) { //
|
if (v3Global.opt.libCreate().empty()) { //
|
||||||
puts("tracep->popPrefix();\n");
|
puts("tracep->popPrefix();\n");
|
||||||
|
} else {
|
||||||
|
puts("if (tracep->rootInit()) {\n");
|
||||||
|
puts("tracep->popPrefix();\n");
|
||||||
|
puts("tracep->popPrefix();\n");
|
||||||
|
puts("}\n");
|
||||||
}
|
}
|
||||||
puts("}\n");
|
puts("}\n");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -167,6 +167,7 @@ void V3LinkLevel::wrapTop(AstNetlist* rootp) {
|
||||||
UINFO(1, "No module found to wrap");
|
UINFO(1, "No module found to wrap");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
rootp->resolvedTopModuleName(oldmodp->name());
|
||||||
|
|
||||||
AstNodeModule* const newmodp = new AstModule{oldmodp->fileline(), "$root", oldmodp->libname()};
|
AstNodeModule* const newmodp = new AstModule{oldmodp->fileline(), "$root", oldmodp->libname()};
|
||||||
newmodp->name(AstNode::encodeName(newmodp->name())); // so origName is nice
|
newmodp->name(AstNode::encodeName(newmodp->name())); // so origName is nice
|
||||||
|
|
|
||||||
|
|
@ -221,8 +221,38 @@ class TraceVisitor final : public VNVisitor {
|
||||||
std::map<std::pair<const AstIface*, std::string>, std::vector<AstVarScope*>>
|
std::map<std::pair<const AstIface*, std::string>, std::vector<AstVarScope*>>
|
||||||
m_ifaceMemberVscps;
|
m_ifaceMemberVscps;
|
||||||
|
|
||||||
|
class TraceInitDeclCollector final : public VNVisitor {
|
||||||
|
std::vector<AstTraceDecl*>& m_declps;
|
||||||
|
std::set<const AstCFunc*> m_seenFuncps;
|
||||||
|
|
||||||
|
void visit(AstTraceDecl* nodep) override { m_declps.push_back(nodep); }
|
||||||
|
void visit(AstCCall* nodep) override {
|
||||||
|
if (AstCFunc* const funcp = nodep->funcp()) collect(funcp);
|
||||||
|
}
|
||||||
|
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TraceInitDeclCollector(std::vector<AstTraceDecl*>& declps)
|
||||||
|
: m_declps{declps} {}
|
||||||
|
void collect(AstCFunc* funcp) {
|
||||||
|
if (funcp && m_seenFuncps.insert(funcp).second) iterate(funcp);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
|
|
||||||
|
static bool sameRootInitAlias(const AstTraceDecl* rootDeclp, const AstTraceDecl* topDeclp) {
|
||||||
|
const VNumRange& rootBitRange = rootDeclp->bitRange();
|
||||||
|
const VNumRange& topBitRange = topDeclp->bitRange();
|
||||||
|
return rootDeclp->showname() == topDeclp->showname()
|
||||||
|
&& rootDeclp->declDirection() == topDeclp->declDirection()
|
||||||
|
&& rootDeclp->widthMin() == topDeclp->widthMin()
|
||||||
|
&& rootBitRange.ranged() == topBitRange.ranged()
|
||||||
|
&& (!rootBitRange.ranged()
|
||||||
|
|| (rootBitRange.left() == topBitRange.left()
|
||||||
|
&& rootBitRange.right() == topBitRange.right()));
|
||||||
|
}
|
||||||
|
|
||||||
void detectDuplicates() {
|
void detectDuplicates() {
|
||||||
UINFO(9, "Finding duplicates");
|
UINFO(9, "Finding duplicates");
|
||||||
// Note uses user4
|
// Note uses user4
|
||||||
|
|
@ -1076,6 +1106,32 @@ class TraceVisitor final : public VNVisitor {
|
||||||
// Create the full and incremental dump functions
|
// Create the full and incremental dump functions
|
||||||
createNonConstTraceFunctions(traces, nNonConstCodes, m_parallelism);
|
createNonConstTraceFunctions(traces, nNonConstCodes, m_parallelism);
|
||||||
|
|
||||||
|
// Root-traced libraries alias wrapper IOs onto the existing top-module codes.
|
||||||
|
if (!v3Global.opt.libCreate().empty()) {
|
||||||
|
std::vector<AstTraceDecl*> rootDeclps;
|
||||||
|
std::vector<AstTraceDecl*> topDeclps;
|
||||||
|
TraceInitDeclCollector rootCollector{rootDeclps};
|
||||||
|
TraceInitDeclCollector topCollector{topDeclps};
|
||||||
|
for (AstNode* blockp = m_topScopep->blocksp(); blockp; blockp = blockp->nextp()) {
|
||||||
|
AstCFunc* const funcp = VN_CAST(blockp, CFunc);
|
||||||
|
if (funcp && VString::startsWith(funcp->name(), "trace_init_leaf_root__")) {
|
||||||
|
rootCollector.collect(funcp);
|
||||||
|
} else if (funcp && VString::startsWith(funcp->name(), "trace_init_leaf_top__")) {
|
||||||
|
topCollector.collect(funcp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<bool> used(topDeclps.size(), false);
|
||||||
|
for (AstTraceDecl* const rootDeclp : rootDeclps) {
|
||||||
|
for (size_t i = 0; i < topDeclps.size(); ++i) {
|
||||||
|
if (used[i] || !sameRootInitAlias(rootDeclp, topDeclps[i])) continue;
|
||||||
|
rootDeclp->code(topDeclps[i]->code());
|
||||||
|
used[i] = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Remove refs to traced values from TraceDecl nodes, these have now moved under
|
// Remove refs to traced values from TraceDecl nodes, these have now moved under
|
||||||
// TraceInc
|
// TraceInc
|
||||||
for (const auto& i : traces) {
|
for (const auto& i : traces) {
|
||||||
|
|
@ -1179,6 +1235,20 @@ class TraceVisitor final : public VNVisitor {
|
||||||
void visit(AstTraceDecl* nodep) override {
|
void visit(AstTraceDecl* nodep) override {
|
||||||
UINFO(8, " TRACE " << nodep);
|
UINFO(8, " TRACE " << nodep);
|
||||||
if (!m_finding && !nodep->inDtypeFunc()) {
|
if (!m_finding && !nodep->inDtypeFunc()) {
|
||||||
|
// Skip decls inside trace_init_leaf_root__* functions: these are
|
||||||
|
// duplicates of decls in trace_init_leaf_top__* (root vs regular
|
||||||
|
// scope path) and should share the top decl's code via the
|
||||||
|
// sameRootInitAlias post-pass at createTraceFunctions(). Putting
|
||||||
|
// them in the dedup graph would allocate distinct trace codes for
|
||||||
|
// them, growing nTraceCodes past what trace_init_top actually
|
||||||
|
// declares -- so the parent's full callback writes to codes the
|
||||||
|
// SAIF/VCD runtime never registered, tripping
|
||||||
|
// verilated_saif_c.cpp: Activity must be declared earlier
|
||||||
|
// verilated_vcd_c.cpp: finishLine: suffixp[0] failed
|
||||||
|
// (cf. t_lib, t_trace_hier_block_*).
|
||||||
|
if (m_cfuncp && VString::startsWith(m_cfuncp->name(), "trace_init_leaf_root__")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
V3GraphVertex* const vertexp = new TraceTraceVertex{&m_graph, nodep};
|
V3GraphVertex* const vertexp = new TraceTraceVertex{&m_graph, nodep};
|
||||||
nodep->user1p(vertexp);
|
nodep->user1p(vertexp);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,10 @@ public:
|
||||||
|
|
||||||
// Emit Prefix adjustments to unwind the path back to its original state
|
// Emit Prefix adjustments to unwind the path back to its original state
|
||||||
void unwind() {
|
void unwind() {
|
||||||
for (unsigned toPop = m_stack.size(); --toPop;) m_emit(new AstTracePopPrefix{m_flp});
|
while (m_stack.size() > 1) {
|
||||||
|
m_emit(new AstTracePopPrefix{m_flp});
|
||||||
|
m_stack.pop_back();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -139,6 +142,9 @@ class TraceDeclVisitor final : public VNVisitor {
|
||||||
uint32_t m_offset = std::numeric_limits<uint32_t>::max(); // Offset for types
|
uint32_t m_offset = std::numeric_limits<uint32_t>::max(); // Offset for types
|
||||||
int m_topFuncSize = 0; // Size of the top function currently being built
|
int m_topFuncSize = 0; // Size of the top function currently being built
|
||||||
int m_subFuncSize = 0; // Size of the sub function currently being built
|
int m_subFuncSize = 0; // Size of the sub function currently being built
|
||||||
|
bool m_forceNewLeaf = false; // Force next addToSubFunc to start a fresh leaf
|
||||||
|
size_t m_topScopeRootFuncCount = 0; // Top-scope init functions used only for wrapper IOs
|
||||||
|
bool m_topScopeRootPhase = false; // Emitting top-scope wrapper IO declarations
|
||||||
const int m_funcSizeLimit // Maximum size of a function
|
const int m_funcSizeLimit // Maximum size of a function
|
||||||
= v3Global.opt.outputSplitCTrace() ? v3Global.opt.outputSplitCTrace()
|
= v3Global.opt.outputSplitCTrace() ? v3Global.opt.outputSplitCTrace()
|
||||||
: std::numeric_limits<int>::max();
|
: std::numeric_limits<int>::max();
|
||||||
|
|
@ -184,21 +190,21 @@ class TraceDeclVisitor final : public VNVisitor {
|
||||||
m_name = vcdName.substr(pathLen);
|
m_name = vcdName.substr(pathLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
// When creating a --lib-create library, drop the name of the top module (l2 name).
|
// When creating a --lib-create library, drop the name of the selected top module.
|
||||||
// This will be replaced by the instance name in the model that uses the library.
|
// This will be replaced by the instance name in the model that uses the library, or
|
||||||
// This would be a bit murky when there are other top level entities ($unit,
|
// restored at runtime if the library itself is traced as the root model. Other top
|
||||||
// packages, which have an instance in all libs - a problem on its own). If
|
// level entities ($unit, packages, ...) keep a '$libroot' wrapper so they still have
|
||||||
// --top-module was explicitly specified, then we will drop the prefix only for the
|
// a stable location in the dump.
|
||||||
// actual top level module, and wrap the rest in '$libroot'. This way at least we get a
|
|
||||||
// usable dump of everything, with library instances showing in a right place, without
|
|
||||||
// pollution from other top level entities.
|
|
||||||
if (inTopScope && !v3Global.opt.libCreate().empty()) {
|
if (inTopScope && !v3Global.opt.libCreate().empty()) {
|
||||||
const size_t start = m_path.find(' ');
|
const size_t start = m_path.find(' ');
|
||||||
// Must have a prefix in the top scope with lib, as top wrapper signals not traced
|
// Must have a prefix in the top scope with lib, as top wrapper signals not traced
|
||||||
UASSERT_OBJ(start != std::string::npos, nodep, "No prefix with --lib-create");
|
UASSERT_OBJ(start != std::string::npos, nodep, "No prefix with --lib-create");
|
||||||
const std::string prefix = m_path.substr(0, start);
|
const std::string prefix = m_path.substr(0, start);
|
||||||
|
// Wrapper primary IOs stay under $rootio so a root-traced library can restore
|
||||||
|
// them under the runtime C++ instance name without affecting embedded use.
|
||||||
|
if (prefix == "$rootio") return;
|
||||||
m_path = m_path.substr(start + 1);
|
m_path = m_path.substr(start + 1);
|
||||||
if (v3Global.opt.topModule() != prefix) m_path = "$libroot " + m_path;
|
if (v3Global.rootp()->traceLibTopName() != prefix) m_path = "$libroot " + m_path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -299,10 +305,15 @@ class TraceDeclVisitor final : public VNVisitor {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Defer trace splitting until V3Trace
|
// Defer trace splitting until V3Trace
|
||||||
if (m_subFuncps.empty()) {
|
if (m_subFuncps.empty() || m_forceNewLeaf) {
|
||||||
|
m_forceNewLeaf = false;
|
||||||
FileLine* const flp = m_currScopep->fileline();
|
FileLine* const flp = m_currScopep->fileline();
|
||||||
const string n = cvtToStr(m_subFuncps.size());
|
const string n = cvtToStr(m_subFuncps.size());
|
||||||
const string name{"trace_init_sub__" + m_currScopep->nameDotless() + "__" + n};
|
const string name
|
||||||
|
= m_currScopep == m_topScopep->scopep() && !v3Global.opt.libCreate().empty()
|
||||||
|
? (m_topScopeRootPhase ? "trace_init_leaf_root__" : "trace_init_leaf_top__")
|
||||||
|
+ n
|
||||||
|
: "trace_init_sub__" + m_currScopep->nameDotless() + "__" + n;
|
||||||
AstCFunc* const funcp = newCFunc(flp, name);
|
AstCFunc* const funcp = newCFunc(flp, name);
|
||||||
funcp->addStmtsp(new AstCStmt{flp, "const int c = vlSymsp->__Vm_baseCode;"});
|
funcp->addStmtsp(new AstCStmt{flp, "const int c = vlSymsp->__Vm_baseCode;"});
|
||||||
m_subFuncps.push_back(funcp);
|
m_subFuncps.push_back(funcp);
|
||||||
|
|
@ -649,10 +660,11 @@ class TraceDeclVisitor final : public VNVisitor {
|
||||||
m_entries.begin(), m_entries.end(),
|
m_entries.begin(), m_entries.end(),
|
||||||
[](const TraceEntry& a, const TraceEntry& b) { return a.operatorCompare(b); });
|
[](const TraceEntry& a, const TraceEntry& b) { return a.operatorCompare(b); });
|
||||||
|
|
||||||
// Build trace initialization functions for this AstScope
|
|
||||||
FileLine* const flp = nodep->fileline();
|
FileLine* const flp = nodep->fileline();
|
||||||
PathAdjustor pathAdjustor{flp, [&](AstNodeStmt* stmtp) { addToSubFunc(stmtp); }};
|
PathAdjustor pathAdjustor{flp, [&](AstNodeStmt* stmtp) { addToSubFunc(stmtp); }};
|
||||||
for (const TraceEntry& entry : m_entries) {
|
const bool splitRootPrimaryIos = nodep->isTop() && !v3Global.opt.libCreate().empty();
|
||||||
|
const auto emitEntry = [&](const TraceEntry& entry) {
|
||||||
|
AstVarScope* const vscp = entry.vscp();
|
||||||
// Adjust name prefix based on path in hierarchy
|
// Adjust name prefix based on path in hierarchy
|
||||||
UINFO(9, "path='" << entry.path() << "' name='" << entry.name() << "' "
|
UINFO(9, "path='" << entry.path() << "' name='" << entry.name() << "' "
|
||||||
<< (entry.cellp() ? static_cast<AstNode*>(entry.cellp())
|
<< (entry.cellp() ? static_cast<AstNode*>(entry.cellp())
|
||||||
|
|
@ -661,7 +673,7 @@ class TraceDeclVisitor final : public VNVisitor {
|
||||||
|
|
||||||
m_traName = entry.name();
|
m_traName = entry.name();
|
||||||
|
|
||||||
if (AstVarScope* const vscp = entry.vscp()) {
|
if (vscp) {
|
||||||
// This is a signal: build AstTraceDecl for it
|
// This is a signal: build AstTraceDecl for it
|
||||||
m_traVscp = vscp;
|
m_traVscp = vscp;
|
||||||
const string& ignoreReason = vscIgnoreTrace(m_traVscp);
|
const string& ignoreReason = vscIgnoreTrace(m_traVscp);
|
||||||
|
|
@ -692,6 +704,33 @@ class TraceDeclVisitor final : public VNVisitor {
|
||||||
addToSubFunc(stmtp);
|
addToSubFunc(stmtp);
|
||||||
m_cellInitPlaceholders.emplace_back(nodep, cellp, stmtp);
|
m_cellInitPlaceholders.emplace_back(nodep, cellp, stmtp);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
if (splitRootPrimaryIos) {
|
||||||
|
m_topScopeRootPhase = true;
|
||||||
|
for (const TraceEntry& entry : m_entries) {
|
||||||
|
AstVarScope* const vscp = entry.vscp();
|
||||||
|
if (!(vscp && vscp->varp()->isPrimaryIO())) continue;
|
||||||
|
emitEntry(entry);
|
||||||
|
}
|
||||||
|
m_topScopeRootPhase = false;
|
||||||
|
pathAdjustor.unwind();
|
||||||
|
m_topScopeRootFuncCount = m_subFuncps.size();
|
||||||
|
if (m_topScopeRootFuncCount) {
|
||||||
|
// Force the next addToSubFunc to start a fresh leaf so
|
||||||
|
// root-phase decls and top-phase decls live in separate
|
||||||
|
// functions. Without this, both phases land in the same
|
||||||
|
// leaf and `trace_init_top` ends up emitting both the
|
||||||
|
// $rootio-prefixed IOs and the regular-scope decls, so
|
||||||
|
// each IO gets traced twice when the lib is consumed
|
||||||
|
// via initLib(name).
|
||||||
|
m_subFuncSize = 0;
|
||||||
|
m_forceNewLeaf = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const TraceEntry& entry : m_entries) {
|
||||||
|
AstVarScope* const vscp = entry.vscp();
|
||||||
|
if (splitRootPrimaryIos && vscp && vscp->varp()->isPrimaryIO()) continue;
|
||||||
|
emitEntry(entry);
|
||||||
}
|
}
|
||||||
pathAdjustor.unwind();
|
pathAdjustor.unwind();
|
||||||
m_traVscp = nullptr;
|
m_traVscp = nullptr;
|
||||||
|
|
@ -752,8 +791,6 @@ class TraceDeclVisitor final : public VNVisitor {
|
||||||
|
|
||||||
// When creating a --lib-create library ...
|
// When creating a --lib-create library ...
|
||||||
if (!v3Global.opt.libCreate().empty()) {
|
if (!v3Global.opt.libCreate().empty()) {
|
||||||
// Ignore the wrapper created primary IO ports
|
|
||||||
if (nodep->varp()->isPrimaryIO()) return;
|
|
||||||
// Ignore parameters in packages. These will be traced at the top level.
|
// Ignore parameters in packages. These will be traced at the top level.
|
||||||
if (nodep->varp()->isParam() && VN_IS(nodep->scopep()->modp(), Package)) return;
|
if (nodep->varp()->isParam() && VN_IS(nodep->scopep()->modp(), Package)) return;
|
||||||
}
|
}
|
||||||
|
|
@ -939,8 +976,22 @@ public:
|
||||||
// push/pop pairs is a bit hard. It is cleaner to remove them.
|
// push/pop pairs is a bit hard. It is cleaner to remove them.
|
||||||
removeRedundantPrefixPushPop();
|
removeRedundantPrefixPushPop();
|
||||||
|
|
||||||
// Call the initialization functions of the root scope from the top function
|
const std::vector<AstCFunc*>& topScopeFuncps = m_scopeInitFuncps.at(m_topScopep->scopep());
|
||||||
for (AstCFunc* const funcp : m_scopeInitFuncps.at(m_topScopep->scopep())) {
|
AstCFunc* rootFuncp = nullptr;
|
||||||
|
if (!v3Global.opt.libCreate().empty()) {
|
||||||
|
rootFuncp = newCFunc(flp, "trace_init_root");
|
||||||
|
for (size_t i = 0; i < m_topScopeRootFuncCount; ++i) {
|
||||||
|
AstCCall* const callp = new AstCCall{flp, topScopeFuncps.at(i)};
|
||||||
|
callp->dtypeSetVoid();
|
||||||
|
callp->argTypes("tracep");
|
||||||
|
rootFuncp->addStmtsp(callp->makeStmt());
|
||||||
|
}
|
||||||
|
if (!m_topScopeRootFuncCount) rootFuncp->addStmtsp(new AstComment{flp, "Empty"});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the non-wrapper initialization functions of the root scope from the top function
|
||||||
|
for (size_t i = m_topScopeRootFuncCount; i < topScopeFuncps.size(); ++i) {
|
||||||
|
AstCFunc* const funcp = topScopeFuncps.at(i);
|
||||||
AstCCall* const callp = new AstCCall{flp, funcp};
|
AstCCall* const callp = new AstCCall{flp, funcp};
|
||||||
callp->dtypeSetVoid();
|
callp->dtypeSetVoid();
|
||||||
callp->argTypes("tracep");
|
callp->argTypes("tracep");
|
||||||
|
|
@ -967,6 +1018,7 @@ public:
|
||||||
AstCFunc* const topFuncp = m_topFuncps.front();
|
AstCFunc* const topFuncp = m_topFuncps.front();
|
||||||
topFuncp->name("trace_init_top");
|
topFuncp->name("trace_init_top");
|
||||||
|
|
||||||
|
if (rootFuncp && v3Global.opt.debugCheck()) checkCallsRecurse(rootFuncp);
|
||||||
checkCalls(topFuncp);
|
checkCalls(topFuncp);
|
||||||
}
|
}
|
||||||
~TraceDeclVisitor() override {
|
~TraceDeclVisitor() override {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||||
|
//
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||||
|
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
#include <verilated.h>
|
||||||
|
|
||||||
|
#include VM_PREFIX_INCLUDE
|
||||||
|
|
||||||
|
extern "C" int sim_main(int argc, char* argv[]) {
|
||||||
|
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||||
|
const std::unique_ptr<VM_PREFIX> topp{new VM_PREFIX{contextp.get(), "top"}};
|
||||||
|
|
||||||
|
contextp->debug(0);
|
||||||
|
contextp->traceEverOn(true);
|
||||||
|
contextp->commandArgs(argc, argv);
|
||||||
|
|
||||||
|
while (!contextp->gotFinish()) {
|
||||||
|
topp->eval();
|
||||||
|
topp->clk = !topp->clk;
|
||||||
|
contextp->timeInc(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
topp->final();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) { return sim_main(argc, argv); }
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||||
|
// SPDX-FileCopyrightText: 2026 Antmicro
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
`define STRINGIFY(x) `"x`"
|
||||||
|
|
||||||
|
module t(
|
||||||
|
input clk
|
||||||
|
);
|
||||||
|
|
||||||
|
int cyc = 1;
|
||||||
|
|
||||||
|
Factorial factorial(
|
||||||
|
.clk(clk),
|
||||||
|
.i(cyc)
|
||||||
|
);
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
$dumpfile(`STRINGIFY(`TEST_DUMPFILE));
|
||||||
|
$dumpvars;
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
cyc <= cyc+1;
|
||||||
|
if (cyc == 5) begin
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module Factorial(
|
||||||
|
input clk,
|
||||||
|
input int i
|
||||||
|
);
|
||||||
|
int fact = 1;
|
||||||
|
always @(posedge clk) begin
|
||||||
|
fact <= fact * i;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
$date
|
||||||
|
Thu Apr 2 18:53:18 2026
|
||||||
|
|
||||||
|
$end
|
||||||
|
$version
|
||||||
|
Generated by VerilatedFst
|
||||||
|
$end
|
||||||
|
$timescale
|
||||||
|
1ps
|
||||||
|
$end
|
||||||
|
$scope module top $end
|
||||||
|
$var wire 1 ! clk $end
|
||||||
|
$scope module t $end
|
||||||
|
$var wire 1 ! clk $end
|
||||||
|
$var int 32 " cyc [31:0] $end
|
||||||
|
$scope module factorial $end
|
||||||
|
$var wire 1 ! clk $end
|
||||||
|
$var wire 32 " i [31:0] $end
|
||||||
|
$var int 32 # fact [31:0] $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$enddefinitions $end
|
||||||
|
#0
|
||||||
|
$dumpvars
|
||||||
|
b00000000000000000000000000000001 #
|
||||||
|
b00000000000000000000000000000001 "
|
||||||
|
0!
|
||||||
|
$end
|
||||||
|
#1
|
||||||
|
1!
|
||||||
|
b00000000000000000000000000000010 "
|
||||||
|
#2
|
||||||
|
0!
|
||||||
|
#3
|
||||||
|
1!
|
||||||
|
b00000000000000000000000000000011 "
|
||||||
|
b00000000000000000000000000000010 #
|
||||||
|
#4
|
||||||
|
0!
|
||||||
|
#5
|
||||||
|
1!
|
||||||
|
b00000000000000000000000000000110 #
|
||||||
|
b00000000000000000000000000000100 "
|
||||||
|
#6
|
||||||
|
0!
|
||||||
|
#7
|
||||||
|
1!
|
||||||
|
b00000000000000000000000000000101 "
|
||||||
|
b00000000000000000000000000011000 #
|
||||||
|
#8
|
||||||
|
0!
|
||||||
|
#9
|
||||||
|
1!
|
||||||
|
b00000000000000000000000001111000 #
|
||||||
|
b00000000000000000000000000000110 "
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
import trace_lib_as_top_common
|
||||||
|
|
||||||
|
test.scenarios('vlt_all')
|
||||||
|
|
||||||
|
trace_lib_as_top_common.run(test)
|
||||||
|
|
@ -0,0 +1,120 @@
|
||||||
|
// Generated by verilated_saif
|
||||||
|
(SAIFILE
|
||||||
|
(SAIFVERSION "2.0")
|
||||||
|
(DIRECTION "backward")
|
||||||
|
(PROGRAM_NAME "Verilator")
|
||||||
|
(DIVIDER / )
|
||||||
|
(TIMESCALE 1ps)
|
||||||
|
(DURATION 9)
|
||||||
|
(INSTANCE top
|
||||||
|
(NET
|
||||||
|
(clk (T0 5) (T1 4) (TZ 0) (TX 0) (TB 0) (TC 9))
|
||||||
|
)
|
||||||
|
(INSTANCE t
|
||||||
|
(NET
|
||||||
|
(clk (T0 5) (T1 4) (TZ 0) (TX 0) (TB 0) (TC 9))
|
||||||
|
(cyc\[0\] (T0 4) (T1 5) (TZ 0) (TX 0) (TB 0) (TC 6))
|
||||||
|
(cyc\[1\] (T0 5) (T1 4) (TZ 0) (TX 0) (TB 0) (TC 3))
|
||||||
|
(cyc\[2\] (T0 5) (T1 4) (TZ 0) (TX 0) (TB 0) (TC 1))
|
||||||
|
(cyc\[3\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[4\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[5\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[6\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[7\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[8\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[9\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[10\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[11\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[12\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[13\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[14\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[15\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[16\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[17\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[18\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[19\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[20\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[21\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[22\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[23\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[24\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[25\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[26\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[27\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[28\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[29\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[30\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(cyc\[31\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
)
|
||||||
|
(INSTANCE factorial
|
||||||
|
(NET
|
||||||
|
(clk (T0 5) (T1 4) (TZ 0) (TX 0) (TB 0) (TC 9))
|
||||||
|
(i\[0\] (T0 4) (T1 5) (TZ 0) (TX 0) (TB 0) (TC 6))
|
||||||
|
(i\[1\] (T0 5) (T1 4) (TZ 0) (TX 0) (TB 0) (TC 3))
|
||||||
|
(i\[2\] (T0 5) (T1 4) (TZ 0) (TX 0) (TB 0) (TC 1))
|
||||||
|
(i\[3\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[4\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[5\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[6\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[7\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[8\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[9\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[10\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[11\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[12\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[13\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[14\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[15\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[16\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[17\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[18\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[19\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[20\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[21\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[22\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[23\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[24\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[25\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[26\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[27\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[28\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[29\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[30\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(i\[31\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[0\] (T0 6) (T1 3) (TZ 0) (TX 0) (TB 0) (TC 2))
|
||||||
|
(fact\[1\] (T0 5) (T1 4) (TZ 0) (TX 0) (TB 0) (TC 2))
|
||||||
|
(fact\[2\] (T0 7) (T1 2) (TZ 0) (TX 0) (TB 0) (TC 2))
|
||||||
|
(fact\[3\] (T0 7) (T1 2) (TZ 0) (TX 0) (TB 0) (TC 1))
|
||||||
|
(fact\[4\] (T0 7) (T1 2) (TZ 0) (TX 0) (TB 0) (TC 1))
|
||||||
|
(fact\[5\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 1))
|
||||||
|
(fact\[6\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 1))
|
||||||
|
(fact\[7\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[8\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[9\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[10\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[11\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[12\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[13\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[14\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[15\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[16\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[17\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[18\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[19\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[20\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[21\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[22\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[23\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[24\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[25\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[26\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[27\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[28\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[29\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[30\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
(fact\[31\] (T0 9) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 0))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
import trace_lib_as_top_common
|
||||||
|
|
||||||
|
test.scenarios('vlt_all')
|
||||||
|
|
||||||
|
trace_lib_as_top_common.run(test)
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
$version Generated by VerilatedVcd $end
|
||||||
|
$timescale 1ps $end
|
||||||
|
$scope module top $end
|
||||||
|
$var wire 1 " clk $end
|
||||||
|
$scope module t $end
|
||||||
|
$var wire 1 " clk $end
|
||||||
|
$var wire 32 # cyc [31:0] $end
|
||||||
|
$scope module factorial $end
|
||||||
|
$var wire 1 " clk $end
|
||||||
|
$var wire 32 # i [31:0] $end
|
||||||
|
$var wire 32 $ fact [31:0] $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$upscope $end
|
||||||
|
$enddefinitions $end
|
||||||
|
|
||||||
|
|
||||||
|
#0
|
||||||
|
0"
|
||||||
|
b00000000000000000000000000000001 #
|
||||||
|
b00000000000000000000000000000001 $
|
||||||
|
#1
|
||||||
|
1"
|
||||||
|
b00000000000000000000000000000010 #
|
||||||
|
#2
|
||||||
|
0"
|
||||||
|
#3
|
||||||
|
1"
|
||||||
|
b00000000000000000000000000000011 #
|
||||||
|
b00000000000000000000000000000010 $
|
||||||
|
#4
|
||||||
|
0"
|
||||||
|
#5
|
||||||
|
1"
|
||||||
|
b00000000000000000000000000000100 #
|
||||||
|
b00000000000000000000000000000110 $
|
||||||
|
#6
|
||||||
|
0"
|
||||||
|
#7
|
||||||
|
1"
|
||||||
|
b00000000000000000000000000000101 #
|
||||||
|
b00000000000000000000000000011000 $
|
||||||
|
#8
|
||||||
|
0"
|
||||||
|
#9
|
||||||
|
1"
|
||||||
|
b00000000000000000000000000000110 #
|
||||||
|
b00000000000000000000000001111000 $
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
import trace_lib_as_top_common
|
||||||
|
|
||||||
|
test.scenarios('vlt_all')
|
||||||
|
|
||||||
|
trace_lib_as_top_common.run(test)
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# 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-FileCopyrightText: 2026 Wilson Snyder
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def run(test, *, verilator_flags2=()):
|
||||||
|
fmt, = test.parse_name(r"t_trace_lib_as_top_([a-z]+)")
|
||||||
|
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
test.skip("Skipping on Windows: test depends on Unix-style shared-library loading")
|
||||||
|
|
||||||
|
# All test use the same SV file
|
||||||
|
test.top_filename = "t/t_trace_lib_as_top.v"
|
||||||
|
test.pli_filename = os.path.abspath("t/t_trace_lib_as_top.cpp")
|
||||||
|
# Any variations after the format name must yield the exact same trace
|
||||||
|
test.golden_filename = test.py_filename.rpartition(fmt)[0] + fmt + ".out"
|
||||||
|
|
||||||
|
flags = [
|
||||||
|
f"--trace-{fmt}",
|
||||||
|
]
|
||||||
|
flags.extend(verilator_flags2)
|
||||||
|
|
||||||
|
cflags = (f'-DVM_PREFIX={test.vm_prefix} '
|
||||||
|
f"-DVM_PREFIX_INCLUDE='<{test.vm_prefix}.h>' ")
|
||||||
|
|
||||||
|
# Compile and run without lib-create
|
||||||
|
test.compile(verilator_flags2=[test.pli_filename] + flags +
|
||||||
|
["--exe", "--build", "-CFLAGS", f'"{cflags}"'])
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.trace_identical(test.trace_filename, test.golden_filename)
|
||||||
|
|
||||||
|
# Compile and run with lib-create
|
||||||
|
test.compile(verilator_flags2=[test.pli_filename] + flags +
|
||||||
|
["--build", "--lib-create", "simulator", "-CFLAGS", f'"{cflags}"'])
|
||||||
|
|
||||||
|
# Load library and execute the simulation loop
|
||||||
|
# This is to avoid linking manually so that the test is portable
|
||||||
|
# Running in test.run() instead of directly to keep output in the test log
|
||||||
|
libsim = f"./{test.obj_dir}/libsimulator.so"
|
||||||
|
pycode = ("import ctypes;"
|
||||||
|
f"lib=ctypes.CDLL({libsim!r});"
|
||||||
|
"lib.sim_main(0, None)")
|
||||||
|
test.run(cmd=[sys.executable, "-c", f'"{pycode}"'], logfile=test.run_log_filename)
|
||||||
|
|
||||||
|
test.trace_identical(test.trace_filename, test.golden_filename)
|
||||||
|
|
||||||
|
test.passes()
|
||||||
Loading…
Reference in New Issue