diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index bbe5f8c56..553cfa711 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -37,6 +37,7 @@ Chuxuan Wang Chykon Conor McCullough Dan Petrisko +Danny Oler Daniel Bates Dave Sargeant David Horton diff --git a/src/V3Unroll.cpp b/src/V3Unroll.cpp index 67ed5f1d0..bac260f31 100644 --- a/src/V3Unroll.cpp +++ b/src/V3Unroll.cpp @@ -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; } diff --git a/test_regress/t/t_unroll_automatic_task_fork.out b/test_regress/t/t_unroll_automatic_task_fork.out new file mode 100644 index 000000000..456cdcfa0 --- /dev/null +++ b/test_regress/t/t_unroll_automatic_task_fork.out @@ -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 *-* diff --git a/test_regress/t/t_unroll_automatic_task_fork.py b/test_regress/t/t_unroll_automatic_task_fork.py new file mode 100755 index 000000000..d2498e873 --- /dev/null +++ b/test_regress/t/t_unroll_automatic_task_fork.py @@ -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() diff --git a/test_regress/t/t_unroll_automatic_task_fork.v b/test_regress/t/t_unroll_automatic_task_fork.v new file mode 100644 index 000000000..b77d25261 --- /dev/null +++ b/test_regress/t/t_unroll_automatic_task_fork.v @@ -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