From 7f85d7f45386993e942dd201bb8ec4cf382ffa29 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 20 Sep 2025 09:59:48 -0400 Subject: [PATCH] Add error on localparam value from hierarchical path (#6456). --- Changes | 1 + src/V3Param.cpp | 7 ++++ .../t/t_interface_array_parameter_access.py | 2 +- .../t/t_interface_array_parameter_access.v | 2 +- test_regress/t/t_interface_localparam.v | 2 +- test_regress/t/t_interface_param_acc_bits.py | 2 +- test_regress/t/t_interface_param_acc_bits.v | 2 +- .../t/t_interface_parameter_access.py | 2 +- test_regress/t/t_interface_parameter_access.v | 18 +++++----- test_regress/t/t_param_hier_bad.out | 6 ++++ test_regress/t/t_param_hier_bad.py | 16 +++++++++ test_regress/t/t_param_hier_bad.v | 36 +++++++++++++++++++ 12 files changed, 81 insertions(+), 15 deletions(-) create mode 100644 test_regress/t/t_param_hier_bad.out create mode 100755 test_regress/t/t_param_hier_bad.py create mode 100644 test_regress/t/t_param_hier_bad.v diff --git a/Changes b/Changes index 1bbc39946..a4066df85 100644 --- a/Changes +++ b/Changes @@ -17,6 +17,7 @@ Verilator 5.041 devel * Add configure `--enable-asan` to compile verilator_bin with the address sanitizer (#6404). [Geza Lore] * Add $(LDFLAGS) and $(LIBS) to when building shared libraries (#6425) (#6426). [Ahmed El-Mahmoudy] * Add ASSIGNEQEXPR when use `=` inside expressions (#5567). [Ethan Sifferman] +* Add error on localparam value from hierarchical path (#6456). [Luca Rufer] * Deprecate sensitivity list on public_flat_rw attributes (#6443). [Geza Lore] * Support modports referencing clocking blocks (#4555) (#6436). [Ryszard Rozak, Antmicro Ltd.] * Support pure functions in sensitivity lists (#6393). [Krzysztof Bieganski, Antmicro Ltd.] diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 1de149e8b..0e9bc4457 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -1416,6 +1416,13 @@ class ParamVisitor final : public VNVisitor { if (nodep->user2SetOnce()) return; // Process once iterateChildren(nodep); if (nodep->isParam()) { + // See if any Future before we process + if (nodep->valuep()) + nodep->valuep()->foreach([&](const AstVarXRef* refp) { + refp->v3error("Parameter values cannot be hierarchical" + " (IEEE 1800-2023 6.20.2): " + << nodep->prettyNameQ()); + }); if (!nodep->valuep() && !VN_IS(m_modp, Class)) { nodep->v3error("Parameter without default value is never given value" << " (IEEE 1800-2023 6.20.1): " << nodep->prettyNameQ()); diff --git a/test_regress/t/t_interface_array_parameter_access.py b/test_regress/t/t_interface_array_parameter_access.py index d4f986441..dbdaf4551 100755 --- a/test_regress/t/t_interface_array_parameter_access.py +++ b/test_regress/t/t_interface_array_parameter_access.py @@ -9,7 +9,7 @@ import vltest_bootstrap -test.scenarios('simulator') +test.scenarios('simulator_st') test.compile() diff --git a/test_regress/t/t_interface_array_parameter_access.v b/test_regress/t/t_interface_array_parameter_access.v index 33de01a6a..075ceb3eb 100644 --- a/test_regress/t/t_interface_array_parameter_access.v +++ b/test_regress/t/t_interface_array_parameter_access.v @@ -12,7 +12,7 @@ interface intf endinterface module sub (intf.modp the_intf_port [4]); - localparam int intf_foo = the_intf_port[0].FOO; + const int intf_foo = the_intf_port[0].FOO; initial begin if (intf_foo != 4) $stop; diff --git a/test_regress/t/t_interface_localparam.v b/test_regress/t/t_interface_localparam.v index e7ba1810c..14d129f99 100644 --- a/test_regress/t/t_interface_localparam.v +++ b/test_regress/t/t_interface_localparam.v @@ -35,7 +35,7 @@ module Core( ); // this will constify and valDiv2 will have the default value - localparam valDiv4Upper = intf.valDiv2; + const int valDiv4Upper = intf.valDiv2; SimpleIntf #(.VAL(68)) core_intf (); diff --git a/test_regress/t/t_interface_param_acc_bits.py b/test_regress/t/t_interface_param_acc_bits.py index d4f986441..dbdaf4551 100755 --- a/test_regress/t/t_interface_param_acc_bits.py +++ b/test_regress/t/t_interface_param_acc_bits.py @@ -9,7 +9,7 @@ import vltest_bootstrap -test.scenarios('simulator') +test.scenarios('simulator_st') test.compile() diff --git a/test_regress/t/t_interface_param_acc_bits.v b/test_regress/t/t_interface_param_acc_bits.v index 41ac2bce8..8dc51c0fd 100644 --- a/test_regress/t/t_interface_param_acc_bits.v +++ b/test_regress/t/t_interface_param_acc_bits.v @@ -17,7 +17,7 @@ endinterface module t (); simple_bus sb_intf(); - localparam LP = $bits(sb_intf.payload.data); + const int LP = $bits(sb_intf.payload.data); simple_bus #(.PARAMETER($bits(sb_intf.DUMMY))) simple(); simple_bus #(.PARAMETER($bits(sb_intf.x))) simple2(); initial begin diff --git a/test_regress/t/t_interface_parameter_access.py b/test_regress/t/t_interface_parameter_access.py index d4f986441..dbdaf4551 100755 --- a/test_regress/t/t_interface_parameter_access.py +++ b/test_regress/t/t_interface_parameter_access.py @@ -9,7 +9,7 @@ import vltest_bootstrap -test.scenarios('simulator') +test.scenarios('simulator_st') test.compile() diff --git a/test_regress/t/t_interface_parameter_access.v b/test_regress/t/t_interface_parameter_access.v index 17f353a5c..d56a1fbc1 100644 --- a/test_regress/t/t_interface_parameter_access.v +++ b/test_regress/t/t_interface_parameter_access.v @@ -45,9 +45,9 @@ module t (/*AUTOARG*/ .intf_array (array_interface) ); - localparam THE_TOP_FOO = the_interface.FOO; - localparam THE_TOP_FOO_BITS = $bits({the_interface.FOO, the_interface.FOO}); - localparam THE_ARRAY_FOO = array_interface[0].FOO; + const int THE_TOP_FOO = the_interface.FOO; + const int THE_TOP_FOO_BITS = $bits({the_interface.FOO, the_interface.FOO}); + const int THE_ARRAY_FOO = array_interface[0].FOO; initial begin if (THE_TOP_FOO != 5) begin @@ -75,12 +75,12 @@ module testmod test_if.mp intf_array [1:0] ); - localparam THE_FOO = intf.FOO; - localparam THE_OTHER_FOO = intf_no_mp.FOO; - localparam THE_ARRAY_FOO = intf_array[0].FOO; - localparam THE_BAR = intf.BAR; - localparam THE_OTHER_BAR = intf_no_mp.BAR; - localparam THE_ARRAY_BAR = intf_array[0].BAR; + const int THE_FOO = intf.FOO; + const int THE_OTHER_FOO = intf_no_mp.FOO; + const int THE_ARRAY_FOO = intf_array[0].FOO; + const int THE_BAR = intf.BAR; + const int THE_OTHER_BAR = intf_no_mp.BAR; + const int THE_ARRAY_BAR = intf_array[0].BAR; always @(posedge clk) begin if (THE_FOO != 5) begin diff --git a/test_regress/t/t_param_hier_bad.out b/test_regress/t/t_param_hier_bad.out new file mode 100644 index 000000000..27cb5777f --- /dev/null +++ b/test_regress/t/t_param_hier_bad.out @@ -0,0 +1,6 @@ +%Error: t/t_param_hier_bad.v:26:32: Parameter values cannot be hierarchical (IEEE 1800-2023 6.20.2): 'SUB_Y' + : ... note: In instance 't' + 26 | localparam int SUB_Y = u_sub.Y; + | ^ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: Exiting due to diff --git a/test_regress/t/t_param_hier_bad.py b/test_regress/t/t_param_hier_bad.py new file mode 100755 index 000000000..55203b6c9 --- /dev/null +++ b/test_regress/t/t_param_hier_bad.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2025 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('linter') + +test.lint(fails=True, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_param_hier_bad.v b/test_regress/t/t_param_hier_bad.v new file mode 100644 index 000000000..e9a4d1e6c --- /dev/null +++ b/test_regress/t/t_param_hier_bad.v @@ -0,0 +1,36 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by 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 + +module sub #( + parameter int X = 1 +) (); + + localparam int Y = X; + localparam int Z = X; + +endmodule + +module t; + localparam int MY_X = 2; + + sub #(.X(MY_X)) u_sub (); + + localparam int SUB_Y = u_sub.Y; // <--- BAD: IEEE 1800-2023 6.20.2 no hierarchical + + initial begin + `checkd(SUB_Y, 1); + `checkd(u_sub.X, 2); + `checkd(u_sub.Y, 1); + `checkd(u_sub.Z, 2); + $finish; + end + +endmodule