Fix automatic task variables in unrolled loops with forks (#6194) (#6201).

This commit is contained in:
Danny Oler 2025-07-21 16:28:50 -07:00 committed by GitHub
parent 7401a8a43a
commit 74d4b0c0ea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 158 additions and 0 deletions

View File

@ -37,6 +37,7 @@ Chuxuan Wang
Chykon
Conor McCullough
Dan Petrisko
Danny Oler
Daniel Bates
Dave Sargeant
David Horton

View File

@ -46,6 +46,7 @@ class UnrollVisitor final : public VNVisitor {
bool m_varModeCheck; // Just checking RHS assignments
bool m_varModeReplace; // Replacing varrefs
bool m_varAssignHit; // Assign var hit
bool m_forkHit; // Fork hit
bool m_generate; // Expand single generate For loop
string m_beginName; // What name to give begin iterations
VDouble0 m_statLoops; // Statistic tracking
@ -133,6 +134,7 @@ class UnrollVisitor final : public VNVisitor {
// Now, make sure there's no assignment to this variable in the loop
m_varModeCheck = true;
m_varAssignHit = false;
m_forkHit = false;
m_ignoreIncp = incp;
iterateAndNextNull(precondsp);
iterateAndNextNull(bodysp);
@ -141,6 +143,8 @@ class UnrollVisitor final : public VNVisitor {
m_ignoreIncp = nullptr;
if (m_varAssignHit) return cantUnroll(nodep, "genvar assigned *inside* loop");
if (m_forkHit) return cantUnroll(nodep, "fork inside loop");
//
if (m_forVscp) {
UINFO(8, " Loop Variable: " << m_forVscp);
@ -463,6 +467,17 @@ class UnrollVisitor final : public VNVisitor {
}
}
void visit(AstFork* nodep) override {
if (m_varModeCheck) {
if (nodep->joinType().joinNone() || nodep->joinType().joinAny()) {
// Forks are not allowed to unroll for loops, so we just set a flag
m_forkHit = true;
}
} else {
iterateChildren(nodep);
}
}
//--------------------
// Default: Just iterate
void visit(AstNode* nodep) override {
@ -489,6 +504,7 @@ public:
m_varModeCheck = false;
m_varModeReplace = false;
m_varAssignHit = false;
m_forkHit = false;
m_generate = generate;
m_beginName = beginName;
}

View File

@ -0,0 +1,41 @@
task_example start: module 0, channel 0
task_example end: module 0, channel 0
task_example start: module 0, channel 1
task_example end: module 0, channel 1
task_example start: module 1, channel 0
task_example end: module 1, channel 0
task_example start: module 1, channel 1
task_example end: module 1, channel 1
*-* Test 1 Finished *-*
task_example start: module 0, channel 0
task_example end: module 0, channel 0
task_example start: module 0, channel 1
task_example end: module 0, channel 1
task_example start: module 1, channel 0
task_example end: module 1, channel 0
task_example start: module 1, channel 1
task_example end: module 1, channel 1
*-* Test 2 Finished *-*
task_example start: module 0, channel 0
extra statement
task_example start: module 0, channel 1
extra statement
task_example start: module 1, channel 0
extra statement
task_example start: module 1, channel 1
extra statement
task_example end: module 0, channel 0
task_example end: module 0, channel 1
task_example end: module 1, channel 0
task_example end: module 1, channel 1
*-* Test 3 Finished *-*
task_example start: module 0, channel 0
task_example start: module 0, channel 1
task_example start: module 1, channel 0
task_example start: module 1, channel 1
task_example end: module 0, channel 0
task_example end: module 0, channel 1
task_example end: module 1, channel 0
task_example end: module 1, channel 1
*-* Test 4 Finished *-*
*-* All Finished *-*

View File

@ -0,0 +1,18 @@
#!/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('simulator')
test.compile(verilator_flags2=['--binary'])
test.execute(expect_filename=test.golden_filename)
test.passes()

View File

@ -0,0 +1,82 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
// Targets issue 6194
module t;
logic clk;
initial begin
clk = 0;
forever #(1) clk = ~clk;
end
task automatic task_example(int module_id, int channel);
$display("task_example start: module %0d, channel %0d", module_id, channel);
@(posedge clk);
$display("task_example end: module %0d, channel %0d", module_id, channel);
endtask
initial begin : initial_block
for (int m = 0; m < 2; m++) begin
for (int i = 0; i < 2; i++) begin : forked_loop
automatic int mod = m;
automatic int ch = i;
fork : forked_block
task_example(mod, ch);
join
end
end
#10
$write("*-* Test 1 Finished *-*\n");
for (int m = 0; m < 2; m++) begin
for (int i = 0; i < 2; i++) begin : forked_loop
automatic int mod = m;
automatic int ch = i;
fork : forked_block
task_example(mod, ch);
join_any
end
end
#10
$write("*-* Test 2 Finished *-*\n");
for (int m = 0; m < 2; m++) begin
for (int i = 0; i < 2; i++) begin : forked_loop
automatic int mod = m;
automatic int ch = i;
fork : forked_block
task_example(mod, ch);
$display("extra statement");
join_any
end
end
#10
$write("*-* Test 3 Finished *-*\n");
for (int m = 0; m < 2; m++) begin
for (int i = 0; i < 2; i++) begin : forked_loop
automatic int mod = m;
automatic int ch = i;
fork : forked_block
task_example(mod, ch);
join_none
end
end
#10
$write("*-* Test 4 Finished *-*\n");
$write("*-* All Finished *-*\n");
$finish;
end
endmodule