Fix timing control under fork under function (#6407)
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
This commit is contained in:
parent
b45cf5960a
commit
0743d84bcc
|
|
@ -286,6 +286,7 @@ class DynScopeVisitor final : public VNVisitor {
|
|||
const VNUser2InUse m_inuser2;
|
||||
|
||||
// STATE
|
||||
bool m_inFunc = false; // True if in a function
|
||||
AstNodeModule* m_modp = nullptr; // Module we are currently under
|
||||
AstNode* m_procp = nullptr; // Function/task/block we are currently under
|
||||
std::deque<AstNode*> m_frameOrder; // Ordered list of frames (for determinism)
|
||||
|
|
@ -367,6 +368,8 @@ class DynScopeVisitor final : public VNVisitor {
|
|||
void visit(AstNodeFTask* nodep) override {
|
||||
VL_RESTORER(m_procp);
|
||||
m_procp = nodep;
|
||||
VL_RESTORER(m_inFunc);
|
||||
m_inFunc = VN_IS(nodep, Func);
|
||||
if (hasAsyncFork(nodep)) pushDynScopeFrame(m_procp);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
@ -433,12 +436,20 @@ 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
|
||||
nodep->v3warn(
|
||||
E_UNSUPPORTED,
|
||||
"Unsupported: Writing to a captured "
|
||||
<< (nodep->varp()->isInout() ? "inout" : "output") << " variable in a "
|
||||
<< (VN_IS(nodep->backp(), AssignDly) ? "non-blocking assignment" : "fork")
|
||||
<< " after a timing control");
|
||||
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");
|
||||
}
|
||||
}
|
||||
if (!framep->instance().initialized()) framep->createInstancePrototype();
|
||||
framep->captureVarInsert(nodep->varp());
|
||||
|
|
|
|||
|
|
@ -211,6 +211,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
VMemberMap m_memberMap; // Member names cached for fast lookup
|
||||
V3TaskConnectState m_taskConnectState; // State to cache V3Task::taskConnects
|
||||
WidthVP* m_vup = nullptr; // Current node state
|
||||
bool m_underFork = false; // Visiting under a fork
|
||||
const AstCell* m_cellp = nullptr; // Current cell for arrayed instantiations
|
||||
const AstEnumItem* m_enumItemp = nullptr; // Current enum item
|
||||
const AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
||||
|
|
@ -704,7 +705,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
return;
|
||||
}
|
||||
if (VN_IS(m_ftaskp, Func)) {
|
||||
if (!m_underFork && VN_IS(m_ftaskp, Func)) {
|
||||
nodep->v3error("Delays are not legal in functions. Suggest use a task "
|
||||
"(IEEE 1800-2023 13.4.4)");
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
|
|
@ -727,7 +728,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
}
|
||||
void visit(AstFork* nodep) override {
|
||||
if (VN_IS(m_ftaskp, Func) && !nodep->joinType().joinNone()) {
|
||||
if (!m_underFork && VN_IS(m_ftaskp, Func) && !nodep->joinType().joinNone()) {
|
||||
nodep->v3error("Only fork .. join_none is legal in functions. "
|
||||
"(IEEE 1800-2023 13.4.4)");
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
|
|
@ -747,6 +748,8 @@ class WidthVisitor final : public VNVisitor {
|
|||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
} else if (v3Global.opt.timing().isSetTrue()) {
|
||||
VL_RESTORER(m_underFork);
|
||||
m_underFork = true;
|
||||
iterateChildren(nodep);
|
||||
} else if (v3Global.opt.timing().isSetFalse()) {
|
||||
nodep->v3warn(E_NOTIMING, "Fork statements require --timing");
|
||||
|
|
@ -1663,7 +1666,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
void visit(AstEventControl* nodep) override {
|
||||
if (VN_IS(m_ftaskp, Func)) {
|
||||
if (!m_underFork && VN_IS(m_ftaskp, Func)) {
|
||||
nodep->v3error("Event controls are not legal in functions. Suggest use a task "
|
||||
"(IEEE 1800-2023 13.4.4)");
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
|
|
@ -5466,7 +5469,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
}
|
||||
if (VN_IS(nodep, AssignForce)) checkForceReleaseLhs(nodep, nodep->lhsp());
|
||||
if (AstNode* const controlp = nodep->timingControlp()) {
|
||||
if (VN_IS(m_ftaskp, Func)) {
|
||||
if (!m_underFork && VN_IS(m_ftaskp, Func)) {
|
||||
controlp->v3error("Timing controls are not legal in functions. Suggest use a task "
|
||||
"(IEEE 1800-2023 13.4.4)");
|
||||
VL_DO_DANGLING(controlp->unlinkFrBackWithNext()->deleteTree(), controlp);
|
||||
|
|
@ -6631,7 +6634,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
userIterateChildren(nodep, WidthVP{SELF, PRELIM}.p());
|
||||
}
|
||||
void visit(AstWait* nodep) override {
|
||||
if (VN_IS(m_ftaskp, Func)) {
|
||||
if (!m_underFork && VN_IS(m_ftaskp, Func)) {
|
||||
nodep->v3error("Wait statements are not legal in functions. Suggest use a task "
|
||||
"(IEEE 1800-2023 13.4.4)");
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
#!/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 -Wno-UNOPTFLAT"])
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Antmicro.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t(/*AUTOARG*/);
|
||||
|
||||
function int f1;
|
||||
fork begin
|
||||
#1 $stop;
|
||||
end join_none
|
||||
f1 = 0;
|
||||
endfunction
|
||||
|
||||
function int f2;
|
||||
fork begin
|
||||
int x;
|
||||
x = #5 0; $stop;
|
||||
end join_none
|
||||
f2 = 0;
|
||||
endfunction
|
||||
|
||||
event e;
|
||||
function int f3;
|
||||
fork begin
|
||||
int x;
|
||||
@e $stop;
|
||||
x = 0;
|
||||
end join_none
|
||||
f3 = 0;
|
||||
endfunction
|
||||
|
||||
function int f4;
|
||||
fork begin
|
||||
int x;
|
||||
x = @e 0; $stop;
|
||||
end join_none
|
||||
f4 = 0;
|
||||
endfunction
|
||||
|
||||
int i;
|
||||
|
||||
function int f5;
|
||||
fork begin
|
||||
int x;
|
||||
wait(i == 0) $stop;
|
||||
x = 0;
|
||||
end join_none
|
||||
f5 = 0;
|
||||
endfunction
|
||||
|
||||
initial begin
|
||||
fork begin
|
||||
i = f1();
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end join_none
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
%Error: t/t_timing_func_fork_bad.v:12:7: Writing to an output variable of a function after a timing control is not allowed
|
||||
: ... note: In instance 't'
|
||||
12 | 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:13:7: Writing to an output variable of a function after a timing control is not allowed
|
||||
: ... note: In instance 't'
|
||||
13 | o1 = 0;
|
||||
| ^~
|
||||
%Error: t/t_timing_func_fork_bad.v:19:7: Writing to an output variable of a function after a timing control is not allowed
|
||||
: ... note: In instance 't'
|
||||
19 | f2 = #5 0; $stop;
|
||||
| ^~
|
||||
%Error: t/t_timing_func_fork_bad.v:20:7: Writing to an inout variable of a function after a timing control is not allowed
|
||||
: ... note: In instance 't'
|
||||
20 | io2 = 0;
|
||||
| ^~~
|
||||
%Error: t/t_timing_func_fork_bad.v:28:7: Writing to an output variable of a function after a timing control is not allowed
|
||||
: ... note: In instance 't'
|
||||
28 | f3 = 0;
|
||||
| ^~
|
||||
%Error: t/t_timing_func_fork_bad.v:29:7: Writing to an output variable of a function after a timing control is not allowed
|
||||
: ... note: In instance 't'
|
||||
29 | o3 = 0;
|
||||
| ^~
|
||||
%Error: t/t_timing_func_fork_bad.v:35:7: Writing to an output variable of a function after a timing control is not allowed
|
||||
: ... note: In instance 't'
|
||||
35 | f4 = @e 0; $stop;
|
||||
| ^~
|
||||
%Error: t/t_timing_func_fork_bad.v:36:7: Writing to an inout variable of a function after a timing control is not allowed
|
||||
: ... note: In instance 't'
|
||||
36 | io4 = 0;
|
||||
| ^~~
|
||||
%Error: t/t_timing_func_fork_bad.v:45:7: Writing to an output variable of a function after a timing control is not allowed
|
||||
: ... note: In instance 't'
|
||||
45 | f5 = 0;
|
||||
| ^~
|
||||
%Error: t/t_timing_func_fork_bad.v:46:7: Writing to an output variable of a function after a timing control is not allowed
|
||||
: ... note: In instance 't'
|
||||
46 | o5 = 0;
|
||||
| ^~
|
||||
%Error: Exiting due to
|
||||
|
|
@ -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(fails=True,
|
||||
verilator_flags2=["--binary -Wno-UNOPTFLAT"],
|
||||
expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Antmicro.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t(/*AUTOARG*/);
|
||||
|
||||
function int f1(output int o1);
|
||||
fork begin
|
||||
#1 $stop;
|
||||
f1 = 0;
|
||||
o1 = 0;
|
||||
end join_none
|
||||
endfunction
|
||||
|
||||
function int f2(inout io2);
|
||||
fork begin
|
||||
f2 = #5 0; $stop;
|
||||
io2 = 0;
|
||||
end join_none
|
||||
endfunction
|
||||
|
||||
event e;
|
||||
function int f3(output int o3);
|
||||
fork begin
|
||||
@e $stop;
|
||||
f3 = 0;
|
||||
o3 = 0;
|
||||
end join_none
|
||||
endfunction
|
||||
|
||||
function int f4(inout int io4);
|
||||
fork begin
|
||||
f4 = @e 0; $stop;
|
||||
io4 = 0;
|
||||
end join_none
|
||||
endfunction
|
||||
|
||||
int i;
|
||||
|
||||
function int f5(output int o5);
|
||||
fork begin
|
||||
wait(i == 0) $stop;
|
||||
f5 = 0;
|
||||
o5 = 0;
|
||||
end join_none
|
||||
endfunction
|
||||
|
||||
endmodule
|
||||
Loading…
Reference in New Issue