diff --git a/docs/gen/ex_HIERPARAM_faulty.rst b/docs/gen/ex_HIERPARAM_faulty.rst new file mode 100644 index 000000000..343e9cac6 --- /dev/null +++ b/docs/gen/ex_HIERPARAM_faulty.rst @@ -0,0 +1,8 @@ +.. comment: generated by t_param_hier_bad +.. code-block:: sv + :linenos: + :emphasize-lines: 3 + + sub #(.X(MY_X)) u_sub (); + + localparam int SUB_Y = u_sub.Y; // <--- BAD: IEEE 1800-2023 6.20.2 no hierarchical diff --git a/docs/gen/ex_HIERPARAM_msg.rst b/docs/gen/ex_HIERPARAM_msg.rst new file mode 100644 index 000000000..43d2b035d --- /dev/null +++ b/docs/gen/ex_HIERPARAM_msg.rst @@ -0,0 +1,7 @@ +.. comment: generated by t_param_hier_bad +.. code-block:: + + %Error-HIERPARAM: example.v:1:32 Parameter values cannot use hierarchical values (IEEE 1800-2023 6.20.2) + : ... note: In instance 't' + 36 | localparam int SUB_Y = u_sub.Y; + | ^ diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index ce8bf3d7f..1d3efd556 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -896,6 +896,25 @@ List Of Warnings This setting on the top module will be ignored. +.. option:: HIERPARAM + + An error that a hierarchical value or function is being used to assign a parameter. + IEEE 1800-2023 6.20.2 requires this error. + + Faulty example: + + .. include:: ../../docs/gen/ex_HIERPARAM_faulty.rst + + Results in: + + .. include:: ../../docs/gen/ex_HIERPARAM_msg.rst + + Suppressing this error may allow some hierarchical references to work (especially hierarchical + references into interface references), however not all cases are possible, e.g. it cannot + reference the parameter of a lower module in a way that affects determining the parameters + that elaborate that lower module. + + .. option:: IFDEPTH Warns that if/if else statements have exceeded the depth specified with diff --git a/src/V3Error.h b/src/V3Error.h index 280656e0d..6fbf2fdc6 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -108,6 +108,7 @@ public: GENCLK, // Generated Clock. Historical, never issued. GENUNNAMED, // Generate unnamed, without label HIERBLOCK, // Ignored hierarchical block setting + HIERPARAM, // Parameter using hierarchical value IFDEPTH, // If statements too deep IGNOREDRETURN, // Ignoring return value (function as task) IMPERFECTSCH, // Imperfect schedule (disabled by default). Historical, never issued. @@ -213,19 +214,19 @@ public: "CDCRSTLOGIC", "CLKDATA", "CMPCONST", "COLONPLUS", "COMBDLY", "CONSTRAINTIGN", "CONTASSREG", "COVERIGN", "DECLFILENAME", "DEFOVERRIDE", "DEFPARAM", "DEPRECATED", "ENCAPSULATED", "ENDLABEL", "ENUMITEMWIDTH", "ENUMVALUE", "EOFNEWLINE", "GENCLK", - "GENUNNAMED", "HIERBLOCK", "IFDEPTH", "IGNOREDRETURN", "IMPERFECTSCH", "IMPLICIT", - "IMPLICITSTATIC", "IMPORTSTAR", "IMPURE", "INCABSPATH", "INFINITELOOP", "INITIALDLY", - "INSECURE", "LATCH", "LITENDIAN", "MINTYPMAXDLY", "MISINDENT", "MODDUP", "MODMISSING", - "MULTIDRIVEN", "MULTITOP", "NEWERSTD", "NOEFFECT", "NOLATCH", "NONSTD", "NULLPORT", - "PARAMNODEFAULT", "PINCONNECTEMPTY", "PINMISSING", "PINNOCONNECT", "PINNOTFOUND", - "PKGNODECL", "PREPROCZERO", "PROCASSINIT", "PROCASSWIRE", "PROFOUTOFDATE", "PROTECTED", - "PROTOTYPEMIS", "RANDC", "REALCVT", "REDEFMACRO", "RISEFALLDLY", "SELRANGE", - "SHORTREAL", "SIDEEFFECT", "SPECIFYIGN", "SPLITVAR", "STATICVAR", "STMTDLY", - "SYMRSVDWORD", "SYNCASYNCNET", "TICKCOUNT", "TIMESCALEMOD", "UNDRIVEN", "UNOPT", - "UNOPTFLAT", "UNOPTTHREADS", "UNPACKED", "UNSIGNED", "UNUSEDGENVAR", "UNUSEDLOOP", - "UNUSEDPARAM", "UNUSEDSIGNAL", "USERERROR", "USERFATAL", "USERINFO", "USERWARN", - "VARHIDDEN", "WAITCONST", "WIDTH", "WIDTHCONCAT", "WIDTHEXPAND", "WIDTHTRUNC", - "WIDTHXZEXPAND", "ZERODLY", "ZEROREPL", " MAX"}; + "GENUNNAMED", "HIERBLOCK", "HIERPARAM", "IFDEPTH", "IGNOREDRETURN", "IMPERFECTSCH", + "IMPLICIT", "IMPLICITSTATIC", "IMPORTSTAR", "IMPURE", "INCABSPATH", "INFINITELOOP", + "INITIALDLY", "INSECURE", "LATCH", "LITENDIAN", "MINTYPMAXDLY", "MISINDENT", "MODDUP", + "MODMISSING", "MULTIDRIVEN", "MULTITOP", "NEWERSTD", "NOEFFECT", "NOLATCH", "NONSTD", + "NULLPORT", "PARAMNODEFAULT", "PINCONNECTEMPTY", "PINMISSING", "PINNOCONNECT", + "PINNOTFOUND", "PKGNODECL", "PREPROCZERO", "PROCASSINIT", "PROCASSWIRE", + "PROFOUTOFDATE", "PROTECTED", "PROTOTYPEMIS", "RANDC", "REALCVT", "REDEFMACRO", + "RISEFALLDLY", "SELRANGE", "SHORTREAL", "SIDEEFFECT", "SPECIFYIGN", "SPLITVAR", + "STATICVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET", "TICKCOUNT", "TIMESCALEMOD", + "UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS", "UNPACKED", "UNSIGNED", + "UNUSEDGENVAR", "UNUSEDLOOP", "UNUSEDPARAM", "UNUSEDSIGNAL", "USERERROR", "USERFATAL", + "USERINFO", "USERWARN", "VARHIDDEN", "WAITCONST", "WIDTH", "WIDTHCONCAT", + "WIDTHEXPAND", "WIDTHTRUNC", "WIDTHXZEXPAND", "ZERODLY", "ZEROREPL", " MAX"}; return names[m_e]; } // Warnings that default to off @@ -252,10 +253,10 @@ public: bool pretendError() const VL_MT_SAFE { return (m_e == ASSIGNIN || m_e == BADSTDPRAGMA || m_e == BADVLTPRAGMA || m_e == BLKANDNBLK || m_e == BLKLOOPINIT || m_e == CONTASSREG || m_e == ENCAPSULATED - || m_e == ENDLABEL || m_e == ENUMITEMWIDTH || m_e == ENUMVALUE || m_e == IMPURE - || m_e == MODMISSING || m_e == PARAMNODEFAULT || m_e == PINNOTFOUND - || m_e == PKGNODECL || m_e == PROCASSWIRE || m_e == PROTOTYPEMIS - || m_e == ZEROREPL // Says IEEE + || m_e == ENDLABEL || m_e == ENUMITEMWIDTH || m_e == ENUMVALUE || m_e == HIERPARAM + || m_e == IMPURE || m_e == MODMISSING || m_e == PARAMNODEFAULT + || m_e == PINNOTFOUND || m_e == PKGNODECL || m_e == PROCASSWIRE + || m_e == PROTOTYPEMIS || m_e == ZEROREPL // Says IEEE ); } // Warnings to mention manual diff --git a/src/V3Param.cpp b/src/V3Param.cpp index fe8973ec4..7dc98ff91 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -1361,8 +1361,8 @@ class ParamVisitor final : public VNVisitor { if (!valuep) return; valuep->foreachAndNext([&](const AstNodeExpr* exprp) { if (const AstVarXRef* refp = VN_CAST(exprp, VarXRef)) { - refp->v3error("Parameter values cannot use hierarchical values" - " (IEEE 1800-2023 6.20.2)"); + refp->v3warn(HIERPARAM, "Parameter values cannot use hierarchical values" + " (IEEE 1800-2023 6.20.2)"); } else if (const AstNodeFTaskRef* refp = VN_CAST(exprp, NodeFTaskRef)) { if (refp->dotted() != "") { refp->v3error("Parameter values cannot call hierarchical functions" diff --git a/test_regress/t/t_interface_array_parameter_access.v b/test_regress/t/t_interface_array_parameter_access.v index 075ceb3eb..27ce16119 100644 --- a/test_regress/t/t_interface_array_parameter_access.v +++ b/test_regress/t/t_interface_array_parameter_access.v @@ -12,7 +12,9 @@ interface intf endinterface module sub (intf.modp the_intf_port [4]); - const int intf_foo = the_intf_port[0].FOO; + // verilator lint_off HIERPARAM + localparam intf_foo = the_intf_port[0].FOO; + // verilator lint_on HIERPARAM 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 14d129f99..d6d8a06ad 100644 --- a/test_regress/t/t_interface_localparam.v +++ b/test_regress/t/t_interface_localparam.v @@ -35,7 +35,9 @@ module Core( ); // this will constify and valDiv2 will have the default value - const int valDiv4Upper = intf.valDiv2; + // verilator lint_off HIERPARAM + localparam valDiv4Upper = intf.valDiv2; + // verilator lint_on HIERPARAM SimpleIntf #(.VAL(68)) core_intf (); diff --git a/test_regress/t/t_interface_param_another_bad.out b/test_regress/t/t_interface_param_another_bad.out index 26ce6bf02..4d558d4f3 100644 --- a/test_regress/t/t_interface_param_another_bad.out +++ b/test_regress/t/t_interface_param_another_bad.out @@ -1,12 +1,13 @@ -%Error: t/t_interface_param_another_bad.v:9:36: Parameter values cannot use hierarchical values (IEEE 1800-2023 6.20.2) - : ... note: In instance 't' +%Error-HIERPARAM: t/t_interface_param_another_bad.v:9:36: Parameter values cannot use hierarchical values (IEEE 1800-2023 6.20.2) + : ... note: In instance 't' 9 | simple_bus #(.PARAMETER(sb_intf.dummy)) simple(); | ^~~~~ - ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. + ... For error description see https://verilator.org/warn/HIERPARAM?v=latest %Error: t/t_interface_param_another_bad.v:9:36: Expecting expression to be constant, but variable isn't const: 'dummy' : ... note: In instance 't' 9 | simple_bus #(.PARAMETER(sb_intf.dummy)) simple(); | ^~~~~ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. %Error: t/t_interface_param_another_bad.v:9:18: Can't convert defparam value to constant: Param 'PARAMETER' of 'simple' : ... note: In instance 't' 9 | simple_bus #(.PARAMETER(sb_intf.dummy)) simple(); diff --git a/test_regress/t/t_interface_parameter_access.v b/test_regress/t/t_interface_parameter_access.v index d56a1fbc1..cd3851c48 100644 --- a/test_regress/t/t_interface_parameter_access.v +++ b/test_regress/t/t_interface_parameter_access.v @@ -45,9 +45,11 @@ module t (/*AUTOARG*/ .intf_array (array_interface) ); - 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; + // verilator lint_off HIERPARAM + 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; + // verilator lint_on HIERPARAM initial begin if (THE_TOP_FOO != 5) begin @@ -75,12 +77,14 @@ module testmod test_if.mp intf_array [1:0] ); - 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; + // verilator lint_off HIERPARAM + 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; + // verilator lint_on HIERPARAM 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 index 2eda267b2..c585a052c 100644 --- a/test_regress/t/t_param_hier_bad.out +++ b/test_regress/t/t_param_hier_bad.out @@ -1,12 +1,13 @@ -%Error: t/t_param_hier_bad.v:36:32: Parameter values cannot use hierarchical values (IEEE 1800-2023 6.20.2) - : ... note: In instance 't' +%Error-HIERPARAM: t/t_param_hier_bad.v:36:32: Parameter values cannot use hierarchical values (IEEE 1800-2023 6.20.2) + : ... note: In instance 't' 36 | localparam int SUB_Y = u_sub.Y; | ^ - ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. + ... For error description see https://verilator.org/warn/HIERPARAM?v=latest %Error: t/t_param_hier_bad.v:38:35: Parameter values cannot call hierarchical functions (IEEE 1800-2023 6.20.2) : ... note: In instance 't' 38 | localparam int SUB_FUNC = u_sub.sub_func(); | ^~~~~~~~ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. %Error: t/t_param_hier_bad.v:44:18: Parameter values cannot call hierarchical functions (IEEE 1800-2023 6.20.2) : ... note: In instance 't' 44 | sub #(.X(block.block_func())) u_sub2 (); diff --git a/test_regress/t/t_param_hier_bad.py b/test_regress/t/t_param_hier_bad.py index 55203b6c9..d77bef2fb 100755 --- a/test_regress/t/t_param_hier_bad.py +++ b/test_regress/t/t_param_hier_bad.py @@ -11,6 +11,17 @@ import vltest_bootstrap test.scenarios('linter') +if not os.path.exists(test.root + "/.git"): + test.skip("Not in a git repository") + test.lint(fails=True, expect_filename=test.golden_filename) +test.extract(in_filename=test.top_filename, + out_filename=test.root + "/docs/gen/ex_HIERPARAM_faulty.rst", + lines="34-36") + +test.extract(in_filename=test.golden_filename, + out_filename=test.root + "/docs/gen/ex_HIERPARAM_msg.rst", + lines="1-4") + test.passes()