my OG test, a test that should fail, and a variant of the OG with nested tasks

This commit is contained in:
em2machine 2025-12-21 19:11:39 +01:00
parent c801718ba1
commit 76886e14e6
9 changed files with 244 additions and 1 deletions

View File

@ -442,6 +442,16 @@ class UndrivenVisitor final : public VNVisitorConst {
<< " (IEEE 1800-2023 13.5): " << nodep->prettyNameQ());
}
}
// EOM
// 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) {
return;
}
for (int usr = 1; usr < (m_alwaysCombp ? 3 : 2); ++usr) {
UndrivenVarEntry* const entryp = getEntryp(nodep->varp(), usr);
const bool fdrv = nodep->access().isWriteOrRW()
@ -573,6 +583,15 @@ class UndrivenVisitor final : public VNVisitorConst {
iterateChildrenConst(nodep);
if (!m_enableWriteSummary || !m_capturep) return;
// EOM
// 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).
if (m_taskp && !m_alwaysp && !m_inContAssign && !m_inInitialStatic && !m_inBBox) {
return;
}
AstNodeFTask* const calleep = nodep->taskp();
if (!calleep) return;

View File

@ -26,11 +26,13 @@ VL_DEFINE_DEBUG_FUNCTIONS;
namespace {
constexpr int DBG = 9;
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();
@ -105,7 +107,7 @@ private:
} // namespace
bool V3UndrivenCapture::enableWriteSummary = false;
bool V3UndrivenCapture::enableWriteSummary = true;
// static
void V3UndrivenCapture::sortUniqueVars(std::vector<Var>& vec) {

View File

@ -0,0 +1,11 @@
%Warning-MULTIDRIVEN: t/t_lint_taskcall_multidriven_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_taskcall_multidriven_bad.v:28:15:
28 | if (sel2) out = 1'b1;
| ^~~
t/t_lint_taskcall_multidriven_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,63 @@
// 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
module mod #()(
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
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,64 @@
// 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
module mod #()(
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
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