parent
369a315c27
commit
fd7a3f4a16
|
|
@ -1396,8 +1396,7 @@ class ParamProcessor final {
|
||||||
}
|
}
|
||||||
AstConst* const exprp = VN_CAST(pinp->exprp(), Const);
|
AstConst* const exprp = VN_CAST(pinp->exprp(), Const);
|
||||||
AstConst* const origp = VN_CAST(modvarp->valuep(), Const);
|
AstConst* const origp = VN_CAST(modvarp->valuep(), Const);
|
||||||
// Width the pin value to match the port type so that the same
|
// Width the pin to the port's type so equal values hash the same (#5479).
|
||||||
// logical value always produces the same specialization name.
|
|
||||||
AstConst* normedNamep = nullptr;
|
AstConst* normedNamep = nullptr;
|
||||||
if (exprp && !exprp->num().isDouble() && !exprp->num().isString()) {
|
if (exprp && !exprp->num().isDouble() && !exprp->num().isString()) {
|
||||||
AstVar* cloneVarp = modvarp->cloneTree(false);
|
AstVar* cloneVarp = modvarp->cloneTree(false);
|
||||||
|
|
@ -1406,21 +1405,41 @@ class ParamProcessor final {
|
||||||
VL_DO_DANGLING(oldValuep->deleteTree(), oldValuep);
|
VL_DO_DANGLING(oldValuep->deleteTree(), oldValuep);
|
||||||
}
|
}
|
||||||
cloneVarp->valuep(exprp->cloneTree(false));
|
cloneVarp->valuep(exprp->cloneTree(false));
|
||||||
// Clone the dtype and resolve VarRefs to other parameters
|
|
||||||
// with their already-constified pin values (e.g., N-1 in
|
|
||||||
// logic [N-1:0] becomes Const-1 which can be folded).
|
|
||||||
if (AstNodeDType* const origDTypep = modvarp->subDTypep()) {
|
if (AstNodeDType* const origDTypep = modvarp->subDTypep()) {
|
||||||
AstNodeDType* const dtypeClonep = origDTypep->cloneTree(false);
|
AstNodeDType* const dtypeClonep = origDTypep->cloneTree(false);
|
||||||
dtypeClonep->foreach([&](AstVarRef* varrefp) {
|
// Inline every param ref so widthing doesn't reach back into the template
|
||||||
for (AstPin* pp = paramsp; pp; pp = VN_AS(pp->nextp(), Pin)) {
|
// (#7411). Cycle detector for dependent parameters in the same module.
|
||||||
if (pp->modVarp() == varrefp->varp()) {
|
constexpr int maxSubstIters = 1000;
|
||||||
if (AstConst* const constp = VN_CAST(pp->exprp(), Const)) {
|
for (int it = 0; it < maxSubstIters; ++it) {
|
||||||
varrefp->replaceWith(constp->cloneTree(false));
|
bool any = false;
|
||||||
VL_DO_DANGLING(varrefp->deleteTree(), varrefp);
|
dtypeClonep->foreach([&](AstVarRef* varrefp) {
|
||||||
|
AstVar* const targetp = varrefp->varp();
|
||||||
|
AstNode* replacep = nullptr;
|
||||||
|
for (AstPin* pp = paramsp; pp; pp = VN_AS(pp->nextp(), Pin)) {
|
||||||
|
if (pp->modVarp() == targetp) {
|
||||||
|
if (AstConst* const constp = VN_CAST(pp->exprp(), Const)) {
|
||||||
|
replacep = constp->cloneTree(false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
if (!replacep && targetp->valuep()) {
|
||||||
|
replacep = targetp->valuep()->cloneTree(false);
|
||||||
|
}
|
||||||
|
if (replacep) {
|
||||||
|
varrefp->replaceWith(replacep);
|
||||||
|
VL_DO_DANGLING(varrefp->deleteTree(), varrefp);
|
||||||
|
any = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!any) break;
|
||||||
|
}
|
||||||
|
// Bail if anything still points at the template.
|
||||||
|
dtypeClonep->foreach([&](AstVarRef* varrefp) {
|
||||||
|
varrefp->v3fatalSrc(
|
||||||
|
"Unresolved VarRef '"
|
||||||
|
<< varrefp->prettyName() << "' in pin dtype clone. Pin: "
|
||||||
|
<< pinp->prettyNameQ() << " of " << nodep->prettyNameQ());
|
||||||
});
|
});
|
||||||
if (cloneVarp->childDTypep())
|
if (cloneVarp->childDTypep())
|
||||||
cloneVarp->childDTypep()->unlinkFrBack()->deleteTree();
|
cloneVarp->childDTypep()->unlinkFrBack()->deleteTree();
|
||||||
|
|
@ -1429,8 +1448,7 @@ class ParamProcessor final {
|
||||||
}
|
}
|
||||||
V3Const::constifyParamsEdit(cloneVarp);
|
V3Const::constifyParamsEdit(cloneVarp);
|
||||||
if (AstConst* const widthedp = VN_CAST(cloneVarp->valuep(), Const)) {
|
if (AstConst* const widthedp = VN_CAST(cloneVarp->valuep(), Const)) {
|
||||||
// Set the constant's dtype to the port's widthed type
|
// Stamp the port's type on the const so equal values hash the same.
|
||||||
// so identical values hash the same in paramValueNumber.
|
|
||||||
if (cloneVarp->dtypep()) widthedp->dtypep(cloneVarp->dtypep());
|
if (cloneVarp->dtypep()) widthedp->dtypep(cloneVarp->dtypep());
|
||||||
widthedp->unlinkFrBack();
|
widthedp->unlinkFrBack();
|
||||||
normedNamep = widthedp;
|
normedNamep = widthedp;
|
||||||
|
|
|
||||||
|
|
@ -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", "-Wno-WIDTHEXPAND"])
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
// DESCRIPTION: Verilator: Reproducer for issue #7411.
|
||||||
|
//
|
||||||
|
// when V3Param widths a pin value against the port dtype the widthing must not
|
||||||
|
// edit any referenced template vars in place. A dependent localparam like
|
||||||
|
// dirs_lp = dims_p*2+1 must still recompute from the overridden dims_p on
|
||||||
|
// each specialization. (basically - don't poison the template)
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
|
||||||
|
module sub #(
|
||||||
|
parameter int dims_p = 2,
|
||||||
|
parameter int dirs_lp = dims_p*2 + 1,
|
||||||
|
parameter bit [1:0][dirs_lp-1:0][dirs_lp-1:0] matrix_p = '0
|
||||||
|
) ();
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module t;
|
||||||
|
localparam bit [1:0][4:0][4:0] big_matrix = '1;
|
||||||
|
localparam bit [1:0][2:0][2:0] small_matrix = '1;
|
||||||
|
|
||||||
|
// First instance processes matrix_p with the template's default dims_p=2.
|
||||||
|
// Before the fix, this froze dirs_lp on the template at 5.
|
||||||
|
sub #(.matrix_p(big_matrix)) s1 ();
|
||||||
|
|
||||||
|
// Second instance overrides dims_p=1, so dirs_lp must recompute to 3.
|
||||||
|
sub #(.dims_p(1), .matrix_p(small_matrix)) s2 ();
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
if (s1.dirs_lp !== 5) begin
|
||||||
|
$write("%%Error: s1.dirs_lp=%0d expected 5\n", s1.dirs_lp);
|
||||||
|
$stop;
|
||||||
|
end
|
||||||
|
if (s2.dirs_lp !== 3) begin
|
||||||
|
$write("%%Error: s2.dirs_lp=%0d expected 3\n", s2.dirs_lp);
|
||||||
|
$stop;
|
||||||
|
end
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue