diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 41ab822e9..4469d7187 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -1390,15 +1390,6 @@ class RandomizeVisitor final : public VNVisitor { return new AstVar{fl, VVarType::VAR, uniqueNamep->get(""), dtypep->findBasicDType(VBasicDTypeKwd::UINT32)}; }; - auto handleUnsupportedStruct = [&](AstNodeExpr* tempElementp) { - if (VN_IS(tempElementp->dtypep()->skipRefp(), StructDType)) { - tempElementp->dtypep()->v3warn( - E_UNSUPPORTED, - "Unsupported: CreateArrayForeachLoop currently does not support " - "this data type. (Struct-Array unconstrained " - "randomization is not fully supported)"); - } - }; auto createForeachLoop = [&](AstNodeExpr* tempElementp, AstVar* randLoopIndxp) { AstSelLoopVars* const randLoopVarp = new AstSelLoopVars{fl, exprp->cloneTree(false), randLoopIndxp}; @@ -1422,7 +1413,6 @@ class RandomizeVisitor final : public VNVisitor { tempElementp->dtypep(tempDTypep->subDTypep()); tempDTypep = tempDTypep->virtRefDTypep(); } - handleUnsupportedStruct(tempElementp); stmtsp = createForeachLoop(tempElementp, randLoopIndxp); return stmtsp; } diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp index 44fdce79f..13107c8a4 100644 --- a/src/V3Unknown.cpp +++ b/src/V3Unknown.cpp @@ -119,6 +119,28 @@ class UnknownVisitor final : public VNVisitor { = new AstVar{fl, VVarType::MODULETEMP, m_lvboundNames.get(prep), prep->dtypep()}; m_modp->addStmtsp(varp); AstNode* const abovep = prep->backp(); // Grab above point before we replace 'prep' + AstNode* currentStmtp = abovep; + while (currentStmtp && !VN_IS(currentStmtp, NodeStmt)) + currentStmtp = currentStmtp->backp(); + VNRelinker linkContext; + currentStmtp = currentStmtp->unlinkFrBackWithNext(&linkContext); + AstNodeExpr* const selExprp = prep->cloneTree(true); + AstNodeExpr* currentExprp = selExprp; + while (AstNodeExpr* itrSelExprp = VN_AS(currentExprp->op1p(), NodeExpr)) { + if (AstVarRef* const selRefp = VN_CAST(itrSelExprp, VarRef)) { + // Mark the variable reference as READ access to avoid assignment issues + selRefp->access(VAccess::READ); + break; + } + currentExprp = itrSelExprp; + } + // Before assigning the value to the temporary variable, first assign the current array + // element to it. This ensures any field modifications happen on the correct instance + // and prevents overwriting other fields. + AstNode* const newAssignp + = new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, selExprp}; + newAssignp->addNextStmt(currentStmtp, newAssignp); + linkContext.relink(newAssignp); prep->replaceWith(new AstVarRef{fl, varp, VAccess::WRITE}); if (m_timingControlp) m_timingControlp->unlinkFrBack(); AstIf* const newp = new AstIf{ diff --git a/test_regress/t/t_randomize_array.v b/test_regress/t/t_randomize_array.v index ac2f3015f..2155ac67a 100755 --- a/test_regress/t/t_randomize_array.v +++ b/test_regress/t/t_randomize_array.v @@ -106,6 +106,37 @@ class unconstrained_struct_with_array_test; endclass +class unconstrained_struct_array_test; + + typedef struct { + rand int field_a; + rand int field_b; + } simple_struct_t; + rand simple_struct_t struct_array_1[3]; // Unpacked array + rand simple_struct_t struct_array_2[][]; // Dynamic array + + function new(); + struct_array_1 = '{'{default: 0}, '{default: 1}, '{default: 2}}; + + struct_array_2 = new[3]; + foreach (struct_array_2[i]) begin + struct_array_2[i] = new[4]; + end + endfunction + + function void check_randomization(); + foreach (struct_array_1[i]) begin + `check_rand(this, struct_array_1[i].field_a) + `check_rand(this, struct_array_1[i].field_b) + end + foreach (struct_array_2[i, j]) begin + `check_rand(this, struct_array_2[i][j].field_a) + `check_rand(this, struct_array_2[i][j].field_b) + end + endfunction + +endclass + class unconstrained_associative_array_test; rand int associative_array_1d[string]; @@ -172,6 +203,7 @@ module t_randomize_array; unconstrained_unpacked_array_test unpacked_class; unconstrained_dynamic_array_test dynamic_class; unconstrained_struct_with_array_test struct_with_array_class; + unconstrained_struct_array_test struct_array_class; unconstrained_associative_array_test associative_array_class; unconstrained_queue_test queue_class; @@ -200,6 +232,11 @@ module t_randomize_array; struct_with_array_class.check_randomization(); end + struct_array_class = new(); + repeat(2) begin + struct_array_class.check_randomization(); + end + // Test 5: Associative Array Unconstrained Test associative_array_class = new(); repeat(2) begin diff --git a/test_regress/t/t_randomize_array_unsup.v b/test_regress/t/t_randomize_array_unsup.v deleted file mode 100644 index bd140cf81..000000000 --- a/test_regress/t/t_randomize_array_unsup.v +++ /dev/null @@ -1,72 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2024 by PlanV GmbH. -// SPDX-License-Identifier: CC0-1.0 - -`define check_rand(cl, field) \ -begin \ - longint prev_result; \ - int ok = 0; \ - for (int i = 0; i < 10; i++) begin \ - longint result; \ - void'(cl.randomize()); \ - result = longint'(field); \ - if (i > 0 && result != prev_result) ok = 1; \ - prev_result = result; \ - end \ - if (ok != 1) $stop; \ -end - -class unconstrained_struct_array_test; - - typedef struct { - rand int field_a; - rand int field_b; - } simple_struct_t; - - rand simple_struct_t struct_array_2[]; // Dynamic array - rand simple_struct_t struct_array_1[3]; // Unpacked array - - - function new(); - struct_array_1 = '{'{default: 0}, '{default: 1}, '{default: 2}}; - - struct_array_2 = new[3]; - foreach (struct_array_2[i]) begin - struct_array_2[i].field_a = i; - struct_array_2[i].field_b = i + 1; - end - endfunction - - function void check_randomization(); - foreach (struct_array_1[i]) begin - `check_rand(this, struct_array_1[i].field_a) - `check_rand(this, struct_array_1[i].field_b) - end - - foreach (struct_array_2[i]) begin - `check_rand(this, struct_array_2[i].field_a) - `check_rand(this, struct_array_2[i].field_b) - end - endfunction - -endclass - -module t_randomize_array_unsup; - - unconstrained_struct_array_test struct_array_class; - - initial begin - - // Test: Struct Array Unconstrained Constrained Test - struct_array_class = new(); - repeat(2) begin - struct_array_class.check_randomization(); - end - - $write("*-* All Finished *-*\n"); - $finish; - end - -endmodule diff --git a/test_regress/t/t_randomize_array_unsup.py b/test_regress/t/t_struct_array_assignment.py similarity index 86% rename from test_regress/t/t_randomize_array_unsup.py rename to test_regress/t/t_struct_array_assignment.py index 710a094ab..d4f986441 100755 --- a/test_regress/t/t_randomize_array_unsup.py +++ b/test_regress/t/t_struct_array_assignment.py @@ -11,6 +11,8 @@ import vltest_bootstrap test.scenarios('simulator') -test.compile(fails=test.vlt_all, expect_filename=test.golden_filename) +test.compile() + +test.execute() test.passes() diff --git a/test_regress/t/t_struct_array_assignment.v b/test_regress/t/t_struct_array_assignment.v new file mode 100755 index 000000000..60e5d1532 --- /dev/null +++ b/test_regress/t/t_struct_array_assignment.v @@ -0,0 +1,52 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by PlanV GmbH. +// SPDX-License-Identifier: CC0-1.0 + +class unconstrained_struct_array_test; + + typedef struct { + int field_a; + int field_b; + int field_c; + } simple_struct_t; + + simple_struct_t struct_array[3]; // Unpacked array + + function new(); + // Initialize struct_array + struct_array = '{'{default: 0}, '{default: 1}, '{default: 2}}; + endfunction + + // Self-check function to validate the array contents + function void self_test(); + foreach (struct_array[i]) begin + if (struct_array[i].field_a != i) $stop; + if (struct_array[i].field_b != i + 1) $stop; + if (struct_array[i].field_c != i + 2) $stop; + end + endfunction + +endclass + +module t_struct_array_assignment; + unconstrained_struct_array_test cl; + + initial begin + + cl = new(); + + foreach(cl.struct_array[i]) begin + cl.struct_array[i].field_a = i; + cl.struct_array[i].field_b = i + 1; + cl.struct_array[i].field_c = i + 2; + end + + cl.self_test(); + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule