This commit is contained in:
Kamil Danecki 2026-04-03 11:42:07 +02:00 committed by GitHub
commit 718c19b660
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 245 additions and 72 deletions

View File

@ -298,12 +298,39 @@ class BeginVisitor final : public VNVisitor {
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
void visit(AstVar* nodep) override {
if (nodep->user1SetOnce()) { return; }
// If static variable, move it outside a function.
if (nodep->lifetime().isStatic() && m_ftaskp) {
const std::string newName
= m_ftaskp->name() + "__Vstatic__" + dot(m_unnamedScope, nodep->name());
if (nodep->isIO()) {
if (nodep->direction().isRef()) {
nodep->v3error(
"It is illegal to use argument passing by reference for subroutines with "
"a lifetime of static (IEEE 1800-2023 13.5.2)");
}
// Create a port that is used for passing value between argument and static
// variable
AstVar* const portp = nodep->cloneTreePure(false);
nodep->replaceWith(portp);
if (nodep->isInput() || nodep->isInout()) {
AstAssign* const initAssignp = new AstAssign{
nodep->fileline(), new AstVarRef{nodep->fileline(), nodep, VAccess::WRITE},
new AstVarRef{portp->fileline(), portp, VAccess::READ}};
portp->addNextHere(initAssignp);
}
if (nodep->isWritable()) {
AstAssign* const endAssignp = new AstAssign{
nodep->fileline(), new AstVarRef{portp->fileline(), portp, VAccess::WRITE},
new AstVarRef{nodep->fileline(), nodep, VAccess::READ}};
m_ftaskp->addStmtsp(endAssignp);
}
} else {
nodep->unlinkFrBack();
}
nodep->name(newName);
nodep->unlinkFrBack();
m_ftaskp->addHereThisAsNext(nodep);
nodep->funcLocal(false);
} else if (m_unnamedScope != "") {

View File

@ -443,20 +443,11 @@ class DynScopeVisitor final : public VNVisitor {
if (!isEvent && m_afterTimingControl && nodep->varp()->isWritable()
&& nodep->access().isWriteOrRW()) {
// The output variable may not exist after a delay, so we can't just write to it
if (m_inFunc) {
nodep->v3error(
"Writing to an "
<< nodep->varp()->verilogKwd()
<< " variable of a function after a timing control is not allowed");
} else {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Writing to a captured "
<< nodep->varp()->verilogKwd()
<< " variable in a "
<< (VN_IS(nodep->backp(), AssignDly)
? "non-blocking assignment"
: "fork")
<< " after a timing control");
}
nodep->v3error(
"Writing to an "
<< nodep->varp()->verilogKwd() << " automatic variable of a "
<< (m_inFunc ? "function" : "task")
<< " after a timing control is not allowed (IEEE 1800-2023 13.2.2)");
}
if (!framep->instance().initialized()) framep->createInstancePrototype();
framep->captureVarInsert(nodep->varp());

View File

@ -69,6 +69,7 @@ class LinkParseVisitor final : public VNVisitor {
int m_randSequenceNum = 0; // RandSequence uniqify number
VLifetime m_lifetime = VLifetime::STATIC_IMPLICIT; // Propagating lifetime
bool m_lifetimeAllowed = false; // True to allow lifetime settings
bool m_hasTimingControl = false; // If current task has timing control
bool m_moduleWithGenericIface = false; // If current module contains generic interface
std::set<AstVar*> m_portDups; // Non-ANSI port datatype duplicating input/output decls
@ -248,6 +249,9 @@ class LinkParseVisitor final : public VNVisitor {
VL_RESTORER(m_lifetime);
VL_RESTORER(m_lifetimeAllowed);
m_lifetimeAllowed = true;
VL_RESTORER(m_hasTimingControl);
m_hasTimingControl
= nodep->exists([](const AstNode* const nodep) { return nodep->isTimingControl(); });
if (!nodep->lifetime().isNone()) {
m_lifetime = nodep->lifetime().makeImplicit();
} else {
@ -382,7 +386,15 @@ class LinkParseVisitor final : public VNVisitor {
}
}
} else if (m_ftaskp) {
if (!nodep->lifetime().isAutomatic()) nodep->lifetime(VLifetime::AUTOMATIC_IMPLICIT);
// Variables in static tasks with timing control can be used after the task has ended
// with use of join..fork_none, so they need to be static
if (m_ftaskp->lifetime().isStatic() && m_hasTimingControl) {
nodep->v3warn(IMPLICITSTATIC, "Variable's lifetime implicitly set to static "
"because in static task with timing control.");
nodep->lifetime(VLifetime::STATIC_IMPLICIT);
} else {
nodep->lifetime(VLifetime::AUTOMATIC_IMPLICIT);
}
} else if (nodep->lifetime().isNone()) {
// lifetime shouldn't be unknown, set static if none
nodep->lifetime(VLifetime::STATIC_IMPLICIT);

View File

@ -11,7 +11,7 @@ import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=['--binary'])
test.compile(verilator_flags2=['--binary', '-Wno-IMPLICITSTATIC'])
test.execute()

View File

@ -11,7 +11,7 @@ import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=['--binary --trace-fst'])
test.compile(verilator_flags2=['--binary --trace-fst', '-Wno-IMPLICITSTATIC'])
test.execute()

View File

@ -11,7 +11,7 @@ import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=["--binary -Wno-INITIALDLY"])
test.compile(verilator_flags2=["--binary -Wno-INITIALDLY", '-Wno-IMPLICITSTATIC'])
test.execute()

View File

@ -1,10 +0,0 @@
%Error-UNSUPPORTED: t/t_fork_dynscope_unsup.v:17:7: Unsupported: Writing to a captured inout variable in a fork after a timing control
: ... note: In instance 't'
17 | p = #1 1;
| ^
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error-UNSUPPORTED: t/t_fork_dynscope_unsup.v:22:5: Unsupported: Writing to a captured output variable in a non-blocking assignment after a timing control
: ... note: In instance 't'
22 | q <= #1 1;
| ^
%Error: Exiting due to

View File

@ -11,7 +11,7 @@ import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=["--binary"])
test.compile(verilator_flags2=["--binary", '-Wno-IMPLICITSTATIC'])
test.execute()

View File

@ -11,6 +11,8 @@ import vltest_bootstrap
test.scenarios('simulator')
test.lint(fails=True, expect_filename=test.golden_filename)
test.compile(verilator_flags2=["--binary", "-Wno-IMPLICITSTATIC"])
test.execute()
test.passes()

View File

@ -0,0 +1,118 @@
// 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
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
// verilog_format: on
module t;
int x1, x2, x3, x4, x5, x6, x7;
initial begin
x1 = -1;
x2 = -1;
x3 = -1;
x4 = -1;
#1;
t1(x1);
t2(x2);
t3(x3);
t4(x4);
`checkd(x1, 0)
`checkd(x2, -1)
`checkd(x3, 1)
`checkd(x4, 2)
#10 t1(x1);
t2(x2);
t3(x3);
t4(x4);
`checkd(x1, 1)
`checkd(x2, -1)
`checkd(x3, 1)
`checkd(x4, 2)
`checkd(x5, 3)
`checkd(x6, 0)
`checkd(x7, 4)
#5;
`checkd(x1, 1)
`checkd(x2, -1)
`checkd(x3, 1)
`checkd(x4, 2)
`checkd(x5, 3)
`checkd(x6, 0)
`checkd(x7, 4)
$write("*-* All Finished *-*\n");
$finish;
end
always #1 t5(x5);
always #1 t6(x6);
always #1 t7(x7);
task t1(output int x);
fork
x = #1 1;
join_none
if ($time < 10) begin
`checkd(x, 0)
end
else begin
`checkd(x, 1)
end
endtask
task t2(inout int x);
fork
x = #1 2;
join_none
`checkd(x, -1)
endtask
task t3(output int x);
if ($time < 10) begin
`checkd(x, 0)
end
else begin
`checkd(x, 1)
end
fork
x = #1 1;
join_none
#2 `checkd(x, 1);
endtask
task t4(inout int x);
if ($time < 10) begin
`checkd(x, -1)
end
else begin
`checkd(x, 2)
end
fork
x = #1 2;
join_none
#2 `checkd(x, 2);
endtask
task t5(output int x);
x <= #1 3;
endtask
task t6(inout int x);
x <= #1 4;
endtask
task static t7(inout int x);
int y = 0;
x <= #1 4;
#2 y = x;
`checkd(x, 4)
endtask
endmodule

View File

@ -0,0 +1,11 @@
%Warning-IMPLICITSTATIC: t/t_fork_write_after_timing_bad.v:12:19: Variable's lifetime implicitly set to static because in static task with timing control.
12 | task t1(ref int x);
| ^
... For warning description see https://verilator.org/warn/IMPLICITSTATIC?v=latest
... Use "/* verilator lint_off IMPLICITSTATIC */" and lint_on around source to disable this message.
%Error: t/t_fork_write_after_timing_bad.v:12:19: It is illegal to use argument passing by reference for subroutines with a lifetime of static (IEEE 1800-2023 13.5.2)
: ... note: In instance 't'
12 | task t1(ref int x);
| ^
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: Exiting due to

View File

@ -0,0 +1,16 @@
#!/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: 2024 Wilson Snyder
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('simulator')
test.lint(verilator_flags2=["--timing"], fails=True, expect_filename=test.golden_filename)
test.passes()

View File

@ -1,24 +1,17 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain
// SPDX-FileCopyrightText: 2024 Antmicro
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2026 Antmicro
// SPDX-License-Identifier: CC0-1.0
module t;
bit p = 0, q = 0;
int x1;
initial begin
t1(p);
t2(q);
t1(x1);
$finish;
end
task t1(inout p);
task t1(ref int x);
fork
p = #1 1;
x = #1 2;
join_none
endtask
task t2(output q);
q <= #1 1;
endtask
endmodule

View File

@ -1,42 +1,46 @@
%Error: t/t_timing_func_fork_bad.v:13:9: Writing to an output variable of a function after a timing control is not allowed
%Error: t/t_timing_func_fork_bad.v:13:9: Writing to an output automatic variable of a function after a timing control is not allowed (IEEE 1800-2023 13.2.2)
: ... note: In instance 't'
13 | f1 = 0;
| ^~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: t/t_timing_func_fork_bad.v:14:9: Writing to an output variable of a function after a timing control is not allowed
%Error: t/t_timing_func_fork_bad.v:14:9: Writing to an output automatic variable of a function after a timing control is not allowed (IEEE 1800-2023 13.2.2)
: ... note: In instance 't'
14 | o1 = 0;
| ^~
%Error: t/t_timing_func_fork_bad.v:22:9: Writing to an output variable of a function after a timing control is not allowed
%Error: t/t_timing_func_fork_bad.v:22:7: Writing to an output automatic variable of a task after a timing control is not allowed (IEEE 1800-2023 13.2.2)
: ... note: In instance 't'
22 | f2 = #5 0;
22 | o1 = 0;
| ^~
%Error: t/t_timing_func_fork_bad.v:29:9: Writing to an output automatic variable of a function after a timing control is not allowed (IEEE 1800-2023 13.2.2)
: ... note: In instance 't'
29 | f2 = #5 0;
| ^~
%Error: t/t_timing_func_fork_bad.v:24:9: Writing to an inout variable of a function after a timing control is not allowed
%Error: t/t_timing_func_fork_bad.v:31:9: Writing to an inout automatic variable of a function after a timing control is not allowed (IEEE 1800-2023 13.2.2)
: ... note: In instance 't'
24 | io2 = 0;
31 | io2 = 0;
| ^~~
%Error: t/t_timing_func_fork_bad.v:34:9: Writing to an output variable of a function after a timing control is not allowed
%Error: t/t_timing_func_fork_bad.v:41:9: Writing to an output automatic variable of a function after a timing control is not allowed (IEEE 1800-2023 13.2.2)
: ... note: In instance 't'
34 | f3 = 0;
41 | f3 = 0;
| ^~
%Error: t/t_timing_func_fork_bad.v:35:9: Writing to an output variable of a function after a timing control is not allowed
%Error: t/t_timing_func_fork_bad.v:42:9: Writing to an output automatic variable of a function after a timing control is not allowed (IEEE 1800-2023 13.2.2)
: ... note: In instance 't'
35 | o3 = 0;
42 | o3 = 0;
| ^~
%Error: t/t_timing_func_fork_bad.v:43:9: Writing to an output variable of a function after a timing control is not allowed
%Error: t/t_timing_func_fork_bad.v:50:9: Writing to an output automatic variable of a function after a timing control is not allowed (IEEE 1800-2023 13.2.2)
: ... note: In instance 't'
43 | f4 = @e 0;
50 | f4 = @e 0;
| ^~
%Error: t/t_timing_func_fork_bad.v:45:9: Writing to an inout variable of a function after a timing control is not allowed
%Error: t/t_timing_func_fork_bad.v:52:9: Writing to an inout automatic variable of a function after a timing control is not allowed (IEEE 1800-2023 13.2.2)
: ... note: In instance 't'
45 | io4 = 0;
52 | io4 = 0;
| ^~~
%Error: t/t_timing_func_fork_bad.v:56:9: Writing to an output variable of a function after a timing control is not allowed
%Error: t/t_timing_func_fork_bad.v:63:9: Writing to an output automatic variable of a function after a timing control is not allowed (IEEE 1800-2023 13.2.2)
: ... note: In instance 't'
56 | f5 = 0;
63 | f5 = 0;
| ^~
%Error: t/t_timing_func_fork_bad.v:57:9: Writing to an output variable of a function after a timing control is not allowed
%Error: t/t_timing_func_fork_bad.v:64:9: Writing to an output automatic variable of a function after a timing control is not allowed (IEEE 1800-2023 13.2.2)
: ... note: In instance 't'
57 | o5 = 0;
64 | o5 = 0;
| ^~
%Error: Exiting due to

View File

@ -6,7 +6,7 @@
module t;
function int f1(output int o1);
function automatic int f1(output int o1);
fork
begin
#1 $stop;
@ -16,7 +16,14 @@ module t;
join_none
endfunction
function int f2(inout io2);
task automatic t1(output int o1);
fork begin
#1 $stop;
o1 = 0;
end join_none
endtask
function automatic int f2(inout io2);
fork
begin
f2 = #5 0;
@ -27,7 +34,7 @@ module t;
endfunction
event e;
function int f3(output int o3);
function automatic int f3(output int o3);
fork
begin
@e $stop;
@ -37,7 +44,7 @@ module t;
join_none
endfunction
function int f4(inout int io4);
function automatic int f4(inout int io4);
fork
begin
f4 = @e 0;
@ -49,7 +56,7 @@ module t;
int i;
function int f5(output int o5);
function automatic int f5(output int o5);
fork
begin
wait (i == 0) $stop;

View File

@ -17,8 +17,8 @@ if re.search(r'clang', test.cxx_version):
test.skip("uvm_regex.cc from upstream has clang warnings")
test.compile(verilator_flags2=[
"--binary", test.build_jobs, "--vpi", "+define+T_V2017_1_0", "+incdir+t/uvm/v2017_1_0",
test.pli_filename
"--binary", "-Wno-IMPLICITSTATIC", test.build_jobs, "--vpi", "+define+T_V2017_1_0",
"+incdir+t/uvm/v2017_1_0", test.pli_filename
])
test.execute(expect_filename=test.golden_filename)

View File

@ -18,7 +18,7 @@ if re.search(r'clang', test.cxx_version):
test.compile(verilator_flags2=[
"--binary", test.build_jobs, "--vpi", "+define+T_V2020_3_1", "+incdir+t/uvm/v2020_3_1",
test.pli_filename
"-Wno-IMPLICITSTATIC", test.pli_filename
])
test.execute(expect_filename=test.golden_filename)

View File

@ -23,6 +23,7 @@ test.compile(v_flags2=[
"--vpi",
"--CFLAGS -O0",
"-Wall",
"-Wno-IMPLICITSTATIC",
"+incdir+t/uvm", #
"t/uvm/uvm_pkg_all_v2017_1_0_dpi.svh",
test.pli_filename

View File

@ -23,6 +23,7 @@ test.compile(v_flags2=[
"--vpi",
"--CFLAGS -O0",
"-Wall",
'-Wno-IMPLICITSTATIC',
"+incdir+t/uvm", #
"t/uvm/uvm_pkg_all_v2020_3_1_dpi.svh",
test.pli_filename

View File

@ -11,7 +11,7 @@ import vltest_bootstrap
test.scenarios('simulator')
test.compile(v_flags2=["--binary"], verilator_make_gmake=False)
test.compile(v_flags2=["--binary", '-Wno-IMPLICITSTATIC'], verilator_make_gmake=False)
test.execute()