Fixes #7431.
This commit is contained in:
parent
3587ac48a4
commit
72952fd3fb
|
|
@ -107,7 +107,7 @@ class LinkWithVisitor final : public VNVisitor {
|
|||
}
|
||||
|
||||
void visit(AstMemberSel* nodep) override {
|
||||
if (m_inRandomizeWith && nodep->fromp()->isSame(m_currentRandomizeSelectp)) {
|
||||
if (m_inRandomizeWith && nodep->fromp()->sameTree(m_currentRandomizeSelectp)) {
|
||||
// Replace member selects to the element
|
||||
// on which the randomize() is called with LambdaArgRef
|
||||
// This allows V3Randomize to work properly when
|
||||
|
|
|
|||
|
|
@ -753,6 +753,7 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
// (used to format "%s.%s" for struct arrays)
|
||||
std::set<std::string>& m_writtenVars; // Track which variable paths have write_var generated
|
||||
// (shared across all constraints)
|
||||
std::set<std::string> m_inlineWrittenVars; // Per-instance tracking for inline constraints
|
||||
std::set<AstVar*>* m_sizeConstrainedArraysp = nullptr; // Arrays with size+element constraints
|
||||
|
||||
// Build full path for a MemberSel chain (e.g., "obj.l2.l3.l4")
|
||||
|
|
@ -1133,14 +1134,17 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||
// else: Global constraints keep nodep alive for write_var processing
|
||||
relinker.relink(exprp);
|
||||
|
||||
// For global constraints: check if this specific path has been written
|
||||
// For normal constraints: only call write_var if varp->user3() is not set
|
||||
const bool alreadyWritten
|
||||
= isGlobalConstrained ? m_writtenVars.count(smtName) > 0 : varp->user3();
|
||||
// For global constraints: check shared path-level set
|
||||
// For inline constraints: check per-instance set (each __Vrandwith has own randomizer)
|
||||
// For class-level constraints: check varp->user3()
|
||||
const bool alreadyWritten = isGlobalConstrained ? m_writtenVars.count(smtName) > 0
|
||||
: m_inlineInitTaskp ? m_inlineWrittenVars.count(smtName) > 0
|
||||
: varp->user3();
|
||||
const bool shouldWriteVar = !alreadyWritten;
|
||||
if (shouldWriteVar) {
|
||||
// Track this variable path as written
|
||||
if (isGlobalConstrained) m_writtenVars.insert(smtName);
|
||||
if (m_inlineInitTaskp) m_inlineWrittenVars.insert(smtName);
|
||||
// For global constraints, delete nodep after processing
|
||||
if (isGlobalConstrained && !nodep->backp()) VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ endclass
|
|||
|
||||
module t;
|
||||
OuterDyn od;
|
||||
OuterDyn od_arr[5];
|
||||
OuterQueue oq;
|
||||
|
||||
initial begin
|
||||
|
|
@ -104,6 +105,29 @@ module t;
|
|||
end
|
||||
end
|
||||
|
||||
// === Test 4: Array of objects with inline constraint for sub-object members ===
|
||||
// Verifies member resolution AND runtime enforcement when randomize()
|
||||
// target is array-indexed (regression test for verilator/verilator#7431)
|
||||
foreach (od_arr[i]) begin
|
||||
od_arr[i] = new(3);
|
||||
assert(od_arr[i].randomize() with {
|
||||
od_arr[i].items[0].val > 8'd10;
|
||||
od_arr[i].items[0].val < 8'd200;
|
||||
od_arr[i].items[0].tag > 0;
|
||||
} != 0);
|
||||
|
||||
if (!(od_arr[i].items[0].val > 10 && od_arr[i].items[0].val < 200)) begin
|
||||
$display("FAIL: od_arr[%0d].items[0].val=%0d out of range",
|
||||
i, od_arr[i].items[0].val);
|
||||
$stop;
|
||||
end
|
||||
if (od_arr[i].items[0].tag == 0) begin
|
||||
$display("FAIL: od_arr[%0d].items[0].tag=%0d should be > 0",
|
||||
i, od_arr[i].items[0].tag);
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue