Add UNUSED and UNDRIVEN warnings
This commit is contained in:
parent
ebdf8a5f3c
commit
c33299d542
4
Changes
4
Changes
|
|
@ -26,6 +26,10 @@ indicates the contributor was also the author of the fix; Thanks!
|
|||
|
||||
*** With --Wall, add INCABSPATH warning on `include with absolute paths.
|
||||
|
||||
*** With --Wall, add UNDRIVEN warning on undriven nets.
|
||||
|
||||
*** With --Wall, add UNUSED warning on unused nets.
|
||||
|
||||
*** The VARHIDDEN warning is now disabled by default, use -Wall to enable.
|
||||
|
||||
* Verilator 3.805 2010/11/02
|
||||
|
|
|
|||
|
|
@ -884,7 +884,7 @@ received from third parties.
|
|||
|
||||
Disable all code style related warning messages (note by default they are
|
||||
already disabled). This is equivalent to "-Wno-DECLFILENAME -Wno-DEFPARAM
|
||||
-Wno-INCABSPATH -Wno-VARHIDDEN".
|
||||
-Wno-INCABSPATH -Wno-UNDRIVEN -Wno-UNUSED -Wno-VARHIDDEN".
|
||||
|
||||
=item -Wwarn-I<message>
|
||||
|
||||
|
|
@ -901,7 +901,8 @@ enabled), but do not affect style messages. This is equivalent to
|
|||
=item -Wwarn-style
|
||||
|
||||
Enable all code style related warning messages. This is equivalent to
|
||||
"-Wwarn-DECLFILENAME -Wwarn-DEFPARAM -Wwarn-INCABSPATH -Wwarn-VARHIDDEN".
|
||||
"-Wwarn-DECLFILENAME -Wwarn-DEFPARAM -Wwarn-INCABSPATH -Wwarn-UNDRIVEN
|
||||
-Wwarn-UNUSED -Wwarn-VARHIDDEN".
|
||||
|
||||
=item -x-assign 0
|
||||
|
||||
|
|
@ -2582,7 +2583,9 @@ cases would result in simulator mismatches.
|
|||
|
||||
=item UNDRIVEN
|
||||
|
||||
Warns that the specified signal is never sourced.
|
||||
Warns that the specified signal is never sourced. Verilator is fairly
|
||||
liberal in the usage calculations; making a signal public, or loading only
|
||||
a single array element marks the entire signal as driven.
|
||||
|
||||
Disabled by default as this is a code style warning, it will simulate
|
||||
correctly.
|
||||
|
|
@ -2667,8 +2670,9 @@ correctly.
|
|||
|
||||
=item UNUSED
|
||||
|
||||
Warns that the specified signal is never sinked. This is a future message,
|
||||
currently Verilator will not produce this warning.
|
||||
Warns that the specified signal is never sinked. Verilator is fairly
|
||||
liberal in the usage calculations; making a signal public, or accessing
|
||||
only a single array element marks the entire signal as used.
|
||||
|
||||
Disabled by default as this is a code style warning, it will simulate
|
||||
correctly.
|
||||
|
|
|
|||
|
|
@ -221,6 +221,7 @@ RAW_OBJS = \
|
|||
V3Trace.o \
|
||||
V3TraceDecl.o \
|
||||
V3Tristate.o \
|
||||
V3Undriven.o \
|
||||
V3Unknown.o \
|
||||
V3Unroll.o \
|
||||
V3Width.o \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,274 @@
|
|||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Check for unused/undriven signals
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2004-2010 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.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
// V3Undriven's Transformations:
|
||||
//
|
||||
// Each module:
|
||||
// Make vector for all variables
|
||||
// SEL(VARREF(...))) mark only some bits as used/driven
|
||||
// else VARREF(...) mark all bits as used/driven
|
||||
// Report unused/undriven nets
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <unistd.h>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3Undriven.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
//######################################################################
|
||||
// Class for every variable we may process
|
||||
|
||||
class UndrivenVarEntry {
|
||||
// MEMBERS
|
||||
AstVar* m_varp; // Variable this tracks
|
||||
bool m_usedWhole; // True if whole vector used
|
||||
bool m_drivenWhole; // True if whole vector driven
|
||||
vector<bool> m_flags; // Used/Driven on each subbit
|
||||
|
||||
enum { FLAG_USED = 0, FLAG_DRIVEN = 1, FLAGS_PER_BIT = 2 };
|
||||
|
||||
static int debug() {
|
||||
static int level = -1;
|
||||
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
|
||||
return level;
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
UndrivenVarEntry (AstVar* varp) { // Construction for when a var is used
|
||||
UINFO(9, "create "<<varp<<endl);
|
||||
m_varp = varp;
|
||||
m_usedWhole = false;
|
||||
m_drivenWhole = false;
|
||||
|
||||
m_flags.resize(varp->width()*FLAGS_PER_BIT);
|
||||
for (int i=0; i<varp->width()*FLAGS_PER_BIT; i++) {
|
||||
m_flags[i] = false;
|
||||
}
|
||||
}
|
||||
~UndrivenVarEntry() {}
|
||||
private:
|
||||
// METHODS
|
||||
inline bool bitNumOk(int bit) const { return (bit*FLAGS_PER_BIT < (int)m_flags.size()); }
|
||||
inline bool usedFlag(int bit) { return m_flags[bit*FLAGS_PER_BIT + FLAG_USED]; }
|
||||
inline bool drivenFlag(int bit) { return m_flags[bit*FLAGS_PER_BIT + FLAG_DRIVEN]; }
|
||||
string bitNames(int index) {
|
||||
string bits="";
|
||||
bool prev = false;
|
||||
int msb = 0;
|
||||
// bit==-1 loops below; we do one extra iteration so end with prev=false
|
||||
for (int bit=(m_flags.size()/FLAGS_PER_BIT)-1; bit >= -1; --bit) {
|
||||
if (bit>=0 && !m_flags[bit*FLAGS_PER_BIT + index]) {
|
||||
if (!prev) { prev=true; msb = bit; }
|
||||
} else if (prev) {
|
||||
AstBasicDType* bdtypep = m_varp->basicp();
|
||||
int lsb = bit+1;
|
||||
if (bits != "") bits += ",";
|
||||
if (lsb==msb) {
|
||||
bits += cvtToStr(lsb+bdtypep->lsb());
|
||||
} else {
|
||||
if (bdtypep->littleEndian()) {
|
||||
bits += cvtToStr(lsb+bdtypep->lsb())+":"+cvtToStr(msb+bdtypep->lsb());
|
||||
} else {
|
||||
bits += cvtToStr(msb+bdtypep->lsb())+":"+cvtToStr(lsb+bdtypep->lsb());
|
||||
}
|
||||
}
|
||||
prev = false;
|
||||
}
|
||||
}
|
||||
return "["+bits+"]";
|
||||
}
|
||||
public:
|
||||
void usedWhole() {
|
||||
UINFO(9, "set u[*] "<<m_varp->name()<<endl);
|
||||
m_usedWhole = true;
|
||||
}
|
||||
void drivenWhole() {
|
||||
UINFO(9, "set d[*] "<<m_varp->name()<<endl);
|
||||
m_drivenWhole = true;
|
||||
}
|
||||
void usedBit (int bit, int width) {
|
||||
UINFO(9, "set u["<<(bit+width-1)<<":"<<bit<<"] "<<m_varp->name()<<endl);
|
||||
for (int i=0; i<width; i++) {
|
||||
if (bitNumOk(bit+i)) {
|
||||
m_flags[(bit+i)*FLAGS_PER_BIT + FLAG_USED] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
void drivenBit (int bit, int width) {
|
||||
UINFO(9, "set d["<<(bit+width-1)<<":"<<bit<<"] "<<m_varp->name()<<endl);
|
||||
for (int i=0; i<width; i++) {
|
||||
if (bitNumOk(bit+i)) {
|
||||
m_flags[(bit+i)*FLAGS_PER_BIT + FLAG_DRIVEN] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
void reportViolations() {
|
||||
// Combine bits into overall state
|
||||
AstVar* nodep = m_varp;
|
||||
if (!nodep->isParam()) {
|
||||
bool allU=true;
|
||||
bool allD=true;
|
||||
bool anyU=m_usedWhole;
|
||||
bool anyD=m_drivenWhole;
|
||||
for (unsigned bit=0; bit<m_flags.size()/FLAGS_PER_BIT; bit++) {
|
||||
allU &= usedFlag(bit);
|
||||
anyU |= usedFlag(bit);
|
||||
allD &= drivenFlag(bit);
|
||||
anyD |= drivenFlag(bit);
|
||||
}
|
||||
if (allU) m_usedWhole = true;
|
||||
if (allD) m_drivenWhole = true;
|
||||
// Test results
|
||||
if (m_usedWhole && m_drivenWhole) {
|
||||
// Ignore
|
||||
}
|
||||
else if (!anyU && !anyD) {
|
||||
nodep->v3warn(UNDRIVEN, "Signal is not driven, nor used: "<<nodep->prettyName());
|
||||
}
|
||||
else {
|
||||
if (!m_usedWhole && !anyU) {
|
||||
nodep->v3warn(UNUSED, "Signal is not used: "<<nodep->prettyName());
|
||||
} else if (!m_usedWhole) {
|
||||
nodep->v3warn(UNUSED, "Bits of signal are not used: "<<nodep->prettyName()
|
||||
<<bitNames(FLAG_USED));
|
||||
}
|
||||
if (!m_drivenWhole && !anyD) {
|
||||
nodep->v3warn(UNDRIVEN, "Signal is not driven: "<<nodep->prettyName());
|
||||
} else if (!m_drivenWhole) {
|
||||
nodep->v3warn(UNDRIVEN, "Bits of signal are not driven: "<<nodep->prettyName()
|
||||
<<bitNames(FLAG_DRIVEN));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Undriven state, as a visitor of each AstNode
|
||||
|
||||
class UndrivenVisitor : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// AstVar::user1p -> UndrivenVar* for usage var, 0=not set yet
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
vector<UndrivenVarEntry*> m_entryps; // Nodes to delete when we are finished
|
||||
|
||||
// METHODS
|
||||
static int debug() {
|
||||
static int level = -1;
|
||||
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
|
||||
return level;
|
||||
}
|
||||
|
||||
UndrivenVarEntry* getEntryp(AstVar* nodep) {
|
||||
if (!nodep->user1p()) {
|
||||
UndrivenVarEntry* entryp = new UndrivenVarEntry (nodep);
|
||||
m_entryps.push_back(entryp);
|
||||
nodep->user1p(entryp);
|
||||
return entryp;
|
||||
} else {
|
||||
UndrivenVarEntry* entryp = (UndrivenVarEntry*)(nodep->user1p());
|
||||
return entryp;
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstVar* nodep, AstNUser*) {
|
||||
UndrivenVarEntry* entryp = getEntryp (nodep);
|
||||
if (nodep->isInput()
|
||||
|| nodep->isSigPublic() || nodep->isSigUserRWPublic()) {
|
||||
entryp->drivenWhole();
|
||||
}
|
||||
if (nodep->isOutput()
|
||||
|| nodep->isSigPublic() || nodep->isSigUserRWPublic()
|
||||
|| nodep->isSigUserRdPublic()) {
|
||||
entryp->usedWhole();
|
||||
}
|
||||
// Discover variables used in bit definitions, etc
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstArraySel* nodep, AstNUser*) {
|
||||
// Arrays are rarely constant assigned, so for now we punt and do all entries
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstSel* nodep, AstNUser*) {
|
||||
AstVarRef* varrefp = nodep->fromp()->castVarRef();
|
||||
AstConst* constp = nodep->lsbp()->castConst();
|
||||
if (varrefp && constp && !constp->num().isFourState()) {
|
||||
UndrivenVarEntry* entryp = getEntryp (varrefp->varp());
|
||||
int lsb = constp->toUInt();
|
||||
if (varrefp->lvalue()) entryp->drivenBit(lsb, nodep->width());
|
||||
else entryp->usedBit(lsb, nodep->width());
|
||||
} else {
|
||||
// else other varrefs handled as unknown mess in AstVarRef
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
// Any variable
|
||||
UndrivenVarEntry* entryp = getEntryp (nodep->varp());
|
||||
if (nodep->lvalue()) entryp->drivenWhole();
|
||||
else entryp->usedWhole();
|
||||
}
|
||||
|
||||
// Coverage artifacts etc shouldn't count as a sink
|
||||
virtual void visit(AstCoverDecl* nodep, AstNUser*) {}
|
||||
virtual void visit(AstCoverInc* nodep, AstNUser*) {}
|
||||
virtual void visit(AstCoverToggle* nodep, AstNUser*) {}
|
||||
virtual void visit(AstTraceDecl* nodep, AstNUser*) {}
|
||||
virtual void visit(AstTraceInc* nodep, AstNUser*) {}
|
||||
|
||||
// iterate
|
||||
virtual void visit(AstConst* nodep, AstNUser*) {}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
UndrivenVisitor(AstNetlist* nodep) {
|
||||
AstNode::user1ClearTree(); // user1p() used on entire tree
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~UndrivenVisitor() {
|
||||
for (vector<UndrivenVarEntry*>::iterator it = m_entryps.begin(); it != m_entryps.end(); ++it) {
|
||||
(*it)->reportViolations();
|
||||
delete (*it);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Undriven class functions
|
||||
|
||||
void V3Undriven::undrivenAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
UndrivenVisitor visitor (nodep);
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Check for unused/undriven signals
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2010 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.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef _V3UNDRIVEN_H_
|
||||
#define _V3UNDRIVEN_H_ 1
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Undriven {
|
||||
public:
|
||||
static void undrivenAll(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
|
@ -85,6 +85,7 @@
|
|||
#include "V3Trace.h"
|
||||
#include "V3TraceDecl.h"
|
||||
#include "V3Tristate.h"
|
||||
#include "V3Undriven.h"
|
||||
#include "V3Unknown.h"
|
||||
#include "V3Unroll.h"
|
||||
#include "V3Width.h"
|
||||
|
|
@ -184,6 +185,15 @@ void process () {
|
|||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("coverage.tree"));
|
||||
}
|
||||
|
||||
// Push constants, but only true constants preserving liveness
|
||||
// so V3Undriven sees variables to be eliminated, ie "if (0 && foo) ..."
|
||||
V3Const::constifyAllLive(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||
|
||||
// Signal based lint checks, no change to structures
|
||||
// Must be before first constification pass drops dead code
|
||||
V3Undriven::undrivenAll(v3Global.rootp());
|
||||
|
||||
// Assertion insertion
|
||||
// After we've added block coverage, but before other nasty transforms
|
||||
V3AssertPre::assertPreAll(v3Global.rootp());
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2008 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 (
|
||||
v_flags2 => ["--lint-only -Wall -Wno-DECLFILENAME"],
|
||||
fails=>1,
|
||||
verilator_make_gcc => 0,
|
||||
make_top_shell => 0,
|
||||
make_main => 0,
|
||||
expect=>
|
||||
'%Warning-UNUSED: t/t_lint_unused_bad.v:\d+: Bits of signal are not used: assunu1\[5:1\]
|
||||
%Warning-UNUSED: Use .* to disable this message.
|
||||
%Warning-UNDRIVEN: t/t_lint_unused_bad.v:\d+: Bits of signal are not driven: udrb2\[14:13,11\]
|
||||
%Warning-UNDRIVEN: t/t_lint_unused_bad.v:\d+: Signal is not driven, nor used: unu3
|
||||
%Error: Exiting due to.*',
|
||||
) if $Self->{v3};
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2010 by Wilson Snyder.
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Outputs
|
||||
out,
|
||||
// Inputs
|
||||
in
|
||||
);
|
||||
|
||||
input in; // inputs don't get flagged as undriven
|
||||
output out; // outputs don't get flagged as unused
|
||||
|
||||
wire out = in;
|
||||
|
||||
sub sub ();
|
||||
|
||||
endmodule
|
||||
|
||||
module sub;
|
||||
|
||||
wire pub /*verilator public*/; // Ignore publics
|
||||
|
||||
wire [5:0] assunu1 = 0; // Assigned but unused
|
||||
|
||||
wire [3:0] assunub2 = 0; // Assigned but bit 2 unused
|
||||
|
||||
wire [15:10] udrb2; // [14:13,11] is undriven
|
||||
assign udrb2[15] = 0;
|
||||
assign udrb2[12] = 0;
|
||||
assign udrb2[10] = 0;
|
||||
|
||||
wire unu3; // Totally unused
|
||||
|
||||
localparam THREE = 3;
|
||||
|
||||
initial begin
|
||||
if (0 && assunu1[0] != 0 && udrb2 != 0) begin end
|
||||
if (0 && assunub2[THREE] && assunub2[1:0]!=0) begin end
|
||||
end
|
||||
endmodule
|
||||
Loading…
Reference in New Issue