Merge 26aeb24f40 into 1b93033690
This commit is contained in:
commit
43b66d8665
|
|
@ -170,13 +170,21 @@ class RandomizeMarkVisitor final : public VNVisitor {
|
|||
if (VN_IS(pinp, With)) continue;
|
||||
const AstArg* const argp = VN_CAST(pinp, Arg);
|
||||
if (!argp) continue;
|
||||
const AstNodeExpr* const exprp = argp->exprp();
|
||||
if (const AstNodeVarRef* const varrefp = VN_CAST(exprp, NodeVarRef)) {
|
||||
if (varrefp->varp() == varp) return true;
|
||||
} else if (const AstMemberSel* const memberselp = VN_CAST(exprp, MemberSel)) {
|
||||
if (memberselp->varp() == varp) return true;
|
||||
} else if (const AstArraySel* const arrselp = VN_CAST(exprp, ArraySel)) {
|
||||
if (VN_AS(arrselp->fromp(), VarRef)->varp() == varp) return true;
|
||||
const AstNodeExpr* exprp = argp->exprp();
|
||||
// Traverse through ArraySel and MemberSel to find the base variable
|
||||
while (exprp) {
|
||||
if (const AstNodeVarRef* const varrefp = VN_CAST(exprp, NodeVarRef)) {
|
||||
if (varrefp->varp() == varp) return true;
|
||||
break;
|
||||
}
|
||||
if (const AstMemberSel* const memberselp = VN_CAST(exprp, MemberSel)) {
|
||||
if (memberselp->varp() == varp) return true;
|
||||
exprp = memberselp->fromp();
|
||||
} else if (const AstArraySel* const arrselp = VN_CAST(exprp, ArraySel)) {
|
||||
exprp = arrselp->fromp();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
@ -535,22 +543,31 @@ class RandomizeMarkVisitor final : public VNVisitor {
|
|||
AstArg* const argp = VN_CAST(pinp, Arg);
|
||||
if (!argp) continue;
|
||||
AstNodeExpr* exprp = argp->exprp();
|
||||
// IEEE 1800-2023 18.11: "Arguments are limited to the names of properties
|
||||
// of the calling object; expressions are not allowed."
|
||||
// However, for compatibility with other simulators, we support complex
|
||||
// expressions like obj.member[idx] in std::randomize().
|
||||
while (exprp) {
|
||||
AstVar* randVarp = nullptr;
|
||||
AstVarRef* varrefp = nullptr;
|
||||
if (AstMemberSel* const memberSelp = VN_CAST(exprp, MemberSel)) {
|
||||
randVarp = memberSelp->varp();
|
||||
exprp = memberSelp->fromp();
|
||||
} else if (AstArraySel* const arraySelp = VN_CAST(exprp, ArraySel)) {
|
||||
// Check if child is VarRef and mark it
|
||||
if (AstVarRef* const childVarRefp = VN_CAST(arraySelp->fromp(), VarRef)) {
|
||||
childVarRefp->access(VAccess::READWRITE);
|
||||
}
|
||||
exprp = arraySelp->fromp();
|
||||
continue; // Skip ArraySel, continue traversing
|
||||
} else if ((varrefp = VN_CAST(exprp, VarRef))) {
|
||||
randVarp = varrefp->varp();
|
||||
varrefp->user1(true);
|
||||
exprp = nullptr;
|
||||
} else {
|
||||
varrefp = VN_AS(VN_CAST(exprp, ArraySel)->fromp(), VarRef);
|
||||
randVarp = varrefp->varp();
|
||||
varrefp->user1(true);
|
||||
varrefp->access(VAccess::READWRITE);
|
||||
exprp = nullptr;
|
||||
// All invalid and unsupported expressions should be caught in V3Width
|
||||
nodep->v3fatalSrc(
|
||||
"Unexpected expression type in std::randomize() argument");
|
||||
}
|
||||
UASSERT_OBJ(randVarp, nodep, "No rand variable found");
|
||||
AstNode* backp = randVarp;
|
||||
|
|
@ -578,15 +595,28 @@ class RandomizeMarkVisitor final : public VNVisitor {
|
|||
fromVarp = varrefp->varp();
|
||||
}
|
||||
}
|
||||
// IEEE 1800-2023 18.11: "Arguments are limited to the names of properties
|
||||
// of the calling object; expressions are not allowed."
|
||||
// However, for compatibility with other simulators, we support complex
|
||||
// expressions like obj.member[idx].field in inline randomize().
|
||||
while (exprp) {
|
||||
AstVar* randVarp = nullptr;
|
||||
if (AstMemberSel* const memberSelp = VN_CAST(exprp, MemberSel)) {
|
||||
randVarp = memberSelp->varp();
|
||||
exprp = memberSelp->fromp();
|
||||
} else {
|
||||
AstVarRef* const varrefp = VN_AS(exprp, VarRef);
|
||||
} else if (AstArraySel* const arraySelp = VN_CAST(exprp, ArraySel)) {
|
||||
// Check if child is VarRef and mark it
|
||||
if (AstVarRef* const childVarRefp = VN_CAST(arraySelp->fromp(), VarRef)) {
|
||||
childVarRefp->access(VAccess::READWRITE);
|
||||
}
|
||||
exprp = arraySelp->fromp();
|
||||
continue; // Skip ArraySel, continue traversing
|
||||
} else if (AstVarRef* const varrefp = VN_CAST(exprp, VarRef)) {
|
||||
randVarp = varrefp->varp();
|
||||
exprp = nullptr;
|
||||
} else {
|
||||
// All invalid and unsupported expressions should be caught in V3Width
|
||||
nodep->v3fatalSrc("Unexpected expression type in randomize() argument");
|
||||
}
|
||||
if (randVarp == fromVarp) break;
|
||||
UASSERT_OBJ(randVarp, nodep, "No rand variable found");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2025 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()
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Antmicro.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
class inner_class;
|
||||
logic [3:0] c;
|
||||
logic [3:0] d[2];
|
||||
endclass
|
||||
|
||||
class test_class;
|
||||
logic [3:0] member[5];
|
||||
logic [3:0] member_2d[3][4];
|
||||
inner_class b;
|
||||
endclass
|
||||
|
||||
module t;
|
||||
initial begin
|
||||
test_class example;
|
||||
example = new;
|
||||
example.b = new;
|
||||
|
||||
// Simple array element access
|
||||
repeat(5) begin
|
||||
if (std::randomize(example.member[1]) with {example.member[1] inside {[0 : 3]};} == 0) begin
|
||||
$stop;
|
||||
end
|
||||
if (example.member[1] > 3) begin
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
|
||||
// Different array indices
|
||||
repeat(5) begin
|
||||
if (std::randomize(example.member[0]) with {example.member[0] inside {[5 : 7]};} == 0) begin
|
||||
$stop;
|
||||
end
|
||||
if (example.member[0] < 5 || example.member[0] > 7) begin
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
|
||||
// Last element
|
||||
repeat(5) begin
|
||||
if (std::randomize(example.member[4]) with {example.member[4] inside {[10 : 15]};} == 0) begin
|
||||
$stop;
|
||||
end
|
||||
if (example.member[4] < 10 || example.member[4] > 15) begin
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
|
||||
// 2D array access
|
||||
repeat(5) begin
|
||||
if (std::randomize(example.member_2d[1][2]) with {example.member_2d[1][2] inside {[8 : 12]};} == 0) begin
|
||||
$stop;
|
||||
end
|
||||
if (example.member_2d[1][2] < 8 || example.member_2d[1][2] > 12) begin
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
|
||||
// 2D array different indices
|
||||
repeat(5) begin
|
||||
if (std::randomize(example.member_2d[0][0]) with {example.member_2d[0][0] inside {[1 : 4]};} == 0) begin
|
||||
$stop;
|
||||
end
|
||||
if (example.member_2d[0][0] < 1 || example.member_2d[0][0] > 4) begin
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
|
||||
// Nested object: obj.b.c
|
||||
repeat(5) begin
|
||||
if (std::randomize(example.b.c) with {example.b.c inside {[5 : 9]};} == 0) begin
|
||||
$stop;
|
||||
end
|
||||
if (example.b.c < 5 || example.b.c > 9) begin
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
|
||||
// Nested object with array: obj.b.d[0]
|
||||
repeat(5) begin
|
||||
if (std::randomize(example.b.d[0]) with {example.b.d[0] inside {[11 : 14]};} == 0) begin
|
||||
$stop;
|
||||
end
|
||||
if (example.b.d[0] < 11 || example.b.d[0] > 14) begin
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
|
||||
// Nested object with array: obj.b.d[1] (different index)
|
||||
repeat(5) begin
|
||||
if (std::randomize(example.b.d[1]) with {example.b.d[1] inside {[2 : 6]};} == 0) begin
|
||||
$stop;
|
||||
end
|
||||
if (example.b.d[1] < 2 || example.b.d[1] > 6) begin
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
Loading…
Reference in New Issue