Fix inherited rand array with .size + foreach constraint (#7650)
Fixes #7558.
This commit is contained in:
parent
f93b4bbd05
commit
6c96ce4b40
|
|
@ -4818,7 +4818,12 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
pinp->addPinsp(namep);
|
||||
pinp->addPinsp(new AstConst{fl, AstConst::Unsized64{},
|
||||
static_cast<uint64_t>(sizeVarp->width())});
|
||||
pinp->addPinsp(new AstVarRef{fl, sizeVarp, VAccess::READ});
|
||||
// sizeVarp may live in a base class when the constrained
|
||||
// array is inherited; route VarRef through its declaring
|
||||
// class so V3Scope can resolve it.
|
||||
AstVarRef* const sizeVarRefp = new AstVarRef{fl, sizeVarp, VAccess::READ};
|
||||
sizeVarRefp->classOrPackagep(VN_AS(sizeVarp->user2p(), NodeModule));
|
||||
pinp->addPinsp(sizeVarRefp);
|
||||
randomizep->addStmtsp(pinp->makeStmt());
|
||||
}
|
||||
|
||||
|
|
@ -5265,12 +5270,18 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
bool wasCreated = false;
|
||||
AstVar* const sizeVarp
|
||||
= createOrGetSizeVar(classp, arrVarp, fl, methodp->findIntDType(), wasCreated);
|
||||
// arrVarp and sizeVarp may live in a base class when the
|
||||
// array is inherited; route VarRefs through their declaring
|
||||
// class so V3Scope can resolve them.
|
||||
AstNodeModule* const arrClassp = VN_AS(arrVarp->user2p(), NodeModule);
|
||||
AstNodeModule* const sizeClassp = VN_AS(sizeVarp->user2p(), NodeModule);
|
||||
if (wasCreated) {
|
||||
// Generate resize for dynamic arrays/queues (not assoc arrays)
|
||||
if (!VN_IS(arrVarp->dtypep()->skipRefp(), AssocArrayDType)) {
|
||||
AstCMethodHard* const resizep = new AstCMethodHard{
|
||||
fl, new AstVarRef{fl, classp, arrVarp, VAccess::READWRITE},
|
||||
VCMethod::DYN_RESIZE, new AstVarRef{fl, sizeVarp, VAccess::READ}};
|
||||
fl, new AstVarRef{fl, arrClassp, arrVarp, VAccess::READWRITE},
|
||||
VCMethod::DYN_RESIZE,
|
||||
new AstVarRef{fl, sizeClassp, sizeVarp, VAccess::READ}};
|
||||
resizep->dtypep(methodp->findVoidDType());
|
||||
inlineResizeStmtsp
|
||||
= AstNode::addNext(inlineResizeStmtsp, new AstStmtExpr{fl, resizep});
|
||||
|
|
@ -5279,7 +5290,8 @@ class RandomizeVisitor final : public VNVisitor {
|
|||
// Append size >= 0 constraint so ConstraintExprVisitor processes it
|
||||
capturedTreep->addNext(createSizeGteZeroConstraint(fl, sizeVarp));
|
||||
}
|
||||
AstVarRef* const sizeVarRefp = new AstVarRef{fl, sizeVarp, VAccess::READ};
|
||||
AstVarRef* const sizeVarRefp
|
||||
= new AstVarRef{fl, sizeClassp, sizeVarp, VAccess::READ};
|
||||
sizeVarRefp->user1(true);
|
||||
methodp->replaceWith(sizeVarRefp);
|
||||
VL_DO_DANGLING(methodp->deleteTree(), methodp);
|
||||
|
|
|
|||
|
|
@ -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,93 @@
|
|||
// 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
|
||||
|
||||
// Scenario A: minimized reproducer from issue #7558 reporter (2026-05-15).
|
||||
// Dynamic array, parameterized virtual class wrapping the rand class,
|
||||
// 3-level extends, randomize() reached indirectly via `req` field.
|
||||
package uvm_pkg;
|
||||
virtual class uvm_sequence #(type REQ = int);
|
||||
REQ req;
|
||||
endclass
|
||||
endpackage
|
||||
|
||||
package s_t_pkg;
|
||||
import uvm_pkg::*;
|
||||
parameter S_D_WIDTH = 64;
|
||||
|
||||
class s_txn_base;
|
||||
rand logic [S_D_WIDTH-1:0] p_d[];
|
||||
rand int d_s_dw;
|
||||
constraint d_s_dw_c {
|
||||
p_d.size() == d_s_dw / 16;
|
||||
d_s_dw inside {[16 : 80]};
|
||||
}
|
||||
endclass
|
||||
|
||||
class s_t_txn extends s_txn_base;
|
||||
constraint d_incremental {
|
||||
foreach (p_d[i]) if (i == 0) p_d[i] == '0;
|
||||
}
|
||||
endclass
|
||||
|
||||
class t_base_sequence extends uvm_sequence#(s_t_txn);
|
||||
endclass
|
||||
|
||||
class t_base_port_seq extends t_base_sequence;
|
||||
endclass
|
||||
|
||||
class p_c_seq extends t_base_port_seq;
|
||||
virtual task body();
|
||||
void'(req.randomize());
|
||||
endtask
|
||||
endclass
|
||||
endpackage
|
||||
|
||||
// Scenario B: same bug class but on a queue (rand int q[$]) -- exercises
|
||||
// the queue dtype dispatch in V3Randomize, distinct from dynamic array.
|
||||
package q_pkg;
|
||||
class q_base;
|
||||
rand int q[$];
|
||||
constraint c_size {q.size() == 3;}
|
||||
endclass
|
||||
|
||||
class q_derived extends q_base;
|
||||
constraint c_inc {foreach (q[i]) q[i] == i * 10;}
|
||||
endclass
|
||||
endpackage
|
||||
|
||||
module t;
|
||||
import s_t_pkg::*;
|
||||
import q_pkg::*;
|
||||
|
||||
initial begin
|
||||
// Scenario A: solomatnikov reproducer
|
||||
static p_c_seq seq = new();
|
||||
seq.req = new();
|
||||
repeat (5) begin
|
||||
seq.body();
|
||||
`checkd(seq.req.p_d.size(), seq.req.d_s_dw / 16)
|
||||
if (seq.req.p_d.size() > 0) `checkd(seq.req.p_d[0], 0)
|
||||
end
|
||||
|
||||
// Scenario B: queue extension
|
||||
begin
|
||||
automatic q_derived qd = new();
|
||||
repeat (5) begin
|
||||
`checkd(qd.randomize(), 1)
|
||||
`checkd(qd.q.size(), 3)
|
||||
foreach (qd.q[i]) `checkd(qd.q[i], i * 10)
|
||||
end
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
Loading…
Reference in New Issue