This commit is contained in:
Artur Bieniek 2026-03-30 16:34:36 +02:00 committed by GitHub
commit b625f96ab2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 429 additions and 25 deletions

View File

@ -299,6 +299,7 @@ protected:
private:
std::vector<bool> m_sigs_enabledVec; // Staging for m_sigs_enabledp
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_constOffloadCbs; // Routines to perform offloaded const dump
std::vector<CallbackRecord> m_fullCbs; // Routines to perform full dump
@ -312,6 +313,7 @@ private:
uint32_t m_numSignals = 0; // Number of distinct signals
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
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.
std::vector<std::pair<int, std::string>> m_dumpvars; // dumpvar() entries
double m_timeRes = 1e-9; // Time resolution (ns/ms etc)
@ -328,6 +330,7 @@ private:
// to access duck-typed functions to avoid a virtual function call.
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 runOffloadedCallbacks(const std::vector<CallbackRecord>& cbVec);
@ -449,6 +452,7 @@ public:
//=========================================================================
// 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 addInitCb(initCb_t cb, void* userp, const std::string& name, bool isLibInstance,
uint32_t nTraceCodes) VL_MT_SAFE;

View File

@ -301,6 +301,25 @@ VerilatedTrace<VL_SUB_T, VL_BUF_T>::~VerilatedTrace() {
//=========================================================================
// 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 <>
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),
@ -311,18 +330,13 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::traceInit() VL_MT_UNSAFE {
m_numSignals = 0;
m_maxBits = 0;
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 the initialize callbacks of library instances underneath
// - Store the base code
for (const CallbackRecord& cbr : m_initCbs) {
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);
}
for (size_t i = 0; i < m_initCbs.size(); ++i) runInitCallback(i, true);
if (expectedCodes && nextCode() != expectedCodes) {
VL_FATAL_MT(__FILE__, __LINE__, "",
@ -728,14 +742,9 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addCleanupCb(cleanupCb_t cb, void* user
template <>
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
void* const prevInitUserp = m_initUserp;
for (const CallbackRecord& cbr : m_initCbs) {
if (cbr.m_name != name) continue;
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;
for (size_t i = 0; i < m_initCbs.size(); ++i) {
if (m_initCbs[i].m_name != name) continue;
runInitCallback(i, false);
}
}

View File

@ -1271,6 +1271,7 @@ class AstNetlist final : public AstNode {
// @astgen ptr := m_stlFirstIterationp: Optional[AstVarScope] // Settle first iteration flag
VTimescale m_timeunit; // Global time unit
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
uint32_t m_nTraceCodes = 0; // Number of trace codes used by design
public:
@ -1314,10 +1315,16 @@ public:
void timeprecisionMerge(FileLine*, const VTimescale& value);
void timescaleSpecified(bool specified) { m_timescaleSpecified = specified; }
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; }
void nTraceCodes(uint32_t value) { m_nTraceCodes = value; }
AstVarScope* stlFirstIterationp();
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 {
// A package export declaration

View File

@ -528,6 +528,8 @@ class EmitCModel final : public EmitCFunc {
void emitTraceMethods(AstNodeModule* modp) {
const string topModNameProtected = EmitCUtil::prefixNameProtect(modp);
const string topTraceName
= V3OutFormatter::quoteNameControls(v3Global.rootp()->traceLibTopName());
putSectionDelimiter("Trace configuration");
@ -553,11 +555,18 @@ class EmitCModel final : public EmitCFunc {
puts("vlSymsp->__Vm_baseCode = code;\n");
if (v3Global.opt.libCreate().empty()) {
puts("tracep->pushPrefix(vlSymsp->name(), VerilatedTracePrefixType::SCOPE_MODULE);\n");
} else {
puts("if (tracep->rootInit()) {\n");
puts("tracep->pushPrefix(\"" + topTraceName
+ "\", VerilatedTracePrefixType::SCOPE_MODULE);\n");
puts("}\n");
}
puts(topModNameProtected + "__" + protect("trace_decl_types") + "(tracep);\n");
puts(topModNameProtected + "__" + protect("trace_init_top") + "(vlSelf, tracep);\n");
if (v3Global.opt.libCreate().empty()) { //
puts("tracep->popPrefix();\n");
} else {
puts("if (tracep->rootInit()) tracep->popPrefix();\n");
}
puts("}\n");

View File

@ -167,6 +167,7 @@ void V3LinkLevel::wrapTop(AstNetlist* rootp) {
UINFO(1, "No module found to wrap");
return;
}
rootp->resolvedTopModuleName(oldmodp->name());
AstNodeModule* const newmodp = new AstModule{oldmodp->fileline(), "$root", oldmodp->libname()};
newmodp->name(AstNode::encodeName(newmodp->name())); // so origName is nice

View File

@ -148,21 +148,18 @@ class TraceDeclVisitor final : public VNVisitor {
m_name = vcdName.substr(pathLen);
}
// When creating a --lib-create library, drop the name of the top module (l2 name).
// This will be replaced by the instance name in the model that uses the library.
// This would be a bit murky when there are other top level entities ($unit,
// packages, which have an instance in all libs - a problem on its own). If
// --top-module was explicitly specified, then we will drop the prefix only for the
// 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.
// 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, or
// restored at runtime if the library itself is traced as the root model. Other top
// level entities ($unit, packages, ...) keep a '$libroot' wrapper so they still have
// a stable location in the dump.
if (inTopScope && !v3Global.opt.libCreate().empty()) {
const size_t start = m_path.find(' ');
// 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");
const std::string prefix = m_path.substr(0, start);
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;
}
}

View File

@ -0,0 +1,30 @@
// -*- 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;
}

View File

@ -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

View File

@ -0,0 +1,53 @@
$date
Thu Mar 26 14:01:02 2026
$end
$version
Generated by VerilatedFst
$end
$timescale
1ps
$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
$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 "

View File

@ -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)

View File

@ -0,0 +1,115 @@
// Generated by verilated_saif
(SAIFILE
(SAIFVERSION "2.0")
(DIRECTION "backward")
(PROGRAM_NAME "Verilator")
(DIVIDER / )
(TIMESCALE 1ps)
(DURATION 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))
)
)
)
)

View File

@ -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)

View File

@ -0,0 +1,45 @@
$version Generated by VerilatedVcd $end
$timescale 1ps $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
$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 $

View File

@ -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)

View File

@ -0,0 +1,49 @@
# 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>' ")
# Run test
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()