diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 3e4e960d5..eac1fc1f5 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -1442,9 +1442,19 @@ class ParamProcessor final { // Cast/CastSize default values are not yet folded by V3Width. // Constify here so the comparison below sees a Const node. // Other node kinds are handled in the branches above. + // + // Only fold when the cast is self-contained. modvarp is the + // parameter on the shared module template and constifyParamsEdit + // is destructive: a default that reads another parameter + // (VarRef) or a type parameter (RefDType) must be evaluated per + // instance, and folding it here would evaluate it against the + // template's own defaults and bake that in for every later + // instance that relies on the default. if (modvarp->valuep() && (VN_IS(modvarp->valuep(), Cast) || VN_IS(modvarp->valuep(), CastSize))) { - V3Const::constifyParamsEdit(modvarp->valuep()); + const bool dependent = modvarp->valuep()->exists( + [](AstNode* np) { return VN_IS(np, VarRef) || VN_IS(np, RefDType); }); + if (!dependent) V3Const::constifyParamsEdit(modvarp->valuep()); } UINFO(9, "cellPinCleanup: after constify " << pinp); // String constants are parsed as logic arrays and converted to strings in V3Const. diff --git a/test_regress/t/t_param_cast_default_struct.py b/test_regress/t/t_param_cast_default_struct.py new file mode 100755 index 000000000..6fe7d000c --- /dev/null +++ b/test_regress/t/t_param_cast_default_struct.py @@ -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() diff --git a/test_regress/t/t_param_cast_default_struct.v b/test_regress/t/t_param_cast_default_struct.v new file mode 100644 index 000000000..263f6f6aa --- /dev/null +++ b/test_regress/t/t_param_cast_default_struct.v @@ -0,0 +1,35 @@ +// 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 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 + +// A parameter whose default is a cast of a member of a struct-typed +// parameter. + +typedef struct packed {int unsigned CAP;} cfg_t; + +module m #( + parameter cfg_t cfg = '{CAP: 0}, + parameter int unsigned p_cap = int'(cfg.CAP) +); +endmodule + +module t; + localparam cfg_t c = '{CAP: 32}; + + m #(.cfg(c), .p_cap(64)) u_over (); // explicit override, elaborated first + m #(.cfg(c)) u_dflt (); // takes the default: int'(cfg.CAP) == 32 + + initial begin + `checkd(u_over.p_cap, 64); + `checkd(u_dflt.p_cap, 32); // 0 before the fix + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule