diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 93e9d434a..96eb0f176 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -913,7 +913,7 @@ class ConstraintExprVisitor final : public VNVisitor { // Returns nullptr for unsupported expression types. // Helper: build a dynamic AstCExpr for "baseName[idx]" pattern AstCExpr* buildArraySelNameExpr(FileLine* fl, const std::string& baseName, - const AstArraySel* selp) { + const AstNodeSel* selp) { AstCExpr* const p = new AstCExpr{fl, ""}; p->add("(\""s + baseName + ".\" + vlToSolverHex("); p->add(selp->bitp()->cloneTreePure(false)); @@ -974,7 +974,9 @@ class ConstraintExprVisitor final : public VNVisitor { p->dtypeSetString(); return p; } - if (const AstArraySel* const selp = VN_CAST(exprp, ArraySel)) { + const AstNodeSel* selp = VN_CAST(exprp, ArraySel); + if (!selp) selp = VN_CAST(exprp, AssocSel); + if (selp) { // arr[i] -> dynamic name std::string baseName; if (const AstVarRef* const vp = VN_CAST(selp->fromp(), VarRef)) { @@ -2379,12 +2381,6 @@ class ConstraintExprVisitor final : public VNVisitor { AstNodeModule* const genModp = VN_AS(m_genp->user2p(), NodeModule); for (AstNodeExpr* lhsp = nodep->lhssp(); lhsp; lhsp = VN_CAST(lhsp->nextp(), NodeExpr)) { - if (VN_IS(lhsp->dtypep()->skipRefp(), AssocArrayDType)) { - lhsp->v3warn(E_UNSUPPORTED, - "Unsupported: 'solve ... before' with associative array"); - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - return; - } AstNodeExpr* const lhsTestp = buildSolveBeforeNameExpr(fl, lhsp); if (!lhsTestp) { lhsp->v3fatalSrc("Unexpected expression type in solve...before lhs"); @@ -2393,12 +2389,6 @@ class ConstraintExprVisitor final : public VNVisitor { VL_DO_DANGLING(lhsTestp->deleteTree(), lhsTestp); for (AstNodeExpr* rhsp = nodep->rhssp(); rhsp; rhsp = VN_CAST(rhsp->nextp(), NodeExpr)) { - if (VN_IS(rhsp->dtypep()->skipRefp(), AssocArrayDType)) { - rhsp->v3warn(E_UNSUPPORTED, - "Unsupported: 'solve ... before' with associative array"); - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - return; - } AstNodeExpr* const rhsNamep = buildSolveBeforeNameExpr(fl, rhsp); if (!rhsNamep) { rhsp->v3fatalSrc("Unexpected expression type in solve...before rhs"); diff --git a/test_regress/t/t_constraint_solve_before_assoc_unsup.py b/test_regress/t/t_constraint_solve_before_assoc.py similarity index 76% rename from test_regress/t/t_constraint_solve_before_assoc_unsup.py rename to test_regress/t/t_constraint_solve_before_assoc.py index 38cf36b43..db1adb3f9 100755 --- a/test_regress/t/t_constraint_solve_before_assoc_unsup.py +++ b/test_regress/t/t_constraint_solve_before_assoc.py @@ -9,8 +9,13 @@ import vltest_bootstrap -test.scenarios('linter') +test.scenarios('simulator') -test.lint(fails=True, expect_filename=test.golden_filename) +if not test.have_solver: + test.skip("No constraint solver installed") + +test.compile() + +test.execute() test.passes() diff --git a/test_regress/t/t_constraint_solve_before_assoc.v b/test_regress/t/t_constraint_solve_before_assoc.v new file mode 100644 index 000000000..ef411a9ce --- /dev/null +++ b/test_regress/t/t_constraint_solve_before_assoc.v @@ -0,0 +1,62 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 PlanV GmbH +// SPDX-License-Identifier: CC0-1.0 + +// verilog_format: off +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0) +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0) +// verilog_format: on + +class Assoc; + rand int unsigned m[int]; + rand int unsigned s; + function new; + m[123] = 1; + m[456] = 1; + endfunction + constraint c { + solve m before s; + m[123] == 2; + m[456] == 3; + s == 1; + } +endclass + +class Assoc2; + rand int unsigned m[string]; + rand int unsigned s; + function new; + m["abc"] = 1; + m["def"] = 1; + endfunction + constraint c { + solve m before s; + m["abc"] == 2; + m["def"] == 3; + s == 1; + } +endclass + +module t; + Assoc o; + Assoc2 o2; + initial begin + o = new; + o2 = new; + void'(o.randomize()); + `checkd(o.m[123], 2); + `checkd(o.m[456], 3); + `checkd(o.s, 1); + + void'(o2.randomize()); + `checkd(o2.m["abc"], 2); + `checkd(o2.m["def"], 3); + `checkd(o2.s, 1); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_constraint_solve_before_assoc_unsup.out b/test_regress/t/t_constraint_solve_before_assoc_unsup.out deleted file mode 100644 index e737b4c63..000000000 --- a/test_regress/t/t_constraint_solve_before_assoc_unsup.out +++ /dev/null @@ -1,6 +0,0 @@ -%Error-UNSUPPORTED: t/t_constraint_solve_before_assoc_unsup.v:11:11: Unsupported: 'solve ... before' with associative array - : ... note: In instance 't' - 11 | solve m before s; - | ^ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error: Exiting due to diff --git a/test_regress/t/t_constraint_solve_before_assoc_unsup.v b/test_regress/t/t_constraint_solve_before_assoc_unsup.v deleted file mode 100644 index fb6c852d2..000000000 --- a/test_regress/t/t_constraint_solve_before_assoc_unsup.v +++ /dev/null @@ -1,24 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain. -// SPDX-FileCopyrightText: 2026 PlanV GmbH -// SPDX-License-Identifier: CC0-1.0 - -class Assoc; - rand int unsigned m[int]; - rand int unsigned s; - constraint c { - solve m before s; - m.size() == 2; - } -endclass - -module t; - Assoc o; - initial begin - o = new; - void'(o.randomize()); - $write("*-* All Finished *-*\n"); - $finish; - end -endmodule