Fix internal error when derived class calls this.randomize() with inherited rand members (#7229) (#7234)
This commit is contained in:
parent
3ba9077726
commit
5bf1d060c9
|
|
@ -730,6 +730,8 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
AstClass* const m_classp;
|
||||
AstNodeFTask* const m_inlineInitTaskp; // Method to add write_var calls to
|
||||
// (may be null, then new() is used)
|
||||
AstNodeFTask* const m_memberselInitTaskp; // Fallback for membersel write_var when
|
||||
// classp has no randomize() (inherited members)
|
||||
AstVar* const m_genp; // VlRandomizer variable of the class
|
||||
AstVar* m_randModeVarp; // Relevant randmode state variable
|
||||
bool m_wantSingle = false; // Whether to merge constraint expressions with LOGAND
|
||||
|
|
@ -1248,6 +1250,9 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
varp->user3(true);
|
||||
if (membersel) {
|
||||
initTaskp = VN_AS(m_memberMap.findMember(classp, "randomize"), NodeFTask);
|
||||
// Inherited rand members may belong to a base class
|
||||
// that has no randomize(); use the caller's function
|
||||
if (!initTaskp) initTaskp = m_memberselInitTaskp;
|
||||
UASSERT_OBJ(initTaskp, classp, "No randomize() in class");
|
||||
} else {
|
||||
initTaskp = VN_AS(m_memberMap.findMember(classp, "new"), NodeFTask);
|
||||
|
|
@ -2388,9 +2393,11 @@ public:
|
|||
// CONSTRUCTORS
|
||||
explicit ConstraintExprVisitor(AstClass* classp, VMemberMap& memberMap, AstNode* nodep,
|
||||
AstNodeFTask* inlineInitTaskp, AstVar* genp,
|
||||
AstVar* randModeVarp, std::set<std::string>& writtenVars)
|
||||
AstVar* randModeVarp, std::set<std::string>& writtenVars,
|
||||
AstNodeFTask* memberselInitTaskp = nullptr)
|
||||
: m_classp{classp}
|
||||
, m_inlineInitTaskp{inlineInitTaskp}
|
||||
, m_memberselInitTaskp{memberselInitTaskp}
|
||||
, m_genp{genp}
|
||||
, m_randModeVarp{randModeVarp}
|
||||
, m_memberMap{memberMap}
|
||||
|
|
@ -3979,7 +3986,7 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
if (constrp->itemsp()) expandUniqueElementList(constrp->itemsp());
|
||||
if (constrp->itemsp()) lowerDistConstraints(taskp, constrp->itemsp());
|
||||
ConstraintExprVisitor{classp, m_memberMap, constrp->itemsp(), nullptr,
|
||||
genp, randModeVarp, m_writtenVars};
|
||||
genp, randModeVarp, m_writtenVars, randomizep};
|
||||
if (constrp->itemsp()) {
|
||||
taskp->addStmtsp(wrapIfConstraintMode(
|
||||
nodep, constrp, constrp->itemsp()->unlinkFrBackWithNext()));
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
// 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 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
|
||||
|
||||
// Test: this.randomize() called in derived class with inherited rand members
|
||||
// and constraints from base class. Verifies IS_RANDOMIZED propagation and
|
||||
// membersel write_var fallback for ancestor classes.
|
||||
|
||||
class sub_cfg_c;
|
||||
rand bit enabled;
|
||||
constraint defaults {
|
||||
soft enabled == 1'b0;
|
||||
}
|
||||
endclass
|
||||
|
||||
class base_c;
|
||||
rand sub_cfg_c cfg;
|
||||
rand int unsigned watchdog;
|
||||
|
||||
constraint override_cons {
|
||||
cfg.enabled == 1'b1;
|
||||
}
|
||||
|
||||
constraint watchdog_range {
|
||||
watchdog inside {[32'd50:32'd200]};
|
||||
}
|
||||
|
||||
function new();
|
||||
cfg = new();
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
// Derived class: no additional rand members, calls this.randomize()
|
||||
class derived_c extends base_c;
|
||||
function int do_randomize();
|
||||
return this.randomize();
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
// Deep inheritance: grandchild with no rand members
|
||||
class grandchild_c extends derived_c;
|
||||
function int do_rand_deep();
|
||||
return this.randomize();
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
module t;
|
||||
initial begin
|
||||
automatic derived_c d = new();
|
||||
automatic grandchild_c g = new();
|
||||
|
||||
// Test derived class this.randomize()
|
||||
repeat (20) begin
|
||||
`checkd(d.do_randomize(), 1)
|
||||
`checkd(d.cfg.enabled, 1)
|
||||
`checkd(d.watchdog >= 32'd50 && d.watchdog <= 32'd200, 1)
|
||||
end
|
||||
|
||||
// Test deep inheritance this.randomize()
|
||||
repeat (20) begin
|
||||
`checkd(g.do_rand_deep(), 1)
|
||||
`checkd(g.cfg.enabled, 1)
|
||||
`checkd(g.watchdog >= 32'd50 && g.watchdog <= 32'd200, 1)
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
Loading…
Reference in New Issue