Support packed/unpacked and dynamic array unconstrained randomization (#5414) (#5415)

This commit is contained in:
Yilou Wang 2024-09-20 02:07:05 +02:00 committed by GitHub
parent 175e1dde73
commit 70112438c3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 325 additions and 35 deletions

View File

@ -1344,11 +1344,54 @@ class RandomizeVisitor final : public VNVisitor {
UINFO(9, "created " << varp << endl);
return newp;
}
AstNodeStmt* createArrayForeachLoop(FileLine* const fl, AstNodeDType* const dtypep,
AstNodeExpr* exprp) {
V3UniqueNames* uniqueNamep = new V3UniqueNames{"__Vrandarr"};
AstNodeDType* tempDTypep = dtypep;
AstVar* randLoopIndxp = nullptr;
AstNodeStmt* stmtsp = nullptr;
auto createLoopIndex = [&](AstNodeDType* tempDTypep) {
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};
return new AstForeach{fl, randLoopVarp, newRandStmtsp(fl, tempElementp, nullptr)};
};
AstNodeExpr* tempElementp = nullptr;
while (VN_CAST(tempDTypep, DynArrayDType) || VN_CAST(tempDTypep, UnpackArrayDType)) {
AstVar* const newRandLoopIndxp = createLoopIndex(tempDTypep);
randLoopIndxp = AstNode::addNext(randLoopIndxp, newRandLoopIndxp);
tempElementp
= VN_CAST(tempDTypep, DynArrayDType)
? static_cast<AstNodeExpr*>(
new AstCMethodHard{fl, tempElementp ? tempElementp : exprp, "atWrite",
new AstVarRef{fl, newRandLoopIndxp, VAccess::READ}})
: static_cast<AstNodeExpr*>(
new AstArraySel{fl, tempElementp ? tempElementp : exprp,
new AstVarRef{fl, newRandLoopIndxp, VAccess::READ}});
tempElementp->dtypep(tempDTypep->subDTypep());
tempDTypep = tempDTypep->virtRefDTypep();
}
handleUnsupportedStruct(tempElementp);
stmtsp = createForeachLoop(tempElementp, randLoopIndxp);
return stmtsp;
}
AstNodeStmt* newRandStmtsp(FileLine* fl, AstNodeExpr* exprp, AstVar* randcVarp, int offset = 0,
AstMemberDType* memberp = nullptr) {
if (const auto* const structDtp
= VN_CAST(memberp ? memberp->subDTypep()->skipRefp() : exprp->dtypep()->skipRefp(),
StructDType)) {
AstNodeDType* const memberDtp
= memberp ? memberp->subDTypep()->skipRefp() : exprp->dtypep()->skipRefp();
if (const auto* const structDtp = VN_CAST(memberDtp, StructDType)) {
AstNodeStmt* stmtsp = nullptr;
if (structDtp->packed()) offset += memberp ? memberp->lsb() : 0;
for (AstMemberDType* smemberp = structDtp->membersp(); smemberp;
@ -1364,16 +1407,10 @@ class RandomizeVisitor final : public VNVisitor {
if (!structSelp->dtypep()) structSelp->dtypep(smemberp->subDTypep());
randp = newRandStmtsp(fl, structSelp, nullptr);
}
if (stmtsp) {
stmtsp->addNext(randp);
} else {
stmtsp = randp;
}
stmtsp = stmtsp ? stmtsp->addNext(randp) : randp;
}
return stmtsp;
} else if (const auto* const unionDtp = VN_CAST(memberp ? memberp->subDTypep()->skipRefp()
: exprp->dtypep()->skipRefp(),
UnionDType)) {
} else if (const auto* const unionDtp = VN_CAST(memberDtp, UnionDType)) {
if (!unionDtp->packed()) {
unionDtp->v3error("Unpacked unions shall not be declared as rand or randc."
" (IEEE 1800-2023 18.4)");
@ -1381,6 +1418,11 @@ class RandomizeVisitor final : public VNVisitor {
}
AstMemberDType* const firstMemberp = unionDtp->membersp();
return newRandStmtsp(fl, exprp, nullptr, offset, firstMemberp);
} else if (AstDynArrayDType* const dynarrayDtp = VN_CAST(memberDtp, DynArrayDType)) {
return createArrayForeachLoop(fl, dynarrayDtp, exprp);
} else if (AstUnpackArrayDType* const unpackarrayDtp
= VN_CAST(memberDtp, UnpackArrayDType)) {
return createArrayForeachLoop(fl, unpackarrayDtp, exprp);
} else {
AstNodeExpr* valp;
if (AstEnumDType* const enumDtp = VN_CAST(memberp ? memberp->subDTypep()->subDTypep()
@ -1561,11 +1603,12 @@ class RandomizeVisitor final : public VNVisitor {
if (memberVarp->user3()) return; // Handled in constraints
const AstNodeDType* const dtypep = memberVarp->dtypep()->skipRefp();
if (VN_IS(dtypep, BasicDType) || VN_IS(dtypep, StructDType)
|| VN_IS(dtypep, UnionDType)) {
|| VN_IS(dtypep, UnionDType) || VN_IS(dtypep, PackArrayDType)
|| VN_IS(dtypep, UnpackArrayDType) || VN_IS(dtypep, DynArrayDType)) {
AstVar* const randcVarp = newRandcVarsp(memberVarp);
AstVarRef* const refp = new AstVarRef{fl, classp, memberVarp, VAccess::WRITE};
AstNodeStmt* const stmtp = newRandStmtsp(fl, refp, randcVarp);
basicRandomizep->addStmtsp(stmtp);
basicRandomizep->addStmtsp(new AstBegin{fl, "", stmtp});
} else if (const AstClassRefDType* const classRefp = VN_CAST(dtypep, ClassRefDType)) {
if (classRefp->classp() == nodep) {
memberVarp->v3warn(E_UNSUPPORTED,

View File

@ -0,0 +1,21 @@
#!/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')
if not test.have_solver:
test.skip("No constraint solver installed")
test.compile()
test.execute()
test.passes()

View File

@ -0,0 +1,145 @@
// 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_packed_array_test;
rand bit [3:0] [2:0] [15:0] packed_array;
function new();
packed_array = '{default: '{default: '{default: 'h0}}};
endfunction
function void check_randomization();
`check_rand(this, this.packed_array)
endfunction
endclass
class unconstrained_unpacked_array_test;
rand bit [2:0] [15:0] unpacked_array [3][5];
function new();
unpacked_array = '{ '{default: '{default: 'h0}},
'{default: '{default: 'h1}},
'{default: '{default: 'h2}}};
endfunction
function void check_randomization();
foreach (unpacked_array[i]) begin
foreach (unpacked_array[i][j]) begin
// At the innermost packed level, invoke check_rand
`check_rand(this, this.unpacked_array[i][j])
end
end
endfunction
endclass
class unconstrained_dynamic_array_test;
rand int dynamic_array_1d[];
rand int dynamic_array_2d[][];
function new();
// Initialize 1D dynamic array
dynamic_array_1d = new[5];
foreach(dynamic_array_1d[i]) begin
dynamic_array_1d[i] = 'h0 + i;
end
// Initialize 2D dynamic array
dynamic_array_2d = new[3];
foreach(dynamic_array_2d[i]) begin
dynamic_array_2d[i] = new[3];
foreach(dynamic_array_2d[i][j]) begin
dynamic_array_2d[i][j] = 'h0 + i + j;
end
end
endfunction
function void check_randomization();
foreach (dynamic_array_1d[i]) begin
`check_rand(this, dynamic_array_1d[i])
end
foreach (dynamic_array_2d[i]) begin
foreach (dynamic_array_2d[i][j]) begin
`check_rand(this, dynamic_array_2d[i][j])
end
end
endfunction
endclass
class unconstrained_struct_with_array_test;
typedef struct {
rand bit [7:0] byte_array[4];
} struct_with_array_t;
rand struct_with_array_t struct_with_array;
function new();
struct_with_array = '{'{default: 'h0}};
endfunction
function void check_randomization();
foreach (struct_with_array.byte_array[i]) begin
`check_rand(this, struct_with_array.byte_array[i])
end
endfunction
endclass
module t_randomize_array;
unconstrained_packed_array_test packed_class;
unconstrained_unpacked_array_test unpacked_class;
unconstrained_dynamic_array_test dynamic_class;
unconstrained_struct_with_array_test struct_with_array_class;
initial begin
// Test 1: Packed Array Unconstrained Constrained Test
packed_class = new();
repeat(2) begin
packed_class.check_randomization();
end
// Test 2: Unpacked Array Unconstrained Constrained Test
unpacked_class = new();
repeat(2) begin
unpacked_class.check_randomization();
end
// Test 3: Dynamic Array Unconstrained Constrained Test
dynamic_class = new();
repeat(2) begin
dynamic_class.check_randomization();
end
// Test 4: Struct Containing Array Test
struct_with_array_class = new();
repeat(2) begin
struct_with_array_class.check_randomization();
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,8 @@
%Error-UNSUPPORTED: t/t_randomize_array_unsup.v:28:8: Unsupported: CreateArrayForeachLoop currently does not support this data type. (Struct-Array unconstrained randomization is not fully supported)
28 | rand simple_struct_t struct_array_2[];
| ^~~~~~~~~~~~~~~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error-UNSUPPORTED: t/t_randomize_array_unsup.v:29:8: Unsupported: CreateArrayForeachLoop currently does not support this data type. (Struct-Array unconstrained randomization is not fully supported)
29 | rand simple_struct_t struct_array_1[3];
| ^~~~~~~~~~~~~~~
%Error: Exiting due to

View File

@ -0,0 +1,16 @@
#!/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(fails=test.vlt_all, expect_filename=test.golden_filename)
test.passes()

View File

@ -0,0 +1,72 @@
// 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

@ -1,5 +1,5 @@
%Warning-CONSTRAINTIGN: t/t_randomize_method_types_unsup.v:14:32: Unsupported: randomizing this expression, treating as state
14 | constraint dynsize { dynarr.size < 20; }
%Warning-CONSTRAINTIGN: t/t_randomize_method_types_unsup.v:13:32: Unsupported: randomizing this expression, treating as state
13 | constraint dynsize { dynarr.size < 20; }
| ^~~~
... For warning description see https://verilator.org/warn/CONSTRAINTIGN?v=latest
... Use "/* verilator lint_off CONSTRAINTIGN */" and lint_on around source to disable this message.
@ -7,16 +7,8 @@
: ... note: In instance 't'
8 | rand int assocarr[string];
| ^~~~~~~~
%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:9:13: Unsupported: random member variable with type 'int$[]'
: ... note: In instance 't'
9 | rand int dynarr[];
| ^~~~~~
%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:10:13: Unsupported: random member variable with type 'int$[0:4]'
%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:10:13: Unsupported: random member variable with the type of the containing class
: ... note: In instance 't'
10 | rand int unpackarr[5];
| ^~~~~~~~~
%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:11:13: Unsupported: random member variable with the type of the containing class
: ... note: In instance 't'
11 | rand Cls cls;
10 | rand Cls cls;
| ^~~
%Error: Exiting due to

View File

@ -7,7 +7,6 @@
class Cls;
rand int assocarr[string];
rand int dynarr[];
rand int unpackarr[5];
rand Cls cls;
rand int i;
int st;

View File

@ -21072,21 +21072,15 @@ typedef class uvm_tlm_extension_base;
class uvm_tlm_generic_payload extends uvm_sequence_item;
rand bit [63:0] m_address;
rand uvm_tlm_command_e m_command;
//TODO issue-4625 - Rand fields of dynamic array types
//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:21081:35: Unsupported: random member variable with type 'byte[]'
/*TODO rand*/ byte unsigned m_data[];
rand byte unsigned m_data[];
rand int unsigned m_length;
rand uvm_tlm_response_status_e m_response_status;
bit m_dmi;
//TODO issue-4625 - Rand fields of dynamic array types
//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:21081:35: Unsupported: random member variable with type 'byte[]'
/*TODO rand*/ byte unsigned m_byte_enable[];
rand byte unsigned m_byte_enable[];
rand int unsigned m_byte_enable_length;
rand int unsigned m_streaming_width;
protected uvm_tlm_extension_base m_extensions [uvm_tlm_extension_base];
//TODO issue-4625 - Rand fields of dynamic array types
//TODO %Error-UNSUPPORTED: t/t_uvm_pkg_todo.vh:21081:35: Unsupported: random member variable with type 'CLASSREFDTYPE 'uvm_tlm_extension_base'[]'
local /*rand*/ uvm_tlm_extension_base m_rand_exts[];
local rand uvm_tlm_extension_base m_rand_exts[];
typedef uvm_object_registry#(uvm_tlm_generic_payload,"uvm_tlm_generic_payload") type_id;
static function uvm_tlm_generic_payload type_id_create (string name="",
uvm_component parent=null,