Fix constraint_mode()/rand_mode() in constructor being overwritten by init code (#7054)
This commit is contained in:
parent
84350859e0
commit
996a4b6e1a
|
|
@ -2366,12 +2366,28 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
= new AstCMethodHard{fl, new AstVarRef{fl, modeVarModp, modeVarp, VAccess::WRITE},
|
||||
VCMethod::DYN_RESIZE, new AstConst{fl, modeCount}};
|
||||
dynarrayNewp->dtypeSetVoid();
|
||||
AstNodeFTask* const newp = VN_AS(m_memberMap.findMember(classp, "new"), NodeFTask);
|
||||
UASSERT_OBJ(newp, classp, "No new() in class");
|
||||
newp->addStmtsp(dynarrayNewp->makeStmt());
|
||||
newp->addStmtsp(makeModeSetLoop(fl,
|
||||
new AstVarRef{fl, modeVarModp, modeVarp, VAccess::WRITE},
|
||||
new AstConst{fl, 1}, true));
|
||||
AstNodeFTask* const ctorNewp = VN_AS(m_memberMap.findMember(classp, "new"), NodeFTask);
|
||||
UASSERT_OBJ(ctorNewp, classp, "No new() in class");
|
||||
// Build init chain: resize -> set-all-to-1 loop
|
||||
AstNode* const initFirstp = dynarrayNewp->makeStmt();
|
||||
initFirstp->addNext(
|
||||
makeModeSetLoop(fl, new AstVarRef{fl, modeVarModp, modeVarp, VAccess::WRITE},
|
||||
new AstConst{fl, 1}, true));
|
||||
// Prepend init code before user statements in constructor body, but after
|
||||
// var declarations and super.new(). This ensures that user's constraint_mode()
|
||||
// or rand_mode() calls in the constructor execute after mode arrays are initialized.
|
||||
// Pattern from V3LinkDot::addImplicitSuperNewCall.
|
||||
for (AstNode* stmtp = ctorNewp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (!VN_IS(stmtp, NodeStmt)) continue; // Skip var declarations
|
||||
if (const AstStmtExpr* const sep = VN_CAST(stmtp, StmtExpr)) {
|
||||
if (VN_IS(sep->exprp(), New)) continue; // Skip super.new()
|
||||
}
|
||||
// Found first user statement - insert init code before it
|
||||
stmtp->addHereThisAsNext(initFirstp);
|
||||
return;
|
||||
}
|
||||
// No user statements (empty constructor or only var decls/super.new)
|
||||
ctorNewp->addStmtsp(initFirstp);
|
||||
}
|
||||
void makeStaticModeInit(AstVar* modeVarp, AstClass* classp, uint32_t modeCount) {
|
||||
// For static constraint mode, we need lazy initialization since it's shared across
|
||||
|
|
|
|||
|
|
@ -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,47 @@
|
|||
// 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 constraint_mode() called inside class constructor (function new)
|
||||
|
||||
class ConstraintModeInCtor;
|
||||
rand bit [7:0] value;
|
||||
|
||||
constraint low_range_c { value < 50; };
|
||||
constraint high_range_c { value >= 50; value < 200; };
|
||||
|
||||
function new;
|
||||
// Disable high_range_c in constructor - only low_range_c should be active
|
||||
high_range_c.constraint_mode(0);
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
module t;
|
||||
initial begin
|
||||
automatic ConstraintModeInCtor obj = new;
|
||||
automatic int i;
|
||||
|
||||
// Test 1: constraint_mode(0) in constructor should disable constraint
|
||||
for (i = 0; i < 20; i++) begin
|
||||
void'(obj.randomize());
|
||||
if (obj.value >= 50) $stop;
|
||||
end
|
||||
|
||||
// Test 2: Query constraint_mode state set in constructor
|
||||
if (obj.low_range_c.constraint_mode != 1) $stop;
|
||||
if (obj.high_range_c.constraint_mode != 0) $stop;
|
||||
|
||||
// Test 3: Switch constraints at runtime
|
||||
obj.low_range_c.constraint_mode(0);
|
||||
obj.high_range_c.constraint_mode(1);
|
||||
for (i = 0; i < 20; i++) begin
|
||||
void'(obj.randomize());
|
||||
if (obj.value < 50 || obj.value >= 200) $stop;
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
Loading…
Reference in New Issue