diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index d6d70fef2..ed77ba41e 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -47,6 +47,8 @@ class LinkResolveVisitor final : public VNVisitor { // Below state needs to be preserved between each module call. AstNodeModule* m_modp = nullptr; // Current module AstClass* m_classp = nullptr; // Class we're inside + string m_randcIllegalWhy; // Why randc illegal + AstNode* m_randcIllegalp = nullptr; // Node causing randc illegal AstNodeFTask* m_ftaskp = nullptr; // Function or task we're inside AstNodeCoverOrAssert* m_assertp = nullptr; // Current assertion int m_senitemCvtNum = 0; // Temporary signal counter @@ -82,6 +84,30 @@ class LinkResolveVisitor final : public VNVisitor { } iterateChildren(nodep); } + void visit(AstConstraintBefore* nodep) override { + VL_RESTORER(m_randcIllegalWhy); + VL_RESTORER(m_randcIllegalp); + m_randcIllegalWhy = "'solve before' (IEEE 1800-2023 18.5.9)"; + m_randcIllegalp = nodep; + iterateChildrenConst(nodep); + } + void visit(AstDist* nodep) override { + VL_RESTORER(m_randcIllegalWhy); + VL_RESTORER(m_randcIllegalp); + m_randcIllegalWhy = "'constraint dist' (IEEE 1800-2023 18.5.3)"; + m_randcIllegalp = nodep; + iterateChildrenConst(nodep); + } + void visit(AstConstraintExpr* nodep) override { + VL_RESTORER(m_randcIllegalWhy); + VL_RESTORER(m_randcIllegalp); + if (nodep->isSoft()) { + m_randcIllegalWhy = "'constraint soft' (IEEE 1800-2023 18.5.13.1)"; + m_randcIllegalp = nodep; + } + iterateChildrenConst(nodep); + } + void visit(AstInitialAutomatic* nodep) override { iterateChildren(nodep); // Initial assignments under function/tasks can just be simple @@ -110,13 +136,24 @@ class LinkResolveVisitor final : public VNVisitor { } void visit(AstNodeVarRef* nodep) override { - // VarRef: Resolve its reference - if (nodep->varp()) nodep->varp()->usedParam(true); - // TODO should look for where genvar is valid, but for now catch - // just gross errors of using genvar outside any generate - if (nodep->varp() && nodep->varp()->isGenVar() && !m_underGenFor) { - nodep->v3error("Genvar " << nodep->prettyNameQ() - << " used outside generate for loop (IEEE 1800-2023 27.4)"); + if (nodep->varp()) { // Else due to dead code, might not have var pointer + // VarRef: Resolve its reference + nodep->varp()->usedParam(true); + // TODO should look for where genvar is valid, but for now catch + // just gross errors of using genvar outside any generate + if (nodep->varp()->isGenVar() && !m_underGenFor) { + nodep->v3error("Genvar " + << nodep->prettyNameQ() + << " used outside generate for loop (IEEE 1800-2023 27.4)"); + } + if (nodep->varp()->isRandC() && m_randcIllegalp) { + nodep->v3error("Randc variables not allowed in " + << m_randcIllegalWhy << '\n' + << nodep->warnContextPrimary() << '\n' + << m_randcIllegalp->warnOther() + << "... Location of restricting expression\n" + << m_randcIllegalp->warnContextSecondary()); + } } iterateChildren(nodep); } diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 4067cff6b..a6c259d6d 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -131,8 +131,6 @@ class RandomizeMarkVisitor final : public VNVisitor { BaseToDerivedMap m_baseToDerivedMap; // Mapping from base classes to classes that extend them AstClass* m_classp = nullptr; // Current class - AstConstraintBefore* m_constraintBeforep = nullptr; // Current before constraint - AstConstraintExpr* m_constraintExprp = nullptr; // Current constraint expression AstNode* m_constraintExprGenp = nullptr; // Current constraint or constraint if expression AstNodeModule* m_modp; // Current module AstNodeStmt* m_stmtp = nullptr; // Current statement @@ -403,14 +401,7 @@ class RandomizeMarkVisitor final : public VNVisitor { } } } - void visit(AstConstraintBefore* nodep) override { - VL_RESTORER(m_constraintBeforep); - m_constraintBeforep = nodep; - iterateChildrenConst(nodep); - } void visit(AstConstraintExpr* nodep) override { - VL_RESTORER(m_constraintExprp); - m_constraintExprp = nodep; VL_RESTORER(m_constraintExprGenp); m_constraintExprGenp = nodep; iterateChildrenConst(nodep); @@ -425,15 +416,6 @@ class RandomizeMarkVisitor final : public VNVisitor { iterateAndNextConstNull(nodep->elsesp()); } void visit(AstNodeVarRef* nodep) override { - if (nodep->varp()->isRandC()) { - if (m_constraintExprp && m_constraintExprp->isSoft()) { - nodep->v3error( - "Randc variables not allowed in 'constraint soft' (IEEE 1800-2023 18.5.13.1)"); - } else if (m_constraintBeforep) { - nodep->v3error( - "Randc variables not allowed in 'solve before' (IEEE 1800-2023 18.5.9)"); - } - } if (!m_constraintExprGenp) return; if (nodep->varp()->lifetime().isStatic()) m_staticRefs.emplace(nodep); diff --git a/test_regress/t/t_constraint_before_randc_bad.out b/test_regress/t/t_constraint_before_randc_bad.out new file mode 100644 index 000000000..4cbf1a3a8 --- /dev/null +++ b/test_regress/t/t_constraint_before_randc_bad.out @@ -0,0 +1,7 @@ +%Error: t/t_constraint_before_randc_bad.v:11:45: Randc variables not allowed in 'solve before' (IEEE 1800-2023 18.5.9) + 11 | constraint raint2_bad { solve b1 before b2; } + | ^~ + t/t_constraint_before_randc_bad.v:11:29: ... Location of restricting expression + 11 | constraint raint2_bad { solve b1 before b2; } + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_randomize_before_randc_bad.py b/test_regress/t/t_constraint_before_randc_bad.py similarity index 100% rename from test_regress/t/t_randomize_before_randc_bad.py rename to test_regress/t/t_constraint_before_randc_bad.py diff --git a/test_regress/t/t_randomize_before_randc_bad.v b/test_regress/t/t_constraint_before_randc_bad.v similarity index 100% rename from test_regress/t/t_randomize_before_randc_bad.v rename to test_regress/t/t_constraint_before_randc_bad.v diff --git a/test_regress/t/t_constraint_dist_randc_bad.out b/test_regress/t/t_constraint_dist_randc_bad.out new file mode 100644 index 000000000..faff6e9be --- /dev/null +++ b/test_regress/t/t_constraint_dist_randc_bad.out @@ -0,0 +1,7 @@ +%Error: t/t_constraint_dist_randc_bad.v:10:23: Randc variables not allowed in 'constraint dist' (IEEE 1800-2023 18.5.3) + 10 | constraint c_bad { rc dist {3 := 0, 10 := 5}; } + | ^~ + t/t_constraint_dist_randc_bad.v:10:26: ... Location of restricting expression + 10 | constraint c_bad { rc dist {3 := 0, 10 := 5}; } + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_randomize_soft_randc_bad.py b/test_regress/t/t_constraint_dist_randc_bad.py similarity index 100% rename from test_regress/t/t_randomize_soft_randc_bad.py rename to test_regress/t/t_constraint_dist_randc_bad.py diff --git a/test_regress/t/t_constraint_dist_randc_bad.v b/test_regress/t/t_constraint_dist_randc_bad.v new file mode 100644 index 000000000..40cd2a770 --- /dev/null +++ b/test_regress/t/t_constraint_dist_randc_bad.v @@ -0,0 +1,14 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Cls1; + randc int rc; + + constraint c_bad { rc dist {3 := 0, 10 := 5}; } // Bad, no dist on randc +endclass + +module t (/*AUTOARG*/); +endmodule diff --git a/test_regress/t/t_constraint_soft_randc_bad.out b/test_regress/t/t_constraint_soft_randc_bad.out new file mode 100644 index 000000000..d87a61b02 --- /dev/null +++ b/test_regress/t/t_constraint_soft_randc_bad.out @@ -0,0 +1,7 @@ +%Error: t/t_constraint_soft_randc_bad.v:10:28: Randc variables not allowed in 'constraint soft' (IEEE 1800-2023 18.5.13.1) + 10 | constraint c_bad { soft rc > 4; } + | ^~ + t/t_constraint_soft_randc_bad.v:10:23: ... Location of restricting expression + 10 | constraint c_bad { soft rc > 4; } + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_constraint_soft_randc_bad.py b/test_regress/t/t_constraint_soft_randc_bad.py new file mode 100755 index 000000000..30c3d4f77 --- /dev/null +++ b/test_regress/t/t_constraint_soft_randc_bad.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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=test.vlt_all, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_randomize_soft_randc_bad.v b/test_regress/t/t_constraint_soft_randc_bad.v similarity index 100% rename from test_regress/t/t_randomize_soft_randc_bad.v rename to test_regress/t/t_constraint_soft_randc_bad.v diff --git a/test_regress/t/t_randomize_before_randc_bad.out b/test_regress/t/t_randomize_before_randc_bad.out deleted file mode 100644 index 9480b7624..000000000 --- a/test_regress/t/t_randomize_before_randc_bad.out +++ /dev/null @@ -1,5 +0,0 @@ -%Error: t/t_randomize_before_randc_bad.v:11:45: Randc variables not allowed in 'solve before' (IEEE 1800-2023 18.5.9) - : ... note: In instance 't' - 11 | constraint raint2_bad { solve b1 before b2; } - | ^~ -%Error: Exiting due to diff --git a/test_regress/t/t_randomize_soft_randc_bad.out b/test_regress/t/t_randomize_soft_randc_bad.out deleted file mode 100644 index a1646e725..000000000 --- a/test_regress/t/t_randomize_soft_randc_bad.out +++ /dev/null @@ -1,5 +0,0 @@ -%Error: t/t_randomize_soft_randc_bad.v:10:28: Randc variables not allowed in 'constraint soft' (IEEE 1800-2023 18.5.13.1) - : ... note: In instance 't' - 10 | constraint c_bad { soft rc > 4; } - | ^~ -%Error: Exiting due to