From dc90e6c3c3696f48e01e909deaf33b04bc2d896a Mon Sep 17 00:00:00 2001 From: Stefan Wallentowitz Date: Tue, 26 May 2020 20:38:14 +0200 Subject: [PATCH] Generate file with waivers (#2354) This adds the flag --generate-waivefile . This will generate a verilator config file with the proper lint_off statemens to turn off warnings emitted during this particular run. This feature can be used to start with using Verilator as linter and systematically capture all known lint warning for further elimination. It hopefully helps people turning of -Wno-fatal or -Wno-lint and gradually improve their code base. Signed-off-by: Stefan Wallentowitz --- Changes | 3 ++ bin/verilator | 12 +++++ src/Makefile_obj.in | 1 + src/V3FileLine.cpp | 2 + src/V3Options.cpp | 4 ++ src/V3Options.h | 3 ++ src/V3Waiver.cpp | 57 +++++++++++++++++++++++ src/V3Waiver.h | 35 ++++++++++++++ src/Verilator.cpp | 9 ++++ test_regress/t/t_waiveroutput.out | 13 ++++++ test_regress/t/t_waiveroutput.pl | 30 ++++++++++++ test_regress/t/t_waiveroutput.v | 10 ++++ test_regress/t/t_waiveroutput_allgood.out | 10 ++++ test_regress/t/t_waiveroutput_allgood.pl | 25 ++++++++++ test_regress/t/t_waiveroutput_allgood.vlt | 12 +++++ test_regress/t/t_wire_beh1364_bad.pl | 8 +++- 16 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 src/V3Waiver.cpp create mode 100644 src/V3Waiver.h create mode 100644 test_regress/t/t_waiveroutput.out create mode 100755 test_regress/t/t_waiveroutput.pl create mode 100644 test_regress/t/t_waiveroutput.v create mode 100644 test_regress/t/t_waiveroutput_allgood.out create mode 100755 test_regress/t/t_waiveroutput_allgood.pl create mode 100644 test_regress/t/t_waiveroutput_allgood.vlt diff --git a/Changes b/Changes index 699de9efb..889f493b0 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,9 @@ The contributors that suggested a given feature are shown in []. Thanks! * Verilator 4.035 devel +** Add --waiver-output flag that writes a verilator config file (.vlt) with + waivers to the warnings emitted during a Verilator run. + *** Support verilator_coverage --write-info for lcov HTML reports. **** Support multi channel descriptor I/O (#2190) [Stephen Henry] diff --git a/bin/verilator b/bin/verilator index 8189e8c82..e3de112cc 100755 --- a/bin/verilator +++ b/bin/verilator @@ -399,6 +399,7 @@ detailed descriptions in L for more information. +verilog2001ext+ Synonym for +1364-2001ext+ --version Displays program version and exits --vpi Enable VPI compiles + --waiver-output Create a waiver file based on the linter warnings -Wall Enable all style warnings -Werror- Convert warnings to errors -Wfuture- Disable unknown message warnings @@ -1606,6 +1607,17 @@ Displays program version and exits. Enable use of VPI and linking against the verilated_vpi.cpp files. +=item --waiver-output + +Generate a waiver file which contains all waiver statements to suppress the +warnings emitted during this Verilator run. This is in particular useful as +a starting point for solving linter warnings or suppressing them +systematically. + +The generated file is in the Verilator Configuration format, see +L, and can directly be consumed by Verilator. The +standard file extension is .vlt. + =item -Wall Enable all code style warnings, including code style warnings that are diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 911f97e1f..4b8d75548 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -246,6 +246,7 @@ RAW_OBJS = \ V3Undriven.o \ V3Unknown.o \ V3Unroll.o \ + V3Waiver.o \ V3Width.o \ V3WidthSel.o \ diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index b69161489..915de3bbf 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -28,6 +28,7 @@ # include "V3Config.h" # include "V3File.h" #endif +#include "V3Waiver.h" // clang-format on #include @@ -366,6 +367,7 @@ void FileLine::v3errorEnd(std::ostringstream& sstr, const string& locationStr) { } else if (!V3Error::errorContexted()) { nsstr << warnContextPrimary(); } + if (!m_waive) { V3Waiver::addEntry(V3Error::errorCode(), filename(), sstr.str()); } V3Error::v3errorEnd(nsstr, lstr.str()); } diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 1cdd942db..0c88e6030 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -1197,6 +1197,9 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char parseOptsFile(fl, parseFileArg(optdir, argv[i]), false); } else if (!strcmp(sw, "-gdb")) { // Used only in perl shell + } else if (!strcmp(sw, "-waiver-output") && (i + 1) < argc) { + shift; + m_waiverOutput = argv[i]; } else if (!strcmp(sw, "-rr")) { // Used only in perl shell } else if (!strcmp(sw, "-gdbbt")) { @@ -1627,6 +1630,7 @@ V3Options::V3Options() { m_makeDir = "obj_dir"; m_bin = ""; m_flags = ""; + m_waiverOutput = ""; m_l2Name = ""; m_unusedRegexp = "*unused*"; m_xAssign = "fast"; diff --git a/src/V3Options.h b/src/V3Options.h index 7813f236d..af90dfbbf 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -317,6 +317,7 @@ private: string m_protectLib; // main switch: --protect-lib {lib_name} string m_topModule; // main switch: --top-module string m_unusedRegexp; // main switch: --unused-regexp + string m_waiverOutput; // main switch: --waiver-output {filename} string m_xAssign; // main switch: --x-assign string m_xInitial; // main switch: --x-initial string m_xmlOutput; // main switch: --xml-output @@ -522,6 +523,8 @@ public: } string topModule() const { return m_topModule; } string unusedRegexp() const { return m_unusedRegexp; } + string waiverOutput() const { return m_waiverOutput; } + bool isWaiverOutput() const { return !m_waiverOutput.empty(); } string xAssign() const { return m_xAssign; } string xInitial() const { return m_xInitial; } string xmlOutput() const { return m_xmlOutput; } diff --git a/src/V3Waiver.cpp b/src/V3Waiver.cpp new file mode 100644 index 000000000..153c1c12f --- /dev/null +++ b/src/V3Waiver.cpp @@ -0,0 +1,57 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Emit waivers into a config file +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2020 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 +// +//************************************************************************* + +#include "verilatedos.h" + +#include "V3File.h" +#include "V3Waiver.h" + +#include +#include +#include + +void V3Waiver::addEntry(V3ErrorCode errorCode, const std::string& filename, + const std::string& str) { + std::stringstream entry; + entry << "lint_off -rule " << errorCode.ascii() << " -file \"*" << filename << "\" -match \"" + << str << "\""; + s_waiverList.push_back(entry.str()); +} + +void V3Waiver::write(const std::string& filename) { + const vl_unique_ptr ofp(V3File::new_ofstream(filename)); + if (ofp->fail()) v3fatal("Can't write " << filename); + + *ofp << "// DESCR" + "IPTION: Verilator output: Waivers generated with --waiver-output" + << std::endl + << endl; + + *ofp << "`verilator_config" << endl << endl; + + *ofp << "// Below you find suggested waivers. You have three options:" << endl; + *ofp << "// 1. Fix the reason for the linter warning" << endl; + *ofp << "// 2. Keep the waiver permanently if you are sure this is okay" << endl; + *ofp << "// 3. Keep the waiver temporarily to suppress the output" << endl << endl; + + if (s_waiverList.size() == 0) { *ofp << "// No waivers needed - great!" << endl; } + + for (V3Waiver::WaiverList::const_iterator it = s_waiverList.begin(); it != s_waiverList.end(); + ++it) { + *ofp << "// " << *it << std::endl << endl; + } +} + +V3Waiver::WaiverList V3Waiver::s_waiverList; diff --git a/src/V3Waiver.h b/src/V3Waiver.h new file mode 100644 index 000000000..67d4d65a0 --- /dev/null +++ b/src/V3Waiver.h @@ -0,0 +1,35 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Emit Waivers +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2020 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 +// +//************************************************************************* + +#ifndef _V3WAIVER_H_ +#define _V3WAIVER_H_ 1 + +#include "V3Error.h" + +#include +#include + +class V3Waiver { + // TYPES + typedef std::vector WaiverList; + static WaiverList s_waiverList; + +public: + static void addEntry(V3ErrorCode errorCode, const string& filename, const std::string& str); + static void write(const std::string& filename); +}; + +#endif // Guard diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 690874d29..c58d26c91 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -93,6 +93,7 @@ #include "V3Undriven.h" #include "V3Unknown.h" #include "V3Unroll.h" +#include "V3Waiver.h" #include "V3Width.h" #include @@ -542,6 +543,14 @@ static void verilate(const string& argString) { // Final steps V3Global::dumpCheckGlobalTree("final", 990, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); + + V3Error::abortIfErrors(); + + if (v3Global.opt.isWaiverOutput()) { + // Create waiver output, must be just before we exit on warnings + V3Waiver::write(v3Global.opt.waiverOutput()); + } + V3Error::abortIfWarnings(); if (v3Global.opt.makeDepend().isTrue()) { diff --git a/test_regress/t/t_waiveroutput.out b/test_regress/t/t_waiveroutput.out new file mode 100644 index 000000000..01132a95d --- /dev/null +++ b/test_regress/t/t_waiveroutput.out @@ -0,0 +1,13 @@ +// DESCRIPTION: Verilator output: Waivers generated with --waiver-output + +`verilator_config + +// Below you find suggested waivers. You have three options: +// 1. Fix the reason for the linter warning +// 2. Keep the waiver permanently if you are sure this is okay +// 3. Keep the waiver temporarily to suppress the output + +// lint_off -rule WIDTH -file "*t/t_waiveroutput.v" -match "Operator ASSIGN expects 1 bits on the Assign RHS, but Assign RHS's CONST '2'h3' generates 2 bits." + +// lint_off -rule UNUSED -file "*t/t_waiveroutput.v" -match "Signal is not used: 'width_warn'" + diff --git a/test_regress/t/t_waiveroutput.pl b/test_regress/t/t_waiveroutput.pl new file mode 100755 index 000000000..08f77ed08 --- /dev/null +++ b/test_regress/t/t_waiveroutput.pl @@ -0,0 +1,30 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2012 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 + +scenarios(vlt => 1); + +my $out_filename = "$Self->{obj_dir}/$Self->{name}_waiver_gen.vlt"; +my $waiver_filename = "$Self->{obj_dir}/$Self->{name}_waiver.vlt"; + +compile( + v_flags2 => ['--waiver-output', $out_filename], + fails => 1, + ); + +files_identical("$out_filename", $Self->{golden_filename}); + +run(cmd=>["sed 's/\\/\\/ lint_off/lint_off/g' $out_filename > $waiver_filename"]); + +compile( + v_flags2 => [$waiver_filename], + ); + +ok(1); +1; diff --git a/test_regress/t/t_waiveroutput.v b/test_regress/t/t_waiveroutput.v new file mode 100644 index 000000000..c84e9dec4 --- /dev/null +++ b/test_regress/t/t_waiveroutput.v @@ -0,0 +1,10 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2012 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t_waiveroutput; + + reg width_warn = 2'b11; // Width warning - must be line 18 +endmodule diff --git a/test_regress/t/t_waiveroutput_allgood.out b/test_regress/t/t_waiveroutput_allgood.out new file mode 100644 index 000000000..673c0445a --- /dev/null +++ b/test_regress/t/t_waiveroutput_allgood.out @@ -0,0 +1,10 @@ +// DESCRIPTION: Verilator output: Waivers generated with --waiver-output + +`verilator_config + +// Below you find suggested waivers. You have three options: +// 1. Fix the reason for the linter warning +// 2. Keep the waiver permanently if you are sure this is okay +// 3. Keep the waiver temporarily to suppress the output + +// No waivers needed - great! diff --git a/test_regress/t/t_waiveroutput_allgood.pl b/test_regress/t/t_waiveroutput_allgood.pl new file mode 100755 index 000000000..8a1846a0d --- /dev/null +++ b/test_regress/t/t_waiveroutput_allgood.pl @@ -0,0 +1,25 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2012 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 + +scenarios(vlt => 1); + +my $out_filename = "$Self->{obj_dir}/$Self->{name}_waiver_gen.vlt"; +my $waiver_filename = "t/$Self->{name}.vlt"; + +top_filename("t/t_waiveroutput.v"); + +compile( + v_flags2 => [$waiver_filename, '--waiver-output', $out_filename], + ); + +files_identical("$out_filename", $Self->{golden_filename}); + +ok(1); +1; diff --git a/test_regress/t/t_waiveroutput_allgood.vlt b/test_regress/t/t_waiveroutput_allgood.vlt new file mode 100644 index 000000000..2f6af4e29 --- /dev/null +++ b/test_regress/t/t_waiveroutput_allgood.vlt @@ -0,0 +1,12 @@ +// DESCRIPTION: Verilator output: Waivers generated with --waiver-output + +`verilator_config + +// Below you find suggested waivers. You have three options: +// 1. Fix the reason for the linter warning +// 2. Keep the waiver permanently if you are sure this is okay +// 3. Keep the waiver temporarily to suppress the output + +lint_off -rule WIDTH -file "*t/t_waiveroutput.v" -match "Operator ASSIGN expects 1 bits on the Assign RHS, but Assign RHS's CONST '2'h3' generates 2 bits." + +lint_off -rule UNUSED -file "*t/t_waiveroutput.v" -match "Signal is not used: 'width_warn'" diff --git a/test_regress/t/t_wire_beh1364_bad.pl b/test_regress/t/t_wire_beh1364_bad.pl index 77f34c903..ee98f2262 100755 --- a/test_regress/t/t_wire_beh1364_bad.pl +++ b/test_regress/t/t_wire_beh1364_bad.pl @@ -10,11 +10,17 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); +my $waiver_filename = "$Self->{obj_dir}/$Self->{name}_waiver.vlt"; + lint( - verilator_flags2 => ["--lint-only --language 1364-2001"], + verilator_flags2 => ["--lint-only --language 1364-2001 --waiver-output ${waiver_filename}"], fails => 1, expect_filename => $Self->{golden_filename}, ); +if (-e $waiver_filename) { + error("Waiver file generated, not expected.."); +} + ok(1); 1;