diff --git a/Changes b/Changes index d184e7bd1..0d2803490 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,8 @@ indicates the contributor was also the author of the fix; Thanks! * Verilator 3.81*** +**** Throw UNUSED/UNDRIVEN only once per net in a parametrized module. + **** Fix false BLKSEQ on non-unrolled for loop indexes. [Jeff Winston] **** Fix block comment not separating identifiers, bug311. [Gene Sullivan] diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index 4aa08862b..eecea0e6b 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -162,7 +162,7 @@ private: m_ifDepth = -1; } else if (++m_ifDepth > v3Global.opt.ifDepth()) { nodep->v3warn(IFDEPTH,"Deep 'if' statement; suggest unique/priority to avoid slow logic"); - nodep->fileline()->warnOn(V3ErrorCode::IFDEPTH, false); // Warn only once + nodep->fileline()->modifyWarnOff(V3ErrorCode::IFDEPTH, true); // Warn only once m_ifDepth = -1; } nodep->iterateChildren(*this); diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index d7f617893..67dec96cd 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -47,11 +48,14 @@ class LinkParseVisitor : public AstNVisitor { private: // NODE STATE // Cleared on netlist - // AstNode::user() -> bool. True if processed + // AstNode::user1() -> bool. True if processed + // AstNode::user2() -> bool. True if fileline recomputed AstUser1InUse m_inuser1; + AstUser2InUse m_inuser2; // TYPES typedef map ,AstTypedef*> ImplTypedefMap; + typedef set FileLineSet; // STATE string m_dotText; // Dotted module text we are building for a dotted node, passed up @@ -60,6 +64,7 @@ private: AstText* m_baseTextp; // Lowest TEXT node that needs replacement with varref AstVar* m_varp; // Variable we're under ImplTypedefMap m_implTypedef; // Created typedefs for each + FileLineSet m_filelines; // Filelines that have been seen // METHODS static int debug() { @@ -68,6 +73,21 @@ private: return level; } + void cleanFileline(AstNode* nodep) { + if (!nodep->user2Inc()) { // Process once + // We make all filelines unique per AstNode. This allows us to + // later turn off messages on a fileline when an issue is found + // so that messages on replicated blocks occur only once, + // without suppressing other token's messages as a side effect. + // We could have verilog.l create a new one on every token, + // but that's a lot more structures than only doing AST nodes. + if (m_filelines.find(nodep->fileline()) != m_filelines.end()) { + nodep->fileline(new FileLine(nodep->fileline())); + } + m_filelines.insert(nodep->fileline()); + } + } + void checkExpected(AstNode* nodep) { if (m_exp != AstParseRefExp::PX_NONE) { nodep->v3fatalSrc("Tree syntax error: Not expecting "<type()<<" under a "<backp()->type()); @@ -78,6 +98,7 @@ private: // VISITs virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) { if (!nodep->user1Inc()) { // Process only once. + cleanFileline(nodep); UINFO(5," "<lhsp()->iterateAndNext(*this); @@ -165,6 +187,7 @@ private: } virtual void visit(AstSelBit* nodep, AstNUser*) { if (!nodep->user1Inc()) { // Process only once. + cleanFileline(nodep); if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart} m_dotText = ""; nodep->lhsp()->iterateAndNext(*this); @@ -193,6 +216,7 @@ private: virtual void visit(AstNodePreSel* nodep, AstNUser*) { // Excludes simple AstSel, see above if (!nodep->user1Inc()) { // Process only once. + cleanFileline(nodep); if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart} nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed in the cell part of a dotted reference"); } else if (m_exp==AstParseRefExp::PX_FUNC) { @@ -215,6 +239,7 @@ private: } virtual void visit(AstText* nodep, AstNUser*) { if (!nodep->user1Inc()) { // Process only once. + cleanFileline(nodep); if (m_exp != AstParseRefExp::PX_NONE) { UINFO(7," "<iterateChildren(*this); if (nodep->rangep()) { if (!nodep->rangep()->msbp()->castConst() @@ -251,12 +277,14 @@ private: virtual void visit(AstVar* nodep, AstNUser*) { + cleanFileline(nodep); m_varp = nodep; nodep->iterateChildren(*this); m_varp = NULL; } virtual void visit(AstAttrOf* nodep, AstNUser*) { + cleanFileline(nodep); nodep->iterateChildren(*this); if (nodep->attrType() == AstAttrType::VAR_CLOCK) { if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable"); @@ -303,6 +331,7 @@ private: virtual void visit(AstAlwaysPublic* nodep, AstNUser*) { // AlwaysPublic was attached under a var, but it's a statement that should be // at the same level as the var + cleanFileline(nodep); nodep->iterateChildren(*this); if (m_varp) { nodep->unlinkFrBack(); @@ -315,6 +344,7 @@ private: } virtual void visit(AstDefImplicitDType* nodep, AstNUser*) { + cleanFileline(nodep); UINFO(8," DEFIMPLICIT "<iterateChildren(*this); } diff --git a/src/V3Undriven.cpp b/src/V3Undriven.cpp index 67286c457..3c1c539ae 100644 --- a/src/V3Undriven.cpp +++ b/src/V3Undriven.cpp @@ -170,27 +170,36 @@ public: // thus undriven+unused bits get UNUSED warnings, as they're not as buggy. if (!unusedMatch(nodep)) { nodep->v3warn(UNUSED, "Signal is not driven, nor used: "<prettyName()); + nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); // Warn only once } } else if (allD && !anyU) { if (!unusedMatch(nodep)) { nodep->v3warn(UNUSED, "Signal is not used: "<prettyName()); + nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); // Warn only once } } else if (!anyD && allU) { nodep->v3warn(UNDRIVEN, "Signal is not driven: "<prettyName()); + nodep->fileline()->modifyWarnOff(V3ErrorCode::UNDRIVEN, true); // Warn only once } else { // Bits have different dispositions + bool setU=false; bool setD=false; if (anynotDU && !unusedMatch(nodep)) { nodep->v3warn(UNUSED, "Bits of signal are not driven, nor used: "<prettyName() <v3warn(UNUSED, "Bits of signal are not used: "<prettyName() <v3warn(UNDRIVEN, "Bits of signal are not driven: "<prettyName() <fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); // Warn only once + if (setD) nodep->fileline()->modifyWarnOff(V3ErrorCode::UNDRIVEN, true); // Warn only once } } } diff --git a/test_regress/t/t_cdc_async_bad.pl b/test_regress/t/t_cdc_async_bad.pl index 5878fd9d6..02e1d5efc 100755 --- a/test_regress/t/t_cdc_async_bad.pl +++ b/test_regress/t/t_cdc_async_bad.pl @@ -16,6 +16,7 @@ compile ( %Warning-CDCRSTLOGIC: Use "/\* verilator lint_off CDCRSTLOGIC \*/" and lint_on around source to disable this message. %Warning-CDCRSTLOGIC: See details in obj_dir/t_cdc_async_bad/Vt_cdc_async_bad__cdc.txt %Warning-CDCRSTLOGIC: t/t_cdc_async_bad.v:\d+: Logic in path that feeds async reset, via signal: v.rst6a_bad_n +%Warning-CDCRSTLOGIC: t/t_cdc_async_bad.v:\d+: Logic in path that feeds async reset, via signal: v.rst6b_bad_n %Warning-CDCRSTLOGIC: t/t_cdc_async_bad.v:\d+: Logic in path that feeds async reset, via signal: v.rst3_bad_n %Error: Exiting due to.*', ); diff --git a/test_regress/t/t_lint_once_bad.pl b/test_regress/t/t_lint_once_bad.pl new file mode 100755 index 000000000..3576d17b1 --- /dev/null +++ b/test_regress/t/t_lint_once_bad.pl @@ -0,0 +1,24 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 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. + +compile ( + make_top_shell => 0, + make_main => 0, + v_flags2 => ["--lint-only -Wwarn-UNUSED"], + verilator_make_gcc => 0, + fails=>1, + expect=> +'%Warning-UNUSED: t/t_lint_once_bad.v:\d+: Signal is not driven, nor used: unus1 +%Warning-UNUSED: Use .* to disable this message. +%Warning-UNUSED: t/t_lint_once_bad.v:\d+: Signal is not driven, nor used: unus2 +%Error: Exiting due to.*', + ) if $Self->{v3}; + +ok(1); +1; diff --git a/test_regress/t/t_lint_once_bad.v b/test_regress/t/t_lint_once_bad.v new file mode 100644 index 000000000..c70b88e02 --- /dev/null +++ b/test_regress/t/t_lint_once_bad.v @@ -0,0 +1,19 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2006 by Wilson Snyder. + +// Check that we report warnings only once on parameterized modules +// Also check that we don't suppress warnings on the same line + +module t (); + sub #(.A(1)) sub1(); + sub #(.A(2)) sub2(); + sub #(.A(3)) sub3(); +endmodule + +module sub; + parameter A = 0; + + reg [A:0] unus1; reg [A:0] unus2; +endmodule