From a660fa54a703d5131782da2c04ab6cd6d38124fc Mon Sep 17 00:00:00 2001 From: Igor Zaworski Date: Mon, 9 Feb 2026 15:56:38 +0100 Subject: [PATCH] Fix unique constraint in derived class (#7022) --- src/V3Randomize.cpp | 34 ++++++++++--- .../t/t_constraint_unq_arr_derived.py | 21 ++++++++ test_regress/t/t_constraint_unq_arr_derived.v | 51 +++++++++++++++++++ ...onstraint_unq_arr_derived_inline_unsup.out | 7 +++ ...constraint_unq_arr_derived_inline_unsup.py | 16 ++++++ ..._constraint_unq_arr_derived_inline_unsup.v | 39 ++++++++++++++ .../t/t_std_randomize_unsup_unq_arr.out | 7 +++ .../t/t_std_randomize_unsup_unq_arr.py | 16 ++++++ .../t/t_std_randomize_unsup_unq_arr.v | 14 +++++ 9 files changed, 198 insertions(+), 7 deletions(-) create mode 100755 test_regress/t/t_constraint_unq_arr_derived.py create mode 100644 test_regress/t/t_constraint_unq_arr_derived.v create mode 100644 test_regress/t/t_constraint_unq_arr_derived_inline_unsup.out create mode 100755 test_regress/t/t_constraint_unq_arr_derived_inline_unsup.py create mode 100644 test_regress/t/t_constraint_unq_arr_derived_inline_unsup.v create mode 100644 test_regress/t/t_std_randomize_unsup_unq_arr.out create mode 100755 test_regress/t/t_std_randomize_unsup_unq_arr.py create mode 100644 test_regress/t/t_std_randomize_unsup_unq_arr.v diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 2a4dd3d8a..8b34004c5 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -1339,15 +1339,34 @@ class ConstraintExprVisitor final : public VNVisitor { VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } void visit(AstConstraintUnique* nodep) override { - if (!m_classp) return; + if (!m_classp) { + nodep->v3warn(CONSTRAINTIGN, + "Unsupported: Unique constraint in std::randomize() with {}"); + pushDeletep(nodep->unlinkFrBack()); + return; + } + UASSERT_OBJ(m_classp, nodep, "m_classp not set"); FileLine* const fl = nodep->fileline(); AstNodeFTask* const initTaskp = VN_AS(m_memberMap.findMember(m_classp, "new"), NodeFTask); - if (!initTaskp) return; + UASSERT_OBJ(initTaskp, nodep, "Class has no init Task"); - AstVar* const genVarp = VN_AS(m_classp->user3p(), Var); - if (!genVarp) return; + AstVar* const genVarp = [](const AstClass* classp) { + while (classp->extendsp()) classp = classp->extendsp()->classp(); + return VN_AS(classp->user3p(), Var); + }(m_classp); + + // UASSERT_OBJ(genVarp, nodep, "No generator variable"); + if (!genVarp) { + // This shall be substituted with an assert when it will be supported + nodep->v3warn(CONSTRAINTIGN, "Unsupported: Unique constraint in randomize() with {}"); + pushDeletep(nodep->unlinkFrBack()); + return; + } + + AstNodeModule* const modp = VN_AS(genVarp->user2p(), NodeModule); + UASSERT_OBJ(modp, nodep, "genVarp has no NodeModule set"); for (AstNode* itemp = nodep->rangesp(); itemp; itemp = itemp->nextp()) { if (AstVarRef* const varRefp = VN_CAST(itemp, VarRef)) { @@ -1380,8 +1399,9 @@ class ConstraintExprVisitor final : public VNVisitor { continue; } - AstCMethodHard* const wCallp = new AstCMethodHard{ - fl, new AstVarRef{fl, genVarp, VAccess::READ}, VCMethod::RANDOMIZER_WRITE_VAR}; + AstCMethodHard* const wCallp + = new AstCMethodHard{fl, new AstVarRef{fl, modp, genVarp, VAccess::READ}, + VCMethod::RANDOMIZER_WRITE_VAR}; wCallp->addPinsp(new AstVarRef{fl, varp, VAccess::READ}); wCallp->addPinsp(new AstConst{fl, AstConst::Unsized64{}, static_cast(varp->dtypep()->width())}); @@ -1406,7 +1426,7 @@ class ConstraintExprVisitor final : public VNVisitor { uPins->addNext(new AstConst{fl, arraySize}); AstCMethodHard* const uCallp - = new AstCMethodHard{fl, new AstVarRef{fl, genVarp, VAccess::READ}, + = new AstCMethodHard{fl, new AstVarRef{fl, modp, genVarp, VAccess::READ}, VCMethod::RANDOMIZER_UNIQUE, uPins}; uCallp->dtypep(nodep->findVoidDType()); initTaskp->addStmtsp(new AstStmtExpr{fl, uCallp}); diff --git a/test_regress/t/t_constraint_unq_arr_derived.py b/test_regress/t/t_constraint_unq_arr_derived.py new file mode 100755 index 000000000..db1adb3f9 --- /dev/null +++ b/test_regress/t/t_constraint_unq_arr_derived.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# 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() diff --git a/test_regress/t/t_constraint_unq_arr_derived.v b/test_regress/t/t_constraint_unq_arr_derived.v new file mode 100644 index 000000000..edc421833 --- /dev/null +++ b/test_regress/t/t_constraint_unq_arr_derived.v @@ -0,0 +1,51 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain +// SPDX-FileCopyrightText: 2026 Antmicro +// SPDX-License-Identifier: CC0-1.0 + +typedef enum bit [4:0] { + ZERO = 5'b00000, + RA, SP, GP, TP, T0, T1, T2, S0, S1, A0, A1, A2, A3, A4, A5, A6, A7, + S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, T3, T4, T5, T6 +} EnumType; + +class Base; + rand EnumType b_scratch_reg; + rand EnumType b_pmp_reg[2]; + rand EnumType b_sp; + rand EnumType b_tp; + + constraint b_example_constraint { + unique {b_pmp_reg}; + {b_pmp_reg[0] > 0}; + {b_pmp_reg[0] < 3}; + {b_pmp_reg[1] > 0}; + {b_pmp_reg[1] < 3}; + } +endclass + +class Foo extends Base; + rand EnumType scratch_reg; + rand EnumType pmp_reg[2]; + rand EnumType sp; + rand EnumType tp; + + constraint example_constraint { + unique {pmp_reg}; + {pmp_reg[0] > 0}; + {pmp_reg[0] < 3}; + {pmp_reg[1] > 0}; + {pmp_reg[1] < 3}; + } +endclass + +module t; + Foo foo; + initial begin + foo = new; + repeat(100) if (foo.randomize() != 1 || foo.pmp_reg[0] == foo.pmp_reg[1]) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_constraint_unq_arr_derived_inline_unsup.out b/test_regress/t/t_constraint_unq_arr_derived_inline_unsup.out new file mode 100644 index 000000000..6ab6318f2 --- /dev/null +++ b/test_regress/t/t_constraint_unq_arr_derived_inline_unsup.out @@ -0,0 +1,7 @@ +%Warning-CONSTRAINTIGN: t/t_constraint_unq_arr_derived_inline_unsup.v:32:7: Unsupported: Unique constraint in randomize() with {} + : ... note: In instance 't' + 32 | unique{foo.pmp_reg}; + | ^~~~~~ + ... 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. +%Error: Exiting due to diff --git a/test_regress/t/t_constraint_unq_arr_derived_inline_unsup.py b/test_regress/t/t_constraint_unq_arr_derived_inline_unsup.py new file mode 100755 index 000000000..18ef27714 --- /dev/null +++ b/test_regress/t/t_constraint_unq_arr_derived_inline_unsup.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('vlt') + +test.lint(fails=test.vlt_all, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_constraint_unq_arr_derived_inline_unsup.v b/test_regress/t/t_constraint_unq_arr_derived_inline_unsup.v new file mode 100644 index 000000000..e63e5b659 --- /dev/null +++ b/test_regress/t/t_constraint_unq_arr_derived_inline_unsup.v @@ -0,0 +1,39 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain +// SPDX-FileCopyrightText: 2026 Antmicro +// SPDX-License-Identifier: CC0-1.0 + +typedef enum bit [4:0] { + ZERO = 5'b00000, + RA, SP, GP, TP, T0, T1, T2, S0, S1, A0, A1, A2, A3, A4, A5, A6, A7, + S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, T3, T4, T5, T6 +} EnumType; + +class Base; + rand EnumType b_scratch_reg; + rand EnumType b_pmp_reg[2]; + rand EnumType b_sp; + rand EnumType b_tp; +endclass + +class Foo extends Base; + rand EnumType scratch_reg; + rand EnumType pmp_reg[2]; + rand EnumType sp; + rand EnumType tp; +endclass + +module t; + Foo foo; + initial begin + foo = new; + repeat(100) if (foo.randomize() with { + unique{foo.pmp_reg}; + foo.pmp_reg[0] inside {1,2}; + foo.pmp_reg[1] inside {1,2};} + != 1 || foo.pmp_reg[0] == foo.pmp_reg[1]) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_std_randomize_unsup_unq_arr.out b/test_regress/t/t_std_randomize_unsup_unq_arr.out new file mode 100644 index 000000000..978589179 --- /dev/null +++ b/test_regress/t/t_std_randomize_unsup_unq_arr.out @@ -0,0 +1,7 @@ +%Warning-CONSTRAINTIGN: t/t_std_randomize_unsup_unq_arr.v:10:39: Unsupported: Unique constraint in std::randomize() with {} + : ... note: In instance 't' + 10 | if (!bit'(std::randomize(x) with {unique{x};}) || x[0] == x[1]) $stop; + | ^~~~~~ + ... 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. +%Error: Exiting due to diff --git a/test_regress/t/t_std_randomize_unsup_unq_arr.py b/test_regress/t/t_std_randomize_unsup_unq_arr.py new file mode 100755 index 000000000..18ef27714 --- /dev/null +++ b/test_regress/t/t_std_randomize_unsup_unq_arr.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('vlt') + +test.lint(fails=test.vlt_all, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_std_randomize_unsup_unq_arr.v b/test_regress/t/t_std_randomize_unsup_unq_arr.v new file mode 100644 index 000000000..fa71c27db --- /dev/null +++ b/test_regress/t/t_std_randomize_unsup_unq_arr.v @@ -0,0 +1,14 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain +// SPDX-FileCopyrightText: 2026 Antmicro +// SPDX-License-Identifier: CC0-1.0 + +module t; + initial begin + bit x[2]; + if (!bit'(std::randomize(x) with {unique{x};}) || x[0] == x[1]) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule