diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 1fa1f4919..b26f920fd 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -2368,9 +2368,8 @@ class ConstraintExprVisitor final : public VNVisitor { const std::string smtArrayName = arrVarp->name(); AstNodeDType* elemDtp = arrVarp->dtypep()->skipRefp()->subDTypep(); const int elemWidth = elemDtp->width(); - AstNodeModule* const classModulep = m_classp - ? static_cast(m_classp) - : VN_AS(m_genp->user2p(), NodeModule); + AstNodeModule* const arrModulep = VN_AS(arrVarp->user2p(), NodeModule); + AstNodeModule* const genModulep = VN_AS(m_genp->user2p(), NodeModule); arrVarp->user3(true); // Create variable name using AstSFormatF @@ -2379,7 +2378,7 @@ class ConstraintExprVisitor final : public VNVisitor { // Create array element reference: array.atWrite(index) AstCMethodHard* const atWritep = new AstCMethodHard{ - fl, new AstVarRef{fl, classModulep, arrVarp, VAccess::READWRITE}, + fl, new AstVarRef{fl, arrModulep, arrVarp, VAccess::READWRITE}, VCMethod::ARRAY_AT_WRITE, new AstVarRef{fl, loopVarp, VAccess::READ}}; atWritep->dtypeFrom(elemDtp); @@ -2392,7 +2391,7 @@ class ConstraintExprVisitor final : public VNVisitor { // Create write_var method call: gen.write_var(arrElement, width, name, 0) AstCMethodHard* const writeVarp = new AstCMethodHard{ - fl, new AstVarRef{fl, classModulep, m_genp, VAccess::READWRITE}, + fl, new AstVarRef{fl, genModulep, m_genp, VAccess::READWRITE}, VCMethod::RANDOMIZER_WRITE_VAR, atWritep}; writeVarp->addPinsp(new AstConst{fl, AstConst::WidthedValue{}, 64, static_cast(elemWidth)}); diff --git a/test_regress/t/t_constraint_array_reduction_inherit.py b/test_regress/t/t_constraint_array_reduction_inherit.py new file mode 100755 index 000000000..db1adb3f9 --- /dev/null +++ b/test_regress/t/t_constraint_array_reduction_inherit.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_array_reduction_inherit.v b/test_regress/t/t_constraint_array_reduction_inherit.v new file mode 100644 index 000000000..35389555b --- /dev/null +++ b/test_regress/t/t_constraint_array_reduction_inherit.v @@ -0,0 +1,75 @@ +// 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 + +// Test array reduction methods in constraints with class inheritance (issue #7226) +// The bug was that .sum() in a constraint crashed with "Can't locate varref scope" +// when the class extends another class. +// verilog_format: off +`define stop $stop +`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); +`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); +// verilog_format: on + +class Base; + rand int base_val; + constraint c_base {base_val inside {[1:100]};} +endclass + +// Derived class with dynamic array and .sum() constraint -- the crash scenario +class Derived extends Base; + rand int arr[]; + constraint c_size {arr.size() == 4;} + constraint c_sum {arr.sum() == 200;} + function new(); + arr = new[4]; + endfunction +endclass + +// Multi-level inheritance: ensure deeper hierarchies also work +class GrandChild extends Derived; + rand bit [7:0] extra[3]; + constraint c_extra_or {extra.or() != 0;} +endclass + +module t; + + initial begin + static Derived d = new(); + static GrandChild g = new(); + int sum_check; + + // Test single-level inheritance with .sum() + repeat (5) begin + `checkd(d.randomize(), 1) + `checkd(d.arr.size(), 4) + sum_check = 0; + foreach (d.arr[i]) sum_check += d.arr[i]; + `checkd(sum_check, 200) + `checkd(d.base_val inside {[1:100]}, 1) + end + + // Test multi-level inheritance with reduction on fixed array + repeat (5) begin + bit [7:0] or_check; + `checkd(g.randomize(), 1) + `checkd(g.arr.size(), 4) + sum_check = 0; + foreach (g.arr[i]) sum_check += g.arr[i]; + `checkd(sum_check, 200) + or_check = 0; + foreach (g.extra[i]) or_check |= g.extra[i]; + if (or_check == 0) begin + $write("%%Error: %s:%0d: extra.or() should be nonzero\n", `__FILE__, `__LINE__); + `stop; + end + `checkd(g.base_val inside {[1:100]}, 1) + end + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule