Throw UNUSED/UNDRIVEN only once per net in a parametrized module.
This commit is contained in:
parent
481b261458
commit
a435ae98f9
2
Changes
2
Changes
|
|
@ -5,6 +5,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
||||||
|
|
||||||
* Verilator 3.81***
|
* 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 false BLKSEQ on non-unrolled for loop indexes. [Jeff Winston]
|
||||||
|
|
||||||
**** Fix block comment not separating identifiers, bug311. [Gene Sullivan]
|
**** Fix block comment not separating identifiers, bug311. [Gene Sullivan]
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ private:
|
||||||
m_ifDepth = -1;
|
m_ifDepth = -1;
|
||||||
} else if (++m_ifDepth > v3Global.opt.ifDepth()) {
|
} else if (++m_ifDepth > v3Global.opt.ifDepth()) {
|
||||||
nodep->v3warn(IFDEPTH,"Deep 'if' statement; suggest unique/priority to avoid slow logic");
|
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;
|
m_ifDepth = -1;
|
||||||
}
|
}
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <set>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
@ -47,11 +48,14 @@ class LinkParseVisitor : public AstNVisitor {
|
||||||
private:
|
private:
|
||||||
// NODE STATE
|
// NODE STATE
|
||||||
// Cleared on netlist
|
// 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;
|
AstUser1InUse m_inuser1;
|
||||||
|
AstUser2InUse m_inuser2;
|
||||||
|
|
||||||
// TYPES
|
// TYPES
|
||||||
typedef map <pair<void*,string>,AstTypedef*> ImplTypedefMap;
|
typedef map <pair<void*,string>,AstTypedef*> ImplTypedefMap;
|
||||||
|
typedef set <FileLine*> FileLineSet;
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
string m_dotText; // Dotted module text we are building for a dotted node, passed up
|
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
|
AstText* m_baseTextp; // Lowest TEXT node that needs replacement with varref
|
||||||
AstVar* m_varp; // Variable we're under
|
AstVar* m_varp; // Variable we're under
|
||||||
ImplTypedefMap m_implTypedef; // Created typedefs for each <container,name>
|
ImplTypedefMap m_implTypedef; // Created typedefs for each <container,name>
|
||||||
|
FileLineSet m_filelines; // Filelines that have been seen
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
static int debug() {
|
static int debug() {
|
||||||
|
|
@ -68,6 +73,21 @@ private:
|
||||||
return level;
|
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) {
|
void checkExpected(AstNode* nodep) {
|
||||||
if (m_exp != AstParseRefExp::PX_NONE) {
|
if (m_exp != AstParseRefExp::PX_NONE) {
|
||||||
nodep->v3fatalSrc("Tree syntax error: Not expecting "<<nodep->type()<<" under a "<<nodep->backp()->type());
|
nodep->v3fatalSrc("Tree syntax error: Not expecting "<<nodep->type()<<" under a "<<nodep->backp()->type());
|
||||||
|
|
@ -78,6 +98,7 @@ private:
|
||||||
// VISITs
|
// VISITs
|
||||||
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
||||||
if (!nodep->user1Inc()) { // Process only once.
|
if (!nodep->user1Inc()) { // Process only once.
|
||||||
|
cleanFileline(nodep);
|
||||||
UINFO(5," "<<nodep<<endl);
|
UINFO(5," "<<nodep<<endl);
|
||||||
checkExpected(nodep);
|
checkExpected(nodep);
|
||||||
// Due to a need to get the arguments, the ParseRefs are under here,
|
// Due to a need to get the arguments, the ParseRefs are under here,
|
||||||
|
|
@ -141,6 +162,7 @@ private:
|
||||||
}
|
}
|
||||||
virtual void visit(AstDot* nodep, AstNUser*) {
|
virtual void visit(AstDot* nodep, AstNUser*) {
|
||||||
UINFO(5," "<<nodep<<endl);
|
UINFO(5," "<<nodep<<endl);
|
||||||
|
cleanFileline(nodep);
|
||||||
if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
||||||
m_dotText = "";
|
m_dotText = "";
|
||||||
nodep->lhsp()->iterateAndNext(*this);
|
nodep->lhsp()->iterateAndNext(*this);
|
||||||
|
|
@ -165,6 +187,7 @@ private:
|
||||||
}
|
}
|
||||||
virtual void visit(AstSelBit* nodep, AstNUser*) {
|
virtual void visit(AstSelBit* nodep, AstNUser*) {
|
||||||
if (!nodep->user1Inc()) { // Process only once.
|
if (!nodep->user1Inc()) { // Process only once.
|
||||||
|
cleanFileline(nodep);
|
||||||
if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
||||||
m_dotText = "";
|
m_dotText = "";
|
||||||
nodep->lhsp()->iterateAndNext(*this);
|
nodep->lhsp()->iterateAndNext(*this);
|
||||||
|
|
@ -193,6 +216,7 @@ private:
|
||||||
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
|
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
|
||||||
// Excludes simple AstSel, see above
|
// Excludes simple AstSel, see above
|
||||||
if (!nodep->user1Inc()) { // Process only once.
|
if (!nodep->user1Inc()) { // Process only once.
|
||||||
|
cleanFileline(nodep);
|
||||||
if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
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");
|
nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed in the cell part of a dotted reference");
|
||||||
} else if (m_exp==AstParseRefExp::PX_FUNC) {
|
} else if (m_exp==AstParseRefExp::PX_FUNC) {
|
||||||
|
|
@ -215,6 +239,7 @@ private:
|
||||||
}
|
}
|
||||||
virtual void visit(AstText* nodep, AstNUser*) {
|
virtual void visit(AstText* nodep, AstNUser*) {
|
||||||
if (!nodep->user1Inc()) { // Process only once.
|
if (!nodep->user1Inc()) { // Process only once.
|
||||||
|
cleanFileline(nodep);
|
||||||
if (m_exp != AstParseRefExp::PX_NONE) {
|
if (m_exp != AstParseRefExp::PX_NONE) {
|
||||||
UINFO(7," "<<nodep<<endl);
|
UINFO(7," "<<nodep<<endl);
|
||||||
if (m_inModDot) { // Dotted part, just pass up
|
if (m_inModDot) { // Dotted part, just pass up
|
||||||
|
|
@ -228,6 +253,7 @@ private:
|
||||||
}
|
}
|
||||||
virtual void visit(AstEnumItem* nodep, AstNUser*) {
|
virtual void visit(AstEnumItem* nodep, AstNUser*) {
|
||||||
// Expand ranges
|
// Expand ranges
|
||||||
|
cleanFileline(nodep);
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (nodep->rangep()) {
|
if (nodep->rangep()) {
|
||||||
if (!nodep->rangep()->msbp()->castConst()
|
if (!nodep->rangep()->msbp()->castConst()
|
||||||
|
|
@ -251,12 +277,14 @@ private:
|
||||||
|
|
||||||
|
|
||||||
virtual void visit(AstVar* nodep, AstNUser*) {
|
virtual void visit(AstVar* nodep, AstNUser*) {
|
||||||
|
cleanFileline(nodep);
|
||||||
m_varp = nodep;
|
m_varp = nodep;
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
m_varp = NULL;
|
m_varp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void visit(AstAttrOf* nodep, AstNUser*) {
|
virtual void visit(AstAttrOf* nodep, AstNUser*) {
|
||||||
|
cleanFileline(nodep);
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (nodep->attrType() == AstAttrType::VAR_CLOCK) {
|
if (nodep->attrType() == AstAttrType::VAR_CLOCK) {
|
||||||
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
|
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
|
||||||
|
|
@ -303,6 +331,7 @@ private:
|
||||||
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
|
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
|
||||||
// AlwaysPublic was attached under a var, but it's a statement that should be
|
// AlwaysPublic was attached under a var, but it's a statement that should be
|
||||||
// at the same level as the var
|
// at the same level as the var
|
||||||
|
cleanFileline(nodep);
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (m_varp) {
|
if (m_varp) {
|
||||||
nodep->unlinkFrBack();
|
nodep->unlinkFrBack();
|
||||||
|
|
@ -315,6 +344,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void visit(AstDefImplicitDType* nodep, AstNUser*) {
|
virtual void visit(AstDefImplicitDType* nodep, AstNUser*) {
|
||||||
|
cleanFileline(nodep);
|
||||||
UINFO(8," DEFIMPLICIT "<<nodep<<endl);
|
UINFO(8," DEFIMPLICIT "<<nodep<<endl);
|
||||||
// Must remember what names we've already created, and combine duplicates
|
// Must remember what names we've already created, and combine duplicates
|
||||||
// so that for "var enum {...} a,b" a & b will share a common typedef
|
// so that for "var enum {...} a,b" a & b will share a common typedef
|
||||||
|
|
@ -351,6 +381,7 @@ private:
|
||||||
|
|
||||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||||
// Default: Just iterate
|
// Default: Just iterate
|
||||||
|
cleanFileline(nodep);
|
||||||
checkExpected(nodep); // So we detect node types we forgot to list here
|
checkExpected(nodep); // So we detect node types we forgot to list here
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -170,27 +170,36 @@ public:
|
||||||
// thus undriven+unused bits get UNUSED warnings, as they're not as buggy.
|
// thus undriven+unused bits get UNUSED warnings, as they're not as buggy.
|
||||||
if (!unusedMatch(nodep)) {
|
if (!unusedMatch(nodep)) {
|
||||||
nodep->v3warn(UNUSED, "Signal is not driven, nor used: "<<nodep->prettyName());
|
nodep->v3warn(UNUSED, "Signal is not driven, nor used: "<<nodep->prettyName());
|
||||||
|
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); // Warn only once
|
||||||
}
|
}
|
||||||
} else if (allD && !anyU) {
|
} else if (allD && !anyU) {
|
||||||
if (!unusedMatch(nodep)) {
|
if (!unusedMatch(nodep)) {
|
||||||
nodep->v3warn(UNUSED, "Signal is not used: "<<nodep->prettyName());
|
nodep->v3warn(UNUSED, "Signal is not used: "<<nodep->prettyName());
|
||||||
|
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); // Warn only once
|
||||||
}
|
}
|
||||||
} else if (!anyD && allU) {
|
} else if (!anyD && allU) {
|
||||||
nodep->v3warn(UNDRIVEN, "Signal is not driven: "<<nodep->prettyName());
|
nodep->v3warn(UNDRIVEN, "Signal is not driven: "<<nodep->prettyName());
|
||||||
|
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNDRIVEN, true); // Warn only once
|
||||||
} else {
|
} else {
|
||||||
// Bits have different dispositions
|
// Bits have different dispositions
|
||||||
|
bool setU=false; bool setD=false;
|
||||||
if (anynotDU && !unusedMatch(nodep)) {
|
if (anynotDU && !unusedMatch(nodep)) {
|
||||||
nodep->v3warn(UNUSED, "Bits of signal are not driven, nor used: "<<nodep->prettyName()
|
nodep->v3warn(UNUSED, "Bits of signal are not driven, nor used: "<<nodep->prettyName()
|
||||||
<<bitNames(BN_BOTH));
|
<<bitNames(BN_BOTH));
|
||||||
|
setU=true;
|
||||||
}
|
}
|
||||||
if (anyDnotU && !unusedMatch(nodep)) {
|
if (anyDnotU && !unusedMatch(nodep)) {
|
||||||
nodep->v3warn(UNUSED, "Bits of signal are not used: "<<nodep->prettyName()
|
nodep->v3warn(UNUSED, "Bits of signal are not used: "<<nodep->prettyName()
|
||||||
<<bitNames(BN_UNUSED));
|
<<bitNames(BN_UNUSED));
|
||||||
|
setU=true;
|
||||||
}
|
}
|
||||||
if (anyUnotD) {
|
if (anyUnotD) {
|
||||||
nodep->v3warn(UNDRIVEN, "Bits of signal are not driven: "<<nodep->prettyName()
|
nodep->v3warn(UNDRIVEN, "Bits of signal are not driven: "<<nodep->prettyName()
|
||||||
<<bitNames(BN_UNDRIVEN));
|
<<bitNames(BN_UNDRIVEN));
|
||||||
|
setD=true;
|
||||||
}
|
}
|
||||||
|
if (setU) nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); // Warn only once
|
||||||
|
if (setD) nodep->fileline()->modifyWarnOff(V3ErrorCode::UNDRIVEN, true); // Warn only once
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ compile (
|
||||||
%Warning-CDCRSTLOGIC: Use "/\* verilator lint_off CDCRSTLOGIC \*/" and lint_on around source to disable this message.
|
%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: 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.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
|
%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.*',
|
%Error: Exiting due to.*',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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
|
||||||
Loading…
Reference in New Issue