Fix for ariane/CVA6 false member call on object error (#7445) (#7450)

Fixes #7445.
This commit is contained in:
em2machine 2026-04-20 12:21:59 -04:00 committed by GitHub
parent f3c63d017a
commit 23ca23b7b5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 150 additions and 9 deletions

View File

@ -58,6 +58,7 @@ Drew Ranck
Drew Taussig
Driss Hafdi
Edgar E. Iglesias
Eric Mejdrich
Eric Müller
Eric Rippey
Eunseo Song

View File

@ -1406,13 +1406,16 @@ class ParamProcessor final {
}
cloneVarp->valuep(exprp->cloneTree(false));
if (AstNodeDType* const origDTypep = modvarp->subDTypep()) {
AstNodeDType* const dtypeClonep = origDTypep->cloneTree(false);
// Inline every param ref so widthing doesn't reach back into the template
// (#7411). Cycle detector for dependent parameters in the same module.
// Attach clone under cloneVarp so the root has a back pointer.
if (cloneVarp->childDTypep())
cloneVarp->childDTypep()->unlinkFrBack()->deleteTree();
cloneVarp->childDTypep(origDTypep->cloneTree(false));
cloneVarp->dtypep(nullptr);
// Inline param refs so widthing doesn't touch the template (#7411).
constexpr int maxSubstIters = 1000;
for (int it = 0; it < maxSubstIters; ++it) {
bool any = false;
dtypeClonep->foreach([&](AstVarRef* varrefp) {
cloneVarp->foreach([&](AstVarRef* varrefp) {
AstVar* const targetp = varrefp->varp();
AstNode* replacep = nullptr;
for (AstPin* pp = paramsp; pp; pp = VN_AS(pp->nextp(), Pin)) {
@ -1432,19 +1435,40 @@ class ParamProcessor final {
any = true;
}
});
// Substitute RefDType to an overridden paramtype. RefDType is
// not a foreach leaf, so collect matches and replace after the
// walk. Reverse order so descendants are replaced before
// ancestors -- replacing an ancestor would free its descendants.
std::vector<std::pair<AstRefDType*, AstNodeDType*>> toReplace;
cloneVarp->foreach([&](AstRefDType* refp) {
AstParamTypeDType* const ptdp
= VN_CAST(refp->refDTypep(), ParamTypeDType);
if (!ptdp) return;
for (AstPin* pp = paramsp; pp; pp = VN_AS(pp->nextp(), Pin)) {
if (pp->modPTypep() == ptdp) {
if (AstNodeDType* const overDtp
= VN_CAST(pp->exprp(), NodeDType)) {
toReplace.emplace_back(refp, overDtp);
}
break;
}
}
});
for (auto it = toReplace.rbegin(); it != toReplace.rend(); ++it) {
AstRefDType* const refp = it->first;
refp->replaceWith(it->second->cloneTree(false));
VL_DO_DANGLING(refp->deleteTree(), refp);
any = true;
}
if (!any) break;
}
// Bail if anything still points at the template.
dtypeClonep->foreach([&](AstVarRef* varrefp) {
cloneVarp->foreach([&](AstVarRef* varrefp) {
varrefp->v3fatalSrc(
"Unresolved VarRef '"
<< varrefp->prettyName() << "' in pin dtype clone. Pin: "
<< pinp->prettyNameQ() << " of " << nodep->prettyNameQ());
});
if (cloneVarp->childDTypep())
cloneVarp->childDTypep()->unlinkFrBack()->deleteTree();
cloneVarp->childDTypep(dtypeClonep);
cloneVarp->dtypep(nullptr);
}
V3Const::constifyParamsEdit(cloneVarp);
if (AstConst* const widthedp = VN_CAST(cloneVarp->valuep(), Const)) {

View File

@ -0,0 +1,18 @@
#!/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')
test.compile(verilator_flags2=["--binary"])
test.execute()
test.passes()

View File

@ -0,0 +1,44 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2026 Wilson Snyder
// SPDX-License-Identifier: CC0-1.0
// Method/member access on a value-parameter whose type is
// the enclosing module's type-parameter.
typedef struct packed {
logic [7:0] S_TIMER;
logic [7:0] M_TIMER;
logic [7:0] M_EXT;
} my_irq_t;
module leaf #(
parameter type interrupts_t = logic,
parameter interrupts_t INTERRUPTS = '0
) ();
logic [7:0] observed;
always_comb observed = INTERRUPTS.M_TIMER;
endmodule
module mid #(
parameter type interrupts_t = logic,
parameter interrupts_t INTERRUPTS = '0
) ();
leaf #(.interrupts_t(interrupts_t), .INTERRUPTS(INTERRUPTS)) l();
endmodule
module t;
localparam type irq_t = my_irq_t;
localparam irq_t IRQ = '{S_TIMER: 8'hAA, M_TIMER: 8'h55, M_EXT: 8'hCC};
mid #(.interrupts_t(irq_t), .INTERRUPTS(IRQ)) m();
initial begin
#1;
if (m.l.observed !== 8'h55) begin
$write("%%Error: observed=%h expected 55\n", m.l.observed);
$stop;
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,18 @@
#!/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')
test.compile(verilator_flags2=["--binary"])
test.execute()
test.passes()

View File

@ -0,0 +1,36 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2026 Wilson Snyder
// SPDX-License-Identifier: CC0-1.0
// verilog_format: off
`define stop $stop
`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
package pkg;
typedef struct packed {
logic [1:0][31:0] bar;
} T;
localparam T t = 64'h87654321_deadbeef;
endpackage
module foo #(
parameter type T = int,
parameter T t = 0
) ();
initial begin
`checkh(t.bar[0], 32'hdeadbeef);
`checkh(t.bar[1], 32'h87654321);
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
module top;
foo #(
.T(pkg::T),
.t(pkg::t)
) u_foo ();
endmodule