This commit is contained in:
em2machine 2025-12-23 19:33:11 -05:00 committed by GitHub
commit 067605cb1e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 1899 additions and 15 deletions

View File

@ -189,6 +189,7 @@ set(HEADERS
V3Tristate.h
V3Udp.h
V3Undriven.h
V3UndrivenCapture.h
V3UniqueNames.h
V3Unknown.h
V3Unroll.h
@ -358,6 +359,7 @@ set(COMMON_SOURCES
V3Tristate.cpp
V3Udp.cpp
V3Undriven.cpp
V3UndrivenCapture.cpp
V3Unknown.cpp
V3Unroll.cpp
V3UnrollGen.cpp

View File

@ -341,6 +341,7 @@ RAW_OBJS_PCH_ASTNOMT = \
V3Tristate.o \
V3Udp.o \
V3Undriven.o \
V3UndrivenCapture.o \
V3Unknown.o \
V3Unroll.o \
V3UnrollGen.o \

View File

@ -28,6 +28,7 @@
#include "V3Undriven.h"
#include "V3Stats.h"
#include "V3UndrivenCapture.h"
#include <vector>
@ -51,6 +52,9 @@ class UndrivenVarEntry final {
const FileLine* m_nodeFileLinep = nullptr; // File line of varref if driven, else nullptr
bool m_underGen = false; // Under a generate
const AstNodeFTaskRef* m_callNodep
= nullptr; // Call node if driven via writeSummary, else nullptr
enum : uint8_t { FLAG_USED = 0, FLAG_DRIVEN = 1, FLAG_DRIVEN_ALWCOMB = 2, FLAGS_PER_BIT = 3 };
public:
@ -278,6 +282,12 @@ public:
}
}
}
void drivenViaCall(const AstNodeFTaskRef* nodep) {
drivenWhole();
if (!m_callNodep) { m_callNodep = nodep; }
}
const AstNodeFTaskRef* callNodep() const { return m_callNodep; }
};
//######################################################################
@ -304,6 +314,9 @@ class UndrivenVisitor final : public VNVisitorConst {
const AstAlways* m_alwaysp = nullptr; // Current always of either type
const AstAlways* m_alwaysCombp = nullptr; // Current always if combo, otherwise nullptr
V3UndrivenCapture* const m_capturep = nullptr; // Capture object. 'nullptr' if disabled.
const bool m_enableWriteSummary = false; // Enable writeSummary computation plumbing
// METHODS
UndrivenVarEntry* getEntryp(AstVar* nodep, int which_user) {
@ -420,6 +433,16 @@ class UndrivenVisitor final : public VNVisitorConst {
<< " (IEEE 1800-2023 13.5): " << nodep->prettyNameQ());
}
}
// If writeSummary is enabled, task/function definitions are treated as non-executed.
// Their effects are applied at call sites via writeSummary(), so don't let definition
// traversal create phantom "other writes" for MULTIDRIVEN.
if (m_enableWriteSummary && m_taskp && !m_alwaysp && !m_inContAssign && !m_inInitialStatic
&& !m_inBBox && !m_taskp->dpiExport()) {
AstVar* const retVarp = VN_CAST(m_taskp->fvarp(), Var);
if (!retVarp || nodep->varp() != retVarp) return;
}
for (int usr = 1; usr < (m_alwaysCombp ? 3 : 2); ++usr) {
UndrivenVarEntry* const entryp = getEntryp(nodep->varp(), usr);
const bool fdrv = nodep->access().isWriteOrRW()
@ -432,7 +455,13 @@ class UndrivenVisitor final : public VNVisitorConst {
if (entryp->isDrivenWhole() && !m_inBBox && !VN_IS(nodep, VarXRef)
&& !VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType)
&& nodep->fileline() != entryp->getNodeFileLinep() && !entryp->isUnderGen()
&& entryp->getNodep()) {
&& (entryp->getNodep() || (m_enableWriteSummary && entryp->callNodep()))) {
const AstNode* const otherWritep
= entryp->getNodep()
? static_cast<const AstNode*>(entryp->getNodep())
: (m_enableWriteSummary ? entryp->callNodep() : nullptr);
if (m_alwaysCombp
&& (!entryp->isDrivenAlwaysCombWhole()
|| (m_alwaysCombp != entryp->getAlwCombp()
@ -443,20 +472,18 @@ class UndrivenVisitor final : public VNVisitorConst {
<< " (IEEE 1800-2023 9.2.2.2): " << nodep->prettyNameQ() << '\n'
<< nodep->warnOther() << '\n'
<< nodep->warnContextPrimary() << '\n'
<< entryp->getNodep()->warnOther()
<< "... Location of other write\n"
<< entryp->getNodep()->warnContextSecondary());
<< otherWritep->warnOther() << "... Location of other write\n"
<< otherWritep->warnContextSecondary());
}
if (!m_alwaysCombp && entryp->isDrivenAlwaysCombWhole()) {
nodep->v3warn(MULTIDRIVEN,
"Variable also written to in always_comb"
<< " (IEEE 1800-2023 9.2.2.2): " << nodep->prettyNameQ()
<< '\n'
<< nodep->warnOther() << '\n'
<< nodep->warnContextPrimary() << '\n'
<< entryp->getNodep()->warnOther()
<< "... Location of always_comb write\n"
<< entryp->getNodep()->warnContextSecondary());
nodep->v3warn(MULTIDRIVEN, "Variable also written to in always_comb"
<< " (IEEE 1800-2023 9.2.2.2): "
<< nodep->prettyNameQ() << '\n'
<< nodep->warnOther() << '\n'
<< nodep->warnContextPrimary() << '\n'
<< otherWritep->warnOther()
<< "... Location of always_comb write\n"
<< otherWritep->warnContextSecondary());
}
}
entryp->drivenWhole(nodep, nodep->fileline());
@ -523,10 +550,39 @@ class UndrivenVisitor final : public VNVisitorConst {
iterateChildrenConst(nodep);
if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) UINFO(9, " Done " << nodep);
}
void visit(AstNodeFTaskRef* nodep) override {
VL_RESTORER(m_inFTaskRef);
m_inFTaskRef = true;
iterateChildrenConst(nodep);
if (!m_enableWriteSummary || !m_capturep) return;
// If writeSummary is enabled, task/function definitions are treated as non-executed.
// Do not apply writeSummary at calls inside a task definition, or they will look like
// independent drivers (phantom MULTIDRIVEN). Did the lambda on purpose - lessen chance of
// screwup in future edits.
const auto inExecutedContext = [this]() {
return !(m_taskp && !m_alwaysp && !m_inContAssign && !m_inInitialStatic && !m_inBBox
&& !m_taskp->dpiExport());
};
if (!inExecutedContext()) return;
AstNodeFTask* const calleep = nodep->taskp();
if (!calleep) return;
const auto& vars = m_capturep->writeSummary(calleep);
for (AstVar* const varp : vars) {
for (int usr = 1; usr < (m_alwaysCombp ? 3 : 2); ++usr) {
UndrivenVarEntry* const entryp = getEntryp(varp, usr);
entryp->drivenViaCall(nodep);
if (m_alwaysCombp)
entryp->drivenAlwaysCombWhole(m_alwaysCombp, m_alwaysCombp->fileline());
}
}
}
void visit(AstNodeFTask* nodep) override {
@ -556,7 +612,13 @@ class UndrivenVisitor final : public VNVisitorConst {
public:
// CONSTRUCTORS
explicit UndrivenVisitor(AstNetlist* nodep) { iterateConst(nodep); }
explicit UndrivenVisitor(AstNetlist* nodep, V3UndrivenCapture* capturep,
bool enableWriteSummary)
: m_capturep{capturep}
, m_enableWriteSummary{enableWriteSummary} {
iterateConst(nodep);
}
~UndrivenVisitor() override {
for (UndrivenVarEntry* ip : m_entryps[1]) ip->reportViolations();
for (int usr = 1; usr < 3; ++usr) {
@ -570,6 +632,12 @@ public:
void V3Undriven::undrivenAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ":");
{ UndrivenVisitor{nodep}; }
const bool enable = V3UndrivenCapture::enableWriteSummary;
if (enable) {
V3UndrivenCapture capture{nodep};
{ UndrivenVisitor{nodep, &capture, enable}; }
} else {
{ UndrivenVisitor{nodep, nullptr, enable}; }
}
if (v3Global.opt.stats()) V3Stats::statsStage("undriven");
}

211
src/V3UndrivenCapture.cpp Normal file
View File

@ -0,0 +1,211 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Capture task/function write summaries for undriven checks
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2003-2025 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
//
//*************************************************************************
#include "V3UndrivenCapture.h"
#include "V3Error.h"
#include "V3Global.h"
#include <algorithm>
VL_DEFINE_DEBUG_FUNCTIONS;
namespace {
struct Stats final {
uint64_t ftasks = 0;
uint64_t varWrites = 0;
uint64_t callEdges = 0;
} g_stats;
static std::string taskNameQ(const AstNodeFTask* taskp) {
if (!taskp) return "<null>";
return taskp->prettyNameQ();
}
class CaptureVisitor final : public VNVisitorConst {
V3UndrivenCapture& m_cap;
const AstNodeFTask* m_curTaskp = nullptr;
static void iterateListConst(VNVisitorConst& v, AstNode* nodep) {
for (AstNode* np = nodep; np; np = np->nextp()) np->accept(v);
}
public:
explicit CaptureVisitor(V3UndrivenCapture& cap, AstNetlist* netlistp)
: m_cap{cap} {
iterateConst(netlistp);
}
private:
// Visit a task/function definition and collect direct writes and direct callees.
void visit(AstNodeFTask* nodep) override {
VL_RESTORER(m_curTaskp);
m_curTaskp = nodep;
++g_stats.ftasks;
UINFO(9, "undriven capture enter ftask " << nodep << " " << nodep->prettyNameQ());
m_cap.noteTask(nodep);
iterateListConst(*this, nodep->stmtsp());
}
void visit(AstNodeVarRef* nodep) override {
if (m_curTaskp && nodep->access().isWriteOrRW()) {
++g_stats.varWrites;
UINFO(9, "undriven capture direct write in " << taskNameQ(m_curTaskp)
<< " var=" << nodep->varp()->prettyNameQ()
<< " at " << nodep->fileline());
m_cap.noteDirectWrite(m_curTaskp, nodep->varp());
}
iterateChildrenConst(nodep);
}
void visit(AstNodeFTaskRef* nodep) override {
// Record the call edge if resolved
if (m_curTaskp) {
if (AstNodeFTask* const calleep = nodep->taskp()) {
++g_stats.callEdges;
UINFO(9, "undriven capture call edge " << taskNameQ(m_curTaskp) << " -> "
<< taskNameQ(calleep));
m_cap.noteCallEdge(m_curTaskp, calleep);
} else {
UINFO(9, "undriven capture unresolved call in " << taskNameQ(m_curTaskp)
<< " name=" << nodep->name());
}
}
iterateChildrenConst(nodep); // still scan pins/args
}
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
};
} // namespace
bool V3UndrivenCapture::enableWriteSummary = true;
void V3UndrivenCapture::sortUniqueVars(std::vector<AstVar*>& vec) {
std::sort(vec.begin(), vec.end());
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
}
void V3UndrivenCapture::sortUniqueFTasks(std::vector<const AstNodeFTask*>& vec) {
std::sort(vec.begin(), vec.end());
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
}
V3UndrivenCapture::V3UndrivenCapture(AstNetlist* netlistp) {
gather(netlistp);
// Normalize direct lists
for (auto& kv : m_info) {
sortUniqueVars(kv.second.directWrites);
sortUniqueFTasks(kv.second.callees);
}
// Compute summaries for all tasks
for (const auto& kv : m_info) (void)computeWriteSummary(kv.first);
UINFO(9, "undriven capture stats ftasks="
<< g_stats.ftasks << " varWrites=" << g_stats.varWrites
<< " callEdges=" << g_stats.callEdges << " uniqueTasks=" << m_info.size());
}
void V3UndrivenCapture::gather(AstNetlist* netlistp) {
// Walk netlist and populate m_info with direct writes + call edges
CaptureVisitor{*this, netlistp};
}
const V3UndrivenCapture::FTaskInfo* V3UndrivenCapture::find(const AstNodeFTask* taskp) const {
const auto it = m_info.find(taskp);
if (it == m_info.end()) return nullptr;
return &it->second;
}
const std::vector<AstVar*>& V3UndrivenCapture::writeSummary(const AstNodeFTask* taskp) {
// Ensure entry exists even if empty
(void)m_info[taskp];
return computeWriteSummary(taskp);
}
const std::vector<AstVar*>& V3UndrivenCapture::computeWriteSummary(const AstNodeFTask* taskp) {
FTaskInfo& info = m_info[taskp];
if (info.state == State::DONE) {
UINFO(9, "undriven capture writeSummary cached size=" << info.writeSummary.size()
<< " for " << taskNameQ(taskp));
return info.writeSummary;
}
if (info.state == State::VISITING) {
UINFO(9, "undriven capture recursion detected at "
<< taskNameQ(taskp)
<< " returning directWrites size=" << info.directWrites.size());
// Cycle detected. return directWrites only to guarantee termination.
if (info.writeSummary.empty()) info.writeSummary = info.directWrites;
sortUniqueVars(info.writeSummary);
return info.writeSummary;
}
info.state = State::VISITING;
// Start with direct writes
info.writeSummary = info.directWrites;
// Need callees
for (const AstNodeFTask* calleep : info.callees) {
if (m_info.find(calleep) == m_info.end()) continue;
const std::vector<AstVar*>& sub = computeWriteSummary(calleep);
info.writeSummary.insert(info.writeSummary.end(), sub.begin(), sub.end());
}
// Remove duplicates and sort because grabbing all of the callees can result in duplicates
sortUniqueVars(info.writeSummary);
UINFO(9, "undriven capture writeSummary computed size=" << info.writeSummary.size() << " for "
<< taskNameQ(taskp));
// We are done, so set the m_info state correctly and return the vector of variables
info.state = State::DONE;
return info.writeSummary;
}
void V3UndrivenCapture::noteTask(const AstNodeFTask* taskp) { (void)m_info[taskp]; }
void V3UndrivenCapture::noteDirectWrite(const AstNodeFTask* taskp, AstVar* varp) {
FTaskInfo& info = m_info[taskp];
// Exclude function return variable (not an externally visible side-effect)
AstVar* const retVarp = VN_CAST(taskp->fvarp(), Var);
if (retVarp && varp == retVarp) return;
info.directWrites.push_back(varp);
}
void V3UndrivenCapture::noteCallEdge(const AstNodeFTask* callerp, const AstNodeFTask* calleep) {
m_info[callerp].callees.push_back(calleep);
(void)m_info[calleep]; // ensure callee entry exists
}
void V3UndrivenCapture::debugDumpTask(const AstNodeFTask* taskp, int level) const {
const auto* const infop = find(taskp);
if (!infop) {
UINFO(level, "undriven capture no entry for task " << taskp);
return;
}
UINFO(level, "undriven capture dump task " << taskp << " " << taskp->prettyNameQ()
<< " directWrites=" << infop->directWrites.size()
<< " callees=" << infop->callees.size()
<< " writeSummary=" << infop->writeSummary.size());
}

113
src/V3UndrivenCapture.h Normal file
View File

@ -0,0 +1,113 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Capture task/function write summaries for undriven checks
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2003-2025 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
//
//*************************************************************************
//*************************************************************************
//
// Capture task/function write summaries for multidriven checks.
// Per-task/function capture info keyed by resolved AstNodeFTask* identity (FTask = function or
// task). This is our 'graph' of tasks/functions. Each node has a list of direct callees and
// a list of variables written in the function body. There are methods to dedup after walking the
// tree. V3Undriven then uses the writeSummary for multidriven checks - i.e. it treats writes (side
// effects) inside subroutines as part of the caller's process.
//
//*************************************************************************
#ifndef VERILATOR_V3UNDRIVENCAPTURE_H_
#define VERILATOR_V3UNDRIVENCAPTURE_H_
#include "config_build.h"
#include "V3Ast.h"
#include <unordered_map>
#include <vector>
class AstNetlist;
class V3UndrivenCapture final {
public:
// DFS computation state for writeSummary propagation.
// UNVISITED: write summary not computed yet
// VISITING: currently computing on the call stack - used to detect cycles
// DONE: write summary computed
enum class State : uint8_t { UNVISITED, VISITING, DONE };
struct FTaskInfo final {
// Variables written directly in this task/function body.
std::vector<AstVar*> directWrites;
// Direct resolved callees from this task/function body.
std::vector<const AstNodeFTask*> callees;
// 'Write through write' writeSummary for the given task/function. Meaning ultimately
// everything that this function/task writes to.
std::vector<AstVar*> writeSummary;
// State for writeSummary computation.
State state = State::UNVISITED;
};
// Enable writeSummary computation. If disabled, then the existing V3Undriven behaviour is
// used.
static bool enableWriteSummary;
private:
// Per-task/function capture info keyed by resolved AstNodeFTask* identity (FTask = function or
// task). This is our 'graph' of tasks/functions. Each node has a list of direct callees and
// a list of variables written in the function body. There are methods to remove duplicates
// otherwise this could explode.
std::unordered_map<const AstNodeFTask*, FTaskInfo> m_info;
// Sort and remove duplicates from a vector of variables. This is called after a task/function
// write summary is computed. writeSummary can accumulate duplicates if a variable is written
// in multiple tasks/functions.
static void sortUniqueVars(std::vector<AstVar*>& vec);
// Sort and remove duplicates from a vector of callees. The visitor can record the same callee
// multiple times (multiple call sites, branches, etc).
static void sortUniqueFTasks(std::vector<const AstNodeFTask*>& vec);
// Collect direct writes and call edges for all tasks/functions. Run one time when
// UndrivenCapture is created. This runs the visitor over the tree.
void gather(AstNetlist* netlistp);
// Compute (and cache) 'write through write' writeSummary for the given task/function.
const std::vector<AstVar*>& computeWriteSummary(const AstNodeFTask* taskp);
public:
// Build capture database and precompute writeSummary for all discovered tasks/functions.
explicit V3UndrivenCapture(AstNetlist* netlistp);
// Lookup task/function capture info (nullptr if unknown). This is currently only used for the
// debug helper.
const FTaskInfo* find(const AstNodeFTask* taskp) const;
// Get write through write through write, etc (call chain) writeSummary for a task/function
// (creates empty entry if needed). This returns a vector of variables that a particular
// task/function writes to, including all variables written by functions called by this
// task/function, and so on.
const std::vector<AstVar*>& writeSummary(const AstNodeFTask* taskp);
// Used by the capture visitor to record information about tasks/functions and their statements
// and callees. noteTask() makes sure there is an entry for the given taskp.
void noteTask(const AstNodeFTask* taskp);
// Inside the body of taskp there is a write to variable varp
void noteDirectWrite(const AstNodeFTask* taskp, AstVar* varp);
// Inside the body of callerp there is a call to calleep, this is needed so we can create a
// summary that includes all variables written by functions called by this task/function, and
// so on.
void noteCallEdge(const AstNodeFTask* callerp, const AstNodeFTask* calleep);
// Dump one task's summary for debugging. leaving this in, in case need to debug future
// functionality.
void debugDumpTask(const AstNodeFTask* taskp, int level = 9) const;
};
#endif // VERILATOR_V3UNDRIVENCAPTURE_H_

View File

@ -0,0 +1,11 @@
%Warning-MULTIDRIVEN: t/t_lint_multidriven_taskcall_bad.v:28:15: Variable written to in always_comb also written by other process (IEEE 1800-2023 9.2.2.2): 'out'
: ... note: In instance 't'
t/t_lint_multidriven_taskcall_bad.v:28:15:
28 | if (sel2) out = 1'b1;
| ^~~
t/t_lint_multidriven_taskcall_bad.v:20:5: ... Location of other write
20 | out = 1'b0;
| ^~~
... For warning description see https://verilator.org/warn/MULTIDRIVEN?v=latest
... Use "/* verilator lint_off MULTIDRIVEN */" and lint_on around source to disable this message.
%Error: Exiting due to

View File

@ -0,0 +1,16 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2024 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
import vltest_bootstrap
test.scenarios('linter')
test.lint(fails=True, expect_filename=test.golden_filename)
test.passes()

View File

@ -0,0 +1,32 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
// SPDX-License-Identifier: CC0-1.0
module t (
input logic sel,
input logic sel2,
input logic d,
output logic out
);
task automatic do_stuff(input logic din);
out = din;
endtask
// Driver #1 (via task call)
always_comb begin
out = 1'b0;
if (sel) do_stuff(d);
end
// Driver #2 (separate process)
// I only want the MULTIDRIVEN.
/* verilator lint_off LATCH */
always_comb begin
if (sel2) out = 1'b1;
end
/* verilator lint_on LATCH */
endmodule

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 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
import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=["--binary"])
test.execute()
test.passes()

View File

@ -0,0 +1,72 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
// SPDX-License-Identifier: CC0-1.0
// class task writes through ref argument (direct assignment + class task in same always_comb)
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
class C;
task automatic set1(ref logic q);
q = 1'b1;
endtask
task automatic set0(ref logic q);
q = 1'b0;
endtask
endclass
module mod #()(
input logic sel
,output logic val
);
logic l0;
C c;
initial c = new;
always_comb begin
l0 = 1'b0;
if (sel) begin
c.set1(l0);
end
end
assign val = l0;
endmodule
module m_tb#()();
logic sel, val;
mod m(
.sel(sel)
,.val(val)
);
initial begin
#1;
sel = 'b0;
#1;
`checkd(val, 1'b0);
sel = 'b1;
#1;
`checkd(val, 1'b1);
sel = 'b0;
#1;
`checkd(val, 1'b0);
end
initial begin
#5;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 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
import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=["--binary"])
test.execute()
test.passes()

View File

@ -0,0 +1,72 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
// SPDX-License-Identifier: CC0-1.0
// class task chain - nested method calls write through ref in same always_comb
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
class C;
task automatic inner(inout logic q);
q = 1'b1;
endtask
task automatic outer(inout logic q);
inner(q);
endtask
endclass
module mod #()(
input logic sel
,output logic val
);
logic l0;
C c;
initial c = new;
always_comb begin
l0 = 1'b0;
if (sel) begin
c.outer(l0);
end
end
assign val = l0;
endmodule
module m_tb#()();
logic sel, val;
mod m(
.sel(sel)
,.val(val)
);
initial begin
#1;
sel = 'b0;
#1;
`checkd(val, 1'b0);
sel = 'b1;
#1;
`checkd(val, 1'b1);
sel = 'b0;
#1;
`checkd(val, 1'b0);
end
initial begin
#5;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 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
import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=["--binary"])
test.execute()
test.passes()

View File

@ -0,0 +1,71 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
// SPDX-License-Identifier: CC0-1.0
// class handle passed through module port - class method writes through ref
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
class C;
task automatic set1(ref logic q);
q = 1'b1;
endtask
endclass
module mod #()(
input logic sel
,output logic val
,C c
);
logic l0;
always_comb begin
l0 = 1'b0;
if (sel) begin
c.set1(l0);
end
end
assign val = l0;
endmodule
module m_tb#()();
logic sel, val;
C c;
initial c = new;
mod m(
.sel(sel)
,.val(val)
,.c(c)
);
initial begin
#1;
sel = 'b0;
#1;
`checkd(val, 1'b0);
sel = 'b1;
#1;
`checkd(val, 1'b1);
sel = 'b0;
#1;
`checkd(val, 1'b0);
end
initial begin
#5;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 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
import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=["--binary"])
test.execute()
test.passes()

View File

@ -0,0 +1,66 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
// SPDX-License-Identifier: CC0-1.0
// static class task - call via class scope, writes through ref in same always_comb
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
class C;
static task automatic set1(ref logic q);
q = 1'b1;
endtask
endclass
module mod #()(
input logic sel
,output logic val
);
logic l0;
always_comb begin
l0 = 1'b0;
if (sel) begin
C::set1(l0);
end
end
assign val = l0;
endmodule
module m_tb#()();
logic sel, val;
mod m(
.sel(sel)
,.val(val)
);
initial begin
#1;
sel = 'b0;
#1;
`checkd(val, 1'b0);
sel = 'b1;
#1;
`checkd(val, 1'b1);
sel = 'b0;
#1;
`checkd(val, 1'b0);
end
initial begin
#5;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 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
import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=["--binary"])
test.execute()
test.passes()

View File

@ -0,0 +1,79 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
// SPDX-License-Identifier: CC0-1.0
// class composition - one class calls another task, ultimately writes through ref
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
class CInner;
task automatic set1(ref logic q);
q = 1'b1;
endtask
endclass
class COuter;
CInner inner;
function new();
inner = new;
endfunction
task automatic set1(ref logic q);
inner.set1(q);
endtask
endclass
module mod #()(
input logic sel
,output logic val
);
logic l0;
COuter c;
initial c = new;
always_comb begin
l0 = 1'b0;
if (sel) begin
c.set1(l0);
end
end
assign val = l0;
endmodule
module m_tb#()();
logic sel, val;
mod m(
.sel(sel)
,.val(val)
);
initial begin
#1;
sel = 'b0;
#1;
`checkd(val, 1'b0);
sel = 'b1;
#1;
`checkd(val, 1'b1);
sel = 'b0;
#1;
`checkd(val, 1'b0);
end
initial begin
#5;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 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
import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=["--binary"])
test.execute()
test.passes()

View File

@ -0,0 +1,69 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
// SPDX-License-Identifier: CC0-1.0
// class function returns value - always_comb writes var directly + via class function call
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
class C;
function automatic logic ret1();
return 1'b1;
endfunction
endclass
module mod #()(
input logic sel
,output logic val
);
logic l0;
C c;
initial c = new;
always_comb begin
l0 = 1'b0;
if (sel) begin
l0 = c.ret1();
end
end
assign val = l0;
endmodule
module m_tb#()();
logic sel, val;
mod m(
.sel(sel)
,.val(val)
);
initial begin
#1;
sel = 'b0;
#1;
`checkd(val, 1'b0);
sel = 'b1;
#1;
`checkd(val, 1'b1);
sel = 'b0;
#1;
`checkd(val, 1'b0);
end
initial begin
#5;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 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
import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=["--binary"])
test.execute()
test.passes()

View File

@ -0,0 +1,66 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
// SPDX-License-Identifier: CC0-1.0
// static class function returns value - always_comb uses class scope call
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
class C;
static function automatic logic ret1();
return 1'b1;
endfunction
endclass
module mod #()(
input logic sel
,output logic val
);
logic l0;
always_comb begin
l0 = 1'b0;
if (sel) begin
l0 = C::ret1();
end
end
assign val = l0;
endmodule
module m_tb#()();
logic sel, val;
mod m(
.sel(sel)
,.val(val)
);
initial begin
#1;
sel = 'b0;
#1;
`checkd(val, 1'b0);
sel = 'b1;
#1;
`checkd(val, 1'b1);
sel = 'b0;
#1;
`checkd(val, 1'b0);
end
initial begin
#5;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 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
import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=["--binary"])
test.execute()
test.passes()

View File

@ -0,0 +1,43 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
// SPDX-License-Identifier: CC0-1.0
// MULTIDRIVEN false positive - package function return var
//
// Minimal reproducer for: package function with "return expr" used in always_comb expression.
// The function return variable must not be treated as a side-effect "writeSummary" target.
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
package p;
function automatic int num_bytes(input int size);
return 1 << size;
endfunction
endpackage
module t;
typedef struct packed {
logic [31:0] addr;
logic [2:0] size;
} meta_t;
meta_t rd_meta_q;
meta_t rd_meta;
always_comb begin
rd_meta = rd_meta_q;
rd_meta.addr = rd_meta_q.addr + p::num_bytes(int'(rd_meta_q.size));
end
initial begin
rd_meta_q.addr = 32'h100;
rd_meta_q.size = 3'd2; // num_bytes = 4
#1;
`checkd(rd_meta.addr, 32'h104);
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 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
import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=["--binary"])
test.execute()
test.passes()

View File

@ -0,0 +1,68 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
// SPDX-License-Identifier: CC0-1.0
// multidriven interface test - direct assignment to interface signal and task assign in same process
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
interface my_if;
logic l0;
task set_l0_1(); l0 = 1'b1; endtask
task set_l0_0(); l0 = 1'b0; endtask
endinterface
module mod #()(
input logic sel
,output logic val
);
my_if if0();
always_comb begin
if0.l0 = 1'b0;
if(sel) begin
if0.set_l0_1();
end
end
assign val = if0.l0;
endmodule
module m_tb#()();
logic sel, val;
mod m(
.sel(sel)
,.val(val)
);
initial begin
#1;
sel = 'b0;
`checkd(val, 1'b0);
#1;
sel = 'b1;
`checkd(val, 1'b1);
#1;
sel = 'b0;
`checkd(val, 1'b0);
#1;
end
initial begin
#5;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 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
import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=["--binary"])
test.execute()
test.passes()

View File

@ -0,0 +1,68 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
// SPDX-License-Identifier: CC0-1.0
// interface task chain - nested task calls write interface signal in same always_comb
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
interface my_if;
logic l0;
task set_l0_1_inner(); l0 = 1'b1; endtask
task set_l0_1_outer(); set_l0_1_inner(); endtask
endinterface
module mod #()(
input logic sel
,output logic val
);
my_if if0();
always_comb begin
if0.l0 = 1'b0;
if (sel) begin
if0.set_l0_1_outer();
end
end
assign val = if0.l0;
endmodule
module m_tb#()();
logic sel, val;
mod m(
.sel(sel)
,.val(val)
);
initial begin
#1;
sel = 'b0;
`checkd(val, 1'b0);
#1;
sel = 'b1;
`checkd(val, 1'b1);
#1;
sel = 'b0;
`checkd(val, 1'b0);
#1;
end
initial begin
#5;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 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
import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=["--binary"])
test.execute()
test.passes()

View File

@ -0,0 +1,69 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
// SPDX-License-Identifier: CC0-1.0
// interface passed through module port - direct assign + task call in same always_comb
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
interface my_if;
logic l0;
task set_l0_1(); l0 = 1'b1; endtask
task set_l0_0(); l0 = 1'b0; endtask
endinterface
module mod #()(
input logic sel
,output logic val
,my_if ifp
);
always_comb begin
ifp.l0 = 1'b0;
if (sel) begin
ifp.set_l0_1();
end
end
assign val = ifp.l0;
endmodule
module m_tb#()();
logic sel, val;
my_if if0();
mod m(
.sel(sel)
,.val(val)
,.ifp(if0)
);
initial begin
#1;
sel = 'b0;
`checkd(val, 1'b0);
#1;
sel = 'b1;
`checkd(val, 1'b1);
#1;
sel = 'b0;
`checkd(val, 1'b0);
#1;
end
initial begin
#5;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 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
import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=["--binary"])
test.execute()
test.passes()

View File

@ -0,0 +1,73 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
// SPDX-License-Identifier: CC0-1.0
// interface modport + task import - write interface signal in same always_comb
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
interface my_if;
logic l0;
task set_l0_1(); l0 = 1'b1; endtask
modport mp (
output l0,
import set_l0_1
);
endinterface
module mod #()(
input logic sel
,output logic val
,my_if.mp ifp
);
always_comb begin
ifp.l0 = 1'b0;
if (sel) begin
ifp.set_l0_1();
end
end
assign val = ifp.l0;
endmodule
module m_tb#()();
logic sel, val;
my_if if0();
mod m(
.sel(sel)
,.val(val)
,.ifp(if0)
);
initial begin
#1;
sel = 'b0;
`checkd(val, 1'b0);
#1;
sel = 'b1;
`checkd(val, 1'b1);
#1;
sel = 'b0;
`checkd(val, 1'b0);
#1;
end
initial begin
#5;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 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
import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=["--binary"])
test.execute()
test.passes()

View File

@ -0,0 +1,69 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
// SPDX-License-Identifier: CC0-1.0
// interface task writes through output formal - actual is interface member
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
interface my_if;
logic l0;
task automatic set_any(output logic q);
q = 1'b1;
endtask
endinterface
module mod #()(
input logic sel
,output logic val
);
my_if if0();
always_comb begin
if0.l0 = 1'b0;
if (sel) begin
if0.set_any(if0.l0);
end
end
assign val = if0.l0;
endmodule
module m_tb#()();
logic sel, val;
mod m(
.sel(sel)
,.val(val)
);
initial begin
#1;
sel = 'b0;
`checkd(val, 1'b0);
#1;
sel = 'b1;
`checkd(val, 1'b1);
#1;
sel = 'b0;
`checkd(val, 1'b0);
#1;
end
initial begin
#5;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 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
import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=["--binary"])
test.execute()
test.passes()

View File

@ -0,0 +1,69 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
// SPDX-License-Identifier: CC0-1.0
// nested interface test - direct assignment + nested interface task call in same always_comb
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
interface leaf_if;
logic l0;
task set1(); l0 = 1'b1; endtask
endinterface
interface top_if;
leaf_if sub();
endinterface
module mod #()(
input logic sel
,output logic val
);
top_if if0();
always_comb begin
if0.sub.l0 = 1'b0;
if (sel) begin
if0.sub.set1();
end
end
assign val = if0.sub.l0;
endmodule
module m_tb#()();
logic sel, val;
mod m(
.sel(sel)
,.val(val)
);
initial begin
#1;
sel = 'b0;
`checkd(val, 1'b0);
#1;
sel = 'b1;
`checkd(val, 1'b1);
#1;
sel = 'b0;
`checkd(val, 1'b0);
#1;
end
initial begin
#5;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 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
import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=["--binary"])
test.execute()
test.passes()

View File

@ -0,0 +1,68 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
// SPDX-License-Identifier: CC0-1.0
// nested interface aggregator - two nested interfaces, only one driven
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
interface chan_if;
logic b0;
task set1(); b0 = 1'b1; endtask
endinterface
interface agg_if;
chan_if tlb();
chan_if ic();
endinterface
module mod #()(
input logic sel
,output logic val
);
agg_if a();
always_comb begin
a.tlb.b0 = 1'b0;
if (sel) a.tlb.set1();
end
assign val = a.tlb.b0;
endmodule
module m_tb#()();
logic sel, val;
mod m(
.sel(sel)
,.val(val)
);
initial begin
#1;
sel = 'b0;
`checkd(val, 1'b0);
#1;
sel = 'b1;
`checkd(val, 1'b1);
#1;
sel = 'b0;
`checkd(val, 1'b0);
#1;
end
initial begin
#5;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 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
import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=["--binary"])
test.execute()
test.passes()

View File

@ -0,0 +1,120 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
// SPDX-License-Identifier: CC0-1.0
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
// direct task call
module mod0 #()(
input logic sel,
output logic val
);
logic l0;
task do_stuff();
l0 = 'b1;
endtask
always_comb begin
l0 = 'b0;
if(sel) begin
do_stuff();
end
end
assign val = l0;
endmodule
// nested task call chain
module mod1 #()(
input logic sel,
output logic val
);
logic l0;
task do_inner();
l0 = 'b1;
endtask
task do_outer();
do_inner();
endtask
always_comb begin
l0 = 'b0;
if (sel) do_outer();
end
assign val = l0;
endmodule
// task writes through an output arguement
module mod2 #()(
input logic sel,
output logic val
);
logic l0;
task automatic do_stuff(output logic q);
q = 1'b1;
endtask
always_comb begin
l0 = 1'b0;
if (sel) do_stuff(l0);
end
assign val = l0;
endmodule
// function call that writes
module mod3 #()(
input logic sel,
output logic val
);
logic l0;
function automatic void do_func();
l0 = 1'b1;
endfunction
always_comb begin
l0 = 1'b0;
if (sel) do_func();
end
assign val = l0;
endmodule
// two tasks set0/set1
module mod4 #()(
input logic sel,
output logic val
);
logic l0;
task automatic set1(); l0 = 1'b1; endtask
task automatic set0(); l0 = 1'b0; endtask
always_comb begin
set0();
if (sel) begin
set1();
end
end
assign val = l0;
endmodule
module m_tb;
logic sel;
logic v0, v1, v2, v3, v4;
mod0 u0(.sel(sel), .val(v0));
mod1 u1(.sel(sel), .val(v1));
mod2 u2(.sel(sel), .val(v2));
mod3 u3(.sel(sel), .val(v3));
mod4 u4(.sel(sel), .val(v4));
initial begin
#1; sel = 0;
`checkd(v0, 0); `checkd(v1, 0); `checkd(v2, 0); `checkd(v3, 0); `checkd(v4, 0);
#1; sel = 1;
`checkd(v0, 1); `checkd(v1, 1); `checkd(v2, 1); `checkd(v3, 1); `checkd(v4, 1);
#1; sel = 0;
`checkd(v0, 0); `checkd(v1, 0); `checkd(v2, 0); `checkd(v3, 0); `checkd(v4, 0);
#1;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule