diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index 4d43665ec..31f21e5b2 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -251,10 +251,11 @@ class DelayedVisitor final : public VNVisitor { const AstNodeDType* const dtypep = vscp->dtypep()->skipRefp(); // Unpacked arrays if (const AstUnpackArrayDType* const uaDTypep = VN_CAST(dtypep, UnpackArrayDType)) { + // Basic underlying type of elements, if any. + AstBasicDType* const basicp = uaDTypep->basicp(); // If used in a loop, we must have a dynamic commit queue. (Also works in suspendables) if (vscpInfo.m_inLoop) { // Arrays with compound element types are currently not supported in loops - AstBasicDType* const basicp = uaDTypep->basicp(); if (!basicp || !(basicp->isIntegralOrPacked() // || basicp->isDouble() // @@ -266,8 +267,12 @@ class DelayedVisitor final : public VNVisitor { } // In a suspendable of fork, we must use the unique flag scheme, TODO: why? if (vscpInfo.m_inSuspOrFork) return Scheme::FlagUnique; - // Otherwise use the shared flag scheme - return Scheme::FlagShared; + // Otherwise if an array of packed/basic elements, use the shared flag scheme + if (basicp) return Scheme::FlagShared; + // Finally fall back on the shadow variable scheme, e.g. for + // arrays of unpacked structs. This will be slow. + // TODO: generic LHS scheme as discussed in #5092 + return Scheme::ShadowVar; } // In a suspendable of fork, we must use the unique flag scheme, TODO: why? diff --git a/test_regress/t/t_nba_struct_array.py b/test_regress/t/t_nba_struct_array.py new file mode 100755 index 000000000..f64ff6ad9 --- /dev/null +++ b/test_regress/t/t_nba_struct_array.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() + +test.execute(check_finished=True) + +test.passes() diff --git a/test_regress/t/t_nba_struct_array.v b/test_regress/t/t_nba_struct_array.v new file mode 100644 index 000000000..6233c3cf1 --- /dev/null +++ b/test_regress/t/t_nba_struct_array.v @@ -0,0 +1,93 @@ + +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0) + +module t(clk); + input clk; + + logic [31:0] cyc = 0; + always @(posedge clk) begin + cyc <= cyc + 1; + if (cyc == 99) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +`define at_posedge_clk_on_cycle(n) always @(posedge clk) if (cyc == n) + + struct { + int foo; + int bar; + } arr [2]; + + initial begin + arr[0].foo = 0; + arr[0].bar = 100; + arr[1].foo = 0; + arr[1].bar = 100; + end + + `at_posedge_clk_on_cycle(0) begin + for (int i = 0; i < 2; ++i) begin + `checkh(arr[i].foo, 0); + `checkh(arr[i].bar, 100); + end + end + `at_posedge_clk_on_cycle(1) begin + for (int i = 0; i < 2; ++i) begin + `checkh(arr[i].foo, 0); + `checkh(arr[i].bar, 100); + end + arr[0].foo <= 0; + arr[0].bar <= -0; + arr[1].foo <= 1; + arr[1].bar <= -1; + for (int i = 0; i < 2; ++i) begin + `checkh(arr[i].foo, 0); + `checkh(arr[i].bar, 100); + end + end + `at_posedge_clk_on_cycle(2) begin + for (int i = 0; i < 2; ++i) begin + `checkh(arr[i].foo, i); + `checkh(arr[i].bar, -i); + end + arr[0].foo <= ~0; + arr[0].bar <= 0; + arr[1].foo <= ~1; + arr[1].bar <= 1; + for (int i = 0; i < 2; ++i) begin + `checkh(arr[i].foo, i); + `checkh(arr[i].bar, -i); + end + end + `at_posedge_clk_on_cycle(3) begin + for (int i = 0; i < 2; ++i) begin + `checkh(arr[i].foo, ~i); + `checkh(arr[i].bar, i); + end + arr[0].foo <= -1; + arr[0].bar <= -2; + arr[1].foo <= -1; + arr[1].bar <= -2; + for (int i = 0; i < 2; ++i) begin + `checkh(arr[i].foo, ~i); + `checkh(arr[i].bar, i); + end + end + `at_posedge_clk_on_cycle(4) begin + for (int i = 0; i < 2; ++i) begin + `checkh(arr[i].foo, -1); + `checkh(arr[i].bar, -2); + end + end + + +endmodule