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***
|
||||
|
||||
**** 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]
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include <cstdarg>
|
||||
#include <unistd.h>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -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 <pair<void*,string>,AstTypedef*> ImplTypedefMap;
|
||||
typedef set <FileLine*> 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 <container,name>
|
||||
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 "<<nodep->type()<<" under a "<<nodep->backp()->type());
|
||||
|
|
@ -78,6 +98,7 @@ private:
|
|||
// VISITs
|
||||
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
||||
if (!nodep->user1Inc()) { // Process only once.
|
||||
cleanFileline(nodep);
|
||||
UINFO(5," "<<nodep<<endl);
|
||||
checkExpected(nodep);
|
||||
// Due to a need to get the arguments, the ParseRefs are under here,
|
||||
|
|
@ -141,6 +162,7 @@ private:
|
|||
}
|
||||
virtual void visit(AstDot* nodep, AstNUser*) {
|
||||
UINFO(5," "<<nodep<<endl);
|
||||
cleanFileline(nodep);
|
||||
if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
||||
m_dotText = "";
|
||||
nodep->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," "<<nodep<<endl);
|
||||
if (m_inModDot) { // Dotted part, just pass up
|
||||
|
|
@ -228,6 +253,7 @@ private:
|
|||
}
|
||||
virtual void visit(AstEnumItem* nodep, AstNUser*) {
|
||||
// Expand ranges
|
||||
cleanFileline(nodep);
|
||||
nodep->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 "<<nodep<<endl);
|
||||
// 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
|
||||
|
|
@ -351,6 +381,7 @@ private:
|
|||
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
// Default: Just iterate
|
||||
cleanFileline(nodep);
|
||||
checkExpected(nodep); // So we detect node types we forgot to list here
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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: "<<nodep->prettyName());
|
||||
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); // Warn only once
|
||||
}
|
||||
} else if (allD && !anyU) {
|
||||
if (!unusedMatch(nodep)) {
|
||||
nodep->v3warn(UNUSED, "Signal is not used: "<<nodep->prettyName());
|
||||
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); // Warn only once
|
||||
}
|
||||
} else if (!anyD && allU) {
|
||||
nodep->v3warn(UNDRIVEN, "Signal is not driven: "<<nodep->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: "<<nodep->prettyName()
|
||||
<<bitNames(BN_BOTH));
|
||||
setU=true;
|
||||
}
|
||||
if (anyDnotU && !unusedMatch(nodep)) {
|
||||
nodep->v3warn(UNUSED, "Bits of signal are not used: "<<nodep->prettyName()
|
||||
<<bitNames(BN_UNUSED));
|
||||
setU=true;
|
||||
}
|
||||
if (anyUnotD) {
|
||||
nodep->v3warn(UNDRIVEN, "Bits of signal are not driven: "<<nodep->prettyName()
|
||||
<<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: 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.*',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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