reformat
This commit is contained in:
parent
04f7251975
commit
12747ae18f
|
|
@ -307,7 +307,6 @@ class RandomizeMarkVisitor final : public VNVisitor {
|
||||||
// Process per-variable (object instance), not per-class
|
// Process per-variable (object instance), not per-class
|
||||||
// This allows multiple objects of the same class (e.g., obj1 and obj2 of type Sub)
|
// This allows multiple objects of the same class (e.g., obj1 and obj2 of type Sub)
|
||||||
if (m_processedVars.insert(objVar).second) {
|
if (m_processedVars.insert(objVar).second) {
|
||||||
|
|
||||||
// Clone constraints from the top-level class (e.g., Level1 for obj_a)
|
// Clone constraints from the top-level class (e.g., Level1 for obj_a)
|
||||||
gConsClass->foreachMember([&](AstClass* const classp, AstConstraint* const constrp) {
|
gConsClass->foreachMember([&](AstClass* const classp, AstConstraint* const constrp) {
|
||||||
AstConstraint* const cloneConstrp = constrp->cloneTree(false);
|
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)) {
|
if (VN_IS(nodep->fromp(), VarRef) || VN_IS(nodep->fromp(), MemberSel)) {
|
||||||
markNestedGlobalConstrainedRecurse(nodep->fromp());
|
markNestedGlobalConstrainedRecurse(nodep->fromp());
|
||||||
} else if (VN_IS(nodep->fromp(), ArraySel)) {
|
} 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:
|
// Global constraint processing algorithm:
|
||||||
// 1. Detect globally constrained object variables in randomized classes
|
// 1. Detect globally constrained object variables in randomized classes
|
||||||
|
|
@ -832,7 +832,6 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||||
|
|
||||||
AstMemberSel* membersel = nullptr;
|
AstMemberSel* membersel = nullptr;
|
||||||
std::string smtName;
|
std::string smtName;
|
||||||
|
|
||||||
if (isGlobalConstrained && VN_IS(nodep->backp(), MemberSel)) {
|
if (isGlobalConstrained && VN_IS(nodep->backp(), MemberSel)) {
|
||||||
// For global constraints: build complete path from topmost MemberSel
|
// For global constraints: build complete path from topmost MemberSel
|
||||||
AstNode* topMemberSel = nodep->backp();
|
AstNode* topMemberSel = nodep->backp();
|
||||||
|
|
@ -1119,11 +1118,9 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
void visit(AstMemberSel* nodep) override {
|
void visit(AstMemberSel* nodep) override {
|
||||||
if (nodep->varp()->rand().isRandomizable() && nodep->fromp()) {
|
if (nodep->varp()->rand().isRandomizable() && nodep->fromp()) {
|
||||||
|
|
||||||
AstNode* rootNode = nodep->fromp();
|
AstNode* rootNode = nodep->fromp();
|
||||||
while (const AstMemberSel* const selp = VN_CAST(rootNode, MemberSel))
|
while (const AstMemberSel* const selp = VN_CAST(rootNode, MemberSel))
|
||||||
rootNode = selp->fromp();
|
rootNode = selp->fromp();
|
||||||
|
|
||||||
// Check if the root variable participates in global constraints
|
// Check if the root variable participates in global constraints
|
||||||
if (const AstVarRef* const varRefp = VN_CAST(rootNode, VarRef)) {
|
if (const AstVarRef* const varRefp = VN_CAST(rootNode, VarRef)) {
|
||||||
AstVar* const constrainedVar = varRefp->varp();
|
AstVar* const constrainedVar = varRefp->varp();
|
||||||
|
|
|
||||||
|
|
@ -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'
|
: ... 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
|
... 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'
|
: ... note: In instance 't_constraint_global_arr_unsup'
|
||||||
42 | mid.arr[0].y == 201;
|
42 | m_mid.m_arr[0].m_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;
|
|
||||||
| ^~~
|
| ^~~
|
||||||
%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'
|
: ... note: In instance 't_constraint_global_arr_unsup'
|
||||||
48 | mid_arr[0].obj.y == 301;
|
47 | m_mid_arr[0].m_obj.m_x == 300;
|
||||||
| ^~~
|
| ^~~~~
|
||||||
%Error-UNSUPPORTED: t/t_constraint_global_arr_unsup.v:53:20: Unsupported in global constraint
|
%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'
|
: ... note: In instance 't_constraint_global_arr_unsup'
|
||||||
53 | mid_arr[1].arr[2].y == 400;
|
48 | m_mid_arr[0].m_obj.m_y == 301;
|
||||||
| ^~~
|
| ^~~~~
|
||||||
%Error-UNSUPPORTED: t/t_constraint_global_arr_unsup.v:53:27: Unsupported in global constraint
|
%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'
|
: ... 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
|
%Error: Exiting due to
|
||||||
|
|
|
||||||
|
|
@ -6,81 +6,81 @@
|
||||||
|
|
||||||
/* verilator lint_off WIDTHTRUNC */
|
/* verilator lint_off WIDTHTRUNC */
|
||||||
class Inner;
|
class Inner;
|
||||||
rand int x;
|
rand int m_x;
|
||||||
rand int y;
|
rand int m_y;
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
class Middle;
|
class Middle;
|
||||||
rand Inner obj;
|
rand Inner m_obj;
|
||||||
rand Inner arr[3];
|
rand Inner m_arr[3];
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
class Outer;
|
class Outer;
|
||||||
rand Middle mid;
|
rand Middle m_mid;
|
||||||
rand Middle mid_arr[2];
|
rand Middle m_mid_arr[2];
|
||||||
|
|
||||||
function new();
|
function new();
|
||||||
mid = new;
|
m_mid = new;
|
||||||
mid.obj = new;
|
m_mid.m_obj = new;
|
||||||
foreach (mid.arr[i]) mid.arr[i] = new;
|
foreach (m_mid.m_arr[i]) m_mid.m_arr[i] = new;
|
||||||
foreach (mid_arr[i]) begin
|
foreach (m_mid_arr[i]) begin
|
||||||
mid_arr[i] = new;
|
m_mid_arr[i] = new;
|
||||||
mid_arr[i].obj = new;
|
m_mid_arr[i].m_obj = new;
|
||||||
foreach (mid_arr[i].arr[j]) mid_arr[i].arr[j] = new;
|
foreach (m_mid_arr[i].m_arr[j]) m_mid_arr[i].m_arr[j] = new;
|
||||||
end
|
end
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
// Case 1: Simple nested member access (should work)
|
// Case 1: Simple nested member access (should work)
|
||||||
constraint c_simple {
|
constraint c_simple {
|
||||||
mid.obj.x == 100;
|
m_mid.m_obj.m_x == 100;
|
||||||
mid.obj.y == 101;
|
m_mid.m_obj.m_y == 101;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Case 2: Array indexing in the path (may not work)
|
// Case 2: Array indexing in the path (may not work)
|
||||||
constraint c_array_index {
|
constraint c_array_index {
|
||||||
mid.arr[0].x == 200;
|
m_mid.m_arr[0].m_x == 200;
|
||||||
mid.arr[0].y == 201;
|
m_mid.m_arr[0].m_y == 201;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Case 3: Nested array indexing
|
// Case 3: Nested array indexing
|
||||||
constraint c_nested_array {
|
constraint c_nested_array {
|
||||||
mid_arr[0].obj.x == 300;
|
m_mid_arr[0].m_obj.m_x == 300;
|
||||||
mid_arr[0].obj.y == 301;
|
m_mid_arr[0].m_obj.m_y == 301;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Case 4: Multiple array indices
|
// Case 4: Multiple array indices
|
||||||
constraint c_multi_array {
|
constraint c_multi_array {
|
||||||
mid_arr[1].arr[2].y == 400;
|
m_mid_arr[1].m_arr[2].m_y == 400;
|
||||||
}
|
}
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
module t_constraint_global_arr_unsup;
|
module t_constraint_global_arr_unsup;
|
||||||
initial begin
|
initial begin
|
||||||
Outer o = new;
|
Outer o = new;
|
||||||
if (o.randomize()) begin
|
if (o.randomize()) begin
|
||||||
$display("Case 1 - Simple: mid.obj.x = %0d (expected 100)", o.mid.obj.x);
|
$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.mid.obj.y);
|
$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.mid.arr[0].x);
|
$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.mid.arr[0].y);
|
$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.mid_arr[0].obj.x);
|
$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.mid_arr[0].obj.y);
|
$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.mid_arr[1].arr[2].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
|
// Check results
|
||||||
if (o.mid.obj.x == 100 && o.mid.obj.y == 101 &&
|
if (o.m_mid.m_obj.m_x == 100 && o.m_mid.m_obj.m_y == 101 &&
|
||||||
o.mid.arr[0].x == 200 && o.mid.arr[0].y == 201 &&
|
o.m_mid.m_arr[0].m_x == 200 && o.m_mid.m_arr[0].m_y == 201 &&
|
||||||
o.mid_arr[0].obj.x == 300 && o.mid_arr[0].obj.y == 301 &&
|
o.m_mid_arr[0].m_obj.m_x == 300 && o.m_mid_arr[0].m_obj.m_y == 301 &&
|
||||||
o.mid_arr[1].arr[2].y == 400) begin
|
o.m_mid_arr[1].m_arr[2].m_y == 400) begin
|
||||||
$display("*-* All Finished *-*");
|
$display("*-* All Finished *-*");
|
||||||
$finish;
|
$finish;
|
||||||
end else begin
|
end else begin
|
||||||
$display("*-* FAILED *-*");
|
$display("*-* FAILED *-*");
|
||||||
$stop;
|
$stop;
|
||||||
end
|
end
|
||||||
end else begin
|
end else begin
|
||||||
$display("*-* FAILED: randomize() returned 0 *-*");
|
$display("*-* FAILED: randomize() returned 0 *-*");
|
||||||
$stop;
|
$stop;
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
end
|
||||||
endmodule
|
endmodule
|
||||||
/* verilator lint_off WIDTHTRUNC */
|
/* verilator lint_off WIDTHTRUNC */
|
||||||
|
|
|
||||||
|
|
@ -5,81 +5,81 @@
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
class Inner;
|
class Inner;
|
||||||
rand int val;
|
rand int m_val;
|
||||||
constraint c_local { val inside {[1:5]}; }
|
constraint c_local { m_val inside {[1:5]}; }
|
||||||
function new(); val = 0; endfunction
|
function new(); m_val = 0; endfunction
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
class Mid;
|
class Mid;
|
||||||
int limit;
|
int m_limit;
|
||||||
rand int x;
|
rand int m_x;
|
||||||
rand Inner inner;
|
rand Inner m_inner;
|
||||||
constraint c_mid { x == limit; }
|
constraint c_mid { m_x == m_limit; }
|
||||||
function new(int lim);
|
function new(int lim);
|
||||||
limit = lim;
|
m_limit = lim;
|
||||||
inner = new();
|
m_inner = new();
|
||||||
endfunction
|
endfunction
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
class Top;
|
class Top;
|
||||||
rand Mid m1;
|
rand Mid m_m1;
|
||||||
rand Mid m2;
|
rand Mid m_m2;
|
||||||
rand int y;
|
rand int m_y;
|
||||||
|
|
||||||
constraint c_global {
|
constraint c_global {
|
||||||
m1.inner.val < m2.inner.val;
|
m_m1.m_inner.m_val < m_m2.m_inner.m_val;
|
||||||
y > m1.x;
|
m_y > m_m1.m_x;
|
||||||
y < m2.x;
|
m_y < m_m2.m_x;
|
||||||
m1.inner.val + m2.inner.val < 8;
|
m_m1.m_inner.m_val + m_m2.m_inner.m_val < 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
function new();
|
function new();
|
||||||
m1 = new(3);
|
m_m1 = new(3);
|
||||||
m2 = new(5);
|
m_m2 = new(5);
|
||||||
y = 0;
|
m_y = 0;
|
||||||
endfunction
|
endfunction
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
module t_constraint_global_random;
|
module t_constraint_global_random;
|
||||||
int success;
|
int success;
|
||||||
Top t;
|
Top t;
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
t = new();
|
t = new();
|
||||||
|
|
||||||
// Test 1: Regular randomize() with global constraints
|
// Test 1: Regular randomize() with global constraints
|
||||||
success = t.randomize();
|
success = t.randomize();
|
||||||
if (success != 1) $stop;
|
if (success != 1) $stop;
|
||||||
|
|
||||||
// $display("m1.x=%0d, m2.x=%0d, y=%0d", t.m1.x, t.m2.x, t.y);
|
// $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.m1.inner.val, t.m2.inner.val);
|
// $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.m_m1.m_x != 3 || t.m_m2.m_x != 5) $stop;
|
||||||
if (t.m1.inner.val >= t.m2.inner.val) $stop;
|
if (t.m_m1.m_inner.m_val >= t.m_m2.m_inner.m_val) $stop;
|
||||||
if (t.y <= t.m1.x || t.y >= t.m2.x) $stop;
|
if (t.m_y <= t.m_m1.m_x || t.m_y >= t.m_m2.m_x) $stop;
|
||||||
if (t.m1.inner.val + t.m2.inner.val >= 8) $stop;
|
if (t.m_m1.m_inner.m_val + t.m_m2.m_inner.m_val >= 8) $stop;
|
||||||
if (t.m1.inner.val < 1 || t.m1.inner.val > 5 ||
|
if (t.m_m1.m_inner.m_val < 1 || t.m_m1.m_inner.m_val > 5 ||
|
||||||
t.m2.inner.val < 1 || t.m2.inner.val > 5) $stop;
|
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
|
// Test 2: randomize() with inline constraint on global-constrained members
|
||||||
success = 0;
|
success = 0;
|
||||||
success = t.randomize() with {
|
success = t.randomize() with {
|
||||||
m1.inner.val == 2;
|
m_m1.m_inner.m_val == 2;
|
||||||
m2.inner.val == 5;
|
m_m2.m_inner.m_val == 5;
|
||||||
};
|
};
|
||||||
if (success != 1) $stop;
|
if (success != 1) $stop;
|
||||||
|
|
||||||
// Verify inline constraints
|
// Verify inline constraints
|
||||||
if (t.m1.inner.val != 2) $stop;
|
if (t.m_m1.m_inner.m_val != 2) $stop;
|
||||||
if (t.m2.inner.val != 5) $stop;
|
if (t.m_m2.m_inner.m_val != 5) $stop;
|
||||||
|
|
||||||
// Verify global constraints still hold
|
// Verify global constraints still hold
|
||||||
if (t.m1.x != 3 || t.m2.x != 5) $stop;
|
if (t.m_m1.m_x != 3 || t.m_m2.m_x != 5) $stop;
|
||||||
if (t.m1.inner.val >= t.m2.inner.val) $stop;
|
if (t.m_m1.m_inner.m_val >= t.m_m2.m_inner.m_val) $stop;
|
||||||
if (t.y <= t.m1.x || t.y >= t.m2.x) $stop;
|
if (t.m_y <= t.m_m1.m_x || t.m_y >= t.m_m2.m_x) $stop;
|
||||||
if (t.m1.inner.val + t.m2.inner.val >= 8) $stop;
|
if (t.m_m1.m_inner.m_val + t.m_m2.m_inner.m_val >= 8) $stop;
|
||||||
|
|
||||||
$write("*-* All Finished *-*\n");
|
$write("*-* All Finished *-*\n");
|
||||||
$finish;
|
$finish;
|
||||||
end
|
end
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue