This commit is contained in:
Yilou Wang 2025-10-29 14:40:24 +01:00
parent 04f7251975
commit 12747ae18f
4 changed files with 138 additions and 141 deletions

View File

@ -307,7 +307,6 @@ class RandomizeMarkVisitor final : public VNVisitor {
// Process per-variable (object instance), not per-class
// This allows multiple objects of the same class (e.g., obj1 and obj2 of type Sub)
if (m_processedVars.insert(objVar).second) {
// Clone constraints from the top-level class (e.g., Level1 for obj_a)
gConsClass->foreachMember([&](AstClass* const classp, AstConstraint* const constrp) {
AstConstraint* const cloneConstrp = constrp->cloneTree(false);
@ -611,7 +610,8 @@ class RandomizeMarkVisitor final : public VNVisitor {
if (VN_IS(nodep->fromp(), VarRef) || VN_IS(nodep->fromp(), MemberSel)) {
markNestedGlobalConstrainedRecurse(nodep->fromp());
} else if (VN_IS(nodep->fromp(), ArraySel)) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported in global constraint");
nodep->v3warn(E_UNSUPPORTED, "Unsupported: " << nodep->prettyTypeName()
<< " within a global constraint");
}
// Global constraint processing algorithm:
// 1. Detect globally constrained object variables in randomized classes
@ -832,7 +832,6 @@ class ConstraintExprVisitor final : public VNVisitor {
AstMemberSel* membersel = nullptr;
std::string smtName;
if (isGlobalConstrained && VN_IS(nodep->backp(), MemberSel)) {
// For global constraints: build complete path from topmost MemberSel
AstNode* topMemberSel = nodep->backp();
@ -1119,11 +1118,9 @@ class ConstraintExprVisitor final : public VNVisitor {
}
void visit(AstMemberSel* nodep) override {
if (nodep->varp()->rand().isRandomizable() && nodep->fromp()) {
AstNode* rootNode = nodep->fromp();
while (const AstMemberSel* const selp = VN_CAST(rootNode, MemberSel))
rootNode = selp->fromp();
// Check if the root variable participates in global constraints
if (const AstVarRef* const varRefp = VN_CAST(rootNode, VarRef)) {
AstVar* const constrainedVar = varRefp->varp();

View File

@ -1,26 +1,26 @@
%Error-UNSUPPORTED: t/t_constraint_global_arr_unsup.v:41:20: Unsupported in global constraint
%Error-UNSUPPORTED: t/t_constraint_global_arr_unsup.v:41:20: Unsupported: MEMBERSEL 'm_x' within a global constraint
: ... note: In instance 't_constraint_global_arr_unsup'
41 | mid.arr[0].x == 200;
| ^
41 | m_mid.m_arr[0].m_x == 200;
| ^~~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error-UNSUPPORTED: t/t_constraint_global_arr_unsup.v:42:20: Unsupported in global constraint
%Error-UNSUPPORTED: t/t_constraint_global_arr_unsup.v:42:20: Unsupported: MEMBERSEL 'm_y' within a global constraint
: ... note: In instance 't_constraint_global_arr_unsup'
42 | mid.arr[0].y == 201;
| ^
%Error-UNSUPPORTED: t/t_constraint_global_arr_unsup.v:47:20: Unsupported in global constraint
: ... note: In instance 't_constraint_global_arr_unsup'
47 | mid_arr[0].obj.x == 300;
42 | m_mid.m_arr[0].m_y == 201;
| ^~~
%Error-UNSUPPORTED: t/t_constraint_global_arr_unsup.v:48:20: Unsupported in global constraint
%Error-UNSUPPORTED: t/t_constraint_global_arr_unsup.v:47:18: Unsupported: MEMBERSEL 'm_obj' within a global constraint
: ... note: In instance 't_constraint_global_arr_unsup'
48 | mid_arr[0].obj.y == 301;
| ^~~
%Error-UNSUPPORTED: t/t_constraint_global_arr_unsup.v:53:20: Unsupported in global constraint
47 | m_mid_arr[0].m_obj.m_x == 300;
| ^~~~~
%Error-UNSUPPORTED: t/t_constraint_global_arr_unsup.v:48:18: Unsupported: MEMBERSEL 'm_obj' within a global constraint
: ... note: In instance 't_constraint_global_arr_unsup'
53 | mid_arr[1].arr[2].y == 400;
| ^~~
%Error-UNSUPPORTED: t/t_constraint_global_arr_unsup.v:53:27: Unsupported in global constraint
48 | m_mid_arr[0].m_obj.m_y == 301;
| ^~~~~
%Error-UNSUPPORTED: t/t_constraint_global_arr_unsup.v:53:18: Unsupported: MEMBERSEL 'm_arr' within a global constraint
: ... note: In instance 't_constraint_global_arr_unsup'
53 | mid_arr[1].arr[2].y == 400;
| ^
53 | m_mid_arr[1].m_arr[2].m_y == 400;
| ^~~~~
%Error-UNSUPPORTED: t/t_constraint_global_arr_unsup.v:53:27: Unsupported: MEMBERSEL 'm_y' within a global constraint
: ... note: In instance 't_constraint_global_arr_unsup'
53 | m_mid_arr[1].m_arr[2].m_y == 400;
| ^~~
%Error: Exiting due to

View File

@ -6,81 +6,81 @@
/* verilator lint_off WIDTHTRUNC */
class Inner;
rand int x;
rand int y;
rand int m_x;
rand int m_y;
endclass
class Middle;
rand Inner obj;
rand Inner arr[3];
rand Inner m_obj;
rand Inner m_arr[3];
endclass
class Outer;
rand Middle mid;
rand Middle mid_arr[2];
rand Middle m_mid;
rand Middle m_mid_arr[2];
function new();
mid = new;
mid.obj = new;
foreach (mid.arr[i]) mid.arr[i] = new;
foreach (mid_arr[i]) begin
mid_arr[i] = new;
mid_arr[i].obj = new;
foreach (mid_arr[i].arr[j]) mid_arr[i].arr[j] = new;
end
endfunction
function new();
m_mid = new;
m_mid.m_obj = new;
foreach (m_mid.m_arr[i]) m_mid.m_arr[i] = new;
foreach (m_mid_arr[i]) begin
m_mid_arr[i] = new;
m_mid_arr[i].m_obj = new;
foreach (m_mid_arr[i].m_arr[j]) m_mid_arr[i].m_arr[j] = new;
end
endfunction
// Case 1: Simple nested member access (should work)
constraint c_simple {
mid.obj.x == 100;
mid.obj.y == 101;
}
// Case 1: Simple nested member access (should work)
constraint c_simple {
m_mid.m_obj.m_x == 100;
m_mid.m_obj.m_y == 101;
}
// Case 2: Array indexing in the path (may not work)
constraint c_array_index {
mid.arr[0].x == 200;
mid.arr[0].y == 201;
}
// Case 2: Array indexing in the path (may not work)
constraint c_array_index {
m_mid.m_arr[0].m_x == 200;
m_mid.m_arr[0].m_y == 201;
}
// Case 3: Nested array indexing
constraint c_nested_array {
mid_arr[0].obj.x == 300;
mid_arr[0].obj.y == 301;
}
// Case 3: Nested array indexing
constraint c_nested_array {
m_mid_arr[0].m_obj.m_x == 300;
m_mid_arr[0].m_obj.m_y == 301;
}
// Case 4: Multiple array indices
constraint c_multi_array {
mid_arr[1].arr[2].y == 400;
}
// Case 4: Multiple array indices
constraint c_multi_array {
m_mid_arr[1].m_arr[2].m_y == 400;
}
endclass
module t_constraint_global_arr_unsup;
initial begin
Outer o = new;
if (o.randomize()) begin
$display("Case 1 - Simple: mid.obj.x = %0d (expected 100)", o.mid.obj.x);
$display("Case 1 - Simple: mid.obj.y = %0d (expected 101)", o.mid.obj.y);
$display("Case 2 - Array[0]: mid.arr[0].x = %0d (expected 200)", o.mid.arr[0].x);
$display("Case 2 - Array[0]: mid.arr[0].y = %0d (expected 201)", o.mid.arr[0].y);
$display("Case 3 - Nested[0]: mid_arr[0].obj.x = %0d (expected 300)", o.mid_arr[0].obj.x);
$display("Case 3 - Nested[0]: mid_arr[0].obj.y = %0d (expected 301)", o.mid_arr[0].obj.y);
$display("Case 4 - Multi[1][2]: mid_arr[1].arr[2].y = %0d (expected 400)", o.mid_arr[1].arr[2].y);
initial begin
Outer o = new;
if (o.randomize()) begin
$display("Case 1 - Simple: mid.obj.x = %0d (expected 100)", o.m_mid.m_obj.m_x);
$display("Case 1 - Simple: mid.obj.y = %0d (expected 101)", o.m_mid.m_obj.m_y);
$display("Case 2 - Array[0]: mid.arr[0].x = %0d (expected 200)", o.m_mid.m_arr[0].m_x);
$display("Case 2 - Array[0]: mid.arr[0].y = %0d (expected 201)", o.m_mid.m_arr[0].m_y);
$display("Case 3 - Nested[0]: mid_arr[0].obj.x = %0d (expected 300)", o.m_mid_arr[0].m_obj.m_x);
$display("Case 3 - Nested[0]: mid_arr[0].obj.y = %0d (expected 301)", o.m_mid_arr[0].m_obj.m_y);
$display("Case 4 - Multi[1][2]: mid_arr[1].arr[2].y = %0d (expected 400)", o.m_mid_arr[1].m_arr[2].m_y);
// Check results
if (o.mid.obj.x == 100 && o.mid.obj.y == 101 &&
o.mid.arr[0].x == 200 && o.mid.arr[0].y == 201 &&
o.mid_arr[0].obj.x == 300 && o.mid_arr[0].obj.y == 301 &&
o.mid_arr[1].arr[2].y == 400) begin
$display("*-* All Finished *-*");
$finish;
end else begin
$display("*-* FAILED *-*");
$stop;
end
end else begin
$display("*-* FAILED: randomize() returned 0 *-*");
$stop;
end
// Check results
if (o.m_mid.m_obj.m_x == 100 && o.m_mid.m_obj.m_y == 101 &&
o.m_mid.m_arr[0].m_x == 200 && o.m_mid.m_arr[0].m_y == 201 &&
o.m_mid_arr[0].m_obj.m_x == 300 && o.m_mid_arr[0].m_obj.m_y == 301 &&
o.m_mid_arr[1].m_arr[2].m_y == 400) begin
$display("*-* All Finished *-*");
$finish;
end else begin
$display("*-* FAILED *-*");
$stop;
end
end else begin
$display("*-* FAILED: randomize() returned 0 *-*");
$stop;
end
end
endmodule
/* verilator lint_off WIDTHTRUNC */

View File

@ -5,81 +5,81 @@
// SPDX-License-Identifier: CC0-1.0
class Inner;
rand int val;
constraint c_local { val inside {[1:5]}; }
function new(); val = 0; endfunction
rand int m_val;
constraint c_local { m_val inside {[1:5]}; }
function new(); m_val = 0; endfunction
endclass
class Mid;
int limit;
rand int x;
rand Inner inner;
constraint c_mid { x == limit; }
function new(int lim);
limit = lim;
inner = new();
endfunction
int m_limit;
rand int m_x;
rand Inner m_inner;
constraint c_mid { m_x == m_limit; }
function new(int lim);
m_limit = lim;
m_inner = new();
endfunction
endclass
class Top;
rand Mid m1;
rand Mid m2;
rand int y;
rand Mid m_m1;
rand Mid m_m2;
rand int m_y;
constraint c_global {
m1.inner.val < m2.inner.val;
y > m1.x;
y < m2.x;
m1.inner.val + m2.inner.val < 8;
}
constraint c_global {
m_m1.m_inner.m_val < m_m2.m_inner.m_val;
m_y > m_m1.m_x;
m_y < m_m2.m_x;
m_m1.m_inner.m_val + m_m2.m_inner.m_val < 8;
}
function new();
m1 = new(3);
m2 = new(5);
y = 0;
endfunction
function new();
m_m1 = new(3);
m_m2 = new(5);
m_y = 0;
endfunction
endclass
module t_constraint_global_random;
int success;
Top t;
int success;
Top t;
initial begin
t = new();
initial begin
t = new();
// Test 1: Regular randomize() with global constraints
success = t.randomize();
if (success != 1) $stop;
// Test 1: Regular randomize() with global constraints
success = t.randomize();
if (success != 1) $stop;
// $display("m1.x=%0d, m2.x=%0d, y=%0d", t.m1.x, t.m2.x, t.y);
// $display("m1.inner.val=%0d, m2.inner.val=%0d", t.m1.inner.val, t.m2.inner.val);
// $display("m1.x=%0d, m2.x=%0d, y=%0d", t.m_m1.m_x, t.m_m2.m_x, t.m_y);
// $display("m1.inner.val=%0d, m2.inner.val=%0d", t.m_m1.m_inner.m_val, t.m_m2.m_inner.m_val);
if (t.m1.x != 3 || t.m2.x != 5) $stop;
if (t.m1.inner.val >= t.m2.inner.val) $stop;
if (t.y <= t.m1.x || t.y >= t.m2.x) $stop;
if (t.m1.inner.val + t.m2.inner.val >= 8) $stop;
if (t.m1.inner.val < 1 || t.m1.inner.val > 5 ||
t.m2.inner.val < 1 || t.m2.inner.val > 5) $stop;
if (t.m_m1.m_x != 3 || t.m_m2.m_x != 5) $stop;
if (t.m_m1.m_inner.m_val >= t.m_m2.m_inner.m_val) $stop;
if (t.m_y <= t.m_m1.m_x || t.m_y >= t.m_m2.m_x) $stop;
if (t.m_m1.m_inner.m_val + t.m_m2.m_inner.m_val >= 8) $stop;
if (t.m_m1.m_inner.m_val < 1 || t.m_m1.m_inner.m_val > 5 ||
t.m_m2.m_inner.m_val < 1 || t.m_m2.m_inner.m_val > 5) $stop;
// Test 2: randomize() with inline constraint on global-constrained members
success = 0;
success = t.randomize() with {
m1.inner.val == 2;
m2.inner.val == 5;
};
if (success != 1) $stop;
// Test 2: randomize() with inline constraint on global-constrained members
success = 0;
success = t.randomize() with {
m_m1.m_inner.m_val == 2;
m_m2.m_inner.m_val == 5;
};
if (success != 1) $stop;
// Verify inline constraints
if (t.m1.inner.val != 2) $stop;
if (t.m2.inner.val != 5) $stop;
// Verify inline constraints
if (t.m_m1.m_inner.m_val != 2) $stop;
if (t.m_m2.m_inner.m_val != 5) $stop;
// Verify global constraints still hold
if (t.m1.x != 3 || t.m2.x != 5) $stop;
if (t.m1.inner.val >= t.m2.inner.val) $stop;
if (t.y <= t.m1.x || t.y >= t.m2.x) $stop;
if (t.m1.inner.val + t.m2.inner.val >= 8) $stop;
// Verify global constraints still hold
if (t.m_m1.m_x != 3 || t.m_m2.m_x != 5) $stop;
if (t.m_m1.m_inner.m_val >= t.m_m2.m_inner.m_val) $stop;
if (t.m_y <= t.m_m1.m_x || t.m_y >= t.m_m2.m_x) $stop;
if (t.m_m1.m_inner.m_val + t.m_m2.m_inner.m_val >= 8) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule