Fix struct array assignment (#5455) (#5537)

This commit is contained in:
Yilou Wang 2024-10-21 15:54:33 +02:00 committed by GitHub
parent 76fe224e7c
commit 8c3cc3af8f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 114 additions and 83 deletions

View File

@ -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;
}

View File

@ -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{

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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